mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-07-08 15:04:21 +01:00
Fix medium sized devices using bar navigation instead of rail navigation.
This commit is contained in:
committed by
Alex Hart
parent
c2f8261419
commit
b02210c166
@@ -16,6 +16,7 @@ import androidx.compose.ui.platform.LocalResources
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.window.core.layout.WindowSizeClass
|
||||
import org.signal.core.ui.WindowBreakpoint
|
||||
import org.signal.core.ui.getWindowBreakpoint
|
||||
import org.signal.core.ui.rememberIsSplitPane
|
||||
|
||||
@@ -78,7 +79,7 @@ data class MainContentLayoutData(
|
||||
val isSplitPane = resources.rememberIsSplitPane()
|
||||
|
||||
return remember(windowSizeClass, mode, breakpoint, isSplitPane) {
|
||||
val isLargeWindowSize = breakpoint.isLargeWindow
|
||||
val isLargeWindowSize = breakpoint is WindowBreakpoint.Large
|
||||
|
||||
MainContentLayoutData(
|
||||
shape = when {
|
||||
|
||||
@@ -81,8 +81,9 @@ enum class NavigationType {
|
||||
val windowBreakpoint = remember(config) { resources.getWindowBreakpoint() }
|
||||
|
||||
return when (windowBreakpoint) {
|
||||
WindowBreakpoint.SMALL, WindowBreakpoint.MEDIUM -> BAR
|
||||
WindowBreakpoint.LARGE_WIDTH, WindowBreakpoint.LARGE_HEIGHT -> RAIL
|
||||
is WindowBreakpoint.Small -> BAR
|
||||
is WindowBreakpoint.Medium -> if (windowBreakpoint.isWidthExpanded) RAIL else BAR
|
||||
is WindowBreakpoint.Large -> RAIL
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,47 +54,61 @@ fun rememberWindowBreakpoint(): WindowBreakpoint {
|
||||
* Determines the device's form factor based on the current [Resources] and window size class.
|
||||
*
|
||||
* This function uses several heuristics:
|
||||
* - Returns [WindowBreakpoint.SMALL] if the width or height is compact
|
||||
* - Otherwise, falls back to aspect ratio heuristics: wide windows use [WindowBreakpoint.LARGE_WIDTH], tall windows use [WindowBreakpoint.LARGE_HEIGHT], else [WindowBreakpoint.MEDIUM].
|
||||
* - Returns [WindowBreakpoint.Small] if the window width or height is compact.
|
||||
* - Otherwise, falls back to window aspect ratio heuristics:
|
||||
* aspect ratio < [TABLET_ASPECT_RATIO] is [WindowBreakpoint.Medium]
|
||||
* aspect ratio >= [TABLET_ASPECT_RATIO] is [WindowBreakpoint.Large]
|
||||
*
|
||||
* @return the inferred [WindowBreakpoint] for the current device.
|
||||
*/
|
||||
fun Resources.getWindowBreakpoint(): WindowBreakpoint {
|
||||
val windowSizeClass = getWindowSizeClass()
|
||||
val isWidthExpanded = windowSizeClass.isWidthExpanded
|
||||
val isHeightExpanded = windowSizeClass.isHeightExpanded
|
||||
|
||||
if (windowSizeClass.isWidthCompact || windowSizeClass.isHeightCompact) {
|
||||
return WindowBreakpoint.SMALL
|
||||
return WindowBreakpoint.Small(isWidthExpanded, isHeightExpanded)
|
||||
}
|
||||
|
||||
val numerator = maxOf(displayMetrics.widthPixels, displayMetrics.heightPixels)
|
||||
val denominator = minOf(displayMetrics.widthPixels, displayMetrics.heightPixels)
|
||||
val aspectRatio = numerator.toFloat() / denominator
|
||||
|
||||
return when {
|
||||
aspectRatio < TABLET_ASPECT_RATIO -> WindowBreakpoint.MEDIUM
|
||||
else -> {
|
||||
if (displayMetrics.widthPixels >= displayMetrics.heightPixels) {
|
||||
WindowBreakpoint.LARGE_WIDTH
|
||||
} else {
|
||||
WindowBreakpoint.LARGE_HEIGHT
|
||||
}
|
||||
}
|
||||
return if (aspectRatio < TABLET_ASPECT_RATIO) {
|
||||
WindowBreakpoint.Medium(isWidthExpanded, isHeightExpanded)
|
||||
} else {
|
||||
WindowBreakpoint.Large(isWidthExpanded, isHeightExpanded)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates the general form factor of the device for responsive UI purposes.
|
||||
*
|
||||
* - [SMALL]: A window with a compact width or height, typical of phone-sized devices.
|
||||
* - [MEDIUM]: A window where neither width nor height is compact or expanded, typical of foldables.
|
||||
* - [LARGE_WIDTH]: A window with expanded width and medium height, typical of tablets in landscape orientation.
|
||||
* - [LARGE_HEIGHT]: A window with medium width and expanded height, typical of tablets in portrait orientation.
|
||||
* - [Small]: A window with a compact width or height, typical of phone-sized devices.
|
||||
* - [Medium]: A non-compact window with a near-square aspect ratio (< [TABLET_ASPECT_RATIO]), typical of open foldable devices.
|
||||
* - [Large]: A window with an aspect ratio >= [TABLET_ASPECT_RATIO], typical of tablets.
|
||||
*/
|
||||
enum class WindowBreakpoint(val isLargeWindow: Boolean) {
|
||||
SMALL(isLargeWindow = false),
|
||||
MEDIUM(isLargeWindow = false),
|
||||
LARGE_WIDTH(isLargeWindow = true),
|
||||
LARGE_HEIGHT(isLargeWindow = true)
|
||||
sealed interface WindowBreakpoint {
|
||||
/** True when the [WindowSizeClass] width is >= the expanded breakpoint (e.g., a tablet in landscape orientation) */
|
||||
val isWidthExpanded: Boolean
|
||||
|
||||
/** True when the [WindowSizeClass] height is >= the expanded breakpoint (e.g., a tablet in landscape orientation) */
|
||||
val isHeightExpanded: Boolean
|
||||
|
||||
data class Small(
|
||||
override val isWidthExpanded: Boolean,
|
||||
override val isHeightExpanded: Boolean
|
||||
) : WindowBreakpoint
|
||||
|
||||
data class Medium(
|
||||
override val isWidthExpanded: Boolean,
|
||||
override val isHeightExpanded: Boolean
|
||||
) : WindowBreakpoint
|
||||
|
||||
data class Large(
|
||||
override val isWidthExpanded: Boolean,
|
||||
override val isHeightExpanded: Boolean
|
||||
) : WindowBreakpoint
|
||||
}
|
||||
|
||||
@Composable
|
||||
@@ -117,8 +131,9 @@ fun Resources.isSplitPane(
|
||||
return true
|
||||
}
|
||||
|
||||
return when (getWindowBreakpoint()) {
|
||||
WindowBreakpoint.SMALL, WindowBreakpoint.LARGE_HEIGHT -> false
|
||||
WindowBreakpoint.MEDIUM, WindowBreakpoint.LARGE_WIDTH -> true
|
||||
return when (val breakpoint = getWindowBreakpoint()) {
|
||||
is WindowBreakpoint.Small -> false
|
||||
is WindowBreakpoint.Medium -> true
|
||||
is WindowBreakpoint.Large -> breakpoint.isWidthExpanded
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ fun HSVColorBar(
|
||||
onColorChanged: (Int) -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
val orientation = if (rememberWindowBreakpoint() == WindowBreakpoint.SMALL) {
|
||||
val orientation = if (rememberWindowBreakpoint() is WindowBreakpoint.Small) {
|
||||
ColorBarOrientation.HORIZONTAL
|
||||
} else {
|
||||
ColorBarOrientation.VERTICAL
|
||||
|
||||
@@ -292,7 +292,7 @@ private fun OrientedImageEditorToolbar(
|
||||
content: @Composable () -> Unit
|
||||
) {
|
||||
val windowBreakpoint = rememberWindowBreakpoint()
|
||||
val isRow = windowBreakpoint == WindowBreakpoint.SMALL
|
||||
val isRow = windowBreakpoint is WindowBreakpoint.Small
|
||||
|
||||
if (isRow) {
|
||||
Row(modifier = modifier.height(48.dp)) {
|
||||
|
||||
@@ -59,7 +59,7 @@ fun MediaEditScreen(
|
||||
.fillMaxSize()
|
||||
.navigationBarsPadding()
|
||||
) {
|
||||
val isSmallWindowBreakpoint = rememberWindowBreakpoint() == WindowBreakpoint.SMALL
|
||||
val isSmallWindowBreakpoint = rememberWindowBreakpoint() is WindowBreakpoint.Small
|
||||
val controllers = remember { EditorController.Container() }
|
||||
|
||||
val currentController = state.focusedMedia?.let {
|
||||
|
||||
+4
-5
@@ -125,11 +125,10 @@ object RegistrationScaffold {
|
||||
|
||||
@Composable
|
||||
fun rememberLayoutParams(): Params {
|
||||
return when (rememberWindowBreakpoint()) {
|
||||
WindowBreakpoint.SMALL -> smallLayoutParams
|
||||
WindowBreakpoint.MEDIUM -> mediumLayoutParams
|
||||
WindowBreakpoint.LARGE_WIDTH -> largeWidthLayoutParams
|
||||
WindowBreakpoint.LARGE_HEIGHT -> largeHeightLayoutParams
|
||||
return when (val breakpoint = rememberWindowBreakpoint()) {
|
||||
is WindowBreakpoint.Small -> smallLayoutParams
|
||||
is WindowBreakpoint.Medium -> mediumLayoutParams
|
||||
is WindowBreakpoint.Large -> if (breakpoint.isWidthExpanded) largeWidthLayoutParams else largeHeightLayoutParams
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+9
-12
@@ -417,10 +417,9 @@ fun getQrOuterBorderSize(isInOverlay: Boolean): Dp {
|
||||
|
||||
val breakpoint = rememberWindowBreakpoint()
|
||||
return when (breakpoint) {
|
||||
WindowBreakpoint.SMALL -> 296.dp
|
||||
WindowBreakpoint.MEDIUM -> 296.dp
|
||||
WindowBreakpoint.LARGE_WIDTH -> 364.dp
|
||||
WindowBreakpoint.LARGE_HEIGHT -> 364.dp
|
||||
is WindowBreakpoint.Small -> 296.dp
|
||||
is WindowBreakpoint.Medium -> 296.dp
|
||||
is WindowBreakpoint.Large -> 364.dp
|
||||
}
|
||||
}
|
||||
|
||||
@@ -432,10 +431,9 @@ fun getQrInnerBorderSize(isInOverlay: Boolean): Dp {
|
||||
|
||||
val breakpoint = rememberWindowBreakpoint()
|
||||
return when (breakpoint) {
|
||||
WindowBreakpoint.SMALL -> 232.dp
|
||||
WindowBreakpoint.MEDIUM -> 232.dp
|
||||
WindowBreakpoint.LARGE_WIDTH -> 284.dp
|
||||
WindowBreakpoint.LARGE_HEIGHT -> 284.dp
|
||||
is WindowBreakpoint.Small -> 232.dp
|
||||
is WindowBreakpoint.Medium -> 232.dp
|
||||
is WindowBreakpoint.Large -> 284.dp
|
||||
}
|
||||
}
|
||||
|
||||
@@ -447,10 +445,9 @@ fun getQrCodeSize(isInOverlay: Boolean): Dp {
|
||||
|
||||
val breakpoint = rememberWindowBreakpoint()
|
||||
return when (breakpoint) {
|
||||
WindowBreakpoint.SMALL -> 208.dp
|
||||
WindowBreakpoint.MEDIUM -> 208.dp
|
||||
WindowBreakpoint.LARGE_WIDTH -> 256.dp
|
||||
WindowBreakpoint.LARGE_HEIGHT -> 256.dp
|
||||
is WindowBreakpoint.Small -> 208.dp
|
||||
is WindowBreakpoint.Medium -> 208.dp
|
||||
is WindowBreakpoint.Large -> 256.dp
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-4
@@ -173,10 +173,9 @@ private fun FooterContent(
|
||||
val breakpoint = rememberWindowBreakpoint()
|
||||
|
||||
when (breakpoint) {
|
||||
WindowBreakpoint.SMALL -> StackedFooter(params, modifier, onEvent)
|
||||
WindowBreakpoint.MEDIUM -> StackedFooter(params, modifier, onEvent)
|
||||
WindowBreakpoint.LARGE_WIDTH -> InlineFooter(modifier, onEvent)
|
||||
WindowBreakpoint.LARGE_HEIGHT -> InlineFooter(modifier, onEvent)
|
||||
is WindowBreakpoint.Small -> StackedFooter(params, modifier, onEvent)
|
||||
is WindowBreakpoint.Medium -> StackedFooter(params, modifier, onEvent)
|
||||
is WindowBreakpoint.Large -> InlineFooter(modifier, onEvent)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -84,7 +84,7 @@ fun WelcomeScreen(
|
||||
val onTermsAndPrivacyClick = { onEvent(WelcomeScreenEvents.ViewTermsAndPrivacy) }
|
||||
|
||||
when (windowBreakpoint) {
|
||||
WindowBreakpoint.SMALL -> {
|
||||
is WindowBreakpoint.Small -> {
|
||||
CompactLayout(
|
||||
onEvent = onEvent,
|
||||
onRestoreOrTransferClick = onRestoreOrTransferClick,
|
||||
@@ -93,7 +93,7 @@ fun WelcomeScreen(
|
||||
)
|
||||
}
|
||||
|
||||
WindowBreakpoint.MEDIUM -> {
|
||||
is WindowBreakpoint.Medium -> {
|
||||
MediumLayout(
|
||||
onEvent = onEvent,
|
||||
onRestoreOrTransferClick = onRestoreOrTransferClick,
|
||||
@@ -102,7 +102,7 @@ fun WelcomeScreen(
|
||||
)
|
||||
}
|
||||
|
||||
WindowBreakpoint.LARGE_WIDTH, WindowBreakpoint.LARGE_HEIGHT -> {
|
||||
is WindowBreakpoint.Large -> {
|
||||
LargeLayout(
|
||||
isLinkAndSyncAvailable = isLinkAndSyncAvailable,
|
||||
onEvent = onEvent,
|
||||
|
||||
Reference in New Issue
Block a user