diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/ConversationSettingsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/ConversationSettingsFragment.kt index b6c0b0395b..dfdb6108f8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/ConversationSettingsFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/ConversationSettingsFragment.kt @@ -30,6 +30,8 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.snackbar.Snackbar import io.reactivex.rxjava3.kotlin.subscribeBy import kotlinx.coroutines.launch +import org.signal.core.ui.getWindowSizeClass +import org.signal.core.ui.isSplitPane import org.signal.core.ui.permissions.Permissions import org.signal.core.util.DimensionUnit import org.signal.core.util.Result @@ -117,6 +119,7 @@ import org.thoughtcrime.securesms.util.ExpirationUtil import org.thoughtcrime.securesms.util.Material3OnScrollHelper import org.thoughtcrime.securesms.util.RemoteConfig import org.thoughtcrime.securesms.util.ViewUtil +import org.thoughtcrime.securesms.util.WindowUtil import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter import org.thoughtcrime.securesms.util.navigation.safeNavigate import org.thoughtcrime.securesms.util.views.SimpleProgressDialog @@ -261,8 +264,25 @@ class ConversationSettingsFragment : } } + private fun goToConversationList() { + if (mainNavRouter != null) { + mainNavRouter?.goTo(MainNavigationDetailLocation.Empty) + } else { + startActivity(MainActivity.clearTopAndOpenDetail(requireContext(), MainNavigationDetailLocation.Empty)) + } + } + override fun getMaterial3OnScrollHelper(toolbar: Toolbar?): Material3OnScrollHelper { - return object : Material3OnScrollHelper(activity = requireActivity(), views = listOf(toolbar!!), lifecycleOwner = viewLifecycleOwner) { + return object : Material3OnScrollHelper( + activity = requireActivity(), + views = listOf(toolbar!!), + lifecycleOwner = viewLifecycleOwner, + setStatusBarColor = { color -> + if (!resources.getWindowSizeClass().isSplitPane() || activity is ConversationSettingsActivity) { + WindowUtil.setStatusBarColor(requireActivity().window, color) + } + } + ) { override val inactiveColorSet = ColorSet( toolbarColorRes = CoreUiR.color.signal_colorBackground_0, statusBarColorRes = CoreUiR.color.signal_colorBackground @@ -972,7 +992,7 @@ class ConversationSettingsFragment : icon = DSLSettingsIcon.from(R.drawable.symbol_archive_24), onClick = { viewModel.toggleArchive() - onToolbarNavigationClicked() + goToConversationList() } ) } @@ -986,11 +1006,7 @@ class ConversationSettingsFragment : lifecycleScope.launch { viewModel.deleteChat() progressDialog.dismissAllowingStateLoss() - if (mainNavRouter != null) { - mainNavRouter?.goTo(MainNavigationDetailLocation.Empty) - } else { - startActivity(MainActivity.clearTopAndOpenDetail(requireContext(), MainNavigationDetailLocation.Empty)) - } + goToConversationList() } } ) @@ -1059,7 +1075,7 @@ class ConversationSettingsFragment : .onReportSpam() .subscribeBy { Toast.makeText(requireContext(), R.string.ConversationFragment_reported_as_spam, Toast.LENGTH_SHORT).show() - onToolbarNavigationClicked() + goToConversationList() } .addTo(lifecycleDisposable) }, @@ -1073,7 +1089,7 @@ class ConversationSettingsFragment : when (result) { is Result.Success -> { Toast.makeText(requireContext(), R.string.ConversationFragment_reported_as_spam_and_blocked, Toast.LENGTH_SHORT).show() - onToolbarNavigationClicked() + goToConversationList() } is Result.Failure -> { @@ -1108,7 +1124,7 @@ class ConversationSettingsFragment : .onReportSpam() .subscribeBy { Toast.makeText(requireContext(), R.string.ConversationFragment_reported_as_spam, Toast.LENGTH_SHORT).show() - onToolbarNavigationClicked() + goToConversationList() } .addTo(lifecycleDisposable) }, diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/ConversationSettingsNavHostFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/ConversationSettingsNavHostFragment.kt new file mode 100644 index 0000000000..0dead83c2d --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/ConversationSettingsNavHostFragment.kt @@ -0,0 +1,39 @@ +/* + * Copyright 2026 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.thoughtcrime.securesms.components.settings.conversation + +import android.os.Bundle +import androidx.core.os.bundleOf +import androidx.navigation.fragment.NavHostFragment +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import org.thoughtcrime.securesms.R +import org.thoughtcrime.securesms.components.settings.DSLSettingsActivity +import org.thoughtcrime.securesms.recipients.Recipient +import org.thoughtcrime.securesms.recipients.RecipientId + +class ConversationSettingsNavHostFragment : NavHostFragment() { + + companion object { + suspend fun createArgs(recipientId: RecipientId): Bundle { + val recipient = withContext(Dispatchers.IO) { Recipient.resolved(recipientId) } + + val args = if (recipient.isGroup) { + ConversationSettingsFragmentArgs.Builder(null, recipient.requireGroupId(), null) + } else { + ConversationSettingsFragmentArgs.Builder(recipientId, null, null) + }.build() + + return bundleOf(DSLSettingsActivity.ARG_START_BUNDLE to args.toBundle()) + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + val args = requireArguments().getBundle(DSLSettingsActivity.ARG_START_BUNDLE) + navController.setGraph(R.navigation.conversation_settings, args) + super.onCreate(savedInstanceState) + } +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationFragment.kt index 1ec64a49fe..b090aacf0b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationFragment.kt @@ -4129,7 +4129,7 @@ class ConversationFragment : override fun handleManageGroup() { viewModel.recipientSnapshot?.let { recipient -> - navigateToConversationSettingsStandalone(recipient) + navigateTo(MainNavigationDetailLocation.Chats.ConversationSettings(recipient.id)) } } @@ -4166,7 +4166,7 @@ class ConversationFragment : override fun handleConversationSettings() { viewModel.recipientSnapshot?.let { recipient -> if (!viewModel.hasMessageRequestState || recipient.isBlocked) { - navigateToConversationSettingsStandalone(recipient) + navigateTo(MainNavigationDetailLocation.Chats.ConversationSettings(recipient.id)) } } } @@ -4235,6 +4235,7 @@ class ConversationFragment : } else { when (location) { is MainNavigationDetailLocation.Chats.MessageDetails -> navigateToMessageDetailsStandalone(location) + is MainNavigationDetailLocation.Chats.ConversationSettings -> navigateToConversationSettingsStandalone(viewModel.recipientSnapshot!!) is MainNavigationDetailLocation.Chats.Conversation -> error("ConversationFragment shouldn't navigate to another conversation - use the main navigation infrastructure instead.") } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/main/ChatsNavHost.kt b/app/src/main/java/org/thoughtcrime/securesms/main/ChatsNavHost.kt index c70dca92b7..447931ff90 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/main/ChatsNavHost.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/main/ChatsNavHost.kt @@ -6,6 +6,7 @@ package org.thoughtcrime.securesms.main import android.os.Build +import android.os.Bundle import androidx.compose.animation.core.Transition import androidx.compose.animation.core.animateDp import androidx.compose.animation.core.animateFloat @@ -22,6 +23,7 @@ import androidx.compose.runtime.Stable import androidx.compose.runtime.getValue import androidx.compose.runtime.key import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.produceState import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier @@ -47,6 +49,7 @@ import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch import org.signal.core.ui.isSplitPane import org.thoughtcrime.securesms.MainNavigator +import org.thoughtcrime.securesms.components.settings.conversation.ConversationSettingsNavHostFragment import org.thoughtcrime.securesms.compose.FragmentBackHandler import org.thoughtcrime.securesms.compose.FragmentBackPressedState import org.thoughtcrime.securesms.conversation.ConversationArgs @@ -162,12 +165,44 @@ fun NavGraphBuilder.chatNavGraphBuilder( clazz = MessageDetailsFragment::class.java, fragmentState = fragmentState, arguments = MessageDetailsFragment.args(route.recipientId, route.messageId), - modifier = Modifier.fillMaxSize() + modifier = Modifier + .fillMaxSize() .background(MaterialTheme.colorScheme.background) .statusBarsPadding() .navigationBarsPadding() ) } + + composable( + typeMap = mapOf( + typeOf() to JsonSerializableNavType(RecipientId.serializer()) + ) + ) { navBackStackEntry -> + + val navigatorProvider = LocalContext.current as? MainNavigator.NavigatorProvider + val fragmentState = key(route) { rememberFragmentState() } + val route = navBackStackEntry.toRoute() + val arguments: Bundle? by produceState(null, route.recipientId) { + value = ConversationSettingsNavHostFragment.createArgs(route.recipientId) + } + + LaunchedEffect(Unit) { + navigatorProvider?.onFirstRender() + } + + arguments?.let { args -> + AndroidFragment( + clazz = ConversationSettingsNavHostFragment::class.java, + fragmentState = fragmentState, + arguments = args, + modifier = Modifier + .fillMaxSize() + .background(MaterialTheme.colorScheme.background) + .statusBarsPadding() + .navigationBarsPadding() + ) + } + } } @Composable diff --git a/app/src/main/java/org/thoughtcrime/securesms/main/MainNavigationDetailLocation.kt b/app/src/main/java/org/thoughtcrime/securesms/main/MainNavigationDetailLocation.kt index d9a51ce9f1..cd57987ad9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/main/MainNavigationDetailLocation.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/main/MainNavigationDetailLocation.kt @@ -73,6 +73,13 @@ sealed class MainNavigationDetailLocation : Parcelable { @IgnoredOnParcel override val controllerKey: RecipientId = recipientId } + + @Serializable + data class ConversationSettings(val recipientId: RecipientId) : Chats() { + @Transient + @IgnoredOnParcel + override val controllerKey: RecipientId = recipientId + } } /**