compose: details: Merge suggestions pane back into AppDetails

Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
This commit is contained in:
Aayush Gupta
2025-05-17 14:33:07 +08:00
parent 5276e70373
commit 5d0bb8b634
2 changed files with 59 additions and 117 deletions

View File

@@ -8,11 +8,15 @@ package com.aurora.store.compose.ui.details
import android.content.ActivityNotFoundException import android.content.ActivityNotFoundException
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.RowScope import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding 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.rememberScrollState
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Icon
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi import androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi
import androidx.compose.material3.adaptive.layout.AnimatedPane import androidx.compose.material3.adaptive.layout.AnimatedPane
@@ -28,9 +32,11 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
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
@@ -49,6 +55,7 @@ import com.aurora.gplayapi.data.models.Review
import com.aurora.store.R import com.aurora.store.R
import com.aurora.store.compose.composables.HeaderComposable import com.aurora.store.compose.composables.HeaderComposable
import com.aurora.store.compose.composables.TopAppBarComposable import com.aurora.store.compose.composables.TopAppBarComposable
import com.aurora.store.compose.composables.app.AppListComposable
import com.aurora.store.compose.composables.app.AppProgressComposable import com.aurora.store.compose.composables.app.AppProgressComposable
import com.aurora.store.compose.composables.app.NoAppComposable import com.aurora.store.compose.composables.app.NoAppComposable
import com.aurora.store.compose.composables.preview.AppPreviewProvider import com.aurora.store.compose.composables.preview.AppPreviewProvider
@@ -78,6 +85,7 @@ import com.aurora.store.util.PackageUtil.PACKAGE_NAME_GMS
import com.aurora.store.util.ShortcutManagerUtil import com.aurora.store.util.ShortcutManagerUtil
import com.aurora.store.viewmodel.details.AppDetailsViewModel import com.aurora.store.viewmodel.details.AppDetailsViewModel
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlin.random.Random
import com.aurora.gplayapi.data.models.datasafety.Report as DataSafetyReport import com.aurora.gplayapi.data.models.datasafety.Report as DataSafetyReport
@Composable @Composable
@@ -97,6 +105,7 @@ fun AppDetailsScreen(
val plexusScores by viewModel.plexusScores.collectAsStateWithLifecycle() val plexusScores by viewModel.plexusScores.collectAsStateWithLifecycle()
val download by viewModel.download.collectAsStateWithLifecycle() val download by viewModel.download.collectAsStateWithLifecycle()
val installProgress by viewModel.installProgress.collectAsStateWithLifecycle() val installProgress by viewModel.installProgress.collectAsStateWithLifecycle()
val suggestions by viewModel.suggestions.collectAsStateWithLifecycle()
var shouldShowManualDownloadDialog by rememberSaveable { mutableStateOf(false) } var shouldShowManualDownloadDialog by rememberSaveable { mutableStateOf(false) }
@@ -135,6 +144,7 @@ fun AppDetailsScreen(
ScreenContentApp( ScreenContentApp(
app = this, app = this,
featuredReviews = featuredReviews, featuredReviews = featuredReviews,
suggestions = suggestions,
isFavorite = favorite, isFavorite = favorite,
isAnonymous = viewModel.authProvider.isAnonymous, isAnonymous = viewModel.authProvider.isAnonymous,
download = download, download = download,
@@ -208,6 +218,7 @@ private fun ScreenContentError(onNavigateUp: () -> Unit = {}) {
private fun ScreenContentApp( private fun ScreenContentApp(
app: App, app: App,
featuredReviews: List<Review> = emptyList(), featuredReviews: List<Review> = emptyList(),
suggestions: List<App> = emptyList(),
isFavorite: Boolean = false, isFavorite: Boolean = false,
isAnonymous: Boolean = true, isAnonymous: Boolean = true,
download: Download? = null, download: Download? = null,
@@ -292,10 +303,10 @@ private fun ScreenContentApp(
}, },
supportingPane = { supportingPane = {
AnimatedPane { AnimatedPane {
DetailsSuggestions( ScreenContentAppSupporting(
onNavigateUp = null, suggestions = suggestions,
onNavigateToAppDetails = onNavigateToAppDetails, onNavigateToAppDetails = onNavigateToAppDetails,
menuActions = { SetupMenu() } menuActions = { if (!shouldShowMenuOnMainPane) SetupMenu() }
) )
} }
}, },
@@ -492,6 +503,49 @@ private fun ScreenContentAppMainPane(
} }
} }
/**
* Composable to display similar and related app suggestions
*/
@Composable
private fun ScreenContentAppSupporting(
menuActions: @Composable (RowScope.() -> Unit) = {},
suggestions: List<App> = emptyList(),
onNavigateToAppDetails: (packageName: String) -> Unit = {}
) {
Scaffold(
topBar = { TopAppBarComposable(actions = menuActions) }
) { paddingValues ->
Column(
modifier = Modifier
.fillMaxSize()
.padding(paddingValues)
) {
Row(
modifier = Modifier.padding(dimensionResource(R.dimen.margin_medium)),
verticalAlignment = Alignment.CenterVertically
) {
Icon(
painter = painterResource(R.drawable.ic_suggestions),
contentDescription = null
)
HeaderComposable(title = stringResource(R.string.pref_ui_similar_apps))
}
LazyColumn(
modifier = Modifier
.fillMaxSize()
.padding(vertical = dimensionResource(R.dimen.padding_medium))
) {
items(items = suggestions, key = { item -> item.id }) { app ->
AppListComposable(
app = app,
onClick = { onNavigateToAppDetails(app.packageName) }
)
}
}
}
}
}
@PreviewScreenSizes @PreviewScreenSizes
@Composable @Composable
@OptIn(ExperimentalCoilApi::class) @OptIn(ExperimentalCoilApi::class)
@@ -500,7 +554,8 @@ private fun AppDetailsScreenPreview(@PreviewParameter(AppPreviewProvider::class)
ScreenContentApp( ScreenContentApp(
app = app, app = app,
isAnonymous = false, isAnonymous = false,
hasValidUpdate = false hasValidUpdate = false,
suggestions = List(10) { app.copy(id = Random.nextInt()) }
) )
} }
} }

View File

@@ -1,113 +0,0 @@
/*
* SPDX-FileCopyrightText: 2025 The Calyx Institute
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package com.aurora.store.compose.ui.details
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.Icon
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.dimensionResource
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.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import coil3.annotation.ExperimentalCoilApi
import coil3.compose.LocalAsyncImagePreviewHandler
import com.aurora.gplayapi.data.models.App
import com.aurora.store.R
import com.aurora.store.compose.composables.HeaderComposable
import com.aurora.store.compose.composables.TopAppBarComposable
import com.aurora.store.compose.composables.app.AppListComposable
import com.aurora.store.compose.composables.preview.AppPreviewProvider
import com.aurora.store.compose.composables.preview.coilPreviewProvider
import com.aurora.store.viewmodel.details.AppDetailsViewModel
import kotlin.random.Random
/**
* Screen to display similar and related suggestions for an app, supposed to be used internally
* by the [AppDetailsScreen] and not navigable from other screens
*/
@Composable
fun DetailsSuggestions(
onNavigateUp: (() -> Unit)?,
menuActions: @Composable (RowScope.() -> Unit) = {},
viewModel: AppDetailsViewModel = hiltViewModel(),
onNavigateToAppDetails: (packageName: String) -> Unit
) {
val suggestions by viewModel.suggestions.collectAsStateWithLifecycle()
ScreenContent(
onNavigateUp = onNavigateUp,
menuActions = menuActions,
suggestions = suggestions,
onNavigateToAppDetails = onNavigateToAppDetails
)
}
@Composable
private fun ScreenContent(
onNavigateUp: (() -> Unit)? = {},
menuActions: @Composable (RowScope.() -> Unit) = {},
suggestions: List<App> = emptyList(),
onNavigateToAppDetails: (packageName: String) -> Unit = {}
) {
Scaffold(
topBar = { TopAppBarComposable(onNavigateUp = onNavigateUp, actions = menuActions) }
) { paddingValues ->
Column(
modifier = Modifier
.fillMaxSize()
.padding(paddingValues)
) {
Row(
modifier = Modifier.padding(dimensionResource(R.dimen.margin_medium)),
verticalAlignment = Alignment.CenterVertically
) {
Icon(
painter = painterResource(R.drawable.ic_suggestions),
contentDescription = null
)
HeaderComposable(title = stringResource(R.string.pref_ui_similar_apps))
}
LazyColumn(
modifier = Modifier
.fillMaxSize()
.padding(vertical = dimensionResource(R.dimen.padding_medium))
) {
items(items = suggestions, key = { item -> item.id }) { app ->
AppListComposable(
app = app,
onClick = { onNavigateToAppDetails(app.packageName) }
)
}
}
}
}
}
@Preview
@Composable
@OptIn(ExperimentalCoilApi::class)
private fun DetailsSuggestionsPreview(@PreviewParameter(AppPreviewProvider::class) app: App) {
CompositionLocalProvider(LocalAsyncImagePreviewHandler provides coilPreviewProvider) {
ScreenContent(
onNavigateUp = null,
suggestions = List(10) { app.copy(id = Random.nextInt()) }
)
}
}