mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-20 02:58:45 +00:00
Utilize snapshotFlow to fix insets.
This commit is contained in:
committed by
Cody Henthorne
parent
b49074a786
commit
971bcf4f41
@@ -102,7 +102,6 @@ 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.DetailsScreenNavHost
|
||||
import org.thoughtcrime.securesms.main.InsetsViewModelUpdater
|
||||
import org.thoughtcrime.securesms.main.MainBottomChrome
|
||||
import org.thoughtcrime.securesms.main.MainBottomChromeCallback
|
||||
import org.thoughtcrime.securesms.main.MainBottomChromeState
|
||||
@@ -415,8 +414,6 @@ class MainActivity : PassphraseRequiredActivity(), VoiceNoteMediaControllerOwner
|
||||
}
|
||||
}
|
||||
|
||||
InsetsViewModelUpdater()
|
||||
|
||||
AppScaffold(
|
||||
navigator = wrappedNavigator,
|
||||
paneExpansionState = paneExpansionState,
|
||||
|
||||
@@ -13,7 +13,7 @@ import androidx.core.view.WindowInsetsCompat
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.main.InsetsViewModel
|
||||
import org.thoughtcrime.securesms.main.VerticalInsets
|
||||
import org.thoughtcrime.securesms.util.ViewUtil
|
||||
import org.thoughtcrime.securesms.window.WindowSizeClass.Companion.getWindowSizeClass
|
||||
import kotlin.math.roundToInt
|
||||
@@ -66,7 +66,7 @@ open class InsetAwareConstraintLayout @JvmOverloads constructor(
|
||||
|
||||
private var insets: WindowInsetsCompat? = null
|
||||
private var windowTypes: Int = InsetAwareConstraintLayout.windowTypes
|
||||
private var verticalInsetOverride: InsetsViewModel.Insets = InsetsViewModel.Insets.Zero
|
||||
private var verticalInsetOverride: VerticalInsets = VerticalInsets.Zero
|
||||
|
||||
private val windowInsetsListener = androidx.core.view.OnApplyWindowInsetsListener { _, insets ->
|
||||
this.insets = insets
|
||||
@@ -130,7 +130,7 @@ open class InsetAwareConstraintLayout @JvmOverloads constructor(
|
||||
}
|
||||
}
|
||||
|
||||
fun applyInsets(insets: InsetsViewModel.Insets) {
|
||||
fun applyInsets(insets: VerticalInsets) {
|
||||
verticalInsetOverride = insets
|
||||
|
||||
if (this.insets != null) {
|
||||
@@ -138,14 +138,6 @@ open class InsetAwareConstraintLayout @JvmOverloads constructor(
|
||||
}
|
||||
}
|
||||
|
||||
fun clearVerticalInsetOverride() {
|
||||
verticalInsetOverride = InsetsViewModel.Insets.Zero
|
||||
|
||||
if (this.insets != null) {
|
||||
applyInsets(this.insets!!.getInsets(windowTypes), this.insets!!.getInsets(keyboardType))
|
||||
}
|
||||
}
|
||||
|
||||
fun addKeyboardStateListener(listener: KeyboardStateListener) {
|
||||
keyboardStateListeners += listener
|
||||
}
|
||||
@@ -165,8 +157,8 @@ open class InsetAwareConstraintLayout @JvmOverloads constructor(
|
||||
private fun applyInsets(windowInsets: Insets, keyboardInsets: Insets) {
|
||||
val isLtr = ViewUtil.isLtr(this)
|
||||
|
||||
val statusBar = if (verticalInsetOverride == InsetsViewModel.Insets.Zero) windowInsets.top else verticalInsetOverride.statusBar.roundToInt()
|
||||
val navigationBar = if (verticalInsetOverride == InsetsViewModel.Insets.Zero) windowInsets.bottom else verticalInsetOverride.navBar.roundToInt()
|
||||
val statusBar = if (verticalInsetOverride == VerticalInsets.Zero) windowInsets.top else verticalInsetOverride.statusBar.roundToInt()
|
||||
val navigationBar = if (verticalInsetOverride == VerticalInsets.Zero) windowInsets.bottom else verticalInsetOverride.navBar.roundToInt()
|
||||
val parentStart = if (isLtr) windowInsets.left else windowInsets.right
|
||||
val parentEnd = if (isLtr) windowInsets.right else windowInsets.left
|
||||
|
||||
|
||||
@@ -258,8 +258,8 @@ import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.linkpreview.LinkPreview
|
||||
import org.thoughtcrime.securesms.linkpreview.LinkPreviewViewModelV2
|
||||
import org.thoughtcrime.securesms.longmessage.LongMessageFragment
|
||||
import org.thoughtcrime.securesms.main.InsetsViewModel
|
||||
import org.thoughtcrime.securesms.main.MainNavigationListLocation
|
||||
import org.thoughtcrime.securesms.main.VerticalInsets
|
||||
import org.thoughtcrime.securesms.mediaoverview.MediaOverviewActivity
|
||||
import org.thoughtcrime.securesms.mediapreview.MediaIntentFactory
|
||||
import org.thoughtcrime.securesms.mediapreview.MediaPreviewV2Activity
|
||||
@@ -490,8 +490,6 @@ class ConversationFragment :
|
||||
|
||||
private val shareDataTimestampViewModel: ShareDataTimestampViewModel by activityViewModels()
|
||||
|
||||
private val insetsViewModel: InsetsViewModel by activityViewModels()
|
||||
|
||||
private val inlineQueryController: InlineQueryResultsControllerV2 by lazy {
|
||||
InlineQueryResultsControllerV2(
|
||||
this,
|
||||
@@ -601,22 +599,13 @@ class ConversationFragment :
|
||||
SignalLocalMetrics.ConversationOpen.start()
|
||||
}
|
||||
|
||||
fun applyRootInsets(insets: VerticalInsets) {
|
||||
binding.root.applyInsets(insets)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
binding.toolbar.isBackInvokedCallbackEnabled = false
|
||||
|
||||
if (WindowSizeClass.isLargeScreenSupportEnabled()) {
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||
binding.root.clearVerticalInsetOverride()
|
||||
if (!resources.getWindowSizeClass().isSplitPane()) {
|
||||
insetsViewModel.insets.collect {
|
||||
binding.root.applyInsets(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
binding.root.setApplyRootInsets(!WindowSizeClass.isLargeScreenSupportEnabled())
|
||||
binding.root.setUseWindowTypes(!WindowSizeClass.isLargeScreenSupportEnabled())
|
||||
|
||||
|
||||
@@ -6,14 +6,22 @@
|
||||
package org.thoughtcrime.securesms.main
|
||||
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.key
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.runtime.snapshotFlow
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.fragment.compose.AndroidFragment
|
||||
import androidx.fragment.compose.rememberFragmentState
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import androidx.navigation.NavGraphBuilder
|
||||
import androidx.navigation.compose.composable
|
||||
import androidx.navigation.toRoute
|
||||
import kotlinx.coroutines.launch
|
||||
import org.thoughtcrime.securesms.conversation.ConversationArgs
|
||||
import org.thoughtcrime.securesms.conversation.ConversationIntents
|
||||
import org.thoughtcrime.securesms.conversation.v2.ConversationFragment
|
||||
@@ -29,10 +37,12 @@ fun NavGraphBuilder.chatNavGraphBuilder() {
|
||||
typeMap = mapOf(
|
||||
typeOf<ConversationArgs>() to JsonSerializableNavType(ConversationArgs.serializer())
|
||||
)
|
||||
) {
|
||||
val route = it.toRoute<MainNavigationDetailLocation.Chats.Conversation>()
|
||||
) { navBackStackEntry ->
|
||||
val route = navBackStackEntry.toRoute<MainNavigationDetailLocation.Chats.Conversation>()
|
||||
val fragmentState = key(route) { rememberFragmentState() }
|
||||
val context = LocalContext.current
|
||||
val insets by rememberVerticalInsets()
|
||||
val insetFlow = remember { snapshotFlow { insets } }
|
||||
|
||||
AndroidFragment(
|
||||
clazz = ConversationFragment::class.java,
|
||||
@@ -40,6 +50,14 @@ fun NavGraphBuilder.chatNavGraphBuilder() {
|
||||
arguments = requireNotNull(ConversationIntents.createBuilderSync(context, route.conversationArgs).build().extras) { "Handed null Conversation intent arguments." },
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
)
|
||||
) { fragment ->
|
||||
fragment.viewLifecycleOwner.lifecycleScope.launch {
|
||||
fragment.repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
insetFlow.collect {
|
||||
fragment.applyRootInsets(insets)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,38 +12,24 @@ import androidx.compose.foundation.layout.asPaddingValues
|
||||
import androidx.compose.foundation.layout.navigationBars
|
||||
import androidx.compose.foundation.layout.statusBars
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.SideEffect
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.unit.Density
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import org.thoughtcrime.securesms.window.WindowSizeClass
|
||||
|
||||
class InsetsViewModel : ViewModel() {
|
||||
private val internalInsets = MutableStateFlow(Insets.Zero)
|
||||
val insets: StateFlow<Insets> = internalInsets
|
||||
|
||||
fun updateInsets(insets: Insets) {
|
||||
internalInsets.update { insets }
|
||||
}
|
||||
|
||||
data class Insets(
|
||||
@param:Px val statusBar: Float,
|
||||
@param:Px val navBar: Float
|
||||
) {
|
||||
companion object {
|
||||
val Zero = Insets(0f, 0f)
|
||||
}
|
||||
data class VerticalInsets(
|
||||
@param:Px val statusBar: Float,
|
||||
@param:Px val navBar: Float
|
||||
) {
|
||||
companion object {
|
||||
val Zero = VerticalInsets(0f, 0f)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun InsetsViewModelUpdater(
|
||||
insetsViewModel: InsetsViewModel = viewModel { InsetsViewModel() }
|
||||
) {
|
||||
fun rememberVerticalInsets(): State<VerticalInsets> {
|
||||
val statusBarInsets = WindowInsets.statusBars
|
||||
val navigationBarInsets = WindowInsets.navigationBars
|
||||
|
||||
@@ -51,35 +37,27 @@ fun InsetsViewModelUpdater(
|
||||
val navigationBarPadding = navigationBarInsets.asPaddingValues()
|
||||
val density = LocalDensity.current
|
||||
|
||||
LaunchedEffect(
|
||||
statusBarPadding,
|
||||
navigationBarPadding,
|
||||
density
|
||||
) {
|
||||
calculateAndUpdateInsets(
|
||||
density,
|
||||
insetsViewModel,
|
||||
statusBarPadding,
|
||||
navigationBarPadding
|
||||
)
|
||||
val windowSizeClass = WindowSizeClass.rememberWindowSizeClass()
|
||||
|
||||
val insets = remember { mutableStateOf(VerticalInsets.Zero) }
|
||||
val updated = remember(statusBarInsets, navigationBarInsets, windowSizeClass) {
|
||||
insets.value = if (windowSizeClass.isSplitPane()) {
|
||||
VerticalInsets.Zero
|
||||
} else {
|
||||
calculateAndUpdateInsets(density, statusBarPadding, navigationBarPadding)
|
||||
}
|
||||
|
||||
0
|
||||
}
|
||||
|
||||
SideEffect {
|
||||
calculateAndUpdateInsets(
|
||||
density,
|
||||
insetsViewModel,
|
||||
statusBarPadding,
|
||||
navigationBarPadding
|
||||
)
|
||||
}
|
||||
return insets
|
||||
}
|
||||
|
||||
private fun calculateAndUpdateInsets(
|
||||
density: Density,
|
||||
insetsViewModel: InsetsViewModel,
|
||||
statusBarPadding: PaddingValues,
|
||||
navigationBarPadding: PaddingValues
|
||||
) {
|
||||
): VerticalInsets {
|
||||
val statusBarPx = with(density) {
|
||||
(statusBarPadding.calculateTopPadding() + statusBarPadding.calculateBottomPadding()).toPx()
|
||||
}
|
||||
@@ -88,10 +66,8 @@ private fun calculateAndUpdateInsets(
|
||||
(navigationBarPadding.calculateTopPadding() + navigationBarPadding.calculateBottomPadding()).toPx()
|
||||
}
|
||||
|
||||
insetsViewModel.updateInsets(
|
||||
InsetsViewModel.Insets(
|
||||
statusBar = statusBarPx,
|
||||
navBar = navBarPx
|
||||
)
|
||||
return VerticalInsets(
|
||||
statusBar = statusBarPx,
|
||||
navBar = navBarPx
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user