Skip to content

Commit 861d732

Browse files
committed
Fixed edge to edge on accounts screen
Signed-off-by: Arnau Mora <[email protected]>
1 parent 36f5848 commit 861d732

File tree

5 files changed

+147
-18
lines changed

5 files changed

+147
-18
lines changed

app/src/main/kotlin/at/bitfire/davdroid/ui/AccountsDrawerHandler.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@ import androidx.compose.foundation.background
1212
import androidx.compose.foundation.layout.Box
1313
import androidx.compose.foundation.layout.Column
1414
import androidx.compose.foundation.layout.Spacer
15+
import androidx.compose.foundation.layout.displayCutoutPadding
1516
import androidx.compose.foundation.layout.fillMaxWidth
1617
import androidx.compose.foundation.layout.height
18+
import androidx.compose.foundation.layout.navigationBarsPadding
1719
import androidx.compose.foundation.layout.padding
1820
import androidx.compose.foundation.layout.size
1921
import androidx.compose.foundation.layout.statusBarsPadding
@@ -52,6 +54,8 @@ import androidx.compose.ui.unit.dp
5254
import androidx.core.net.toUri
5355
import at.bitfire.davdroid.BuildConfig
5456
import at.bitfire.davdroid.R
57+
import at.bitfire.davdroid.ui.edgetoedge.onlyLandscape
58+
import at.bitfire.davdroid.ui.edgetoedge.onlyPortrait
5559
import at.bitfire.davdroid.ui.webdav.WebdavMountsActivity
5660
import kotlinx.coroutines.launch
5761
import java.net.URI
@@ -81,6 +85,8 @@ abstract class AccountsDrawerHandler {
8185
Column(modifier = Modifier
8286
.fillMaxWidth()
8387
.verticalScroll(rememberScrollState())
88+
.onlyPortrait { navigationBarsPadding() }
89+
.onlyLandscape { displayCutoutPadding() }
8490
) {
8591
BrandingHeader()
8692

@@ -249,8 +255,8 @@ fun MenuEntry_Preview() {
249255
fun BrandingHeader() {
250256
Column(
251257
Modifier
252-
.statusBarsPadding()
253258
.background(Color.DarkGray)
259+
.statusBarsPadding()
254260
.fillMaxWidth()
255261
.padding(16.dp)
256262
) {

app/src/main/kotlin/at/bitfire/davdroid/ui/AccountsScreen.kt

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,13 @@ import androidx.compose.foundation.clickable
1616
import androidx.compose.foundation.layout.Box
1717
import androidx.compose.foundation.layout.Column
1818
import androidx.compose.foundation.layout.WindowInsets
19+
import androidx.compose.foundation.layout.add
20+
import androidx.compose.foundation.layout.displayCutout
1921
import androidx.compose.foundation.layout.fillMaxSize
2022
import androidx.compose.foundation.layout.fillMaxWidth
23+
import androidx.compose.foundation.layout.navigationBarsPadding
2124
import androidx.compose.foundation.layout.padding
25+
import androidx.compose.foundation.layout.safeContent
2226
import androidx.compose.foundation.layout.size
2327
import androidx.compose.foundation.rememberScrollState
2428
import androidx.compose.foundation.verticalScroll
@@ -44,10 +48,12 @@ import androidx.compose.material3.MaterialTheme
4448
import androidx.compose.material3.ModalDrawerSheet
4549
import androidx.compose.material3.ModalNavigationDrawer
4650
import androidx.compose.material3.Scaffold
51+
import androidx.compose.material3.ScaffoldDefaults
4752
import androidx.compose.material3.SnackbarHost
4853
import androidx.compose.material3.SnackbarHostState
4954
import androidx.compose.material3.Text
5055
import androidx.compose.material3.TopAppBar
56+
import androidx.compose.material3.TopAppBarDefaults
5157
import androidx.compose.material3.pulltorefresh.PullToRefreshBox
5258
import androidx.compose.material3.rememberDrawerState
5359
import androidx.compose.runtime.Composable
@@ -78,6 +84,9 @@ import at.bitfire.davdroid.R
7884
import at.bitfire.davdroid.ui.account.AccountProgress
7985
import at.bitfire.davdroid.ui.composable.ActionCard
8086
import at.bitfire.davdroid.ui.composable.ProgressBar
87+
import at.bitfire.davdroid.ui.edgetoedge.LocalStatusBarScrimColors
88+
import at.bitfire.davdroid.ui.edgetoedge.onlyLandscape
89+
import at.bitfire.davdroid.ui.edgetoedge.withOrientation
8190
import com.google.accompanist.permissions.ExperimentalPermissionsApi
8291
import com.google.accompanist.permissions.isGranted
8392
import com.google.accompanist.permissions.rememberPermissionState
@@ -167,6 +176,16 @@ fun AccountsScreen(
167176

168177
val snackbarHostState = remember { SnackbarHostState() }
169178
AppTheme {
179+
val statusBarTheme = LocalStatusBarScrimColors.current
180+
LaunchedEffect(drawerState.isClosed) {
181+
// Set to false because the background is dark, so show icons in light mode
182+
if (drawerState.isClosed) {
183+
statusBarTheme.resetStatusBarDarkTheme()
184+
} else {
185+
statusBarTheme.setStatusBarDarkTheme(true)
186+
}
187+
}
188+
170189
ModalNavigationDrawer(
171190
drawerState = drawerState,
172191
drawerContent = {
@@ -185,8 +204,16 @@ fun AccountsScreen(
185204
}
186205
) {
187206
Scaffold(
207+
contentWindowInsets = withOrientation(
208+
landscape = WindowInsets.safeContent,
209+
portrait = ScaffoldDefaults.contentWindowInsets,
210+
),
188211
topBar = {
189212
TopAppBar(
213+
windowInsets = TopAppBarDefaults.windowInsets.onlyLandscape {
214+
// only add the display cutout when portrait
215+
add(WindowInsets.displayCutout)
216+
},
190217
navigationIcon = {
191218
IconToggleButton(false, onCheckedChange = { openDrawer ->
192219
scope.launch {
@@ -208,7 +235,13 @@ fun AccountsScreen(
208235
)
209236
},
210237
floatingActionButton = {
211-
Column(horizontalAlignment = Alignment.CenterHorizontally) {
238+
Column(
239+
horizontalAlignment = Alignment.CenterHorizontally,
240+
modifier = withOrientation(
241+
landscape = Modifier.navigationBarsPadding(),
242+
portrait = Modifier,
243+
),
244+
) {
212245
if (showAddAccount == AccountsModel.FABStyle.WithText)
213246
ExtendedFloatingActionButton(
214247
text = { Text(stringResource(R.string.login_add_account)) },

app/src/main/kotlin/at/bitfire/davdroid/ui/AppTheme.kt

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,40 +5,49 @@
55
package at.bitfire.davdroid.ui
66

77
import androidx.activity.SystemBarStyle
8+
import androidx.activity.compose.LocalActivity
89
import androidx.activity.enableEdgeToEdge
910
import androidx.appcompat.app.AppCompatActivity
1011
import androidx.compose.foundation.isSystemInDarkTheme
11-
import androidx.compose.foundation.layout.Box
12-
import androidx.compose.foundation.layout.displayCutoutPadding
13-
import androidx.compose.foundation.layout.fillMaxSize
14-
import androidx.compose.foundation.layout.navigationBarsPadding
1512
import androidx.compose.material3.MaterialTheme
1613
import androidx.compose.runtime.Composable
1714
import androidx.compose.runtime.CompositionLocalProvider
18-
import androidx.compose.runtime.SideEffect
19-
import androidx.compose.ui.Modifier
20-
import androidx.compose.ui.draw.clipToBounds
15+
import androidx.compose.runtime.LaunchedEffect
16+
import androidx.compose.runtime.getValue
2117
import androidx.compose.ui.graphics.toArgb
2218
import androidx.compose.ui.platform.LocalContext
2319
import androidx.compose.ui.platform.LocalUriHandler
2420
import androidx.compose.ui.platform.LocalView
2521
import androidx.lifecycle.compose.LifecycleResumeEffect
22+
import androidx.lifecycle.compose.collectAsStateWithLifecycle
2623
import at.bitfire.davdroid.ui.composable.SafeAndroidUriHandler
24+
import at.bitfire.davdroid.ui.edgetoedge.LocalStatusBarScrimColors
25+
import at.bitfire.davdroid.ui.edgetoedge.StatusBarScrimColors
2726

2827
@Composable
2928
fun AppTheme(
3029
darkTheme: Boolean = isSystemInDarkTheme(),
3130
content: @Composable () -> Unit
31+
) = CompositionLocalProvider(
32+
LocalStatusBarScrimColors provides StatusBarScrimColors(
33+
initialStatusBarDarkTheme = darkTheme
34+
)
3235
) {
33-
val view = LocalView.current
34-
SideEffect {
36+
val activity = LocalActivity.current
37+
val statusBarDarkMode by LocalStatusBarScrimColors.current.statusBarDarkTheme.collectAsStateWithLifecycle()
38+
val navigationBarDarkTheme by LocalStatusBarScrimColors.current.navigationBarDarkTheme.collectAsStateWithLifecycle()
39+
LaunchedEffect(statusBarDarkMode, navigationBarDarkTheme) {
3540
// If applicable, call Activity.enableEdgeToEdge to enable edge-to-edge layout on Android <15, too.
3641
// When we have moved everything into one Activity with Compose navigation, we can call it there instead.
37-
(view.context as? AppCompatActivity)?.enableEdgeToEdge(
42+
(activity as? AppCompatActivity)?.enableEdgeToEdge(
3843
navigationBarStyle = SystemBarStyle.auto(
3944
lightScrim = M3ColorScheme.lightScheme.scrim.toArgb(),
4045
darkScrim = M3ColorScheme.darkScheme.scrim.toArgb()
41-
) { darkTheme }
46+
) { navigationBarDarkTheme },
47+
statusBarStyle = SystemBarStyle.auto(
48+
lightScrim = M3ColorScheme.lightScheme.scrim.toArgb(),
49+
darkScrim = M3ColorScheme.darkScheme.scrim.toArgb()
50+
) { statusBarDarkMode }
4251
)
4352
}
4453

@@ -50,14 +59,12 @@ fun AppTheme(
5059
M3ColorScheme.lightScheme
5160
else
5261
M3ColorScheme.darkScheme,
53-
) {
54-
Box(Modifier.fillMaxSize().displayCutoutPadding().navigationBarsPadding().clipToBounds()) {
55-
content()
56-
}
57-
}
62+
content = content,
63+
)
5864
}
5965

6066
// Track if the app is in the foreground
67+
val view = LocalView.current
6168
LifecycleResumeEffect(view) {
6269
ForegroundTracker.onResume()
6370
onPauseOrDispose {
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
3+
*/
4+
5+
package at.bitfire.davdroid.ui.edgetoedge
6+
7+
import android.content.res.Configuration.ORIENTATION_LANDSCAPE
8+
import androidx.compose.runtime.Composable
9+
import androidx.compose.ui.platform.LocalConfiguration
10+
11+
@Composable
12+
private fun isLandscape(): Boolean {
13+
val config = LocalConfiguration.current
14+
return config.orientation == ORIENTATION_LANDSCAPE
15+
}
16+
17+
@Composable
18+
fun <T> T.onlyPortrait(modifier: @Composable T.() -> T): T {
19+
return if (isLandscape()) {
20+
this
21+
} else {
22+
modifier()
23+
}
24+
}
25+
26+
@Composable
27+
fun <T> T.onlyLandscape(modifier: @Composable T.() -> T): T {
28+
return if (isLandscape()) {
29+
modifier()
30+
} else {
31+
this
32+
}
33+
}
34+
35+
@Composable
36+
fun <T> withOrientation(landscape: T, portrait: T): T {
37+
return if (isLandscape()) {
38+
landscape
39+
} else {
40+
portrait
41+
}
42+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
3+
*/
4+
5+
package at.bitfire.davdroid.ui.edgetoedge
6+
7+
import androidx.compose.runtime.compositionLocalOf
8+
import kotlinx.coroutines.flow.MutableStateFlow
9+
import kotlinx.coroutines.flow.asStateFlow
10+
11+
class StatusBarScrimColors(
12+
private val initialStatusBarDarkTheme: Boolean = false,
13+
private val initialNavigationBarDarkTheme: Boolean = initialStatusBarDarkTheme,
14+
) {
15+
private val _statusBarDarkTheme = MutableStateFlow(initialStatusBarDarkTheme)
16+
val statusBarDarkTheme get() = _statusBarDarkTheme.asStateFlow()
17+
18+
private val _navigationBarDarkTheme = MutableStateFlow(initialNavigationBarDarkTheme)
19+
val navigationBarDarkTheme get() = _navigationBarDarkTheme.asStateFlow()
20+
21+
fun setStatusBarDarkTheme(darkTheme: Boolean) {
22+
_statusBarDarkTheme.tryEmit(darkTheme)
23+
}
24+
fun resetStatusBarDarkTheme() {
25+
_statusBarDarkTheme.tryEmit(initialStatusBarDarkTheme)
26+
}
27+
28+
fun setNavigationBarDarkTheme(darkTheme: Boolean) {
29+
_navigationBarDarkTheme.tryEmit(darkTheme)
30+
}
31+
fun resetNavigationBarDarkTheme() {
32+
_navigationBarDarkTheme.tryEmit(initialNavigationBarDarkTheme)
33+
}
34+
35+
fun reset() {
36+
resetStatusBarDarkTheme()
37+
resetNavigationBarDarkTheme()
38+
}
39+
}
40+
41+
val LocalStatusBarScrimColors = compositionLocalOf { StatusBarScrimColors() }

0 commit comments

Comments
 (0)