Show videos in media overview

Fixes #5941
Closes #6152
// FREEBIE
This commit is contained in:
haffenloher 2017-02-01 03:49:19 +01:00 committed by Moxie Marlinspike
parent 98d223f094
commit 83e31cac07
9 changed files with 50 additions and 48 deletions

View File

@ -21,6 +21,6 @@
android:gravity="center_horizontal" android:gravity="center_horizontal"
android:paddingTop="30dp" android:paddingTop="30dp"
android:visibility="gone" android:visibility="gone"
android:text="@string/media_overview_activity__no_images" /> android:text="@string/media_overview_activity__no_media" />
</RelativeLayout> </RelativeLayout>

View File

@ -8,6 +8,6 @@
android:id="@+id/image" android:id="@+id/image"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:contentDescription="@string/media_preview_activity__image_content_description" /> android:contentDescription="@string/media_preview_activity__media_content_description" />
</org.thoughtcrime.securesms.components.SquareFrameLayout> </org.thoughtcrime.securesms.components.SquareFrameLayout>

View File

@ -4,7 +4,7 @@
<item android:title="@string/conversation__menu_add_attachment" <item android:title="@string/conversation__menu_add_attachment"
android:id="@+id/menu_add_attachment" /> android:id="@+id/menu_add_attachment" />
<item android:title="@string/conversation__menu_view_media" <item android:title="@string/conversation__menu_view_all_media"
android:id="@+id/menu_view_media" /> android:id="@+id/menu_view_media" />
<item android:title="@string/conversation__menu_conversation_settings" <item android:title="@string/conversation__menu_conversation_settings"

View File

@ -10,7 +10,7 @@
android:icon="@drawable/ic_save_white_24dp" android:icon="@drawable/ic_save_white_24dp"
app:showAsAction="always"/> app:showAsAction="always"/>
<item android:id="@+id/media_preview__overview" <item android:id="@+id/media_preview__overview"
android:title="@string/media_preview__overview_title" android:title="@string/media_preview__all_media_title"
android:icon="@drawable/ic_photo_library_white_24dp" android:icon="@drawable/ic_photo_library_white_24dp"
app:showAsAction="ifRoom"/> app:showAsAction="ifRoom"/>
</menu> </menu>

View File

@ -858,7 +858,7 @@
<string name="load_more_header__see_full_conversation">See full conversation</string> <string name="load_more_header__see_full_conversation">See full conversation</string>
<!-- media_overview_activity --> <!-- media_overview_activity -->
<string name="media_overview_activity__no_images">No images</string> <string name="media_overview_activity__no_media">No media</string>
<!-- message_recipients_list_item --> <!-- message_recipients_list_item -->
<string name="message_recipients_list_item__verify">VERIFY</string> <string name="message_recipients_list_item__verify">VERIFY</string>
@ -1012,8 +1012,8 @@
<string name="AndroidManifest__verify_safety_number">Verify safety number</string> <string name="AndroidManifest__verify_safety_number">Verify safety number</string>
<string name="AndroidManifest__log_submit">Submit debug log</string> <string name="AndroidManifest__log_submit">Submit debug log</string>
<string name="AndroidManifest__media_preview">Media preview</string> <string name="AndroidManifest__media_preview">Media preview</string>
<string name="AndroidManifest__media_overview">All images</string> <string name="AndroidManifest__all_media">All media</string>
<string name="AndroidManifest__media_overview_named">All images with %1$s</string> <string name="AndroidManifest__all_media_named">All media with %1$s</string>
<string name="AndroidManifest__message_details">Message details</string> <string name="AndroidManifest__message_details">Message details</string>
<string name="AndroidManifest__linked_devices">Linked devices</string> <string name="AndroidManifest__linked_devices">Linked devices</string>
<string name="AndroidManifest__invite_friends">Invite friends</string> <string name="AndroidManifest__invite_friends">Invite friends</string>
@ -1233,7 +1233,7 @@
<string name="conversation__menu_edit_group">Edit group</string> <string name="conversation__menu_edit_group">Edit group</string>
<string name="conversation__menu_leave_group">Leave group</string> <string name="conversation__menu_leave_group">Leave group</string>
<string name="conversation__menu_delete_thread">Delete conversation</string> <string name="conversation__menu_delete_thread">Delete conversation</string>
<string name="conversation__menu_view_media">All images</string> <string name="conversation__menu_view_all_media">All media</string>
<string name="conversation__menu_conversation_settings">Conversation settings</string> <string name="conversation__menu_conversation_settings">Conversation settings</string>
<!-- conversation_popup --> <!-- conversation_popup -->
@ -1296,13 +1296,13 @@
<!-- media_preview --> <!-- media_preview -->
<string name="media_preview__save_title">Save</string> <string name="media_preview__save_title">Save</string>
<string name="media_preview__forward_title">Forward</string> <string name="media_preview__forward_title">Forward</string>
<string name="media_preview__overview_title">All images</string> <string name="media_preview__all_media_title">All media</string>
<!-- media_overview --> <!-- media_overview -->
<string name="media_overview__save_all">Save all</string> <string name="media_overview__save_all">Save all</string>
<!-- media_preview_activity --> <!-- media_preview_activity -->
<string name="media_preview_activity__image_content_description">Image preview</string> <string name="media_preview_activity__media_content_description">Media preview</string>
<!-- new_conversation_activity --> <!-- new_conversation_activity -->
<string name="new_conversation_activity__refresh">Refresh</string> <string name="new_conversation_activity__refresh">Refresh</string>

View File

@ -27,18 +27,18 @@ import android.view.View;
import android.view.View.OnClickListener; import android.view.View.OnClickListener;
import android.view.ViewGroup; import android.view.ViewGroup;
import org.thoughtcrime.securesms.ImageMediaAdapter.ViewHolder; import org.thoughtcrime.securesms.MediaAdapter.ViewHolder;
import org.thoughtcrime.securesms.components.ThumbnailView; import org.thoughtcrime.securesms.components.ThumbnailView;
import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter; import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter;
import org.thoughtcrime.securesms.database.ImageDatabase.ImageRecord; import org.thoughtcrime.securesms.database.MediaDatabase.MediaRecord;
import org.thoughtcrime.securesms.mms.Slide; import org.thoughtcrime.securesms.mms.Slide;
import org.thoughtcrime.securesms.recipients.RecipientFactory; import org.thoughtcrime.securesms.recipients.RecipientFactory;
import org.thoughtcrime.securesms.recipients.Recipients; import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.util.MediaUtil; import org.thoughtcrime.securesms.util.MediaUtil;
public class ImageMediaAdapter extends CursorRecyclerViewAdapter<ViewHolder> { public class MediaAdapter extends CursorRecyclerViewAdapter<ViewHolder> {
private static final String TAG = ImageMediaAdapter.class.getSimpleName(); private static final String TAG = MediaAdapter.class.getSimpleName();
private final MasterSecret masterSecret; private final MasterSecret masterSecret;
private final long threadId; private final long threadId;
@ -52,7 +52,7 @@ public class ImageMediaAdapter extends CursorRecyclerViewAdapter<ViewHolder> {
} }
} }
public ImageMediaAdapter(Context context, MasterSecret masterSecret, Cursor c, long threadId) { public MediaAdapter(Context context, MasterSecret masterSecret, Cursor c, long threadId) {
super(context, c); super(context, c);
this.masterSecret = masterSecret; this.masterSecret = masterSecret;
this.threadId = threadId; this.threadId = threadId;
@ -67,40 +67,41 @@ public class ImageMediaAdapter extends CursorRecyclerViewAdapter<ViewHolder> {
@Override @Override
public void onBindItemViewHolder(final ViewHolder viewHolder, final @NonNull Cursor cursor) { public void onBindItemViewHolder(final ViewHolder viewHolder, final @NonNull Cursor cursor) {
final ThumbnailView imageView = viewHolder.imageView; final ThumbnailView imageView = viewHolder.imageView;
final ImageRecord imageRecord = ImageRecord.from(cursor); final MediaRecord mediaRecord = MediaRecord.from(cursor);
Slide slide = MediaUtil.getSlideForAttachment(getContext(), imageRecord.getAttachment()); Slide slide = MediaUtil.getSlideForAttachment(getContext(), mediaRecord.getAttachment());
if (slide != null) { if (slide != null) {
imageView.setImageResource(masterSecret, slide, false); imageView.setImageResource(masterSecret, slide, false);
} }
imageView.setOnClickListener(new OnMediaClickListener(imageRecord)); imageView.setOnClickListener(new OnMediaClickListener(mediaRecord));
} }
private class OnMediaClickListener implements OnClickListener { private class OnMediaClickListener implements OnClickListener {
private final ImageRecord imageRecord; private final MediaRecord mediaRecord;
private OnMediaClickListener(ImageRecord imageRecord) { private OnMediaClickListener(MediaRecord mediaRecord) {
this.imageRecord = imageRecord; this.mediaRecord = mediaRecord;
} }
@Override @Override
public void onClick(View v) { public void onClick(View v) {
if (imageRecord.getAttachment().getDataUri() != null) { if (mediaRecord.getAttachment().getDataUri() != null) {
Intent intent = new Intent(getContext(), MediaPreviewActivity.class); Intent intent = new Intent(getContext(), MediaPreviewActivity.class);
intent.putExtra(MediaPreviewActivity.DATE_EXTRA, imageRecord.getDate()); intent.putExtra(MediaPreviewActivity.DATE_EXTRA, mediaRecord.getDate());
intent.putExtra(MediaPreviewActivity.SIZE_EXTRA, mediaRecord.getAttachment().getSize());
intent.putExtra(MediaPreviewActivity.THREAD_ID_EXTRA, threadId); intent.putExtra(MediaPreviewActivity.THREAD_ID_EXTRA, threadId);
if (!TextUtils.isEmpty(imageRecord.getAddress())) { if (!TextUtils.isEmpty(mediaRecord.getAddress())) {
Recipients recipients = RecipientFactory.getRecipientsFromString(getContext(), Recipients recipients = RecipientFactory.getRecipientsFromString(getContext(),
imageRecord.getAddress(), mediaRecord.getAddress(),
true); true);
if (recipients != null && recipients.getPrimaryRecipient() != null) { if (recipients != null && recipients.getPrimaryRecipient() != null) {
intent.putExtra(MediaPreviewActivity.RECIPIENT_EXTRA, recipients.getPrimaryRecipient().getRecipientId()); intent.putExtra(MediaPreviewActivity.RECIPIENT_EXTRA, recipients.getPrimaryRecipient().getRecipientId());
} }
} }
intent.setDataAndType(imageRecord.getAttachment().getDataUri(), imageRecord.getContentType()); intent.setDataAndType(mediaRecord.getAttachment().getDataUri(), mediaRecord.getContentType());
getContext().startActivity(intent); getContext().startActivity(intent);
} }
} }

View File

@ -40,7 +40,7 @@ import android.widget.TextView;
import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter; import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter;
import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.ImageDatabase.ImageRecord; import org.thoughtcrime.securesms.database.MediaDatabase.MediaRecord;
import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.Recipient.RecipientModifiedListener; import org.thoughtcrime.securesms.recipients.Recipient.RecipientModifiedListener;
import org.thoughtcrime.securesms.recipients.RecipientFactory; import org.thoughtcrime.securesms.recipients.RecipientFactory;
@ -114,8 +114,8 @@ public class MediaOverviewActivity extends PassphraseRequiredActionBarActivity i
private void initializeActionBar() { private void initializeActionBar() {
getSupportActionBar().setTitle(recipient == null getSupportActionBar().setTitle(recipient == null
? getString(R.string.AndroidManifest__media_overview) ? getString(R.string.AndroidManifest__all_media)
: getString(R.string.AndroidManifest__media_overview_named, recipient.toShortString())); : getString(R.string.AndroidManifest__all_media_named, recipient.toShortString()));
} }
@Override @Override
@ -162,11 +162,11 @@ public class MediaOverviewActivity extends PassphraseRequiredActionBarActivity i
R.string.please_wait) { R.string.please_wait) {
@Override @Override
protected List<SaveAttachmentTask.Attachment> doInBackground(Void... params) { protected List<SaveAttachmentTask.Attachment> doInBackground(Void... params) {
Cursor cursor = DatabaseFactory.getImageDatabase(c).getImagesForThread(threadId); Cursor cursor = DatabaseFactory.getMediaDatabase(c).getMediaForThread(threadId);
List<SaveAttachmentTask.Attachment> attachments = new ArrayList<>(cursor.getCount()); List<SaveAttachmentTask.Attachment> attachments = new ArrayList<>(cursor.getCount());
while (cursor != null && cursor.moveToNext()) { while (cursor != null && cursor.moveToNext()) {
ImageRecord record = ImageRecord.from(cursor); MediaRecord record = MediaRecord.from(cursor);
attachments.add(new SaveAttachmentTask.Attachment(record.getAttachment().getDataUri(), attachments.add(new SaveAttachmentTask.Attachment(record.getAttachment().getDataUri(),
record.getContentType(), record.getContentType(),
record.getDate())); record.getDate()));
@ -220,7 +220,7 @@ public class MediaOverviewActivity extends PassphraseRequiredActionBarActivity i
@Override @Override
public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) { public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
Log.w(TAG, "onLoadFinished()"); Log.w(TAG, "onLoadFinished()");
gridView.setAdapter(new ImageMediaAdapter(this, masterSecret, cursor, threadId)); gridView.setAdapter(new MediaAdapter(this, masterSecret, cursor, threadId));
noImages.setVisibility(gridView.getAdapter().getItemCount() > 0 ? View.GONE : View.VISIBLE); noImages.setVisibility(gridView.getAdapter().getItemCount() > 0 ? View.GONE : View.VISIBLE);
invalidateOptionsMenu(); invalidateOptionsMenu();
} }
@ -240,7 +240,7 @@ public class MediaOverviewActivity extends PassphraseRequiredActionBarActivity i
@Override @Override
public Cursor getCursor() { public Cursor getCursor() {
return DatabaseFactory.getImageDatabase(getContext()).getImagesForThread(threadId); return DatabaseFactory.getMediaDatabase(getContext()).getMediaForThread(threadId);
} }
} }
} }

View File

@ -87,7 +87,7 @@ public class DatabaseFactory {
private final EncryptingSmsDatabase encryptingSms; private final EncryptingSmsDatabase encryptingSms;
private final MmsDatabase mms; private final MmsDatabase mms;
private final AttachmentDatabase attachments; private final AttachmentDatabase attachments;
private final ImageDatabase image; private final MediaDatabase media;
private final ThreadDatabase thread; private final ThreadDatabase thread;
private final CanonicalAddressDatabase address; private final CanonicalAddressDatabase address;
private final MmsAddressDatabase mmsAddress; private final MmsAddressDatabase mmsAddress;
@ -136,8 +136,8 @@ public class DatabaseFactory {
return getInstance(context).attachments; return getInstance(context).attachments;
} }
public static ImageDatabase getImageDatabase(Context context) { public static MediaDatabase getMediaDatabase(Context context) {
return getInstance(context).image; return getInstance(context).media;
} }
public static MmsAddressDatabase getMmsAddressDatabase(Context context) { public static MmsAddressDatabase getMmsAddressDatabase(Context context) {
@ -174,7 +174,7 @@ public class DatabaseFactory {
this.encryptingSms = new EncryptingSmsDatabase(context, databaseHelper); this.encryptingSms = new EncryptingSmsDatabase(context, databaseHelper);
this.mms = new MmsDatabase(context, databaseHelper); this.mms = new MmsDatabase(context, databaseHelper);
this.attachments = new AttachmentDatabase(context, databaseHelper); this.attachments = new AttachmentDatabase(context, databaseHelper);
this.image = new ImageDatabase(context, databaseHelper); this.media = new MediaDatabase(context, databaseHelper);
this.thread = new ThreadDatabase(context, databaseHelper); this.thread = new ThreadDatabase(context, databaseHelper);
this.address = CanonicalAddressDatabase.getInstance(context); this.address = CanonicalAddressDatabase.getInstance(context);
this.mmsAddress = new MmsAddressDatabase(context, databaseHelper); this.mmsAddress = new MmsAddressDatabase(context, databaseHelper);

View File

@ -9,9 +9,9 @@ import org.thoughtcrime.securesms.attachments.Attachment;
import org.thoughtcrime.securesms.attachments.AttachmentId; import org.thoughtcrime.securesms.attachments.AttachmentId;
import org.thoughtcrime.securesms.attachments.DatabaseAttachment; import org.thoughtcrime.securesms.attachments.DatabaseAttachment;
public class ImageDatabase extends Database { public class MediaDatabase extends Database {
private final static String IMAGES_QUERY = "SELECT " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.ROW_ID + ", " private final static String MEDIA_QUERY = "SELECT " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.ROW_ID + ", "
+ AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.CONTENT_TYPE + ", " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.CONTENT_TYPE + ", "
+ AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.THUMBNAIL_ASPECT_RATIO + ", " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.THUMBNAIL_ASPECT_RATIO + ", "
+ AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.UNIQUE_ID + ", " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.UNIQUE_ID + ", "
@ -28,23 +28,24 @@ public class ImageDatabase extends Database {
+ " ON " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.MMS_ID + " = " + MmsDatabase.TABLE_NAME + "." + MmsDatabase.ID + " " + " ON " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.MMS_ID + " = " + MmsDatabase.TABLE_NAME + "." + MmsDatabase.ID + " "
+ "WHERE " + AttachmentDatabase.MMS_ID + " IN (SELECT " + MmsSmsColumns.ID + "WHERE " + AttachmentDatabase.MMS_ID + " IN (SELECT " + MmsSmsColumns.ID
+ " FROM " + MmsDatabase.TABLE_NAME + " FROM " + MmsDatabase.TABLE_NAME
+ " WHERE " + MmsDatabase.THREAD_ID + " = ?) AND " + " WHERE " + MmsDatabase.THREAD_ID + " = ?) AND ("
+ AttachmentDatabase.CONTENT_TYPE + " LIKE 'image/%' AND " + AttachmentDatabase.CONTENT_TYPE + " LIKE 'image/%' OR "
+ AttachmentDatabase.CONTENT_TYPE + " LIKE 'video/%') AND "
+ AttachmentDatabase.DATA + " IS NOT NULL " + AttachmentDatabase.DATA + " IS NOT NULL "
+ "ORDER BY " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.ROW_ID + " DESC"; + "ORDER BY " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.ROW_ID + " DESC";
public ImageDatabase(Context context, SQLiteOpenHelper databaseHelper) { public MediaDatabase(Context context, SQLiteOpenHelper databaseHelper) {
super(context, databaseHelper); super(context, databaseHelper);
} }
public Cursor getImagesForThread(long threadId) { public Cursor getMediaForThread(long threadId) {
SQLiteDatabase database = databaseHelper.getReadableDatabase(); SQLiteDatabase database = databaseHelper.getReadableDatabase();
Cursor cursor = database.rawQuery(IMAGES_QUERY, new String[]{threadId+""}); Cursor cursor = database.rawQuery(MEDIA_QUERY, new String[]{threadId+""});
setNotifyConverationListeners(cursor, threadId); setNotifyConverationListeners(cursor, threadId);
return cursor; return cursor;
} }
public static class ImageRecord { public static class MediaRecord {
private final AttachmentId attachmentId; private final AttachmentId attachmentId;
private final long mmsId; private final long mmsId;
private final boolean hasData; private final boolean hasData;
@ -55,7 +56,7 @@ public class ImageDatabase extends Database {
private final int transferState; private final int transferState;
private final long size; private final long size;
private ImageRecord(AttachmentId attachmentId, long mmsId, private MediaRecord(AttachmentId attachmentId, long mmsId,
boolean hasData, boolean hasThumbnail, boolean hasData, boolean hasThumbnail,
String contentType, String address, long date, String contentType, String address, long date,
int transferState, long size) int transferState, long size)
@ -71,7 +72,7 @@ public class ImageDatabase extends Database {
this.size = size; this.size = size;
} }
public static ImageRecord from(Cursor cursor) { public static MediaRecord from(Cursor cursor) {
AttachmentId attachmentId = new AttachmentId(cursor.getLong(cursor.getColumnIndexOrThrow(AttachmentDatabase.ROW_ID)), AttachmentId attachmentId = new AttachmentId(cursor.getLong(cursor.getColumnIndexOrThrow(AttachmentDatabase.ROW_ID)),
cursor.getLong(cursor.getColumnIndexOrThrow(AttachmentDatabase.UNIQUE_ID))); cursor.getLong(cursor.getColumnIndexOrThrow(AttachmentDatabase.UNIQUE_ID)));
@ -83,7 +84,7 @@ public class ImageDatabase extends Database {
date = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.DATE_RECEIVED)); date = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.DATE_RECEIVED));
} }
return new ImageRecord(attachmentId, return new MediaRecord(attachmentId,
cursor.getLong(cursor.getColumnIndexOrThrow(AttachmentDatabase.MMS_ID)), cursor.getLong(cursor.getColumnIndexOrThrow(AttachmentDatabase.MMS_ID)),
!cursor.isNull(cursor.getColumnIndexOrThrow(AttachmentDatabase.DATA)), !cursor.isNull(cursor.getColumnIndexOrThrow(AttachmentDatabase.DATA)),
!cursor.isNull(cursor.getColumnIndexOrThrow(AttachmentDatabase.THUMBNAIL)), !cursor.isNull(cursor.getColumnIndexOrThrow(AttachmentDatabase.THUMBNAIL)),