compose: details: Adjust adaptive screens based on latest alpha changes

* WindowWidthSizeClass is deprecated, switch to WindowSizeClass and breakpoints instead with flipped logic
* Specify a dragHandle and adaptStratergy for supporting pane to levitate on single pane screens

Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
This commit is contained in:
Aayush Gupta
2025-08-20 11:26:02 +08:00
parent d4179319f4
commit 94c5f90fbb
10 changed files with 99 additions and 37 deletions

View File

@@ -9,7 +9,7 @@ import androidx.compose.material3.adaptive.WindowAdaptiveInfo
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.window.core.layout.WindowWidthSizeClass import androidx.window.core.layout.WindowSizeClass
import com.aurora.store.R import com.aurora.store.R
/** /**
@@ -17,7 +17,10 @@ import com.aurora.store.R
*/ */
val WindowAdaptiveInfo.adaptiveNavigationIcon: Painter val WindowAdaptiveInfo.adaptiveNavigationIcon: Painter
@Composable @Composable
get() = when (windowSizeClass.windowWidthSizeClass) { get() = when {
WindowWidthSizeClass.COMPACT -> painterResource(R.drawable.ic_arrow_back) windowSizeClass.isWidthAtLeastBreakpoint(WindowSizeClass.WIDTH_DP_MEDIUM_LOWER_BOUND) -> {
else -> painterResource(R.drawable.ic_cancel) painterResource(R.drawable.ic_cancel)
}
else -> painterResource(R.drawable.ic_arrow_back)
} }

View File

@@ -6,6 +6,7 @@
package com.aurora.store.compose.ui.details package com.aurora.store.compose.ui.details
import android.content.ActivityNotFoundException import android.content.ActivityNotFoundException
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
@@ -16,16 +17,24 @@ import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.LocalMinimumInteractiveComponentSize
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.VerticalDragHandle
import androidx.compose.material3.adaptive.WindowAdaptiveInfo
import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo
import androidx.compose.material3.adaptive.layout.AdaptStrategy
import androidx.compose.material3.adaptive.layout.AnimatedPane import androidx.compose.material3.adaptive.layout.AnimatedPane
import androidx.compose.material3.adaptive.layout.PaneAdaptedValue import androidx.compose.material3.adaptive.layout.PaneAdaptedValue
import androidx.compose.material3.adaptive.layout.SupportingPaneScaffoldDefaults
import androidx.compose.material3.adaptive.layout.SupportingPaneScaffoldRole import androidx.compose.material3.adaptive.layout.SupportingPaneScaffoldRole
import androidx.compose.material3.adaptive.layout.calculatePaneScaffoldDirective
import androidx.compose.material3.adaptive.navigation.NavigableSupportingPaneScaffold import androidx.compose.material3.adaptive.navigation.NavigableSupportingPaneScaffold
import androidx.compose.material3.adaptive.navigation.rememberSupportingPaneScaffoldNavigator import androidx.compose.material3.adaptive.navigation.rememberSupportingPaneScaffoldNavigator
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
@@ -194,10 +203,19 @@ private fun ScreenContentApp(
onCancelDownload: () -> Unit = {}, onCancelDownload: () -> Unit = {},
onUninstall: () -> Unit = {}, onUninstall: () -> Unit = {},
onOpen: () -> Unit = {}, onOpen: () -> Unit = {},
onTestingSubscriptionChange: (subscribe: Boolean) -> Unit = {} onTestingSubscriptionChange: (subscribe: Boolean) -> Unit = {},
windowAdaptiveInfo: WindowAdaptiveInfo = currentWindowAdaptiveInfo()
) { ) {
val context = LocalContext.current val context = LocalContext.current
val scaffoldNavigator = rememberSupportingPaneScaffoldNavigator<Screen>() val scaffoldDirective = calculatePaneScaffoldDirective(windowAdaptiveInfo)
val scaffoldNavigator = rememberSupportingPaneScaffoldNavigator<Screen>(
scaffoldDirective = scaffoldDirective,
adaptStrategies = SupportingPaneScaffoldDefaults.adaptStrategies(
supportingPaneAdaptStrategy = AdaptStrategy
.Levitate()
.onlyIfSinglePane(scaffoldDirective)
)
)
val coroutineScope = rememberCoroutineScope() val coroutineScope = rememberCoroutineScope()
val shouldShowMenuOnMainPane = scaffoldNavigator val shouldShowMenuOnMainPane = scaffoldNavigator
.scaffoldValue[SupportingPaneScaffoldRole.Supporting] == PaneAdaptedValue.Hidden .scaffoldValue[SupportingPaneScaffoldRole.Supporting] == PaneAdaptedValue.Hidden
@@ -423,8 +441,12 @@ private fun ScreenContentApp(
scaffoldNavigator.currentDestination?.contentKey?.let { screen -> scaffoldNavigator.currentDestination?.contentKey?.let { screen ->
AnimatedPane { AnimatedPane {
when (screen) { when (screen) {
is Screen.DetailsReview -> DetailsReviewScreen(onNavigateUp = ::showMainPane) is Screen.DetailsReview -> DetailsReviewScreen(
is Screen.DetailsExodus -> DetailsExodusScreen(onNavigateUp = ::showMainPane) onNavigateUp = ::showMainPane
)
is Screen.DetailsExodus -> DetailsExodusScreen(
onNavigateUp = ::showMainPane
)
is Screen.DetailsMore -> DetailsMoreScreen( is Screen.DetailsMore -> DetailsMoreScreen(
onNavigateUp = ::showMainPane, onNavigateUp = ::showMainPane,
onNavigateToAppDetails = onNavigateToAppDetails onNavigateToAppDetails = onNavigateToAppDetails
@@ -449,6 +471,16 @@ private fun ScreenContentApp(
} }
} }
} }
},
paneExpansionDragHandle = { state ->
VerticalDragHandle(
modifier = Modifier.paneExpansionDraggable(
state = state,
minTouchTargetSize = LocalMinimumInteractiveComponentSize.current,
interactionSource = remember { MutableInteractionSource() }
),
interactionSource = remember { MutableInteractionSource() }
)
} }
) )
} }

View File

@@ -22,7 +22,7 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.window.core.layout.WindowWidthSizeClass import androidx.window.core.layout.WindowSizeClass
import com.aurora.Constants.EXODUS_REPORT_URL import com.aurora.Constants.EXODUS_REPORT_URL
import com.aurora.extensions.adaptiveNavigationIcon import com.aurora.extensions.adaptiveNavigationIcon
import com.aurora.extensions.browse import com.aurora.extensions.browse
@@ -49,9 +49,12 @@ fun DetailsExodusScreen(
val exodusReport by appDetailsViewModel.exodusReport.collectAsStateWithLifecycle() val exodusReport by appDetailsViewModel.exodusReport.collectAsStateWithLifecycle()
val trackers by detailsExodusViewModel.trackers.collectAsStateWithLifecycle() val trackers by detailsExodusViewModel.trackers.collectAsStateWithLifecycle()
val topAppBarTitle = when (windowAdaptiveInfo.windowSizeClass.windowWidthSizeClass) { val topAppBarTitle = when {
WindowWidthSizeClass.COMPACT -> app!!.displayName windowAdaptiveInfo.windowSizeClass.isWidthAtLeastBreakpoint(WindowSizeClass.WIDTH_DP_MEDIUM_LOWER_BOUND) -> {
else -> stringResource(R.string.details_privacy) stringResource(R.string.details_privacy)
}
else -> app!!.displayName
} }
ScreenContent( ScreenContent(

View File

@@ -43,6 +43,7 @@ import androidx.compose.ui.unit.dp
import androidx.core.text.isDigitsOnly import androidx.core.text.isDigitsOnly
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.window.core.layout.WindowSizeClass
import androidx.window.core.layout.WindowWidthSizeClass import androidx.window.core.layout.WindowWidthSizeClass
import com.aurora.extensions.adaptiveNavigationIcon import com.aurora.extensions.adaptiveNavigationIcon
import com.aurora.extensions.toast import com.aurora.extensions.toast
@@ -63,9 +64,12 @@ fun DetailsManualDownloadScreen(
val context = LocalContext.current val context = LocalContext.current
val app by viewModel.app.collectAsStateWithLifecycle() val app by viewModel.app.collectAsStateWithLifecycle()
val topAppBarTitle = when (windowAdaptiveInfo.windowSizeClass.windowWidthSizeClass) { val topAppBarTitle = when {
WindowWidthSizeClass.COMPACT -> app!!.displayName windowAdaptiveInfo.windowSizeClass.isWidthAtLeastBreakpoint(WindowSizeClass.WIDTH_DP_MEDIUM_LOWER_BOUND) -> {
else -> stringResource(R.string.title_manual_download) stringResource(R.string.title_manual_download)
}
else -> app!!.displayName
} }
LaunchedEffect(key1 = Unit) { LaunchedEffect(key1 = Unit) {

View File

@@ -31,7 +31,7 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.window.core.layout.WindowWidthSizeClass import androidx.window.core.layout.WindowSizeClass
import coil3.compose.LocalAsyncImagePreviewHandler import coil3.compose.LocalAsyncImagePreviewHandler
import com.aurora.extensions.adaptiveNavigationIcon import com.aurora.extensions.adaptiveNavigationIcon
import com.aurora.gplayapi.data.models.App import com.aurora.gplayapi.data.models.App
@@ -74,9 +74,12 @@ private fun ScreenContent(
onNavigateToAppDetails: (packageName: String) -> Unit = {}, onNavigateToAppDetails: (packageName: String) -> Unit = {},
windowAdaptiveInfo: WindowAdaptiveInfo = currentWindowAdaptiveInfo() windowAdaptiveInfo: WindowAdaptiveInfo = currentWindowAdaptiveInfo()
) { ) {
val topAppBarTitle = when (windowAdaptiveInfo.windowSizeClass.windowWidthSizeClass) { val topAppBarTitle = when {
WindowWidthSizeClass.COMPACT -> app.displayName windowAdaptiveInfo.windowSizeClass.isWidthAtLeastBreakpoint(WindowSizeClass.WIDTH_DP_MEDIUM_LOWER_BOUND) -> {
else -> stringResource(R.string.details_more_about_app) stringResource(R.string.details_more_about_app)
}
else -> app.displayName
} }
Scaffold( Scaffold(

View File

@@ -25,7 +25,7 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.window.core.layout.WindowWidthSizeClass import androidx.window.core.layout.WindowSizeClass
import com.aurora.extensions.adaptiveNavigationIcon import com.aurora.extensions.adaptiveNavigationIcon
import com.aurora.gplayapi.data.models.App import com.aurora.gplayapi.data.models.App
import com.aurora.store.R import com.aurora.store.R
@@ -48,9 +48,12 @@ fun DetailsPermissionScreen(
val app by appDetailsViewModel.app.collectAsStateWithLifecycle() val app by appDetailsViewModel.app.collectAsStateWithLifecycle()
val permissionsInfo by detailsPermissionViewModel.permissionsInfo.collectAsStateWithLifecycle() val permissionsInfo by detailsPermissionViewModel.permissionsInfo.collectAsStateWithLifecycle()
val topAppBarTitle = when (windowAdaptiveInfo.windowSizeClass.windowWidthSizeClass) { val topAppBarTitle = when {
WindowWidthSizeClass.COMPACT -> app!!.displayName windowAdaptiveInfo.windowSizeClass.isWidthAtLeastBreakpoint(WindowSizeClass.WIDTH_DP_MEDIUM_LOWER_BOUND) -> {
else -> stringResource(R.string.details_permission) stringResource(R.string.details_permission)
}
else -> app!!.displayName
} }
ScreenContent( ScreenContent(

View File

@@ -37,7 +37,7 @@ import androidx.paging.PagingData
import androidx.paging.compose.LazyPagingItems import androidx.paging.compose.LazyPagingItems
import androidx.paging.compose.collectAsLazyPagingItems import androidx.paging.compose.collectAsLazyPagingItems
import androidx.paging.compose.itemKey import androidx.paging.compose.itemKey
import androidx.window.core.layout.WindowWidthSizeClass import androidx.window.core.layout.WindowSizeClass
import coil3.compose.LocalAsyncImagePreviewHandler import coil3.compose.LocalAsyncImagePreviewHandler
import com.aurora.extensions.adaptiveNavigationIcon import com.aurora.extensions.adaptiveNavigationIcon
import com.aurora.gplayapi.data.models.Review import com.aurora.gplayapi.data.models.Review
@@ -63,9 +63,12 @@ fun DetailsReviewScreen(
val app by appDetailsViewModel.app.collectAsStateWithLifecycle() val app by appDetailsViewModel.app.collectAsStateWithLifecycle()
val reviews = detailsReviewViewModel.reviews.collectAsLazyPagingItems() val reviews = detailsReviewViewModel.reviews.collectAsLazyPagingItems()
val topAppBarTitle = when (windowAdaptiveInfo.windowSizeClass.windowWidthSizeClass) { val topAppBarTitle = when {
WindowWidthSizeClass.COMPACT -> app!!.displayName windowAdaptiveInfo.windowSizeClass.isWidthAtLeastBreakpoint(WindowSizeClass.WIDTH_DP_MEDIUM_LOWER_BOUND) -> {
else -> stringResource(R.string.details_ratings) stringResource(R.string.details_ratings)
}
else -> app!!.displayName
} }
ScreenContent( ScreenContent(

View File

@@ -21,7 +21,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.window.core.layout.WindowWidthSizeClass import androidx.window.core.layout.WindowSizeClass
import com.aurora.extensions.adaptiveNavigationIcon import com.aurora.extensions.adaptiveNavigationIcon
import com.aurora.gplayapi.data.models.Artwork import com.aurora.gplayapi.data.models.Artwork
import com.aurora.store.R import com.aurora.store.R
@@ -38,9 +38,12 @@ fun DetailsScreenshotScreen(
) { ) {
val app by viewModel.app.collectAsStateWithLifecycle() val app by viewModel.app.collectAsStateWithLifecycle()
val topAppBarTitle = when (windowAdaptiveInfo.windowSizeClass.windowWidthSizeClass) { val topAppBarTitle = when {
WindowWidthSizeClass.COMPACT -> app!!.displayName windowAdaptiveInfo.windowSizeClass.isWidthAtLeastBreakpoint(WindowSizeClass.WIDTH_DP_MEDIUM_LOWER_BOUND) -> {
else -> stringResource(R.string.details_more_about_app) stringResource(R.string.details_more_about_app)
}
else -> app!!.displayName
} }
ScreenContent( ScreenContent(

View File

@@ -21,6 +21,7 @@ import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.window.core.layout.WindowSizeClass
import androidx.window.core.layout.WindowWidthSizeClass import androidx.window.core.layout.WindowWidthSizeClass
import com.aurora.store.R import com.aurora.store.R
@@ -49,9 +50,12 @@ fun AppActions(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.padding_medium)) horizontalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.padding_medium))
) { ) {
val buttonWidthModifier = when (windowAdaptiveInfo.windowSizeClass.windowWidthSizeClass) { val buttonWidthModifier = when {
WindowWidthSizeClass.COMPACT -> Modifier.weight(1F) windowAdaptiveInfo.windowSizeClass.isWidthAtLeastBreakpoint(WindowSizeClass.WIDTH_DP_MEDIUM_LOWER_BOUND) -> {
else -> Modifier.widthIn(min = dimensionResource(R.dimen.width_button)) Modifier.widthIn(min = dimensionResource(R.dimen.width_button))
}
else -> Modifier.weight(1F)
} }
FilledTonalButton( FilledTonalButton(

View File

@@ -30,6 +30,7 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.util.fastForEach import androidx.compose.ui.util.fastForEach
import androidx.window.core.layout.WindowSizeClass
import androidx.window.core.layout.WindowWidthSizeClass import androidx.window.core.layout.WindowWidthSizeClass
import com.aurora.gplayapi.data.models.App import com.aurora.gplayapi.data.models.App
import com.aurora.gplayapi.data.models.Rating import com.aurora.gplayapi.data.models.Rating
@@ -64,9 +65,12 @@ fun AppRatingAndReviews(
if (it.sum() == 0F) return if (it.sum() == 0F) return
} }
val avgRating = when (windowAdaptiveInfo.windowSizeClass.windowWidthSizeClass) { val avgRating = when {
WindowWidthSizeClass.COMPACT -> String.format(Locale.getDefault(), "%.1f", rating.average) windowAdaptiveInfo.windowSizeClass.isWidthAtLeastBreakpoint(WindowSizeClass.WIDTH_DP_MEDIUM_LOWER_BOUND) -> {
else -> String.format(Locale.getDefault(), "%.1f / 5.0", rating.average) String.format(Locale.getDefault(), "%.1f / 5.0", rating.average)
}
else -> String.format(Locale.getDefault(), "%.1f", rating.average)
} }
HeaderComposable( HeaderComposable(