diff --git a/app/src/main/java/org/thoughtcrime/securesms/MainActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/MainActivity.kt index c58fea0b87..c9d63d9497 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/MainActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/MainActivity.kt @@ -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 = 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) + } + } } 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 dd1727c6ef..043b44d24f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListFragment.java @@ -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(); } }) ); diff --git a/app/src/main/java/org/thoughtcrime/securesms/main/MainActivityListHostFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/main/MainActivityListHostFragment.kt index e52db78d72..04a2d2adc4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/main/MainActivityListHostFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/main/MainActivityListHostFragment.kt @@ -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(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) } 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 f03e7d7c39..b9414675f6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/main/MainToolbarViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/main/MainToolbarViewModel.kt @@ -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 { 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 index 3dabb94b0a..92ad070f18 100644 --- a/app/src/main/res/layout/main_activity_list_host_fragment.xml +++ b/app/src/main/res/layout/main_activity_list_host_fragment.xml @@ -7,11 +7,6 @@ android:orientation="vertical" tools:viewBindingIgnore="true"> - -