Add archive state indicator to media chat items.

This commit is contained in:
Cody Henthorne
2025-06-10 15:24:18 -04:00
committed by GitHub
parent 536b599449
commit 2394972620
13 changed files with 155 additions and 1 deletions

View File

@@ -1,6 +1,7 @@
package org.thoughtcrime.securesms.components;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.PorterDuff;
@@ -33,10 +34,12 @@ import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.attachments.DatabaseAttachment;
import org.thoughtcrime.securesms.audio.AudioWaveForms;
import org.thoughtcrime.securesms.components.voice.VoiceNotePlaybackState;
import org.thoughtcrime.securesms.database.AttachmentTable;
import org.thoughtcrime.securesms.events.PartProgressEvent;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.mms.AudioSlide;
import org.thoughtcrime.securesms.mms.SlideClickListener;
@@ -246,6 +249,22 @@ public final class AudioView extends FrameLayout {
}
this.audioSlide = audio;
if (SignalStore.internal().getShowArchiveStateHint() && audioSlide.asAttachment() instanceof DatabaseAttachment) {
DatabaseAttachment dbAttachment = (DatabaseAttachment) audioSlide.asAttachment();
View mediaArchive = findViewById(R.id.thumbnail_media_archive);
if (mediaArchive != null) {
mediaArchive.setVisibility(View.VISIBLE);
switch (dbAttachment.archiveTransferState) {
case NONE -> mediaArchive.setBackgroundTintList(ColorStateList.valueOf(Color.BLACK));
case COPY_PENDING -> mediaArchive.setBackgroundTintList(ColorStateList.valueOf(Color.BLUE));
case UPLOAD_IN_PROGRESS -> mediaArchive.setBackgroundTintList(ColorStateList.valueOf(Color.CYAN));
case FINISHED -> mediaArchive.setBackgroundTintList(ColorStateList.valueOf(Color.GREEN));
case TEMPORARY_FAILURE -> mediaArchive.setBackgroundTintList(ColorStateList.valueOf(Color.YELLOW));
case PERMANENT_FAILURE -> mediaArchive.setBackgroundTintList(ColorStateList.valueOf(Color.RED));
}
}
}
}
public void setDownloadClickListener(@Nullable SlideClickListener listener) {

View File

@@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.components;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.PorterDuff;
@@ -23,8 +24,10 @@ import org.greenrobot.eventbus.ThreadMode;
import org.signal.core.util.ByteSize;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.attachments.DatabaseAttachment;
import org.thoughtcrime.securesms.database.AttachmentTable;
import org.thoughtcrime.securesms.events.PartProgressEvent;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.mms.Slide;
import org.thoughtcrime.securesms.mms.SlideClickListener;
import org.thoughtcrime.securesms.mms.SlidesClickedListener;
@@ -138,6 +141,20 @@ public class DocumentView extends FrameLayout {
this.fileSize.setText(new ByteSize(documentSlide.getFileSize()).toUnitString(2));
this.document.setText(documentSlide.getFileType(getContext()).orElse("").toLowerCase());
this.setOnClickListener(new OpenClickedListener(documentSlide));
if (SignalStore.internal().getShowArchiveStateHint() && documentSlide.asAttachment() instanceof DatabaseAttachment) {
DatabaseAttachment dbAttachment = (DatabaseAttachment) documentSlide.asAttachment();
View mediaArchive = findViewById(R.id.thumbnail_media_archive);
mediaArchive.setVisibility(View.VISIBLE);
switch (dbAttachment.archiveTransferState) {
case NONE -> mediaArchive.setBackgroundTintList(ColorStateList.valueOf(Color.BLACK));
case COPY_PENDING -> mediaArchive.setBackgroundTintList(ColorStateList.valueOf(Color.BLUE));
case UPLOAD_IN_PROGRESS -> mediaArchive.setBackgroundTintList(ColorStateList.valueOf(Color.CYAN));
case FINISHED -> mediaArchive.setBackgroundTintList(ColorStateList.valueOf(Color.GREEN));
case TEMPORARY_FAILURE -> mediaArchive.setBackgroundTintList(ColorStateList.valueOf(Color.YELLOW));
case PERMANENT_FAILURE -> mediaArchive.setBackgroundTintList(ColorStateList.valueOf(Color.RED));
}
}
}
@Override

View File

@@ -6,6 +6,7 @@
package org.thoughtcrime.securesms.components;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
@@ -45,6 +46,8 @@ import org.thoughtcrime.securesms.attachments.DatabaseAttachment;
import org.thoughtcrime.securesms.blurhash.BlurHash;
import org.thoughtcrime.securesms.components.transfercontrols.TransferControlView;
import org.thoughtcrime.securesms.database.AttachmentTable;
import org.thoughtcrime.securesms.keyvalue.InternalValues;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader.DecryptableUri;
import org.thoughtcrime.securesms.mms.ImageSlide;
import org.thoughtcrime.securesms.mms.PartAuthority;
@@ -55,6 +58,7 @@ import org.thoughtcrime.securesms.mms.VideoSlide;
import org.thoughtcrime.securesms.stories.StoryTextPostModel;
import org.thoughtcrime.securesms.util.AttachmentUtil;
import org.thoughtcrime.securesms.util.MediaUtil;
import org.thoughtcrime.securesms.util.RemoteConfig;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.views.Stub;
@@ -415,7 +419,21 @@ public class ThumbnailView extends FrameLayout {
Attachment slideAttachment = slide.asAttachment();
String id;
if (slideAttachment instanceof DatabaseAttachment) {
id = ((DatabaseAttachment) slideAttachment).attachmentId.serialize();
DatabaseAttachment dbAttachment = (DatabaseAttachment) slideAttachment;
id = dbAttachment.attachmentId.serialize();
if (SignalStore.internal().getShowArchiveStateHint()) {
View mediaArchive = findViewById(R.id.thumbnail_media_archive);
mediaArchive.setVisibility(View.VISIBLE);
switch (dbAttachment.archiveTransferState) {
case NONE -> mediaArchive.setBackgroundTintList(ColorStateList.valueOf(Color.BLACK));
case COPY_PENDING -> mediaArchive.setBackgroundTintList(ColorStateList.valueOf(Color.BLUE));
case UPLOAD_IN_PROGRESS -> mediaArchive.setBackgroundTintList(ColorStateList.valueOf(Color.CYAN));
case FINISHED -> mediaArchive.setBackgroundTintList(ColorStateList.valueOf(Color.GREEN));
case TEMPORARY_FAILURE -> mediaArchive.setBackgroundTintList(ColorStateList.valueOf(Color.YELLOW));
case PERMANENT_FAILURE -> mediaArchive.setBackgroundTintList(ColorStateList.valueOf(Color.RED));
}
}
} else {
final Uri uri = slideAttachment.getUri();
if (uri != null) {

View File

@@ -248,6 +248,15 @@ class InternalSettingsFragment : DSLSettingsFragment(R.string.preferences__inter
}
)
switchPref(
title = DSLSettingsText.from("Show archive status hint"),
summary = DSLSettingsText.from("Shows a color square based on archive status, green good, red bad."),
isChecked = state.showArchiveStateHint,
onClick = {
viewModel.setShowMediaArchiveStateHint(!state.showArchiveStateHint)
}
)
clickPref(
title = DSLSettingsText.from("Log dump PreKey ServiceId-KeyIds"),
onClick = {

View File

@@ -6,6 +6,7 @@ import org.thoughtcrime.securesms.emoji.EmojiFiles
data class InternalSettingsState(
val seeMoreUserDetails: Boolean,
val shakeToReport: Boolean,
val showArchiveStateHint: Boolean,
val gv2forceInvites: Boolean,
val gv2ignoreP2PChanges: Boolean,
val allowCensorshipSetting: Boolean,

View File

@@ -44,6 +44,11 @@ class InternalSettingsViewModel(private val repository: InternalSettingsReposito
refresh()
}
fun setShowMediaArchiveStateHint(enabled: Boolean) {
preferenceDataStore.putBoolean(InternalValues.SHOW_ARCHIVE_STATE_HINT, enabled)
refresh()
}
fun setDisableStorageService(enabled: Boolean) {
preferenceDataStore.putBoolean(InternalValues.DISABLE_STORAGE_SERVICE, enabled)
refresh()
@@ -167,6 +172,7 @@ class InternalSettingsViewModel(private val repository: InternalSettingsReposito
private fun getState() = InternalSettingsState(
seeMoreUserDetails = SignalStore.internal.recipientDetails,
shakeToReport = SignalStore.internal.shakeToReport,
showArchiveStateHint = SignalStore.internal.showArchiveStateHint,
gv2forceInvites = SignalStore.internal.gv2ForceInvites,
gv2ignoreP2PChanges = SignalStore.internal.gv2IgnoreP2PChanges,
allowCensorshipSetting = SignalStore.internal.allowChangingCensorshipSetting,

View File

@@ -33,6 +33,7 @@ class InternalValues internal constructor(store: KeyValueStore) : SignalStoreVal
const val NEW_CALL_UI: String = "internal.new.call.ui"
const val LARGE_SCREEN_UI: String = "internal.large.screen.ui"
const val FORCE_SPLIT_PANE_ON_COMPACT_LANDSCAPE: String = "internal.force.split.pane.on.compact.landscape.ui"
const val SHOW_ARCHIVE_STATE_HINT: String = "internal.show_archive_state_hint"
}
public override fun onFirstEverAppLaunch() = Unit
@@ -178,6 +179,8 @@ class InternalValues internal constructor(store: KeyValueStore) : SignalStoreVal
var forceSsre2Capability by booleanValue("internal.force_ssre2_capability", false).defaultForExternalUsers()
var showArchiveStateHint by booleanValue(SHOW_ARCHIVE_STATE_HINT, false).defaultForExternalUsers()
private fun <T> SignalStoreValueDelegate<T>.defaultForExternalUsers(): SignalStoreValueDelegate<T> {
return this.withPrecondition { RemoteConfig.internalUser }
}

View File

@@ -17,6 +17,8 @@
package org.thoughtcrime.securesms.mediaoverview;
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.Color;
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
@@ -39,12 +41,14 @@ import org.signal.core.util.ByteSize;
import org.signal.libsignal.protocol.util.Pair;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.attachments.AttachmentId;
import org.thoughtcrime.securesms.attachments.DatabaseAttachment;
import org.thoughtcrime.securesms.components.AudioView;
import org.thoughtcrime.securesms.components.ThumbnailView;
import org.thoughtcrime.securesms.components.voice.VoiceNotePlaybackState;
import org.thoughtcrime.securesms.database.MediaTable;
import org.thoughtcrime.securesms.database.MediaTable.MediaRecord;
import org.thoughtcrime.securesms.database.loaders.GroupedThreadMediaLoader.GroupedThreadMedia;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.mediapreview.MediaPreviewCache;
import org.thoughtcrime.securesms.mms.AudioSlide;
import org.thoughtcrime.securesms.mms.Slide;
@@ -520,6 +524,22 @@ final class MediaGalleryAllAdapter extends StickyHeaderGridAdapter {
super.bind(context, mediaRecord, slide);
documentType.setText(slide.getFileType(context).orElse("").toLowerCase());
if (SignalStore.internal().getShowArchiveStateHint() && slide.asAttachment() instanceof DatabaseAttachment) {
DatabaseAttachment dbAttachment = (DatabaseAttachment) slide.asAttachment();
View mediaArchive = itemView.findViewById(R.id.thumbnail_media_archive);
if (mediaArchive != null) {
mediaArchive.setVisibility(View.VISIBLE);
switch (dbAttachment.archiveTransferState) {
case NONE -> mediaArchive.setBackgroundTintList(ColorStateList.valueOf(Color.BLACK));
case COPY_PENDING -> mediaArchive.setBackgroundTintList(ColorStateList.valueOf(Color.BLUE));
case UPLOAD_IN_PROGRESS -> mediaArchive.setBackgroundTintList(ColorStateList.valueOf(Color.CYAN));
case FINISHED -> mediaArchive.setBackgroundTintList(ColorStateList.valueOf(Color.GREEN));
case TEMPORARY_FAILURE -> mediaArchive.setBackgroundTintList(ColorStateList.valueOf(Color.YELLOW));
case PERMANENT_FAILURE -> mediaArchive.setBackgroundTintList(ColorStateList.valueOf(Color.RED));
}
}
}
}
}
@@ -552,6 +572,22 @@ final class MediaGalleryAllAdapter extends StickyHeaderGridAdapter {
audioView.setOnClickListener(view -> itemClickListener.onMediaClicked(audioView, mediaRecord));
itemView.setOnClickListener(view -> itemClickListener.onMediaClicked(audioView, mediaRecord));
if (SignalStore.internal().getShowArchiveStateHint() && slide.asAttachment() instanceof DatabaseAttachment) {
DatabaseAttachment dbAttachment = (DatabaseAttachment) slide.asAttachment();
View mediaArchive = itemView.findViewById(R.id.thumbnail_media_archive);
if (mediaArchive != null) {
mediaArchive.setVisibility(View.VISIBLE);
switch (dbAttachment.archiveTransferState) {
case NONE -> mediaArchive.setBackgroundTintList(ColorStateList.valueOf(Color.BLACK));
case COPY_PENDING -> mediaArchive.setBackgroundTintList(ColorStateList.valueOf(Color.BLUE));
case UPLOAD_IN_PROGRESS -> mediaArchive.setBackgroundTintList(ColorStateList.valueOf(Color.CYAN));
case FINISHED -> mediaArchive.setBackgroundTintList(ColorStateList.valueOf(Color.GREEN));
case TEMPORARY_FAILURE -> mediaArchive.setBackgroundTintList(ColorStateList.valueOf(Color.YELLOW));
case PERMANENT_FAILURE -> mediaArchive.setBackgroundTintList(ColorStateList.valueOf(Color.RED));
}
}
}
}
@Override