Display thumbnail previews for images in conversation list.
Closes #4262 // FREEBIE
This commit is contained in:
parent
15c6f18750
commit
5111fe2e95
12 changed files with 221 additions and 107 deletions
|
@ -22,66 +22,81 @@
|
||||||
android:layout_marginRight="10dp"
|
android:layout_marginRight="10dp"
|
||||||
android:layout_marginLeft="10dp" />
|
android:layout_marginLeft="10dp" />
|
||||||
|
|
||||||
<LinearLayout
|
<RelativeLayout android:layout_width="match_parent"
|
||||||
android:layout_width="match_parent"
|
android:layout_height="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_marginLeft="4dip"
|
||||||
android:layout_marginTop="4dip"
|
android:layout_marginRight="8dip"
|
||||||
android:layout_marginLeft="4dip"
|
android:layout_centerVertical="true"
|
||||||
android:layout_marginRight="8dip"
|
android:layout_toRightOf="@id/contact_photo_image"
|
||||||
android:layout_marginBottom="4dip"
|
android:weightSum="1"
|
||||||
android:layout_centerVertical="true"
|
android:orientation="horizontal">
|
||||||
android:layout_toRightOf="@id/contact_photo_image"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<LinearLayout
|
<org.thoughtcrime.securesms.components.FromTextView
|
||||||
android:layout_width="match_parent"
|
android:id="@+id/from"
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:weightSum="1"
|
|
||||||
android:gravity="bottom">
|
|
||||||
|
|
||||||
<org.thoughtcrime.securesms.components.FromTextView
|
|
||||||
android:id="@+id/from"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
|
||||||
android:textColor="?attr/conversation_list_item_contact_color"
|
|
||||||
android:singleLine="true"
|
|
||||||
tools:text="Jules Bonnot"
|
|
||||||
android:ellipsize="end"
|
|
||||||
android:drawablePadding="5dp"/>
|
|
||||||
|
|
||||||
<ImageView android:id="@+id/error"
|
|
||||||
android:layout_marginLeft="3dip"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_width="20sp"
|
|
||||||
android:visibility="gone"
|
|
||||||
android:src="@drawable/ic_action_warning_red"
|
|
||||||
android:contentDescription="@string/conversation_list_item_view__error_alert" />
|
|
||||||
|
|
||||||
<TextView android:id="@+id/date"
|
|
||||||
android:layout_marginLeft="3dip"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
|
||||||
android:textColor="?attr/conversation_list_item_date_color"
|
|
||||||
android:fontFamily="sans-serif-light"
|
|
||||||
tools:text="30 mins"
|
|
||||||
android:singleLine="true"
|
|
||||||
android:layout_gravity="top" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
|
|
||||||
android:id="@+id/subject"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
android:layout_alignParentTop="true"
|
||||||
android:textColor="?attr/conversation_list_item_subject_color"
|
android:layout_alignParentLeft="true"
|
||||||
android:fontFamily="sans-serif-light"
|
android:layout_toLeftOf="@+id/thumbnail"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||||
|
android:textColor="?attr/conversation_list_item_contact_color"
|
||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
tools:text="Wheels arrive at 3pm flat."
|
tools:text="Jules Bonnot"
|
||||||
android:ellipsize="end" />
|
android:ellipsize="end"
|
||||||
|
android:drawablePadding="5dp"/>
|
||||||
|
|
||||||
</LinearLayout>
|
<ImageView android:id="@+id/error"
|
||||||
|
android:layout_height="20dp"
|
||||||
|
android:layout_width="20dp"
|
||||||
|
android:layout_alignParentLeft="true"
|
||||||
|
android:layout_below="@id/from"
|
||||||
|
android:paddingBottom="3dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="visible"
|
||||||
|
android:src="@drawable/ic_action_warning_red"
|
||||||
|
android:contentDescription="@string/conversation_list_item_view__error_alert" />
|
||||||
|
|
||||||
|
<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_toRightOf="@id/error"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||||
|
android:textColor="?attr/conversation_list_item_subject_color"
|
||||||
|
android:fontFamily="sans-serif-light"
|
||||||
|
android:singleLine="true"
|
||||||
|
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="5dip"
|
||||||
|
android:layout_marginLeft="5dip"
|
||||||
|
android:layout_toLeftOf="@+id/date"
|
||||||
|
android:layout_alignParentTop="true"
|
||||||
|
android:layout_marginTop="5dip"
|
||||||
|
android:contentDescription="@string/conversation_activity__attachment_thumbnail"
|
||||||
|
app:backgroundColorHint="?conversation_background"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:src="@drawable/ic_video_light"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
<TextView android:id="@id/date"
|
||||||
|
android:layout_marginLeft="3dip"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_alignParentRight="true"
|
||||||
|
android:layout_alignParentTop="true"
|
||||||
|
android:layout_above="@id/subject"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||||
|
android:textColor="?attr/conversation_list_item_date_color"
|
||||||
|
android:fontFamily="sans-serif-light"
|
||||||
|
tools:text="30 mins"
|
||||||
|
android:singleLine="true"/>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
</org.thoughtcrime.securesms.ConversationListItem>
|
</org.thoughtcrime.securesms.ConversationListItem>
|
||||||
|
|
|
@ -449,6 +449,7 @@
|
||||||
<string name="ThreadRecord_called">You called</string>
|
<string name="ThreadRecord_called">You called</string>
|
||||||
<string name="ThreadRecord_called_you">Called you</string>
|
<string name="ThreadRecord_called_you">Called you</string>
|
||||||
<string name="ThreadRecord_missed_call">Missed call</string>
|
<string name="ThreadRecord_missed_call">Missed call</string>
|
||||||
|
<string name="ThreadRecord_media_message">Media message</string>
|
||||||
|
|
||||||
<!-- VerifyIdentityActivity -->
|
<!-- VerifyIdentityActivity -->
|
||||||
<string name="VerifyIdentityActivity_you_do_not_have_an_identity_key">You do not have an identity key.</string>
|
<string name="VerifyIdentityActivity_you_do_not_have_an_identity_key">You do not have an identity key.</string>
|
||||||
|
|
|
@ -1080,7 +1080,9 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||||
if (threadId == -1) threadId = threadDatabase.getThreadIdFor(getRecipients(), thisDistributionType);
|
if (threadId == -1) threadId = threadDatabase.getThreadIdFor(getRecipients(), thisDistributionType);
|
||||||
|
|
||||||
draftDatabase.insertDrafts(new MasterCipher(thisMasterSecret), threadId, drafts);
|
draftDatabase.insertDrafts(new MasterCipher(thisMasterSecret), threadId, drafts);
|
||||||
threadDatabase.updateSnippet(threadId, drafts.getSnippet(ConversationActivity.this), System.currentTimeMillis(), Types.BASE_DRAFT_TYPE);
|
threadDatabase.updateSnippet(threadId, drafts.getSnippet(ConversationActivity.this),
|
||||||
|
drafts.getUriSnippet(ConversationActivity.this),
|
||||||
|
System.currentTimeMillis(), Types.BASE_DRAFT_TYPE);
|
||||||
} else if (threadId > 0) {
|
} else if (threadId > 0) {
|
||||||
threadDatabase.update(threadId);
|
threadDatabase.update(threadId);
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,6 +47,7 @@ import java.util.Set;
|
||||||
public class ConversationListAdapter extends CursorRecyclerViewAdapter<ConversationListAdapter.ViewHolder> {
|
public class ConversationListAdapter extends CursorRecyclerViewAdapter<ConversationListAdapter.ViewHolder> {
|
||||||
|
|
||||||
private final ThreadDatabase threadDatabase;
|
private final ThreadDatabase threadDatabase;
|
||||||
|
private final MasterSecret masterSecret;
|
||||||
private final MasterCipher masterCipher;
|
private final MasterCipher masterCipher;
|
||||||
private final Locale locale;
|
private final Locale locale;
|
||||||
private final Context context;
|
private final Context context;
|
||||||
|
@ -86,6 +87,7 @@ public class ConversationListAdapter extends CursorRecyclerViewAdapter<Conversat
|
||||||
@Nullable Cursor cursor,
|
@Nullable Cursor cursor,
|
||||||
@Nullable ItemClickListener clickListener) {
|
@Nullable ItemClickListener clickListener) {
|
||||||
super(context, cursor);
|
super(context, cursor);
|
||||||
|
this.masterSecret = masterSecret;
|
||||||
this.masterCipher = new MasterCipher(masterSecret);
|
this.masterCipher = new MasterCipher(masterSecret);
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.threadDatabase = DatabaseFactory.getThreadDatabase(context);
|
this.threadDatabase = DatabaseFactory.getThreadDatabase(context);
|
||||||
|
@ -109,7 +111,7 @@ public class ConversationListAdapter extends CursorRecyclerViewAdapter<Conversat
|
||||||
ThreadDatabase.Reader reader = threadDatabase.readerFor(cursor, masterCipher);
|
ThreadDatabase.Reader reader = threadDatabase.readerFor(cursor, masterCipher);
|
||||||
ThreadRecord record = reader.getCurrent();
|
ThreadRecord record = reader.getCurrent();
|
||||||
|
|
||||||
viewHolder.getItem().set(record, locale, batchSet, batchMode);
|
viewHolder.getItem().set(masterSecret, record, locale, batchSet, batchMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void toggleThreadInBatchSet(long threadId) {
|
public void toggleThreadInBatchSet(long threadId) {
|
||||||
|
|
|
@ -25,12 +25,16 @@ import android.os.Build.VERSION;
|
||||||
import android.os.Build.VERSION_CODES;
|
import android.os.Build.VERSION_CODES;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.support.annotation.DrawableRes;
|
import android.support.annotation.DrawableRes;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
|
import android.view.View;
|
||||||
import android.widget.RelativeLayout;
|
import android.widget.RelativeLayout;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.components.AvatarImageView;
|
import org.thoughtcrime.securesms.components.AvatarImageView;
|
||||||
import org.thoughtcrime.securesms.components.FromTextView;
|
import org.thoughtcrime.securesms.components.FromTextView;
|
||||||
|
import org.thoughtcrime.securesms.components.ThumbnailView;
|
||||||
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
import org.thoughtcrime.securesms.database.model.ThreadRecord;
|
import org.thoughtcrime.securesms.database.model.ThreadRecord;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||||
import org.thoughtcrime.securesms.util.DateUtils;
|
import org.thoughtcrime.securesms.util.DateUtils;
|
||||||
|
@ -64,6 +68,7 @@ public class ConversationListItem extends RelativeLayout
|
||||||
private TextView dateView;
|
private TextView dateView;
|
||||||
private boolean read;
|
private boolean read;
|
||||||
private AvatarImageView contactPhotoImage;
|
private AvatarImageView contactPhotoImage;
|
||||||
|
private ThumbnailView thumbnailView;
|
||||||
|
|
||||||
private final @DrawableRes int readBackground;
|
private final @DrawableRes int readBackground;
|
||||||
private final @DrawableRes int unreadBackround;
|
private final @DrawableRes int unreadBackround;
|
||||||
|
@ -88,9 +93,12 @@ public class ConversationListItem extends RelativeLayout
|
||||||
this.fromView = (FromTextView) findViewById(R.id.from);
|
this.fromView = (FromTextView) findViewById(R.id.from);
|
||||||
this.dateView = (TextView) findViewById(R.id.date);
|
this.dateView = (TextView) findViewById(R.id.date);
|
||||||
this.contactPhotoImage = (AvatarImageView) findViewById(R.id.contact_photo_image);
|
this.contactPhotoImage = (AvatarImageView) findViewById(R.id.contact_photo_image);
|
||||||
|
this.thumbnailView = (ThumbnailView) findViewById(R.id.thumbnail);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void set(ThreadRecord thread, Locale locale, Set<Long> selectedThreads, boolean batchMode) {
|
public void set(@NonNull MasterSecret masterSecret, @NonNull ThreadRecord thread,
|
||||||
|
@NonNull Locale locale, @NonNull Set<Long> selectedThreads, boolean batchMode)
|
||||||
|
{
|
||||||
this.selectedThreads = selectedThreads;
|
this.selectedThreads = selectedThreads;
|
||||||
this.recipients = thread.getRecipients();
|
this.recipients = thread.getRecipients();
|
||||||
this.threadId = thread.getThreadId();
|
this.threadId = thread.getThreadId();
|
||||||
|
@ -109,6 +117,7 @@ public class ConversationListItem extends RelativeLayout
|
||||||
dateView.setTypeface(read ? LIGHT_TYPEFACE : BOLD_TYPEFACE);
|
dateView.setTypeface(read ? LIGHT_TYPEFACE : BOLD_TYPEFACE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setThumbnailSnippet(masterSecret, thread);
|
||||||
setBatchState(batchMode);
|
setBatchState(batchMode);
|
||||||
setBackground(thread);
|
setBackground(thread);
|
||||||
setRippleColor(recipients);
|
setRippleColor(recipients);
|
||||||
|
@ -136,6 +145,23 @@ public class ConversationListItem extends RelativeLayout
|
||||||
return distributionType;
|
return distributionType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setThumbnailSnippet(MasterSecret masterSecret, ThreadRecord thread) {
|
||||||
|
if (thread.getSnippetUri() != null) {
|
||||||
|
this.thumbnailView.setVisibility(View.VISIBLE);
|
||||||
|
this.thumbnailView.setImageResource(masterSecret, thread.getSnippetUri());
|
||||||
|
|
||||||
|
LayoutParams subjectParams = (RelativeLayout.LayoutParams)this.subjectView.getLayoutParams();
|
||||||
|
subjectParams.addRule(RelativeLayout.LEFT_OF, R.id.thumbnail);
|
||||||
|
this.subjectView.setLayoutParams(subjectParams);
|
||||||
|
} else {
|
||||||
|
this.thumbnailView.setVisibility(View.GONE);
|
||||||
|
|
||||||
|
LayoutParams subjectParams = (RelativeLayout.LayoutParams)this.subjectView.getLayoutParams();
|
||||||
|
subjectParams.addRule(RelativeLayout.LEFT_OF, 0);
|
||||||
|
this.subjectView.setLayoutParams(subjectParams);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void setBackground(ThreadRecord thread) {
|
private void setBackground(ThreadRecord thread) {
|
||||||
if (thread.isRead()) setBackgroundResource(readBackground);
|
if (thread.isRead()) setBackgroundResource(readBackground);
|
||||||
else setBackgroundResource(unreadBackround);
|
else setBackgroundResource(unreadBackround);
|
||||||
|
|
|
@ -5,6 +5,7 @@ import android.app.Activity;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.TypedArray;
|
import android.content.res.TypedArray;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Build.VERSION;
|
import android.os.Build.VERSION;
|
||||||
import android.os.Build.VERSION_CODES;
|
import android.os.Build.VERSION_CODES;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
@ -124,6 +125,15 @@ public class ThumbnailView extends FrameLayout {
|
||||||
else Glide.clear(image);
|
else Glide.clear(image);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setImageResource(@NonNull MasterSecret masterSecret, @NonNull Uri uri) {
|
||||||
|
if (transferControls.isPresent()) getTransferControls().setVisibility(View.GONE);
|
||||||
|
|
||||||
|
Glide.with(getContext()).load(new DecryptableUri(masterSecret, uri))
|
||||||
|
.crossFade()
|
||||||
|
.transform(new RoundedCorners(getContext(), true, radius, backgroundColorHint))
|
||||||
|
.into(image);
|
||||||
|
}
|
||||||
|
|
||||||
public void setThumbnailClickListener(SlideClickListener listener) {
|
public void setThumbnailClickListener(SlideClickListener listener) {
|
||||||
this.thumbnailClickListener = listener;
|
this.thumbnailClickListener = listener;
|
||||||
}
|
}
|
||||||
|
|
|
@ -266,6 +266,7 @@ public class AttachmentDatabase extends Database {
|
||||||
partData.first.delete();
|
partData.first.delete();
|
||||||
} else {
|
} else {
|
||||||
notifyConversationListeners(DatabaseFactory.getMmsDatabase(context).getThreadIdForMessage(mmsId));
|
notifyConversationListeners(DatabaseFactory.getMmsDatabase(context).getThreadIdForMessage(mmsId));
|
||||||
|
notifyConversationListListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
thumbnailExecutor.submit(new ThumbnailFetchCallable(masterSecret, attachmentId));
|
thumbnailExecutor.submit(new ThumbnailFetchCallable(masterSecret, attachmentId));
|
||||||
|
|
|
@ -46,28 +46,29 @@ import ws.com.google.android.mms.ContentType;
|
||||||
|
|
||||||
public class DatabaseFactory {
|
public class DatabaseFactory {
|
||||||
|
|
||||||
private static final int INTRODUCED_IDENTITIES_VERSION = 2;
|
private static final int INTRODUCED_IDENTITIES_VERSION = 2;
|
||||||
private static final int INTRODUCED_INDEXES_VERSION = 3;
|
private static final int INTRODUCED_INDEXES_VERSION = 3;
|
||||||
private static final int INTRODUCED_DATE_SENT_VERSION = 4;
|
private static final int INTRODUCED_DATE_SENT_VERSION = 4;
|
||||||
private static final int INTRODUCED_DRAFTS_VERSION = 5;
|
private static final int INTRODUCED_DRAFTS_VERSION = 5;
|
||||||
private static final int INTRODUCED_NEW_TYPES_VERSION = 6;
|
private static final int INTRODUCED_NEW_TYPES_VERSION = 6;
|
||||||
private static final int INTRODUCED_MMS_BODY_VERSION = 7;
|
private static final int INTRODUCED_MMS_BODY_VERSION = 7;
|
||||||
private static final int INTRODUCED_MMS_FROM_VERSION = 8;
|
private static final int INTRODUCED_MMS_FROM_VERSION = 8;
|
||||||
private static final int INTRODUCED_TOFU_IDENTITY_VERSION = 9;
|
private static final int INTRODUCED_TOFU_IDENTITY_VERSION = 9;
|
||||||
private static final int INTRODUCED_PUSH_DATABASE_VERSION = 10;
|
private static final int INTRODUCED_PUSH_DATABASE_VERSION = 10;
|
||||||
private static final int INTRODUCED_GROUP_DATABASE_VERSION = 11;
|
private static final int INTRODUCED_GROUP_DATABASE_VERSION = 11;
|
||||||
private static final int INTRODUCED_PUSH_FIX_VERSION = 12;
|
private static final int INTRODUCED_PUSH_FIX_VERSION = 12;
|
||||||
private static final int INTRODUCED_DELIVERY_RECEIPTS = 13;
|
private static final int INTRODUCED_DELIVERY_RECEIPTS = 13;
|
||||||
private static final int INTRODUCED_PART_DATA_SIZE_VERSION = 14;
|
private static final int INTRODUCED_PART_DATA_SIZE_VERSION = 14;
|
||||||
private static final int INTRODUCED_THUMBNAILS_VERSION = 15;
|
private static final int INTRODUCED_THUMBNAILS_VERSION = 15;
|
||||||
private static final int INTRODUCED_IDENTITY_COLUMN_VERSION = 16;
|
private static final int INTRODUCED_IDENTITY_COLUMN_VERSION = 16;
|
||||||
private static final int INTRODUCED_UNIQUE_PART_IDS_VERSION = 17;
|
private static final int INTRODUCED_UNIQUE_PART_IDS_VERSION = 17;
|
||||||
private static final int INTRODUCED_RECIPIENT_PREFS_DB = 18;
|
private static final int INTRODUCED_RECIPIENT_PREFS_DB = 18;
|
||||||
private static final int INTRODUCED_ENVELOPE_CONTENT_VERSION = 19;
|
private static final int INTRODUCED_ENVELOPE_CONTENT_VERSION = 19;
|
||||||
private static final int INTRODUCED_COLOR_PREFERENCE_VERSION = 20;
|
private static final int INTRODUCED_COLOR_PREFERENCE_VERSION = 20;
|
||||||
private static final int INTRODUCED_DB_OPTIMIZATIONS_VERSION = 21;
|
private static final int INTRODUCED_DB_OPTIMIZATIONS_VERSION = 21;
|
||||||
private static final int INTRODUCED_INVITE_REMINDERS_VERSION = 22;
|
private static final int INTRODUCED_INVITE_REMINDERS_VERSION = 22;
|
||||||
private static final int DATABASE_VERSION = 22;
|
private static final int INTRODUCED_CONVERSATION_LIST_THUMBNAILS_VERSION = 23;
|
||||||
|
private static final int DATABASE_VERSION = 23;
|
||||||
|
|
||||||
private static final String DATABASE_NAME = "messages.db";
|
private static final String DATABASE_NAME = "messages.db";
|
||||||
private static final Object lock = new Object();
|
private static final Object lock = new Object();
|
||||||
|
@ -773,6 +774,10 @@ public class DatabaseFactory {
|
||||||
db.execSQL("ALTER TABLE recipient_preferences ADD COLUMN seen_invite_reminder INTEGER DEFAULT 0");
|
db.execSQL("ALTER TABLE recipient_preferences ADD COLUMN seen_invite_reminder INTEGER DEFAULT 0");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (oldVersion < INTRODUCED_CONVERSATION_LIST_THUMBNAILS_VERSION) {
|
||||||
|
db.execSQL("ALTER TABLE thread ADD COLUMN snippet_uri TEXT DEFAULT NULL");
|
||||||
|
}
|
||||||
|
|
||||||
db.setTransactionSuccessful();
|
db.setTransactionSuccessful();
|
||||||
db.endTransaction();
|
db.endTransaction();
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,8 @@ import android.content.Context;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
import android.database.sqlite.SQLiteOpenHelper;
|
import android.database.sqlite.SQLiteOpenHelper;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
|
@ -136,7 +138,7 @@ public class DraftDatabase extends Database {
|
||||||
public static class Drafts extends LinkedList<Draft> {
|
public static class Drafts extends LinkedList<Draft> {
|
||||||
private Draft getDraftOfType(String type) {
|
private Draft getDraftOfType(String type) {
|
||||||
for (Draft draft : this) {
|
for (Draft draft : this) {
|
||||||
if (Draft.TEXT.equals(draft.getType())) {
|
if (type.equals(draft.getType())) {
|
||||||
return draft;
|
return draft;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -153,5 +155,15 @@ public class DraftDatabase extends Database {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public @Nullable Uri getUriSnippet(Context context) {
|
||||||
|
Draft imageDraft = getDraftOfType(Draft.IMAGE);
|
||||||
|
|
||||||
|
if (imageDraft != null && imageDraft.getValue() != null) {
|
||||||
|
return Uri.parse(imageDraft.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -791,14 +791,14 @@ public class MmsDatabase extends MessagingDatabase {
|
||||||
addressDatabase.insertAddressesForId(messageId, addresses);
|
addressDatabase.insertAddressesForId(messageId, addresses);
|
||||||
partsDatabase.insertAttachmentsForMessage(masterSecret, messageId, attachments);
|
partsDatabase.insertAttachmentsForMessage(masterSecret, messageId, attachments);
|
||||||
|
|
||||||
notifyConversationListeners(contentValues.getAsLong(THREAD_ID));
|
|
||||||
DatabaseFactory.getThreadDatabase(context).update(contentValues.getAsLong(THREAD_ID));
|
|
||||||
db.setTransactionSuccessful();
|
db.setTransactionSuccessful();
|
||||||
return messageId;
|
return messageId;
|
||||||
} finally {
|
} finally {
|
||||||
db.endTransaction();
|
db.endTransaction();
|
||||||
}
|
|
||||||
|
|
||||||
|
notifyConversationListeners(contentValues.getAsLong(THREAD_ID));
|
||||||
|
DatabaseFactory.getThreadDatabase(context).update(contentValues.getAsLong(THREAD_ID));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean delete(long messageId) {
|
public boolean delete(long messageId) {
|
||||||
|
|
|
@ -22,6 +22,7 @@ import android.database.Cursor;
|
||||||
import android.database.MergeCursor;
|
import android.database.MergeCursor;
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
import android.database.sqlite.SQLiteOpenHelper;
|
import android.database.sqlite.SQLiteOpenHelper;
|
||||||
|
import android.net.Uri;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
@ -29,8 +30,11 @@ import android.util.Log;
|
||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
import org.thoughtcrime.securesms.crypto.MasterCipher;
|
import org.thoughtcrime.securesms.crypto.MasterCipher;
|
||||||
import org.thoughtcrime.securesms.database.model.DisplayRecord;
|
import org.thoughtcrime.securesms.database.model.DisplayRecord;
|
||||||
|
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord;
|
||||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||||
import org.thoughtcrime.securesms.database.model.ThreadRecord;
|
import org.thoughtcrime.securesms.database.model.ThreadRecord;
|
||||||
|
import org.thoughtcrime.securesms.mms.Slide;
|
||||||
|
import org.thoughtcrime.securesms.mms.SlideDeck;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||||
|
@ -45,6 +49,8 @@ import java.util.Set;
|
||||||
|
|
||||||
public class ThreadDatabase extends Database {
|
public class ThreadDatabase extends Database {
|
||||||
|
|
||||||
|
private static final String TAG = ThreadDatabase.class.getSimpleName();
|
||||||
|
|
||||||
static final String TABLE_NAME = "thread";
|
static final String TABLE_NAME = "thread";
|
||||||
public static final String ID = "_id";
|
public static final String ID = "_id";
|
||||||
public static final String DATE = "date";
|
public static final String DATE = "date";
|
||||||
|
@ -55,14 +61,14 @@ public class ThreadDatabase extends Database {
|
||||||
public static final String READ = "read";
|
public static final String READ = "read";
|
||||||
private static final String TYPE = "type";
|
private static final String TYPE = "type";
|
||||||
private static final String ERROR = "error";
|
private static final String ERROR = "error";
|
||||||
private static final String HAS_ATTACHMENT = "has_attachment";
|
|
||||||
public static final String SNIPPET_TYPE = "snippet_type";
|
public static final String SNIPPET_TYPE = "snippet_type";
|
||||||
|
private static final String SNIPPET_URI = "snippet_uri";
|
||||||
|
|
||||||
public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " (" + ID + " INTEGER PRIMARY KEY, " +
|
public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " (" + ID + " INTEGER PRIMARY KEY, " +
|
||||||
DATE + " INTEGER DEFAULT 0, " + MESSAGE_COUNT + " INTEGER DEFAULT 0, " +
|
DATE + " INTEGER DEFAULT 0, " + MESSAGE_COUNT + " INTEGER DEFAULT 0, " +
|
||||||
RECIPIENT_IDS + " TEXT, " + SNIPPET + " TEXT, " + SNIPPET_CHARSET + " INTEGER DEFAULT 0, " +
|
RECIPIENT_IDS + " TEXT, " + SNIPPET + " TEXT, " + SNIPPET_CHARSET + " INTEGER DEFAULT 0, " +
|
||||||
READ + " INTEGER DEFAULT 1, " + TYPE + " INTEGER DEFAULT 0, " + ERROR + " INTEGER DEFAULT 0, " +
|
READ + " INTEGER DEFAULT 1, " + TYPE + " INTEGER DEFAULT 0, " + ERROR + " INTEGER DEFAULT 0, " +
|
||||||
SNIPPET_TYPE + " INTEGER DEFAULT 0);";
|
SNIPPET_TYPE + " INTEGER DEFAULT 0, " + SNIPPET_URI + " TEXT DEFAULT NULL);";
|
||||||
|
|
||||||
public static final String[] CREATE_INDEXS = {
|
public static final String[] CREATE_INDEXS = {
|
||||||
"CREATE INDEX IF NOT EXISTS thread_recipient_ids_index ON " + TABLE_NAME + " (" + RECIPIENT_IDS + ");",
|
"CREATE INDEX IF NOT EXISTS thread_recipient_ids_index ON " + TABLE_NAME + " (" + RECIPIENT_IDS + ");",
|
||||||
|
@ -73,7 +79,7 @@ public class ThreadDatabase extends Database {
|
||||||
}
|
}
|
||||||
|
|
||||||
private long[] getRecipientIds(Recipients recipients) {
|
private long[] getRecipientIds(Recipients recipients) {
|
||||||
Set<Long> recipientSet = new HashSet<Long>();
|
Set<Long> recipientSet = new HashSet<>();
|
||||||
List<Recipient> recipientList = recipients.getRecipientsList();
|
List<Recipient> recipientList = recipients.getRecipientsList();
|
||||||
|
|
||||||
for (Recipient recipient : recipientList) {
|
for (Recipient recipient : recipientList) {
|
||||||
|
@ -118,12 +124,13 @@ public class ThreadDatabase extends Database {
|
||||||
return db.insert(TABLE_NAME, null, contentValues);
|
return db.insert(TABLE_NAME, null, contentValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateThread(long threadId, long count, String body, long date, long type)
|
private void updateThread(long threadId, long count, String body, @Nullable Uri attachment, long date, long type)
|
||||||
{
|
{
|
||||||
ContentValues contentValues = new ContentValues(4);
|
ContentValues contentValues = new ContentValues(4);
|
||||||
contentValues.put(DATE, date - date % 1000);
|
contentValues.put(DATE, date - date % 1000);
|
||||||
contentValues.put(MESSAGE_COUNT, count);
|
contentValues.put(MESSAGE_COUNT, count);
|
||||||
contentValues.put(SNIPPET, body);
|
contentValues.put(SNIPPET, body);
|
||||||
|
contentValues.put(SNIPPET_URI, attachment == null ? null : attachment.toString());
|
||||||
contentValues.put(SNIPPET_TYPE, type);
|
contentValues.put(SNIPPET_TYPE, type);
|
||||||
|
|
||||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||||
|
@ -131,12 +138,13 @@ public class ThreadDatabase extends Database {
|
||||||
notifyConversationListListeners();
|
notifyConversationListListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateSnippet(long threadId, String snippet, long date, long type) {
|
public void updateSnippet(long threadId, String snippet, @Nullable Uri attachment, long date, long type) {
|
||||||
ContentValues contentValues = new ContentValues(3);
|
ContentValues contentValues = new ContentValues(3);
|
||||||
|
|
||||||
contentValues.put(DATE, date - date % 1000);
|
contentValues.put(DATE, date - date % 1000);
|
||||||
contentValues.put(SNIPPET, snippet);
|
contentValues.put(SNIPPET, snippet);
|
||||||
contentValues.put(SNIPPET_TYPE, type);
|
contentValues.put(SNIPPET_TYPE, type);
|
||||||
|
contentValues.put(SNIPPET_URI, attachment == null ? null : attachment.toString());
|
||||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||||
db.update(TABLE_NAME, contentValues, ID + " = ?", new String[] {threadId + ""});
|
db.update(TABLE_NAME, contentValues, ID + " = ?", new String[] {threadId + ""});
|
||||||
notifyConversationListListeners();
|
notifyConversationListListeners();
|
||||||
|
@ -144,7 +152,7 @@ public class ThreadDatabase extends Database {
|
||||||
|
|
||||||
private void deleteThread(long threadId) {
|
private void deleteThread(long threadId) {
|
||||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||||
db.delete(TABLE_NAME, ID_WHERE, new String[] {threadId+""});
|
db.delete(TABLE_NAME, ID_WHERE, new String[] {threadId + ""});
|
||||||
notifyConversationListListeners();
|
notifyConversationListListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -247,7 +255,7 @@ public class ThreadDatabase extends Database {
|
||||||
contentValues.put(READ, 0);
|
contentValues.put(READ, 0);
|
||||||
|
|
||||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||||
db.update(TABLE_NAME, contentValues, ID_WHERE, new String[] {threadId+""});
|
db.update(TABLE_NAME, contentValues, ID_WHERE, new String[] {threadId + ""});
|
||||||
notifyConversationListListeners();
|
notifyConversationListListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,7 +264,7 @@ public class ThreadDatabase extends Database {
|
||||||
contentValues.put(TYPE, distributionType);
|
contentValues.put(TYPE, distributionType);
|
||||||
|
|
||||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||||
db.update(TABLE_NAME, contentValues, ID_WHERE, new String[] {threadId+""});
|
db.update(TABLE_NAME, contentValues, ID_WHERE, new String[] {threadId + ""});
|
||||||
notifyConversationListListeners();
|
notifyConversationListListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -413,7 +421,7 @@ public class ThreadDatabase extends Database {
|
||||||
if (record.isPush()) timestamp = record.getDateSent();
|
if (record.isPush()) timestamp = record.getDateSent();
|
||||||
else timestamp = record.getDateReceived();
|
else timestamp = record.getDateReceived();
|
||||||
|
|
||||||
updateThread(threadId, count, record.getBody().getBody(), timestamp, record.getType());
|
updateThread(threadId, count, record.getBody().getBody(), getAttachmentUriFor(record), timestamp, record.getType());
|
||||||
notifyConversationListListeners();
|
notifyConversationListListeners();
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
|
@ -427,6 +435,15 @@ public class ThreadDatabase extends Database {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private @Nullable Uri getAttachmentUriFor(MessageRecord record) {
|
||||||
|
if (!record.isMms() || record.isMmsNotification()) return null;
|
||||||
|
|
||||||
|
SlideDeck slideDeck = ((MediaMmsMessageRecord)record).getSlideDeck();
|
||||||
|
Slide thumbnail = slideDeck.getThumbnailSlide();
|
||||||
|
|
||||||
|
return thumbnail != null ? thumbnail.getThumbnailUri() : null;
|
||||||
|
}
|
||||||
|
|
||||||
public static interface ProgressListener {
|
public static interface ProgressListener {
|
||||||
public void onProgress(int complete, int total);
|
public void onProgress(int complete, int total);
|
||||||
}
|
}
|
||||||
|
@ -459,9 +476,9 @@ public class ThreadDatabase extends Database {
|
||||||
}
|
}
|
||||||
|
|
||||||
public ThreadRecord getCurrent() {
|
public ThreadRecord getCurrent() {
|
||||||
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.ID));
|
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.ID));
|
||||||
String recipientId = cursor.getString(cursor.getColumnIndexOrThrow(ThreadDatabase.RECIPIENT_IDS));
|
String recipientId = cursor.getString(cursor.getColumnIndexOrThrow(ThreadDatabase.RECIPIENT_IDS));
|
||||||
Recipients recipients = RecipientFactory.getRecipientsForIds(context, recipientId, true);
|
Recipients recipients = RecipientFactory.getRecipientsForIds(context, recipientId, true);
|
||||||
|
|
||||||
DisplayRecord.Body body = getPlaintextBody(cursor);
|
DisplayRecord.Body body = getPlaintextBody(cursor);
|
||||||
long date = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.DATE));
|
long date = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.DATE));
|
||||||
|
@ -469,8 +486,9 @@ public class ThreadDatabase extends Database {
|
||||||
long read = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.READ));
|
long read = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.READ));
|
||||||
long type = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.SNIPPET_TYPE));
|
long type = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.SNIPPET_TYPE));
|
||||||
int distributionType = cursor.getInt(cursor.getColumnIndexOrThrow(ThreadDatabase.TYPE));
|
int distributionType = cursor.getInt(cursor.getColumnIndexOrThrow(ThreadDatabase.TYPE));
|
||||||
|
Uri snippetUri = getSnippetUri(cursor);
|
||||||
|
|
||||||
return new ThreadRecord(context, body, recipients, date, count,
|
return new ThreadRecord(context, body, snippetUri, recipients, date, count,
|
||||||
read == 1, threadId, type, distributionType);
|
read == 1, threadId, type, distributionType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -492,6 +510,19 @@ public class ThreadDatabase extends Database {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private @Nullable Uri getSnippetUri(Cursor cursor) {
|
||||||
|
if (cursor.isNull(cursor.getColumnIndexOrThrow(ThreadDatabase.SNIPPET_URI))) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return Uri.parse(cursor.getString(cursor.getColumnIndexOrThrow(ThreadDatabase.SNIPPET_URI)));
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
Log.w(TAG, e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void close() {
|
public void close() {
|
||||||
cursor.close();
|
cursor.close();
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,9 @@
|
||||||
package org.thoughtcrime.securesms.database.model;
|
package org.thoughtcrime.securesms.database.model;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
import android.text.Spannable;
|
import android.text.Spannable;
|
||||||
import android.text.SpannableString;
|
import android.text.SpannableString;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
@ -36,22 +39,28 @@ import org.thoughtcrime.securesms.util.GroupUtil;
|
||||||
*/
|
*/
|
||||||
public class ThreadRecord extends DisplayRecord {
|
public class ThreadRecord extends DisplayRecord {
|
||||||
|
|
||||||
private final Context context;
|
private @NonNull final Context context;
|
||||||
private final long count;
|
private @Nullable final Uri snippetUri;
|
||||||
private final boolean read;
|
private final long count;
|
||||||
private final int distributionType;
|
private final boolean read;
|
||||||
|
private final int distributionType;
|
||||||
|
|
||||||
public ThreadRecord(Context context, Body body, Recipients recipients, long date,
|
public ThreadRecord(@NonNull Context context, @NonNull Body body, @Nullable Uri snippetUri,
|
||||||
long count, boolean read, long threadId, long snippetType,
|
@NonNull Recipients recipients, long date, long count, boolean read,
|
||||||
int distributionType)
|
long threadId, long snippetType, int distributionType)
|
||||||
{
|
{
|
||||||
super(context, body, recipients, date, date, threadId, snippetType);
|
super(context, body, recipients, date, date, threadId, snippetType);
|
||||||
this.context = context.getApplicationContext();
|
this.context = context.getApplicationContext();
|
||||||
|
this.snippetUri = snippetUri;
|
||||||
this.count = count;
|
this.count = count;
|
||||||
this.read = read;
|
this.read = read;
|
||||||
this.distributionType = distributionType;
|
this.distributionType = distributionType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public @Nullable Uri getSnippetUri() {
|
||||||
|
return snippetUri;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SpannableString getDisplayBody() {
|
public SpannableString getDisplayBody() {
|
||||||
if (SmsDatabase.Types.isDecryptInProgressType(type)) {
|
if (SmsDatabase.Types.isDecryptInProgressType(type)) {
|
||||||
|
@ -83,7 +92,7 @@ public class ThreadRecord extends DisplayRecord {
|
||||||
return emphasisAdded(context.getString(org.thoughtcrime.securesms.R.string.ThreadRecord_missed_call));
|
return emphasisAdded(context.getString(org.thoughtcrime.securesms.R.string.ThreadRecord_missed_call));
|
||||||
} else {
|
} else {
|
||||||
if (TextUtils.isEmpty(getBody().getBody())) {
|
if (TextUtils.isEmpty(getBody().getBody())) {
|
||||||
return new SpannableString(context.getString(R.string.MessageNotifier_no_subject));
|
return new SpannableString(emphasisAdded(context.getString(R.string.ThreadRecord_media_message)));
|
||||||
} else {
|
} else {
|
||||||
return new SpannableString(getBody().getBody());
|
return new SpannableString(getBody().getBody());
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue