From 92c71b363028b2f6eced17bf013043297ce3143e Mon Sep 17 00:00:00 2001 From: Alex Hart Date: Mon, 5 Jan 2026 15:37:43 -0400 Subject: [PATCH] Fix issue where latest chat would reappear after reopening the app. --- .../thoughtcrime/securesms/MainActivity.kt | 6 ++--- .../ConversationListFragment.java | 2 +- .../securesms/main/MainNavigationViewModel.kt | 23 ++++++++++++++++++- .../ui/countrycode/CountryCodeSelectScreen.kt | 2 +- 4 files changed, 26 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/MainActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/MainActivity.kt index 50faed6265..ca67edf322 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/MainActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/MainActivity.kt @@ -69,6 +69,7 @@ import androidx.fragment.compose.rememberFragmentState import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.lifecycle.createSavedStateHandle import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle import androidx.recyclerview.widget.RecyclerView @@ -108,7 +109,6 @@ import org.thoughtcrime.securesms.components.settings.app.subscription.GooglePay import org.thoughtcrime.securesms.components.snackbars.LocalSnackbarStateConsumerRegistry import org.thoughtcrime.securesms.components.snackbars.SnackbarHostKey import org.thoughtcrime.securesms.components.snackbars.SnackbarState -import org.thoughtcrime.securesms.components.snackbars.SnackbarStateConsumerRegistry import org.thoughtcrime.securesms.components.voice.VoiceNoteMediaController import org.thoughtcrime.securesms.components.voice.VoiceNoteMediaControllerOwner import org.thoughtcrime.securesms.compose.SignalTheme @@ -221,7 +221,7 @@ class MainActivity : PassphraseRequiredActivity(), VoiceNoteMediaControllerOwner private val mainNavigationViewModel: MainNavigationViewModel by viewModel { val startingTab = intent.extras?.getSerializableCompat(KEY_STARTING_TAB, MainNavigationListLocation::class.java) - MainNavigationViewModel(startingTab ?: MainNavigationListLocation.CHATS) + MainNavigationViewModel(it.createSavedStateHandle(), startingTab ?: MainNavigationListLocation.CHATS) } private val vitalsViewModel: VitalsViewModel by viewModel { @@ -247,8 +247,6 @@ class MainActivity : PassphraseRequiredActivity(), VoiceNoteMediaControllerOwner private val megaphoneActionController = MainMegaphoneActionController() private val mainNavigationCallback = MainNavigationCallback() - private val snackbarRegistry = SnackbarStateConsumerRegistry() - override val googlePayRepository: GooglePayRepository by lazy { GooglePayRepository(this) } override val googlePayResultPublisher: Subject = PublishSubject.create() diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListFragment.java b/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListFragment.java index 4b5024ca10..7104c9fb88 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListFragment.java @@ -253,7 +253,7 @@ public class ConversationListFragment extends MainFragment implements Conversati super.onCreate(icicle); startupStopwatch = new Stopwatch("startup"); mainToolbarViewModel = new ViewModelProvider(requireActivity()).get(MainToolbarViewModel.class); - mainNavigationViewModel = new ViewModelProvider(requireActivity()).get(MainNavigationViewModel.class); + mainNavigationViewModel = new ViewModelProvider(requireActivity(), new MainNavigationViewModel.Factory()).get(MainNavigationViewModel.class); } @Override diff --git a/app/src/main/java/org/thoughtcrime/securesms/main/MainNavigationViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/main/MainNavigationViewModel.kt index 77c09acb08..ea3e54e5ac 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/main/MainNavigationViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/main/MainNavigationViewModel.kt @@ -9,8 +9,12 @@ import androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi import androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole import androidx.compose.material3.adaptive.navigation.BackNavigationBehavior import androidx.compose.material3.adaptive.navigation.ThreePaneScaffoldNavigator +import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.createSavedStateHandle import androidx.lifecycle.viewModelScope +import androidx.lifecycle.viewmodel.CreationExtras import io.reactivex.rxjava3.core.Observable import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow @@ -34,13 +38,30 @@ import org.thoughtcrime.securesms.megaphone.Megaphone import org.thoughtcrime.securesms.megaphone.Megaphones import org.thoughtcrime.securesms.notifications.profiles.NotificationProfile import org.thoughtcrime.securesms.stories.Stories +import org.thoughtcrime.securesms.util.delegate import org.thoughtcrime.securesms.window.AppScaffoldNavigator import java.util.Optional @OptIn(ExperimentalMaterial3AdaptiveApi::class) class MainNavigationViewModel( + private val savedStateHandle: SavedStateHandle, initialListLocation: MainNavigationListLocation = MainNavigationListLocation.CHATS ) : ViewModel(), MainNavigationRouter { + + companion object { + private const val LOCK_PANE_TO_SECONDARY = "lock_pane_to_secondary" + } + + class Factory( + private val initialListLocation: MainNavigationListLocation = MainNavigationListLocation.CHATS + ) : ViewModelProvider.Factory { + override fun create(modelClass: Class, extras: CreationExtras): T { + val savedStateHandle = extras.createSavedStateHandle() + @Suppress("UNCHECKED_CAST") + return MainNavigationViewModel(savedStateHandle, initialListLocation) as T + } + } + private val megaphoneRepository = AppDependencies.megaphoneRepository private var navigator: AppScaffoldNavigator? = null @@ -94,7 +115,7 @@ class MainNavigationViewModel( * where the user can change configurations (such as opening a foldable) and we will restore state and errantly * take them back into a PRIMARY pane. This boolean helps avoid these cases. */ - private var lockPaneToSecondary = false + private var lockPaneToSecondary: Boolean by savedStateHandle.delegate(LOCK_PANE_TO_SECONDARY, false) val snackbarRegistry = SnackbarStateConsumerRegistry() diff --git a/app/src/main/java/org/thoughtcrime/securesms/registration/ui/countrycode/CountryCodeSelectScreen.kt b/app/src/main/java/org/thoughtcrime/securesms/registration/ui/countrycode/CountryCodeSelectScreen.kt index 6cbcb1a93e..052d4a887f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/registration/ui/countrycode/CountryCodeSelectScreen.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/registration/ui/countrycode/CountryCodeSelectScreen.kt @@ -339,4 +339,4 @@ private fun LargeFontScreenPreview() { title = "Your country" ) } -} \ No newline at end of file +}