Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a2d6a00cd1 | |||
| ffe69f7f4b | |||
| 887cc3a1bb | |||
| c192b719f5 | |||
| ed0de74406 | |||
| ff1878511d | |||
| a77cbee5f2 | |||
| e92fda0ca3 | |||
| a4c9e1699b | |||
| df87b64f66 | |||
| b79e8e812d | |||
| ec2deebda4 | |||
| befbf84c59 | |||
| 7b205db200 | |||
| e43c85b12b | |||
| 758c175b3d | |||
| fdceb0e080 | |||
| 3863ef91e1 | |||
| 6e07258fc7 |
@@ -192,7 +192,6 @@
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize" />
|
||||
|
||||
<activity android:name=".GroupCreateActivity"
|
||||
android:windowSoftInputMode="stateVisible"
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
||||
|
||||
<activity android:name=".DatabaseUpgradeActivity"
|
||||
|
||||
@@ -255,8 +255,8 @@ android {
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
versionCode 397
|
||||
versionName "0.0.7"
|
||||
versionCode 398
|
||||
versionName "0.0.8"
|
||||
applicationId "chat.delta.androidii"
|
||||
|
||||
minSdkVersion 14
|
||||
|
||||
|
Before Width: | Height: | Size: 129 B After Width: | Height: | Size: 344 B |
|
Before Width: | Height: | Size: 512 B After Width: | Height: | Size: 727 B |
|
Before Width: | Height: | Size: 92 B After Width: | Height: | Size: 351 B |
|
Before Width: | Height: | Size: 331 B After Width: | Height: | Size: 508 B |
|
Before Width: | Height: | Size: 97 B After Width: | Height: | Size: 368 B |
|
Before Width: | Height: | Size: 634 B After Width: | Height: | Size: 822 B |
|
Before Width: | Height: | Size: 97 B After Width: | Height: | Size: 387 B |
|
Before Width: | Height: | Size: 1017 B After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.6 KiB |
@@ -73,7 +73,7 @@
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_margin="16dp"
|
||||
app:backgroundTint="@color/signal_primary"
|
||||
android:src="@drawable/ic_create_white_24dp"
|
||||
android:src="@drawable/ic_add_white_24dp"
|
||||
android:focusable="true"
|
||||
android:contentDescription="@string/conversation_list_fragment__fab_content_description"/>
|
||||
|
||||
|
||||
@@ -8,9 +8,7 @@
|
||||
android:focusable="true"
|
||||
android:nextFocusRight="@+id/fab"
|
||||
android:nextFocusLeft="@+id/container"
|
||||
android:layout_height="72dp"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingRight="16dp">
|
||||
android:layout_height="72dp">
|
||||
|
||||
<org.thoughtcrime.securesms.components.AvatarImageView
|
||||
android:id="@+id/contact_photo_image"
|
||||
@@ -23,150 +21,123 @@
|
||||
android:cropToPadding="true"
|
||||
tools:src="@drawable/ic_contact_picture"
|
||||
android:contentDescription="@string/conversation_list_item_view__contact_photo_image"
|
||||
android:layout_marginRight="12dp"
|
||||
android:layout_marginEnd="12dp" />
|
||||
android:layout_marginLeft="12dp"
|
||||
android:layout_marginRight="12dp" />
|
||||
|
||||
<RelativeLayout android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="4dp"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_toRightOf="@id/contact_photo_image"
|
||||
android:layout_toEndOf="@id/contact_photo_image"
|
||||
android:weightSum="1"
|
||||
android:orientation="horizontal">
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_toRightOf="@id/contact_photo_image"
|
||||
android:layout_toEndOf="@id/contact_photo_image">
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/from"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_toLeftOf="@+id/thumbnail"
|
||||
android:layout_toStartOf="@+id/thumbnail">
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_weight="2"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<org.thoughtcrime.securesms.components.FromTextView
|
||||
android:id="@+id/from_text"
|
||||
style="@style/Signal.Text.Body"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true"
|
||||
<LinearLayout
|
||||
android:id="@+id/from"
|
||||
android:orientation="horizontal"
|
||||
android:layout_marginBottom="2dp"
|
||||
android:layout_toLeftOf="@id/verified_indicator"
|
||||
android:layout_toStartOf="@id/verified_indicator"
|
||||
android:drawablePadding="5dp"
|
||||
android:ellipsize="end"
|
||||
android:fontFamily="sans-serif-medium"
|
||||
android:maxLines="1"
|
||||
android:textColor="?attr/conversation_list_item_contact_color"
|
||||
tools:text="Jules Bonnot" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/verified_indicator"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:src="@drawable/ic_verified"
|
||||
android:visibility="gone"
|
||||
android:layout_marginLeft="5dp"
|
||||
android:layout_marginStart="5dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginRight="5dp"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentEnd="true" />
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
</RelativeLayout>
|
||||
<org.thoughtcrime.securesms.components.FromTextView
|
||||
android:id="@+id/from_text"
|
||||
style="@style/Signal.Text.Body"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:drawablePadding="5dp"
|
||||
android:ellipsize="end"
|
||||
android:fontFamily="sans-serif-medium"
|
||||
android:maxLines="1"
|
||||
android:textColor="?attr/conversation_list_item_contact_color"
|
||||
tools:text="Jules Bonnot" />
|
||||
|
||||
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
|
||||
<ImageView
|
||||
android:id="@+id/verified_indicator"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:src="@drawable/ic_verified"
|
||||
android:visibility="visible"
|
||||
android:layout_marginLeft="5dp"
|
||||
android:layout_marginRight="5dp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
|
||||
android:id="@+id/subject"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/from"
|
||||
android:layout_toLeftOf="@+id/status"
|
||||
android:layout_toStartOf="@+id/status"
|
||||
android:paddingRight="1dp"
|
||||
style="@style/Signal.Text.Preview"
|
||||
android:textColor="?attr/conversation_list_item_subject_color"
|
||||
android:maxLines="1"
|
||||
tools:text="Wheels arrive at 3pm flat. This is a somewhat longer message."
|
||||
android:ellipsize="end" />
|
||||
|
||||
<org.thoughtcrime.securesms.components.ThumbnailView
|
||||
android:id="@+id/thumbnail"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginRight="5dp"
|
||||
android:layout_marginLeft="5dp"
|
||||
android:layout_toLeftOf="@+id/date"
|
||||
android:layout_toStartOf="@+id/date"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_marginTop="5dp"
|
||||
android:contentDescription="@string/conversation_activity__attachment_thumbnail"
|
||||
android:visibility="gone"
|
||||
tools:src="@drawable/ic_video_light"
|
||||
tools:visibility="visible" />
|
||||
</LinearLayout>
|
||||
|
||||
<TextView android:id="@id/date"
|
||||
android:layout_marginLeft="3dp"
|
||||
android:layout_marginStart="3dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignBaseline="@+id/from"
|
||||
android:layout_above="@id/subject"
|
||||
style="@style/Signal.Text.Caption"
|
||||
android:textColor="?attr/conversation_list_item_date_color"
|
||||
android:textAllCaps="true"
|
||||
tools:text="30 mins"
|
||||
android:singleLine="true"/>
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:gravity="end"
|
||||
android:layout_marginLeft="24dp"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginRight="12dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView android:id="@+id/archived"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/date"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignBaseline="@id/subject"
|
||||
android:layout_marginLeft="5dp"
|
||||
android:layout_marginStart="5dp"
|
||||
android:paddingLeft="6dp"
|
||||
android:paddingRight="6dp"
|
||||
android:paddingTop="2dp"
|
||||
android:paddingBottom="2dp"
|
||||
style="@style/Signal.Text.Caption"
|
||||
android:text="@string/conversation_list_item_view__archived"
|
||||
android:textColor="@color/core_white"
|
||||
android:textAllCaps="true"
|
||||
android:background="@drawable/archived_indicator_background" />
|
||||
<TextView android:id="@id/date"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
style="@style/Signal.Text.Caption"
|
||||
android:textColor="?attr/conversation_list_item_date_color"
|
||||
android:textAllCaps="true"
|
||||
tools:text="30 mins"
|
||||
android:singleLine="true"/>
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:minHeight="20dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<FrameLayout android:id="@+id/status"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_below="@id/date"
|
||||
android:layout_toLeftOf="@id/archived"
|
||||
android:layout_toStartOf="@id/archived"
|
||||
android:layout_alignWithParentIfMissing="true">
|
||||
<TextView android:id="@+id/archived"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="6dp"
|
||||
android:paddingRight="6dp"
|
||||
android:paddingTop="2dp"
|
||||
android:paddingBottom="2dp"
|
||||
style="@style/Signal.Text.Caption"
|
||||
android:text="@string/conversation_list_item_view__archived"
|
||||
android:textColor="@color/core_white"
|
||||
android:textAllCaps="true"
|
||||
android:background="@drawable/archived_indicator_background" />
|
||||
|
||||
<org.thoughtcrime.securesms.components.DeliveryStatusView
|
||||
android:id="@+id/delivery_status"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
app:iconColor="?attr/conversation_list_item_delivery_icon_color"/>
|
||||
<org.thoughtcrime.securesms.components.DeliveryStatusView
|
||||
android:id="@+id/delivery_status"
|
||||
android:layout_marginTop="6dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:iconColor="?attr/conversation_list_item_delivery_icon_color"/>
|
||||
|
||||
<ImageView android:id="@+id/unread_indicator"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"/>
|
||||
<ImageView android:id="@+id/unread_indicator"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"/>
|
||||
</LinearLayout>
|
||||
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
|
||||
</RelativeLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<View android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:background="@drawable/attachment_selector_shadow"/>
|
||||
|
||||
</org.thoughtcrime.securesms.ConversationListItem>
|
||||
|
||||
@@ -39,7 +39,8 @@
|
||||
tools:src="@drawable/ic_contact_picture"
|
||||
android:contentDescription="@string/conversation_list_item_view__contact_photo_image"/>
|
||||
|
||||
<RelativeLayout
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:id="@+id/content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -47,35 +48,33 @@
|
||||
android:layout_toEndOf="@id/contact_photo_image"
|
||||
android:layout_toRightOf="@id/contact_photo_image">
|
||||
|
||||
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
|
||||
android:id="@+id/title"
|
||||
style="@style/TextSecure.TitleTextStyle"
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_toLeftOf="@id/verified_indicator"
|
||||
android:layout_toStartOf="@id/verified_indicator"
|
||||
android:drawablePadding="5dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textSize="18dp"
|
||||
android:transitionName="recipient_name"
|
||||
tools:text="Jules Bonnot" />
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/verified_indicator"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="5dp"
|
||||
android:layout_marginStart="5dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:layout_marginRight="5dp"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:src="@drawable/ic_verified"
|
||||
android:visibility="gone" />
|
||||
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
|
||||
android:id="@+id/title"
|
||||
style="@style/TextSecure.TitleTextStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:drawablePadding="5dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textSize="18dp"
|
||||
android:transitionName="recipient_name"
|
||||
tools:text="Jules Bonnot" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/verified_indicator"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginLeft="5dp"
|
||||
android:layout_marginRight="5dp"
|
||||
android:src="@drawable/ic_verified"
|
||||
android:visibility="gone" />
|
||||
</LinearLayout>
|
||||
|
||||
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
|
||||
android:id="@+id/subtitle"
|
||||
@@ -86,9 +85,8 @@
|
||||
android:maxLines="1"
|
||||
android:textDirection="ltr"
|
||||
android:textSize="13dp"
|
||||
android:layout_below="@id/title"
|
||||
tools:text="(123) 123-1234" />
|
||||
|
||||
</RelativeLayout>
|
||||
</LinearLayout>
|
||||
|
||||
</org.thoughtcrime.securesms.ConversationTitleView>
|
||||
@@ -1532,5 +1532,6 @@
|
||||
<string name="conversation__menu_archive_chat">Archive chat</string>
|
||||
<string name="conversation__menu_unarchive_chat">Unarchive chat</string>
|
||||
<string name="conversation__menu_delete_chat">Delete chat</string>
|
||||
<string name="conversation__no_messages">No messages.</string>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -28,16 +28,16 @@ import java.util.Enumeration;
|
||||
import java.util.Hashtable;
|
||||
|
||||
public class DcEventCenter {
|
||||
private Hashtable<Integer, ArrayList<Object>> allObservers = new Hashtable<>();
|
||||
private Hashtable<Integer, ArrayList<DcEventDelegate>> allObservers = new Hashtable<>();
|
||||
private final Object LOCK = new Object();
|
||||
|
||||
public interface DcEventDelegate {
|
||||
void handleEvent(int eventId, Object data1, Object data2);
|
||||
}
|
||||
|
||||
public void addObserver(Object observer, int eventId) {
|
||||
public void addObserver(DcEventDelegate observer, int eventId) {
|
||||
synchronized (LOCK) {
|
||||
ArrayList<Object> idObservers = allObservers.get(eventId);
|
||||
ArrayList<DcEventDelegate> idObservers = allObservers.get(eventId);
|
||||
if (idObservers == null) {
|
||||
allObservers.put(eventId, (idObservers = new ArrayList<>()));
|
||||
}
|
||||
@@ -45,9 +45,9 @@ public class DcEventCenter {
|
||||
}
|
||||
}
|
||||
|
||||
public void removeObserver(Object observer, int eventId) {
|
||||
public void removeObserver(DcEventDelegate observer, int eventId) {
|
||||
synchronized (LOCK) {
|
||||
ArrayList<Object> idObservers = allObservers.get(eventId);
|
||||
ArrayList<DcEventDelegate> idObservers = allObservers.get(eventId);
|
||||
if (idObservers != null) {
|
||||
idObservers.remove(observer);
|
||||
}
|
||||
@@ -59,7 +59,7 @@ public class DcEventCenter {
|
||||
Enumeration<Integer> enumKey = allObservers.keys();
|
||||
while(enumKey.hasMoreElements()) {
|
||||
Integer eventId = enumKey.nextElement();
|
||||
ArrayList<Object> idObservers = allObservers.get(eventId);
|
||||
ArrayList<DcEventDelegate> idObservers = allObservers.get(eventId);
|
||||
if (idObservers != null) {
|
||||
idObservers.remove(observer);
|
||||
}
|
||||
@@ -69,11 +69,11 @@ public class DcEventCenter {
|
||||
|
||||
public void sendToObservers(int eventId, Object data1, Object data2) {
|
||||
synchronized (LOCK) {
|
||||
ArrayList<Object> idObservers = allObservers.get(eventId);
|
||||
ArrayList<DcEventDelegate> idObservers = allObservers.get(eventId);
|
||||
if (idObservers != null) {
|
||||
for (int i = 0; i < idObservers.size(); i++) {
|
||||
Object observer = idObservers.get(i);
|
||||
((DcEventDelegate) observer).handleEvent(eventId, data1, data2);
|
||||
DcEventDelegate observer = idObservers.get(i);
|
||||
observer.handleEvent(eventId, data1, data2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.b44t.messenger;
|
||||
|
||||
/**
|
||||
* Contains a list of media entries, their respective positions and ability to move through it.
|
||||
*/
|
||||
public class DcMediaGalleryElement {
|
||||
|
||||
final int[] mediaMsgs;
|
||||
int position;
|
||||
final DcContext context;
|
||||
public DcMediaGalleryElement(int[] mediaMsgs, int position, DcContext context, boolean leftIsRecent) {
|
||||
this.mediaMsgs = mediaMsgs;
|
||||
this.position = position;
|
||||
this.context = context;
|
||||
|
||||
// normal state is left is recent. If the ui needs right to be recent we reverse the order here.
|
||||
if (!leftIsRecent) {
|
||||
for (int ii = 0; ii < mediaMsgs.length / 2; ii++) {
|
||||
int tmp = mediaMsgs[ii];
|
||||
int opposite = mediaMsgs.length - 1 - ii;
|
||||
mediaMsgs[ii] = mediaMsgs[opposite];
|
||||
mediaMsgs[opposite] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return mediaMsgs.length;
|
||||
}
|
||||
|
||||
public int getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
public void moveToPosition(int newPosition) {
|
||||
if(newPosition < 0 || newPosition >= mediaMsgs.length)
|
||||
throw new IllegalArgumentException("can't move outside of known area.");
|
||||
position = newPosition;
|
||||
}
|
||||
|
||||
public DcMsg getMessage() {
|
||||
return context.getMsg(mediaMsgs[position]);
|
||||
}
|
||||
}
|
||||
@@ -31,8 +31,7 @@ import org.thoughtcrime.securesms.database.model.Quote;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientProvider;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.io.File;
|
||||
import java.util.Set;
|
||||
|
||||
public class DcMsg {
|
||||
@@ -54,6 +53,7 @@ public class DcMsg {
|
||||
public final static int DC_STATE_OUT_DELIVERED = 26;
|
||||
public final static int DC_STATE_OUT_MDN_RCVD = 28;
|
||||
|
||||
public static final int DC_MSG_NO_ID = 0;
|
||||
public final static int DC_MSG_ID_MARKER1 = 1;
|
||||
public final static int DC_MSG_ID_DAYMARKER = 9;
|
||||
|
||||
@@ -111,6 +111,12 @@ public class DcMsg {
|
||||
public native void setDimension (int width, int height);
|
||||
public native void setDuration (int duration);
|
||||
|
||||
public File getFileAsFile() {
|
||||
if(getFile()==null)
|
||||
throw new AssertionError("expected a file to be present.");
|
||||
return new File(getFile());
|
||||
}
|
||||
|
||||
// aliases and higher-level tools
|
||||
public static int[] msgSetToIds(final Set<DcMsg> dcMsgs) {
|
||||
int cnt = dcMsgs==null? 0 : dcMsgs.size();
|
||||
|
||||
@@ -170,10 +170,15 @@ public class ConversationFragment extends Fragment
|
||||
|
||||
private void setNoMessageText() {
|
||||
if(threadId==DcChat.DC_CHAT_ID_DEADDROP) {
|
||||
noMessageTextView.setText(R.string.menu_deaddrop);
|
||||
noMessageTextView.setText(R.string.conversation__no_messages);
|
||||
}
|
||||
else if(getListAdapter().isGroupChat()){
|
||||
noMessageTextView.setText(R.string.ConversationActivity_MsgNewGroupDraftHint);
|
||||
if( dcContext.getChat((int)threadId).isUnpromoted() ) {
|
||||
noMessageTextView.setText(R.string.ConversationActivity_MsgNewGroupDraftHint);
|
||||
}
|
||||
else {
|
||||
noMessageTextView.setText(R.string.conversation__no_messages);
|
||||
}
|
||||
}else{
|
||||
String name = getListAdapter().getChatName();
|
||||
String message = getString(R.string.ConversationActivity_NoMessagesHint, name, name);
|
||||
|
||||
@@ -683,11 +683,9 @@ public class ConversationItem extends LinearLayout
|
||||
} else if (MediaPreviewActivity.isContentTypeSupported(slide.getContentType()) && slide.getUri() != null) {
|
||||
Intent intent = new Intent(context, MediaPreviewActivity.class);
|
||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
intent.setDataAndType(slide.getUri(), slide.getContentType());
|
||||
intent.putExtra(MediaPreviewActivity.DC_MSG_ID, slide.getDcMsgId());
|
||||
intent.putExtra(MediaPreviewActivity.ADDRESS_EXTRA, conversationRecipient.getAddress());
|
||||
intent.putExtra(MediaPreviewActivity.OUTGOING_EXTRA, messageRecord.isOutgoing());
|
||||
intent.putExtra(MediaPreviewActivity.DATE_EXTRA, messageRecord.getTimestamp());
|
||||
intent.putExtra(MediaPreviewActivity.SIZE_EXTRA, slide.asAttachment().getSize());
|
||||
intent.putExtra(MediaPreviewActivity.LEFT_IS_RECENT_EXTRA, false);
|
||||
|
||||
context.startActivity(intent);
|
||||
|
||||
@@ -17,9 +17,7 @@
|
||||
package org.thoughtcrime.securesms;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.support.v7.widget.TooltipCompat;
|
||||
@@ -28,19 +26,15 @@ import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.b44t.messenger.DcChat;
|
||||
import com.b44t.messenger.DcContact;
|
||||
import com.google.zxing.integration.android.IntentIntegrator;
|
||||
import com.google.zxing.integration.android.IntentResult;
|
||||
|
||||
import org.thoughtcrime.securesms.components.SearchToolbar;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.lock.RegistrationLockDialog;
|
||||
import org.thoughtcrime.securesms.permissions.Permissions;
|
||||
import org.thoughtcrime.securesms.qr.QrScanHandler;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.search.SearchFragment;
|
||||
import org.thoughtcrime.securesms.service.KeyCachingService;
|
||||
import org.thoughtcrime.securesms.util.DynamicLanguage;
|
||||
|
||||
@@ -48,6 +48,7 @@ class ConversationListAdapter extends RecyclerView.Adapter {
|
||||
private static final int MESSAGE_TYPE_SWITCH_ARCHIVE = 1;
|
||||
private static final int MESSAGE_TYPE_THREAD = 2;
|
||||
private static final int MESSAGE_TYPE_INBOX_ZERO = 3;
|
||||
private static final int MESSAGE_TYPE_DEADDROP = 4; // DEADDROP and THREAD share the same class, however, for DEADDROP it is modified on construction so it cannot be reused
|
||||
|
||||
private final @NonNull ApplicationDcContext dcContext;
|
||||
private @NonNull DcChatlist dcChatlist;
|
||||
@@ -138,7 +139,10 @@ class ConversationListAdapter extends RecyclerView.Adapter {
|
||||
public int getItemViewType(int i) {
|
||||
int chatId = dcChatlist.getChatId(i);
|
||||
|
||||
if (chatId == DcChat.DC_CHAT_ID_ARCHIVED_LINK) {
|
||||
if (chatId==DcChat.DC_CHAT_ID_DEADDROP) {
|
||||
return MESSAGE_TYPE_DEADDROP;
|
||||
}
|
||||
else if (chatId == DcChat.DC_CHAT_ID_ARCHIVED_LINK) {
|
||||
return MESSAGE_TYPE_SWITCH_ARCHIVE;
|
||||
} else if(chatId == DcChat.DC_CHAT_ID_ALLDONE_HINT) {
|
||||
return MESSAGE_TYPE_INBOX_ZERO;
|
||||
|
||||
@@ -17,11 +17,9 @@
|
||||
package org.thoughtcrime.securesms;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Typeface;
|
||||
import android.graphics.drawable.RippleDrawable;
|
||||
import android.os.Build.VERSION;
|
||||
import android.os.Build.VERSION_CODES;
|
||||
import android.support.annotation.NonNull;
|
||||
@@ -40,6 +38,7 @@ import android.widget.TextView;
|
||||
import com.amulyakhare.textdrawable.TextDrawable;
|
||||
import com.annimon.stream.Stream;
|
||||
import com.b44t.messenger.DcChat;
|
||||
import com.b44t.messenger.DcContact;
|
||||
import com.b44t.messenger.DcContext;
|
||||
import com.b44t.messenger.DcLot;
|
||||
import com.b44t.messenger.DcMsg;
|
||||
@@ -47,7 +46,7 @@ import com.b44t.messenger.DcMsg;
|
||||
import org.thoughtcrime.securesms.components.AvatarImageView;
|
||||
import org.thoughtcrime.securesms.components.DeliveryStatusView;
|
||||
import org.thoughtcrime.securesms.components.FromTextView;
|
||||
import org.thoughtcrime.securesms.components.ThumbnailView;
|
||||
import org.thoughtcrime.securesms.connect.ApplicationDcContext;
|
||||
import org.thoughtcrime.securesms.connect.DcHelper;
|
||||
import org.thoughtcrime.securesms.database.model.ThreadRecord;
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||
@@ -88,9 +87,6 @@ public class ConversationListItem extends RelativeLayout
|
||||
|
||||
private int unreadCount;
|
||||
private AvatarImageView contactPhotoImage;
|
||||
private ThumbnailView thumbnailView;
|
||||
|
||||
private int distributionType;
|
||||
|
||||
public ConversationListItem(Context context) {
|
||||
this(context, null);
|
||||
@@ -108,11 +104,9 @@ public class ConversationListItem extends RelativeLayout
|
||||
this.dateView = findViewById(R.id.date);
|
||||
this.deliveryStatusIndicator = findViewById(R.id.delivery_status);
|
||||
this.contactPhotoImage = findViewById(R.id.contact_photo_image);
|
||||
this.thumbnailView = findViewById(R.id.thumbnail);
|
||||
this.archivedView = findViewById(R.id.archived);
|
||||
this.unreadIndicator = findViewById(R.id.unread_indicator);
|
||||
this.verifiedIndicator = findViewById(R.id.verified_indicator);
|
||||
thumbnailView.setClickable(false);
|
||||
|
||||
ViewUtil.setTextViewGravityStart(this.fromView, getContext());
|
||||
ViewUtil.setTextViewGravityStart(this.subjectView, getContext());
|
||||
@@ -146,7 +140,6 @@ public class ConversationListItem extends RelativeLayout
|
||||
this.msgId = msgId;
|
||||
this.glideRequests = glideRequests;
|
||||
this.unreadCount = thread.getUnreadCount();
|
||||
this.distributionType = thread.getDistributionType();
|
||||
this.lastSeen = thread.getLastSeen();
|
||||
|
||||
if (highlightSubstring != null) {
|
||||
@@ -163,23 +156,21 @@ public class ConversationListItem extends RelativeLayout
|
||||
if (thread.getDate() > 0) {
|
||||
CharSequence date = DateUtils.getBriefRelativeTimeSpanString(getContext(), locale, thread.getDate());
|
||||
dateView.setText(date);
|
||||
dateView.setTypeface(unreadCount == 0 ? LIGHT_TYPEFACE : BOLD_TYPEFACE);
|
||||
dateView.setTextColor(unreadCount == 0 ? ThemeUtil.getThemedColor(getContext(), R.attr.conversation_list_item_date_color)
|
||||
: ThemeUtil.getThemedColor(getContext(), R.attr.conversation_list_item_unread_color));
|
||||
}
|
||||
|
||||
if (thread.isArchived()) {
|
||||
this.archivedView.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
this.archivedView.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
setStatusIcons(thread);
|
||||
setThumbnailSnippet(thread);
|
||||
setBatchState(batchMode);
|
||||
setRippleColor(recipient);
|
||||
setUnreadIndicator(thread);
|
||||
this.contactPhotoImage.setAvatar(glideRequests, recipient, true);
|
||||
setBgColor();
|
||||
|
||||
if(threadId==DcChat.DC_CHAT_ID_DEADDROP) {
|
||||
ApplicationDcContext dcContext = DcHelper.getContext(getContext());
|
||||
DcContact dcContact = dcContext.getContact(dcContext.getMsg(msgId).getFromId());
|
||||
this.contactPhotoImage.setAvatar(glideRequests, dcContext.getRecipient(dcContact), true);
|
||||
}
|
||||
else {
|
||||
this.contactPhotoImage.setAvatar(glideRequests, recipient, true);
|
||||
}
|
||||
|
||||
verifiedIndicator.setVisibility(thread.isVerified() ? VISIBLE : GONE);
|
||||
}
|
||||
|
||||
@@ -198,10 +189,9 @@ public class ConversationListItem extends RelativeLayout
|
||||
archivedView.setVisibility(GONE);
|
||||
unreadIndicator.setVisibility(GONE);
|
||||
deliveryStatusIndicator.setNone();
|
||||
thumbnailView.setVisibility(GONE);
|
||||
|
||||
setBatchState(false);
|
||||
setRippleColor(contact);
|
||||
setBgColor();
|
||||
contactPhotoImage.setAvatar(glideRequests, recipient, true);
|
||||
}
|
||||
|
||||
@@ -220,10 +210,9 @@ public class ConversationListItem extends RelativeLayout
|
||||
archivedView.setVisibility(GONE);
|
||||
unreadIndicator.setVisibility(GONE);
|
||||
deliveryStatusIndicator.setNone();
|
||||
thumbnailView.setVisibility(GONE);
|
||||
|
||||
setBatchState(false);
|
||||
setRippleColor(recipient);
|
||||
setBgColor();
|
||||
contactPhotoImage.setAvatar(glideRequests, recipient, true);
|
||||
}
|
||||
|
||||
@@ -256,88 +245,63 @@ public class ConversationListItem extends RelativeLayout
|
||||
return lastSeen;
|
||||
}
|
||||
|
||||
private void setThumbnailSnippet(ThreadRecord thread) {
|
||||
if (thread.getSnippetUri() != null) {
|
||||
this.thumbnailView.setVisibility(View.VISIBLE);
|
||||
this.thumbnailView.setImageResource(glideRequests, thread.getSnippetUri());
|
||||
|
||||
LayoutParams subjectParams = (RelativeLayout.LayoutParams)this.subjectView.getLayoutParams();
|
||||
subjectParams.addRule(RelativeLayout.LEFT_OF, R.id.thumbnail);
|
||||
if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
subjectParams.addRule(RelativeLayout.START_OF, R.id.thumbnail);
|
||||
}
|
||||
this.subjectView.setLayoutParams(subjectParams);
|
||||
this.post(new ThumbnailPositioner(thumbnailView, archivedView, deliveryStatusIndicator, dateView));
|
||||
} else {
|
||||
this.thumbnailView.setVisibility(View.GONE);
|
||||
|
||||
LayoutParams subjectParams = (RelativeLayout.LayoutParams)this.subjectView.getLayoutParams();
|
||||
subjectParams.addRule(RelativeLayout.LEFT_OF, R.id.status);
|
||||
if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
subjectParams.addRule(RelativeLayout.START_OF, R.id.status);
|
||||
}
|
||||
this.subjectView.setLayoutParams(subjectParams);
|
||||
}
|
||||
}
|
||||
|
||||
private void setStatusIcons(ThreadRecord thread) {
|
||||
int state = dcSummary.getState();
|
||||
|
||||
if (state==DcMsg.DC_STATE_IN_FRESH || state==DcMsg.DC_STATE_IN_NOTICED) {
|
||||
if (thread.isArchived())
|
||||
{
|
||||
// archived
|
||||
this.archivedView.setVisibility(View.VISIBLE);
|
||||
deliveryStatusIndicator.setNone();
|
||||
} else if (state==DcMsg.DC_STATE_OUT_ERROR) {
|
||||
deliveryStatusIndicator.setFailed();
|
||||
} else {
|
||||
if(state==DcMsg.DC_STATE_OUT_MDN_RCVD) {
|
||||
deliveryStatusIndicator.setRead();
|
||||
}
|
||||
else if(state==DcMsg.DC_STATE_OUT_DELIVERED) {
|
||||
deliveryStatusIndicator.setSent();
|
||||
}
|
||||
else if (state==DcMsg.DC_STATE_OUT_PENDING){
|
||||
deliveryStatusIndicator.setPending();
|
||||
}
|
||||
else {
|
||||
deliveryStatusIndicator.setNone();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setRippleColor(Recipient recipient) {
|
||||
if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
|
||||
// TODO: a different backgroupd for the deaddrop would be nice, however the following code collades with the selected state and should be fixex
|
||||
|
||||
// if(threadId==DcChat.DC_CHAT_ID_DEADDROP) {
|
||||
// TypedArray ta = getContext().obtainStyledAttributes(new int[] { R.attr.conversation_list_deaddrop_bg_color});
|
||||
// setBackgroundColor(ta.getColor(0, 0xffffffff));
|
||||
// ta.recycle();
|
||||
// }
|
||||
// else {
|
||||
// TypedArray ta = getContext().obtainStyledAttributes(new int[] { R.attr.conversation_list_item_background});
|
||||
// setBackground(ta.getDrawable(0));
|
||||
// ta.recycle();
|
||||
|
||||
((RippleDrawable)(getBackground()).mutate())
|
||||
.setColor(ColorStateList.valueOf(recipient.getColor().toConversationColor(getContext())));
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
private void setUnreadIndicator(ThreadRecord thread) {
|
||||
if (thread.getUnreadCount() == 0) {
|
||||
unreadIndicator.setVisibility(View.GONE);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.archivedView.setVisibility(View.GONE);
|
||||
int state = dcSummary.getState();
|
||||
if (state==DcMsg.DC_STATE_IN_FRESH || state==DcMsg.DC_STATE_IN_NOTICED)
|
||||
{
|
||||
// incoming
|
||||
deliveryStatusIndicator.setNone();
|
||||
int unreadCount = thread.getUnreadCount();
|
||||
if(unreadCount==0) {
|
||||
unreadIndicator.setVisibility(View.GONE);
|
||||
}
|
||||
else {
|
||||
unreadIndicator.setImageDrawable(TextDrawable.builder()
|
||||
.beginConfig()
|
||||
.width(ViewUtil.dpToPx(getContext(), 24))
|
||||
.height(ViewUtil.dpToPx(getContext(), 24))
|
||||
.textColor(Color.WHITE)
|
||||
.bold()
|
||||
.endConfig()
|
||||
.buildRound(String.valueOf(unreadCount), getResources().getColor(R.color.green_A700)));
|
||||
unreadIndicator.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// outgoing
|
||||
unreadIndicator.setVisibility(View.GONE);
|
||||
if (state == DcMsg.DC_STATE_OUT_ERROR) {
|
||||
deliveryStatusIndicator.setFailed();
|
||||
} else if (state == DcMsg.DC_STATE_OUT_MDN_RCVD) {
|
||||
deliveryStatusIndicator.setRead();
|
||||
} else if (state == DcMsg.DC_STATE_OUT_DELIVERED) {
|
||||
deliveryStatusIndicator.setSent();
|
||||
} else if (state == DcMsg.DC_STATE_OUT_PENDING) {
|
||||
deliveryStatusIndicator.setPending();
|
||||
} else {
|
||||
deliveryStatusIndicator.setNone();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unreadIndicator.setImageDrawable(TextDrawable.builder()
|
||||
.beginConfig()
|
||||
.width(ViewUtil.dpToPx(getContext(), 24))
|
||||
.height(ViewUtil.dpToPx(getContext(), 24))
|
||||
.textColor(Color.WHITE)
|
||||
.bold()
|
||||
.endConfig()
|
||||
.buildRound(String.valueOf(thread.getUnreadCount()), getResources().getColor(R.color.green_A700)));
|
||||
unreadIndicator.setVisibility(View.VISIBLE);
|
||||
private void setBgColor() {
|
||||
if(threadId==DcChat.DC_CHAT_ID_DEADDROP) {
|
||||
TypedArray ta = getContext().obtainStyledAttributes(new int[] { R.attr.conversation_list_deaddrop_bg_color});
|
||||
setBackgroundColor(ta.getColor(0, 0xffffffff));
|
||||
ta.recycle();
|
||||
}
|
||||
}
|
||||
|
||||
private Spanned getHighlightedSpan(@NonNull Locale locale,
|
||||
@@ -377,41 +341,4 @@ public class ConversationListItem extends RelativeLayout
|
||||
|
||||
return spanned;
|
||||
}
|
||||
|
||||
private static class ThumbnailPositioner implements Runnable {
|
||||
|
||||
private final View thumbnailView;
|
||||
private final View archivedView;
|
||||
private final View deliveryStatusView;
|
||||
private final View dateView;
|
||||
|
||||
ThumbnailPositioner(View thumbnailView, View archivedView, View deliveryStatusView, View dateView) {
|
||||
this.thumbnailView = thumbnailView;
|
||||
this.archivedView = archivedView;
|
||||
this.deliveryStatusView = deliveryStatusView;
|
||||
this.dateView = dateView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
LayoutParams thumbnailParams = (RelativeLayout.LayoutParams)thumbnailView.getLayoutParams();
|
||||
|
||||
if (archivedView.getVisibility() == View.VISIBLE &&
|
||||
(archivedView.getWidth() + deliveryStatusView.getWidth()) > dateView.getWidth())
|
||||
{
|
||||
thumbnailParams.addRule(RelativeLayout.LEFT_OF, R.id.status);
|
||||
if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
thumbnailParams.addRule(RelativeLayout.START_OF, R.id.status);
|
||||
}
|
||||
} else {
|
||||
thumbnailParams.addRule(RelativeLayout.LEFT_OF, R.id.date);
|
||||
if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
thumbnailParams.addRule(RelativeLayout.START_OF, R.id.date);
|
||||
}
|
||||
}
|
||||
|
||||
thumbnailView.setLayoutParams(thumbnailParams);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,12 +25,12 @@ import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
import android.util.SparseBooleanArray;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ListView;
|
||||
@@ -53,6 +53,7 @@ import org.thoughtcrime.securesms.mms.GlideApp;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.DynamicLanguage;
|
||||
import org.thoughtcrime.securesms.util.DynamicTheme;
|
||||
import org.thoughtcrime.securesms.util.FileUtils;
|
||||
import org.thoughtcrime.securesms.util.SelectedRecipientsAdapter;
|
||||
import org.thoughtcrime.securesms.util.SelectedRecipientsAdapter.OnRecipientDeletedListener;
|
||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
@@ -114,8 +115,8 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
|
||||
createVerified = getIntent().getBooleanExtra(GROUP_CREATE_VERIFIED_EXTRA, false);
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_close_white_24dp);
|
||||
initializeResources();
|
||||
initializeExistingGroup();
|
||||
initializeResources();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -204,7 +205,25 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
|
||||
verifyButton.setOnClickListener(new ShowQrButtonListener());
|
||||
verifyButton.setVisibility(View.VISIBLE);
|
||||
}
|
||||
avatar.setImageDrawable(new ResourceContactPhoto(R.drawable.ic_group_white_24dp).asDrawable(this, ContactColors.UNKNOWN_COLOR.toConversationColor(this)));
|
||||
initializeAvatarView();
|
||||
}
|
||||
|
||||
private void initializeAvatarView() {
|
||||
boolean imageLoaded = false;
|
||||
if (editGroupChatId != null) {
|
||||
String avatarPath = dcContext.getChat(editGroupChatId).getProfileImage();
|
||||
File avatarFile = new File(avatarPath);
|
||||
if (avatarFile.exists()) {
|
||||
imageLoaded = true;
|
||||
GlideApp.with(this)
|
||||
.load(avatarFile)
|
||||
.circleCrop()
|
||||
.into(avatar);
|
||||
}
|
||||
}
|
||||
if (!imageLoaded) {
|
||||
avatar.setImageDrawable(new ResourceContactPhoto(R.drawable.ic_group_white_24dp).asDrawable(this, ContactColors.UNKNOWN_COLOR.toConversationColor(this)));
|
||||
}
|
||||
avatar.setOnClickListener(view -> Crop.pickImage(GroupCreateActivity.this));
|
||||
}
|
||||
|
||||
@@ -212,6 +231,7 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
|
||||
final Address groupAddress = getIntent().getParcelableExtra(GROUP_ADDRESS_EXTRA);
|
||||
if (groupAddress != null) {
|
||||
editGroupChatId = groupAddress.getDcChatId();
|
||||
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
|
||||
new FillExistingGroupInfoAsyncTask(this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, editGroupChatId);
|
||||
}
|
||||
}
|
||||
@@ -270,28 +290,30 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
|
||||
finish();
|
||||
}
|
||||
|
||||
@SuppressWarnings("ResultOfMethodCallIgnored")
|
||||
private void setGroupAvatar(int chatId) {
|
||||
if(avatarBmp == null) {
|
||||
return;
|
||||
}
|
||||
String avatarPath = getFilesDir().getAbsolutePath() + "/chatAvatar_" + chatId + ".jpg";
|
||||
if(avatarBmp == null) {
|
||||
return;
|
||||
}
|
||||
String avatarPath = dcContext.getChat(chatId).getProfileImage();
|
||||
if (avatarPath != null && !avatarPath.isEmpty()) {
|
||||
File oldImage = new File(avatarPath);
|
||||
if (oldImage.exists()) {
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
oldImage.delete();
|
||||
}
|
||||
FileOutputStream outStream;
|
||||
try {
|
||||
outStream = new FileOutputStream(avatarPath);
|
||||
avatarBmp.compress(Bitmap.CompressFormat.JPEG, 85, outStream);
|
||||
dcContext.setChatProfileImage(chatId, avatarPath);
|
||||
Log.d("dboehrs", "setGroupAvatar: " + avatarPath);
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
avatarPath = FileUtils.getFilePathForChatAvatar(this, chatId, System.currentTimeMillis());
|
||||
FileOutputStream outStream;
|
||||
try {
|
||||
outStream = new FileOutputStream(avatarPath);
|
||||
avatarBmp.compress(Bitmap.CompressFormat.JPEG, 85, outStream);
|
||||
dcContext.setChatProfileImage(chatId, avatarPath);
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean showGroupNameEmptyToast(String groupName) {
|
||||
private boolean showGroupNameEmptyToast(String groupName) {
|
||||
if(groupName == null) {
|
||||
Toast.makeText(this, getString(R.string.GroupCreateActivity_please_enter_group_name), Toast.LENGTH_LONG).show();
|
||||
return true;
|
||||
@@ -383,22 +405,27 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
|
||||
new Crop(data.getData()).output(outputFile).asSquare().start(this);
|
||||
break;
|
||||
case Crop.REQUEST_CROP:
|
||||
GlideApp.with(this)
|
||||
.asBitmap()
|
||||
.load(Crop.getOutput(data))
|
||||
.skipMemoryCache(true)
|
||||
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
||||
.centerCrop()
|
||||
.override(AVATAR_SIZE, AVATAR_SIZE)
|
||||
.into(new SimpleTarget<Bitmap>() {
|
||||
@Override
|
||||
public void onResourceReady(@NonNull Bitmap resource, Transition<? super Bitmap> transition) {
|
||||
setAvatar(Crop.getOutput(data), resource);
|
||||
}
|
||||
});
|
||||
setAvatarView(data);
|
||||
}
|
||||
}
|
||||
|
||||
private void setAvatarView(Intent data) {
|
||||
final Uri output = Crop.getOutput(data);
|
||||
GlideApp.with(this)
|
||||
.asBitmap()
|
||||
.load(output)
|
||||
.skipMemoryCache(true)
|
||||
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
||||
.centerCrop()
|
||||
.override(AVATAR_SIZE, AVATAR_SIZE)
|
||||
.into(new SimpleTarget<Bitmap>() {
|
||||
@Override
|
||||
public void onResourceReady(@NonNull Bitmap resource, Transition<? super Bitmap> transition) {
|
||||
setAvatar(output, resource);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private class AddRecipientButtonListener implements View.OnClickListener {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
|
||||
@@ -23,10 +23,10 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.b44t.messenger.DcMsg;
|
||||
import com.codewaves.stickyheadergrid.StickyHeaderGridAdapter;
|
||||
|
||||
import org.thoughtcrime.securesms.components.ThumbnailView;
|
||||
import org.thoughtcrime.securesms.database.MediaDatabase.MediaRecord;
|
||||
import org.thoughtcrime.securesms.database.loaders.BucketedThreadMediaLoader.BucketedThreadMedia;
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||
import org.thoughtcrime.securesms.mms.Slide;
|
||||
@@ -46,7 +46,7 @@ class MediaGalleryAdapter extends StickyHeaderGridAdapter {
|
||||
private final GlideRequests glideRequests;
|
||||
private final Locale locale;
|
||||
private final ItemClickListener itemClickListener;
|
||||
private final Set<MediaRecord> selected;
|
||||
private final Set<DcMsg> selected;
|
||||
|
||||
private BucketedThreadMedia media;
|
||||
|
||||
@@ -105,10 +105,10 @@ class MediaGalleryAdapter extends StickyHeaderGridAdapter {
|
||||
|
||||
@Override
|
||||
public void onBindItemViewHolder(ItemViewHolder viewHolder, int section, int offset) {
|
||||
MediaRecord mediaRecord = media.get(section, offset);
|
||||
DcMsg mediaRecord = media.get(section, offset);
|
||||
ThumbnailView thumbnailView = ((ViewHolder)viewHolder).imageView;
|
||||
View selectedIndicator = ((ViewHolder)viewHolder).selectedIndicator;
|
||||
Slide slide = MediaUtil.getSlideForAttachment(context, mediaRecord.getAttachment());
|
||||
Slide slide = MediaUtil.getSlideForMsg(context, mediaRecord);
|
||||
|
||||
if (slide != null) {
|
||||
thumbnailView.setImageResource(glideRequests, slide, false, false);
|
||||
@@ -133,7 +133,7 @@ class MediaGalleryAdapter extends StickyHeaderGridAdapter {
|
||||
return media.getSectionItemCount(section);
|
||||
}
|
||||
|
||||
public void toggleSelection(@NonNull MediaRecord mediaRecord) {
|
||||
public void toggleSelection(@NonNull DcMsg mediaRecord) {
|
||||
if (!selected.remove(mediaRecord)) {
|
||||
selected.add(mediaRecord);
|
||||
}
|
||||
@@ -145,7 +145,7 @@ class MediaGalleryAdapter extends StickyHeaderGridAdapter {
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public Collection<MediaRecord> getSelectedMedia() {
|
||||
public Collection<DcMsg> getSelectedMedia() {
|
||||
return new HashSet<>(selected);
|
||||
}
|
||||
|
||||
@@ -155,7 +155,7 @@ class MediaGalleryAdapter extends StickyHeaderGridAdapter {
|
||||
}
|
||||
|
||||
interface ItemClickListener {
|
||||
void onMediaClicked(@NonNull MediaRecord mediaRecord);
|
||||
void onMediaLongClicked(MediaRecord mediaRecord);
|
||||
void onMediaClicked(@NonNull DcMsg mediaRecord);
|
||||
void onMediaLongClicked(DcMsg mediaRecord);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,17 +47,18 @@ import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.b44t.messenger.DcContext;
|
||||
import com.b44t.messenger.DcMsg;
|
||||
import com.codewaves.stickyheadergrid.StickyHeaderGridLayoutManager;
|
||||
|
||||
import org.thoughtcrime.securesms.connect.DcHelper;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter;
|
||||
import org.thoughtcrime.securesms.database.MediaDatabase;
|
||||
import org.thoughtcrime.securesms.database.loaders.BucketedThreadMediaLoader;
|
||||
import org.thoughtcrime.securesms.database.loaders.BucketedThreadMediaLoader.BucketedThreadMedia;
|
||||
import org.thoughtcrime.securesms.database.loaders.ThreadMediaLoader;
|
||||
import org.thoughtcrime.securesms.mms.GlideApp;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.AttachmentUtil;
|
||||
import org.thoughtcrime.securesms.util.DynamicLanguage;
|
||||
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
|
||||
import org.thoughtcrime.securesms.util.DynamicTheme;
|
||||
@@ -257,7 +258,7 @@ public class MediaOverviewActivity extends PassphraseRequiredActionBarActivity
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMediaClicked(@NonNull MediaDatabase.MediaRecord mediaRecord) {
|
||||
public void onMediaClicked(@NonNull DcMsg mediaRecord) {
|
||||
if (actionMode != null) {
|
||||
handleMediaMultiSelectClick(mediaRecord);
|
||||
} else {
|
||||
@@ -265,7 +266,7 @@ public class MediaOverviewActivity extends PassphraseRequiredActionBarActivity
|
||||
}
|
||||
}
|
||||
|
||||
private void handleMediaMultiSelectClick(@NonNull MediaDatabase.MediaRecord mediaRecord) {
|
||||
private void handleMediaMultiSelectClick(@NonNull DcMsg mediaRecord) {
|
||||
MediaGalleryAdapter adapter = getListAdapter();
|
||||
|
||||
adapter.toggleSelection(mediaRecord);
|
||||
@@ -277,8 +278,8 @@ public class MediaOverviewActivity extends PassphraseRequiredActionBarActivity
|
||||
}
|
||||
}
|
||||
|
||||
private void handleMediaPreviewClick(@NonNull MediaDatabase.MediaRecord mediaRecord) {
|
||||
if (mediaRecord.getAttachment().getDataUri() == null) {
|
||||
private void handleMediaPreviewClick(@NonNull DcMsg mediaRecord) {
|
||||
if (mediaRecord.getFile() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -288,18 +289,15 @@ public class MediaOverviewActivity extends PassphraseRequiredActionBarActivity
|
||||
}
|
||||
|
||||
Intent intent = new Intent(context, MediaPreviewActivity.class);
|
||||
intent.putExtra(MediaPreviewActivity.DATE_EXTRA, mediaRecord.getDate());
|
||||
intent.putExtra(MediaPreviewActivity.SIZE_EXTRA, mediaRecord.getAttachment().getSize());
|
||||
intent.putExtra(MediaPreviewActivity.DC_MSG_ID, mediaRecord.getId());
|
||||
intent.putExtra(MediaPreviewActivity.ADDRESS_EXTRA, recipient.getAddress());
|
||||
intent.putExtra(MediaPreviewActivity.OUTGOING_EXTRA, mediaRecord.isOutgoing());
|
||||
intent.putExtra(MediaPreviewActivity.LEFT_IS_RECENT_EXTRA, true);
|
||||
|
||||
intent.setDataAndType(mediaRecord.getAttachment().getDataUri(), mediaRecord.getContentType());
|
||||
context.startActivity(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMediaLongClicked(MediaDatabase.MediaRecord mediaRecord) {
|
||||
public void onMediaLongClicked(DcMsg mediaRecord) {
|
||||
if (actionMode == null) {
|
||||
((MediaGalleryAdapter) recyclerView.getAdapter()).toggleSelection(mediaRecord);
|
||||
recyclerView.getAdapter().notifyDataSetChanged();
|
||||
@@ -309,7 +307,7 @@ public class MediaOverviewActivity extends PassphraseRequiredActionBarActivity
|
||||
}
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
private void handleDeleteMedia(@NonNull Collection<MediaDatabase.MediaRecord> mediaRecords) {
|
||||
private void handleDeleteMedia(@NonNull Collection<DcMsg> mediaRecords) {
|
||||
int recordCount = mediaRecords.size();
|
||||
Resources res = getContext().getResources();
|
||||
String confirmTitle = res.getQuantityString(R.plurals.MediaOverviewActivity_Media_delete_confirm_title,
|
||||
@@ -324,25 +322,26 @@ public class MediaOverviewActivity extends PassphraseRequiredActionBarActivity
|
||||
builder.setTitle(confirmTitle);
|
||||
builder.setMessage(confirmMessage);
|
||||
builder.setCancelable(true);
|
||||
final DcContext dcContext = DcHelper.getContext(getContext());
|
||||
|
||||
builder.setPositiveButton(R.string.delete, (dialogInterface, i) -> {
|
||||
new ProgressDialogAsyncTask<MediaDatabase.MediaRecord, Void, Void>(getContext(),
|
||||
new ProgressDialogAsyncTask<DcMsg, Void, Void>(getContext(),
|
||||
R.string.MediaOverviewActivity_Media_delete_progress_title,
|
||||
R.string.MediaOverviewActivity_Media_delete_progress_message)
|
||||
{
|
||||
@Override
|
||||
protected Void doInBackground(MediaDatabase.MediaRecord... records) {
|
||||
protected Void doInBackground(DcMsg... records) {
|
||||
if (records == null || records.length == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (MediaDatabase.MediaRecord record : records) {
|
||||
AttachmentUtil.deleteAttachment(getContext(), record.getAttachment());
|
||||
for (DcMsg record : records) {
|
||||
dcContext.deleteMsgs(new int[]{record.getId()});
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}.execute(mediaRecords.toArray(new MediaDatabase.MediaRecord[mediaRecords.size()]));
|
||||
}.execute(mediaRecords.toArray(new DcMsg[mediaRecords.size()]));
|
||||
});
|
||||
builder.setNegativeButton(android.R.string.cancel, null);
|
||||
builder.show();
|
||||
|
||||
@@ -20,9 +20,7 @@ import android.Manifest;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build.VERSION;
|
||||
@@ -32,7 +30,6 @@ import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.LoaderManager;
|
||||
import android.support.v4.content.Loader;
|
||||
import android.support.v4.util.Pair;
|
||||
import android.support.v4.view.PagerAdapter;
|
||||
import android.support.v4.view.ViewPager;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
@@ -48,21 +45,20 @@ import android.view.WindowManager;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.thoughtcrime.securesms.attachments.AttachmentId;
|
||||
import org.thoughtcrime.securesms.attachments.DatabaseAttachment;
|
||||
import com.b44t.messenger.DcContext;
|
||||
import com.b44t.messenger.DcMediaGalleryElement;
|
||||
import com.b44t.messenger.DcMsg;
|
||||
|
||||
import org.thoughtcrime.securesms.components.MediaView;
|
||||
import org.thoughtcrime.securesms.components.viewpager.ExtendedOnPageChangedListener;
|
||||
import org.thoughtcrime.securesms.connect.DcHelper;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.database.AttachmentDatabase;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.MediaDatabase.MediaRecord;
|
||||
import org.thoughtcrime.securesms.database.loaders.PagingMediaLoader;
|
||||
import org.thoughtcrime.securesms.mms.GlideApp;
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||
import org.thoughtcrime.securesms.permissions.Permissions;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
|
||||
import org.thoughtcrime.securesms.util.AttachmentUtil;
|
||||
import org.thoughtcrime.securesms.util.DateUtils;
|
||||
import org.thoughtcrime.securesms.util.DynamicLanguage;
|
||||
import org.thoughtcrime.securesms.util.SaveAttachmentTask;
|
||||
@@ -75,22 +71,29 @@ import java.util.WeakHashMap;
|
||||
/**
|
||||
* Activity for displaying media attachments in-app
|
||||
*/
|
||||
public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity implements RecipientModifiedListener, LoaderManager.LoaderCallbacks<Pair<Cursor, Integer>> {
|
||||
public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity
|
||||
implements RecipientModifiedListener, LoaderManager.LoaderCallbacks<DcMediaGalleryElement> {
|
||||
|
||||
private final static String TAG = MediaPreviewActivity.class.getSimpleName();
|
||||
|
||||
public static final String ADDRESS_EXTRA = "address";
|
||||
public static final String DATE_EXTRA = "date";
|
||||
public static final String SIZE_EXTRA = "size";
|
||||
public static final String OUTGOING_EXTRA = "outgoing";
|
||||
public static final String LEFT_IS_RECENT_EXTRA = "left_is_recent";
|
||||
public static final String DC_MSG_ID = "dc_msg_id";
|
||||
|
||||
/** USE ONLY IF YOU HAVE NO MESSAGE ID! */
|
||||
public static final String DATE_EXTRA = "date";
|
||||
|
||||
/** USE ONLY IF YOU HAVE NO MESSAGE ID! */
|
||||
public static final String SIZE_EXTRA = "size";
|
||||
|
||||
private final DynamicLanguage dynamicLanguage = new DynamicLanguage();
|
||||
|
||||
@Nullable
|
||||
private DcMsg messageRecord;
|
||||
private DcContext dcContext;
|
||||
private MediaItem initialMedia;
|
||||
private ViewPager mediaPager;
|
||||
private Uri initialMediaUri;
|
||||
private String initialMediaType;
|
||||
private long initialMediaSize;
|
||||
private Recipient conversationRecipient;
|
||||
private boolean leftIsRecent;
|
||||
|
||||
@@ -181,32 +184,51 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity im
|
||||
private void initializeResources() {
|
||||
Address address = getIntent().getParcelableExtra(ADDRESS_EXTRA);
|
||||
|
||||
initialMediaUri = getIntent().getData();
|
||||
initialMediaType = getIntent().getType();
|
||||
initialMediaSize = getIntent().getLongExtra(SIZE_EXTRA, 0);
|
||||
final Context context = getApplicationContext();
|
||||
this.dcContext = DcHelper.getContext(context);
|
||||
final int msgId = getIntent().getIntExtra(DC_MSG_ID, DcMsg.DC_MSG_NO_ID);
|
||||
|
||||
if(msgId == DcMsg.DC_MSG_NO_ID) {
|
||||
messageRecord = null;
|
||||
long date = getIntent().getLongExtra(DATE_EXTRA, 0);
|
||||
long size = getIntent().getLongExtra(SIZE_EXTRA, 0);
|
||||
initialMedia = new MediaItem(null, getIntent().getData(), getIntent().getType(),
|
||||
DcMsg.DC_MSG_NO_ID, date, size, false);
|
||||
|
||||
if (address != null) {
|
||||
conversationRecipient = Recipient.from(context, address, false);
|
||||
} else {
|
||||
conversationRecipient = null;
|
||||
}
|
||||
} else {
|
||||
messageRecord = dcContext.getMsg(msgId);
|
||||
initialMedia = new MediaItem(Recipient.from(context, msgId), Uri.fromFile(messageRecord.getFileAsFile()),
|
||||
messageRecord.getFilemime(), messageRecord.getId(), messageRecord.getDateReceived(),
|
||||
messageRecord.getFilebytes(), messageRecord.isOutgoing());
|
||||
conversationRecipient = Recipient.from(context, msgId);
|
||||
}
|
||||
leftIsRecent = getIntent().getBooleanExtra(LEFT_IS_RECENT_EXTRA, false);
|
||||
restartItem = -1;
|
||||
|
||||
if (address != null) {
|
||||
conversationRecipient = Recipient.from(this, address, true);
|
||||
} else {
|
||||
conversationRecipient = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void initializeMedia() {
|
||||
if (!isContentTypeSupported(initialMediaType)) {
|
||||
|
||||
// if you search for the place where the media are loaded, go to 'onCreateLoader'.
|
||||
|
||||
if (!isContentTypeSupported(initialMedia.type)) {
|
||||
Log.w(TAG, "Unsupported media type sent to MediaPreviewActivity, finishing.");
|
||||
Toast.makeText(getApplicationContext(), R.string.MediaPreviewActivity_unssuported_media_type, Toast.LENGTH_LONG).show();
|
||||
finish();
|
||||
}
|
||||
|
||||
Log.w(TAG, "Loading Part URI: " + initialMediaUri);
|
||||
Log.w(TAG, "Loading Part URI: " + initialMedia);
|
||||
|
||||
if (conversationRecipient != null) {
|
||||
if (messageRecord != null) {
|
||||
getSupportLoaderManager().restartLoader(0, null, this);
|
||||
} else {
|
||||
mediaPager.setAdapter(new SingleItemPagerAdapter(this, GlideApp.with(this), getWindow(), initialMediaUri, initialMediaType, initialMediaSize));
|
||||
mediaPager.setAdapter(new SingleItemPagerAdapter(this, GlideApp.with(this),
|
||||
getWindow(), initialMedia.uri, initialMedia.type, initialMedia.size));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -261,7 +283,7 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity im
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
private void deleteMedia() {
|
||||
MediaItem mediaItem = getCurrentMediaItem();
|
||||
if (mediaItem == null || mediaItem.attachment == null) {
|
||||
if (mediaItem == null || mediaItem.msgId == DcMsg.DC_MSG_NO_ID) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -275,11 +297,10 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity im
|
||||
new AsyncTask<Void, Void, Void>() {
|
||||
@Override
|
||||
protected Void doInBackground(Void... voids) {
|
||||
if (mediaItem.attachment == null) {
|
||||
if (mediaItem.msgId == DcMsg.DC_MSG_NO_ID) {
|
||||
return null;
|
||||
}
|
||||
AttachmentUtil.deleteAttachment(MediaPreviewActivity.this.getApplicationContext(),
|
||||
mediaItem.attachment);
|
||||
dcContext.deleteMsgs(new int[]{mediaItem.msgId});
|
||||
return null;
|
||||
}
|
||||
}.execute();
|
||||
@@ -340,25 +361,26 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity im
|
||||
}
|
||||
|
||||
@Override
|
||||
public Loader<Pair<Cursor, Integer>> onCreateLoader(int id, Bundle args) {
|
||||
return new PagingMediaLoader(this, conversationRecipient, initialMediaUri, leftIsRecent);
|
||||
public Loader<DcMediaGalleryElement> onCreateLoader(int id, Bundle args) {
|
||||
return new PagingMediaLoader(this, messageRecord, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadFinished(Loader<Pair<Cursor, Integer>> loader, @Nullable Pair<Cursor, Integer> data) {
|
||||
public void onLoadFinished(Loader<DcMediaGalleryElement> loader, @Nullable DcMediaGalleryElement data) {
|
||||
if (data != null) {
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
CursorPagerAdapter adapter = new CursorPagerAdapter(this, GlideApp.with(this), getWindow(), data.first, data.second, leftIsRecent);
|
||||
DcMediaPagerAdapter adapter = new DcMediaPagerAdapter(this, GlideApp.with(this),
|
||||
getWindow(), data, leftIsRecent);
|
||||
mediaPager.setAdapter(adapter);
|
||||
adapter.setActive(true);
|
||||
|
||||
if (restartItem < 0) mediaPager.setCurrentItem(data.second);
|
||||
if (restartItem < 0) mediaPager.setCurrentItem(data.getPosition());
|
||||
else mediaPager.setCurrentItem(restartItem);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoaderReset(Loader<Pair<Cursor, Integer>> loader) {
|
||||
public void onLoaderReset(Loader<DcMediaGalleryElement> loader) {
|
||||
|
||||
}
|
||||
|
||||
@@ -450,7 +472,7 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity im
|
||||
|
||||
@Override
|
||||
public MediaItem getMediaItemFor(int position) {
|
||||
return new MediaItem(null, null, uri, mediaType, -1, true);
|
||||
return new MediaItem(null, uri, mediaType, DcMsg.DC_MSG_NO_ID, -1, -1, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -459,29 +481,29 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity im
|
||||
}
|
||||
}
|
||||
|
||||
private static class CursorPagerAdapter extends PagerAdapter implements MediaItemAdapter {
|
||||
private static class DcMediaPagerAdapter extends PagerAdapter implements MediaItemAdapter {
|
||||
|
||||
private final WeakHashMap<Integer, MediaView> mediaViews = new WeakHashMap<>();
|
||||
|
||||
private final Context context;
|
||||
private final GlideRequests glideRequests;
|
||||
private final Window window;
|
||||
private final Cursor cursor;
|
||||
private final DcMediaGalleryElement gallery;
|
||||
private final boolean leftIsRecent;
|
||||
|
||||
private boolean active;
|
||||
private int autoPlayPosition;
|
||||
|
||||
CursorPagerAdapter(@NonNull Context context, @NonNull GlideRequests glideRequests,
|
||||
@NonNull Window window, @NonNull Cursor cursor, int autoPlayPosition,
|
||||
DcMediaPagerAdapter(@NonNull Context context, @NonNull GlideRequests glideRequests,
|
||||
@NonNull Window window, @NonNull DcMediaGalleryElement gallery,
|
||||
boolean leftIsRecent)
|
||||
{
|
||||
this.context = context.getApplicationContext();
|
||||
this.glideRequests = glideRequests;
|
||||
this.window = window;
|
||||
this.cursor = cursor;
|
||||
this.autoPlayPosition = autoPlayPosition;
|
||||
this.gallery = gallery;
|
||||
this.leftIsRecent = leftIsRecent;
|
||||
this.autoPlayPosition = gallery.getPosition();
|
||||
}
|
||||
|
||||
public void setActive(boolean active) {
|
||||
@@ -492,7 +514,7 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity im
|
||||
@Override
|
||||
public int getCount() {
|
||||
if (!active) return 0;
|
||||
else return cursor.getCount();
|
||||
else return gallery.getCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -509,13 +531,14 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity im
|
||||
|
||||
autoPlayPosition = -1;
|
||||
|
||||
cursor.moveToPosition(cursorPosition);
|
||||
gallery.moveToPosition(cursorPosition);
|
||||
|
||||
MediaRecord mediaRecord = MediaRecord.from(context, cursor);
|
||||
DcMsg msg = gallery.getMessage();
|
||||
|
||||
try {
|
||||
//noinspection ConstantConditions
|
||||
mediaView.set(glideRequests, window, mediaRecord.getAttachment().getDataUri(), mediaRecord.getAttachment().getContentType(), mediaRecord.getAttachment().getSize(), autoplay);
|
||||
mediaView.set(glideRequests, window, Uri.fromFile(msg.getFileAsFile()),
|
||||
msg.getFilemime(), msg.getFilebytes(), autoplay);
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
@@ -536,18 +559,18 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity im
|
||||
}
|
||||
|
||||
public MediaItem getMediaItemFor(int position) {
|
||||
cursor.moveToPosition(getCursorPosition(position));
|
||||
MediaRecord mediaRecord = MediaRecord.from(context, cursor);
|
||||
Address address = mediaRecord.getAddress();
|
||||
gallery.moveToPosition(getCursorPosition(position));
|
||||
DcMsg msg = gallery.getMessage();
|
||||
|
||||
if (mediaRecord.getAttachment().getDataUri() == null) throw new AssertionError();
|
||||
if (msg.getFile() == null) throw new AssertionError();
|
||||
|
||||
return new MediaItem(address != null ? Recipient.from(context, address,true) : null,
|
||||
mediaRecord.getAttachment(),
|
||||
mediaRecord.getAttachment().getDataUri(),
|
||||
mediaRecord.getContentType(),
|
||||
mediaRecord.getDate(),
|
||||
mediaRecord.isOutgoing());
|
||||
return new MediaItem(Recipient.from(context, msg.getId()),
|
||||
Uri.fromFile(msg.getFileAsFile()),
|
||||
msg.getFilemime(),
|
||||
msg.getId(),
|
||||
msg.getDateReceived(),
|
||||
msg.getFilebytes(),
|
||||
msg.isOutgoing());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -558,30 +581,33 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity im
|
||||
|
||||
private int getCursorPosition(int position) {
|
||||
if (leftIsRecent) return position;
|
||||
else return cursor.getCount() - 1 - position;
|
||||
else return gallery.getCount() - 1 - position;
|
||||
}
|
||||
}
|
||||
|
||||
private static class MediaItem {
|
||||
private final @Nullable Recipient recipient;
|
||||
private final @Nullable DatabaseAttachment attachment;
|
||||
private final @NonNull Uri uri;
|
||||
private final @NonNull String type;
|
||||
private final int msgId;
|
||||
private final long date;
|
||||
private final long size;
|
||||
private final boolean outgoing;
|
||||
|
||||
private MediaItem(@Nullable Recipient recipient,
|
||||
@Nullable DatabaseAttachment attachment,
|
||||
@NonNull Uri uri,
|
||||
@NonNull String type,
|
||||
int msgId,
|
||||
long date,
|
||||
long size,
|
||||
boolean outgoing)
|
||||
{
|
||||
this.recipient = recipient;
|
||||
this.attachment = attachment;
|
||||
this.uri = uri;
|
||||
this.type = type;
|
||||
this.msgId = msgId;
|
||||
this.date = date;
|
||||
this.size = size;
|
||||
this.outgoing = outgoing;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,8 +167,11 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
|
||||
Intent intent = new Intent(RecipientPreferenceActivity.this, MediaPreviewActivity.class);
|
||||
intent.putExtra(MediaPreviewActivity.ADDRESS_EXTRA, address);
|
||||
intent.putExtra(MediaPreviewActivity.OUTGOING_EXTRA, mediaRecord.isOutgoing());
|
||||
intent.putExtra(MediaPreviewActivity.DATE_EXTRA, mediaRecord.getDate());
|
||||
intent.putExtra(MediaPreviewActivity.SIZE_EXTRA, mediaRecord.getAttachment().getSize());
|
||||
Log.e(TAG, "MEDIA PREVIEW NOT IMPLEMENTED HERE must have dcMsgId in Media Record first!");
|
||||
if(true)
|
||||
throw new IllegalStateException("Media Preview not implemented");
|
||||
/* intent.putExtra(MediaPreviewActivity.DATE_EXTRA, mediaRecord.getDate());
|
||||
intent.putExtra(MediaPreviewActivity.SIZE_EXTRA, mediaRecord.getAttachment().getSize());*/
|
||||
intent.putExtra(MediaPreviewActivity.LEFT_IS_RECENT_EXTRA, ViewCompat.getLayoutDirection(threadPhotoRailView) == ViewCompat.LAYOUT_DIRECTION_LTR);
|
||||
intent.setDataAndType(mediaRecord.getAttachment().getDataUri(), mediaRecord.getContentType());
|
||||
startActivity(intent);
|
||||
@@ -192,13 +195,13 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
|
||||
}
|
||||
|
||||
private void setHeader(@NonNull Recipient recipient) {
|
||||
glideRequests.load(recipient.getContactPhoto())
|
||||
glideRequests.load(recipient.getContactPhoto(this))
|
||||
.fallback(recipient.getFallbackContactPhoto().asCallCard(this))
|
||||
.error(recipient.getFallbackContactPhoto().asCallCard(this))
|
||||
.diskCacheStrategy(DiskCacheStrategy.ALL)
|
||||
.into(this.avatar);
|
||||
|
||||
if (recipient.getContactPhoto() == null) this.avatar.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
|
||||
if (recipient.getContactPhoto(this) == null) this.avatar.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
|
||||
else this.avatar.setScaleType(ImageView.ScaleType.CENTER_CROP);
|
||||
|
||||
this.avatar.setBackgroundColor(recipient.getColor().toActionBarColor(this));
|
||||
|
||||
@@ -1,19 +1,17 @@
|
||||
package org.thoughtcrime.securesms.components;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.TypedArray;
|
||||
import android.provider.ContactsContract;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.widget.AppCompatImageView;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.contacts.avatars.ContactColors;
|
||||
import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto;
|
||||
import org.thoughtcrime.securesms.contacts.avatars.GeneratedContactPhoto;
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
@@ -49,7 +47,8 @@ public class AvatarImageView extends AppCompatImageView {
|
||||
|
||||
public void setAvatar(@NonNull GlideRequests requestManager, @Nullable Recipient recipient, boolean quickContactEnabled) {
|
||||
if (recipient != null) {
|
||||
requestManager.load(recipient.getContactPhoto())
|
||||
ContactPhoto contactPhoto = recipient.getContactPhoto(getContext());
|
||||
requestManager.load(contactPhoto)
|
||||
.fallback(recipient.getFallbackContactPhotoDrawable(getContext(), inverted))
|
||||
.error(recipient.getFallbackContactPhotoDrawable(getContext(), inverted))
|
||||
.diskCacheStrategy(DiskCacheStrategy.ALL)
|
||||
|
||||
@@ -293,7 +293,7 @@ public class WebRtcCallScreen extends FrameLayout implements RecipientModifiedLi
|
||||
this.recipient.addListener(this);
|
||||
|
||||
GlideApp.with(getContext().getApplicationContext())
|
||||
.load(recipient.getContactPhoto())
|
||||
.load(recipient.getContactPhoto(getContext()))
|
||||
.fallback(recipient.getFallbackContactPhoto().asCallCard(getContext()))
|
||||
.error(recipient.getFallbackContactPhoto().asCallCard(getContext()))
|
||||
.diskCacheStrategy(DiskCacheStrategy.ALL)
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
package org.thoughtcrime.securesms;
|
||||
|
||||
public class IncomingMessageNotifier {
|
||||
}
|
||||
@@ -6,37 +6,32 @@ import android.net.Uri;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import org.thoughtcrime.securesms.connect.DcHelper;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.GroupDatabase;
|
||||
import org.thoughtcrime.securesms.util.Conversions;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.MessageDigest;
|
||||
|
||||
public class GroupRecordContactPhoto implements ContactPhoto {
|
||||
|
||||
private final @NonNull Address address;
|
||||
private final long avatarId;
|
||||
private final int chatId;
|
||||
|
||||
public GroupRecordContactPhoto(@NonNull Address address, long avatarId) {
|
||||
this.address = address;
|
||||
this.avatarId = avatarId;
|
||||
private final Address address;
|
||||
|
||||
private final String path;
|
||||
|
||||
public GroupRecordContactPhoto(Context context, Address address) {
|
||||
this.address = address;
|
||||
chatId = address.getDcChatId();
|
||||
path = DcHelper.getContext(context).getChat(chatId).getProfileImage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream openInputStream(Context context) throws IOException {
|
||||
GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
|
||||
Optional<GroupDatabase.GroupRecord> groupRecord = groupDatabase.getGroup(address.toGroupString());
|
||||
|
||||
if (groupRecord.isPresent() && groupRecord.get().getAvatar() != null) {
|
||||
return new ByteArrayInputStream(groupRecord.get().getAvatar());
|
||||
}
|
||||
|
||||
throw new IOException("Couldn't load avatar for group: " + address.toGroupString());
|
||||
return new FileInputStream(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -52,7 +47,8 @@ public class GroupRecordContactPhoto implements ContactPhoto {
|
||||
@Override
|
||||
public void updateDiskCacheKey(MessageDigest messageDigest) {
|
||||
messageDigest.update(address.serialize().getBytes());
|
||||
messageDigest.update(Conversions.longToByteArray(avatarId));
|
||||
messageDigest.update(Conversions.longToByteArray(chatId));
|
||||
messageDigest.update(path.getBytes());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -60,12 +56,12 @@ public class GroupRecordContactPhoto implements ContactPhoto {
|
||||
if (other == null || !(other instanceof GroupRecordContactPhoto)) return false;
|
||||
|
||||
GroupRecordContactPhoto that = (GroupRecordContactPhoto)other;
|
||||
return this.address.equals(that.address) && this.avatarId == that.avatarId;
|
||||
return this.address.equals(that.address) && this.chatId == that.chatId && this.path.equals(that.path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.address.hashCode() ^ (int) avatarId;
|
||||
return this.address.hashCode() ^ chatId;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -288,7 +288,7 @@ public class ContactRepository {
|
||||
@WorkerThread
|
||||
private @Nullable AvatarInfo getRecipientAvatarInfo(@NonNull Address address) {
|
||||
Recipient recipient = Recipient.from(context, address, false);
|
||||
ContactPhoto contactPhoto = recipient.getContactPhoto();
|
||||
ContactPhoto contactPhoto = recipient.getContactPhoto(context);
|
||||
|
||||
if (contactPhoto != null) {
|
||||
Uri avatarUri = contactPhoto.getUri(context);
|
||||
|
||||
@@ -47,6 +47,9 @@ public class Address implements Parcelable, Comparable<Address> {
|
||||
|
||||
public static final Address UNKNOWN = new Address("Unknown");
|
||||
|
||||
private final static String DC_CHAT_PREFIX = "dc:";
|
||||
private final static String DC_CONTACT_PREFIX = "dcc:";
|
||||
|
||||
private static final String TAG = Address.class.getSimpleName();
|
||||
|
||||
private static final AtomicReference<Pair<String, ExternalAddressFormatter>> cachedFormatter = new AtomicReference<>();
|
||||
@@ -54,11 +57,11 @@ public class Address implements Parcelable, Comparable<Address> {
|
||||
private final String address;
|
||||
|
||||
public static Address fromChat(int chatId) {
|
||||
return new Address("dc:" + chatId);
|
||||
return new Address(DC_CHAT_PREFIX + chatId);
|
||||
}
|
||||
|
||||
public static Address fromContact(int contactId) {
|
||||
return new Address("dcc:" + contactId);
|
||||
return new Address(DC_CONTACT_PREFIX + contactId);
|
||||
}
|
||||
|
||||
private Address(@NonNull String address) {
|
||||
@@ -134,9 +137,9 @@ public class Address implements Parcelable, Comparable<Address> {
|
||||
return !isGroup() && !isEmail();
|
||||
}
|
||||
|
||||
public boolean isDcChat() { return address.startsWith("dc:"); };
|
||||
public boolean isDcChat() { return address.startsWith(DC_CHAT_PREFIX); };
|
||||
|
||||
public boolean isDcContact() { return address.startsWith("dcc:"); };
|
||||
public boolean isDcContact() { return address.startsWith(DC_CONTACT_PREFIX); };
|
||||
|
||||
public @NonNull String toGroupString() {
|
||||
if (!isGroup()) throw new AssertionError("Not group: " + address);
|
||||
@@ -155,12 +158,12 @@ public class Address implements Parcelable, Comparable<Address> {
|
||||
|
||||
public int getDcChatId() {
|
||||
if(!isDcChat()) throw new AssertionError("Not dc chat: " + address);
|
||||
return Integer.valueOf(address.substring("dc:".length()));
|
||||
return Integer.valueOf(address.substring(DC_CHAT_PREFIX.length()));
|
||||
}
|
||||
|
||||
public int getDcContactId() {
|
||||
if(!isDcContact()) throw new AssertionError("Not dc contact: " + address);
|
||||
return Integer.valueOf(address.substring("dcc:".length()));
|
||||
return Integer.valueOf(address.substring(DC_CONTACT_PREFIX.length()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -2,19 +2,16 @@ package org.thoughtcrime.securesms.database.loaders;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.ContentObserver;
|
||||
import android.database.Cursor;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.content.AsyncTaskLoader;
|
||||
|
||||
import com.annimon.stream.Stream;
|
||||
import com.b44t.messenger.DcContext;
|
||||
import com.b44t.messenger.DcMsg;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.connect.DcHelper;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.database.Database;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.MediaDatabase;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
@@ -33,12 +30,10 @@ public class BucketedThreadMediaLoader extends AsyncTaskLoader<BucketedThreadMed
|
||||
private static final String TAG = BucketedThreadMediaLoader.class.getSimpleName();
|
||||
|
||||
private final Address address;
|
||||
private final ContentObserver observer;
|
||||
|
||||
public BucketedThreadMediaLoader(@NonNull Context context, @NonNull Address address) {
|
||||
super(context);
|
||||
this.address = address;
|
||||
this.observer = new ForceLoadContentObserver();
|
||||
|
||||
onContentChanged();
|
||||
}
|
||||
@@ -57,19 +52,15 @@ public class BucketedThreadMediaLoader extends AsyncTaskLoader<BucketedThreadMed
|
||||
|
||||
@Override
|
||||
protected void onAbandon() {
|
||||
DatabaseFactory.getMediaDatabase(getContext()).unsubscribeToMediaChanges(observer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BucketedThreadMedia loadInBackground() {
|
||||
BucketedThreadMedia result = new BucketedThreadMedia(getContext());
|
||||
long threadId = DatabaseFactory.getThreadDatabase(getContext()).getThreadIdFor(Recipient.from(getContext(), address, true));
|
||||
|
||||
DatabaseFactory.getMediaDatabase(getContext()).subscribeToMediaChanges(observer);
|
||||
try (Cursor cursor = DatabaseFactory.getMediaDatabase(getContext()).getGalleryMediaForThread(threadId)) {
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
result.add(MediaDatabase.MediaRecord.from(getContext(), cursor));
|
||||
}
|
||||
DcContext context = DcHelper.getContext(getContext());
|
||||
int[] messages = context.getChatMedia(address.getDcChatId(), DcMsg.DC_MSG_GIF, DcMsg.DC_MSG_IMAGE);
|
||||
for(int nextId : messages) {
|
||||
result.add(context.getMsg(nextId));
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -86,7 +77,7 @@ public class BucketedThreadMediaLoader extends AsyncTaskLoader<BucketedThreadMed
|
||||
private final TimeBucket[] TIME_SECTIONS;
|
||||
|
||||
public BucketedThreadMedia(@NonNull Context context) {
|
||||
this.TODAY = new TimeBucket(context.getString(R.string.BucketedThreadMedia_Today), TimeBucket.addToCalendar(Calendar.DAY_OF_YEAR, -1), TimeBucket.addToCalendar(Calendar.DAY_OF_YEAR, 1000));
|
||||
this.TODAY = new TimeBucket(context.getString(R.string.BucketedThreadMedia_Today), TimeBucket.addToCalendar(Calendar.DAY_OF_YEAR, -1), TimeBucket.addToCalendar(Calendar.YEAR, 1000));
|
||||
this.YESTERDAY = new TimeBucket(context.getString(R.string.BucketedThreadMedia_Yesterday), TimeBucket.addToCalendar(Calendar.DAY_OF_YEAR, -2), TimeBucket.addToCalendar(Calendar.DAY_OF_YEAR, -1));
|
||||
this.THIS_WEEK = new TimeBucket(context.getString(R.string.BucketedThreadMedia_This_week), TimeBucket.addToCalendar(Calendar.DAY_OF_YEAR, -7), TimeBucket.addToCalendar(Calendar.DAY_OF_YEAR, -2));
|
||||
this.THIS_MONTH = new TimeBucket(context.getString(R.string.BucketedThreadMedia_This_month), TimeBucket.addToCalendar(Calendar.DAY_OF_YEAR, -30), TimeBucket.addToCalendar(Calendar.DAY_OF_YEAR, -7));
|
||||
@@ -94,16 +85,14 @@ public class BucketedThreadMediaLoader extends AsyncTaskLoader<BucketedThreadMed
|
||||
this.OLDER = new MonthBuckets();
|
||||
}
|
||||
|
||||
|
||||
public void add(MediaDatabase.MediaRecord mediaRecord) {
|
||||
public void add(DcMsg imageMessage) {
|
||||
for (TimeBucket timeSection : TIME_SECTIONS) {
|
||||
if (timeSection.inRange(mediaRecord.getDate())) {
|
||||
timeSection.add(mediaRecord);
|
||||
if (timeSection.inRange(imageMessage.getTimestamp())) {
|
||||
timeSection.add(imageMessage);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
OLDER.add(mediaRecord);
|
||||
OLDER.add(imageMessage);
|
||||
}
|
||||
|
||||
public int getSectionCount() {
|
||||
@@ -120,7 +109,7 @@ public class BucketedThreadMediaLoader extends AsyncTaskLoader<BucketedThreadMed
|
||||
else return OLDER.getSectionItemCount(section - activeTimeBuckets.size());
|
||||
}
|
||||
|
||||
public MediaDatabase.MediaRecord get(int section, int item) {
|
||||
public DcMsg get(int section, int item) {
|
||||
List<TimeBucket> activeTimeBuckets = Stream.of(TIME_SECTIONS).filter(timeBucket -> !timeBucket.isEmpty()).toList();
|
||||
|
||||
if (section < activeTimeBuckets.size()) return activeTimeBuckets.get(section).getItem(item);
|
||||
@@ -136,24 +125,24 @@ public class BucketedThreadMediaLoader extends AsyncTaskLoader<BucketedThreadMed
|
||||
|
||||
private static class TimeBucket {
|
||||
|
||||
private final List<MediaDatabase.MediaRecord> records = new LinkedList<>();
|
||||
private final List<DcMsg> records = new LinkedList<>();
|
||||
|
||||
private final long startTime;
|
||||
private final long endtime;
|
||||
private final long endTime;
|
||||
private final String name;
|
||||
|
||||
TimeBucket(String name, long startTime, long endtime) {
|
||||
TimeBucket(String name, long startTime, long endTime) {
|
||||
this.name = name;
|
||||
this.startTime = startTime;
|
||||
this.endtime = endtime;
|
||||
this.endTime = endTime;
|
||||
}
|
||||
|
||||
void add(MediaDatabase.MediaRecord record) {
|
||||
void add(DcMsg record) {
|
||||
this.records.add(record);
|
||||
}
|
||||
|
||||
boolean inRange(long timestamp) {
|
||||
return timestamp > startTime && timestamp <= endtime;
|
||||
return timestamp > startTime && timestamp <= endTime;
|
||||
}
|
||||
|
||||
boolean isEmpty() {
|
||||
@@ -164,7 +153,7 @@ public class BucketedThreadMediaLoader extends AsyncTaskLoader<BucketedThreadMed
|
||||
return records.size();
|
||||
}
|
||||
|
||||
MediaDatabase.MediaRecord getItem(int position) {
|
||||
DcMsg getItem(int position) {
|
||||
return records.get(position);
|
||||
}
|
||||
|
||||
@@ -181,11 +170,11 @@ public class BucketedThreadMediaLoader extends AsyncTaskLoader<BucketedThreadMed
|
||||
|
||||
private static class MonthBuckets {
|
||||
|
||||
private final Map<Date, List<MediaDatabase.MediaRecord>> months = new HashMap<>();
|
||||
private final Map<Date, List<DcMsg>> months = new HashMap<>();
|
||||
|
||||
void add(MediaDatabase.MediaRecord record) {
|
||||
void add(DcMsg record) {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTimeInMillis(record.getDate());
|
||||
calendar.setTimeInMillis(record.getTimestamp());
|
||||
|
||||
int year = calendar.get(Calendar.YEAR) - 1900;
|
||||
int month = calendar.get(Calendar.MONTH);
|
||||
@@ -194,7 +183,7 @@ public class BucketedThreadMediaLoader extends AsyncTaskLoader<BucketedThreadMed
|
||||
if (months.containsKey(date)) {
|
||||
months.get(date).add(record);
|
||||
} else {
|
||||
List<MediaDatabase.MediaRecord> list = new LinkedList<>();
|
||||
List<DcMsg> list = new LinkedList<>();
|
||||
list.add(record);
|
||||
months.put(date, list);
|
||||
}
|
||||
@@ -208,7 +197,7 @@ public class BucketedThreadMediaLoader extends AsyncTaskLoader<BucketedThreadMed
|
||||
return months.get(getSection(section)).size();
|
||||
}
|
||||
|
||||
MediaDatabase.MediaRecord getItem(int section, int position) {
|
||||
DcMsg getItem(int section, int position) {
|
||||
return months.get(getSection(section)).get(position);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,50 +2,50 @@ package org.thoughtcrime.securesms.database.loaders;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.util.Pair;
|
||||
import android.util.Log;
|
||||
|
||||
import org.thoughtcrime.securesms.attachments.AttachmentId;
|
||||
import org.thoughtcrime.securesms.database.AttachmentDatabase;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.mms.PartAuthority;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import com.b44t.messenger.DcContext;
|
||||
import com.b44t.messenger.DcMediaGalleryElement;
|
||||
import com.b44t.messenger.DcMsg;
|
||||
|
||||
import org.thoughtcrime.securesms.connect.DcHelper;
|
||||
import org.thoughtcrime.securesms.util.AsyncLoader;
|
||||
|
||||
public class PagingMediaLoader extends AsyncLoader<Pair<Cursor, Integer>> {
|
||||
public class PagingMediaLoader extends AsyncLoader<DcMediaGalleryElement> {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static final String TAG = PagingMediaLoader.class.getSimpleName();
|
||||
|
||||
private final Recipient recipient;
|
||||
private final Uri uri;
|
||||
private final DcMsg msg;
|
||||
private final boolean leftIsRecent;
|
||||
|
||||
public PagingMediaLoader(@NonNull Context context, @NonNull Recipient recipient, @NonNull Uri uri, boolean leftIsRecent) {
|
||||
public PagingMediaLoader(@NonNull Context context, @NonNull DcMsg msg, boolean leftIsRecent) {
|
||||
super(context);
|
||||
this.recipient = recipient;
|
||||
this.uri = uri;
|
||||
this.msg = msg;
|
||||
this.leftIsRecent = leftIsRecent;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Pair<Cursor, Integer> loadInBackground() {
|
||||
long threadId = DatabaseFactory.getThreadDatabase(getContext()).getThreadIdFor(recipient);
|
||||
Cursor cursor = DatabaseFactory.getMediaDatabase(getContext()).getGalleryMediaForThread(threadId);
|
||||
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
AttachmentId attachmentId = new AttachmentId(cursor.getLong(cursor.getColumnIndexOrThrow(AttachmentDatabase.ROW_ID)), cursor.getLong(cursor.getColumnIndexOrThrow(AttachmentDatabase.UNIQUE_ID)));
|
||||
Uri attachmentUri = PartAuthority.getAttachmentDataUri(attachmentId);
|
||||
|
||||
if (attachmentUri.equals(uri)) {
|
||||
return new Pair<>(cursor, leftIsRecent ? cursor.getPosition() : cursor.getCount() - 1 - cursor.getPosition());
|
||||
public DcMediaGalleryElement loadInBackground() {
|
||||
DcContext context = DcHelper.getContext(getContext());
|
||||
int[] mediaMessages = context.getChatMedia(msg.getChatId(), DcMsg.DC_MSG_GIF, DcMsg.DC_MSG_IMAGE);
|
||||
// first id is the oldest message.
|
||||
int currentIndex = -1;
|
||||
for(int ii = 0; ii < mediaMessages.length; ii++) {
|
||||
if(mediaMessages[ii] == msg.getId()) {
|
||||
currentIndex = ii;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
if(currentIndex == -1) {
|
||||
currentIndex = 0;
|
||||
DcMsg unfound = context.getMsg(msg.getId());
|
||||
Log.d(TAG, "did not find message in list: " + unfound.getId() + " / " + unfound.getFile() + " / " + unfound.getText());
|
||||
}
|
||||
DcMediaGalleryElement retVal = new DcMediaGalleryElement(mediaMessages, currentIndex, context, leftIsRecent);
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -486,9 +486,8 @@ public class AttachmentManager {
|
||||
if (MediaPreviewActivity.isContentTypeSupported(slide.getContentType()) && slide.getUri() != null) {
|
||||
Intent intent = new Intent(context, MediaPreviewActivity.class);
|
||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
intent.putExtra(MediaPreviewActivity.SIZE_EXTRA, slide.asAttachment().getSize());
|
||||
intent.putExtra(MediaPreviewActivity.DC_MSG_ID, slide.getDcMsgId());
|
||||
intent.putExtra(MediaPreviewActivity.OUTGOING_EXTRA, true);
|
||||
intent.setDataAndType(slide.getUri(), slide.getContentType());
|
||||
|
||||
context.startActivity(intent);
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ import org.thoughtcrime.securesms.contacts.avatars.ContactColors;
|
||||
import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto;
|
||||
import org.thoughtcrime.securesms.contacts.avatars.FallbackContactPhoto;
|
||||
import org.thoughtcrime.securesms.contacts.avatars.GeneratedContactPhoto;
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader;
|
||||
import org.thoughtcrime.securesms.mms.GlideApp;
|
||||
import org.thoughtcrime.securesms.mms.Slide;
|
||||
@@ -65,7 +64,7 @@ public class SingleRecipientNotificationBuilder extends AbstractNotificationBuil
|
||||
addPerson(recipient.getContactUri().toString());
|
||||
}
|
||||
|
||||
ContactPhoto contactPhoto = recipient.getContactPhoto();
|
||||
ContactPhoto contactPhoto = recipient.getContactPhoto(context);
|
||||
FallbackContactPhoto fallbackContactPhoto = recipient.getFallbackContactPhoto();
|
||||
|
||||
if (contactPhoto != null) {
|
||||
|
||||
@@ -94,6 +94,10 @@ public class Recipient implements RecipientModifiedListener {
|
||||
private @Nullable String profileAvatar;
|
||||
private boolean profileSharing;
|
||||
|
||||
public static @NonNull Recipient from(@NonNull Context context, int dcMsgId) {
|
||||
ApplicationDcContext dcContext = DcHelper.getContext(context);
|
||||
return dcContext.getRecipient(dcContext.getChat(dcContext.getMsg(dcMsgId).getChatId()));
|
||||
}
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
public static @NonNull Recipient from(@NonNull Context context, @NonNull Address address, boolean asynchronous) {
|
||||
@@ -101,6 +105,8 @@ public class Recipient implements RecipientModifiedListener {
|
||||
ApplicationDcContext dcContext = DcHelper.getContext(context);
|
||||
if(address.isDcContact()) {
|
||||
return dcContext.getRecipient(dcContext.getContact(address.getDcContactId()));
|
||||
} else if (address.isDcChat()) {
|
||||
return dcContext.getRecipient(dcContext.getChat(address.getDcChatId()));
|
||||
}
|
||||
else if(address.isEmail()) {
|
||||
int contactId = dcContext.lookupContactIdByAddr(address.toEmailString());
|
||||
@@ -383,7 +389,7 @@ public class Recipient implements RecipientModifiedListener {
|
||||
}
|
||||
|
||||
public boolean isGroupRecipient() {
|
||||
return address.isGroup();
|
||||
return participants.size() > 1;
|
||||
}
|
||||
|
||||
public boolean isMmsGroupRecipient() {
|
||||
@@ -437,8 +443,8 @@ public class Recipient implements RecipientModifiedListener {
|
||||
else return new GeneratedContactPhoto("#");
|
||||
}
|
||||
|
||||
public synchronized @Nullable ContactPhoto getContactPhoto() {
|
||||
if (isGroupRecipient() && groupAvatarId != null) return new GroupRecordContactPhoto(address, groupAvatarId);
|
||||
public synchronized @Nullable ContactPhoto getContactPhoto(Context context) {
|
||||
if (isGroupRecipient()) return new GroupRecordContactPhoto(context, getAddress());
|
||||
else if (systemContactPhoto != null) return new SystemContactPhoto(address, systemContactPhoto, 0);
|
||||
else if (profileAvatar != null) return new ProfileContactPhoto(address.toEmailString(), profileAvatar);
|
||||
else return null;
|
||||
|
||||
@@ -51,11 +51,11 @@ public class DirectShareService extends ChooserTargetService {
|
||||
|
||||
Bitmap avatar;
|
||||
|
||||
if (recipient.getContactPhoto() != null) {
|
||||
if (recipient.getContactPhoto(getApplicationContext()) != null) {
|
||||
try {
|
||||
avatar = GlideApp.with(this)
|
||||
.asBitmap()
|
||||
.load(recipient.getContactPhoto())
|
||||
.load(recipient.getContactPhoto(getApplicationContext()))
|
||||
.circleCrop()
|
||||
.submit(getResources().getDimensionPixelSize(android.R.dimen.notification_large_icon_width),
|
||||
getResources().getDimensionPixelSize(android.R.dimen.notification_large_icon_width))
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package org.thoughtcrime.securesms.util;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.FileInputStream;
|
||||
@@ -9,6 +12,8 @@ import java.security.NoSuchAlgorithmException;
|
||||
|
||||
public class FileUtils {
|
||||
|
||||
public static final String AVATAR_PATH_TEMPLATE = "/group_chat_avatar_%s_%o.jpg";
|
||||
|
||||
public static native int getFileDescriptorOwner(FileDescriptor fileDescriptor);
|
||||
|
||||
public static byte[] getFileDigest(FileInputStream fin) throws IOException {
|
||||
@@ -50,4 +55,10 @@ public class FileUtils {
|
||||
|
||||
directory.delete();
|
||||
}
|
||||
|
||||
@SuppressLint("DefaultLocale")
|
||||
public static String getFilePathForChatAvatar(Context context, int chatId, long timestamp) {
|
||||
return context.getFilesDir().getAbsolutePath() + String.format(AVATAR_PATH_TEMPLATE, chatId, timestamp);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -67,6 +67,10 @@ public class MediaUtil {
|
||||
return slide;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use getSlideForMsg instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public static Slide getSlideForAttachment(Context context, Attachment attachment) {
|
||||
Slide slide = null;
|
||||
if (isGif(attachment.getContentType())) {
|
||||
|
||||