mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-23 02:10:44 +01:00
Add new navigation and pane support.
This commit is contained in:
committed by
Jeffrey Starke
parent
146a5f5701
commit
fd999be41a
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2025 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
package org.thoughtcrime.securesms.conversation
|
||||
|
||||
import android.net.Uri
|
||||
import android.os.Parcelable
|
||||
import kotlinx.parcelize.IgnoredOnParcel
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import kotlinx.serialization.Serializable
|
||||
import org.thoughtcrime.securesms.badges.models.Badge
|
||||
import org.thoughtcrime.securesms.conversation.ConversationIntents.ConversationScreenType
|
||||
import org.thoughtcrime.securesms.conversation.colors.ChatColors
|
||||
import org.thoughtcrime.securesms.mediasend.Media
|
||||
import org.thoughtcrime.securesms.mms.SlideFactory
|
||||
import org.thoughtcrime.securesms.recipients.Recipient.Companion.resolved
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
import org.thoughtcrime.securesms.serialization.UriSerializer
|
||||
import org.thoughtcrime.securesms.stickers.StickerLocator
|
||||
import org.thoughtcrime.securesms.wallpaper.ChatWallpaper
|
||||
|
||||
@Serializable
|
||||
@Parcelize
|
||||
data class ConversationArgs(
|
||||
val recipientId: RecipientId,
|
||||
@JvmField val threadId: Long,
|
||||
val draftText: String?,
|
||||
@Serializable(with = UriSerializer::class) val draftMedia: Uri?,
|
||||
val draftContentType: String?,
|
||||
val media: List<Media?>?,
|
||||
val stickerLocator: StickerLocator?,
|
||||
val isBorderless: Boolean,
|
||||
val distributionType: Int,
|
||||
val startingPosition: Int,
|
||||
val isFirstTimeInSelfCreatedGroup: Boolean,
|
||||
val isWithSearchOpen: Boolean,
|
||||
val giftBadge: Badge?,
|
||||
val shareDataTimestamp: Long,
|
||||
val conversationScreenType: ConversationScreenType
|
||||
) : Parcelable {
|
||||
@IgnoredOnParcel
|
||||
val draftMediaType: SlideFactory.MediaType? = SlideFactory.MediaType.from(draftContentType)
|
||||
|
||||
@IgnoredOnParcel
|
||||
val wallpaper: ChatWallpaper?
|
||||
get() = resolved(recipientId).wallpaper
|
||||
|
||||
@IgnoredOnParcel
|
||||
val chatColors: ChatColors
|
||||
get() = resolved(recipientId).chatColors
|
||||
|
||||
fun canInitializeFromDatabase(): Boolean {
|
||||
return draftText == null && (draftMedia == null || ConversationIntents.isBubbleIntentUri(draftMedia) || ConversationIntents.isNotificationIntentUri(draftMedia)) && draftMediaType == null
|
||||
}
|
||||
}
|
||||
@@ -11,16 +11,13 @@ import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.thoughtcrime.securesms.badges.models.Badge;
|
||||
import org.thoughtcrime.securesms.conversation.colors.ChatColors;
|
||||
import org.thoughtcrime.securesms.conversation.v2.ConversationActivity;
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||
import org.thoughtcrime.securesms.database.ThreadTable;
|
||||
import org.thoughtcrime.securesms.mediasend.Media;
|
||||
import org.thoughtcrime.securesms.mms.SlideFactory;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.stickers.StickerLocator;
|
||||
import org.thoughtcrime.securesms.wallpaper.ChatWallpaper;
|
||||
import org.whispersystems.signalservice.api.util.Preconditions;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -99,6 +96,12 @@ public class ConversationIntents {
|
||||
return new Builder(context, ConversationActivity.class, recipientId, threadId, ConversationScreenType.NORMAL);
|
||||
}
|
||||
|
||||
public static @NonNull Builder createBuilderSync(@NonNull Context context, @NonNull ConversationArgs conversationArgs) {
|
||||
Preconditions.checkArgument(conversationArgs.threadId > 0, "threadId is invalid");
|
||||
return new Builder(context, ConversationActivity.class, conversationArgs.getRecipientId(), conversationArgs.threadId, ConversationScreenType.NORMAL)
|
||||
.withArgs(conversationArgs);
|
||||
}
|
||||
|
||||
static @Nullable Uri getIntentData(@NonNull Bundle bundle) {
|
||||
return bundle.getParcelable(INTENT_DATA);
|
||||
}
|
||||
@@ -132,170 +135,41 @@ public class ConversationIntents {
|
||||
return ACTION.equals(intent.getAction());
|
||||
}
|
||||
|
||||
public final static class Args {
|
||||
private final RecipientId recipientId;
|
||||
private final long threadId;
|
||||
private final String draftText;
|
||||
private final Uri draftMedia;
|
||||
private final String draftContentType;
|
||||
private final SlideFactory.MediaType draftMediaType;
|
||||
private final ArrayList<Media> media;
|
||||
private final StickerLocator stickerLocator;
|
||||
private final boolean isBorderless;
|
||||
private final int distributionType;
|
||||
private final int startingPosition;
|
||||
private final boolean firstTimeInSelfCreatedGroup;
|
||||
private final boolean withSearchOpen;
|
||||
private final Badge giftBadge;
|
||||
private final long shareDataTimestamp;
|
||||
private final ConversationScreenType conversationScreenType;
|
||||
|
||||
public static Args from(@NonNull Bundle arguments) {
|
||||
Uri intentDataUri = getIntentData(arguments);
|
||||
if (isBubbleIntentUri(intentDataUri)) {
|
||||
return new Args(RecipientId.from(intentDataUri.getQueryParameter(EXTRA_RECIPIENT)),
|
||||
Long.parseLong(intentDataUri.getQueryParameter(EXTRA_THREAD_ID)),
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
false,
|
||||
ThreadTable.DistributionTypes.DEFAULT,
|
||||
-1,
|
||||
false,
|
||||
false,
|
||||
null,
|
||||
-1L,
|
||||
ConversationScreenType.BUBBLE);
|
||||
}
|
||||
|
||||
return new Args(RecipientId.from(Objects.requireNonNull(arguments.getString(EXTRA_RECIPIENT))),
|
||||
arguments.getLong(EXTRA_THREAD_ID, -1),
|
||||
arguments.getString(EXTRA_TEXT),
|
||||
ConversationIntents.getIntentData(arguments),
|
||||
ConversationIntents.getIntentType(arguments),
|
||||
arguments.getParcelableArrayList(EXTRA_MEDIA),
|
||||
arguments.getParcelable(EXTRA_STICKER),
|
||||
arguments.getBoolean(EXTRA_BORDERLESS, false),
|
||||
arguments.getInt(EXTRA_DISTRIBUTION_TYPE, ThreadTable.DistributionTypes.DEFAULT),
|
||||
arguments.getInt(EXTRA_STARTING_POSITION, -1),
|
||||
arguments.getBoolean(EXTRA_FIRST_TIME_IN_SELF_CREATED_GROUP, false),
|
||||
arguments.getBoolean(EXTRA_WITH_SEARCH_OPEN, false),
|
||||
arguments.getParcelable(EXTRA_GIFT_BADGE),
|
||||
arguments.getLong(EXTRA_SHARE_DATA_TIMESTAMP, -1L),
|
||||
ConversationScreenType.from(arguments.getInt(EXTRA_CONVERSATION_TYPE, 0)));
|
||||
public static ConversationArgs readArgsFromBundle(@NonNull Bundle arguments) {
|
||||
Uri intentDataUri = getIntentData(arguments);
|
||||
if (isBubbleIntentUri(intentDataUri)) {
|
||||
return new ConversationArgs(RecipientId.from(intentDataUri.getQueryParameter(EXTRA_RECIPIENT)),
|
||||
Long.parseLong(intentDataUri.getQueryParameter(EXTRA_THREAD_ID)),
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
false,
|
||||
ThreadTable.DistributionTypes.DEFAULT,
|
||||
-1,
|
||||
false,
|
||||
false,
|
||||
null,
|
||||
-1L,
|
||||
ConversationScreenType.BUBBLE);
|
||||
}
|
||||
|
||||
private Args(@NonNull RecipientId recipientId,
|
||||
long threadId,
|
||||
@Nullable String draftText,
|
||||
@Nullable Uri draftMedia,
|
||||
@Nullable String draftContentType,
|
||||
@Nullable ArrayList<Media> media,
|
||||
@Nullable StickerLocator stickerLocator,
|
||||
boolean isBorderless,
|
||||
int distributionType,
|
||||
int startingPosition,
|
||||
boolean firstTimeInSelfCreatedGroup,
|
||||
boolean withSearchOpen,
|
||||
@Nullable Badge giftBadge,
|
||||
long shareDataTimestamp,
|
||||
@NonNull ConversationScreenType conversationScreenType)
|
||||
{
|
||||
this.recipientId = recipientId;
|
||||
this.threadId = threadId;
|
||||
this.draftText = draftText;
|
||||
this.draftMedia = draftMedia;
|
||||
this.draftContentType = draftContentType;
|
||||
this.media = media;
|
||||
this.stickerLocator = stickerLocator;
|
||||
this.isBorderless = isBorderless;
|
||||
this.distributionType = distributionType;
|
||||
this.startingPosition = startingPosition;
|
||||
this.firstTimeInSelfCreatedGroup = firstTimeInSelfCreatedGroup;
|
||||
this.withSearchOpen = withSearchOpen;
|
||||
this.giftBadge = giftBadge;
|
||||
this.shareDataTimestamp = shareDataTimestamp;
|
||||
this.conversationScreenType = conversationScreenType;
|
||||
this.draftMediaType = SlideFactory.MediaType.from(draftContentType);
|
||||
}
|
||||
|
||||
public @NonNull RecipientId getRecipientId() {
|
||||
return recipientId;
|
||||
}
|
||||
|
||||
public long getThreadId() {
|
||||
return threadId;
|
||||
}
|
||||
|
||||
public @Nullable String getDraftText() {
|
||||
return draftText;
|
||||
}
|
||||
|
||||
public @Nullable Uri getDraftMedia() {
|
||||
return draftMedia;
|
||||
}
|
||||
|
||||
public @Nullable String getDraftContentType() {
|
||||
return draftContentType;
|
||||
}
|
||||
|
||||
public @Nullable SlideFactory.MediaType getDraftMediaType() {
|
||||
return draftMediaType;
|
||||
}
|
||||
|
||||
public @Nullable ArrayList<Media> getMedia() {
|
||||
return media;
|
||||
}
|
||||
|
||||
public @Nullable StickerLocator getStickerLocator() {
|
||||
return stickerLocator;
|
||||
}
|
||||
|
||||
public int getDistributionType() {
|
||||
return distributionType;
|
||||
}
|
||||
|
||||
public int getStartingPosition() {
|
||||
return startingPosition;
|
||||
}
|
||||
|
||||
public boolean isBorderless() {
|
||||
return isBorderless;
|
||||
}
|
||||
|
||||
public boolean isFirstTimeInSelfCreatedGroup() {
|
||||
return firstTimeInSelfCreatedGroup;
|
||||
}
|
||||
|
||||
public @Nullable ChatWallpaper getWallpaper() {
|
||||
return Recipient.resolved(recipientId).getWallpaper();
|
||||
}
|
||||
|
||||
public @NonNull ChatColors getChatColors() {
|
||||
return Recipient.resolved(recipientId).getChatColors();
|
||||
}
|
||||
|
||||
public boolean isWithSearchOpen() {
|
||||
return withSearchOpen;
|
||||
}
|
||||
|
||||
public @Nullable Badge getGiftBadge() {
|
||||
return giftBadge;
|
||||
}
|
||||
|
||||
public long getShareDataTimestamp() {
|
||||
return shareDataTimestamp;
|
||||
}
|
||||
|
||||
public @NonNull ConversationScreenType getConversationScreenType() {
|
||||
return conversationScreenType;
|
||||
}
|
||||
|
||||
public boolean canInitializeFromDatabase() {
|
||||
return draftText == null && (draftMedia == null || ConversationIntents.isBubbleIntentUri(draftMedia) || ConversationIntents.isNotificationIntentUri(draftMedia)) && draftMediaType == null;
|
||||
}
|
||||
return new ConversationArgs(RecipientId.from(Objects.requireNonNull(arguments.getString(EXTRA_RECIPIENT))),
|
||||
arguments.getLong(EXTRA_THREAD_ID, -1),
|
||||
arguments.getString(EXTRA_TEXT),
|
||||
ConversationIntents.getIntentData(arguments),
|
||||
ConversationIntents.getIntentType(arguments),
|
||||
arguments.getParcelableArrayList(EXTRA_MEDIA),
|
||||
arguments.getParcelable(EXTRA_STICKER),
|
||||
arguments.getBoolean(EXTRA_BORDERLESS, false),
|
||||
arguments.getInt(EXTRA_DISTRIBUTION_TYPE, ThreadTable.DistributionTypes.DEFAULT),
|
||||
arguments.getInt(EXTRA_STARTING_POSITION, -1),
|
||||
arguments.getBoolean(EXTRA_FIRST_TIME_IN_SELF_CREATED_GROUP, false),
|
||||
arguments.getBoolean(EXTRA_WITH_SEARCH_OPEN, false),
|
||||
arguments.getParcelable(EXTRA_GIFT_BADGE),
|
||||
arguments.getLong(EXTRA_SHARE_DATA_TIMESTAMP, -1L),
|
||||
ConversationScreenType.from(arguments.getInt(EXTRA_CONVERSATION_TYPE, 0)));
|
||||
}
|
||||
|
||||
public final static class Builder {
|
||||
@@ -331,6 +205,23 @@ public class ConversationIntents {
|
||||
this.conversationScreenType = conversationScreenType;
|
||||
}
|
||||
|
||||
public @NonNull Builder withArgs(@NonNull ConversationArgs args) {
|
||||
draftText = args.getDraftText();
|
||||
media = args.getMedia();
|
||||
stickerLocator = args.getStickerLocator();
|
||||
isBorderless = args.isBorderless();
|
||||
distributionType = args.getDistributionType();
|
||||
startingPosition = args.getStartingPosition();
|
||||
dataType = args.getDraftContentType();
|
||||
dataUri = args.getDraftMedia();
|
||||
firstTimeInSelfCreatedGroup = args.isFirstTimeInSelfCreatedGroup();
|
||||
withSearchOpen = args.isWithSearchOpen();
|
||||
giftBadge = args.getGiftBadge();
|
||||
shareDataTimestamp = args.getShareDataTimestamp();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public @NonNull Builder withDraftText(@Nullable String draftText) {
|
||||
this.draftText = draftText;
|
||||
return this;
|
||||
@@ -391,6 +282,26 @@ public class ConversationIntents {
|
||||
return this;
|
||||
}
|
||||
|
||||
public @NonNull ConversationArgs toConversationArgs() {
|
||||
return new ConversationArgs(
|
||||
recipientId,
|
||||
threadId,
|
||||
draftText,
|
||||
dataUri,
|
||||
dataType,
|
||||
media,
|
||||
stickerLocator,
|
||||
isBorderless,
|
||||
distributionType,
|
||||
startingPosition,
|
||||
firstTimeInSelfCreatedGroup,
|
||||
withSearchOpen,
|
||||
giftBadge,
|
||||
shareDataTimestamp,
|
||||
conversationScreenType
|
||||
);
|
||||
}
|
||||
|
||||
public @NonNull Intent build() {
|
||||
if (stickerLocator != null && media != null) {
|
||||
throw new IllegalStateException("Cannot have both sticker and media array");
|
||||
|
||||
@@ -13,7 +13,7 @@ import org.signal.core.util.concurrent.SignalExecutors
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.thoughtcrime.securesms.components.location.SignalPlace
|
||||
import org.thoughtcrime.securesms.components.mention.MentionAnnotation
|
||||
import org.thoughtcrime.securesms.conversation.ConversationIntents
|
||||
import org.thoughtcrime.securesms.conversation.ConversationArgs
|
||||
import org.thoughtcrime.securesms.conversation.ConversationMessage
|
||||
import org.thoughtcrime.securesms.conversation.ConversationMessage.ConversationMessageFactory
|
||||
import org.thoughtcrime.securesms.conversation.MessageStyler
|
||||
@@ -53,7 +53,7 @@ class DraftRepository(
|
||||
private val threadTable: ThreadTable = SignalDatabase.threads,
|
||||
private val draftTable: DraftTable = SignalDatabase.drafts,
|
||||
private val saveDraftsExecutor: Executor = SerialMonoLifoExecutor(SignalExecutors.BOUNDED),
|
||||
private val conversationArguments: ConversationIntents.Args? = null
|
||||
private val conversationArguments: ConversationArgs? = null
|
||||
) {
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -154,6 +154,7 @@ import org.thoughtcrime.securesms.contactshare.SharedContactDetailsActivity
|
||||
import org.thoughtcrime.securesms.conversation.AttachmentKeyboardButton
|
||||
import org.thoughtcrime.securesms.conversation.BadDecryptLearnMoreDialog
|
||||
import org.thoughtcrime.securesms.conversation.ConversationAdapter
|
||||
import org.thoughtcrime.securesms.conversation.ConversationArgs
|
||||
import org.thoughtcrime.securesms.conversation.ConversationBottomSheetCallback
|
||||
import org.thoughtcrime.securesms.conversation.ConversationData
|
||||
import org.thoughtcrime.securesms.conversation.ConversationHeaderView
|
||||
@@ -390,8 +391,8 @@ class ConversationFragment :
|
||||
private const val IS_SCROLLED_TO_BOTTOM_THRESHOLD: Int = 2
|
||||
}
|
||||
|
||||
private val args: ConversationIntents.Args by lazy {
|
||||
ConversationIntents.Args.from(requireArguments())
|
||||
private val args: ConversationArgs by lazy {
|
||||
ConversationIntents.readArgsFromBundle(requireArguments())
|
||||
}
|
||||
|
||||
private val conversationRecipientRepository: ConversationRecipientRepository by lazy {
|
||||
|
||||
@@ -9,7 +9,7 @@ import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.ViewModel
|
||||
import org.thoughtcrime.securesms.conversation.ConversationIntents
|
||||
import org.thoughtcrime.securesms.conversation.ConversationArgs
|
||||
import org.thoughtcrime.securesms.util.delegate
|
||||
|
||||
/**
|
||||
@@ -33,7 +33,7 @@ class ShareDataTimestampViewModel(
|
||||
}
|
||||
}
|
||||
|
||||
fun setTimestampFromConversationArgs(args: ConversationIntents.Args) {
|
||||
fun setTimestampFromConversationArgs(args: ConversationArgs) {
|
||||
timestamp = args.shareDataTimestamp
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user