mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-22 01:40:07 +01:00
Remove MainListHostFragment and rescope list vms to the activity.
This commit is contained in:
@@ -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<NotificationProfile>) {
|
||||
val activeProfile = NotificationProfiles.getActiveProfile(notificationProfiles)
|
||||
if (activeProfile != null) {
|
||||
if (activeProfile.id != SignalStore.notificationProfile.lastProfilePopup) {
|
||||
val view = findViewById<ViewGroup>(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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user