Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix window insets to avoid overlapping display cutouts and system bars #1006

Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,7 @@ import androidx.browser.customtabs.CustomTabsIntent
import androidx.compose.animation.ExperimentalSharedTransitionApi
import androidx.compose.animation.SharedTransitionLayout
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.asPaddingValues
import androidx.compose.foundation.layout.calculateEndPadding
import androidx.compose.foundation.layout.calculateStartPadding
import androidx.compose.foundation.layout.displayCutout
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.windowsizeclass.WindowSizeClass
Expand All @@ -31,7 +25,6 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.text.font.FontFamily
import androidx.core.content.getSystemService
import androidx.core.net.toUri
Expand Down Expand Up @@ -100,7 +93,6 @@ fun KaigiApp(
fontFamily: FontFamily?,
modifier: Modifier = Modifier,
) {
val layoutDirection = LocalLayoutDirection.current
KaigiTheme(
colorContrast = colorContrast(),
fontFamily = fontFamily,
Expand All @@ -112,14 +104,7 @@ fun KaigiApp(
KaigiNavHost(
windowSize = windowSize,
displayFeatures = displayFeatures,
modifier = Modifier.padding(
start = WindowInsets.displayCutout
.asPaddingValues()
.calculateStartPadding(layoutDirection),
end = WindowInsets.displayCutout
.asPaddingValues()
.calculateEndPadding(layoutDirection),
),
modifier = Modifier.fillMaxSize(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,11 @@ fun AboutScreen(
AnimatedTextTopAppBar(
title = stringResource(AboutRes.string.about_droidkaigi),
scrollBehavior = scrollBehavior,
windowInsets = WindowInsets(
left = contentPadding.calculateLeftPadding(layoutDirection),
top = contentPadding.calculateTopPadding(),
right = contentPadding.calculateRightPadding(layoutDirection),
),
)
},
snackbarHost = { SnackbarHost(hostState = snackbarHostState) },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,15 @@ package io.github.droidkaigi.confsched.contributors

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.displayCutout
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.systemBars
import androidx.compose.foundation.layout.union
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.CircularProgressIndicator
Expand Down Expand Up @@ -118,19 +124,22 @@ fun ContributorsScreen(
onBackClick = onBackClick,
scrollBehavior = scrollBehavior,
navIconContentDescription = "Back",
windowInsets = WindowInsets.displayCutout.union(WindowInsets.systemBars).only(
WindowInsetsSides.Horizontal + WindowInsetsSides.Top,
),
)
}
},
contentWindowInsets = WindowInsets.displayCutout.union(WindowInsets.systemBars),
) { padding ->
when (uiState) {
is Exists -> {
Contributors(
contributors = uiState.contributors,
onContributorsItemClick = onContributorsItemClick,
contentPadding = PaddingValues(bottom = padding.calculateBottomPadding()),
contentPadding = padding,
modifier = Modifier
.fillMaxSize()
.padding(top = padding.calculateTopPadding())
.let {
if (scrollBehavior != null) {
it.nestedScroll(scrollBehavior.nestedScrollConnection)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.calculateEndPadding
import androidx.compose.foundation.layout.calculateStartPadding
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
Expand Down Expand Up @@ -131,6 +133,11 @@ fun EventMapScreen(
AnimatedTextTopAppBar(
title = stringResource(EventMapRes.string.eventmap),
scrollBehavior = scrollBehavior,
windowInsets = WindowInsets(
left = contentPadding.calculateLeftPadding(layoutDirection),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the amazing PR! I'll merge it regardless. However, could you explain why the window insets of each screen's AnimatedTextTopAppBar are different?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@takahirom
I gave this window insets to avoid display cutouts and system bars, since default value TopAppBarDefaults.windowInsets only avoids system bars.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your explain. How about making a function like this? And can you resolve the conflict with the main branch?

windowInsets = AnimatedTextTopAppBarDefaults.windowInsets(contentPadding),
object AnimatedTextTopAppBarDefaults {
    @Composable
    fun windowInsets(contentPadding: PaddingValues): WindowInsets {
        val layoutDirection = LocalLayoutDirection.current
        return WindowInsets(
            left = contentPadding.calculateLeftPadding(layoutDirection),
            top = contentPadding.calculateTopPadding(),
            right = contentPadding.calculateRightPadding(layoutDirection),
        )
    }
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes of course!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@takahirom
I realized I didn't need to use content padding for window insets of top app bars.
I'll make default windowInsets like below for each top app bars instead.

object HogeTopAppBarDefaults {
    val windowInsets = WindowInsets.displayCutout.union(WindowInsets.systemBars).only(
        WindowInsetsSides.Horizontal + WindowInsetsSides.Top,
    )
}

top = contentPadding.calculateTopPadding(),
right = contentPadding.calculateRightPadding(layoutDirection),
),
)
},
contentWindowInsets = WindowInsets(
Expand All @@ -143,7 +150,11 @@ fun EventMapScreen(
EventMap(
uiState = uiState,
onEventMapItemClick = onEventMapItemClick,
contentPadding = PaddingValues(bottom = padding.calculateBottomPadding()),
contentPadding = PaddingValues(
start = padding.calculateStartPadding(layoutDirection),
end = padding.calculateEndPadding(layoutDirection),
bottom = padding.calculateBottomPadding(),
),
modifier = Modifier
.fillMaxSize()
.padding(top = padding.calculateTopPadding())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import androidx.compose.animation.core.FastOutLinearInEasing
import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.spring
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.outlined.ArrowBack
Expand All @@ -23,6 +24,7 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.lerp
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.platform.testTag
import androidx.navigation.NavController
import androidx.navigation.NavGraph.Companion.findStartDestination
Expand Down Expand Up @@ -138,6 +140,7 @@ private fun FavoritesScreen(
modifier: Modifier = Modifier,
contentPadding: PaddingValues = PaddingValues(),
) {
val layoutDirection = LocalLayoutDirection.current
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior()

val fraction = if (scrollBehavior.state.overlappedFraction > 0.01f) 1f else 0f
Expand Down Expand Up @@ -172,6 +175,11 @@ private fun FavoritesScreen(
colors = TopAppBarDefaults.topAppBarColors().copy(
scrolledContainerColor = MaterialTheme.colorScheme.surfaceContainer,
),
windowInsets = WindowInsets(
left = contentPadding.calculateLeftPadding(layoutDirection),
top = contentPadding.calculateTopPadding(),
right = contentPadding.calculateRightPadding(layoutDirection),
),
)
},
) { padding ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,16 @@ import androidx.compose.animation.fadeOut
import androidx.compose.animation.scaleIn
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.displayCutout
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.systemBars
import androidx.compose.foundation.layout.union
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.material3.ColorScheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
Expand All @@ -27,6 +34,7 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import androidx.navigation.NavGraphBuilder
Expand Down Expand Up @@ -204,6 +212,7 @@ fun MainScreen(
mainNestedNavGraph: NavGraphBuilder.(NavController, PaddingValues) -> Unit,
modifier: Modifier = Modifier,
) {
val layoutDirection = LocalLayoutDirection.current
val mainNestedNavController = rememberNavController()

val navBackStackEntryRoute =
Expand All @@ -221,15 +230,24 @@ fun MainScreen(

val scaffoldPadding = remember { mutableStateOf(PaddingValues(0.dp)) }

Row(modifier = modifier.fillMaxSize()) {
Row(
modifier = modifier.fillMaxSize()
.windowInsetsPadding(
WindowInsets.displayCutout
.union(WindowInsets.systemBars)
.only(WindowInsetsSides.Start),
),
) {
AnimatedVisibility(visible = navigationType == NavigationRail) {
GlassLikeNavRail(
hazeState = hazeState,
onTabSelected = {
onTabSelected(mainNestedNavController, it)
},
currentTab = currentTab,
modifier = Modifier.padding(scaffoldPadding.value),
modifier = Modifier.padding(
top = scaffoldPadding.value.calculateTopPadding(),
),
)
}

Expand All @@ -246,6 +264,8 @@ fun MainScreen(
)
}
},
contentWindowInsets = WindowInsets.displayCutout
.union(WindowInsets.systemBars),
) { padding ->
scaffoldPadding.value = padding
val hazeStyle =
Expand All @@ -264,7 +284,19 @@ fun MainScreen(
enterTransition = { materialFadeThroughIn() },
exitTransition = { materialFadeThroughOut() },
) {
mainNestedNavGraph(mainNestedNavController, padding)
mainNestedNavGraph(
mainNestedNavController,
PaddingValues(
top = padding.calculateTopPadding(),
bottom = padding.calculateBottomPadding(),
start = if (navigationType == NavigationRail) {
0.dp
} else {
padding.calculateLeftPadding(layoutDirection)
},
end = padding.calculateRightPadding(layoutDirection),
),
)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,11 @@ internal fun ProfileCardScreen(
AnimatedTextTopAppBar(
title = stringResource(ProfileCardRes.string.profile_card_title),
scrollBehavior = scrollBehavior,
windowInsets = WindowInsets(
left = contentPadding.calculateLeftPadding(layoutDirection),
top = contentPadding.calculateTopPadding(),
right = contentPadding.calculateRightPadding(layoutDirection),
),
)
}

Expand All @@ -294,6 +299,11 @@ internal fun ProfileCardScreen(
textColor = MaterialTheme.colorScheme.scrim,
title = stringResource(ProfileCardRes.string.profile_card_title),
scrollBehavior = scrollBehavior,
windowInsets = WindowInsets(
left = contentPadding.calculateLeftPadding(layoutDirection),
top = contentPadding.calculateTopPadding(),
right = contentPadding.calculateRightPadding(layoutDirection),
),
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,17 @@ package io.github.droidkaigi.confsched.sessions
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.calculateEndPadding
import androidx.compose.foundation.layout.calculateStartPadding
import androidx.compose.foundation.layout.displayCutout
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.systemBars
import androidx.compose.foundation.layout.union
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
Expand All @@ -14,6 +22,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.dropUnlessResumed
import androidx.navigation.NavController
Expand Down Expand Up @@ -137,20 +146,29 @@ fun SearchScreen(
onBackClick: () -> Unit,
modifier: Modifier = Modifier,
) {
val layoutDirection = LocalLayoutDirection.current
Scaffold(
topBar = {
SearchTextFieldAppBar(
searchWord = uiState.searchWord,
onChangeSearchWord = onSearchWordChanged,
onClickClear = onClearSearchWordClick,
onClickBack = onBackClick,
windowInsets = WindowInsets.displayCutout.union(WindowInsets.systemBars).only(
WindowInsetsSides.Horizontal + WindowInsetsSides.Top,
),
)
},
modifier = modifier,
containerColor = MaterialTheme.colorScheme.surface,
contentWindowInsets = WindowInsets.displayCutout.union(WindowInsets.systemBars),
) { innerPadding ->
Column(
modifier = Modifier.padding(top = innerPadding.calculateTopPadding()),
modifier = Modifier.padding(
top = innerPadding.calculateTopPadding(),
start = innerPadding.calculateStartPadding(layoutDirection),
end = innerPadding.calculateEndPadding(layoutDirection),
),
) {
HorizontalDivider()
SearchFilters(
Expand Down
Loading
Loading