diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 48640cd2663..d64fe37c3cf 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -24,7 +24,7 @@ android { } } - compileSdk = 34 + compileSdk = 35 testOptions { unitTests { isReturnDefaultValues = true @@ -34,7 +34,7 @@ android { defaultConfig { applicationId = "de.westnordost.streetcomplete" minSdk = 21 - targetSdk = 34 + targetSdk = 35 versionCode = 6003 versionName = "60.0" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" @@ -107,9 +107,9 @@ repositories { } dependencies { - val mockitoVersion = "3.12.4" + val mockitoVersion = "5.14.2" - coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.3") + coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.4") // tests testImplementation("org.mockito:mockito-core:$mockitoVersion") @@ -122,7 +122,7 @@ dependencies { androidTestImplementation(kotlin("test")) // dependency injection - implementation(platform("io.insert-koin:koin-bom:4.0.0")) + implementation(platform("io.insert-koin:koin-bom:4.0.1")) implementation("io.insert-koin:koin-core") implementation("io.insert-koin:koin-android") implementation("io.insert-koin:koin-androidx-workmanager") @@ -130,13 +130,13 @@ dependencies { // Android stuff implementation("com.google.android.material:material:1.12.0") - implementation("androidx.core:core-ktx:1.13.1") + implementation("androidx.core:core-ktx:1.15.0") implementation("androidx.appcompat:appcompat:1.7.0") implementation("androidx.constraintlayout:constraintlayout:2.2.0") implementation("androidx.annotation:annotation:1.9.1") implementation("androidx.fragment:fragment-ktx:1.8.5") implementation("androidx.recyclerview:recyclerview:1.3.2") - implementation("androidx.viewpager:viewpager:1.0.0") + implementation("androidx.viewpager:viewpager:1.1.0") implementation("androidx.localbroadcastmanager:localbroadcastmanager:1.1.0") // Jetpack Compose @@ -149,38 +149,38 @@ dependencies { implementation("androidx.compose.ui:ui-tooling-preview") debugImplementation("androidx.compose.ui:ui-tooling") - implementation("androidx.navigation:navigation-compose:2.8.4") + implementation("androidx.navigation:navigation-compose:2.8.5") implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.7") implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.7") // reorderable lists (raw Compose API is pretty complicated) - implementation("sh.calvin.reorderable:reorderable:2.4.0") + implementation("sh.calvin.reorderable:reorderable:2.4.2") // multiplatform webview (for login via OAuth) - implementation("io.github.kevinnzou:compose-webview-multiplatform-android:1.9.20") + implementation("io.github.kevinnzou:compose-webview-multiplatform-android:1.9.40") // photos implementation("androidx.exifinterface:exifinterface:1.3.7") // settings - implementation("com.russhwolf:multiplatform-settings:1.2.0") + implementation("com.russhwolf:multiplatform-settings:1.3.0") // Kotlin - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0") - implementation("org.jetbrains.kotlinx:kotlinx-io-core:0.5.4") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.1") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.1") + implementation("org.jetbrains.kotlinx:kotlinx-io-core:0.6.0") // Date/time api("org.jetbrains.kotlinx:kotlinx-datetime:0.6.1") // scheduling background jobs - implementation("androidx.work:work-runtime-ktx:2.9.1") + implementation("androidx.work:work-runtime-ktx:2.10.0") // HTTP Client - implementation("io.ktor:ktor-client-core:2.3.13") - implementation("io.ktor:ktor-client-android:2.3.13") - testImplementation("io.ktor:ktor-client-mock:2.3.13") + implementation("io.ktor:ktor-client-core:3.0.3") + implementation("io.ktor:ktor-client-android:3.0.3") + testImplementation("io.ktor:ktor-client-mock:3.0.3") // TODO: as soon as both ktor-client and kotlinx-serialization have been refactored to be based // on kotlinx-io, revisit sending and receiving xml/json payloads via APIs, currently it // is all String-based, i.e. no KMP equivalent of InputStream/OutputStream involved @@ -202,11 +202,11 @@ dependencies { // serialization implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3") - implementation("com.charleskorn.kaml:kaml:0.66.0") - implementation("io.github.pdvrieze.xmlutil:core:0.90.2") + implementation("com.charleskorn.kaml:kaml:0.67.0") + implementation("io.github.pdvrieze.xmlutil:core:0.90.3") // map and location - implementation("org.maplibre.gl:android-sdk:11.6.1") + implementation("org.maplibre.gl:android-sdk:11.7.1") // opening hours parser implementation("de.westnordost:osm-opening-hours:0.1.0") diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index d6db44aa968..b347cb32719 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -89,14 +89,14 @@ diff --git a/app/src/main/java/de/westnordost/streetcomplete/screens/about/AboutScreen.kt b/app/src/main/java/de/westnordost/streetcomplete/screens/about/AboutScreen.kt index 981f6fd4231..fa4f74d119f 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/screens/about/AboutScreen.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/screens/about/AboutScreen.kt @@ -2,9 +2,15 @@ package de.westnordost.streetcomplete.screens.about import android.content.Context import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.WindowInsetsSides import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.only +import androidx.compose.foundation.layout.safeDrawing +import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll +import androidx.compose.material.AppBarDefaults import androidx.compose.material.IconButton import androidx.compose.material.Text import androidx.compose.material.TopAppBar @@ -47,9 +53,15 @@ fun AboutScreen( Column(Modifier.fillMaxSize()) { TopAppBar( title = { Text(stringResource(R.string.action_about2)) }, + windowInsets = AppBarDefaults.topAppBarWindowInsets, navigationIcon = { IconButton(onClick = onClickBack) { BackIcon() } }, ) - Column(modifier = Modifier.verticalScroll(rememberScrollState())) { + Column(modifier = Modifier + .verticalScroll(rememberScrollState()) + .windowInsetsPadding(WindowInsets.safeDrawing.only( + WindowInsetsSides.Horizontal + WindowInsetsSides.Bottom + )) + ) { PreferenceCategory(null) { diff --git a/app/src/main/java/de/westnordost/streetcomplete/screens/about/ChangelogScreen.kt b/app/src/main/java/de/westnordost/streetcomplete/screens/about/ChangelogScreen.kt index b6f916ca844..ad332a38770 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/screens/about/ChangelogScreen.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/screens/about/ChangelogScreen.kt @@ -2,11 +2,18 @@ package de.westnordost.streetcomplete.screens.about import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.WindowInsetsSides +import androidx.compose.foundation.layout.asPaddingValues +import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.only import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.safeDrawing import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.text.selection.SelectionContainer +import androidx.compose.material.AppBarDefaults import androidx.compose.material.Divider import androidx.compose.material.IconButton import androidx.compose.material.MaterialTheme @@ -21,6 +28,7 @@ import androidx.compose.ui.unit.dp import de.westnordost.streetcomplete.R import de.westnordost.streetcomplete.ui.common.BackIcon import de.westnordost.streetcomplete.ui.common.HtmlText +import de.westnordost.streetcomplete.ui.ktx.plus import de.westnordost.streetcomplete.ui.theme.titleLarge import de.westnordost.streetcomplete.util.html.HtmlNode @@ -35,13 +43,18 @@ fun ChangelogScreen( Column(Modifier.fillMaxSize()) { TopAppBar( title = { Text(stringResource(R.string.about_title_changelog)) }, + windowInsets = AppBarDefaults.topAppBarWindowInsets, navigationIcon = { IconButton(onClick = onClickBack) { BackIcon() } }, ) changelog?.let { changelog -> SelectionContainer { + val insets = WindowInsets.safeDrawing.only( + WindowInsetsSides.Horizontal + WindowInsetsSides.Bottom + ).asPaddingValues() ChangelogList( changelog = changelog, - paddingValues = PaddingValues(16.dp) + paddingValues = insets + PaddingValues(16.dp), + modifier = Modifier.consumeWindowInsets(insets) ) } } @@ -63,7 +76,10 @@ fun ChangelogList( key = { index, _ -> index } ) { index, (version, html) -> if (index > 0) Divider(modifier = Modifier.padding(vertical = 16.dp)) - Text(text = version, style = MaterialTheme.typography.titleLarge) + Text( + text = version, + style = MaterialTheme.typography.titleLarge + ) HtmlText( html = html, style = MaterialTheme.typography.body2, diff --git a/app/src/main/java/de/westnordost/streetcomplete/screens/about/CreditsScreen.kt b/app/src/main/java/de/westnordost/streetcomplete/screens/about/CreditsScreen.kt index 75eea72990c..85a1a2d8308 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/screens/about/CreditsScreen.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/screens/about/CreditsScreen.kt @@ -3,13 +3,19 @@ package de.westnordost.streetcomplete.screens.about import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.WindowInsetsSides 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.safeDrawing import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.text.selection.SelectionContainer import androidx.compose.foundation.verticalScroll +import androidx.compose.material.AppBarDefaults import androidx.compose.material.IconButton import androidx.compose.material.LocalTextStyle import androidx.compose.material.MaterialTheme @@ -42,6 +48,7 @@ fun CreditsScreen( Column(Modifier.fillMaxSize()) { TopAppBar( title = { Text(stringResource(R.string.about_title_authors)) }, + windowInsets = AppBarDefaults.topAppBarWindowInsets, navigationIcon = { IconButton(onClick = onClickBack) { BackIcon() } }, ) credits?.let { credits -> @@ -51,6 +58,9 @@ fun CreditsScreen( modifier = Modifier .fillMaxWidth() .verticalScroll(rememberScrollState()) + .windowInsetsPadding(WindowInsets.safeDrawing.only( + WindowInsetsSides.Horizontal + WindowInsetsSides.Bottom + )) .padding(16.dp) ) } diff --git a/app/src/main/java/de/westnordost/streetcomplete/screens/about/PrivacyStatementScreen.kt b/app/src/main/java/de/westnordost/streetcomplete/screens/about/PrivacyStatementScreen.kt index 4b9c30700ef..76af1740855 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/screens/about/PrivacyStatementScreen.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/screens/about/PrivacyStatementScreen.kt @@ -1,12 +1,18 @@ package de.westnordost.streetcomplete.screens.about import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.WindowInsetsSides 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.safeDrawing +import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.text.selection.SelectionContainer import androidx.compose.foundation.verticalScroll +import androidx.compose.material.AppBarDefaults import androidx.compose.material.IconButton import androidx.compose.material.MaterialTheme import androidx.compose.material.Text @@ -28,6 +34,7 @@ fun PrivacyStatementScreen( Column(Modifier.fillMaxSize()) { TopAppBar( title = { Text(stringResource(R.string.about_title_privacy_statement)) }, + windowInsets = AppBarDefaults.topAppBarWindowInsets, navigationIcon = { IconButton(onClick = onClickBack) { BackIcon() } }, ) SelectionContainer { @@ -40,6 +47,9 @@ fun PrivacyStatementScreen( modifier = Modifier .fillMaxWidth() .verticalScroll(rememberScrollState()) + .windowInsetsPadding(WindowInsets.safeDrawing.only( + WindowInsetsSides.Horizontal + WindowInsetsSides.Bottom + )) .padding(16.dp), style = MaterialTheme.typography.body2, ) diff --git a/app/src/main/java/de/westnordost/streetcomplete/screens/about/logs/LogsScreen.kt b/app/src/main/java/de/westnordost/streetcomplete/screens/about/logs/LogsScreen.kt index 225624d53ce..ef74ae537a1 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/screens/about/logs/LogsScreen.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/screens/about/logs/LogsScreen.kt @@ -5,13 +5,20 @@ import android.content.Intent import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.WindowInsetsSides +import androidx.compose.foundation.layout.asPaddingValues +import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.only import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.safeDrawing import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material.AppBarDefaults import androidx.compose.material.Divider import androidx.compose.material.Icon import androidx.compose.material.IconButton @@ -61,6 +68,7 @@ fun LogsScreen( Column(Modifier.fillMaxSize()) { TopAppBar( title = { Text(stringResource(R.string.about_title_logs, logs.size)) }, + windowInsets = AppBarDefaults.topAppBarWindowInsets, navigationIcon = { IconButton(onClick = onClickBack) { BackIcon() } }, actions = { IconButton(onClick = { showFiltersDialog = true }) { @@ -86,7 +94,14 @@ fun LogsScreen( if (logs.isEmpty()) { CenteredLargeTitleHint(stringResource(R.string.no_search_results)) } else { - LazyColumn(state = listState) { + val insets = WindowInsets.safeDrawing.only( + WindowInsetsSides.Horizontal + WindowInsetsSides.Bottom + ).asPaddingValues() + LazyColumn( + state = listState, + contentPadding = insets, + modifier = Modifier.consumeWindowInsets(insets) + ) { itemsIndexed(logs) { index, item -> if (index > 0) Divider() LogsRow(item, modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp)) diff --git a/app/src/main/java/de/westnordost/streetcomplete/screens/main/MainActivity.kt b/app/src/main/java/de/westnordost/streetcomplete/screens/main/MainActivity.kt index c398e37f4af..43dc34ee7ee 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/screens/main/MainActivity.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/screens/main/MainActivity.kt @@ -201,8 +201,7 @@ class MainActivity : //region Lifecycle - Android Lifecycle Callbacks override fun onCreate(savedInstanceState: Bundle?) { - val systemBarStyle = SystemBarStyle.dark(Color.argb(0x80, 0x1b, 0x1b, 0x1b)) - enableEdgeToEdge(systemBarStyle, systemBarStyle) + enableEdgeToEdge() super.onCreate(savedInstanceState) LocalBroadcastManager.getInstance(this).registerReceiver( diff --git a/app/src/main/java/de/westnordost/streetcomplete/screens/main/MainScreen.kt b/app/src/main/java/de/westnordost/streetcomplete/screens/main/MainScreen.kt index 93c9b23573a..5088d252cff 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/screens/main/MainScreen.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/screens/main/MainScreen.kt @@ -19,7 +19,7 @@ import androidx.compose.foundation.layout.defaultMinSize import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.systemBars +import androidx.compose.foundation.layout.safeDrawing import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.material.ButtonDefaults import androidx.compose.material.MaterialTheme @@ -217,7 +217,7 @@ fun MainScreen( Column(Modifier .fillMaxSize() - .windowInsetsPadding(WindowInsets.systemBars) + .windowInsetsPadding(WindowInsets.safeDrawing) .onGloballyPositioned { pointerPinRects["frame"] = it.boundsInRoot() } ) { Box(Modifier @@ -286,7 +286,8 @@ fun MainScreen( .align(Alignment.BottomEnd) .padding(4.dp) .onGloballyPositioned { pointerPinRects["bottom-end"] = it.boundsInRoot() }, - verticalArrangement = Arrangement.spacedBy(8.dp) + verticalArrangement = Arrangement.spacedBy(8.dp), + horizontalAlignment = Alignment.End, ) { val isCompassVisible = abs(mapRotation) >= 1.0 || abs(mapTilt) >= 1.0 AnimatedVisibility( @@ -323,6 +324,7 @@ fun MainScreen( }, modifier = Modifier .align(BiasAlignment(0.333f, 1f)) + .onGloballyPositioned { pointerPinRects["create-node"] = it.boundsInRoot() } .padding(4.dp), colors = ButtonDefaults.buttonColors( backgroundColor = MaterialTheme.colors.secondaryVariant, diff --git a/app/src/main/java/de/westnordost/streetcomplete/screens/main/edithistory/EditHistorySidebar.kt b/app/src/main/java/de/westnordost/streetcomplete/screens/main/edithistory/EditHistorySidebar.kt index 9d50ab1d371..f3d3a1909a1 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/screens/main/edithistory/EditHistorySidebar.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/screens/main/edithistory/EditHistorySidebar.kt @@ -6,15 +6,18 @@ import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.WindowInsetsSides import androidx.compose.foundation.layout.asPaddingValues import androidx.compose.foundation.layout.calculateEndPadding import androidx.compose.foundation.layout.calculateStartPadding import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.only import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.safeDrawing import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.rememberLazyListState @@ -44,6 +47,7 @@ import de.westnordost.streetcomplete.R import de.westnordost.streetcomplete.data.edithistory.Edit import de.westnordost.streetcomplete.data.osm.mapdata.Element import de.westnordost.streetcomplete.ui.ktx.isItemAtIndexFullyVisible +import de.westnordost.streetcomplete.ui.ktx.plus import de.westnordost.streetcomplete.ui.theme.titleSmall import de.westnordost.streetcomplete.util.ktx.toast import kotlinx.coroutines.launch @@ -67,9 +71,6 @@ fun EditHistorySidebar( val scope = rememberCoroutineScope() val context = LocalContext.current - val dir = LocalLayoutDirection.current - - val insets = WindowInsets.safeDrawing.asPaddingValues() var showUndoDialog by remember { mutableStateOf(false) } var editElement by remember { mutableStateOf(null) } @@ -105,28 +106,25 @@ fun EditHistorySidebar( } } - // take care of insets: - // vertical offset as lazy column content padding, left padding as padding of the surface Surface( modifier = modifier - .padding(end = insets.calculateEndPadding(dir)) .fillMaxHeight() - .consumeWindowInsets(insets) + .windowInsetsPadding(WindowInsets.safeDrawing.only(WindowInsetsSides.End)) .shadow(16.dp), // not using surface's elevation here because we don't want it to change its background // color to gray in dark mode ) { + val verticalInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Vertical) LazyColumn( modifier = Modifier - .padding(start = insets.calculateStartPadding(dir)) + .windowInsetsPadding(WindowInsets.safeDrawing.only(WindowInsetsSides.Start)) + .consumeWindowInsets(verticalInsets) .width(80.dp), state = state, horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Bottom, - contentPadding = PaddingValues( - top = insets.calculateTopPadding(), - bottom = insets.calculateBottomPadding() + 24.dp // to align with undo button - ) + // bottom 24 dp to align with undo button + contentPadding = verticalInsets.asPaddingValues() + PaddingValues(bottom = 24.dp) ) { items( items = editItems, diff --git a/app/src/main/java/de/westnordost/streetcomplete/screens/settings/SettingsScreen.kt b/app/src/main/java/de/westnordost/streetcomplete/screens/settings/SettingsScreen.kt index 4ef100d0bea..51940afe2fe 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/screens/settings/SettingsScreen.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/screens/settings/SettingsScreen.kt @@ -3,9 +3,15 @@ package de.westnordost.streetcomplete.screens.settings import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.WindowInsetsSides import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.only +import androidx.compose.foundation.layout.safeDrawing +import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll +import androidx.compose.material.AppBarDefaults import androidx.compose.material.Icon import androidx.compose.material.IconButton import androidx.compose.material.Switch @@ -73,9 +79,15 @@ fun SettingsScreen( Column(Modifier.fillMaxSize()) { TopAppBar( title = { Text(stringResource(R.string.action_settings)) }, + windowInsets = AppBarDefaults.topAppBarWindowInsets, navigationIcon = { IconButton(onClick = onClickBack) { BackIcon() } }, ) - Column(modifier = Modifier.verticalScroll(rememberScrollState())) { + Column(Modifier + .verticalScroll(rememberScrollState()) + .windowInsetsPadding(WindowInsets.safeDrawing.only( + WindowInsetsSides.Horizontal + WindowInsetsSides.Bottom + )) + ) { PreferenceCategory(stringResource(R.string.pref_category_quests)) { Preference( diff --git a/app/src/main/java/de/westnordost/streetcomplete/screens/settings/debug/ShowQuestFormsScreen.kt b/app/src/main/java/de/westnordost/streetcomplete/screens/settings/debug/ShowQuestFormsScreen.kt index d4d6a23a9d5..97ef993ad61 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/screens/settings/debug/ShowQuestFormsScreen.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/screens/settings/debug/ShowQuestFormsScreen.kt @@ -4,10 +4,17 @@ import androidx.compose.foundation.Image import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column +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.asPaddingValues +import androidx.compose.foundation.layout.consumeWindowInsets 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.safeDrawing import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.itemsIndexed @@ -62,9 +69,14 @@ fun ShowQuestFormsScreen( if (filteredQuests.isEmpty()) { CenteredLargeTitleHint(stringResource(R.string.no_search_results)) } else { + val insets = WindowInsets.safeDrawing.only( + WindowInsetsSides.Horizontal + WindowInsetsSides.Bottom + ).asPaddingValues() QuestList( items = filteredQuests, - onClickQuestType = onClickQuestType + onClickQuestType = onClickQuestType, + contentPadding = insets, + modifier = Modifier.consumeWindowInsets(insets) ) } } @@ -92,6 +104,7 @@ private fun ShowQuestFormsTopAppBar( Column { TopAppBar( title = { Text("Show Quest Forms") }, + windowInsets = AppBarDefaults.topAppBarWindowInsets, navigationIcon = { IconButton(onClick = onClickBack) { BackIcon() } }, actions = { IconButton(onClick = { setShowSearch(!showSearch) }) { SearchIcon() } }, elevation = 0.dp @@ -118,8 +131,12 @@ private fun QuestList( items: List, onClickQuestType: (QuestType) -> Unit, modifier: Modifier = Modifier, + contentPadding: PaddingValues = PaddingValues(0.dp) ) { - LazyColumn(modifier) { + LazyColumn( + modifier = modifier, + contentPadding = contentPadding, + ) { itemsIndexed(items, key = { _, it -> it.name }) { index, item -> Column(Modifier.clickable { onClickQuestType(item) }) { if (index > 0) Divider() diff --git a/app/src/main/java/de/westnordost/streetcomplete/screens/settings/quest_presets/QuestPresetsScreen.kt b/app/src/main/java/de/westnordost/streetcomplete/screens/settings/quest_presets/QuestPresetsScreen.kt index e314fb9137e..9ab207cc5d6 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/screens/settings/quest_presets/QuestPresetsScreen.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/screens/settings/quest_presets/QuestPresetsScreen.kt @@ -2,13 +2,23 @@ package de.westnordost.streetcomplete.screens.settings.quest_presets import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +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.asPaddingValues +import androidx.compose.foundation.layout.calculateEndPadding +import androidx.compose.foundation.layout.calculateStartPadding +import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.foundation.layout.fillMaxHeight 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.safeDrawing import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.material.AppBarDefaults import androidx.compose.material.Divider import androidx.compose.material.FloatingActionButton import androidx.compose.material.Icon @@ -24,6 +34,7 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp @@ -42,13 +53,26 @@ import de.westnordost.streetcomplete.ui.theme.titleMedium Column(Modifier.fillMaxSize()) { TopAppBar( title = { Text(stringResource(R.string.action_manage_presets)) }, + windowInsets = AppBarDefaults.topAppBarWindowInsets, navigationIcon = { IconButton(onClick = onClickBack) { BackIcon() } }, ) - Box(Modifier.fillMaxHeight()) { - QuestPresetsList(viewModel) + val insets = WindowInsets.safeDrawing.only( + WindowInsetsSides.Horizontal + WindowInsetsSides.Bottom + ).asPaddingValues() + Box(Modifier + .fillMaxHeight() + .consumeWindowInsets(insets) + ) { + QuestPresetsList( + viewModel = viewModel, + contentPadding = insets, + ) FloatingActionButton( onClick = { showAddDialog = true }, - modifier = Modifier.align(Alignment.BottomEnd).padding(16.dp) + modifier = Modifier + .align(Alignment.BottomEnd) + .padding(16.dp) + .padding(insets) ) { Icon( painter = painterResource(R.drawable.ic_add_24dp), @@ -69,12 +93,27 @@ import de.westnordost.streetcomplete.ui.theme.titleMedium } @Composable -private fun QuestPresetsList(viewModel: QuestPresetsViewModel) { +private fun QuestPresetsList( + viewModel: QuestPresetsViewModel, + modifier: Modifier = Modifier, + contentPadding: PaddingValues = PaddingValues(0.dp) +) { val presets by viewModel.presets.collectAsState() - Column { - QuestPresetsHeader() - LazyColumn { + Column(modifier) { + val layoutDirection = LocalLayoutDirection.current + QuestPresetsHeader(Modifier.padding( + start = contentPadding.calculateStartPadding(layoutDirection), + top = contentPadding.calculateTopPadding(), + end = contentPadding.calculateEndPadding(layoutDirection) + )) + LazyColumn( + contentPadding = PaddingValues( + start = contentPadding.calculateStartPadding(layoutDirection), + end = contentPadding.calculateEndPadding(layoutDirection), + bottom = contentPadding.calculateBottomPadding() + ), + ) { itemsIndexed(presets, key = { _, it -> it.id }) { index, item -> Column { if (index > 0) Divider() @@ -94,8 +133,8 @@ private fun QuestPresetsList(viewModel: QuestPresetsViewModel) { } @Composable -private fun QuestPresetsHeader() { - Column { +private fun QuestPresetsHeader(modifier: Modifier = Modifier) { + Column(modifier) { Row( Modifier .fillMaxWidth() diff --git a/app/src/main/java/de/westnordost/streetcomplete/screens/settings/quest_selection/QuestSelectionList.kt b/app/src/main/java/de/westnordost/streetcomplete/screens/settings/quest_selection/QuestSelectionList.kt index 79de99882c3..44928c0a563 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/screens/settings/quest_selection/QuestSelectionList.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/screens/settings/quest_selection/QuestSelectionList.kt @@ -2,7 +2,10 @@ package de.westnordost.streetcomplete.screens.settings.quest_selection import androidx.compose.animation.core.animateDpAsState import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.calculateEndPadding +import androidx.compose.foundation.layout.calculateStartPadding import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn @@ -20,6 +23,7 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.hapticfeedback.HapticFeedbackType import androidx.compose.ui.platform.LocalHapticFeedback +import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -40,6 +44,8 @@ fun QuestSelectionList( displayCountry: String, onSelectQuest: (questType: QuestType, selected: Boolean) -> Unit, onReorderQuest: (questType: QuestType, toAfter: QuestType) -> Unit, + modifier: Modifier = Modifier, + contentPadding: PaddingValues = PaddingValues(0.dp), ) { var showEnableQuestDialog by remember { mutableStateOf(null) } @@ -64,12 +70,24 @@ fun QuestSelectionList( dragItem = null } - Column { - QuestSelectionHeader() + Column(modifier) { + val layoutDirection = LocalLayoutDirection.current + QuestSelectionHeader(Modifier.padding( + start = contentPadding.calculateStartPadding(layoutDirection), + top = contentPadding.calculateTopPadding(), + end = contentPadding.calculateEndPadding(layoutDirection) + )) // TODO Compose: scrollbars would be nice here (not supported yet by compose) // When they are available: Check other places too, don't want to add a todo in every // single place that could have a scrollbar - LazyColumn(state = listState) { + LazyColumn( + state = listState, + contentPadding = PaddingValues( + start = contentPadding.calculateStartPadding(layoutDirection), + end = contentPadding.calculateEndPadding(layoutDirection), + bottom = contentPadding.calculateBottomPadding() + ), + ) { itemsIndexed(reorderableItems, key = { _, it -> it.questType.name }) { index, item -> ReorderableItem( state = dragDropState, @@ -121,8 +139,8 @@ fun QuestSelectionList( } @Composable -private fun QuestSelectionHeader() { - Column { +private fun QuestSelectionHeader(modifier: Modifier = Modifier) { + Column(modifier) { Row( Modifier .fillMaxWidth() diff --git a/app/src/main/java/de/westnordost/streetcomplete/screens/settings/quest_selection/QuestSelectionScreen.kt b/app/src/main/java/de/westnordost/streetcomplete/screens/settings/quest_selection/QuestSelectionScreen.kt index 4b516c1548f..e9bd68d2544 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/screens/settings/quest_selection/QuestSelectionScreen.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/screens/settings/quest_selection/QuestSelectionScreen.kt @@ -1,7 +1,13 @@ package de.westnordost.streetcomplete.screens.settings.quest_selection import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.WindowInsetsSides +import androidx.compose.foundation.layout.asPaddingValues +import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.only +import androidx.compose.foundation.layout.safeDrawing import androidx.compose.runtime.Composable import androidx.compose.runtime.ReadOnlyComposable import androidx.compose.runtime.collectAsState @@ -55,6 +61,9 @@ fun QuestSelectionScreen( if (filteredQuests.isEmpty()) { CenteredLargeTitleHint(stringResource(R.string.no_search_results)) } else { + val insets = WindowInsets.safeDrawing.only( + WindowInsetsSides.Horizontal + WindowInsetsSides.Bottom + ).asPaddingValues() QuestSelectionList( items = filteredQuests, displayCountry = displayCountry, @@ -63,7 +72,9 @@ fun QuestSelectionScreen( }, onReorderQuest = { questType, toAfter -> viewModel.orderQuest(questType, toAfter) - } + }, + modifier = Modifier.consumeWindowInsets(insets), + contentPadding = insets, ) } } diff --git a/app/src/main/java/de/westnordost/streetcomplete/screens/settings/quest_selection/QuestSelectionTopAppBar.kt b/app/src/main/java/de/westnordost/streetcomplete/screens/settings/quest_selection/QuestSelectionTopAppBar.kt index 8582f0a5c5b..e4789f7a051 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/screens/settings/quest_selection/QuestSelectionTopAppBar.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/screens/settings/quest_selection/QuestSelectionTopAppBar.kt @@ -57,6 +57,7 @@ import de.westnordost.streetcomplete.ui.common.dialogs.ConfirmationDialog Column { TopAppBar( title = { QuestSelectionTitle(currentPresetName) }, + windowInsets = AppBarDefaults.topAppBarWindowInsets, navigationIcon = { IconButton(onClick = onClickBack) { BackIcon() } }, actions = { QuestSelectionTopBarActions( diff --git a/app/src/main/java/de/westnordost/streetcomplete/screens/tutorial/TutorialScreen.kt b/app/src/main/java/de/westnordost/streetcomplete/screens/tutorial/TutorialScreen.kt index 9c0441467c1..bcabea0a5d2 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/screens/tutorial/TutorialScreen.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/screens/tutorial/TutorialScreen.kt @@ -100,8 +100,7 @@ fun TutorialScreen( ) .padding(bottom = 16.dp) ) - }, - modifier = Modifier.safeDrawingPadding() + } ) } } @@ -113,7 +112,7 @@ private fun TutorialScreenLayout( pageContent: @Composable () -> Unit, controls: @Composable () -> Unit, ) { - BoxWithConstraints(modifier) { + BoxWithConstraints(modifier.safeDrawingPadding()) { if (maxHeight > maxWidth) { Column( modifier = Modifier.fillMaxSize(), diff --git a/app/src/main/java/de/westnordost/streetcomplete/screens/user/UserScreen.kt b/app/src/main/java/de/westnordost/streetcomplete/screens/user/UserScreen.kt index 0ee2911cda0..1b6ae3e78f7 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/screens/user/UserScreen.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/screens/user/UserScreen.kt @@ -2,8 +2,13 @@ package de.westnordost.streetcomplete.screens.user import androidx.compose.foundation.layout.BoxWithConstraints import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.WindowInsetsSides import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.only +import androidx.compose.foundation.layout.safeDrawing +import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.PagerState import androidx.compose.foundation.pager.rememberPagerState @@ -82,6 +87,7 @@ private fun UserScreenTopAppBar( Column { TopAppBar( title = { Text(stringResource(R.string.user_profile)) }, + windowInsets = AppBarDefaults.topAppBarWindowInsets, navigationIcon = { IconButton(onClick = onClickBack) { BackIcon() } }, elevation = 0.dp ) @@ -90,7 +96,12 @@ private fun UserScreenTopAppBar( val page = pagerState.targetPage BoxWithConstraints { - TabRow(selectedTabIndex = page) { + TabRow( + selectedTabIndex = page, + modifier = Modifier.windowInsetsPadding( + WindowInsets.safeDrawing.only(WindowInsetsSides.Horizontal) + ) + ) { for (tab in UserTab.entries) { val icon = painterResource(tab.iconId) val text = stringResource(tab.textId) diff --git a/app/src/main/java/de/westnordost/streetcomplete/screens/user/achievements/AchievementsScreen.kt b/app/src/main/java/de/westnordost/streetcomplete/screens/user/achievements/AchievementsScreen.kt index 08865f9edec..67e73eec71a 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/screens/user/achievements/AchievementsScreen.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/screens/user/achievements/AchievementsScreen.kt @@ -1,7 +1,13 @@ package de.westnordost.streetcomplete.screens.user.achievements import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.WindowInsetsSides +import androidx.compose.foundation.layout.asPaddingValues +import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.only +import androidx.compose.foundation.layout.safeDrawing import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.derivedStateOf @@ -15,6 +21,7 @@ import androidx.compose.ui.unit.dp import de.westnordost.streetcomplete.R import de.westnordost.streetcomplete.data.user.achievements.Achievement import de.westnordost.streetcomplete.ui.common.CenteredLargeTitleHint +import de.westnordost.streetcomplete.ui.ktx.plus /** Shows the icons for all achieved achievements and opens a dialog to show the details on click. */ @Composable @@ -25,13 +32,16 @@ fun AchievementsScreen(viewModel: AchievementsViewModel) { var showAchievement by remember { mutableStateOf?>(null) } achievements?.let { + val insets = WindowInsets.safeDrawing.only( + WindowInsetsSides.Horizontal + WindowInsetsSides.Bottom + ).asPaddingValues() LazyAchievementsGrid( achievements = it, onClickAchievement = { achievement, level -> showAchievement = achievement to level }, - modifier = Modifier.fillMaxSize(), - contentPadding = PaddingValues(16.dp) + modifier = Modifier.fillMaxSize().consumeWindowInsets(insets), + contentPadding = insets + PaddingValues(16.dp) ) } if (hasNoAchievements) { diff --git a/app/src/main/java/de/westnordost/streetcomplete/screens/user/edits/CountryStatisticsColumn.kt b/app/src/main/java/de/westnordost/streetcomplete/screens/user/edits/CountryStatisticsColumn.kt index e647b260a13..e09a5fd2c3b 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/screens/user/edits/CountryStatisticsColumn.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/screens/user/edits/CountryStatisticsColumn.kt @@ -26,6 +26,7 @@ fun CountryStatisticsColumn( flagAlignments: Map, isCurrentWeek: Boolean, modifier: Modifier = Modifier, + contentPadding: PaddingValues = PaddingValues(0.dp), ) { var showInfo by remember { mutableStateOf(null) } @@ -38,7 +39,7 @@ fun CountryStatisticsColumn( val maxCount = statistics.firstOrNull()?.count ?: 0 LazyColumn( modifier = modifier, - contentPadding = PaddingValues(top = 16.dp) + contentPadding = contentPadding ) { items(statistics) { item -> BarChartRow( diff --git a/app/src/main/java/de/westnordost/streetcomplete/screens/user/edits/EditStatisticsScreen.kt b/app/src/main/java/de/westnordost/streetcomplete/screens/user/edits/EditStatisticsScreen.kt index 195f9938c7a..656b2882c47 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/screens/user/edits/EditStatisticsScreen.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/screens/user/edits/EditStatisticsScreen.kt @@ -1,15 +1,26 @@ package de.westnordost.streetcomplete.screens.user.edits +import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.WindowInsetsSides +import androidx.compose.foundation.layout.asPaddingValues +import androidx.compose.foundation.layout.consumeWindowInsets +import androidx.compose.foundation.layout.only import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.safeDrawing +import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.material.AppBarDefaults +import androidx.compose.material.MaterialTheme import androidx.compose.material.OutlinedButton import androidx.compose.material.Tab import androidx.compose.material.TabRow import androidx.compose.material.Text +import androidx.compose.material.primarySurface import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState @@ -25,6 +36,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import de.westnordost.streetcomplete.R import de.westnordost.streetcomplete.ui.common.CenteredLargeTitleHint +import de.westnordost.streetcomplete.ui.ktx.plus import kotlinx.coroutines.launch /** Shows the user's edit statistics, alternatively either grouped by edit type or by country */ @@ -55,31 +67,41 @@ fun EditStatisticsScreen( val pagerState = rememberPagerState(pageCount = { EditStatisticsTab.entries.size }) val page = pagerState.targetPage - TabRow( - selectedTabIndex = page, - modifier = Modifier.shadow(AppBarDefaults.TopAppBarElevation) - ) { - for (tab in EditStatisticsTab.entries) { - val index = tab.ordinal - Tab( - selected = page == index, - onClick = { scope.launch { pagerState.animateScrollToPage(index) } }, - text = { Text(stringResource(tab.textId)) } - ) + Box(Modifier.background(MaterialTheme.colors.primarySurface)) { + TabRow( + selectedTabIndex = page, + modifier = Modifier + .windowInsetsPadding(WindowInsets.safeDrawing.only(WindowInsetsSides.Horizontal)) + ) { + for (tab in EditStatisticsTab.entries) { + val index = tab.ordinal + Tab( + selected = page == index, + onClick = { scope.launch { pagerState.animateScrollToPage(index) } }, + text = { Text(stringResource(tab.textId)) } + ) + } } } + val insets = WindowInsets.safeDrawing.only( + WindowInsetsSides.Horizontal + WindowInsetsSides.Bottom + ).asPaddingValues() + HorizontalPager( state = pagerState, userScrollEnabled = false, verticalAlignment = Alignment.Top, - modifier = Modifier.weight(1f) + modifier = Modifier.weight(1f).consumeWindowInsets(insets) ) { p -> when (EditStatisticsTab.entries[p]) { EditStatisticsTab.ByType -> { LaunchedEffect(Unit) { viewModel.queryEditTypeStatistics() } if (editTypeStatistics != null) { - EditTypeStatisticsColumn(editTypeStatistics) + EditTypeStatisticsColumn( + statistics = editTypeStatistics, + contentPadding = insets + PaddingValues(top = 16.dp) + ) } } EditStatisticsTab.ByCountry -> { @@ -89,7 +111,8 @@ fun EditStatisticsScreen( CountryStatisticsColumn( statistics = countryStatistics, flagAlignments = alignments, - isCurrentWeek = isCurrentWeek + isCurrentWeek = isCurrentWeek, + contentPadding = insets + PaddingValues(top = 16.dp) ) } } @@ -105,17 +128,17 @@ fun EditStatisticsScreen( ) ) } - OutlinedButton( onClick = { isCurrentWeek = !isCurrentWeek }, modifier = Modifier .align(Alignment.BottomEnd) .padding(16.dp) + .windowInsetsPadding(WindowInsets.safeDrawing) ) { Text(stringResource( if (isCurrentWeek) R.string.user_profile_current_week_title else R.string.user_profile_all_time_title - ),) + )) } } } diff --git a/app/src/main/java/de/westnordost/streetcomplete/screens/user/edits/EditTypeStatisticsColumn.kt b/app/src/main/java/de/westnordost/streetcomplete/screens/user/edits/EditTypeStatisticsColumn.kt index c74cc52eed6..7dca35c9baf 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/screens/user/edits/EditTypeStatisticsColumn.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/screens/user/edits/EditTypeStatisticsColumn.kt @@ -25,6 +25,7 @@ import de.westnordost.streetcomplete.ui.theme.GrassGreen fun EditTypeStatisticsColumn( statistics: List, modifier: Modifier = Modifier, + contentPadding: PaddingValues = PaddingValues(0.dp), ) { var showInfo by remember { mutableStateOf(null) } @@ -37,7 +38,7 @@ fun EditTypeStatisticsColumn( val maxCount = statistics.firstOrNull()?.count ?: 0 LazyColumn( modifier = modifier, - contentPadding = PaddingValues(top = 16.dp) + contentPadding = contentPadding, ) { items(statistics) { item -> BarChartRow( diff --git a/app/src/main/java/de/westnordost/streetcomplete/screens/user/links/LinksScreen.kt b/app/src/main/java/de/westnordost/streetcomplete/screens/user/links/LinksScreen.kt index 269a4c5a830..d7ef5bd6e0b 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/screens/user/links/LinksScreen.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/screens/user/links/LinksScreen.kt @@ -1,7 +1,13 @@ package de.westnordost.streetcomplete.screens.user.links import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.WindowInsetsSides +import androidx.compose.foundation.layout.asPaddingValues +import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.only +import androidx.compose.foundation.layout.safeDrawing import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.derivedStateOf @@ -12,6 +18,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import de.westnordost.streetcomplete.R import de.westnordost.streetcomplete.ui.common.CenteredLargeTitleHint +import de.westnordost.streetcomplete.ui.ktx.plus /** Shows the user's unlocked links */ @Composable @@ -20,10 +27,13 @@ fun LinksScreen(viewModel: LinksViewModel) { val hasNoLinks by remember { derivedStateOf { links?.isNotEmpty() != true } } links?.let { + val insets = WindowInsets.safeDrawing.only( + WindowInsetsSides.Horizontal + WindowInsetsSides.Bottom + ).asPaddingValues() LazyGroupedLinksColumn( allLinks = it, - modifier = Modifier.fillMaxSize(), - contentPadding = PaddingValues(16.dp) + modifier = Modifier.fillMaxSize().consumeWindowInsets(insets), + contentPadding = insets + PaddingValues(16.dp) ) } if (hasNoLinks) { diff --git a/app/src/main/java/de/westnordost/streetcomplete/screens/user/login/LoginScreen.kt b/app/src/main/java/de/westnordost/streetcomplete/screens/user/login/LoginScreen.kt index eec4eea5f0a..c9b364752c4 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/screens/user/login/LoginScreen.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/screens/user/login/LoginScreen.kt @@ -4,9 +4,15 @@ import android.widget.Toast import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.WindowInsetsSides 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.safeDrawing +import androidx.compose.foundation.layout.windowInsetsPadding +import androidx.compose.material.AppBarDefaults import androidx.compose.material.Button import androidx.compose.material.ContentAlpha import androidx.compose.material.IconButton @@ -74,6 +80,7 @@ fun LoginScreen( Column(Modifier.fillMaxSize()) { TopAppBar( title = { Text(stringResource(R.string.user_login)) }, + windowInsets = AppBarDefaults.topAppBarWindowInsets, navigationIcon = { IconButton(onClick = onClickBack) { BackIcon() } }, ) @@ -119,7 +126,12 @@ fun LoginScreen( } } - Box(Modifier.fillMaxSize()) { + Box(Modifier + .fillMaxSize() + .windowInsetsPadding(WindowInsets.safeDrawing.only( + WindowInsetsSides.Horizontal + WindowInsetsSides.Bottom + )) + ) { if (webViewState.loadingState is LoadingState.Loading) { LinearProgressIndicator(Modifier.fillMaxWidth()) } diff --git a/app/src/main/java/de/westnordost/streetcomplete/screens/user/profile/ProfileScreen.kt b/app/src/main/java/de/westnordost/streetcomplete/screens/user/profile/ProfileScreen.kt index ac52e893762..86a5dbc1b1f 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/screens/user/profile/ProfileScreen.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/screens/user/profile/ProfileScreen.kt @@ -9,10 +9,15 @@ import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.foundation.layout.FlowRow import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.WindowInsetsSides import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.only import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.safeDrawing import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll @@ -67,7 +72,10 @@ fun ProfileScreen(viewModel: ProfileViewModel) { Column( modifier = Modifier .verticalScroll(rememberScrollState()) - .padding(16.dp), + .padding(16.dp) + .windowInsetsPadding(WindowInsets.safeDrawing.only( + WindowInsetsSides.Horizontal + WindowInsetsSides.Bottom + )), verticalArrangement = Arrangement.spacedBy(16.dp), ) { // Basic user info diff --git a/app/src/main/java/de/westnordost/streetcomplete/ui/ktx/PaddingValues.kt b/app/src/main/java/de/westnordost/streetcomplete/ui/ktx/PaddingValues.kt new file mode 100644 index 00000000000..3dc956173da --- /dev/null +++ b/app/src/main/java/de/westnordost/streetcomplete/ui/ktx/PaddingValues.kt @@ -0,0 +1,11 @@ +package de.westnordost.streetcomplete.ui.ktx + +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.ui.unit.LayoutDirection.Ltr + +operator fun PaddingValues.plus(other: PaddingValues): PaddingValues = PaddingValues.Absolute( + left = calculateLeftPadding(Ltr) + other.calculateLeftPadding(Ltr), + top = calculateTopPadding() + other.calculateTopPadding(), + right = calculateRightPadding(Ltr) + other.calculateRightPadding(Ltr), + bottom = calculateBottomPadding() + other.calculateBottomPadding(), +) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 132fd47610a..56bb1692d11 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -7,9 +7,9 @@ dependencies { implementation("com.beust:klaxon:5.6") implementation("de.westnordost:countryboundaries:2.1") implementation("com.esotericsoftware.yamlbeans:yamlbeans:1.17") - implementation("org.jsoup:jsoup:1.18.1") + implementation("org.jsoup:jsoup:1.18.3") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3") - implementation("com.charleskorn.kaml:kaml:0.61.0") + implementation("com.charleskorn.kaml:kaml:0.67.0") implementation("org.jetbrains:markdown:0.7.3") }