diff --git a/app/build.gradle.kts b/app/build.gradle.kts index dfa060a161..32f90cc83c 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -26,8 +26,8 @@ configurations.configureEach { exclude(module = "commons-logging") } -val canonicalVersionCode = 430 -val canonicalVersionName = "1.29.1" +val canonicalVersionCode = 431 +val canonicalVersionName = "1.29.2" val postFixSize = 10 val abiPostFix = mapOf( diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt index 6de900eb76..8440cb6562 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt @@ -59,6 +59,7 @@ import androidx.recyclerview.widget.RecyclerView import com.annimon.stream.Stream import com.bumptech.glide.Glide import com.squareup.phrase.Phrase +import dagger.Lazy import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.lifecycle.withCreationCallback import kotlinx.coroutines.CancellationException @@ -263,7 +264,6 @@ class ConversationActivityV2 : ScreenLockActionBarActivity(), InputBarDelegate, @Inject lateinit var typingStatusRepository: TypingStatusRepository @Inject lateinit var typingStatusSender: TypingStatusSender @Inject lateinit var openGroupManager: OpenGroupManager - @Inject lateinit var attachmentDatabase: AttachmentDatabase @Inject lateinit var clock: SnodeClock @Inject @ManagerScope lateinit var scope: CoroutineScope diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/mentions/MentionCandidateView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/mentions/MentionCandidateView.kt index 7b6619a1eb..46101962f9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/mentions/MentionCandidateView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/mentions/MentionCandidateView.kt @@ -1,11 +1,11 @@ package org.thoughtcrime.securesms.conversation.v2.input_bar.mentions -import android.view.View import network.loki.messenger.databinding.ViewMentionCandidateV2Binding import org.thoughtcrime.securesms.conversation.v2.mention.MentionViewModel import org.thoughtcrime.securesms.ui.components.Avatar import org.thoughtcrime.securesms.ui.setThemedContent import org.thoughtcrime.securesms.ui.theme.LocalDimensions +import org.thoughtcrime.securesms.util.AvatarBadge fun ViewMentionCandidateV2Binding.update(candidate: MentionViewModel.Candidate) { mentionCandidateNameTextView.text = candidate.nameHighlighted @@ -13,8 +13,7 @@ fun ViewMentionCandidateV2Binding.update(candidate: MentionViewModel.Candidate) Avatar( size = LocalDimensions.current.iconMediumAvatar, data = candidate.member.avatarData, + badge = if (candidate.member.showAdminCrown) AvatarBadge.Admin else AvatarBadge.None ) } - - moderatorIconImageView.visibility = if (candidate.member.showAdminCrown) View.VISIBLE else View.GONE } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt index 8796834bbe..3f883900ed 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt @@ -61,6 +61,7 @@ import org.thoughtcrime.securesms.ui.theme.LocalColors import org.thoughtcrime.securesms.ui.theme.LocalDimensions import org.thoughtcrime.securesms.ui.theme.LocalType import org.thoughtcrime.securesms.ui.theme.bold +import org.thoughtcrime.securesms.util.AvatarBadge import org.thoughtcrime.securesms.util.AvatarUtils import org.thoughtcrime.securesms.util.DateUtils import org.thoughtcrime.securesms.util.disableClipping @@ -176,7 +177,6 @@ class VisibleMessageView : FrameLayout { val isStartOfMessageCluster = isStartOfMessageCluster(message, previous, isGroupThread) val isEndOfMessageCluster = isEndOfMessageCluster(message, next, isGroupThread) // Show profile picture and sender name if this is a group thread AND the message is incoming - binding.moderatorIconImageView.isVisible = false binding.profilePictureView.visibility = when { threadRecipient.isGroupOrCommunityRecipient && !message.isOutgoing && isEndOfMessageCluster -> View.VISIBLE threadRecipient.isGroupOrCommunityRecipient -> View.INVISIBLE @@ -200,22 +200,22 @@ class VisibleMessageView : FrameLayout { if (isGroupThread && !message.isOutgoing) { if (isEndOfMessageCluster) { + val showProBadge = if (sender.address is Address.WithAccountId) { + (threadRecipient.data as? RecipientData.GroupLike) + ?.shouldShowAdminCrown(sender.address.accountId) == true + } else { + false + } binding.profilePictureView.setThemedContent { Avatar( size = LocalDimensions.current.iconMediumAvatar, data = avatarUtils.getUIDataFromRecipient(sender), + badge = if(showProBadge) AvatarBadge.Admin else AvatarBadge.None, modifier = Modifier.clickable { delegate?.showUserProfileModal(message.recipient) } ) } - - binding.moderatorIconImageView.isVisible = if (sender.address is Address.WithAccountId) { - (threadRecipient.data as? RecipientData.GroupLike) - ?.shouldShowAdminCrown(sender.address.accountId) == true - } else { - false - } } } if(!message.isOutgoing && (isStartOfMessageCluster && isGroupThread)){ diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/AttachmentDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/AttachmentDatabase.java index 6f07a7f4af..c7564523bc 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/AttachmentDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/AttachmentDatabase.java @@ -26,17 +26,16 @@ import android.text.TextUtils; import android.util.Pair; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import com.bumptech.glide.Glide; import net.zetetic.database.sqlcipher.SQLiteDatabase; -import org.apache.commons.lang3.StringUtils; import org.json.JSONArray; import org.json.JSONException; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; import org.session.libsession.messaging.sending_receiving.attachments.Attachment; import org.session.libsession.messaging.sending_receiving.attachments.AttachmentId; import org.session.libsession.messaging.sending_receiving.attachments.AttachmentState; @@ -80,14 +79,19 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; +import javax.inject.Inject; import javax.inject.Provider; +import javax.inject.Singleton; +import dagger.Lazy; +import dagger.hilt.android.qualifiers.ApplicationContext; import kotlin.jvm.Synchronized; import kotlinx.coroutines.channels.BufferOverflow; import kotlinx.coroutines.flow.MutableSharedFlow; import kotlinx.coroutines.flow.SharedFlow; import kotlinx.coroutines.flow.SharedFlowKt; +@Singleton public class AttachmentDatabase extends Database { private static final String TAG = AttachmentDatabase.class.getSimpleName(); @@ -161,13 +165,18 @@ public class AttachmentDatabase extends Database { final ExecutorService thumbnailExecutor = Util.newSingleThreadedLifoExecutor(); - private final AttachmentSecret attachmentSecret; + private final Lazy<@NonNull AttachmentSecret> attachmentSecret; private final MutableSharedFlow mutableChangesNotification = SharedFlowKt.MutableSharedFlow( 0, 100, BufferOverflow.DROP_OLDEST ); - public AttachmentDatabase(Context context, Provider databaseHelper, AttachmentSecret attachmentSecret) { + @Inject + public AttachmentDatabase( + @ApplicationContext Context context, + Provider databaseHelper, + Lazy<@NonNull AttachmentSecret> attachmentSecret + ) { super(context, databaseHelper); this.attachmentSecret = attachmentSecret; } @@ -535,9 +544,9 @@ public void setTransferState(@NonNull AttachmentId attachmentId, int transferSta try { if (dataInfo.random != null && dataInfo.random.length == 32) { - return ModernDecryptingPartInputStream.createFor(attachmentSecret, dataInfo.random, dataInfo.file, offset); + return ModernDecryptingPartInputStream.createFor(attachmentSecret.get(), dataInfo.random, dataInfo.file, offset); } else { - InputStream stream = ClassicDecryptingPartInputStream.createFor(attachmentSecret, dataInfo.file); + InputStream stream = ClassicDecryptingPartInputStream.createFor(attachmentSecret.get(), dataInfo.file); long skipped = stream.skip(offset); if (skipped != offset) { @@ -607,7 +616,7 @@ public void setTransferState(@NonNull AttachmentId attachmentId, int transferSta File dataFile = File.createTempFile("part", ".mms", partsDirectory); Log.d("AttachmentDatabase", "Writing attachment data to: " + dataFile.getAbsolutePath()); - Pair out = ModernEncryptingPartOutputStream.createFor(attachmentSecret, dataFile, false); + Pair out = ModernEncryptingPartOutputStream.createFor(attachmentSecret.get(), dataFile, false); long length = Util.copy(in, out.second); return new DataInfo(dataFile, length, out.first); @@ -894,7 +903,7 @@ private ThumbnailData generateVideoThumbnail(AttachmentId attachmentId) { return null; } - EncryptedMediaDataSource dataSource = new EncryptedMediaDataSource(attachmentSecret, dataInfo.file, dataInfo.random, dataInfo.length); + EncryptedMediaDataSource dataSource = new EncryptedMediaDataSource(attachmentSecret.get(), dataInfo.file, dataInfo.random, dataInfo.length); MediaMetadataRetriever retriever = new MediaMetadataRetriever(); retriever.setDataSource(dataSource); diff --git a/app/src/main/java/org/thoughtcrime/securesms/dependencies/DatabaseModule.kt b/app/src/main/java/org/thoughtcrime/securesms/dependencies/DatabaseModule.kt index 8fe5cfd092..862f5ea07c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/dependencies/DatabaseModule.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/dependencies/DatabaseModule.kt @@ -54,11 +54,6 @@ object DatabaseModule { return manager.openHelper } - @Provides - @Singleton - fun provideAttachmentDatabase(@ApplicationContext context: Context, - openHelper: Provider, - attachmentSecret: AttachmentSecret) = AttachmentDatabase(context, openHelper, attachmentSecret) @Provides @Singleton fun provideMediaDatbase(@ApplicationContext context: Context, openHelper: Provider) = MediaDatabase(context, openHelper) diff --git a/app/src/main/java/org/thoughtcrime/securesms/glide/cache/EncryptedBitmapCacheDecoder.java b/app/src/main/java/org/thoughtcrime/securesms/glide/cache/EncryptedBitmapCacheDecoder.java index 91f2cb2f26..aa60bbb1da 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/glide/cache/EncryptedBitmapCacheDecoder.java +++ b/app/src/main/java/org/thoughtcrime/securesms/glide/cache/EncryptedBitmapCacheDecoder.java @@ -2,15 +2,18 @@ import android.graphics.Bitmap; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import org.session.libsignal.utilities.Log; import com.bumptech.glide.load.Options; import com.bumptech.glide.load.ResourceDecoder; import com.bumptech.glide.load.engine.Resource; import com.bumptech.glide.load.resource.bitmap.StreamBitmapDecoder; +import org.session.libsignal.utilities.Log; +import org.thoughtcrime.securesms.crypto.AttachmentSecretProvider; + import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -20,10 +23,10 @@ public class EncryptedBitmapCacheDecoder extends EncryptedCoder implements Resou private static final String TAG = EncryptedBitmapCacheDecoder.class.getSimpleName(); private final StreamBitmapDecoder streamBitmapDecoder; - private final byte[] secret; + private final AttachmentSecretProvider attachmentSecretProvider; - public EncryptedBitmapCacheDecoder(@NonNull byte[] secret, @NonNull StreamBitmapDecoder streamBitmapDecoder) { - this.secret = secret; + public EncryptedBitmapCacheDecoder(@NonNull AttachmentSecretProvider attachmentSecretProvider, @NonNull StreamBitmapDecoder streamBitmapDecoder) { + this.attachmentSecretProvider = attachmentSecretProvider; this.streamBitmapDecoder = streamBitmapDecoder; } @@ -33,7 +36,7 @@ public boolean handles(@NonNull File source, @NonNull Options options) { Log.i(TAG, "Checking item for encrypted Bitmap cache decoder: " + source.toString()); - try (InputStream inputStream = createEncryptedInputStream(secret, source)) { + try (InputStream inputStream = createEncryptedInputStream(attachmentSecretProvider.getOrCreateAttachmentSecret().getModernKey(), source)) { return streamBitmapDecoder.handles(inputStream, options); } catch (IOException e) { Log.w(TAG, e); @@ -47,7 +50,7 @@ public Resource decode(@NonNull File source, int width, int height, @Non throws IOException { Log.i(TAG, "Encrypted Bitmap cache decoder running: " + source.toString()); - try (InputStream inputStream = createEncryptedInputStream(secret, source)) { + try (InputStream inputStream = createEncryptedInputStream(attachmentSecretProvider.getOrCreateAttachmentSecret().getModernKey(), source)) { return streamBitmapDecoder.decode(inputStream, width, height, options); } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/glide/cache/EncryptedBitmapResourceEncoder.java b/app/src/main/java/org/thoughtcrime/securesms/glide/cache/EncryptedBitmapResourceEncoder.java index e10e3ecc6e..53d0a7be10 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/glide/cache/EncryptedBitmapResourceEncoder.java +++ b/app/src/main/java/org/thoughtcrime/securesms/glide/cache/EncryptedBitmapResourceEncoder.java @@ -4,6 +4,7 @@ import android.graphics.Bitmap; import androidx.annotation.NonNull; import org.session.libsignal.utilities.Log; +import org.thoughtcrime.securesms.crypto.AttachmentSecretProvider; import com.bumptech.glide.load.EncodeStrategy; import com.bumptech.glide.load.Options; @@ -19,10 +20,10 @@ public class EncryptedBitmapResourceEncoder extends EncryptedCoder implements Re private static final String TAG = EncryptedBitmapResourceEncoder.class.getSimpleName(); - private final byte[] secret; + private final AttachmentSecretProvider secretProvider; - public EncryptedBitmapResourceEncoder(@NonNull byte[] secret) { - this.secret = secret; + public EncryptedBitmapResourceEncoder(@NonNull AttachmentSecretProvider secretProvider) { + this.secretProvider = secretProvider; } @Override @@ -39,7 +40,7 @@ public boolean encode(@NonNull Resource data, @NonNull File file, @NonNu Bitmap.CompressFormat format = getFormat(bitmap, options); int quality = options.get(BitmapEncoder.COMPRESSION_QUALITY); - try (OutputStream os = createEncryptedOutputStream(secret, file)) { + try (OutputStream os = createEncryptedOutputStream(secretProvider.getOrCreateAttachmentSecret().getModernKey(), file)) { bitmap.compress(format, quality, os); os.close(); return true; diff --git a/app/src/main/java/org/thoughtcrime/securesms/glide/cache/EncryptedCacheEncoder.java b/app/src/main/java/org/thoughtcrime/securesms/glide/cache/EncryptedCacheEncoder.java index c5f91ae2ab..d64281d4d7 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/glide/cache/EncryptedCacheEncoder.java +++ b/app/src/main/java/org/thoughtcrime/securesms/glide/cache/EncryptedCacheEncoder.java @@ -1,28 +1,31 @@ package org.thoughtcrime.securesms.glide.cache; -import androidx.annotation.NonNull; import com.bumptech.glide.load.Encoder; import com.bumptech.glide.load.Options; import com.bumptech.glide.load.engine.bitmap_recycle.ArrayPool; +import org.jspecify.annotations.NonNull; import org.session.libsignal.utilities.Log; +import org.thoughtcrime.securesms.crypto.AttachmentSecretProvider; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import dagger.Lazy; + public class EncryptedCacheEncoder extends EncryptedCoder implements Encoder { private static final String TAG = EncryptedCacheEncoder.class.getSimpleName(); - private final byte[] secret; + private final AttachmentSecretProvider attachmentSecretProvider; private final ArrayPool byteArrayPool; - public EncryptedCacheEncoder(@NonNull byte[] secret, @NonNull ArrayPool byteArrayPool) { - this.secret = secret; + public EncryptedCacheEncoder(AttachmentSecretProvider attachmentSecretProvider, @NonNull ArrayPool byteArrayPool) { + this.attachmentSecretProvider = attachmentSecretProvider; this.byteArrayPool = byteArrayPool; } @@ -33,7 +36,7 @@ public boolean encode(@NonNull InputStream data, @NonNull File file, @NonNull Op byte[] buffer = byteArrayPool.get(ArrayPool.STANDARD_BUFFER_SIZE_BYTES, byte[].class); - try (OutputStream outputStream = createEncryptedOutputStream(secret, file)) { + try (OutputStream outputStream = createEncryptedOutputStream(attachmentSecretProvider.getOrCreateAttachmentSecret().getModernKey(), file)) { int read; while ((read = data.read(buffer)) != -1) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/glide/cache/EncryptedGifCacheDecoder.java b/app/src/main/java/org/thoughtcrime/securesms/glide/cache/EncryptedGifCacheDecoder.java index 24a678c8fa..79b47ba416 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/glide/cache/EncryptedGifCacheDecoder.java +++ b/app/src/main/java/org/thoughtcrime/securesms/glide/cache/EncryptedGifCacheDecoder.java @@ -4,6 +4,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import org.session.libsignal.utilities.Log; +import org.thoughtcrime.securesms.crypto.AttachmentSecretProvider; import com.bumptech.glide.load.Options; import com.bumptech.glide.load.ResourceDecoder; @@ -19,11 +20,11 @@ public class EncryptedGifCacheDecoder extends EncryptedCoder implements Resource private static final String TAG = EncryptedGifCacheDecoder.class.getSimpleName(); - private final byte[] secret; + private final AttachmentSecretProvider attachmentSecretProvider; private final StreamGifDecoder gifDecoder; - public EncryptedGifCacheDecoder(@NonNull byte[] secret, @NonNull StreamGifDecoder gifDecoder) { - this.secret = secret; + public EncryptedGifCacheDecoder(@NonNull AttachmentSecretProvider attachmentSecretProvider, @NonNull StreamGifDecoder gifDecoder) { + this.attachmentSecretProvider = attachmentSecretProvider; this.gifDecoder = gifDecoder; } @@ -31,7 +32,7 @@ public EncryptedGifCacheDecoder(@NonNull byte[] secret, @NonNull StreamGifDecode public boolean handles(@NonNull File source, @NonNull Options options) { Log.i(TAG, "Checking item for encrypted GIF cache decoder: " + source.toString()); - try (InputStream inputStream = createEncryptedInputStream(secret, source)) { + try (InputStream inputStream = createEncryptedInputStream(attachmentSecretProvider.getOrCreateAttachmentSecret().getModernKey(), source)) { return gifDecoder.handles(inputStream, options); } catch (IOException e) { Log.w(TAG, e); @@ -43,7 +44,7 @@ public boolean handles(@NonNull File source, @NonNull Options options) { @Override public Resource decode(@NonNull File source, int width, int height, @NonNull Options options) throws IOException { Log.i(TAG, "Encrypted GIF cache decoder running..."); - try (InputStream inputStream = createEncryptedInputStream(secret, source)) { + try (InputStream inputStream = createEncryptedInputStream(attachmentSecretProvider.getOrCreateAttachmentSecret().getModernKey(), source)) { return gifDecoder.decode(inputStream, width, height, options); } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/glide/cache/EncryptedGifDrawableResourceEncoder.java b/app/src/main/java/org/thoughtcrime/securesms/glide/cache/EncryptedGifDrawableResourceEncoder.java index a208e81c3e..4d8ad44ec5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/glide/cache/EncryptedGifDrawableResourceEncoder.java +++ b/app/src/main/java/org/thoughtcrime/securesms/glide/cache/EncryptedGifDrawableResourceEncoder.java @@ -3,6 +3,7 @@ import androidx.annotation.NonNull; import org.session.libsignal.utilities.Log; +import org.thoughtcrime.securesms.crypto.AttachmentSecretProvider; import com.bumptech.glide.load.EncodeStrategy; import com.bumptech.glide.load.Options; @@ -19,10 +20,10 @@ public class EncryptedGifDrawableResourceEncoder extends EncryptedCoder implemen private static final String TAG = EncryptedGifDrawableResourceEncoder.class.getSimpleName(); - private final byte[] secret; + private final AttachmentSecretProvider secretProvider; - public EncryptedGifDrawableResourceEncoder(@NonNull byte[] secret) { - this.secret = secret; + public EncryptedGifDrawableResourceEncoder(@NonNull AttachmentSecretProvider secretProvider) { + this.secretProvider = secretProvider; } @Override @@ -34,7 +35,7 @@ public EncodeStrategy getEncodeStrategy(@NonNull Options options) { public boolean encode(@NonNull Resource data, @NonNull File file, @NonNull Options options) { GifDrawable drawable = data.get(); - try (OutputStream outputStream = createEncryptedOutputStream(secret, file)) { + try (OutputStream outputStream = createEncryptedOutputStream(secretProvider.getOrCreateAttachmentSecret().getModernKey(), file)) { ByteBufferUtil.toStream(drawable.getBuffer(), outputStream); return true; } catch (IOException e) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/logging/PersistentLogger.kt b/app/src/main/java/org/thoughtcrime/securesms/logging/PersistentLogger.kt index d641719a96..43fb455eb3 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/logging/PersistentLogger.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/logging/PersistentLogger.kt @@ -58,8 +58,8 @@ class PersistentLogger @Inject constructor( var logWriter: LogFile.Writer? = null val entryBuilder = StringBuilder() - try { - while (true) { + while (true) { + try { channel.receiveBulkLogs(bulk) if (bulk.isNotEmpty()) { @@ -92,18 +92,18 @@ class PersistentLogger @Inject constructor( logWriter = null } } - - // Notify that the log channel is idle - logChannelIdleSignal.tryEmit(Unit) + } catch (e: Throwable) { + logWriter?.close() + + android.util.Log.e( + TAG, + "Error while processing log entries: ${e.message}", + e + ) } - } catch (e: Exception) { - logWriter?.close() - - android.util.Log.e( - TAG, - "Error while processing log entries: ${e.message}", - e - ) + + // Notify that the log channel is idle + logChannelIdleSignal.tryEmit(Unit) } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/mms/SignalGlideModule.java b/app/src/main/java/org/thoughtcrime/securesms/mms/SignalGlideModule.java index c8e350da15..366bd88c88 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mms/SignalGlideModule.java +++ b/app/src/main/java/org/thoughtcrime/securesms/mms/SignalGlideModule.java @@ -57,16 +57,15 @@ public void applyOptions(Context context, GlideBuilder builder) { @Override public void registerComponents(@NonNull Context context, @NonNull Glide glide, @NonNull Registry registry) { - AttachmentSecret attachmentSecret = AttachmentSecretProvider.getInstance(context).getOrCreateAttachmentSecret(); - byte[] secret = attachmentSecret.getModernKey(); + AttachmentSecretProvider secretProvider = AttachmentSecretProvider.getInstance(context); registry.prepend(File.class, File.class, UnitModelLoader.Factory.getInstance()); - registry.prepend(InputStream.class, new EncryptedCacheEncoder(secret, glide.getArrayPool())); - registry.prepend(File.class, Bitmap.class, new EncryptedBitmapCacheDecoder(secret, new StreamBitmapDecoder(new Downsampler(registry.getImageHeaderParsers(), context.getResources().getDisplayMetrics(), glide.getBitmapPool(), glide.getArrayPool()), glide.getArrayPool()))); - registry.prepend(File.class, GifDrawable.class, new EncryptedGifCacheDecoder(secret, new StreamGifDecoder(registry.getImageHeaderParsers(), new ByteBufferGifDecoder(context, registry.getImageHeaderParsers(), glide.getBitmapPool(), glide.getArrayPool()), glide.getArrayPool()))); + registry.prepend(InputStream.class, new EncryptedCacheEncoder(secretProvider, glide.getArrayPool())); + registry.prepend(File.class, Bitmap.class, new EncryptedBitmapCacheDecoder(secretProvider, new StreamBitmapDecoder(new Downsampler(registry.getImageHeaderParsers(), context.getResources().getDisplayMetrics(), glide.getBitmapPool(), glide.getArrayPool()), glide.getArrayPool()))); + registry.prepend(File.class, GifDrawable.class, new EncryptedGifCacheDecoder(secretProvider, new StreamGifDecoder(registry.getImageHeaderParsers(), new ByteBufferGifDecoder(context, registry.getImageHeaderParsers(), glide.getBitmapPool(), glide.getArrayPool()), glide.getArrayPool()))); - registry.prepend(Bitmap.class, new EncryptedBitmapResourceEncoder(secret)); - registry.prepend(GifDrawable.class, new EncryptedGifDrawableResourceEncoder(secret)); + registry.prepend(Bitmap.class, new EncryptedBitmapResourceEncoder(secretProvider)); + registry.prepend(GifDrawable.class, new EncryptedGifDrawableResourceEncoder(secretProvider)); registry.append(RemoteFile.class, InputStream.class, new RemoteFileLoader.Factory( ((ApplicationContext) (context.getApplicationContext())).getRemoteFileLoader() diff --git a/app/src/main/java/org/thoughtcrime/securesms/ui/ProComponents.kt b/app/src/main/java/org/thoughtcrime/securesms/ui/ProComponents.kt index 640158f89d..a202ddd64c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/ui/ProComponents.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/ui/ProComponents.kt @@ -80,6 +80,7 @@ import org.thoughtcrime.securesms.ui.theme.LocalType import org.thoughtcrime.securesms.ui.theme.PreviewTheme import org.thoughtcrime.securesms.ui.theme.SessionColorsParameterProvider import org.thoughtcrime.securesms.ui.theme.ThemeColors +import org.thoughtcrime.securesms.util.AvatarBadge import org.thoughtcrime.securesms.util.AvatarUIData @@ -750,7 +751,7 @@ fun AvatarQrWidget( label = "corner_radius" ) - // Scale animations for content + // Scale animations for content (used when going from QR back to avatar) val avatarScale by animateFloatAsState( targetValue = if (showQR) 0.8f else 1f, animationSpec = animationSpecFast, @@ -835,7 +836,6 @@ fun AvatarQrWidget( } Avatar( modifier = avatarModifier - .size(animatedSize) .graphicsLayer( alpha = avatarAlpha, scaleX = avatarScale, @@ -844,7 +844,7 @@ fun AvatarQrWidget( , size = animatedSize, maxSizeLoad = LocalDimensions.current.iconXXLargeAvatar, - data = avatarUIData + data = avatarUIData, ) // QR with scale and alpha diff --git a/app/src/main/java/org/thoughtcrime/securesms/ui/components/Avatar.kt b/app/src/main/java/org/thoughtcrime/securesms/ui/components/Avatar.kt index 38d1c4abef..f1e49a1d50 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/ui/components/Avatar.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/ui/components/Avatar.kt @@ -31,6 +31,7 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.max import androidx.compose.ui.unit.sp import coil3.compose.AsyncImagePainter import coil3.compose.SubcomposeAsyncImage @@ -55,6 +56,7 @@ import org.thoughtcrime.securesms.util.AvatarUIData import org.thoughtcrime.securesms.util.AvatarUIElement import org.thoughtcrime.securesms.util.avatarOptions +private val MIN_BADGE_SIZE = 12.dp @Composable fun BaseAvatar( @@ -105,8 +107,8 @@ fun BaseAvatar( Box( modifier = Modifier .align(Alignment.BottomEnd) - .offset(1.dp, 1.dp) // Used to make up for transparent padding in icon. - .size(size * 0.4f) + .offset(x = 1.dp, y = 1.dp) + .size(max(size * 0.4f, MIN_BADGE_SIZE)) ) { badge() } diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/AvatarUtils.kt b/app/src/main/java/org/thoughtcrime/securesms/util/AvatarUtils.kt index a978a65e39..ff7c0d78ed 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/AvatarUtils.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/util/AvatarUtils.kt @@ -231,7 +231,7 @@ data class AvatarUIElement( sealed class AvatarBadge(@DrawableRes val icon: Int){ data object None: AvatarBadge(0) - data object Admin: AvatarBadge(R.drawable.ic_crown_custom_enlarged) + data object Admin: AvatarBadge(R.drawable.ic_crown_custom_enlarged_no_padding) data class Custom(@DrawableRes val iconRes: Int): AvatarBadge(iconRes) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/FilenameUtils.kt b/app/src/main/java/org/thoughtcrime/securesms/util/FilenameUtils.kt index 9476844413..b95876bac7 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/FilenameUtils.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/util/FilenameUtils.kt @@ -92,12 +92,18 @@ object FilenameUtils { val projection = arrayOf(OpenableColumns.DISPLAY_NAME) val contentRes = context.contentResolver if (contentRes != null) { - val cursor = contentRes.query(uri, projection, null, null, null) - cursor?.use { - if (it.moveToFirst()) { - val nameIndex = it.getColumnIndexOrThrow(OpenableColumns.DISPLAY_NAME) - extractedFilename = it.getString(nameIndex) + try { + val cursor = contentRes.query(uri, projection, null, null, null) + cursor?.use { + if (it.moveToFirst()) { + val nameIndex = it.getColumnIndex(OpenableColumns.DISPLAY_NAME) + if (nameIndex != -1) { + extractedFilename = it.getString(nameIndex) + } + } } + } catch (e: Exception) { + Log.w(TAG, "Unable to query display name for uri: $uri", e) } } } diff --git a/app/src/main/res/drawable/ic_crown_custom_enlarged_no_padding.xml b/app/src/main/res/drawable/ic_crown_custom_enlarged_no_padding.xml new file mode 100644 index 0000000000..68c2a6cbd7 --- /dev/null +++ b/app/src/main/res/drawable/ic_crown_custom_enlarged_no_padding.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/layout/view_mention_candidate_v2.xml b/app/src/main/res/layout/view_mention_candidate_v2.xml index c813264b31..5c21663c97 100644 --- a/app/src/main/res/layout/view_mention_candidate_v2.xml +++ b/app/src/main/res/layout/view_mention_candidate_v2.xml @@ -25,19 +25,6 @@ app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent"/> - - - -