From fba6c4a8dff3d8ddbfcd76e6c4de0609dce796a0 Mon Sep 17 00:00:00 2001 From: Rahul Patel Date: Wed, 6 May 2026 05:24:10 +0530 Subject: [PATCH] compose: add scroll hint to all lazy columns + improve padding --- .../aurora/store/compose/composable/Header.kt | 13 +- .../aurora/store/compose/composable/Info.kt | 4 +- .../compose/ui/blacklist/BlacklistScreen.kt | 77 ++++--- .../compose/ui/details/AppDetailsScreen.kt | 194 +++++++++++------- .../store/compose/ui/details/ExodusScreen.kt | 66 +++--- .../store/compose/ui/details/MoreScreen.kt | 74 ++++--- .../compose/ui/details/PermissionScreen.kt | 64 +++--- .../store/compose/ui/details/ReviewScreen.kt | 48 +++-- .../compose/ui/details/composable/Actions.kt | 6 +- .../ui/details/composable/Changelog.kt | 29 ++- .../compose/ui/details/composable/Details.kt | 6 +- .../ui/details/composable/RatingAndReviews.kt | 9 +- .../ui/details/composable/Screenshots.kt | 6 +- .../compose/ui/details/composable/Tags.kt | 2 + .../compose/ui/details/composable/Testing.kt | 5 +- .../compose/ui/downloads/DownloadsScreen.kt | 49 +++-- .../compose/ui/favourite/FavouriteScreen.kt | 43 ++-- .../compose/ui/installed/InstalledScreen.kt | 37 +++- .../store/compose/ui/search/SearchScreen.kt | 40 +++- 19 files changed, 507 insertions(+), 265 deletions(-) diff --git a/app/src/main/java/com/aurora/store/compose/composable/Header.kt b/app/src/main/java/com/aurora/store/compose/composable/Header.kt index ad72517f4..9bda7ea90 100644 --- a/app/src/main/java/com/aurora/store/compose/composable/Header.kt +++ b/app/src/main/java/com/aurora/store/compose/composable/Header.kt @@ -11,14 +11,12 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource @@ -46,18 +44,16 @@ fun Header( Row( modifier = modifier .fillMaxWidth() - .clip(RoundedCornerShape(dimensionResource(R.dimen.radius_small))) .clickable(onClick = { if (onClick != null) onClick() }, enabled = onClick != null) .padding( - horizontal = dimensionResource(R.dimen.padding_small), - vertical = dimensionResource(R.dimen.padding_xxsmall) + horizontal = dimensionResource(R.dimen.padding_medium), + vertical = dimensionResource(R.dimen.padding_xsmall) ), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically ) { Column( - modifier = Modifier.weight(1F), - verticalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.padding_xsmall)) + modifier = Modifier.weight(1F) ) { Text( text = title, @@ -68,7 +64,8 @@ fun Header( if (!subtitle.isNullOrBlank()) { Text( text = subtitle, - style = MaterialTheme.typography.bodyMedium + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant ) } } diff --git a/app/src/main/java/com/aurora/store/compose/composable/Info.kt b/app/src/main/java/com/aurora/store/compose/composable/Info.kt index 80e684f20..0800f2df3 100644 --- a/app/src/main/java/com/aurora/store/compose/composable/Info.kt +++ b/app/src/main/java/com/aurora/store/compose/composable/Info.kt @@ -56,7 +56,7 @@ fun Info( .fillMaxWidth() .clickable(onClick = { if (onClick != null) onClick() }, enabled = onClick != null) .padding( - horizontal = dimensionResource(R.dimen.padding_small), + horizontal = dimensionResource(R.dimen.padding_medium), vertical = dimensionResource(R.dimen.padding_xxsmall) ), horizontalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_normal)), @@ -75,7 +75,7 @@ fun Info( Text( text = description, style = MaterialTheme.typography.bodySmall, - color = MaterialTheme.colorScheme.secondary + color = MaterialTheme.colorScheme.onSurfaceVariant ) } } diff --git a/app/src/main/java/com/aurora/store/compose/ui/blacklist/BlacklistScreen.kt b/app/src/main/java/com/aurora/store/compose/ui/blacklist/BlacklistScreen.kt index 148e2ddb6..d83ac2820 100644 --- a/app/src/main/java/com/aurora/store/compose/ui/blacklist/BlacklistScreen.kt +++ b/app/src/main/java/com/aurora/store/compose/ui/blacklist/BlacklistScreen.kt @@ -10,10 +10,14 @@ import android.net.Uri import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.text.input.clearText import androidx.compose.foundation.text.input.rememberTextFieldState import androidx.compose.foundation.text.input.setTextAndPlaceCursorAtEnd @@ -30,6 +34,7 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.snapshotFlow +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusRequester @@ -40,6 +45,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewWrapper +import androidx.compose.ui.unit.dp import androidx.core.content.pm.PackageInfoCompat import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle @@ -47,6 +53,7 @@ import com.aurora.Constants import com.aurora.extensions.toast import com.aurora.store.R import com.aurora.store.compose.composable.BlackListItem +import com.aurora.store.compose.composable.ScrollHint import com.aurora.store.compose.preview.ThemePreviewProvider import com.aurora.store.compose.ui.blacklist.menu.BlacklistMenu import com.aurora.store.compose.ui.blacklist.menu.MenuItem @@ -209,35 +216,51 @@ private fun ScreenContent( ) } - Scaffold(topBar = { SearchBar() }) { paddingValues -> - LazyColumn( - modifier = Modifier - .fillMaxWidth() - .padding(paddingValues), - verticalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_xxsmall)) - ) { - items(items = packages ?: emptyList(), key = { p -> p.packageName.hashCode() }) { pkg -> - val isBlacklisted = isPackageBlacklisted(pkg.packageName) - val isFiltered = isPackageFiltered(pkg) - BlackListItem( - icon = PackageUtil.getIconForPackage(context, pkg.packageName)!!, - displayName = pkg.applicationInfo!!.loadLabel( - context.packageManager - ).toString(), - packageName = pkg.packageName, - versionName = pkg.versionName!!, - versionCode = PackageInfoCompat.getLongVersionCode(pkg), - isChecked = isBlacklisted || isFiltered, - isEnabled = !isFiltered, - onClick = { - if (isBlacklisted) { - onWhitelist(pkg.packageName) - } else { - onBlacklist(pkg.packageName) - } - } + Scaffold( + modifier = Modifier.navigationBarsPadding(), + topBar = { SearchBar() } + ) { paddingValues -> + val listState = rememberLazyListState() + Box(modifier = Modifier.fillMaxSize()) { + LazyColumn( + modifier = Modifier + .fillMaxWidth() + .padding(paddingValues), + state = listState, + verticalArrangement = Arrangement.spacedBy( + dimensionResource(R.dimen.margin_xxsmall) ) + ) { + items(items = packages ?: emptyList(), key = { p -> + p.packageName.hashCode() + }) { pkg -> + val isBlacklisted = isPackageBlacklisted(pkg.packageName) + val isFiltered = isPackageFiltered(pkg) + BlackListItem( + icon = PackageUtil.getIconForPackage(context, pkg.packageName)!!, + displayName = pkg.applicationInfo!!.loadLabel( + context.packageManager + ).toString(), + packageName = pkg.packageName, + versionName = pkg.versionName!!, + versionCode = PackageInfoCompat.getLongVersionCode(pkg), + isChecked = isBlacklisted || isFiltered, + isEnabled = !isFiltered, + onClick = { + if (isBlacklisted) { + onWhitelist(pkg.packageName) + } else { + onBlacklist(pkg.packageName) + } + } + ) + } } + ScrollHint( + listState = listState, + bottomPadding = 5.dp, + modifier = Modifier.align(Alignment.BottomCenter) + ) } } } diff --git a/app/src/main/java/com/aurora/store/compose/ui/details/AppDetailsScreen.kt b/app/src/main/java/com/aurora/store/compose/ui/details/AppDetailsScreen.kt index 568c680f4..267d69eef 100644 --- a/app/src/main/java/com/aurora/store/compose/ui/details/AppDetailsScreen.kt +++ b/app/src/main/java/com/aurora/store/compose/ui/details/AppDetailsScreen.kt @@ -12,14 +12,15 @@ import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.togetherWith import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll +import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material3.Icon import androidx.compose.material3.Scaffold import androidx.compose.material3.adaptive.WindowAdaptiveInfo @@ -49,6 +50,7 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewScreenSizes import androidx.compose.ui.tooling.preview.PreviewWrapper +import androidx.compose.ui.unit.dp import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation3.runtime.NavKey @@ -65,6 +67,7 @@ import com.aurora.store.R import com.aurora.store.compose.composable.ContainedLoadingIndicator import com.aurora.store.compose.composable.Error import com.aurora.store.compose.composable.Header +import com.aurora.store.compose.composable.ScrollHint import com.aurora.store.compose.composable.TopAppBar import com.aurora.store.compose.composable.app.LargeAppListItem import com.aurora.store.compose.navigation.Screen @@ -163,7 +166,7 @@ fun AppDetailsScreen( PackageUtil.getLaunchIntent(context, packageName) ) } catch (_: ActivityNotFoundException) { - context.toast(context.getString(R.string.unable_to_open)) + context.toast(R.string.unable_to_open) } }, onTestingSubscriptionChange = { subscribe -> @@ -390,6 +393,7 @@ private fun ScreenContentApp( @Composable fun MainPane() { Scaffold( + modifier = Modifier.navigationBarsPadding(), topBar = { TopAppBar( onNavigateUp = onNavigateUp, @@ -397,81 +401,123 @@ private fun ScreenContentApp( ) } ) { paddingValues -> - Column( - modifier = Modifier - .padding(paddingValues) - .fillMaxSize() - .verticalScroll(rememberScrollState()) - .padding(dimensionResource(R.dimen.padding_medium)), - verticalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_medium)) - ) { - Details( - app = app, - state = state, - onNavigateToDetailsDevProfile = { showExtraPane(Screen.DevProfile(it)) } - ) - - SetupActions() - - Tags(app = app) - Changelog(changelog = app.changes) - Header( - title = stringResource(R.string.details_more_about_app), - subtitle = app.shortDescription, - onClick = { showExtraPane(ExtraScreen.More) } - ) - - Screenshots( - screenshots = app.screenshots, - onNavigateToScreenshot = { showExtraPane(ExtraScreen.Screenshot(it)) } - ) - - RatingAndReviews( - rating = app.rating, - featuredReviews = featuredReviews, - onNavigateToDetailsReview = { showExtraPane(ExtraScreen.Review) } - ) - - if (!isAnonymous && app.testingProgram?.isAvailable == true) { - Testing( - isSubscribed = app.testingProgram!!.isSubscribed, - onTestingSubscriptionChange = onTestingSubscriptionChange - ) - } - - Compatibility(needsGms = app.requiresGMS(), plexusScores = plexusScores) - - Header( - title = stringResource(R.string.details_permission), - subtitle = if (app.permissions.isNotEmpty()) { - stringResource(R.string.permissions_requested, app.permissions.size) - } else { - stringResource(R.string.details_no_permission) - }, - onClick = if (app.permissions.isNotEmpty()) { - { showExtraPane(ExtraScreen.Permission) } - } else { - null + val listState = rememberLazyListState() + Box(modifier = Modifier.fillMaxSize()) { + LazyColumn( + modifier = Modifier + .padding(paddingValues) + .fillMaxSize(), + verticalArrangement = Arrangement.spacedBy( + dimensionResource(R.dimen.margin_medium) + ), + state = listState + ) { + item { + Details( + app = app, + state = state, + onNavigateToDetailsDevProfile = { showExtraPane(Screen.DevProfile(it)) } + ) } - ) - if (dataSafetyReport != null) { - DataSafety(report = dataSafetyReport, privacyPolicyUrl = app.privacyPolicyUrl) - } - - Privacy( - report = exodusReport, - onNavigateToDetailsExodus = if (exodusReport != null && exodusReport.id != -1) { - { showExtraPane(ExtraScreen.Exodus) } - } else { - null + item { + SetupActions() } - ) - DeveloperDetails( - address = app.developerAddress, - website = app.developerWebsite, - email = app.developerEmail + item { + Tags(app = app) + } + + item { + Changelog(changelog = app.changes) + } + + item { + Header( + title = stringResource(R.string.details_more_about_app), + subtitle = app.shortDescription, + onClick = { showExtraPane(ExtraScreen.More) } + ) + } + + item { + Screenshots( + screenshots = app.screenshots, + onNavigateToScreenshot = { showExtraPane(ExtraScreen.Screenshot(it)) } + ) + } + + item { + RatingAndReviews( + rating = app.rating, + featuredReviews = featuredReviews, + onNavigateToDetailsReview = { showExtraPane(ExtraScreen.Review) } + ) + } + + item { + if (!isAnonymous && app.testingProgram?.isAvailable == true) { + Testing( + isSubscribed = app.testingProgram!!.isSubscribed, + onTestingSubscriptionChange = onTestingSubscriptionChange + ) + } + } + + item { + Compatibility(needsGms = app.requiresGMS(), plexusScores = plexusScores) + } + + item { + Header( + title = stringResource(R.string.details_permission), + subtitle = if (app.permissions.isNotEmpty()) { + stringResource(R.string.permissions_requested, app.permissions.size) + } else { + stringResource(R.string.details_no_permission) + }, + onClick = if (app.permissions.isNotEmpty()) { + { showExtraPane(ExtraScreen.Permission) } + } else { + null + } + ) + } + + item { + if (dataSafetyReport != null) { + DataSafety( + report = dataSafetyReport, + privacyPolicyUrl = app.privacyPolicyUrl + ) + } + } + + item { + Privacy( + report = exodusReport, + onNavigateToDetailsExodus = if (exodusReport != null && + exodusReport.id != -1 + ) { + { showExtraPane(ExtraScreen.Exodus) } + } else { + null + } + ) + } + + item { + DeveloperDetails( + address = app.developerAddress, + website = app.developerWebsite, + email = app.developerEmail + ) + } + } + ScrollHint( + listState = listState, + bottomPadding = 5.dp, + modifier = Modifier.align(Alignment.BottomCenter) ) } } diff --git a/app/src/main/java/com/aurora/store/compose/ui/details/ExodusScreen.kt b/app/src/main/java/com/aurora/store/compose/ui/details/ExodusScreen.kt index 895193be6..81eef1603 100644 --- a/app/src/main/java/com/aurora/store/compose/ui/details/ExodusScreen.kt +++ b/app/src/main/java/com/aurora/store/compose/ui/details/ExodusScreen.kt @@ -5,11 +5,14 @@ package com.aurora.store.compose.ui.details +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.Icon import androidx.compose.material3.Scaffold @@ -19,6 +22,7 @@ import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.dimensionResource @@ -27,6 +31,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewWrapper +import androidx.compose.ui.unit.dp import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.aurora.Constants.EXODUS_REPORT_URL @@ -38,6 +43,7 @@ import com.aurora.gplayapi.data.models.App import com.aurora.store.R import com.aurora.store.compose.composable.Error import com.aurora.store.compose.composable.Header +import com.aurora.store.compose.composable.ScrollHint import com.aurora.store.compose.composable.TopAppBar import com.aurora.store.compose.composable.details.ExodusListItem import com.aurora.store.compose.preview.AppPreviewProvider @@ -103,6 +109,7 @@ private fun ScreenContentReport( val context = LocalContext.current Scaffold( + modifier = Modifier.navigationBarsPadding(), topBar = { TopAppBar( title = topAppBarTitle, @@ -119,33 +126,42 @@ private fun ScreenContentReport( } } ) { paddingValues -> - LazyColumn( - modifier = Modifier - .padding(paddingValues) - .fillMaxSize() - .padding(horizontal = dimensionResource(R.dimen.padding_medium)) - ) { - stickyHeader { - Surface(modifier = Modifier.fillMaxWidth()) { - Header( - title = if (report?.trackers.isNullOrEmpty()) { - stringResource(R.string.exodus_no_tracker) - } else { - stringResource( - R.string.exodus_report_trackers, - report.trackers.size, - report.version - ) - }, - subtitle = stringResource(R.string.exodus_view_report), - onClick = { context.browse(EXODUS_REPORT_URL + report!!.id) } - ) + val listState = rememberLazyListState() + Box(modifier = Modifier.fillMaxSize()) { + LazyColumn( + modifier = Modifier + .padding(paddingValues) + .fillMaxSize() + .padding(horizontal = dimensionResource(R.dimen.padding_medium)), + state = listState + ) { + stickyHeader { + Surface(modifier = Modifier.fillMaxWidth()) { + Header( + title = if (report?.trackers.isNullOrEmpty()) { + stringResource(R.string.exodus_no_tracker) + } else { + stringResource( + R.string.exodus_report_trackers, + report.trackers.size, + report.version + ) + }, + subtitle = stringResource(R.string.exodus_view_report), + onClick = { context.browse(EXODUS_REPORT_URL + report!!.id) } + ) + } + } + + items(items = trackers, key = { item -> item.id }) { tracker -> + ExodusListItem(tracker = tracker) } } - - items(items = trackers, key = { item -> item.id }) { tracker -> - ExodusListItem(tracker = tracker) - } + ScrollHint( + listState = listState, + bottomPadding = 5.dp, + modifier = Modifier.align(Alignment.BottomCenter) + ) } } } diff --git a/app/src/main/java/com/aurora/store/compose/ui/details/MoreScreen.kt b/app/src/main/java/com/aurora/store/compose/ui/details/MoreScreen.kt index 0d2653f53..c63f14b70 100644 --- a/app/src/main/java/com/aurora/store/compose/ui/details/MoreScreen.kt +++ b/app/src/main/java/com/aurora/store/compose/ui/details/MoreScreen.kt @@ -6,14 +6,15 @@ package com.aurora.store.compose.ui.details import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.items -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll +import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.Text @@ -21,6 +22,7 @@ import androidx.compose.material3.adaptive.WindowAdaptiveInfo import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalLocale import androidx.compose.ui.res.dimensionResource @@ -30,6 +32,7 @@ import androidx.compose.ui.text.fromHtml import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewWrapper +import androidx.compose.ui.unit.dp import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.aurora.extensions.adaptiveNavigationIcon @@ -38,6 +41,7 @@ import com.aurora.gplayapi.data.models.App import com.aurora.store.R import com.aurora.store.compose.composable.Header import com.aurora.store.compose.composable.Info +import com.aurora.store.compose.composable.ScrollHint import com.aurora.store.compose.composable.TopAppBar import com.aurora.store.compose.composable.app.AppListItem import com.aurora.store.compose.preview.AppPreviewProvider @@ -83,6 +87,7 @@ private fun ScreenContent( } Scaffold( + modifier = Modifier.navigationBarsPadding(), topBar = { TopAppBar( title = topAppBarTitle, @@ -91,30 +96,49 @@ private fun ScreenContent( ) } ) { paddingValues -> - Column( - modifier = Modifier - .padding(paddingValues) - .fillMaxSize() - .verticalScroll(rememberScrollState()), - verticalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_medium)) - ) { - Header(title = stringResource(R.string.details_description)) - Text( - modifier = Modifier.padding(horizontal = dimensionResource(R.dimen.padding_medium)), - text = AnnotatedString.fromHtml( - htmlString = app.description - ), - style = MaterialTheme.typography.bodyMedium - ) + val listState = rememberLazyListState() + Box(modifier = Modifier.fillMaxSize()) { + LazyColumn( + modifier = Modifier + .padding(paddingValues) + .fillMaxSize(), + state = listState, + verticalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_medium)) + ) { + item { + Header(title = stringResource(R.string.details_description)) + } - if (dependencies != null) { - AppDependencies( - dependencies = dependencies, - onNavigateToAppDetails = onNavigateToAppDetails - ) + item { + Text( + modifier = Modifier.padding( + horizontal = dimensionResource(R.dimen.padding_medium) + ), + text = AnnotatedString.fromHtml( + htmlString = app.description + ), + style = MaterialTheme.typography.bodyMedium + ) + } + + item { + if (dependencies != null) { + AppDependencies( + dependencies = dependencies, + onNavigateToAppDetails = onNavigateToAppDetails + ) + } + } + + item { + AppInfoMore(app = app) + } } - - AppInfoMore(app = app) + ScrollHint( + listState = listState, + bottomPadding = 5.dp, + modifier = Modifier.align(Alignment.BottomCenter) + ) } } } diff --git a/app/src/main/java/com/aurora/store/compose/ui/details/PermissionScreen.kt b/app/src/main/java/com/aurora/store/compose/ui/details/PermissionScreen.kt index 39ea6ec20..fd55dce7b 100644 --- a/app/src/main/java/com/aurora/store/compose/ui/details/PermissionScreen.kt +++ b/app/src/main/java/com/aurora/store/compose/ui/details/PermissionScreen.kt @@ -7,15 +7,19 @@ package com.aurora.store.compose.ui.details import android.content.pm.PermissionInfo import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material3.Scaffold import androidx.compose.material3.adaptive.WindowAdaptiveInfo import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalLocale @@ -25,6 +29,7 @@ import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewWrapper +import androidx.compose.ui.unit.dp import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.aurora.extensions.adaptiveNavigationIcon @@ -32,6 +37,7 @@ import com.aurora.extensions.isWindowCompact import com.aurora.gplayapi.data.models.App import com.aurora.store.R import com.aurora.store.compose.composable.Info +import com.aurora.store.compose.composable.ScrollHint import com.aurora.store.compose.composable.TopAppBar import com.aurora.store.compose.preview.AppPreviewProvider import com.aurora.store.compose.preview.ThemePreviewProvider @@ -76,6 +82,7 @@ private fun ScreenContent( val packageManager = LocalContext.current.packageManager Scaffold( + modifier = Modifier.navigationBarsPadding(), topBar = { TopAppBar( title = topAppBarTitle, @@ -84,34 +91,43 @@ private fun ScreenContent( ) } ) { paddingValues -> - LazyColumn( - modifier = Modifier - .padding(paddingValues) - .fillMaxSize() - .padding(horizontal = dimensionResource(R.dimen.padding_medium)), - verticalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_medium)) - ) { - items(items = permissionsInfo.keys.toList(), key = { it }) { permission -> - val permissionInfo = permissionsInfo.getValue(permission) + val listState = rememberLazyListState() + Box(modifier = Modifier.fillMaxSize()) { + LazyColumn( + modifier = Modifier + .padding(paddingValues) + .fillMaxSize() + .padding(horizontal = dimensionResource(R.dimen.padding_medium)), + state = listState, + verticalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_medium)) + ) { + items(items = permissionsInfo.keys.toList(), key = { it }) { permission -> + val permissionInfo = permissionsInfo.getValue(permission) - Info( - title = AnnotatedString( - text = permissionInfo.loadLabel(packageManager) - .toString() - .replaceFirstChar { - if (it.isLowerCase()) { - it.titlecase(LocalLocale.current.platformLocale) - } else { - it.toString() + Info( + title = AnnotatedString( + text = permissionInfo.loadLabel(packageManager) + .toString() + .replaceFirstChar { + if (it.isLowerCase()) { + it.titlecase(LocalLocale.current.platformLocale) + } else { + it.toString() + } } - } - ), - description = AnnotatedString( - text = permissionInfo.loadDescription(packageManager)?.toString() - ?: stringResource(R.string.no_description) + ), + description = AnnotatedString( + text = permissionInfo.loadDescription(packageManager)?.toString() + ?: stringResource(R.string.no_description) + ) ) - ) + } } + ScrollHint( + listState = listState, + bottomPadding = 5.dp, + modifier = Modifier.align(Alignment.BottomCenter) + ) } } } diff --git a/app/src/main/java/com/aurora/store/compose/ui/details/ReviewScreen.kt b/app/src/main/java/com/aurora/store/compose/ui/details/ReviewScreen.kt index 0cf2c4f01..6c300045a 100644 --- a/app/src/main/java/com/aurora/store/compose/ui/details/ReviewScreen.kt +++ b/app/src/main/java/com/aurora/store/compose/ui/details/ReviewScreen.kt @@ -6,13 +6,17 @@ package com.aurora.store.compose.ui.details import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material3.FilterChip import androidx.compose.material3.Icon import androidx.compose.material3.Scaffold @@ -24,6 +28,7 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.res.painterResource @@ -31,6 +36,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewWrapper +import androidx.compose.ui.unit.dp import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.paging.LoadState @@ -45,6 +51,7 @@ import com.aurora.gplayapi.data.models.Review import com.aurora.store.R import com.aurora.store.compose.composable.ContainedLoadingIndicator import com.aurora.store.compose.composable.Error +import com.aurora.store.compose.composable.ScrollHint import com.aurora.store.compose.composable.TopAppBar import com.aurora.store.compose.composable.details.ReviewListItem import com.aurora.store.compose.preview.ReviewPreviewProvider @@ -92,22 +99,23 @@ private fun ScreenContent( windowAdaptiveInfo: WindowAdaptiveInfo = currentWindowAdaptiveInfo() ) { Scaffold( + modifier = Modifier.navigationBarsPadding(), topBar = { - TopAppBar( - title = topAppBarTitle, - navigationIcon = windowAdaptiveInfo.adaptiveNavigationIcon, - onNavigateUp = onNavigateUp - ) + Column { + TopAppBar( + title = topAppBarTitle, + navigationIcon = windowAdaptiveInfo.adaptiveNavigationIcon, + onNavigateUp = onNavigateUp + ) + FilterHeader { filter -> onFilter(filter) } + } } ) { paddingValues -> Column( modifier = Modifier .padding(paddingValues) .fillMaxSize() - .padding(horizontal = dimensionResource(R.dimen.padding_medium)) ) { - FilterHeader { filter -> onFilter(filter) } - when (reviews.loadState.refresh) { is LoadState.Loading -> ContainedLoadingIndicator() @@ -120,13 +128,24 @@ private fun ScreenContent( } else -> { - LazyColumn(modifier = Modifier.fillMaxSize()) { - items( - count = reviews.itemCount, - key = reviews.itemKey { it.commentId } - ) { index -> - reviews[index]?.let { review -> ReviewListItem(review = review) } + val listState = rememberLazyListState() + Box(modifier = Modifier.fillMaxSize()) { + LazyColumn( + modifier = Modifier.fillMaxSize(), + state = listState + ) { + items( + count = reviews.itemCount, + key = reviews.itemKey { it.commentId } + ) { index -> + reviews[index]?.let { review -> ReviewListItem(review = review) } + } } + ScrollHint( + listState = listState, + bottomPadding = 5.dp, + modifier = Modifier.align(Alignment.BottomCenter) + ) } } } @@ -155,6 +174,7 @@ private fun FilterHeader(onClick: (filter: Review.Filter) -> Unit) { LazyRow( modifier = Modifier.fillMaxWidth(), + contentPadding = PaddingValues(horizontal = dimensionResource(R.dimen.margin_normal)), horizontalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_normal)) ) { items(items = filters.keys.toList(), key = { item -> item }) { filter -> diff --git a/app/src/main/java/com/aurora/store/compose/ui/details/composable/Actions.kt b/app/src/main/java/com/aurora/store/compose/ui/details/composable/Actions.kt index a352b27ba..f374409a4 100644 --- a/app/src/main/java/com/aurora/store/compose/ui/details/composable/Actions.kt +++ b/app/src/main/java/com/aurora/store/compose/ui/details/composable/Actions.kt @@ -7,8 +7,10 @@ package com.aurora.store.compose.ui.details.composable 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.fillMaxWidth +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.widthIn import androidx.compose.material3.Button import androidx.compose.material3.FilledTonalButton @@ -48,7 +50,9 @@ fun Actions( windowAdaptiveInfo: WindowAdaptiveInfo = currentWindowAdaptiveInfo() ) { Row( - modifier = Modifier.fillMaxWidth(), + modifier = Modifier + .fillMaxWidth() + .padding(PaddingValues(horizontal = dimensionResource(R.dimen.padding_medium))), horizontalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.padding_medium)) ) { val buttonWidthModifier = when { diff --git a/app/src/main/java/com/aurora/store/compose/ui/details/composable/Changelog.kt b/app/src/main/java/com/aurora/store/compose/ui/details/composable/Changelog.kt index 910db28d6..017112d85 100644 --- a/app/src/main/java/com/aurora/store/compose/ui/details/composable/Changelog.kt +++ b/app/src/main/java/com/aurora/store/compose/ui/details/composable/Changelog.kt @@ -41,18 +41,27 @@ fun Changelog(changelog: String) { Box( modifier = Modifier .fillMaxWidth() - .clip(RoundedCornerShape(dimensionResource(R.dimen.radius_small))) - .background(color = MaterialTheme.colorScheme.secondaryContainer) .padding(dimensionResource(R.dimen.padding_medium)) ) { - Text( - text = if (changelog.isBlank()) { - AnnotatedString(text = stringResource(R.string.details_changelog_unavailable)) - } else { - AnnotatedString.fromHtml(htmlString = changelog) - }, - style = MaterialTheme.typography.bodyMedium - ) + Box( + modifier = Modifier + .fillMaxWidth() + .clip(RoundedCornerShape(dimensionResource(R.dimen.radius_small))) + .background(color = MaterialTheme.colorScheme.secondaryContainer) + .padding( + horizontal = dimensionResource(R.dimen.padding_medium), + vertical = dimensionResource(R.dimen.padding_small) + ) + ) { + Text( + text = if (changelog.isBlank()) { + AnnotatedString(text = stringResource(R.string.details_changelog_unavailable)) + } else { + AnnotatedString.fromHtml(htmlString = changelog) + }, + style = MaterialTheme.typography.bodyMedium + ) + } } } diff --git a/app/src/main/java/com/aurora/store/compose/ui/details/composable/Details.kt b/app/src/main/java/com/aurora/store/compose/ui/details/composable/Details.kt index bfb4bf8a7..7449d3b99 100644 --- a/app/src/main/java/com/aurora/store/compose/ui/details/composable/Details.kt +++ b/app/src/main/java/com/aurora/store/compose/ui/details/composable/Details.kt @@ -105,7 +105,11 @@ fun Details( ) } - Row(modifier = Modifier.fillMaxWidth()) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(dimensionResource(R.dimen.margin_medium)) + ) { AnimatedAppIcon( modifier = Modifier.requiredSize(dimensionResource(R.dimen.icon_size_large)), iconUrl = app.iconArtwork.url, diff --git a/app/src/main/java/com/aurora/store/compose/ui/details/composable/RatingAndReviews.kt b/app/src/main/java/com/aurora/store/compose/ui/details/composable/RatingAndReviews.kt index 5a5494b08..6690a9398 100644 --- a/app/src/main/java/com/aurora/store/compose/ui/details/composable/RatingAndReviews.kt +++ b/app/src/main/java/com/aurora/store/compose/ui/details/composable/RatingAndReviews.kt @@ -87,9 +87,11 @@ fun RatingAndReviews( ) Row( - modifier = Modifier.fillMaxWidth(), + modifier = Modifier + .fillMaxWidth() + .padding(dimensionResource(R.dimen.padding_medium)), verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_small)) + horizontalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_large)) ) { Column( modifier = Modifier.padding(dimensionResource(R.dimen.padding_medium)), @@ -111,7 +113,6 @@ fun RatingAndReviews( } Column( - modifier = Modifier.padding(dimensionResource(R.dimen.padding_medium)), verticalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_small)) ) { stars.reversed().fastForEach { star -> @@ -127,7 +128,7 @@ fun RatingAndReviews( val pagerState = rememberPagerState { featuredReviews.size } HorizontalPager( state = pagerState, - contentPadding = PaddingValues(dimensionResource(R.dimen.padding_large)), + contentPadding = PaddingValues(horizontal = dimensionResource(R.dimen.padding_medium)), pageSpacing = dimensionResource(R.dimen.margin_medium) ) { page -> Box( diff --git a/app/src/main/java/com/aurora/store/compose/ui/details/composable/Screenshots.kt b/app/src/main/java/com/aurora/store/compose/ui/details/composable/Screenshots.kt index 6f76d2db1..641d56f9d 100644 --- a/app/src/main/java/com/aurora/store/compose/ui/details/composable/Screenshots.kt +++ b/app/src/main/java/com/aurora/store/compose/ui/details/composable/Screenshots.kt @@ -8,6 +8,7 @@ package com.aurora.store.compose.ui.details.composable 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.height import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.items @@ -34,7 +35,10 @@ import com.aurora.store.compose.preview.ThemePreviewProvider */ @Composable fun Screenshots(screenshots: List, onNavigateToScreenshot: (index: Int) -> Unit = {}) { - LazyRow(horizontalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_small))) { + LazyRow( + contentPadding = PaddingValues(horizontal = dimensionResource(R.dimen.padding_medium)), + horizontalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_small)) + ) { items(items = screenshots, key = { artwork -> artwork.url }) { artwork -> ScreenshotListItem( modifier = Modifier diff --git a/app/src/main/java/com/aurora/store/compose/ui/details/composable/Tags.kt b/app/src/main/java/com/aurora/store/compose/ui/details/composable/Tags.kt index 86690d6d4..d48101a3e 100644 --- a/app/src/main/java/com/aurora/store/compose/ui/details/composable/Tags.kt +++ b/app/src/main/java/com/aurora/store/compose/ui/details/composable/Tags.kt @@ -8,6 +8,7 @@ package com.aurora.store.compose.ui.details.composable import android.text.format.Formatter import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.items import androidx.compose.runtime.Composable @@ -61,6 +62,7 @@ fun Tags(app: App) { ).filterKeys { it != null } LazyRow( + contentPadding = PaddingValues(horizontal = dimensionResource(R.dimen.padding_medium)), horizontalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.padding_medium)) ) { items(items = tags.keys.toList()) { label -> diff --git a/app/src/main/java/com/aurora/store/compose/ui/details/composable/Testing.kt b/app/src/main/java/com/aurora/store/compose/ui/details/composable/Testing.kt index 36b3c85a7..d3dee3293 100644 --- a/app/src/main/java/com/aurora/store/compose/ui/details/composable/Testing.kt +++ b/app/src/main/java/com/aurora/store/compose/ui/details/composable/Testing.kt @@ -9,6 +9,7 @@ import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding import androidx.compose.material3.FilledTonalButton import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -40,7 +41,9 @@ import com.aurora.store.compose.preview.ThemePreviewProvider fun Testing(isSubscribed: Boolean, onTestingSubscriptionChange: (subscribe: Boolean) -> Unit = {}) { Header(title = stringResource(R.string.details_beta)) Row( - modifier = Modifier.fillMaxWidth(), + modifier = Modifier + .fillMaxWidth() + .padding(dimensionResource(R.dimen.padding_medium)), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_small)) ) { diff --git a/app/src/main/java/com/aurora/store/compose/ui/downloads/DownloadsScreen.kt b/app/src/main/java/com/aurora/store/compose/ui/downloads/DownloadsScreen.kt index db745be2b..a7d8a68a6 100644 --- a/app/src/main/java/com/aurora/store/compose/ui/downloads/DownloadsScreen.kt +++ b/app/src/main/java/com/aurora/store/compose/ui/downloads/DownloadsScreen.kt @@ -7,16 +7,20 @@ package com.aurora.store.compose.ui.downloads import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material3.Scaffold import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.dimensionResource @@ -25,6 +29,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewWrapper +import androidx.compose.ui.unit.dp import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel import androidx.paging.LoadState import androidx.paging.PagingData @@ -38,6 +43,7 @@ import com.aurora.store.R import com.aurora.store.compose.composable.ContainedLoadingIndicator import com.aurora.store.compose.composable.DownloadListItem import com.aurora.store.compose.composable.Error +import com.aurora.store.compose.composable.ScrollHint import com.aurora.store.compose.composable.TopAppBar import com.aurora.store.compose.preview.AppPreviewProvider import com.aurora.store.compose.preview.ThemePreviewProvider @@ -124,6 +130,7 @@ private fun ScreenContent( } Scaffold( + modifier = Modifier.navigationBarsPadding(), topBar = { TopAppBar( title = stringResource(R.string.title_download_manager), @@ -153,23 +160,35 @@ private fun ScreenContent( message = stringResource(R.string.download_none) ) } else { - LazyColumn { - items( - count = downloads.itemCount, - key = downloads.itemKey { it.packageName } - ) { index -> - downloads[index]?.let { download -> - DownloadListItem( - modifier = Modifier.animateItem(), - download = download, - onClick = { onNavigateToAppDetails(download.packageName) }, - onClear = { onClear(download) }, - onCancel = { onCancel(download.packageName) }, - onExport = { onExport(download) }, - onInstall = { onInstall(download) } - ) + val listState = rememberLazyListState() + Box(modifier = Modifier.fillMaxSize()) { + LazyColumn( + state = listState + ) { + items( + count = downloads.itemCount, + key = downloads.itemKey { it.packageName } + ) { index -> + downloads[index]?.let { download -> + DownloadListItem( + modifier = Modifier.animateItem(), + download = download, + onClick = { + onNavigateToAppDetails(download.packageName) + }, + onClear = { onClear(download) }, + onCancel = { onCancel(download.packageName) }, + onExport = { onExport(download) }, + onInstall = { onInstall(download) } + ) + } } } + ScrollHint( + listState = listState, + bottomPadding = 5.dp, + modifier = Modifier.align(Alignment.BottomCenter) + ) } } } diff --git a/app/src/main/java/com/aurora/store/compose/ui/favourite/FavouriteScreen.kt b/app/src/main/java/com/aurora/store/compose/ui/favourite/FavouriteScreen.kt index cd6e9b867..c378dfb72 100644 --- a/app/src/main/java/com/aurora/store/compose/ui/favourite/FavouriteScreen.kt +++ b/app/src/main/java/com/aurora/store/compose/ui/favourite/FavouriteScreen.kt @@ -7,16 +7,20 @@ package com.aurora.store.compose.ui.favourite import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material3.Scaffold import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.dimensionResource @@ -25,6 +29,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewWrapper +import androidx.compose.ui.unit.dp import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel import androidx.paging.LoadState import androidx.paging.PagingData @@ -38,6 +43,7 @@ import com.aurora.store.R import com.aurora.store.compose.composable.ContainedLoadingIndicator import com.aurora.store.compose.composable.Error import com.aurora.store.compose.composable.FavouriteListItem +import com.aurora.store.compose.composable.ScrollHint import com.aurora.store.compose.composable.TopAppBar import com.aurora.store.compose.preview.FavouritePreviewProvider import com.aurora.store.compose.preview.ThemePreviewProvider @@ -126,6 +132,7 @@ private fun ScreenContent( } Scaffold( + modifier = Modifier.navigationBarsPadding(), topBar = { TopAppBar( title = stringResource(R.string.title_favourites_manager), @@ -155,20 +162,32 @@ private fun ScreenContent( message = stringResource(R.string.details_no_favourites) ) } else { - LazyColumn { - items( - count = favourites.itemCount, - key = favourites.itemKey { it.packageName } - ) { index -> - favourites[index]?.let { favourite -> - FavouriteListItem( - modifier = Modifier.animateItem(), - favourite = favourite, - onClick = { onNavigateToAppDetails(favourite.packageName) }, - onClear = { onRemoveFavourite(favourite.packageName) } - ) + val listState = rememberLazyListState() + Box(modifier = Modifier.fillMaxSize()) { + LazyColumn( + state = listState + ) { + items( + count = favourites.itemCount, + key = favourites.itemKey { it.packageName } + ) { index -> + favourites[index]?.let { favourite -> + FavouriteListItem( + modifier = Modifier.animateItem(), + favourite = favourite, + onClick = { + onNavigateToAppDetails(favourite.packageName) + }, + onClear = { onRemoveFavourite(favourite.packageName) } + ) + } } } + ScrollHint( + listState = listState, + bottomPadding = 5.dp, + modifier = Modifier.align(Alignment.BottomCenter) + ) } } } diff --git a/app/src/main/java/com/aurora/store/compose/ui/installed/InstalledScreen.kt b/app/src/main/java/com/aurora/store/compose/ui/installed/InstalledScreen.kt index 93cbdca6d..960601e6c 100644 --- a/app/src/main/java/com/aurora/store/compose/ui/installed/InstalledScreen.kt +++ b/app/src/main/java/com/aurora/store/compose/ui/installed/InstalledScreen.kt @@ -5,22 +5,27 @@ package com.aurora.store.compose.ui.installed +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material3.Scaffold import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewWrapper +import androidx.compose.ui.unit.dp import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel import androidx.paging.LoadState import androidx.paging.PagingData @@ -32,6 +37,7 @@ import com.aurora.gplayapi.data.models.App import com.aurora.store.R import com.aurora.store.compose.composable.ContainedLoadingIndicator import com.aurora.store.compose.composable.Error +import com.aurora.store.compose.composable.ScrollHint import com.aurora.store.compose.composable.TopAppBar import com.aurora.store.compose.composable.app.LargeAppListItem import com.aurora.store.compose.preview.AppPreviewProvider @@ -70,6 +76,7 @@ private fun ScreenContent( var initialLoad by rememberSaveable { mutableStateOf(true) } Scaffold( + modifier = Modifier.navigationBarsPadding(), topBar = { TopAppBar( title = stringResource(R.string.title_apps_games), @@ -97,18 +104,28 @@ private fun ScreenContent( message = stringResource(R.string.no_apps_available) ) } else { - LazyColumn { - items( - count = apps.itemCount, - key = apps.itemKey { it.packageName } - ) { index -> - apps[index]?.let { app -> - LargeAppListItem( - app = app, - onClick = { onNavigateToAppDetails(app.packageName) } - ) + val listState = rememberLazyListState() + Box(modifier = Modifier.fillMaxSize()) { + LazyColumn( + state = listState + ) { + items( + count = apps.itemCount, + key = apps.itemKey { it.packageName } + ) { index -> + apps[index]?.let { app -> + LargeAppListItem( + app = app, + onClick = { onNavigateToAppDetails(app.packageName) } + ) + } } } + ScrollHint( + listState = listState, + bottomPadding = 5.dp, + modifier = Modifier.align(Alignment.BottomCenter) + ) } } } diff --git a/app/src/main/java/com/aurora/store/compose/ui/search/SearchScreen.kt b/app/src/main/java/com/aurora/store/compose/ui/search/SearchScreen.kt index fdf117577..a04ced42e 100644 --- a/app/src/main/java/com/aurora/store/compose/ui/search/SearchScreen.kt +++ b/app/src/main/java/com/aurora/store/compose/ui/search/SearchScreen.kt @@ -14,10 +14,12 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.text.input.clearText import androidx.compose.foundation.text.input.rememberTextFieldState import androidx.compose.foundation.text.input.setTextAndPlaceCursorAtEnd @@ -45,6 +47,7 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.runtime.snapshotFlow +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusRequester @@ -58,6 +61,7 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewScreenSizes import androidx.compose.ui.tooling.preview.PreviewWrapper +import androidx.compose.ui.unit.dp import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.paging.LoadState @@ -70,6 +74,7 @@ import com.aurora.gplayapi.data.models.App import com.aurora.store.R import com.aurora.store.compose.composable.ContainedLoadingIndicator import com.aurora.store.compose.composable.Error +import com.aurora.store.compose.composable.ScrollHint import com.aurora.store.compose.composable.SearchSuggestionListItem import com.aurora.store.compose.composable.app.LargeAppListItem import com.aurora.store.compose.preview.AppPreviewProvider @@ -221,7 +226,9 @@ private fun ScreenContent( fun ListPane() { // TODO: https://issuetracker.google.com/issues/445720462 Scaffold( - modifier = Modifier.focusable(), + modifier = Modifier + .focusable() + .navigationBarsPadding(), topBar = { SearchBar() } ) { paddingValues -> Column( @@ -255,18 +262,29 @@ private fun ScreenContent( message = stringResource(R.string.no_apps_available) ) } else { - LazyColumn { - items( - count = results.itemCount, - key = { Uuid.random().toString() } - ) { index -> - results[index]?.let { app -> - LargeAppListItem( - app = app, - onClick = { showDetailPane(app.packageName) } - ) + val listState = rememberLazyListState() + Box(modifier = Modifier.fillMaxSize()) { + LazyColumn( + state = listState, + modifier = Modifier.fillMaxSize() + ) { + items( + count = results.itemCount, + key = { Uuid.random().toString() } + ) { index -> + results[index]?.let { app -> + LargeAppListItem( + app = app, + onClick = { showDetailPane(app.packageName) } + ) + } } } + ScrollHint( + listState = listState, + bottomPadding = 5.dp, + modifier = Modifier.align(Alignment.BottomCenter) + ) } } }