98ecce847507
scale the whole UI up on wide screens instead of capping or splitting it (June's pick after the 480dp cap and the two-pane both got rejected): a WideScreenScale wrapper at the app root overrides LocalDensity by width/411dp, clamped to 1.35x, so every dp and sp grows together and the same single-column layout reads as a bigger screen rather than a stretched phone. One wrapper, no per-screen breakpoints to keep in sync, and an exact no-op at or below 411dp so phones are pixel-identical — verified by shooting the vault list at both 686dp and phone width. Ceiling: a uniform scale is not real adaptive layout; a screen that ever wants a genuinely different wide arrangement will need its own breakpoint.
- time
- 2026-07-24 20:09 UTC · 3 months ago
- machine
- koh2
- agent
- claude-opus-5
- session
- foldable width
- parent
- c8422d123645
↓ peach-android-98ecce84.tar.gzatlas at this save
files changed1 file
app/src/main/java/com/peachpasswords/MainActivity.kt+43 −1app/src/main/java/com/peachpasswords/MainActivity.kt+43 −1
@@ -10,6 +10,14 @@1010 import androidx.activity.enableEdgeToEdge1111 import androidx.compose.foundation.isSystemInDarkTheme1212 import androidx.compose.runtime.SideEffect13+import androidx.compose.ui.unit.dp14+import androidx.compose.ui.unit.Density15+import androidx.compose.ui.platform.LocalDensity16+import androidx.compose.ui.Modifier17+import androidx.compose.runtime.CompositionLocalProvider18+import androidx.compose.runtime.Composable19+import androidx.compose.foundation.layout.fillMaxSize20+import androidx.compose.foundation.layout.BoxWithConstraints1321 import androidx.compose.runtime.collectAsState1422 import androidx.compose.runtime.getValue1523 import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen@@ -116,8 +124,42 @@116124 accent = accent,117125 reduceMotion = settings.reduceMotion,118126 ) {119- PeachAppNavHost(startDestination = start, isUnlocked = vault.isUnlocked)127+ WideScreenScale {128+ PeachAppNavHost(startDestination = start, isUnlocked = vault.isUnlocked)129+ }120130 }131+ }132+ }133+}134+135+/** Layout width a phone gives us; anything past this is "extra" to spend. */136+private val BASE_WIDTH = 411.dp137+138+/** Cap on the up-scale — past this, big text stops reading as deliberate. */139+private const val MAX_SCALE = 1.35f140+141+/**142+ * On a foldable's inner screen the app was a stretched phone: phone-sized type143+ * and rows with the surplus width absorbed as empty space. Scaling the density144+ * grows every dp and sp together, so the same single-column layout simply reads145+ * as a bigger screen — no per-screen breakpoints to keep in sync.146+ *147+ * Ceiling: a uniform scale, not real adaptive layout. If a screen ever wants a148+ * genuinely different wide-screen arrangement it needs its own breakpoint.149+ * No-op at or below [BASE_WIDTH], so phones are untouched.150+ */151+@Composable152+private fun WideScreenScale(content: @Composable () -> Unit) {153+ BoxWithConstraints(Modifier.fillMaxSize()) {154+ val base = LocalDensity.current155+ val scale = (maxWidth / BASE_WIDTH).coerceIn(1f, MAX_SCALE)156+ if (scale == 1f) {157+ content()158+ } else {159+ CompositionLocalProvider(160+ LocalDensity provides Density(base.density * scale, base.fontScale),161+ content = content,162+ )121163 }122164 }123165 }