diff --git a/app/src/main/java/org/thoughtcrime/securesms/MainActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/MainActivity.kt index 5cc778f488..e2eb054880 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/MainActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/MainActivity.kt @@ -13,6 +13,7 @@ import android.content.Intent import android.os.Bundle import android.view.MotionEvent import android.view.View +import android.view.ViewGroup import android.view.ViewTreeObserver import android.widget.Toast import androidx.activity.SystemBarStyle @@ -37,11 +38,11 @@ import androidx.compose.material3.adaptive.layout.calculatePaneScaffoldDirective import androidx.compose.material3.adaptive.navigation.ThreePaneScaffoldNavigator import androidx.compose.material3.adaptive.navigation.rememberListDetailPaneScaffoldNavigator import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.key import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip @@ -50,18 +51,24 @@ import androidx.fragment.app.DialogFragment import androidx.fragment.compose.AndroidFragment import androidx.fragment.compose.rememberFragmentState import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle +import androidx.recyclerview.widget.RecyclerView import com.google.android.material.dialog.MaterialAlertDialogBuilder +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import org.signal.core.ui.compose.theme.SignalTheme import org.signal.core.util.concurrent.LifecycleDisposable import org.signal.core.util.getSerializableCompat +import org.signal.core.util.logging.Log import org.signal.donations.StripeApi import org.thoughtcrime.securesms.calls.YouAreAlreadyInACallSnackbar.show import org.thoughtcrime.securesms.calls.log.CallLogFilter +import org.thoughtcrime.securesms.calls.log.CallLogFragment import org.thoughtcrime.securesms.calls.new.NewCallActivity import org.thoughtcrime.securesms.components.ConnectivityWarningBottomSheet import org.thoughtcrime.securesms.components.DebugLogsPromptDialogFragment @@ -76,14 +83,16 @@ import org.thoughtcrime.securesms.conversation.ConversationIntents import org.thoughtcrime.securesms.conversation.v2.ConversationFragment import org.thoughtcrime.securesms.conversation.v2.MotionEventRelay import org.thoughtcrime.securesms.conversation.v2.ShareDataTimestampViewModel +import org.thoughtcrime.securesms.conversationlist.ConversationListArchiveFragment +import org.thoughtcrime.securesms.conversationlist.ConversationListFragment import org.thoughtcrime.securesms.conversationlist.RelinkDevicesReminderBottomSheetFragment import org.thoughtcrime.securesms.conversationlist.RestoreCompleteBottomSheetDialog import org.thoughtcrime.securesms.conversationlist.model.ConversationFilter +import org.thoughtcrime.securesms.conversationlist.model.UnreadPaymentsLiveData import org.thoughtcrime.securesms.devicetransfer.olddevice.OldDeviceExitActivity import org.thoughtcrime.securesms.groups.ui.creategroup.CreateGroupActivity import org.thoughtcrime.securesms.keyvalue.SignalStore import org.thoughtcrime.securesms.lock.v2.CreateSvrPinActivity -import org.thoughtcrime.securesms.main.MainActivityListHostFragment import org.thoughtcrime.securesms.main.MainBottomChrome import org.thoughtcrime.securesms.main.MainBottomChromeCallback import org.thoughtcrime.securesms.main.MainBottomChromeState @@ -97,7 +106,9 @@ import org.thoughtcrime.securesms.main.MainNavigationViewModel import org.thoughtcrime.securesms.main.MainToolbar import org.thoughtcrime.securesms.main.MainToolbarCallback import org.thoughtcrime.securesms.main.MainToolbarMode +import org.thoughtcrime.securesms.main.MainToolbarState import org.thoughtcrime.securesms.main.MainToolbarViewModel +import org.thoughtcrime.securesms.main.Material3OnScrollHelperBinder import org.thoughtcrime.securesms.main.NavigationBarSpacerCompat import org.thoughtcrime.securesms.main.SnackbarState import org.thoughtcrime.securesms.mediasend.camerax.CameraXUtil @@ -107,25 +118,35 @@ import org.thoughtcrime.securesms.megaphone.MegaphoneActionController import org.thoughtcrime.securesms.megaphone.Megaphones import org.thoughtcrime.securesms.net.DeviceTransferBlockingInterceptor import org.thoughtcrime.securesms.notifications.VitalsViewModel +import org.thoughtcrime.securesms.notifications.profiles.NotificationProfile +import org.thoughtcrime.securesms.notifications.profiles.NotificationProfiles import org.thoughtcrime.securesms.permissions.Permissions import org.thoughtcrime.securesms.profiles.manage.UsernameEditFragment import org.thoughtcrime.securesms.service.KeyCachingService import org.thoughtcrime.securesms.stories.Stories +import org.thoughtcrime.securesms.stories.landing.StoriesLandingFragment import org.thoughtcrime.securesms.stories.settings.StorySettingsActivity import org.thoughtcrime.securesms.util.AppForegroundObserver import org.thoughtcrime.securesms.util.AppStartup +import org.thoughtcrime.securesms.util.BottomSheetUtil import org.thoughtcrime.securesms.util.CachedInflater import org.thoughtcrime.securesms.util.CommunicationActions import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme import org.thoughtcrime.securesms.util.DynamicTheme +import org.thoughtcrime.securesms.util.Material3OnScrollHelper import org.thoughtcrime.securesms.util.SplashScreenUtil +import org.thoughtcrime.securesms.util.TopToastPopup +import org.thoughtcrime.securesms.util.Util import org.thoughtcrime.securesms.util.viewModel import org.thoughtcrime.securesms.window.AppScaffold import org.thoughtcrime.securesms.window.WindowSizeClass +import org.whispersystems.signalservice.api.websocket.WebSocketConnectionState -class MainActivity : PassphraseRequiredActivity(), VoiceNoteMediaControllerOwner, MainNavigator.NavigatorProvider { +class MainActivity : PassphraseRequiredActivity(), VoiceNoteMediaControllerOwner, MainNavigator.NavigatorProvider, Material3OnScrollHelperBinder, ConversationListFragment.Callback, CallLogFragment.Callback { companion object { + private val TAG = Log.tag(MainActivity::class) + private const val KEY_STARTING_TAB = "STARTING_TAB" const val RESULT_CONFIG_CHANGED = Activity.RESULT_FIRST_USER + 901 @@ -172,6 +193,7 @@ class MainActivity : PassphraseRequiredActivity(), VoiceNoteMediaControllerOwner private val motionEventRelay: MotionEventRelay by viewModels() private var onFirstRender = false + private var previousTopToastPopup: TopToastPopup? = null private val mainBottomChromeCallback = BottomChromeCallback() private val megaphoneActionController = MainMegaphoneActionController() @@ -202,27 +224,49 @@ class MainActivity : PassphraseRequiredActivity(), VoiceNoteMediaControllerOwner } }) + UnreadPaymentsLiveData().observe(this) { unread -> + toolbarViewModel.setHasUnreadPayments(unread.isPresent) + } + lifecycleScope.launch { - repeatOnLifecycle(Lifecycle.State.RESUMED) { - mainNavigationViewModel.navigationEvents.collectLatest { - when (it) { - MainNavigationViewModel.NavigationEvent.STORY_CAMERA_FIRST -> { - mainBottomChromeCallback.onCameraClick(MainNavigationListLocation.STORIES) + launch { + repeatOnLifecycle(Lifecycle.State.RESUMED) { + mainNavigationViewModel.navigationEvents.collectLatest { + when (it) { + MainNavigationViewModel.NavigationEvent.STORY_CAMERA_FIRST -> { + mainBottomChromeCallback.onCameraClick(MainNavigationListLocation.STORIES) + } } } } } + + launch { + mainNavigationViewModel.getNotificationProfiles().collectLatest { profiles -> + withContext(Dispatchers.Main) { + updateNotificationProfileStatus(profiles) + } + } + } } shareDataTimestampViewModel.setTimestampFromActivityCreation(savedInstanceState, intent) setContent { - val listHostState = rememberFragmentState() val snackbar by mainNavigationViewModel.snackbar.collectAsStateWithLifecycle() val mainToolbarState by toolbarViewModel.state.collectAsStateWithLifecycle() val megaphone by mainNavigationViewModel.megaphone.collectAsStateWithLifecycle() val mainNavigationState by mainNavigationViewModel.mainNavigationState.collectAsStateWithLifecycle() + LaunchedEffect(mainNavigationState.selectedDestination) { + when (mainNavigationState.selectedDestination) { + MainNavigationListLocation.CHATS -> toolbarViewModel.presentToolbarForConversationListFragment() + MainNavigationListLocation.ARCHIVE -> toolbarViewModel.presentToolbarForConversationListArchiveFragment() + MainNavigationListLocation.CALLS -> toolbarViewModel.presentToolbarForCallLogFragment() + MainNavigationListLocation.STORIES -> toolbarViewModel.presentToolbarForStoriesLandingFragment() + } + } + val isNavigationVisible = remember(mainToolbarState.mode) { mainToolbarState.mode == MainToolbarMode.FULL } @@ -296,11 +340,40 @@ class MainActivity : PassphraseRequiredActivity(), VoiceNoteMediaControllerOwner Box( modifier = Modifier.weight(1f) ) { - AndroidFragment( - clazz = MainActivityListHostFragment::class.java, - fragmentState = listHostState, - modifier = Modifier.fillMaxSize() - ) + when (val destination = mainNavigationState.selectedDestination) { + MainNavigationListLocation.CHATS -> { + val state = key(destination) { rememberFragmentState() } + AndroidFragment( + clazz = ConversationListFragment::class.java, + fragmentState = state, + modifier = Modifier.fillMaxSize() + ) + } + MainNavigationListLocation.ARCHIVE -> { + val state = key(destination) { rememberFragmentState() } + AndroidFragment( + clazz = ConversationListArchiveFragment::class.java, + fragmentState = state, + modifier = Modifier.fillMaxSize() + ) + } + MainNavigationListLocation.CALLS -> { + val state = key(destination) { rememberFragmentState() } + AndroidFragment( + clazz = CallLogFragment::class.java, + fragmentState = state, + modifier = Modifier.fillMaxSize() + ) + } + MainNavigationListLocation.STORIES -> { + val state = key(destination) { rememberFragmentState() } + AndroidFragment( + clazz = StoriesLandingFragment::class.java, + fragmentState = state, + modifier = Modifier.fillMaxSize() + ) + } + } MainBottomChrome( state = mainBottomChromeState, @@ -433,6 +506,7 @@ class MainActivity : PassphraseRequiredActivity(), VoiceNoteMediaControllerOwner when (startingTab) { MainNavigationListLocation.CHATS -> mainNavigationViewModel.onChatsSelected() + MainNavigationListLocation.ARCHIVE -> mainNavigationViewModel.onArchiveSelected() MainNavigationListLocation.CALLS -> mainNavigationViewModel.onCallsSelected() MainNavigationListLocation.STORIES -> { if (Stories.isFeatureEnabled()) { @@ -453,6 +527,8 @@ class MainActivity : PassphraseRequiredActivity(), VoiceNoteMediaControllerOwner super.onResume() dynamicTheme.onResume(this) + toolbarViewModel.refresh() + if (SignalStore.misc.shouldShowLinkedDevicesReminder) { SignalStore.misc.shouldShowLinkedDevicesReminder = false RelinkDevicesReminderBottomSheetFragment.show(supportFragmentManager) @@ -516,6 +592,56 @@ class MainActivity : PassphraseRequiredActivity(), VoiceNoteMediaControllerOwner return navigator } + override fun bindScrollHelper(recyclerView: RecyclerView, lifecycleOwner: LifecycleOwner) { + Material3OnScrollHelper( + activity = this, + views = listOf(), + viewStubs = listOf(), + onSetToolbarColor = { + toolbarViewModel.setToolbarColor(it) + }, + setStatusBarColor = {}, + lifecycleOwner = lifecycleOwner + ).attach(recyclerView) + } + + override fun bindScrollHelper(recyclerView: RecyclerView, lifecycleOwner: LifecycleOwner, chatFolders: RecyclerView, setChatFolder: (Int) -> Unit) { + Material3OnScrollHelper( + activity = this, + views = listOf(chatFolders), + viewStubs = listOf(), + setStatusBarColor = {}, + onSetToolbarColor = { + toolbarViewModel.setToolbarColor(it) + }, + lifecycleOwner = lifecycleOwner, + setChatFolderColor = setChatFolder + ).attach(recyclerView) + } + + override fun updateProxyStatus(state: WebSocketConnectionState) { + if (SignalStore.proxy.isProxyEnabled) { + val proxyState: MainToolbarState.ProxyState = when (state) { + WebSocketConnectionState.CONNECTING, WebSocketConnectionState.DISCONNECTING, WebSocketConnectionState.DISCONNECTED -> MainToolbarState.ProxyState.CONNECTING + WebSocketConnectionState.CONNECTED -> MainToolbarState.ProxyState.CONNECTED + WebSocketConnectionState.AUTHENTICATION_FAILED, WebSocketConnectionState.FAILED, WebSocketConnectionState.REMOTE_DEPRECATED -> MainToolbarState.ProxyState.FAILED + else -> MainToolbarState.ProxyState.NONE + } + + toolbarViewModel.setProxyState(proxyState = proxyState) + } else { + toolbarViewModel.setProxyState(proxyState = MainToolbarState.ProxyState.NONE) + } + } + + override fun onMultiSelectStarted() { + toolbarViewModel.presentToolbarForMultiselect() + } + + override fun onMultiSelectFinished() { + toolbarViewModel.presentToolbarForCurrentDestination() + } + private fun handleDeepLinkIntent(intent: Intent) { handleConversationIntent(intent) handleGroupLinkInIntent(intent) @@ -578,6 +704,44 @@ class MainActivity : PassphraseRequiredActivity(), VoiceNoteMediaControllerOwner } } + private fun updateNotificationProfileStatus(notificationProfiles: List) { + val activeProfile = NotificationProfiles.getActiveProfile(notificationProfiles) + if (activeProfile != null) { + if (activeProfile.id != SignalStore.notificationProfile.lastProfilePopup) { + val view = findViewById(android.R.id.content) + + view.postDelayed({ + try { + var fragmentView = view ?: return@postDelayed + + SignalStore.notificationProfile.lastProfilePopup = activeProfile.id + SignalStore.notificationProfile.lastProfilePopupTime = System.currentTimeMillis() + + if (previousTopToastPopup?.isShowing == true) { + previousTopToastPopup?.dismiss() + } + + val fragment = supportFragmentManager.findFragmentByTag(BottomSheetUtil.STANDARD_BOTTOM_SHEET_FRAGMENT_TAG) + if (fragment != null && fragment.isAdded && fragment.view != null) { + fragmentView = fragment.requireView() as ViewGroup + } + + previousTopToastPopup = TopToastPopup.show(fragmentView, R.drawable.ic_moon_16, getString(R.string.ConversationListFragment__s_on, activeProfile.name)) + } catch (e: Exception) { + Log.w(TAG, "Unable to show toast popup", e) + } + }, 500L) + } + toolbarViewModel.setNotificationProfileEnabled(true) + } else { + toolbarViewModel.setNotificationProfileEnabled(false) + } + + if (!SignalStore.notificationProfile.hasSeenTooltip && Util.hasItems(notificationProfiles)) { + toolbarViewModel.setShowNotificationProfilesTooltip(true) + } + } + inner class ToolbarCallback : MainToolbarCallback { override fun onNewGroupClick() { @@ -744,6 +908,7 @@ class MainActivity : PassphraseRequiredActivity(), VoiceNoteMediaControllerOwner MainNavigationListLocation.CHATS -> mainNavigationViewModel.onChatsSelected() MainNavigationListLocation.CALLS -> mainNavigationViewModel.onCallsSelected() MainNavigationListLocation.STORIES -> mainNavigationViewModel.onStoriesSelected() + MainNavigationListLocation.ARCHIVE -> mainNavigationViewModel.onArchiveSelected() } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/avatar/AvatarImage.kt b/app/src/main/java/org/thoughtcrime/securesms/avatar/AvatarImage.kt index 07a32c3f4f..83e955251f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/avatar/AvatarImage.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/avatar/AvatarImage.kt @@ -9,13 +9,18 @@ import androidx.compose.foundation.background import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.shape.CircleShape import androidx.compose.runtime.Composable -import androidx.compose.runtime.livedata.observeAsState +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalInspectionMode import androidx.compose.ui.viewinterop.AndroidView -import androidx.lifecycle.map +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.rx3.asFlow import org.thoughtcrime.securesms.components.AvatarImageView import org.thoughtcrime.securesms.database.model.ProfileAvatarFileDetails import org.thoughtcrime.securesms.profiles.AvatarHelper @@ -36,11 +41,21 @@ fun AvatarImage( ) } else { val context = LocalContext.current - val state = recipient.live().liveData.map { AvatarImageState(NameUtil.getAbbreviation(it.getDisplayName(context)), it, AvatarHelper.getAvatarFileDetails(context, it.id)) }.observeAsState().value ?: return + var state: AvatarImageState by remember { + mutableStateOf(AvatarImageState(null, recipient, ProfileAvatarFileDetails.NO_DETAILS)) + } + + LaunchedEffect(recipient.id) { + Recipient.observable(recipient.id).asFlow() + .collectLatest { + state = AvatarImageState(NameUtil.getAbbreviation(it.getDisplayName(context)), it, AvatarHelper.getAvatarFileDetails(context, it.id)) + } + } AndroidView( factory = { AvatarImageView(context).apply { + initialize(context, null) this.contentDescription = contentDescription } }, diff --git a/app/src/main/java/org/thoughtcrime/securesms/calls/links/EditCallLinkNameDialogFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/calls/links/EditCallLinkNameDialogFragment.kt index c11d1b68b7..7e67b5515e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/calls/links/EditCallLinkNameDialogFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/calls/links/EditCallLinkNameDialogFragment.kt @@ -34,7 +34,6 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.core.os.bundleOf import androidx.fragment.app.setFragmentResult -import androidx.navigation.fragment.navArgs import org.signal.core.ui.compose.Buttons import org.signal.core.ui.compose.Scaffolds import org.signal.core.util.BreakIteratorCompat @@ -45,11 +44,11 @@ class EditCallLinkNameDialogFragment : ComposeDialogFragment() { companion object { const val RESULT_KEY = "edit_call_link_name" - - private const val MAX_CHARACTER_COUNT = 32 + const val ARG_NAME = "name" } - private val args: EditCallLinkNameDialogFragmentArgs by navArgs() + private val argName: String + get() = requireArguments().getString(ARG_NAME)!! override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -69,8 +68,8 @@ class EditCallLinkNameDialogFragment : ComposeDialogFragment() { var callName by remember { mutableStateOf( TextFieldValue( - text = args.name, - selection = TextRange(args.name.length) + text = argName, + selection = TextRange(argName.length) ) ) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/calls/links/create/CreateCallLinkBottomSheetDialogFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/calls/links/create/CreateCallLinkBottomSheetDialogFragment.kt index 2ceadd32fa..469c20f56e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/calls/links/create/CreateCallLinkBottomSheetDialogFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/calls/links/create/CreateCallLinkBottomSheetDialogFragment.kt @@ -33,9 +33,9 @@ import androidx.compose.ui.res.vectorResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.core.app.ShareCompat +import androidx.core.os.bundleOf import androidx.fragment.app.viewModels import androidx.lifecycle.compose.collectAsStateWithLifecycle -import androidx.navigation.fragment.findNavController import io.reactivex.rxjava3.kotlin.subscribeBy import org.signal.core.ui.compose.BottomSheets import org.signal.core.ui.compose.Buttons @@ -127,9 +127,9 @@ class CreateCallLinkBottomSheetDialogFragment : ComposeBottomSheetDialogFragment private fun onAddACallNameClicked() { val snapshot = viewModel.callLink.value - findNavController().navigate( - CreateCallLinkBottomSheetDialogFragmentDirections.actionCreateCallLinkBottomSheetToEditCallLinkNameDialogFragment(snapshot.state.name) - ) + EditCallLinkNameDialogFragment().apply { + arguments = bundleOf(EditCallLinkNameDialogFragment.ARG_NAME to snapshot.state.name) + }.show(parentFragmentManager, null) } private fun onJoinClicked() { diff --git a/app/src/main/java/org/thoughtcrime/securesms/calls/log/CallLogFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/calls/log/CallLogFragment.kt index a4f2feee01..d709793bef 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/calls/log/CallLogFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/calls/log/CallLogFragment.kt @@ -13,7 +13,6 @@ import androidx.compose.material3.SnackbarDuration import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels -import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.RecyclerView import com.google.android.material.appbar.AppBarLayout import com.google.android.material.dialog.MaterialAlertDialogBuilder @@ -26,6 +25,7 @@ import org.signal.core.util.concurrent.addTo import org.signal.core.util.logging.Log import org.thoughtcrime.securesms.MainNavigator import org.thoughtcrime.securesms.R +import org.thoughtcrime.securesms.calls.links.create.CreateCallLinkBottomSheetDialogFragment import org.thoughtcrime.securesms.calls.links.details.CallLinkDetailsActivity import org.thoughtcrime.securesms.components.ProgressCardDialogFragment import org.thoughtcrime.securesms.components.ScrollToPositionDelegate @@ -50,6 +50,7 @@ import org.thoughtcrime.securesms.main.MainToolbarViewModel import org.thoughtcrime.securesms.main.Material3OnScrollHelperBinder import org.thoughtcrime.securesms.main.SnackbarState import org.thoughtcrime.securesms.recipients.Recipient +import org.thoughtcrime.securesms.util.BottomSheetUtil import org.thoughtcrime.securesms.util.CommunicationActions import org.thoughtcrime.securesms.util.ViewUtil import org.thoughtcrime.securesms.util.doAfterNextLayout @@ -293,7 +294,7 @@ class CallLogFragment : Fragment(R.layout.call_log_fragment), CallLogAdapter.Cal } override fun onCreateACallLinkClicked() { - findNavController().navigate(R.id.createCallLinkBottomSheet) + CreateCallLinkBottomSheetDialogFragment().show(parentFragmentManager, BottomSheetUtil.STANDARD_BOTTOM_SHEET_FRAGMENT_TAG) } override fun onCallClicked(callLogRow: CallLogRow.Call) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/v2/CallInfoCallbacks.kt b/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/v2/CallInfoCallbacks.kt index 3349df9a75..82e1c7c6e2 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/v2/CallInfoCallbacks.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/v2/CallInfoCallbacks.kt @@ -9,12 +9,12 @@ import android.content.ActivityNotFoundException import android.content.Intent import android.widget.Toast import androidx.core.app.ShareCompat +import androidx.core.os.bundleOf import com.google.android.material.dialog.MaterialAlertDialogBuilder import org.thoughtcrime.securesms.BaseActivity import org.thoughtcrime.securesms.R import org.thoughtcrime.securesms.calls.links.CallLinks import org.thoughtcrime.securesms.calls.links.EditCallLinkNameDialogFragment -import org.thoughtcrime.securesms.calls.links.EditCallLinkNameDialogFragmentArgs import org.thoughtcrime.securesms.components.webrtc.controls.CallInfoView import org.thoughtcrime.securesms.components.webrtc.controls.ControlsAndInfoViewModel import org.thoughtcrime.securesms.dependencies.AppDependencies @@ -44,7 +44,7 @@ class CallInfoCallbacks( override fun onEditNameClicked(name: String) { EditCallLinkNameDialogFragment().apply { - arguments = EditCallLinkNameDialogFragmentArgs.Builder(name).build().toBundle() + arguments = bundleOf(EditCallLinkNameDialogFragment.ARG_NAME to name) }.show(activity.supportFragmentManager, null) } 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 c9647774f9..21feed90ec 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 @@ -937,6 +937,7 @@ class ConversationFragment : firstRender = false binding.conversationItemRecycler.doAfterNextLayout { SignalLocalMetrics.ConversationOpen.onRenderFinished() + (requireActivity() as? MainActivity)?.onFirstRender() doAfterFirstRender() } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversationlist/AddToFolderBottomSheet.kt b/app/src/main/java/org/thoughtcrime/securesms/conversationlist/AddToFolderBottomSheet.kt index bb8366f635..f1ab173772 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversationlist/AddToFolderBottomSheet.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversationlist/AddToFolderBottomSheet.kt @@ -32,7 +32,7 @@ import androidx.compose.ui.res.vectorResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.core.os.bundleOf -import androidx.fragment.app.viewModels +import androidx.fragment.app.activityViewModels import org.signal.core.ui.compose.BottomSheets import org.signal.core.ui.compose.Previews import org.signal.core.ui.compose.SignalPreview @@ -59,7 +59,7 @@ class AddToFolderBottomSheet private constructor(private val onDismissListener: OTHER(3) } - private val viewModel: ConversationListViewModel by viewModels( + private val viewModel: ConversationListViewModel.UnarchivedConversationListViewModel by activityViewModels( factoryProducer = { ConversationListViewModel.Factory(isArchived = false) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListAdapter.java b/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListAdapter.java index 91252feda9..c4647fa59b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListAdapter.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListAdapter.java @@ -72,6 +72,8 @@ class ConversationListAdapter extends ListAdapter viewModelClass = isArchived() ? ConversationListViewModel.ArchivedConversationListViewModel.class : ConversationListViewModel.UnarchivedConversationListViewModel.class; + viewModel = new ViewModelProvider(requireActivity(), new ConversationListViewModel.Factory(isArchived())).get(viewModelClass); lifecycleDisposable.add(viewModel.getConversationsState().subscribe(this::onConversationListChanged)); lifecycleDisposable.add(viewModel.getHasNoConversations().subscribe(this::updateEmptyState)); @@ -1389,7 +1388,7 @@ public class ConversationListFragment extends MainFragment implements ActionMode } protected Callback requireCallback() { - return ((Callback) getParentFragment().getParentFragment()); + return ((Callback) requireActivity()); } protected @PluralsRes int getArchivedSnackbarTitleRes() { diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListViewModel.kt index 7eb3eae5bb..0d44faccea 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListViewModel.kt @@ -42,7 +42,7 @@ import org.thoughtcrime.securesms.util.rx.RxStore import org.whispersystems.signalservice.api.websocket.WebSocketConnectionState import java.util.concurrent.TimeUnit -class ConversationListViewModel( +sealed class ConversationListViewModel( private val isArchived: Boolean, private val savedStateHandle: SavedStateHandle ) : ViewModel() { @@ -317,13 +317,20 @@ class ConversationListViewModel( val pinnedCount: Int = 0 ) + class UnarchivedConversationListViewModel(savedStateHandle: SavedStateHandle) : ConversationListViewModel(isArchived = false, savedStateHandle = savedStateHandle) + class ArchivedConversationListViewModel(savedStateHandle: SavedStateHandle) : ConversationListViewModel(isArchived = true, savedStateHandle = savedStateHandle) + class Factory( private val isArchived: Boolean ) : ViewModelProvider.Factory { override fun create(modelClass: Class, extras: CreationExtras): T { val savedStateHandle = extras.createSavedStateHandle() - return modelClass.cast(ConversationListViewModel(isArchived, savedStateHandle))!! + return if (isArchived) { + ArchivedConversationListViewModel(savedStateHandle) as T + } else { + UnarchivedConversationListViewModel(savedStateHandle) as T + } } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/main/MainActivityListHostFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/main/MainActivityListHostFragment.kt deleted file mode 100644 index 6321ec21a3..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/main/MainActivityListHostFragment.kt +++ /dev/null @@ -1,282 +0,0 @@ -package org.thoughtcrime.securesms.main - -import android.os.Bundle -import android.view.View -import android.view.ViewGroup -import androidx.fragment.app.Fragment -import androidx.fragment.app.activityViewModels -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.LifecycleOwner -import androidx.lifecycle.lifecycleScope -import androidx.lifecycle.repeatOnLifecycle -import androidx.navigation.NavController -import androidx.navigation.NavDestination -import androidx.navigation.findNavController -import androidx.recyclerview.widget.RecyclerView -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.collectLatest -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext -import org.signal.core.util.concurrent.LifecycleDisposable -import org.signal.core.util.logging.Log -import org.thoughtcrime.securesms.R -import org.thoughtcrime.securesms.calls.log.CallLogFragment -import org.thoughtcrime.securesms.conversationlist.ConversationListFragment -import org.thoughtcrime.securesms.conversationlist.model.UnreadPaymentsLiveData -import org.thoughtcrime.securesms.keyvalue.SignalStore -import org.thoughtcrime.securesms.notifications.profiles.NotificationProfile -import org.thoughtcrime.securesms.notifications.profiles.NotificationProfiles -import org.thoughtcrime.securesms.util.BottomSheetUtil -import org.thoughtcrime.securesms.util.Material3OnScrollHelper -import org.thoughtcrime.securesms.util.TopToastPopup -import org.thoughtcrime.securesms.util.Util -import org.whispersystems.signalservice.api.websocket.WebSocketConnectionState - -class MainActivityListHostFragment : Fragment(R.layout.main_activity_list_host_fragment), ConversationListFragment.Callback, Material3OnScrollHelperBinder, CallLogFragment.Callback { - - companion object { - private val TAG = Log.tag(MainActivityListHostFragment::class.java) - } - - private val disposables: LifecycleDisposable = LifecycleDisposable() - - private var previousTopToastPopup: TopToastPopup? = null - - private val destinationChangedListener = DestinationChangedListener() - private val toolbarViewModel: MainToolbarViewModel by activityViewModels() - private val mainNavigationViewModel: MainNavigationViewModel by activityViewModels() - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - disposables.bindTo(viewLifecycleOwner) - - UnreadPaymentsLiveData().observe(viewLifecycleOwner) { unread -> - toolbarViewModel.setHasUnreadPayments(unread.isPresent) - } - - lifecycleScope.launch { - repeatOnLifecycle(Lifecycle.State.RESUMED) { - launch { - mainNavigationViewModel.mainNavigationState.collectLatest { state -> - withContext(Dispatchers.Main) { - val controller: NavController = getChildNavController() - when (controller.currentDestination?.id) { - R.id.conversationListFragment -> goToStateFromConversationList(state, controller) - R.id.conversationListArchiveFragment -> Unit - R.id.storiesLandingFragment -> goToStateFromStories(state, controller) - R.id.callLogFragment -> goToStateFromCalling(state, controller) - } - } - } - } - - launch { - mainNavigationViewModel.getNotificationProfiles().collectLatest { profiles -> - withContext(Dispatchers.Main) { - updateNotificationProfileStatus(profiles) - } - } - } - } - } - } - - private fun getChildNavController(): NavController { - return requireView().findViewById(R.id.fragment_container).findNavController() - } - - private fun goToStateFromConversationList(state: MainNavigationState, navController: NavController) { - if (state.selectedDestination == MainNavigationListLocation.CHATS) { - return - } else { - val destination = if (state.selectedDestination == MainNavigationListLocation.STORIES) { - R.id.action_conversationListFragment_to_storiesLandingFragment - } else { - R.id.action_conversationListFragment_to_callLogFragment - } - - navController.navigate( - destination, - null, - null - ) - } - } - - private fun goToStateFromCalling(state: MainNavigationState, navController: NavController) { - when (state.selectedDestination) { - MainNavigationListLocation.CALLS -> return - MainNavigationListLocation.CHATS -> navController.popBackStack(R.id.conversationListFragment, false) - MainNavigationListLocation.STORIES -> navController.navigate(R.id.action_callLogFragment_to_storiesLandingFragment) - } - } - - private fun goToStateFromStories(state: MainNavigationState, navController: NavController) { - when (state.selectedDestination) { - MainNavigationListLocation.STORIES -> return - MainNavigationListLocation.CHATS -> navController.popBackStack(R.id.conversationListFragment, false) - MainNavigationListLocation.CALLS -> navController.navigate(R.id.action_storiesLandingFragment_to_callLogFragment) - } - } - - override fun onResume() { - super.onResume() - toolbarViewModel.refresh() - - requireView() - .findViewById(R.id.fragment_container) - .findNavController() - .addOnDestinationChangedListener(destinationChangedListener) - - if (toolbarViewModel.state.value.mode == MainToolbarMode.ACTION_MODE) { - presentToolbarForMultiselect() - } - } - - override fun onPause() { - super.onPause() - requireView() - .findViewById(R.id.fragment_container) - .findNavController() - .removeOnDestinationChangedListener(destinationChangedListener) - } - - private fun presentToolbarForConversationListFragment() { - toolbarViewModel.setToolbarMode(MainToolbarMode.FULL, destination = MainNavigationListLocation.CHATS, overwriteSearchMode = false) - } - - private fun presentToolbarForConversationListArchiveFragment() { - toolbarViewModel.setToolbarMode(MainToolbarMode.BASIC, destination = MainNavigationListLocation.CHATS) - } - - private fun presentToolbarForStoriesLandingFragment() { - toolbarViewModel.setToolbarMode(MainToolbarMode.FULL, destination = MainNavigationListLocation.STORIES) - } - - private fun presentToolbarForCallLogFragment() { - toolbarViewModel.setToolbarMode(MainToolbarMode.FULL, destination = MainNavigationListLocation.CALLS) - } - - private fun presentToolbarForMultiselect() { - toolbarViewModel.setToolbarMode(MainToolbarMode.ACTION_MODE) - } - - override fun onDestroyView() { - previousTopToastPopup = null - super.onDestroyView() - } - - override fun onMultiSelectStarted() { - presentToolbarForMultiselect() - } - - override fun onMultiSelectFinished() { - val currentDestination: NavDestination? = requireView().findViewById(R.id.fragment_container).findNavController().currentDestination - if (currentDestination != null) { - presentToolbarForDestination(currentDestination) - } - } - - override fun updateProxyStatus(state: WebSocketConnectionState) { - if (SignalStore.proxy.isProxyEnabled) { - val proxyState: MainToolbarState.ProxyState = when (state) { - WebSocketConnectionState.CONNECTING, WebSocketConnectionState.DISCONNECTING, WebSocketConnectionState.DISCONNECTED -> MainToolbarState.ProxyState.CONNECTING - WebSocketConnectionState.CONNECTED -> MainToolbarState.ProxyState.CONNECTED - WebSocketConnectionState.AUTHENTICATION_FAILED, WebSocketConnectionState.FAILED, WebSocketConnectionState.REMOTE_DEPRECATED -> MainToolbarState.ProxyState.FAILED - else -> MainToolbarState.ProxyState.NONE - } - - toolbarViewModel.setProxyState(proxyState = proxyState) - } else { - toolbarViewModel.setProxyState(proxyState = MainToolbarState.ProxyState.NONE) - } - } - - private fun updateNotificationProfileStatus(notificationProfiles: List) { - val activeProfile = NotificationProfiles.getActiveProfile(notificationProfiles) - if (activeProfile != null) { - if (activeProfile.id != SignalStore.notificationProfile.lastProfilePopup) { - view?.postDelayed({ - try { - var fragmentView = view as? ViewGroup ?: return@postDelayed - - SignalStore.notificationProfile.lastProfilePopup = activeProfile.id - SignalStore.notificationProfile.lastProfilePopupTime = System.currentTimeMillis() - - if (previousTopToastPopup?.isShowing == true) { - previousTopToastPopup?.dismiss() - } - - val fragment = parentFragmentManager.findFragmentByTag(BottomSheetUtil.STANDARD_BOTTOM_SHEET_FRAGMENT_TAG) - if (fragment != null && fragment.isAdded && fragment.view != null) { - fragmentView = fragment.requireView() as ViewGroup - } - - previousTopToastPopup = TopToastPopup.show(fragmentView, R.drawable.ic_moon_16, getString(R.string.ConversationListFragment__s_on, activeProfile.name)) - } catch (e: Exception) { - Log.w(TAG, "Unable to show toast popup", e) - } - }, 500L) - } - toolbarViewModel.setNotificationProfileEnabled(true) - } else { - toolbarViewModel.setNotificationProfileEnabled(false) - } - - if (!SignalStore.notificationProfile.hasSeenTooltip && Util.hasItems(notificationProfiles)) { - toolbarViewModel.setShowNotificationProfilesTooltip(true) - } - } - - private fun presentToolbarForDestination(destination: NavDestination) { - when (destination.id) { - R.id.conversationListFragment -> { - presentToolbarForConversationListFragment() - } - - R.id.conversationListArchiveFragment -> { - presentToolbarForConversationListArchiveFragment() - } - - R.id.storiesLandingFragment -> { - presentToolbarForStoriesLandingFragment() - } - - R.id.callLogFragment -> { - presentToolbarForCallLogFragment() - } - } - } - - private inner class DestinationChangedListener : NavController.OnDestinationChangedListener { - override fun onDestinationChanged(controller: NavController, destination: NavDestination, arguments: Bundle?) { - presentToolbarForDestination(destination) - } - } - - override fun bindScrollHelper(recyclerView: RecyclerView, lifecycleOwner: LifecycleOwner) { - Material3OnScrollHelper( - activity = requireActivity(), - views = listOf(), - viewStubs = listOf(), - onSetToolbarColor = { - toolbarViewModel.setToolbarColor(it) - }, - setStatusBarColor = {}, - lifecycleOwner = lifecycleOwner - ).attach(recyclerView) - } - - override fun bindScrollHelper(recyclerView: RecyclerView, lifecycleOwner: LifecycleOwner, chatFolders: RecyclerView, setChatFolder: (Int) -> Unit) { - Material3OnScrollHelper( - activity = requireActivity(), - views = listOf(chatFolders), - viewStubs = listOf(), - setStatusBarColor = {}, - onSetToolbarColor = { - toolbarViewModel.setToolbarColor(it) - }, - lifecycleOwner = lifecycleOwner, - setChatFolderColor = setChatFolder - ).attach(recyclerView) - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/main/MainFloatingActionButtons.kt b/app/src/main/java/org/thoughtcrime/securesms/main/MainFloatingActionButtons.kt index 14708f14cd..3ec59beba8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/main/MainFloatingActionButtons.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/main/MainFloatingActionButtons.kt @@ -170,6 +170,7 @@ private fun PrimaryActionButton( ) { val onClick = remember(destination) { when (destination) { + MainNavigationListLocation.ARCHIVE -> error("Not supported") MainNavigationListLocation.CHATS -> onNewChatClick MainNavigationListLocation.CALLS -> onNewCallClick MainNavigationListLocation.STORIES -> { @@ -184,6 +185,7 @@ private fun PrimaryActionButton( icon = { AnimatedContent(destination) { targetState -> val (icon, contentDescriptionId) = when (targetState) { + MainNavigationListLocation.ARCHIVE -> error("Not supported") MainNavigationListLocation.CHATS -> R.drawable.symbol_edit_24 to R.string.conversation_list_fragment__fab_content_description MainNavigationListLocation.CALLS -> R.drawable.symbol_phone_plus_24 to R.string.CallLogFragment__start_a_new_call MainNavigationListLocation.STORIES -> R.drawable.symbol_camera_24 to R.string.conversation_list_fragment__open_camera_description diff --git a/app/src/main/java/org/thoughtcrime/securesms/main/MainNavigation.kt b/app/src/main/java/org/thoughtcrime/securesms/main/MainNavigation.kt index e762fb58e4..dafc3e823a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/main/MainNavigation.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/main/MainNavigation.kt @@ -68,6 +68,10 @@ enum class MainNavigationListLocation( label = R.string.ConversationListTabs__chats, icon = R.raw.chats_28 ), + ARCHIVE( + label = R.string.ConversationListTabs__chats, + icon = R.raw.chats_28 + ), CALLS( label = R.string.ConversationListTabs__calls, icon = R.raw.calls_28 @@ -104,15 +108,16 @@ fun MainNavigationBar( ) { val entries = remember(state.isStoriesFeatureEnabled) { if (state.isStoriesFeatureEnabled) { - MainNavigationListLocation.entries + MainNavigationListLocation.entries.filterNot { it == MainNavigationListLocation.ARCHIVE } } else { - MainNavigationListLocation.entries.filterNot { it == MainNavigationListLocation.STORIES } + MainNavigationListLocation.entries.filterNot { it == MainNavigationListLocation.STORIES || it == MainNavigationListLocation.ARCHIVE } } } entries.forEach { destination -> val badgeCount = when (destination) { + MainNavigationListLocation.ARCHIVE -> error("Not supported") MainNavigationListLocation.CHATS -> state.chatsCount MainNavigationListLocation.CALLS -> state.callsCount MainNavigationListLocation.STORIES -> state.storiesCount @@ -219,9 +224,9 @@ fun MainNavigationRail( ) { val entries = remember(state.isStoriesFeatureEnabled) { if (state.isStoriesFeatureEnabled) { - MainNavigationListLocation.entries + MainNavigationListLocation.entries.filterNot { it == MainNavigationListLocation.ARCHIVE } } else { - MainNavigationListLocation.entries.filterNot { it == MainNavigationListLocation.STORIES } + MainNavigationListLocation.entries.filterNot { it == MainNavigationListLocation.STORIES || it == MainNavigationListLocation.ARCHIVE } } } @@ -262,6 +267,7 @@ private fun BoxScope.NavigationRailCountIndicator( ) { val count = remember(state, destination) { when (destination) { + MainNavigationListLocation.ARCHIVE -> error("Not supported") MainNavigationListLocation.CHATS -> state.chatsCount MainNavigationListLocation.CALLS -> state.callsCount MainNavigationListLocation.STORIES -> state.storiesCount 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 ae34190634..ec52f7c4b8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/main/MainNavigationViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/main/MainNavigationViewModel.kt @@ -95,6 +95,15 @@ class MainNavigationViewModel( val wrapped = LegacyNavigator(composeScope, threePaneScaffoldNavigator, goToLegacyDetailLocation) this.navigator = wrapped + if (previous != null) { + val destination = previous.currentDestination?.contentKey ?: return wrapped + if (destination is MainNavigationListLocation) { + goTo(destination) + } + } else { + goTo(mainNavigationState.value.selectedDestination) + } + if (previous != null) { val destination = previous.currentDestination?.contentKey ?: return wrapped if (destination is MainNavigationDetailLocation) { @@ -123,6 +132,12 @@ class MainNavigationViewModel( } } + fun goTo(location: MainNavigationListLocation) { + internalMainNavigationState.update { + it.copy(selectedDestination = location) + } + } + fun goToCameraFirstStoryCapture() { viewModelScope.launch { internalNavigationEvents.emit(NavigationEvent.STORY_CAMERA_FIRST) @@ -168,6 +183,13 @@ class MainNavigationViewModel( } } + fun onArchiveSelected() { + internalTabClickEvents.tryEmit(MainNavigationListLocation.ARCHIVE) + internalMainNavigationState.update { + it.copy(selectedDestination = MainNavigationListLocation.ARCHIVE) + } + } + fun onCallsSelected() { internalTabClickEvents.tryEmit(MainNavigationListLocation.CALLS) internalMainNavigationState.update { diff --git a/app/src/main/java/org/thoughtcrime/securesms/main/MainToolbar.kt b/app/src/main/java/org/thoughtcrime/securesms/main/MainToolbar.kt index c966820bb3..43b97ba062 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/main/MainToolbar.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/main/MainToolbar.kt @@ -395,6 +395,7 @@ private fun PrimaryToolbar( controller = controller ) { when (state.destination) { + MainNavigationListLocation.ARCHIVE -> Unit MainNavigationListLocation.CHATS -> ChatDropdownItems(state, callback, dismiss) MainNavigationListLocation.CALLS -> CallDropdownItems(state.callFilter, callback, dismiss) MainNavigationListLocation.STORIES -> StoryDropDownItems(callback, dismiss) diff --git a/app/src/main/java/org/thoughtcrime/securesms/main/MainToolbarViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/main/MainToolbarViewModel.kt index b7ec78960f..202ec7f50f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/main/MainToolbarViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/main/MainToolbarViewModel.kt @@ -73,6 +73,33 @@ class MainToolbarViewModel : ViewModel() { } } + fun presentToolbarForConversationListFragment() { + setToolbarMode(MainToolbarMode.FULL, destination = MainNavigationListLocation.CHATS, overwriteSearchMode = false) + } + + fun presentToolbarForConversationListArchiveFragment() { + setToolbarMode(MainToolbarMode.BASIC, destination = MainNavigationListLocation.CHATS) + } + + fun presentToolbarForStoriesLandingFragment() { + setToolbarMode(MainToolbarMode.FULL, destination = MainNavigationListLocation.STORIES) + } + + fun presentToolbarForCallLogFragment() { + setToolbarMode(MainToolbarMode.FULL, destination = MainNavigationListLocation.CALLS) + } + + fun presentToolbarForMultiselect() { + setToolbarMode(MainToolbarMode.ACTION_MODE) + } + + fun presentToolbarForCurrentDestination() { + when (state.value.destination) { + MainNavigationListLocation.ARCHIVE -> setToolbarMode(MainToolbarMode.BASIC) + else -> setToolbarMode(MainToolbarMode.FULL) + } + } + @JvmOverloads fun setToolbarMode( mode: MainToolbarMode, diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/landing/StoriesLandingFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/landing/StoriesLandingFragment.kt index 8d09c378fa..9ba4e60cc6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/landing/StoriesLandingFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/landing/StoriesLandingFragment.kt @@ -9,7 +9,6 @@ import androidx.compose.ui.platform.ComposeView import androidx.core.app.ActivityOptionsCompat import androidx.core.view.ViewCompat import androidx.fragment.app.activityViewModels -import androidx.fragment.app.viewModels import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView.AdapterDataObserver @@ -66,7 +65,7 @@ class StoriesLandingFragment : DSLSettingsFragment(layoutId = R.layout.stories_l private val lifecycleDisposable = LifecycleDisposable() - private val viewModel: StoriesLandingViewModel by viewModels( + private val viewModel: StoriesLandingViewModel by activityViewModels( factoryProducer = { StoriesLandingViewModel.Factory(StoriesLandingRepository(requireContext())) } diff --git a/app/src/main/res/layout/main_activity_list_host_fragment.xml b/app/src/main/res/layout/main_activity_list_host_fragment.xml deleted file mode 100644 index 92ad070f18..0000000000 --- a/app/src/main/res/layout/main_activity_list_host_fragment.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/app/src/main/res/navigation/main_activity_list.xml b/app/src/main/res/navigation/main_activity_list.xml deleted file mode 100644 index cf9a0e5147..0000000000 --- a/app/src/main/res/navigation/main_activity_list.xml +++ /dev/null @@ -1,76 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file