mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-02 00:17:41 +01:00
Add links to the all media view.
This commit is contained in:
committed by
Cody Henthorne
parent
25b01a30be
commit
08491579dd
@@ -61,8 +61,9 @@ class MediaTable internal constructor(context: Context?, databaseHelper: SignalD
|
||||
${MessageTable.TABLE_NAME}.${MessageTable.DATE_RECEIVED},
|
||||
${MessageTable.TABLE_NAME}.${MessageTable.DATE_SERVER},
|
||||
${MessageTable.TABLE_NAME}.${MessageTable.THREAD_ID},
|
||||
${MessageTable.TABLE_NAME}.${MessageTable.FROM_RECIPIENT_ID},
|
||||
${ThreadTable.TABLE_NAME}.${ThreadTable.RECIPIENT_ID} as $THREAD_RECIPIENT_ID
|
||||
${MessageTable.TABLE_NAME}.${MessageTable.FROM_RECIPIENT_ID},
|
||||
${ThreadTable.TABLE_NAME}.${ThreadTable.RECIPIENT_ID} as $THREAD_RECIPIENT_ID,
|
||||
${MessageTable.TABLE_NAME}.${MessageTable.LINK_PREVIEWS}
|
||||
FROM
|
||||
${AttachmentTable.TABLE_NAME}
|
||||
LEFT JOIN ${MessageTable.TABLE_NAME} ON ${AttachmentTable.TABLE_NAME}.${AttachmentTable.MESSAGE_ID} = ${MessageTable.TABLE_NAME}.${MessageTable.ID}
|
||||
@@ -135,6 +136,69 @@ class MediaTable internal constructor(context: Context?, databaseHelper: SignalD
|
||||
"""
|
||||
)
|
||||
|
||||
private val LINK_MEDIA_QUERY = """
|
||||
SELECT
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.ID} AS ${AttachmentTable.ID},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.CONTENT_TYPE},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.MESSAGE_ID},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.TRANSFER_STATE},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.DATA_SIZE},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.FILE_NAME},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.DATA_FILE},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.THUMBNAIL_FILE},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.CDN_NUMBER},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.REMOTE_LOCATION},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.REMOTE_KEY},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.REMOTE_DIGEST},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.FAST_PREFLIGHT_ID},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.VOICE_NOTE},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.BORDERLESS},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.VIDEO_GIF},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.WIDTH},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.HEIGHT},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.QUOTE},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.QUOTE_TARGET_CONTENT_TYPE},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.STICKER_PACK_ID},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.STICKER_PACK_KEY},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.STICKER_ID},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.STICKER_EMOJI},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.BLUR_HASH},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.TRANSFORM_PROPERTIES},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.DISPLAY_ORDER},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.CAPTION},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.UPLOAD_TIMESTAMP},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.REMOTE_INCREMENTAL_DIGEST},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.REMOTE_INCREMENTAL_DIGEST_CHUNK_SIZE},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.DATA_HASH_END},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.ARCHIVE_CDN},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.THUMBNAIL_RESTORE_STATE},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.ARCHIVE_TRANSFER_STATE},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.ATTACHMENT_UUID},
|
||||
${MessageTable.TABLE_NAME}.${MessageTable.TYPE},
|
||||
${MessageTable.TABLE_NAME}.${MessageTable.DATE_SENT},
|
||||
${MessageTable.TABLE_NAME}.${MessageTable.DATE_RECEIVED},
|
||||
${MessageTable.TABLE_NAME}.${MessageTable.DATE_SERVER},
|
||||
${MessageTable.TABLE_NAME}.${MessageTable.THREAD_ID},
|
||||
${MessageTable.TABLE_NAME}.${MessageTable.FROM_RECIPIENT_ID},
|
||||
${ThreadTable.TABLE_NAME}.${ThreadTable.RECIPIENT_ID} as $THREAD_RECIPIENT_ID,
|
||||
${MessageTable.TABLE_NAME}.${MessageTable.LINK_PREVIEWS}
|
||||
FROM
|
||||
${MessageTable.TABLE_NAME}
|
||||
LEFT JOIN ${AttachmentTable.TABLE_NAME} ON ${AttachmentTable.TABLE_NAME}.${AttachmentTable.MESSAGE_ID} = ${MessageTable.TABLE_NAME}.${MessageTable.ID}
|
||||
AND ${AttachmentTable.TABLE_NAME}.${AttachmentTable.QUOTE} = 0
|
||||
AND ${AttachmentTable.TABLE_NAME}.${AttachmentTable.STICKER_PACK_ID} IS NULL
|
||||
LEFT JOIN ${ThreadTable.TABLE_NAME} ON ${ThreadTable.TABLE_NAME}.${ThreadTable.ID} = ${MessageTable.TABLE_NAME}.${MessageTable.THREAD_ID}
|
||||
WHERE
|
||||
${MessageTable.TABLE_NAME}.${MessageTable.THREAD_ID} __EQUALITY__ ? AND
|
||||
${MessageTable.TABLE_NAME}.${MessageTable.LINK_PREVIEWS} IS NOT NULL AND
|
||||
${MessageTable.TABLE_NAME}.${MessageTable.VIEW_ONCE} = 0 AND
|
||||
${MessageTable.TABLE_NAME}.${MessageTable.STORY_TYPE} = 0 AND
|
||||
${MessageTable.TABLE_NAME}.${MessageTable.LATEST_REVISION_ID} IS NULL AND
|
||||
${MessageTable.TABLE_NAME}.${MessageTable.FROM_RECIPIENT_ID} > 0 AND
|
||||
$THREAD_RECIPIENT_ID > 0 AND
|
||||
${MessageTable.TABLE_NAME}.${MessageTable.SCHEDULED_DATE} < 0
|
||||
"""
|
||||
|
||||
private val DOCUMENT_MEDIA_QUERY = String.format(
|
||||
BASE_MEDIA_QUERY,
|
||||
"""
|
||||
@@ -180,6 +244,17 @@ class MediaTable internal constructor(context: Context?, databaseHelper: SignalD
|
||||
return readableDatabase.rawQuery(query, args)
|
||||
}
|
||||
|
||||
fun getLinkMediaForThread(threadId: Long, sorting: Sorting): Cursor {
|
||||
val orderBy = when (sorting) {
|
||||
Sorting.Newest -> " ORDER BY ${MessageTable.TABLE_NAME}.${MessageTable.DATE_SENT} DESC"
|
||||
Sorting.Oldest -> " ORDER BY ${MessageTable.TABLE_NAME}.${MessageTable.DATE_SENT} ASC"
|
||||
Sorting.Largest -> " ORDER BY ${AttachmentTable.TABLE_NAME}.${AttachmentTable.DATA_SIZE} DESC"
|
||||
}
|
||||
val query = applyEqualityOperator(threadId, LINK_MEDIA_QUERY) + orderBy
|
||||
val args = arrayOf(threadId.toString())
|
||||
return readableDatabase.rawQuery(query, args)
|
||||
}
|
||||
|
||||
fun getAllMediaForThread(threadId: Long, sorting: Sorting): Cursor {
|
||||
val query = sorting.applyToQuery(applyEqualityOperator(threadId, ALL_MEDIA_QUERY))
|
||||
val args = arrayOf(threadId.toString() + "")
|
||||
@@ -236,7 +311,8 @@ class MediaTable internal constructor(context: Context?, databaseHelper: SignalD
|
||||
val threadRecipientId: RecipientId,
|
||||
val threadId: Long,
|
||||
val date: Long,
|
||||
val isOutgoing: Boolean
|
||||
val isOutgoing: Boolean,
|
||||
val linkPreviewJson: String? = null
|
||||
) {
|
||||
|
||||
val contentType: String?
|
||||
@@ -245,8 +321,11 @@ class MediaTable internal constructor(context: Context?, databaseHelper: SignalD
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun from(cursor: Cursor): MediaRecord {
|
||||
val linkPreviewIdx = cursor.getColumnIndex(MessageTable.LINK_PREVIEWS)
|
||||
val attachmentIdIdx = cursor.getColumnIndex(AttachmentTable.ID)
|
||||
val hasAttachment = attachmentIdIdx != -1 && !cursor.isNull(attachmentIdIdx)
|
||||
return MediaRecord(
|
||||
attachment = SignalDatabase.attachments.getAttachment(cursor),
|
||||
attachment = if (hasAttachment) SignalDatabase.attachments.getAttachment(cursor) else null,
|
||||
recipientId = RecipientId.from(cursor.requireLong(MessageTable.FROM_RECIPIENT_ID)),
|
||||
threadId = cursor.requireLong(MessageTable.THREAD_ID),
|
||||
threadRecipientId = RecipientId.from(cursor.requireLong(THREAD_RECIPIENT_ID)),
|
||||
@@ -255,7 +334,8 @@ class MediaTable internal constructor(context: Context?, databaseHelper: SignalD
|
||||
} else {
|
||||
cursor.requireLong(MessageTable.DATE_RECEIVED)
|
||||
},
|
||||
isOutgoing = MessageTypes.isOutgoingMessageType(cursor.requireLong(MessageTable.TYPE))
|
||||
isOutgoing = MessageTypes.isOutgoingMessageType(cursor.requireLong(MessageTable.TYPE)),
|
||||
linkPreviewJson = if (linkPreviewIdx != -1) cursor.getString(linkPreviewIdx) else null
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ public abstract class MediaLoader extends AbstractCursorLoader {
|
||||
GALLERY,
|
||||
DOCUMENT,
|
||||
AUDIO,
|
||||
LINK,
|
||||
ALL
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ public final class ThreadMediaLoader extends MediaLoader {
|
||||
case GALLERY : return mediaDatabase.getGalleryMediaForThread(threadId, sorting);
|
||||
case DOCUMENT: return mediaDatabase.getDocumentMediaForThread(threadId, sorting);
|
||||
case AUDIO : return mediaDatabase.getAudioMediaForThread(threadId, sorting);
|
||||
case LINK : return mediaDatabase.getLinkMediaForThread(threadId, sorting);
|
||||
case ALL : return mediaDatabase.getAllMediaForThread(threadId, sorting);
|
||||
default : throw new AssertionError();
|
||||
}
|
||||
|
||||
@@ -32,6 +32,10 @@ import androidx.annotation.Nullable;
|
||||
import androidx.lifecycle.Observer;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import com.annimon.stream.Collectors;
|
||||
import com.annimon.stream.Stream;
|
||||
import com.bumptech.glide.RequestManager;
|
||||
@@ -53,6 +57,7 @@ import org.thoughtcrime.securesms.mms.AudioSlide;
|
||||
import org.thoughtcrime.securesms.mms.Slide;
|
||||
import org.thoughtcrime.securesms.recipients.LiveRecipient;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.CommunicationActions;
|
||||
import org.thoughtcrime.securesms.util.DateUtils;
|
||||
import org.thoughtcrime.securesms.util.MediaUtil;
|
||||
import org.signal.core.util.Util;
|
||||
@@ -89,6 +94,7 @@ final class MediaGalleryAllAdapter extends StickyHeaderGridAdapter {
|
||||
public static final int GALLERY = 2;
|
||||
private static final int GALLERY_DETAIL = 3;
|
||||
private static final int DOCUMENT_DETAIL = 4;
|
||||
private static final int LINK_DETAIL = 5;
|
||||
|
||||
private static final int PAYLOAD_SELECTED = 1;
|
||||
|
||||
@@ -142,6 +148,8 @@ final class MediaGalleryAllAdapter extends StickyHeaderGridAdapter {
|
||||
return new GalleryDetailViewHolder(LayoutInflater.from(context).inflate(R.layout.media_overview_detail_item_media, parent, false));
|
||||
case AUDIO_DETAIL:
|
||||
return new AudioDetailViewHolder(LayoutInflater.from(context).inflate(R.layout.media_overview_detail_item_audio, parent, false));
|
||||
case LINK_DETAIL:
|
||||
return new LinkDetailViewHolder(LayoutInflater.from(context).inflate(R.layout.media_overview_detail_item_link, parent, false));
|
||||
default:
|
||||
return new DocumentDetailViewHolder(LayoutInflater.from(context).inflate(R.layout.media_overview_detail_item_document, parent, false));
|
||||
}
|
||||
@@ -150,7 +158,11 @@ final class MediaGalleryAllAdapter extends StickyHeaderGridAdapter {
|
||||
@Override
|
||||
public int getSectionItemViewType(int section, int offset) {
|
||||
MediaTable.MediaRecord mediaRecord = media.get(section, offset);
|
||||
Slide slide = MediaUtil.getSlideForAttachment(mediaRecord.getAttachment());
|
||||
|
||||
if (mediaRecord.getLinkPreviewJson() != null) return LINK_DETAIL;
|
||||
if (mediaRecord.getAttachment() == null) return 0;
|
||||
|
||||
Slide slide = MediaUtil.getSlideForAttachment(mediaRecord.getAttachment());
|
||||
|
||||
if (slide.hasAudio()) return AUDIO_DETAIL;
|
||||
if (slide.hasImage() || slide.hasVideo()) return detailView ? GALLERY_DETAIL : GALLERY;
|
||||
@@ -177,7 +189,7 @@ final class MediaGalleryAllAdapter extends StickyHeaderGridAdapter {
|
||||
@Override
|
||||
public void onBindItemViewHolder(ItemViewHolder viewHolder, int section, int offset) {
|
||||
MediaTable.MediaRecord mediaRecord = media.get(section, offset);
|
||||
Slide slide = MediaUtil.getSlideForAttachment(mediaRecord.getAttachment());
|
||||
Slide slide = mediaRecord.getAttachment() != null ? MediaUtil.getSlideForAttachment(mediaRecord.getAttachment()) : null;
|
||||
|
||||
((SelectableViewHolder) viewHolder).bind(context, mediaRecord, slide);
|
||||
}
|
||||
@@ -209,6 +221,8 @@ final class MediaGalleryAllAdapter extends StickyHeaderGridAdapter {
|
||||
}
|
||||
|
||||
public void toggleSelection(@NonNull MediaRecord mediaRecord) {
|
||||
if (mediaRecord.getAttachment() == null) return;
|
||||
|
||||
AttachmentId attachmentId = mediaRecord.getAttachment().attachmentId;
|
||||
MediaTable.MediaRecord removed = selected.remove(attachmentId);
|
||||
if (removed == null) {
|
||||
@@ -244,7 +258,9 @@ final class MediaGalleryAllAdapter extends StickyHeaderGridAdapter {
|
||||
int sectionItemCount = media.getSectionItemCount(section);
|
||||
for (int item = 0; item < sectionItemCount; item++) {
|
||||
MediaRecord mediaRecord = media.get(section, item);
|
||||
selected.put(mediaRecord.getAttachment().attachmentId, mediaRecord);
|
||||
if (mediaRecord.getAttachment() != null) {
|
||||
selected.put(mediaRecord.getAttachment().attachmentId, mediaRecord);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.notifyItemRangeChanged(0, getItemCount(), PAYLOAD_SELECTED);
|
||||
@@ -270,7 +286,7 @@ final class MediaGalleryAllAdapter extends StickyHeaderGridAdapter {
|
||||
this.selectedIndicator = itemView.findViewById(R.id.selected_indicator);
|
||||
}
|
||||
|
||||
public void bind(@NonNull Context context, @NonNull MediaTable.MediaRecord mediaRecord, @NonNull Slide slide) {
|
||||
public void bind(@NonNull Context context, @NonNull MediaTable.MediaRecord mediaRecord, @Nullable Slide slide) {
|
||||
if (bound) {
|
||||
unbind();
|
||||
}
|
||||
@@ -288,7 +304,7 @@ final class MediaGalleryAllAdapter extends StickyHeaderGridAdapter {
|
||||
}
|
||||
|
||||
protected boolean isSelected() {
|
||||
return selected.containsKey(mediaRecord.getAttachment().attachmentId);
|
||||
return mediaRecord.getAttachment() != null && selected.containsKey(mediaRecord.getAttachment().attachmentId);
|
||||
}
|
||||
|
||||
protected void updateSelectedView() {
|
||||
@@ -413,10 +429,10 @@ final class MediaGalleryAllAdapter extends StickyHeaderGridAdapter {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind(@NonNull Context context, @NonNull MediaTable.MediaRecord mediaRecord, @NonNull Slide slide) {
|
||||
public void bind(@NonNull Context context, @NonNull MediaTable.MediaRecord mediaRecord, @Nullable Slide slide) {
|
||||
super.bind(context, mediaRecord, slide);
|
||||
|
||||
fileName = slide.getFileName();
|
||||
fileName = slide != null ? slide.getFileName() : Optional.empty();
|
||||
fileTypeDescription = getFileTypeDescription(context, slide);
|
||||
|
||||
line1.setText(fileName.orElse(fileTypeDescription));
|
||||
@@ -449,14 +465,17 @@ final class MediaGalleryAllAdapter extends StickyHeaderGridAdapter {
|
||||
super.unbind();
|
||||
}
|
||||
|
||||
private String getLine2(@NonNull Context context, @NonNull MediaTable.MediaRecord mediaRecord, @NonNull Slide slide) {
|
||||
private String getLine2(@NonNull Context context, @NonNull MediaTable.MediaRecord mediaRecord, @Nullable Slide slide) {
|
||||
if (slide == null) {
|
||||
return DateUtils.formatDateWithoutDayOfWeek(Locale.getDefault(), mediaRecord.getDate());
|
||||
}
|
||||
return context.getString(R.string.MediaOverviewActivity_detail_line_3_part,
|
||||
new ByteSize(slide.getFileSize()).toUnitString(2),
|
||||
getFileTypeDescription(context, slide),
|
||||
DateUtils.formatDateWithoutDayOfWeek(Locale.getDefault(), mediaRecord.getDate()));
|
||||
}
|
||||
|
||||
protected String getFileTypeDescription(@NonNull Context context, @NonNull Slide slide) {
|
||||
protected String getFileTypeDescription(@NonNull Context context, @Nullable Slide slide) {
|
||||
return context.getString(R.string.MediaOverviewActivity_file);
|
||||
}
|
||||
|
||||
@@ -609,7 +628,7 @@ final class MediaGalleryAllAdapter extends StickyHeaderGridAdapter {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getFileTypeDescription(@NonNull Context context, @NonNull Slide slide) {
|
||||
protected String getFileTypeDescription(@NonNull Context context, @Nullable Slide slide) {
|
||||
return context.getString(R.string.MediaOverviewActivity_audio);
|
||||
}
|
||||
}
|
||||
@@ -641,9 +660,9 @@ final class MediaGalleryAllAdapter extends StickyHeaderGridAdapter {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getFileTypeDescription(@NonNull Context context, @NonNull Slide slide) {
|
||||
if (slide.hasVideo()) return context.getString(R.string.MediaOverviewActivity_video);
|
||||
if (slide.hasImage()) return context.getString(R.string.MediaOverviewActivity_image);
|
||||
protected String getFileTypeDescription(@NonNull Context context, @Nullable Slide slide) {
|
||||
if (slide != null && slide.hasVideo()) return context.getString(R.string.MediaOverviewActivity_video);
|
||||
if (slide != null && slide.hasImage()) return context.getString(R.string.MediaOverviewActivity_image);
|
||||
return super.getFileTypeDescription(context, slide);
|
||||
}
|
||||
|
||||
@@ -660,6 +679,107 @@ final class MediaGalleryAllAdapter extends StickyHeaderGridAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
private class LinkDetailViewHolder extends DetailViewHolder {
|
||||
|
||||
private final ThumbnailView thumbnailView;
|
||||
private final TextView linkUrlView;
|
||||
|
||||
private Slide slide;
|
||||
private String linkUrl;
|
||||
private String linkTitle;
|
||||
|
||||
LinkDetailViewHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
this.thumbnailView = itemView.findViewById(R.id.image);
|
||||
this.linkUrlView = itemView.findViewById(R.id.link_url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind(@NonNull Context context, @NonNull MediaTable.MediaRecord mediaRecord, @Nullable Slide slide) {
|
||||
parseLinkPreview(mediaRecord);
|
||||
super.bind(context, mediaRecord, slide);
|
||||
this.slide = slide;
|
||||
|
||||
if (slide != null) {
|
||||
thumbnailView.setVisibility(View.VISIBLE);
|
||||
thumbnailView.setImageResource(requestManager, slide, false, false);
|
||||
} else {
|
||||
thumbnailView.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
thumbnailView.setOnLongClickListener(view -> onLongClick());
|
||||
|
||||
View.OnClickListener openLink = view -> {
|
||||
if (linkUrl != null && !linkUrl.isEmpty()) {
|
||||
CommunicationActions.openBrowserLink(context, linkUrl);
|
||||
}
|
||||
};
|
||||
thumbnailView.setOnClickListener(openLink);
|
||||
itemView.setOnClickListener(openLink);
|
||||
|
||||
if (linkUrl != null && !linkUrl.isEmpty()) {
|
||||
linkUrlView.setText(linkUrl);
|
||||
linkUrlView.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
linkUrlView.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
TextView line2View = itemView.findViewById(R.id.line2);
|
||||
line2View.setText(DateUtils.formatDateWithoutDayOfWeek(Locale.getDefault(), mediaRecord.getDate()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable String getMediaTitle() {
|
||||
if (linkTitle != null && !linkTitle.isEmpty()) {
|
||||
return linkTitle;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NonNull View getTransitionAnchor() {
|
||||
return itemView;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getFileTypeDescription(@NonNull Context context, @Nullable Slide slide) {
|
||||
return context.getString(R.string.MediaOverviewActivity_link);
|
||||
}
|
||||
|
||||
@Override
|
||||
void rebind() {
|
||||
if (slide != null) {
|
||||
thumbnailView.setImageResource(requestManager, slide, false, false);
|
||||
}
|
||||
super.rebind();
|
||||
}
|
||||
|
||||
@Override
|
||||
void unbind() {
|
||||
if (slide != null) {
|
||||
thumbnailView.clear(requestManager);
|
||||
}
|
||||
super.unbind();
|
||||
}
|
||||
|
||||
private void parseLinkPreview(@NonNull MediaTable.MediaRecord mediaRecord) {
|
||||
linkUrl = "";
|
||||
linkTitle = "";
|
||||
if (mediaRecord.getLinkPreviewJson() != null) {
|
||||
try {
|
||||
JSONArray json = new JSONArray(mediaRecord.getLinkPreviewJson());
|
||||
if (json.length() > 0) {
|
||||
JSONObject preview = json.getJSONObject(0);
|
||||
linkUrl = preview.optString("url", "");
|
||||
linkTitle = preview.optString("title", "");
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final class AudioViewCallbacksAdapter implements AudioView.Callbacks {
|
||||
|
||||
private final AudioItemListener audioItemListener;
|
||||
|
||||
@@ -128,7 +128,7 @@ public final class MediaOverviewActivity extends PassphraseRequiredActivity {
|
||||
}
|
||||
});
|
||||
|
||||
viewPager.setCurrentItem(allThreads ? 3 : 0);
|
||||
viewPager.setCurrentItem(allThreads ? viewPager.getAdapter().getCount() - 1 : 0);
|
||||
}
|
||||
|
||||
private static boolean allowGridSelectionOnPage(int page) {
|
||||
@@ -264,10 +264,15 @@ public final class MediaOverviewActivity extends PassphraseRequiredActivity {
|
||||
MediaOverviewPagerAdapter(FragmentManager fragmentManager) {
|
||||
super(fragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
|
||||
|
||||
pages = new ArrayList<>(4);
|
||||
boolean allThreads = threadId == MediaTable.ALL_THREADS;
|
||||
|
||||
pages = new ArrayList<>(allThreads ? 4 : 5);
|
||||
pages.add(new Pair<>(MediaLoader.MediaType.GALLERY, getString(R.string.MediaOverviewActivity_Media)));
|
||||
pages.add(new Pair<>(MediaLoader.MediaType.DOCUMENT, getString(R.string.MediaOverviewActivity_Files)));
|
||||
pages.add(new Pair<>(MediaLoader.MediaType.AUDIO, getString(R.string.MediaOverviewActivity_Audio)));
|
||||
if (!allThreads) {
|
||||
pages.add(new Pair<>(MediaLoader.MediaType.LINK, getString(R.string.MediaOverviewActivity_Links)));
|
||||
}
|
||||
pages.add(new Pair<>(MediaLoader.MediaType.ALL, getString(R.string.MediaOverviewActivity_All)));
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="?android:attr/colorControlHighlight" />
|
||||
<corners android:radius="8dp" />
|
||||
</shape>
|
||||
88
app/src/main/res/layout/media_overview_detail_item_link.xml
Normal file
88
app/src/main/res/layout/media_overview_detail_item_link.xml
Normal file
@@ -0,0 +1,88 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
tools:viewBindingIgnore="true"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="@dimen/media_overview_detail_item_height">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/image_container"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginStart="@dimen/dsl_settings_gutter"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/link_fallback_icon"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_gravity="center"
|
||||
android:background="@drawable/media_overview_link_fallback_bg"
|
||||
android:importantForAccessibility="no"
|
||||
android:padding="12dp"
|
||||
android:scaleType="centerInside"
|
||||
app:srcCompat="@drawable/symbol_link_24"
|
||||
app:tint="@color/signal_icon_tint_secondary" />
|
||||
|
||||
<org.thoughtcrime.securesms.components.ThumbnailView
|
||||
android:id="@+id/image"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_gravity="center"
|
||||
android:contentDescription="@string/media_preview_activity__media_content_description"
|
||||
app:thumbnail_radius="8dp"
|
||||
app:transparent_overlay_color="@color/transparent_black_08" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<include layout="@layout/media_overview_selected_overlay" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/media_overview_text"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="@dimen/dsl_settings_gutter"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/image_container"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/line1"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="marquee"
|
||||
android:marqueeRepeatLimit="marquee_forever"
|
||||
android:singleLine="true"
|
||||
android:textAppearance="@style/Signal.Text.Body"
|
||||
tools:text="Article Title - Sent by Alice" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/link_url"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:singleLine="true"
|
||||
android:textAppearance="@style/TextAppearance.Signal.Body2"
|
||||
android:textColor="@color/signal_text_secondary"
|
||||
tools:text="https://example.com/some/long/article/path" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/line2"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="marquee"
|
||||
android:singleLine="true"
|
||||
android:textAppearance="@style/TextAppearance.Signal.Body2"
|
||||
android:textColor="@color/signal_text_secondary"
|
||||
tools:text="11.06.19 at 5:25 AM" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -1780,6 +1780,8 @@
|
||||
<string name="MediaOverviewActivity_Files">Files</string>
|
||||
<string name="MediaOverviewActivity_Audio">Audio</string>
|
||||
<string name="MediaOverviewActivity_All">All</string>
|
||||
<string name="MediaOverviewActivity_Links">Links</string>
|
||||
<string name="MediaOverviewActivity_link">Link</string>
|
||||
<plurals name="MediaOverviewActivity_Media_delete_confirm_title">
|
||||
<item quantity="one">Delete selected item?</item>
|
||||
<item quantity="other">Delete selected items?</item>
|
||||
|
||||
Reference in New Issue
Block a user