mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-24 04:58:45 +00:00
Remove custom WindowSizeClass and just depend on Material Adaptive WindowSizeClass.
Co-authored-by: jeffrey-signal <jeffrey@signal.org>
This commit is contained in:
committed by
jeffrey-signal
parent
95c9776b4d
commit
109f651681
@@ -37,6 +37,7 @@ import androidx.compose.foundation.layout.systemBarsPadding
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.SnackbarDuration
|
||||
import androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi
|
||||
import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo
|
||||
import androidx.compose.material3.adaptive.layout.PaneExpansionAnchor
|
||||
import androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole
|
||||
import androidx.compose.material3.adaptive.layout.rememberPaneExpansionState
|
||||
@@ -62,6 +63,8 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.window.core.layout.WindowSizeClass
|
||||
import androidx.window.core.layout.WindowWidthSizeClass
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
@@ -163,7 +166,8 @@ import org.thoughtcrime.securesms.window.AppPaneDragHandle
|
||||
import org.thoughtcrime.securesms.window.AppScaffold
|
||||
import org.thoughtcrime.securesms.window.AppScaffoldAnimationStateFactory
|
||||
import org.thoughtcrime.securesms.window.AppScaffoldNavigator
|
||||
import org.thoughtcrime.securesms.window.WindowSizeClass
|
||||
import org.thoughtcrime.securesms.window.Navigation
|
||||
import org.thoughtcrime.securesms.window.isSplitPane
|
||||
import org.thoughtcrime.securesms.window.rememberThreePaneScaffoldNavigatorDelegate
|
||||
import org.whispersystems.signalservice.api.websocket.WebSocketConnectionState
|
||||
|
||||
@@ -339,17 +343,23 @@ class MainActivity : PassphraseRequiredActivity(), VoiceNoteMediaControllerOwner
|
||||
)
|
||||
}
|
||||
|
||||
val windowSizeClass = WindowSizeClass.rememberWindowSizeClass()
|
||||
val windowSizeClass = currentWindowAdaptiveInfo().windowSizeClass
|
||||
val contentLayoutData = MainContentLayoutData.rememberContentLayoutData(mainToolbarState.mode)
|
||||
|
||||
MainContainer {
|
||||
val wrappedNavigator = rememberNavigator(windowSizeClass, contentLayoutData, maxWidth)
|
||||
val listPaneWidth = contentLayoutData.rememberDefaultPanePreferredWidth(maxWidth)
|
||||
val navigation = Navigation.rememberNavigation()
|
||||
|
||||
val anchors = remember(contentLayoutData, mainToolbarState) {
|
||||
val halfPartitionWidth = contentLayoutData.partitionWidth / 2
|
||||
|
||||
val detailOffset = if (mainToolbarState.mode == MainToolbarMode.SEARCH) 0.dp else 80.dp
|
||||
val detailOffset = when {
|
||||
mainToolbarState.mode == MainToolbarMode.SEARCH -> 0.dp
|
||||
navigation == Navigation.BAR -> 0.dp
|
||||
else -> 80.dp
|
||||
}
|
||||
|
||||
val detailOnlyAnchor = PaneExpansionAnchor.Offset.fromStart(detailOffset + contentLayoutData.listPaddingStart + halfPartitionWidth)
|
||||
val detailAndListAnchor = PaneExpansionAnchor.Offset.fromStart(listPaneWidth + halfPartitionWidth)
|
||||
val listOnlyAnchor = PaneExpansionAnchor.Offset.fromEnd(contentLayoutData.detailPaddingEnd - halfPartitionWidth)
|
||||
@@ -519,7 +529,7 @@ class MainActivity : PassphraseRequiredActivity(), VoiceNoteMediaControllerOwner
|
||||
}
|
||||
},
|
||||
secondaryContent = {
|
||||
val listContainerColor = if (windowSizeClass.isMedium()) {
|
||||
val listContainerColor = if (windowSizeClass.isSplitPane() && windowSizeClass.windowWidthSizeClass == WindowWidthSizeClass.MEDIUM) {
|
||||
SignalTheme.colors.colorSurface1
|
||||
} else {
|
||||
MaterialTheme.colorScheme.surface
|
||||
@@ -699,10 +709,10 @@ class MainActivity : PassphraseRequiredActivity(), VoiceNoteMediaControllerOwner
|
||||
|
||||
@Composable
|
||||
private fun MainContainer(content: @Composable BoxWithConstraintsScope.() -> Unit) {
|
||||
val windowSizeClass = WindowSizeClass.rememberWindowSizeClass()
|
||||
val windowSizeClass = currentWindowAdaptiveInfo().windowSizeClass
|
||||
|
||||
SignalTheme(isDarkMode = DynamicTheme.isDarkTheme(this)) {
|
||||
val backgroundColor = if (windowSizeClass.isCompact()) {
|
||||
val backgroundColor = if (!windowSizeClass.isSplitPane()) {
|
||||
MaterialTheme.colorScheme.surface
|
||||
} else {
|
||||
SignalTheme.colors.colorSurface1
|
||||
|
||||
@@ -16,6 +16,7 @@ import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextField
|
||||
import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
@@ -47,7 +48,7 @@ import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.calls.links.details.CallLinkDetailsViewModel
|
||||
import org.thoughtcrime.securesms.compose.ComposeDialogFragment
|
||||
import org.thoughtcrime.securesms.service.webrtc.links.CallLinkRoomId
|
||||
import org.thoughtcrime.securesms.window.WindowSizeClass
|
||||
import org.thoughtcrime.securesms.window.isSplitPane
|
||||
|
||||
class EditCallLinkNameDialogFragment : ComposeDialogFragment() {
|
||||
|
||||
@@ -109,7 +110,7 @@ fun EditCallLinkNameScreen(
|
||||
onNavigationClick = {
|
||||
backPressedDispatcherOwner?.onBackPressedDispatcher?.onBackPressed()
|
||||
},
|
||||
showNavigationIcon = !WindowSizeClass.rememberWindowSizeClass().isSplitPane()
|
||||
showNavigationIcon = !currentWindowAdaptiveInfo().windowSizeClass.isSplitPane()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
@@ -55,7 +56,7 @@ import org.thoughtcrime.securesms.service.webrtc.links.SignalCallLinkState
|
||||
import org.thoughtcrime.securesms.sharing.v2.ShareActivity
|
||||
import org.thoughtcrime.securesms.util.CommunicationActions
|
||||
import org.thoughtcrime.securesms.util.Util
|
||||
import org.thoughtcrime.securesms.window.WindowSizeClass
|
||||
import org.thoughtcrime.securesms.window.isSplitPane
|
||||
import java.time.Instant
|
||||
|
||||
@Composable
|
||||
@@ -84,7 +85,7 @@ fun CallLinkDetailsScreen(
|
||||
state = state,
|
||||
showAlreadyInACall = showAlreadyInACall,
|
||||
callback = callback,
|
||||
showNavigationIcon = !WindowSizeClass.rememberWindowSizeClass().isSplitPane()
|
||||
showNavigationIcon = !currentWindowAdaptiveInfo().windowSizeClass.isSplitPane()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -61,7 +61,8 @@ import org.thoughtcrime.securesms.util.ViewUtil
|
||||
import org.thoughtcrime.securesms.util.doAfterNextLayout
|
||||
import org.thoughtcrime.securesms.util.fragments.requireListener
|
||||
import org.thoughtcrime.securesms.util.visible
|
||||
import org.thoughtcrime.securesms.window.WindowSizeClass.Companion.getWindowSizeClass
|
||||
import org.thoughtcrime.securesms.window.getWindowSizeClass
|
||||
import org.thoughtcrime.securesms.window.isSplitPane
|
||||
import java.util.Objects
|
||||
|
||||
/**
|
||||
@@ -184,7 +185,7 @@ class CallLogFragment : Fragment(R.layout.call_log_fragment), CallLogAdapter.Cal
|
||||
}
|
||||
}
|
||||
|
||||
if (resources.getWindowSizeClass().isCompact()) {
|
||||
if (!resources.getWindowSizeClass().isSplitPane()) {
|
||||
ViewUtil.setBottomMargin(binding.bottomActionBar, ViewUtil.getNavigationBarHeight(binding.bottomActionBar))
|
||||
}
|
||||
|
||||
|
||||
@@ -19,8 +19,9 @@ import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.util.ThemeUtil
|
||||
import org.thoughtcrime.securesms.util.ViewUtil
|
||||
import org.thoughtcrime.securesms.util.WindowUtil
|
||||
import org.thoughtcrime.securesms.window.WindowSizeClass
|
||||
import org.thoughtcrime.securesms.window.WindowSizeClass.Companion.getWindowSizeClass
|
||||
import org.thoughtcrime.securesms.window.getWindowSizeClass
|
||||
import org.thoughtcrime.securesms.window.isLargeScreenSupportEnabled
|
||||
import org.thoughtcrime.securesms.window.isSplitPane
|
||||
import com.google.android.material.R as MaterialR
|
||||
|
||||
/**
|
||||
@@ -32,7 +33,7 @@ abstract class FixedRoundedCornerBottomSheetDialogFragment : BottomSheetDialogFr
|
||||
* Sheet corner radius in DP
|
||||
*/
|
||||
protected val cornerRadius: Int by lazy {
|
||||
if (WindowSizeClass.isLargeScreenSupportEnabled() && resources.getWindowSizeClass().isSplitPane()) {
|
||||
if (isLargeScreenSupportEnabled() && resources.getWindowSizeClass().isSplitPane()) {
|
||||
32
|
||||
} else {
|
||||
18
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.thoughtcrime.securesms.components
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
@@ -15,7 +16,6 @@ import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.main.VerticalInsets
|
||||
import org.thoughtcrime.securesms.util.ViewUtil
|
||||
import org.thoughtcrime.securesms.window.WindowSizeClass.Companion.getWindowSizeClass
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
/**
|
||||
@@ -241,7 +241,7 @@ open class InsetAwareConstraintLayout @JvmOverloads constructor(
|
||||
}
|
||||
|
||||
private fun isLandscape(): Boolean {
|
||||
return resources.getWindowSizeClass().isLandscape()
|
||||
return resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
|
||||
}
|
||||
|
||||
private val Guideline?.guidelineEnd: Int
|
||||
|
||||
@@ -8,10 +8,12 @@ package org.thoughtcrime.securesms.components.compose
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import org.thoughtcrime.securesms.window.WindowSizeClass
|
||||
import androidx.window.core.layout.WindowWidthSizeClass
|
||||
import org.thoughtcrime.securesms.window.isAtLeast
|
||||
|
||||
/**
|
||||
* Displays the screen title for split-pane UIs on tablets and foldable devices.
|
||||
@@ -21,7 +23,7 @@ fun ScreenTitlePane(
|
||||
title: String,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
val windowSizeClass = WindowSizeClass.rememberWindowSizeClass()
|
||||
val windowSizeClass = currentWindowAdaptiveInfo().windowSizeClass
|
||||
|
||||
Text(
|
||||
text = title,
|
||||
@@ -29,7 +31,7 @@ fun ScreenTitlePane(
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
modifier = modifier
|
||||
.padding(
|
||||
start = if (windowSizeClass.isExtended()) 80.dp else 20.dp,
|
||||
start = if (windowSizeClass.windowWidthSizeClass.isAtLeast(WindowWidthSizeClass.EXPANDED)) 80.dp else 20.dp,
|
||||
end = 20.dp,
|
||||
bottom = 12.dp
|
||||
)
|
||||
|
||||
@@ -185,11 +185,11 @@ class InternalSettingsFragment : DSLSettingsFragment(R.string.preferences__inter
|
||||
|
||||
switchPref(
|
||||
isEnabled = state.largeScreenUi,
|
||||
title = DSLSettingsText.from("Force split pane UI on landscape phones."),
|
||||
title = DSLSettingsText.from("Force split pane UI on phones."),
|
||||
summary = DSLSettingsText.from("This setting requires split pane UI to be enabled."),
|
||||
isChecked = state.forceSplitPaneOnCompactLandscape,
|
||||
isChecked = state.forceSplitPane,
|
||||
onClick = {
|
||||
viewModel.setForceSplitPaneOnCompactLandscape(!state.forceSplitPaneOnCompactLandscape)
|
||||
viewModel.setForceSplitPane(!state.forceSplitPane)
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -32,5 +32,5 @@ data class InternalSettingsState(
|
||||
val hevcEncoding: Boolean,
|
||||
val newCallingUi: Boolean,
|
||||
val largeScreenUi: Boolean,
|
||||
val forceSplitPaneOnCompactLandscape: Boolean
|
||||
val forceSplitPane: Boolean
|
||||
)
|
||||
|
||||
@@ -198,7 +198,7 @@ class InternalSettingsViewModel(private val repository: InternalSettingsReposito
|
||||
hevcEncoding = SignalStore.internal.hevcEncoding,
|
||||
newCallingUi = SignalStore.internal.newCallingUi,
|
||||
largeScreenUi = SignalStore.internal.largeScreenUi,
|
||||
forceSplitPaneOnCompactLandscape = SignalStore.internal.forceSplitPaneOnCompactLandscape
|
||||
forceSplitPane = SignalStore.internal.forceSplitPane
|
||||
)
|
||||
|
||||
fun onClearOnboardingState() {
|
||||
@@ -219,8 +219,8 @@ class InternalSettingsViewModel(private val repository: InternalSettingsReposito
|
||||
refresh()
|
||||
}
|
||||
|
||||
fun setForceSplitPaneOnCompactLandscape(forceSplitPaneOnCompactLandscape: Boolean) {
|
||||
SignalStore.internal.forceSplitPaneOnCompactLandscape = forceSplitPaneOnCompactLandscape
|
||||
fun setForceSplitPane(forceSplitPane: Boolean) {
|
||||
SignalStore.internal.forceSplitPane = forceSplitPane
|
||||
refresh()
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.SheetValue
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
@@ -63,6 +64,8 @@ import androidx.compose.ui.tooling.preview.Devices
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.DpSize
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.window.core.layout.WindowHeightSizeClass
|
||||
import androidx.window.core.layout.WindowWidthSizeClass
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import org.signal.core.ui.compose.BottomSheets
|
||||
@@ -76,7 +79,6 @@ import org.thoughtcrime.securesms.events.CallParticipant
|
||||
import org.thoughtcrime.securesms.events.GroupCallReactionEvent
|
||||
import org.thoughtcrime.securesms.events.WebRtcViewModel
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.window.WindowSizeClass
|
||||
import kotlin.math.max
|
||||
import kotlin.math.round
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
@@ -484,7 +486,7 @@ private fun TinyLocalVideoRenderer(
|
||||
|
||||
if (LocalInspectionMode.current) {
|
||||
Text(
|
||||
"Test ${WindowSizeClass.rememberWindowSizeClass()}",
|
||||
"Test ${currentWindowAdaptiveInfo().windowSizeClass}",
|
||||
modifier = modifier
|
||||
.padding(padding)
|
||||
.height(height)
|
||||
@@ -553,27 +555,28 @@ private fun SmallMoveableLocalVideoRenderer(
|
||||
@Composable
|
||||
private fun rememberTinyPortraitSize(): SelfPictureInPictureDimensions {
|
||||
val smallWidth = dimensionResource(R.dimen.call_screen_overflow_item_size)
|
||||
val windowClass = WindowSizeClass.rememberWindowSizeClass()
|
||||
val windowSizeClass = currentWindowAdaptiveInfo().windowSizeClass
|
||||
val isLandscape = LocalConfiguration.current.orientation == Configuration.ORIENTATION_LANDSCAPE
|
||||
|
||||
val smallSize = when (windowClass) {
|
||||
WindowSizeClass.COMPACT_PORTRAIT -> DpSize(40.dp, smallWidth)
|
||||
WindowSizeClass.COMPACT_LANDSCAPE -> DpSize(smallWidth, 40.dp)
|
||||
WindowSizeClass.EXTENDED_PORTRAIT, WindowSizeClass.EXTENDED_LANDSCAPE -> DpSize(124.dp, 217.dp)
|
||||
val smallSize = when {
|
||||
windowSizeClass.windowWidthSizeClass == WindowWidthSizeClass.COMPACT && !isLandscape -> DpSize(40.dp, smallWidth)
|
||||
windowSizeClass.windowHeightSizeClass == WindowHeightSizeClass.COMPACT && isLandscape -> DpSize(smallWidth, 40.dp)
|
||||
windowSizeClass.windowWidthSizeClass == WindowWidthSizeClass.EXPANDED -> DpSize(124.dp, 217.dp)
|
||||
else -> DpSize(smallWidth, smallWidth)
|
||||
}
|
||||
|
||||
val expandedSize = when (windowClass) {
|
||||
WindowSizeClass.COMPACT_PORTRAIT -> DpSize(180.dp, 320.dp)
|
||||
WindowSizeClass.COMPACT_LANDSCAPE -> DpSize(320.dp, 180.dp)
|
||||
val expandedSize = when {
|
||||
windowSizeClass.windowWidthSizeClass == WindowWidthSizeClass.COMPACT && !isLandscape -> DpSize(180.dp, 320.dp)
|
||||
windowSizeClass.windowHeightSizeClass == WindowHeightSizeClass.COMPACT && isLandscape -> DpSize(320.dp, 180.dp)
|
||||
else -> DpSize(smallWidth, smallWidth)
|
||||
}
|
||||
|
||||
val padding = when (windowClass) {
|
||||
WindowSizeClass.COMPACT_PORTRAIT -> PaddingValues(vertical = 16.dp)
|
||||
val padding = when {
|
||||
windowSizeClass.windowWidthSizeClass == WindowWidthSizeClass.COMPACT && !isLandscape -> PaddingValues(vertical = 16.dp)
|
||||
else -> PaddingValues(16.dp)
|
||||
}
|
||||
|
||||
return remember(windowClass) {
|
||||
return remember(windowSizeClass) {
|
||||
SelfPictureInPictureDimensions(smallSize, expandedSize, padding)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import androidx.compose.material3.SnackbarHost
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi
|
||||
import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
@@ -64,7 +65,8 @@ import org.thoughtcrime.securesms.recipients.ui.findby.FindByActivity
|
||||
import org.thoughtcrime.securesms.recipients.ui.findby.FindByMode
|
||||
import org.thoughtcrime.securesms.util.CommunicationActions
|
||||
import org.thoughtcrime.securesms.window.AppScaffold
|
||||
import org.thoughtcrime.securesms.window.WindowSizeClass
|
||||
import org.thoughtcrime.securesms.window.detailPaneMaxContentWidth
|
||||
import org.thoughtcrime.securesms.window.isSplitPane
|
||||
import org.thoughtcrime.securesms.window.rememberAppScaffoldNavigator
|
||||
|
||||
/**
|
||||
@@ -200,8 +202,8 @@ private fun NewConversationScreenUi(
|
||||
uiState: NewConversationUiState,
|
||||
callbacks: UiCallbacks
|
||||
) {
|
||||
val windowSizeClass = WindowSizeClass.rememberWindowSizeClass()
|
||||
val isSplitPane = windowSizeClass.isSplitPane(forceSplitPaneOnCompactLandscape = uiState.forceSplitPaneOnCompactLandscape)
|
||||
val windowSizeClass = currentWindowAdaptiveInfo().windowSizeClass
|
||||
val isSplitPane = windowSizeClass.isSplitPane(forceSplitPane = uiState.forceSplitPaneOnCompactLandscape)
|
||||
val snackbarHostState = remember { SnackbarHostState() }
|
||||
|
||||
AppScaffold(
|
||||
|
||||
@@ -161,7 +161,7 @@ class NewConversationViewModel : ViewModel() {
|
||||
}
|
||||
|
||||
data class NewConversationUiState(
|
||||
val forceSplitPaneOnCompactLandscape: Boolean = SignalStore.internal.forceSplitPaneOnCompactLandscape,
|
||||
val forceSplitPaneOnCompactLandscape: Boolean = SignalStore.internal.forceSplitPane,
|
||||
val searchQuery: String = "",
|
||||
val isLookingUpRecipient: Boolean = false,
|
||||
val isRefreshingContacts: Boolean = false,
|
||||
|
||||
@@ -6,6 +6,8 @@ import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.commit
|
||||
import androidx.lifecycle.DefaultLifecycleObserver
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.window.core.layout.WindowHeightSizeClass
|
||||
import androidx.window.core.layout.WindowSizeClass
|
||||
import io.reactivex.rxjava3.kotlin.subscribeBy
|
||||
import org.signal.core.util.DimensionUnit
|
||||
import org.signal.core.util.concurrent.LifecycleDisposable
|
||||
@@ -15,7 +17,6 @@ import org.thoughtcrime.securesms.components.ComposeText
|
||||
import org.thoughtcrime.securesms.conversation.ui.mentions.MentionsPickerFragmentV2
|
||||
import org.thoughtcrime.securesms.util.adapter.mapping.AnyMappingModel
|
||||
import org.thoughtcrime.securesms.util.doOnEachLayout
|
||||
import org.thoughtcrime.securesms.window.WindowSizeClass
|
||||
|
||||
/**
|
||||
* Controller for inline search results.
|
||||
@@ -71,7 +72,7 @@ class InlineQueryResultsControllerV2(
|
||||
}
|
||||
|
||||
fun onWindowSizeClassChanged(windowSizeClass: WindowSizeClass) {
|
||||
this.shouldHideForWindowSizeClass = windowSizeClass == WindowSizeClass.COMPACT_LANDSCAPE
|
||||
this.shouldHideForWindowSizeClass = windowSizeClass.windowHeightSizeClass == WindowHeightSizeClass.COMPACT
|
||||
|
||||
if (shouldHideForWindowSizeClass) {
|
||||
dismiss()
|
||||
|
||||
@@ -24,7 +24,7 @@ import org.thoughtcrime.securesms.jobs.ConversationShortcutUpdateJob
|
||||
import org.thoughtcrime.securesms.util.ConfigurationUtil
|
||||
import org.thoughtcrime.securesms.util.Debouncer
|
||||
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme
|
||||
import org.thoughtcrime.securesms.window.WindowSizeClass
|
||||
import org.thoughtcrime.securesms.window.isLargeScreenSupportEnabled
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
/**
|
||||
@@ -54,7 +54,7 @@ open class ConversationActivity : PassphraseRequiredActivity(), VoiceNoteMediaCo
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?, ready: Boolean) {
|
||||
if (!ActivityCompat.isLaunchedFromBubble(this) && WindowSizeClass.isLargeScreenSupportEnabled()) {
|
||||
if (!ActivityCompat.isLaunchedFromBubble(this) && isLargeScreenSupportEnabled()) {
|
||||
startActivity(
|
||||
MainActivity.clearTop(this).apply {
|
||||
action = ConversationIntents.ACTION
|
||||
|
||||
@@ -361,8 +361,9 @@ import org.thoughtcrime.securesms.util.visible
|
||||
import org.thoughtcrime.securesms.verify.VerifyIdentityActivity
|
||||
import org.thoughtcrime.securesms.wallpaper.ChatWallpaper
|
||||
import org.thoughtcrime.securesms.wallpaper.ChatWallpaperDimLevelUtil
|
||||
import org.thoughtcrime.securesms.window.WindowSizeClass
|
||||
import org.thoughtcrime.securesms.window.WindowSizeClass.Companion.getWindowSizeClass
|
||||
import org.thoughtcrime.securesms.window.getWindowSizeClass
|
||||
import org.thoughtcrime.securesms.window.isLargeScreenSupportEnabled
|
||||
import org.thoughtcrime.securesms.window.isSplitPane
|
||||
import java.time.Instant
|
||||
import java.time.LocalDateTime
|
||||
import java.time.ZoneId
|
||||
@@ -615,8 +616,8 @@ class ConversationFragment :
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
binding.toolbar.isBackInvokedCallbackEnabled = false
|
||||
|
||||
binding.root.setApplyRootInsets(!WindowSizeClass.isLargeScreenSupportEnabled())
|
||||
binding.root.setUseWindowTypes(!WindowSizeClass.isLargeScreenSupportEnabled())
|
||||
binding.root.setApplyRootInsets(!isLargeScreenSupportEnabled())
|
||||
binding.root.setUseWindowTypes(!isLargeScreenSupportEnabled())
|
||||
|
||||
disposables.bindTo(viewLifecycleOwner)
|
||||
|
||||
@@ -699,7 +700,7 @@ class ConversationFragment :
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
|
||||
if (!WindowSizeClass.isLargeScreenSupportEnabled()) {
|
||||
if (!isLargeScreenSupportEnabled()) {
|
||||
WindowUtil.setLightNavigationBarFromTheme(requireActivity())
|
||||
WindowUtil.setLightStatusBarFromTheme(requireActivity())
|
||||
}
|
||||
@@ -1455,7 +1456,7 @@ class ConversationFragment :
|
||||
}
|
||||
|
||||
private fun presentNavigationIconForNormal() {
|
||||
if (WindowSizeClass.isLargeScreenSupportEnabled()) {
|
||||
if (isLargeScreenSupportEnabled()) {
|
||||
lifecycleScope.launch {
|
||||
repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||
mainNavigationViewModel.isFullScreenPane.collect { isFullScreenPane ->
|
||||
@@ -3483,7 +3484,7 @@ class ConversationFragment :
|
||||
getVoiceNoteMediaController().resumePlayback(selectedConversationModel.audioUri, messageRecord.id)
|
||||
}
|
||||
|
||||
if (!WindowSizeClass.isLargeScreenSupportEnabled()) {
|
||||
if (!isLargeScreenSupportEnabled()) {
|
||||
WindowUtil.setLightStatusBarFromTheme(requireActivity())
|
||||
WindowUtil.setLightNavigationBarFromTheme(requireActivity())
|
||||
}
|
||||
|
||||
@@ -53,6 +53,7 @@ import androidx.recyclerview.widget.ItemTouchHelper;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.LinearSmoothScroller;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.window.core.layout.WindowHeightSizeClass;
|
||||
|
||||
import com.airbnb.lottie.SimpleColorFilter;
|
||||
import com.annimon.stream.Stream;
|
||||
@@ -159,7 +160,6 @@ import org.thoughtcrime.securesms.util.adapter.mapping.PagingMappingAdapter;
|
||||
import org.thoughtcrime.securesms.util.views.SimpleProgressDialog;
|
||||
import org.thoughtcrime.securesms.util.views.Stub;
|
||||
import org.thoughtcrime.securesms.wallpaper.ChatWallpaper;
|
||||
import org.thoughtcrime.securesms.window.WindowSizeClass;
|
||||
import org.whispersystems.signalservice.api.websocket.WebSocketConnectionState;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
@@ -179,6 +179,9 @@ import io.reactivex.rxjava3.core.Single;
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||
import kotlin.Unit;
|
||||
|
||||
import static org.thoughtcrime.securesms.window.WindowSizeClassExtensionsKt.getWindowSizeClass;
|
||||
import static org.thoughtcrime.securesms.window.WindowSizeClassExtensionsKt.isSplitPane;
|
||||
|
||||
|
||||
public class ConversationListFragment extends MainFragment implements ConversationListAdapter.OnConversationClickListener,
|
||||
ClearFilterViewHolder.OnClearFilterClickListener,
|
||||
@@ -311,7 +314,7 @@ public class ConversationListFragment extends MainFragment implements Conversati
|
||||
|
||||
searchAdapter = contactSearchMediator.getAdapter();
|
||||
|
||||
if (WindowSizeClass.Companion.getWindowSizeClass(getResources()).isCompact()) {
|
||||
if (getWindowSizeClass(getResources()).getWindowHeightSizeClass() == WindowHeightSizeClass.COMPACT) {
|
||||
ViewUtil.setBottomMargin(bottomActionBar, ViewUtil.getNavigationBarHeight(bottomActionBar));
|
||||
}
|
||||
|
||||
@@ -411,7 +414,7 @@ public class ConversationListFragment extends MainFragment implements Conversati
|
||||
}
|
||||
}));
|
||||
|
||||
if (WindowSizeClass.Companion.getWindowSizeClass(getResources()).isSplitPane()) {
|
||||
if (isSplitPane(getWindowSizeClass(getResources()))) {
|
||||
lifecycleDisposable.add(mainNavigationViewModel.getObservableActiveChatThreadId()
|
||||
.subscribeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(defaultAdapter::setActiveThreadId));
|
||||
|
||||
@@ -16,7 +16,8 @@ import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.launch
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.thoughtcrime.securesms.main.MainNavigationDetailLocation
|
||||
import org.thoughtcrime.securesms.window.WindowSizeClass.Companion.getWindowSizeClass
|
||||
import org.thoughtcrime.securesms.window.getWindowSizeClass
|
||||
import org.thoughtcrime.securesms.window.isSplitPane
|
||||
|
||||
/**
|
||||
* When the user searches for a conversation and then enters a message, we should clear
|
||||
@@ -35,7 +36,7 @@ fun Fragment.listenToEventBusWhileResumed(
|
||||
detailLocation
|
||||
.flowWithLifecycle(viewLifecycleOwner.lifecycle, Lifecycle.State.RESUMED)
|
||||
.collectLatest {
|
||||
if (resources.getWindowSizeClass().isCompact()) {
|
||||
if (!resources.getWindowSizeClass().isSplitPane()) {
|
||||
when (it) {
|
||||
is MainNavigationDetailLocation.Chats.Conversation -> unsubscribe()
|
||||
MainNavigationDetailLocation.Empty -> subscribe()
|
||||
|
||||
@@ -33,6 +33,7 @@ import androidx.compose.material3.SnackbarHost
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi
|
||||
import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
@@ -68,7 +69,8 @@ import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
import org.thoughtcrime.securesms.recipients.ui.findby.FindByActivity
|
||||
import org.thoughtcrime.securesms.recipients.ui.findby.FindByMode
|
||||
import org.thoughtcrime.securesms.window.AppScaffold
|
||||
import org.thoughtcrime.securesms.window.WindowSizeClass
|
||||
import org.thoughtcrime.securesms.window.detailPaneMaxContentWidth
|
||||
import org.thoughtcrime.securesms.window.isSplitPane
|
||||
import org.thoughtcrime.securesms.window.rememberAppScaffoldNavigator
|
||||
import java.text.NumberFormat
|
||||
|
||||
@@ -162,8 +164,8 @@ private fun CreateGroupScreenUi(
|
||||
uiState: CreateGroupUiState,
|
||||
callbacks: UiCallbacks
|
||||
) {
|
||||
val windowSizeClass = WindowSizeClass.rememberWindowSizeClass()
|
||||
val isSplitPane = windowSizeClass.isSplitPane(forceSplitPaneOnCompactLandscape = uiState.forceSplitPaneOnCompactLandscape)
|
||||
val windowSizeClass = currentWindowAdaptiveInfo().windowSizeClass
|
||||
val isSplitPane = windowSizeClass.isSplitPane(forceSplitPane = uiState.forceSplitPane)
|
||||
val snackbarHostState = remember { SnackbarHostState() }
|
||||
|
||||
val titleText = if (uiState.newSelections.isNotEmpty()) {
|
||||
@@ -352,7 +354,7 @@ private fun CreateGroupScreenPreview() {
|
||||
Previews.Preview {
|
||||
CreateGroupScreenUi(
|
||||
uiState = CreateGroupUiState(
|
||||
forceSplitPaneOnCompactLandscape = false,
|
||||
forceSplitPane = false,
|
||||
selectionLimits = SelectionLimits.NO_LIMITS
|
||||
),
|
||||
callbacks = UiCallbacks.Empty
|
||||
|
||||
@@ -168,7 +168,7 @@ class CreateGroupViewModel : ViewModel() {
|
||||
}
|
||||
|
||||
data class CreateGroupUiState(
|
||||
val forceSplitPaneOnCompactLandscape: Boolean = SignalStore.internal.forceSplitPaneOnCompactLandscape,
|
||||
val forceSplitPane: Boolean = SignalStore.internal.forceSplitPane,
|
||||
val searchQuery: String = "",
|
||||
val selectionLimits: SelectionLimits = RemoteConfig.groupLimits.excludingSelf(),
|
||||
val newSelections: List<SelectedContact> = emptyList(),
|
||||
|
||||
@@ -51,7 +51,7 @@ class InternalValues internal constructor(store: KeyValueStore) : SignalStoreVal
|
||||
/**
|
||||
* Force split-pane mode on compact landscape
|
||||
*/
|
||||
var forceSplitPaneOnCompactLandscape by booleanValue(FORCE_SPLIT_PANE_ON_COMPACT_LANDSCAPE, false).falseForExternalUsers()
|
||||
var forceSplitPane by booleanValue(FORCE_SPLIT_PANE_ON_COMPACT_LANDSCAPE, false).falseForExternalUsers()
|
||||
|
||||
/**
|
||||
* Members will not be added directly to a GV2 even if they could be.
|
||||
|
||||
@@ -34,13 +34,14 @@ import org.thoughtcrime.securesms.util.ServiceUtil;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.thoughtcrime.securesms.util.VersionTracker;
|
||||
import org.thoughtcrime.securesms.window.WindowSizeClass;
|
||||
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Locale;
|
||||
|
||||
import static org.thoughtcrime.securesms.window.WindowSizeClassExtensionsKt.getWindowSizeClass;
|
||||
|
||||
public class LogSectionSystemInfo implements LogSection {
|
||||
|
||||
@Override
|
||||
@@ -62,7 +63,7 @@ public class LogSectionSystemInfo implements LogSection {
|
||||
builder.append("Screen : ").append(getScreenResolution(context)).append(", ")
|
||||
.append(ScreenDensity.get(context)).append(", ")
|
||||
.append(getScreenRefreshRate(context)).append("\n");
|
||||
builder.append("WindowSizeClass : ").append(WindowSizeClass.Companion.getWindowSizeClass(context.getResources())).append("\n");
|
||||
builder.append("WindowSizeClass : ").append(getWindowSizeClass(context.getResources())).append("\n");
|
||||
builder.append("Font Scale : ").append(context.getResources().getConfiguration().fontScale).append("\n");
|
||||
builder.append("Animation Scale : ").append(ContextUtil.getAnimationScale(context)).append("\n");
|
||||
builder.append("Android : ").append(Build.VERSION.RELEASE).append(", API ")
|
||||
|
||||
@@ -39,6 +39,7 @@ import androidx.lifecycle.repeatOnLifecycle
|
||||
import androidx.navigation.NavGraphBuilder
|
||||
import androidx.navigation.compose.composable
|
||||
import androidx.navigation.toRoute
|
||||
import androidx.window.core.layout.WindowSizeClass
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -49,7 +50,8 @@ import org.thoughtcrime.securesms.conversation.v2.ConversationFragment
|
||||
import org.thoughtcrime.securesms.serialization.JsonSerializableNavType
|
||||
import org.thoughtcrime.securesms.window.AppScaffoldAnimationDefaults
|
||||
import org.thoughtcrime.securesms.window.AppScaffoldAnimationState
|
||||
import org.thoughtcrime.securesms.window.WindowSizeClass
|
||||
import org.thoughtcrime.securesms.window.isLargeScreenSupportEnabled
|
||||
import org.thoughtcrime.securesms.window.isSplitPane
|
||||
import kotlin.reflect.typeOf
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
|
||||
@@ -205,7 +207,7 @@ class ChatNavGraphState private constructor(
|
||||
private var hasWrittenToGraphicsLayer: Boolean by mutableStateOf(false)
|
||||
|
||||
suspend fun writeGraphicsLayerToBitmap() {
|
||||
if (WindowSizeClass.isLargeScreenSupportEnabled() && !windowSizeClass.isSplitPane() && hasWrittenToGraphicsLayer) {
|
||||
if (isLargeScreenSupportEnabled() && !windowSizeClass.isSplitPane() && hasWrittenToGraphicsLayer) {
|
||||
chatBitmap = graphicsLayer.toImageBitmap()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,12 +15,12 @@ import androidx.compose.foundation.layout.navigationBarsPadding
|
||||
import androidx.compose.material3.SnackbarDuration
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.material3.SnackbarResult
|
||||
import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import org.signal.core.ui.compose.AllDevicePreviews
|
||||
import org.signal.core.ui.compose.Dialogs
|
||||
import org.signal.core.ui.compose.Previews
|
||||
@@ -29,7 +29,7 @@ import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.megaphone.Megaphone
|
||||
import org.thoughtcrime.securesms.megaphone.MegaphoneActionController
|
||||
import org.thoughtcrime.securesms.megaphone.Megaphones
|
||||
import org.thoughtcrime.securesms.window.WindowSizeClass
|
||||
import org.thoughtcrime.securesms.window.isSplitPane
|
||||
|
||||
data class SnackbarState(
|
||||
val message: String,
|
||||
@@ -77,14 +77,14 @@ fun MainBottomChrome(
|
||||
megaphoneActionController: MegaphoneActionController,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
val windowSizeClass = WindowSizeClass.rememberWindowSizeClass()
|
||||
val windowSizeClass = currentWindowAdaptiveInfo().windowSizeClass
|
||||
|
||||
Column(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.animateContentSize()
|
||||
) {
|
||||
if (state.mainToolbarMode == MainToolbarMode.FULL && windowSizeClass.isCompact()) {
|
||||
if (state.mainToolbarMode == MainToolbarMode.FULL && !windowSizeClass.isSplitPane()) {
|
||||
Box(
|
||||
contentAlignment = Alignment.CenterEnd,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
@@ -104,7 +104,7 @@ fun MainBottomChrome(
|
||||
)
|
||||
}
|
||||
|
||||
val snackBarModifier = if (windowSizeClass.isCompact() && state.mainToolbarMode == MainToolbarMode.BASIC) {
|
||||
val snackBarModifier = if (!windowSizeClass.isSplitPane() && state.mainToolbarMode == MainToolbarMode.BASIC) {
|
||||
Modifier.navigationBarsPadding()
|
||||
} else {
|
||||
Modifier
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
package org.thoughtcrime.securesms.main
|
||||
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.runtime.remember
|
||||
@@ -13,7 +14,9 @@ import androidx.compose.ui.graphics.RectangleShape
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import org.thoughtcrime.securesms.window.WindowSizeClass
|
||||
import androidx.window.core.layout.WindowWidthSizeClass
|
||||
import org.thoughtcrime.securesms.window.isAtLeast
|
||||
import org.thoughtcrime.securesms.window.isSplitPane
|
||||
|
||||
private val MEDIUM_CONTENT_CORNERS = 18.dp
|
||||
private val EXTENDED_CONTENT_CORNERS = 14.dp
|
||||
@@ -42,7 +45,7 @@ data class MainContentLayoutData(
|
||||
*/
|
||||
@Composable
|
||||
fun hasDragHandle(): Boolean {
|
||||
return !WindowSizeClass.rememberWindowSizeClass().isCompact()
|
||||
return currentWindowAdaptiveInfo().windowSizeClass.isSplitPane()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -50,12 +53,12 @@ data class MainContentLayoutData(
|
||||
*/
|
||||
@Composable
|
||||
fun rememberDefaultPanePreferredWidth(maxWidth: Dp): Dp {
|
||||
val windowSizeClass = WindowSizeClass.rememberWindowSizeClass()
|
||||
val windowSizeClass = currentWindowAdaptiveInfo().windowSizeClass
|
||||
|
||||
return remember(maxWidth, windowSizeClass) {
|
||||
when {
|
||||
!windowSizeClass.isSplitPane() -> maxWidth
|
||||
windowSizeClass.isExtended() -> 416.dp
|
||||
windowSizeClass.windowWidthSizeClass.isAtLeast(WindowWidthSizeClass.EXPANDED) -> 416.dp
|
||||
else -> (maxWidth - extraPadding) / 2f
|
||||
}
|
||||
}
|
||||
@@ -67,23 +70,23 @@ data class MainContentLayoutData(
|
||||
*/
|
||||
@Composable
|
||||
fun rememberContentLayoutData(mode: MainToolbarMode): MainContentLayoutData {
|
||||
val windowSizeClass = WindowSizeClass.rememberWindowSizeClass()
|
||||
val windowSizeClass = currentWindowAdaptiveInfo().windowSizeClass
|
||||
|
||||
return remember(windowSizeClass, mode) {
|
||||
MainContentLayoutData(
|
||||
shape = when {
|
||||
!windowSizeClass.isSplitPane() -> RectangleShape
|
||||
windowSizeClass.isExtended() -> RoundedCornerShape(EXTENDED_CONTENT_CORNERS)
|
||||
windowSizeClass.windowWidthSizeClass.isAtLeast(WindowWidthSizeClass.EXPANDED) -> RoundedCornerShape(EXTENDED_CONTENT_CORNERS)
|
||||
else -> RoundedCornerShape(MEDIUM_CONTENT_CORNERS)
|
||||
},
|
||||
navigationBarShape = when {
|
||||
!windowSizeClass.isSplitPane() -> RectangleShape
|
||||
windowSizeClass.isExtended() -> RoundedCornerShape(0.dp, 0.dp, EXTENDED_CONTENT_CORNERS, EXTENDED_CONTENT_CORNERS)
|
||||
windowSizeClass.windowWidthSizeClass.isAtLeast(WindowWidthSizeClass.EXPANDED) -> RoundedCornerShape(0.dp, 0.dp, EXTENDED_CONTENT_CORNERS, EXTENDED_CONTENT_CORNERS)
|
||||
else -> RoundedCornerShape(0.dp, 0.dp, MEDIUM_CONTENT_CORNERS, MEDIUM_CONTENT_CORNERS)
|
||||
},
|
||||
partitionWidth = when {
|
||||
!windowSizeClass.isSplitPane() -> 0.dp
|
||||
windowSizeClass.isExtended() -> 24.dp
|
||||
windowSizeClass.windowWidthSizeClass.isAtLeast(WindowWidthSizeClass.EXPANDED) -> 24.dp
|
||||
else -> 13.dp
|
||||
},
|
||||
listPaddingStart = when {
|
||||
@@ -97,7 +100,7 @@ data class MainContentLayoutData(
|
||||
},
|
||||
detailPaddingEnd = when {
|
||||
!windowSizeClass.isSplitPane() -> 0.dp
|
||||
windowSizeClass.isExtended() -> 24.dp
|
||||
windowSizeClass.windowWidthSizeClass.isAtLeast(WindowWidthSizeClass.EXPANDED) -> 24.dp
|
||||
else -> 12.dp
|
||||
}
|
||||
)
|
||||
|
||||
@@ -8,17 +8,18 @@ package org.thoughtcrime.securesms.main
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.window.core.layout.WindowHeightSizeClass
|
||||
import org.signal.core.ui.compose.DayNightPreviews
|
||||
import org.signal.core.ui.compose.Previews
|
||||
import org.thoughtcrime.securesms.megaphone.Megaphone
|
||||
import org.thoughtcrime.securesms.megaphone.MegaphoneActionController
|
||||
import org.thoughtcrime.securesms.megaphone.MegaphoneComponent
|
||||
import org.thoughtcrime.securesms.megaphone.Megaphones
|
||||
import org.thoughtcrime.securesms.window.WindowSizeClass
|
||||
|
||||
data class MainMegaphoneState(
|
||||
val megaphone: Megaphone = Megaphone.NONE,
|
||||
@@ -44,9 +45,9 @@ fun MainMegaphoneContainer(
|
||||
controller: MegaphoneActionController,
|
||||
onMegaphoneVisible: (Megaphone) -> Unit
|
||||
) {
|
||||
val windowSizeClass = WindowSizeClass.rememberWindowSizeClass()
|
||||
val windowSizeClass = currentWindowAdaptiveInfo().windowSizeClass
|
||||
val visible = remember(windowSizeClass, state) {
|
||||
!(state.megaphone == Megaphone.NONE || state.mainToolbarMode != MainToolbarMode.FULL || windowSizeClass == WindowSizeClass.COMPACT_LANDSCAPE)
|
||||
!(state.megaphone == Megaphone.NONE || state.mainToolbarMode != MainToolbarMode.FULL || windowSizeClass.windowHeightSizeClass == WindowHeightSizeClass.COMPACT)
|
||||
}
|
||||
|
||||
AnimatedVisibility(visible = visible) {
|
||||
@@ -57,7 +58,7 @@ fun MainMegaphoneContainer(
|
||||
}
|
||||
|
||||
LaunchedEffect(state, windowSizeClass) {
|
||||
if (state.megaphone == Megaphone.NONE || state.mainToolbarMode == MainToolbarMode.BASIC || windowSizeClass == WindowSizeClass.COMPACT_LANDSCAPE) {
|
||||
if (state.megaphone == Megaphone.NONE || state.mainToolbarMode == MainToolbarMode.BASIC || windowSizeClass.windowHeightSizeClass == WindowHeightSizeClass.COMPACT) {
|
||||
return@LaunchedEffect
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ import org.thoughtcrime.securesms.megaphone.Megaphones
|
||||
import org.thoughtcrime.securesms.notifications.profiles.NotificationProfile
|
||||
import org.thoughtcrime.securesms.stories.Stories
|
||||
import org.thoughtcrime.securesms.window.AppScaffoldNavigator
|
||||
import org.thoughtcrime.securesms.window.WindowSizeClass
|
||||
import org.thoughtcrime.securesms.window.isLargeScreenSupportEnabled
|
||||
import java.util.Optional
|
||||
|
||||
@OptIn(ExperimentalMaterial3AdaptiveApi::class)
|
||||
@@ -198,7 +198,7 @@ class MainNavigationViewModel(
|
||||
override fun goTo(location: MainNavigationDetailLocation) {
|
||||
lockPaneToSecondary = false
|
||||
|
||||
if (!WindowSizeClass.isLargeScreenSupportEnabled()) {
|
||||
if (!isLargeScreenSupportEnabled()) {
|
||||
goToLegacyDetailLocation?.invoke(location)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.asPaddingValues
|
||||
import androidx.compose.foundation.layout.navigationBars
|
||||
import androidx.compose.foundation.layout.statusBars
|
||||
import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
@@ -20,7 +21,7 @@ import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.unit.Density
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import org.thoughtcrime.securesms.window.WindowSizeClass
|
||||
import org.thoughtcrime.securesms.window.isSplitPane
|
||||
|
||||
@Parcelize
|
||||
data class VerticalInsets(
|
||||
@@ -41,7 +42,7 @@ fun rememberVerticalInsets(): State<VerticalInsets> {
|
||||
val navigationBarPadding = navigationBarInsets.asPaddingValues()
|
||||
val density = LocalDensity.current
|
||||
|
||||
val windowSizeClass = WindowSizeClass.rememberWindowSizeClass()
|
||||
val windowSizeClass = currentWindowAdaptiveInfo().windowSizeClass
|
||||
|
||||
val insets = rememberSaveable { mutableStateOf(VerticalInsets.Zero) }
|
||||
val updated = remember(statusBarInsets, navigationBarInsets, windowSizeClass) {
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
|
||||
package org.thoughtcrime.securesms.window
|
||||
|
||||
import android.content.res.Configuration
|
||||
import android.content.res.Resources
|
||||
import androidx.compose.animation.EnterTransition
|
||||
import androidx.compose.animation.ExitTransition
|
||||
import androidx.compose.foundation.background
|
||||
@@ -16,7 +14,6 @@ import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.consumeWindowInsets
|
||||
import androidx.compose.foundation.layout.displayCutoutPadding
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
@@ -42,23 +39,17 @@ import androidx.compose.ui.draw.drawWithContent
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.graphicsLayer
|
||||
import androidx.compose.ui.layout.layout
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.compose.ui.platform.LocalInspectionMode
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.zIndex
|
||||
import androidx.window.core.ExperimentalWindowCoreApi
|
||||
import androidx.window.core.layout.WindowHeightSizeClass
|
||||
import androidx.window.core.layout.WindowWidthSizeClass
|
||||
import org.signal.core.ui.compose.AllDevicePreviews
|
||||
import org.signal.core.ui.compose.Previews
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.main.MainFloatingActionButtonsCallback
|
||||
import org.thoughtcrime.securesms.main.MainNavigationBar
|
||||
import org.thoughtcrime.securesms.main.MainNavigationRail
|
||||
import org.thoughtcrime.securesms.main.MainNavigationState
|
||||
import org.thoughtcrime.securesms.util.RemoteConfig
|
||||
import kotlin.math.max
|
||||
|
||||
enum class Navigation {
|
||||
@@ -68,141 +59,15 @@ enum class Navigation {
|
||||
companion object {
|
||||
@Composable
|
||||
fun rememberNavigation(): Navigation {
|
||||
val windowSizeClass = WindowSizeClass.rememberWindowSizeClass()
|
||||
val windowSizeClass = currentWindowAdaptiveInfo().windowSizeClass
|
||||
|
||||
return remember(windowSizeClass) { windowSizeClass.navigation }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes the size of screen we are displaying, and what components should be displayed.
|
||||
*
|
||||
* Screens should utilize this class by convention instead of calling [currentWindowAdaptiveInfo]
|
||||
* themselves, as this class includes checks with [RemoteConfig] to ensure we're allowed to display
|
||||
* content in different screen sizes.
|
||||
*
|
||||
* https://developer.android.com/develop/ui/compose/layouts/adaptive/use-window-size-classes
|
||||
*/
|
||||
enum class WindowSizeClass(
|
||||
val navigation: Navigation
|
||||
) {
|
||||
COMPACT_PORTRAIT(Navigation.BAR),
|
||||
COMPACT_LANDSCAPE(Navigation.BAR),
|
||||
MEDIUM_PORTRAIT(Navigation.RAIL),
|
||||
MEDIUM_LANDSCAPE(Navigation.RAIL),
|
||||
EXTENDED_PORTRAIT(Navigation.RAIL),
|
||||
EXTENDED_LANDSCAPE(Navigation.RAIL);
|
||||
|
||||
val listPaneDefaultPreferredWidth: Dp
|
||||
get() = if (isExtended()) 416.dp else 316.dp
|
||||
|
||||
val detailPaneMaxContentWidth: Dp = 624.dp
|
||||
val horizontalPartitionDefaultSpacerSize: Dp = 12.dp
|
||||
|
||||
fun isCompact(): Boolean = this == COMPACT_PORTRAIT || this == COMPACT_LANDSCAPE
|
||||
fun isMedium(): Boolean = this == MEDIUM_PORTRAIT || this == MEDIUM_LANDSCAPE
|
||||
fun isExtended(): Boolean = this == EXTENDED_PORTRAIT || this == EXTENDED_LANDSCAPE
|
||||
|
||||
fun isLandscape(): Boolean = this == COMPACT_LANDSCAPE || this == MEDIUM_LANDSCAPE || this == EXTENDED_LANDSCAPE
|
||||
fun isPortrait(): Boolean = !isLandscape()
|
||||
|
||||
@JvmOverloads
|
||||
fun isSplitPane(
|
||||
forceSplitPaneOnCompactLandscape: Boolean = SignalStore.internal.forceSplitPaneOnCompactLandscape
|
||||
): Boolean {
|
||||
return if (isLargeScreenSupportEnabled() && forceSplitPaneOnCompactLandscape) {
|
||||
this != COMPACT_PORTRAIT
|
||||
} else {
|
||||
this.navigation != Navigation.BAR
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
@OptIn(ExperimentalWindowCoreApi::class)
|
||||
fun Resources.getWindowSizeClass(): WindowSizeClass {
|
||||
val orientation = configuration.orientation
|
||||
|
||||
if (isForcedCompact()) {
|
||||
return getCompactSizeClassForOrientation(orientation)
|
||||
}
|
||||
|
||||
val windowSizeClass = androidx.window.core.layout.WindowSizeClass.compute(
|
||||
displayMetrics.widthPixels,
|
||||
displayMetrics.heightPixels,
|
||||
displayMetrics.density
|
||||
)
|
||||
|
||||
return getSizeClassForOrientationAndSystemSizeClass(orientation, windowSizeClass)
|
||||
}
|
||||
|
||||
fun isLargeScreenSupportEnabled(): Boolean {
|
||||
return RemoteConfig.largeScreenUi && SignalStore.internal.largeScreenUi
|
||||
}
|
||||
|
||||
fun isForcedCompact(): Boolean {
|
||||
return !isLargeScreenSupportEnabled()
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun checkForcedCompact(): Boolean {
|
||||
return !LocalInspectionMode.current && isForcedCompact()
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun rememberWindowSizeClass(forceCompact: Boolean = checkForcedCompact()): WindowSizeClass {
|
||||
val orientation = LocalConfiguration.current.orientation
|
||||
|
||||
if (forceCompact) {
|
||||
return remember(orientation) {
|
||||
getCompactSizeClassForOrientation(orientation)
|
||||
return remember(windowSizeClass) {
|
||||
if (windowSizeClass.isSplitPane() && windowSizeClass.windowHeightSizeClass.isAtLeast(WindowHeightSizeClass.MEDIUM)) {
|
||||
RAIL
|
||||
} else {
|
||||
BAR
|
||||
}
|
||||
}
|
||||
|
||||
val wsc = currentWindowAdaptiveInfo().windowSizeClass
|
||||
|
||||
return remember(orientation, wsc) {
|
||||
getSizeClassForOrientationAndSystemSizeClass(orientation, wsc)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getCompactSizeClassForOrientation(orientation: Int): WindowSizeClass {
|
||||
return when (orientation) {
|
||||
Configuration.ORIENTATION_PORTRAIT, Configuration.ORIENTATION_UNDEFINED, Configuration.ORIENTATION_SQUARE -> {
|
||||
COMPACT_PORTRAIT
|
||||
}
|
||||
|
||||
Configuration.ORIENTATION_LANDSCAPE -> COMPACT_LANDSCAPE
|
||||
else -> error("Unexpected orientation: $orientation")
|
||||
}
|
||||
}
|
||||
|
||||
private fun getSizeClassForOrientationAndSystemSizeClass(orientation: Int, windowSizeClass: androidx.window.core.layout.WindowSizeClass): WindowSizeClass {
|
||||
if (windowSizeClass.windowWidthSizeClass == WindowWidthSizeClass.COMPACT || windowSizeClass.windowHeightSizeClass == WindowHeightSizeClass.COMPACT) {
|
||||
return getCompactSizeClassForOrientation(orientation)
|
||||
}
|
||||
|
||||
return when (orientation) {
|
||||
Configuration.ORIENTATION_PORTRAIT, Configuration.ORIENTATION_UNDEFINED, Configuration.ORIENTATION_SQUARE -> {
|
||||
when (windowSizeClass.windowWidthSizeClass) {
|
||||
WindowWidthSizeClass.COMPACT -> COMPACT_PORTRAIT
|
||||
WindowWidthSizeClass.MEDIUM -> MEDIUM_PORTRAIT
|
||||
WindowWidthSizeClass.EXPANDED -> EXTENDED_PORTRAIT
|
||||
else -> error("Unsupported.")
|
||||
}
|
||||
}
|
||||
|
||||
Configuration.ORIENTATION_LANDSCAPE -> {
|
||||
when (windowSizeClass.windowWidthSizeClass) {
|
||||
WindowWidthSizeClass.COMPACT -> COMPACT_LANDSCAPE
|
||||
WindowWidthSizeClass.MEDIUM -> MEDIUM_LANDSCAPE
|
||||
WindowWidthSizeClass.EXPANDED -> EXTENDED_LANDSCAPE
|
||||
else -> error("Unsupported.")
|
||||
}
|
||||
}
|
||||
|
||||
else -> error("Unexpected orientation: $orientation")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -240,8 +105,8 @@ fun AppScaffold(
|
||||
contentWindowInsets: WindowInsets = ScaffoldDefaults.contentWindowInsets,
|
||||
animatorFactory: AppScaffoldAnimationStateFactory = AppScaffoldAnimationStateFactory.Default
|
||||
) {
|
||||
val isForcedCompact = WindowSizeClass.checkForcedCompact()
|
||||
val windowSizeClass = WindowSizeClass.rememberWindowSizeClass()
|
||||
val isForcedCompact = !LocalInspectionMode.current && !isLargeScreenSupportEnabled()
|
||||
val windowSizeClass = currentWindowAdaptiveInfo().windowSizeClass
|
||||
|
||||
if (isForcedCompact) {
|
||||
ListAndNavigation(
|
||||
@@ -249,7 +114,6 @@ fun AppScaffold(
|
||||
listContent = secondaryContent,
|
||||
navRailContent = navRailContent,
|
||||
bottomNavContent = bottomNavContent,
|
||||
windowSizeClass = windowSizeClass,
|
||||
contentWindowInsets = contentWindowInsets,
|
||||
modifier = modifier
|
||||
)
|
||||
@@ -314,7 +178,6 @@ fun AppScaffold(
|
||||
listContent = secondaryContent,
|
||||
navRailContent = navRailContent,
|
||||
bottomNavContent = bottomNavContent,
|
||||
windowSizeClass = windowSizeClass,
|
||||
contentWindowInsets = WindowInsets() // parent scaffold already applies the necessary insets
|
||||
)
|
||||
}
|
||||
@@ -380,10 +243,11 @@ private fun ListAndNavigation(
|
||||
navRailContent: @Composable () -> Unit,
|
||||
bottomNavContent: @Composable () -> Unit,
|
||||
snackbarHost: @Composable () -> Unit = {},
|
||||
windowSizeClass: WindowSizeClass,
|
||||
contentWindowInsets: WindowInsets,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
val navigation = Navigation.rememberNavigation()
|
||||
|
||||
Scaffold(
|
||||
containerColor = Color.Transparent,
|
||||
topBar = topBarContent,
|
||||
@@ -394,9 +258,8 @@ private fun ListAndNavigation(
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.padding(paddingValues)
|
||||
.then(if (windowSizeClass.isLandscape()) Modifier.displayCutoutPadding() else Modifier)
|
||||
) {
|
||||
if (windowSizeClass.navigation == Navigation.RAIL) {
|
||||
if (navigation == Navigation.RAIL) {
|
||||
navRailContent()
|
||||
}
|
||||
|
||||
@@ -405,7 +268,7 @@ private fun ListAndNavigation(
|
||||
listContent()
|
||||
}
|
||||
|
||||
if (windowSizeClass.navigation == Navigation.BAR) {
|
||||
if (navigation == Navigation.BAR) {
|
||||
bottomNavContent()
|
||||
}
|
||||
}
|
||||
@@ -418,11 +281,11 @@ private fun ListAndNavigation(
|
||||
@Composable
|
||||
private fun AppScaffoldPreview() {
|
||||
Previews.Preview {
|
||||
val windowSizeClass = WindowSizeClass.rememberWindowSizeClass()
|
||||
val windowSizeClass = currentWindowAdaptiveInfo().windowSizeClass
|
||||
|
||||
AppScaffold(
|
||||
navigator = rememberAppScaffoldNavigator(
|
||||
isSplitPane = windowSizeClass.navigation != Navigation.BAR,
|
||||
isSplitPane = windowSizeClass.isSplitPane(),
|
||||
defaultPanePreferredWidth = 416.dp,
|
||||
horizontalPartitionSpacerSize = 16.dp
|
||||
),
|
||||
|
||||
@@ -21,6 +21,7 @@ import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.platform.LocalInspectionMode
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.window.core.layout.WindowSizeClass
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
|
||||
/**
|
||||
@@ -94,9 +95,9 @@ open class AppScaffoldNavigator<T> @RememberInComposition constructor(private va
|
||||
@OptIn(ExperimentalMaterial3AdaptiveApi::class)
|
||||
@Composable
|
||||
fun rememberAppScaffoldNavigator(
|
||||
windowSizeClass: WindowSizeClass = WindowSizeClass.rememberWindowSizeClass(),
|
||||
windowSizeClass: WindowSizeClass = currentWindowAdaptiveInfo().windowSizeClass,
|
||||
isSplitPane: Boolean = windowSizeClass.isSplitPane(
|
||||
forceSplitPaneOnCompactLandscape = if (LocalInspectionMode.current) false else SignalStore.internal.forceSplitPaneOnCompactLandscape
|
||||
forceSplitPane = if (LocalInspectionMode.current) false else SignalStore.internal.forceSplitPane
|
||||
),
|
||||
horizontalPartitionSpacerSize: Dp = windowSizeClass.horizontalPartitionDefaultSpacerSize,
|
||||
defaultPanePreferredWidth: Dp = windowSizeClass.listPaneDefaultPreferredWidth
|
||||
|
||||
@@ -12,6 +12,7 @@ import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi
|
||||
import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
@@ -29,7 +30,7 @@ import org.thoughtcrime.securesms.R
|
||||
@Composable
|
||||
private fun AppScaffoldWithTopBarPreview() {
|
||||
Previews.Preview {
|
||||
val windowSizeClass = WindowSizeClass.rememberWindowSizeClass()
|
||||
val windowSizeClass = currentWindowAdaptiveInfo().windowSizeClass
|
||||
|
||||
AppScaffold(
|
||||
navigator = rememberAppScaffoldNavigator(),
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2025 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.thoughtcrime.securesms.window
|
||||
|
||||
import android.content.res.Resources
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.window.core.ExperimentalWindowCoreApi
|
||||
import androidx.window.core.layout.WindowHeightSizeClass
|
||||
import androidx.window.core.layout.WindowSizeClass
|
||||
import androidx.window.core.layout.WindowWidthSizeClass
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.util.RemoteConfig
|
||||
|
||||
val WindowSizeClass.listPaneDefaultPreferredWidth: Dp get() = if (windowWidthSizeClass.isAtLeast(WindowWidthSizeClass.EXPANDED)) 416.dp else 316.dp
|
||||
val WindowSizeClass.horizontalPartitionDefaultSpacerSize: Dp get() = 12.dp
|
||||
val WindowSizeClass.detailPaneMaxContentWidth: Dp get() = 624.dp
|
||||
|
||||
fun WindowHeightSizeClass.isAtLeast(other: WindowHeightSizeClass): Boolean {
|
||||
return hashCode() >= other.hashCode()
|
||||
}
|
||||
|
||||
fun WindowWidthSizeClass.isAtLeast(other: WindowWidthSizeClass): Boolean {
|
||||
return hashCode() >= other.hashCode()
|
||||
}
|
||||
|
||||
/**
|
||||
* Global check for large screen support, can be inlined after production release.
|
||||
*/
|
||||
fun isLargeScreenSupportEnabled(): Boolean {
|
||||
return RemoteConfig.largeScreenUi && SignalStore.internal.largeScreenUi
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalWindowCoreApi::class)
|
||||
fun Resources.getWindowSizeClass(): WindowSizeClass {
|
||||
return WindowSizeClass.compute(displayMetrics.widthPixels, displayMetrics.heightPixels, displayMetrics.density)
|
||||
}
|
||||
|
||||
/**
|
||||
* Split Pane is enabled as long as the width size class is MEDIUM or greater
|
||||
*/
|
||||
@JvmOverloads
|
||||
fun WindowSizeClass.isSplitPane(
|
||||
forceSplitPane: Boolean = SignalStore.internal.forceSplitPane
|
||||
): Boolean {
|
||||
if (forceSplitPane) {
|
||||
return true
|
||||
}
|
||||
|
||||
return windowWidthSizeClass.isAtLeast(WindowWidthSizeClass.MEDIUM)
|
||||
}
|
||||
Reference in New Issue
Block a user