Move toolbar into main activity composable.

This commit is contained in:
Alex Hart
2025-03-31 12:57:15 -03:00
committed by Greyson Parrelli
parent 23af6e2bf9
commit 49fcf08331
5 changed files with 130 additions and 127 deletions

View File

@@ -13,36 +13,53 @@ import android.os.Bundle
import android.view.View
import android.view.ViewTreeObserver
import androidx.activity.compose.setContent
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.core.content.ContextCompat
import androidx.fragment.compose.AndroidFragment
import androidx.fragment.compose.rememberFragmentState
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import org.signal.core.ui.compose.theme.SignalTheme
import org.signal.core.util.concurrent.LifecycleDisposable
import org.signal.core.util.getSerializableCompat
import org.signal.donations.StripeApi
import org.thoughtcrime.securesms.calls.YouAreAlreadyInACallSnackbar.show
import org.thoughtcrime.securesms.calls.log.CallLogFilter
import org.thoughtcrime.securesms.components.ConnectivityWarningBottomSheet
import org.thoughtcrime.securesms.components.DebugLogsPromptDialogFragment
import org.thoughtcrime.securesms.components.DeviceSpecificNotificationBottomSheet
import org.thoughtcrime.securesms.components.PromptBatterySaverDialogFragment
import org.thoughtcrime.securesms.components.settings.app.AppSettingsActivity
import org.thoughtcrime.securesms.components.settings.app.AppSettingsActivity.Companion.manageSubscriptions
import org.thoughtcrime.securesms.components.settings.app.notifications.manual.NotificationProfileSelectionFragment
import org.thoughtcrime.securesms.components.voice.VoiceNoteMediaController
import org.thoughtcrime.securesms.components.voice.VoiceNoteMediaControllerOwner
import org.thoughtcrime.securesms.conversationlist.RelinkDevicesReminderBottomSheetFragment
import org.thoughtcrime.securesms.conversationlist.RestoreCompleteBottomSheetDialog
import org.thoughtcrime.securesms.conversationlist.model.ConversationFilter
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.main.MainActivityListHostFragment
import org.thoughtcrime.securesms.main.MainNavigationDestination
import org.thoughtcrime.securesms.main.MainNavigationDetailLocation
import org.thoughtcrime.securesms.main.MainToolbar
import org.thoughtcrime.securesms.main.MainToolbarCallback
import org.thoughtcrime.securesms.main.MainToolbarMode
import org.thoughtcrime.securesms.main.MainToolbarViewModel
import org.thoughtcrime.securesms.net.DeviceTransferBlockingInterceptor
import org.thoughtcrime.securesms.notifications.VitalsViewModel
import org.thoughtcrime.securesms.service.KeyCachingService
import org.thoughtcrime.securesms.stories.Stories
import org.thoughtcrime.securesms.stories.settings.StorySettingsActivity
import org.thoughtcrime.securesms.stories.tabs.ConversationListTabRepository
import org.thoughtcrime.securesms.stories.tabs.ConversationListTabsFragment
import org.thoughtcrime.securesms.stories.tabs.ConversationListTabsViewModel
@@ -50,6 +67,7 @@ import org.thoughtcrime.securesms.util.AppStartup
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.SplashScreenUtil
import org.thoughtcrime.securesms.util.WindowUtil
import org.thoughtcrime.securesms.util.viewModel
@@ -91,6 +109,15 @@ class MainActivity : PassphraseRequiredActivity(), VoiceNoteMediaControllerOwner
VitalsViewModel(application)
}
private val openSettings: ActivityResultLauncher<Intent> = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == RESULT_CONFIG_CHANGED) {
recreate()
}
}
private val toolbarViewModel: MainToolbarViewModel by viewModels()
private val toolbarCallback = ToolbarCallback()
private var onFirstRender = false
override fun onCreate(savedInstanceState: Bundle?, ready: Boolean) {
@@ -124,11 +151,22 @@ class MainActivity : PassphraseRequiredActivity(), VoiceNoteMediaControllerOwner
)
}
) {
AndroidFragment(
clazz = MainActivityListHostFragment::class.java,
fragmentState = listHostState,
modifier = Modifier.fillMaxSize()
)
Column {
val state by toolbarViewModel.state.collectAsStateWithLifecycle()
SignalTheme(isDarkMode = DynamicTheme.isDarkTheme(LocalContext.current)) {
MainToolbar(
state = state,
callback = toolbarCallback
)
}
AndroidFragment(
clazz = MainActivityListHostFragment::class.java,
fragmentState = listHostState,
modifier = Modifier.fillMaxSize()
)
}
}
}
@@ -175,6 +213,7 @@ class MainActivity : PassphraseRequiredActivity(), VoiceNoteMediaControllerOwner
conversationListTabsViewModel.onStoriesSelected()
}
}
null -> Unit
}
}
@@ -298,4 +337,87 @@ class MainActivity : PassphraseRequiredActivity(), VoiceNoteMediaControllerOwner
}
}
}
inner class ToolbarCallback : MainToolbarCallback {
override fun onNewGroupClick() {
startActivity(CreateGroupActivity.newIntent(this@MainActivity))
}
override fun onClearPassphraseClick() {
val intent = Intent(this@MainActivity, KeyCachingService::class.java)
intent.setAction(KeyCachingService.CLEAR_KEY_ACTION)
startService(intent)
}
override fun onMarkReadClick() {
toolbarViewModel.markAllMessagesRead()
}
override fun onInviteFriendsClick() {
val intent = Intent(this@MainActivity, InviteActivity::class.java)
startActivity(intent)
}
override fun onFilterUnreadChatsClick() {
toolbarViewModel.setChatFilter(ConversationFilter.UNREAD)
}
override fun onClearUnreadChatsFilterClick() {
toolbarViewModel.setChatFilter(ConversationFilter.OFF)
}
override fun onSettingsClick() {
openSettings.launch(AppSettingsActivity.home(this@MainActivity))
}
override fun onNotificationProfileClick() {
NotificationProfileSelectionFragment.show(supportFragmentManager)
}
override fun onProxyClick() {
startActivity(AppSettingsActivity.proxy(this@MainActivity))
}
override fun onSearchClick() {
conversationListTabsViewModel.onSearchOpened()
toolbarViewModel.setToolbarMode(MainToolbarMode.SEARCH)
toolbarViewModel.emitEvent(MainToolbarViewModel.Event.Search.Open)
}
override fun onClearCallHistoryClick() {
toolbarViewModel.clearCallHistory()
}
override fun onFilterMissedCallsClick() {
toolbarViewModel.setCallLogFilter(CallLogFilter.MISSED)
}
override fun onClearCallFilterClick() {
toolbarViewModel.setCallLogFilter(CallLogFilter.ALL)
}
override fun onStoryPrivacyClick() {
startActivity(StorySettingsActivity.getIntent(this@MainActivity))
}
override fun onCloseSearchClick() {
conversationListTabsViewModel.onSearchClosed()
toolbarViewModel.setToolbarMode(MainToolbarMode.FULL)
toolbarViewModel.emitEvent(MainToolbarViewModel.Event.Search.Close)
}
override fun onCloseArchiveClick() {
toolbarViewModel.emitEvent(MainToolbarViewModel.Event.Chats.CloseArchive)
}
override fun onSearchQueryUpdated(query: String) {
toolbarViewModel.setSearchQuery(query)
}
override fun onNotificationProfileTooltipDismissed() {
SignalStore.notificationProfile.hasSeenTooltip = true
toolbarViewModel.setShowNotificationProfilesTooltip(false)
}
}
}

View File

@@ -800,6 +800,8 @@ public class ConversationListFragment extends MainFragment implements ActionMode
handleFilterUnreadChats();
} else if (event instanceof MainToolbarViewModel.Event.Chats.ClearFilter) {
onClearFilterClick();
} else if (event instanceof MainToolbarViewModel.Event.Chats.CloseArchive) {
NavHostFragment.findNavController(this).popBackStack();
}
})
);

View File

@@ -1,47 +1,31 @@
package org.thoughtcrime.securesms.main
import android.content.Intent
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.runtime.getValue
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.LocalContext
import androidx.core.view.ViewCompat
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.fragment.app.viewModels
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.NavController
import androidx.navigation.NavDestination
import androidx.navigation.findNavController
import androidx.navigation.fragment.FragmentNavigatorExtras
import androidx.recyclerview.widget.RecyclerView
import io.reactivex.rxjava3.kotlin.subscribeBy
import org.signal.core.ui.compose.theme.SignalTheme
import org.signal.core.util.concurrent.LifecycleDisposable
import org.signal.core.util.logging.Log
import org.thoughtcrime.securesms.InviteActivity
import org.thoughtcrime.securesms.MainActivity
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.calls.log.CallLogFilter
import org.thoughtcrime.securesms.calls.log.CallLogFragment
import org.thoughtcrime.securesms.components.settings.app.AppSettingsActivity
import org.thoughtcrime.securesms.components.settings.app.notifications.manual.NotificationProfileSelectionFragment
import org.thoughtcrime.securesms.conversationlist.ConversationListFragment
import org.thoughtcrime.securesms.conversationlist.model.ConversationFilter
import org.thoughtcrime.securesms.conversationlist.model.UnreadPaymentsLiveData
import org.thoughtcrime.securesms.groups.ui.creategroup.CreateGroupActivity
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.notifications.profiles.NotificationProfile
import org.thoughtcrime.securesms.notifications.profiles.NotificationProfiles
import org.thoughtcrime.securesms.service.KeyCachingService
import org.thoughtcrime.securesms.stories.settings.StorySettingsActivity
import org.thoughtcrime.securesms.stories.tabs.ConversationListTabsState
import org.thoughtcrime.securesms.stories.tabs.ConversationListTabsViewModel
import org.thoughtcrime.securesms.util.BottomSheetUtil
import org.thoughtcrime.securesms.util.DynamicTheme
import org.thoughtcrime.securesms.util.Material3OnScrollHelper
import org.thoughtcrime.securesms.util.TopToastPopup
import org.thoughtcrime.securesms.util.Util
@@ -59,112 +43,11 @@ class MainActivityListHostFragment : Fragment(R.layout.main_activity_list_host_f
private var previousTopToastPopup: TopToastPopup? = null
private val destinationChangedListener = DestinationChangedListener()
private val openSettings = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == MainActivity.RESULT_CONFIG_CHANGED) {
requireActivity().recreate()
}
}
private val toolbarCallback = object : MainToolbarCallback {
override fun onNewGroupClick() {
startActivity(CreateGroupActivity.newIntent(requireActivity()))
}
override fun onClearPassphraseClick() {
val intent = Intent(requireActivity(), KeyCachingService::class.java)
intent.setAction(KeyCachingService.CLEAR_KEY_ACTION)
requireActivity().startService(intent)
}
override fun onMarkReadClick() {
toolbarViewModel.markAllMessagesRead()
}
override fun onInviteFriendsClick() {
val intent = Intent(requireContext(), InviteActivity::class.java)
startActivity(intent)
}
override fun onFilterUnreadChatsClick() {
toolbarViewModel.setChatFilter(ConversationFilter.UNREAD)
}
override fun onClearUnreadChatsFilterClick() {
toolbarViewModel.setChatFilter(ConversationFilter.OFF)
}
override fun onSettingsClick() {
openSettings.launch(AppSettingsActivity.home(requireContext()))
}
override fun onNotificationProfileClick() {
NotificationProfileSelectionFragment.show(parentFragmentManager)
}
override fun onProxyClick() {
startActivity(AppSettingsActivity.proxy(requireContext()))
}
override fun onSearchClick() {
conversationListTabsViewModel.onSearchOpened()
toolbarViewModel.setToolbarMode(MainToolbarMode.SEARCH)
toolbarViewModel.emitEvent(MainToolbarViewModel.Event.Search.Open)
}
override fun onClearCallHistoryClick() {
toolbarViewModel.clearCallHistory()
}
override fun onFilterMissedCallsClick() {
toolbarViewModel.setCallLogFilter(CallLogFilter.MISSED)
}
override fun onClearCallFilterClick() {
toolbarViewModel.setCallLogFilter(CallLogFilter.ALL)
}
override fun onStoryPrivacyClick() {
startActivity(StorySettingsActivity.getIntent(requireContext()))
}
override fun onCloseSearchClick() {
conversationListTabsViewModel.onSearchClosed()
toolbarViewModel.setToolbarMode(MainToolbarMode.FULL)
toolbarViewModel.emitEvent(MainToolbarViewModel.Event.Search.Close)
}
override fun onCloseArchiveClick() {
getChildNavController().popBackStack()
}
override fun onSearchQueryUpdated(query: String) {
toolbarViewModel.setSearchQuery(query)
}
override fun onNotificationProfileTooltipDismissed() {
SignalStore.notificationProfile.hasSeenTooltip = true
toolbarViewModel.setShowNotificationProfilesTooltip(false)
}
}
private val toolbarViewModel: MainToolbarViewModel by activityViewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
disposables.bindTo(viewLifecycleOwner)
val toolbarContainer = view.findViewById<ComposeView>(R.id.toolbar_container)
toolbarContainer.setContent {
val state by toolbarViewModel.state.collectAsStateWithLifecycle()
SignalTheme(isDarkMode = DynamicTheme.isDarkTheme(LocalContext.current)) {
MainToolbar(
state = state,
callback = toolbarCallback
)
}
}
UnreadPaymentsLiveData().observe(viewLifecycleOwner) { unread ->
toolbarViewModel.setHasUnreadPayments(unread.isPresent)
}

View File

@@ -157,6 +157,7 @@ class MainToolbarViewModel : ViewModel() {
sealed interface Chats : Event {
data object ApplyFilter : Chats
data object ClearFilter : Chats
data object CloseArchive : Chats
}
sealed interface CallLog : Event {