compose: details: Setup permissions screen
Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
This commit is contained in:
@@ -60,4 +60,10 @@ sealed class Screen(
|
||||
*/
|
||||
@Serializable
|
||||
data object DetailsReview : Screen()
|
||||
|
||||
/**
|
||||
* Child screen of [AppDetails]; Avoid navigating to this screen directly.
|
||||
*/
|
||||
@Serializable
|
||||
data object DetailsPermission : Screen()
|
||||
}
|
||||
|
||||
@@ -291,6 +291,7 @@ private fun ScreenContentApp(
|
||||
onNavigateToDetailsScreenshot = { showExtraPane(Screen.DetailsScreenshot(it)) },
|
||||
onNavigateToDetailsReview = { showExtraPane(Screen.DetailsReview) },
|
||||
onNavigateToDetailsExodus = { showExtraPane(Screen.DetailsExodus) },
|
||||
onNavigateToDetailsPermission = { showExtraPane(Screen.DetailsPermission) },
|
||||
onDownload = onDownload,
|
||||
onManualDownload = onManualDownload,
|
||||
onCancelDownload = onCancelDownload,
|
||||
@@ -320,7 +321,9 @@ private fun ScreenContentApp(
|
||||
onNavigateUp = ::showMainPane,
|
||||
onNavigateToAppDetails = onNavigateToAppDetails
|
||||
)
|
||||
|
||||
is Screen.DetailsPermission -> DetailsPermissionScreen(
|
||||
onNavigateUp = ::showMainPane
|
||||
)
|
||||
is Screen.DetailsScreenshot -> DetailsScreenshotScreen(
|
||||
index = screen.index,
|
||||
onNavigateUp = ::showMainPane
|
||||
@@ -359,6 +362,7 @@ private fun ScreenContentAppMainPane(
|
||||
onNavigateToDetailsScreenshot: (index: Int) -> Unit,
|
||||
onNavigateToDetailsReview: () -> Unit,
|
||||
onNavigateToDetailsExodus: () -> Unit,
|
||||
onNavigateToDetailsPermission: () -> Unit,
|
||||
onDownload: () -> Unit,
|
||||
onManualDownload: () -> Unit,
|
||||
onCancelDownload: () -> Unit,
|
||||
@@ -480,7 +484,12 @@ private fun ScreenContentAppMainPane(
|
||||
|
||||
HeaderComposable(
|
||||
title = stringResource(R.string.details_permission),
|
||||
subtitle = stringResource(R.string.permissions, app.permissions.size)
|
||||
subtitle = if (app.permissions.isNotEmpty()) {
|
||||
stringResource(R.string.permissions, app.permissions.size)
|
||||
} else {
|
||||
stringResource(R.string.details_no_permission)
|
||||
},
|
||||
onClick = if (app.permissions.isNotEmpty()) onNavigateToDetailsPermission else null
|
||||
)
|
||||
|
||||
if (dataSafetyReport != null) AppDataSafety(report = dataSafetyReport)
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 The Calyx Institute
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
package com.aurora.store.compose.ui.details
|
||||
|
||||
import android.content.pm.PermissionInfo
|
||||
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.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
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.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.dimensionResource
|
||||
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 androidx.window.core.layout.WindowWidthSizeClass
|
||||
import com.aurora.extensions.adaptiveNavigationIcon
|
||||
import com.aurora.gplayapi.data.models.App
|
||||
import com.aurora.store.R
|
||||
import com.aurora.store.compose.composables.TopAppBarComposable
|
||||
import com.aurora.store.compose.composables.preview.AppPreviewProvider
|
||||
import com.aurora.store.viewmodel.details.AppDetailsViewModel
|
||||
import com.aurora.store.viewmodel.details.DetailsPermissionViewModel
|
||||
|
||||
@Composable
|
||||
fun DetailsPermissionScreen(
|
||||
onNavigateUp: () -> Unit,
|
||||
appDetailsViewModel: AppDetailsViewModel = hiltViewModel(),
|
||||
detailsPermissionViewModel: DetailsPermissionViewModel = hiltViewModel { factory: DetailsPermissionViewModel.Factory ->
|
||||
factory.create(appDetailsViewModel.app.value!!.permissions)
|
||||
},
|
||||
windowAdaptiveInfo: WindowAdaptiveInfo = currentWindowAdaptiveInfo()
|
||||
) {
|
||||
val app by appDetailsViewModel.app.collectAsStateWithLifecycle()
|
||||
val permissionsInfo by detailsPermissionViewModel.permissionsInfo.collectAsStateWithLifecycle()
|
||||
|
||||
val topAppBarTitle = when (windowAdaptiveInfo.windowSizeClass.windowWidthSizeClass) {
|
||||
WindowWidthSizeClass.COMPACT -> app!!.displayName
|
||||
else -> stringResource(R.string.details_permission)
|
||||
}
|
||||
|
||||
ScreenContent(
|
||||
topAppBarTitle = topAppBarTitle,
|
||||
onNavigateUp = onNavigateUp,
|
||||
permissionsInfo = permissionsInfo
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ScreenContent(
|
||||
topAppBarTitle: String? = null,
|
||||
permissionsInfo: Map<String, PermissionInfo?> = emptyMap(),
|
||||
onNavigateUp: () -> Unit = {},
|
||||
windowAdaptiveInfo: WindowAdaptiveInfo = currentWindowAdaptiveInfo()
|
||||
) {
|
||||
val packageManager = LocalContext.current.packageManager
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
TopAppBarComposable(
|
||||
title = topAppBarTitle,
|
||||
navigationIcon = windowAdaptiveInfo.adaptiveNavigationIcon,
|
||||
onNavigateUp = onNavigateUp
|
||||
)
|
||||
}
|
||||
) { paddingValues ->
|
||||
LazyColumn(
|
||||
modifier = Modifier
|
||||
.padding(paddingValues)
|
||||
.fillMaxSize()
|
||||
.padding(horizontal = dimensionResource(R.dimen.padding_medium))
|
||||
) {
|
||||
items(items = permissionsInfo.keys.toList(), key = { it }) { permission ->
|
||||
// Bail out if this is not a known permission for the OS
|
||||
val permissionInfo = permissionsInfo.getValue(permission) ?: return@items
|
||||
|
||||
Text(
|
||||
text = permissionInfo.loadLabel(packageManager).toString(),
|
||||
style = MaterialTheme.typography.bodyMedium
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun DetailsPermissionScreenPreview(@PreviewParameter(AppPreviewProvider::class) app: App) {
|
||||
ScreenContent(
|
||||
topAppBarTitle = app.displayName
|
||||
)
|
||||
}
|
||||
@@ -37,7 +37,7 @@ class DetailsExodusViewModel @AssistedInject constructor(
|
||||
getExodusTrackersFromReport()
|
||||
}
|
||||
|
||||
fun getExodusTrackersFromReport() {
|
||||
private fun getExodusTrackersFromReport() {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
val trackerObjects = exodusReport.trackers.map {
|
||||
exodusTrackers.getJSONObject(it.toString())
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 The Calyx Institute
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
package com.aurora.store.viewmodel.details
|
||||
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.pm.PermissionInfo
|
||||
import androidx.lifecycle.ViewModel
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
|
||||
@HiltViewModel(assistedFactory = DetailsPermissionViewModel.Factory::class)
|
||||
class DetailsPermissionViewModel @AssistedInject constructor(
|
||||
@Assisted private val permissions: List<String>,
|
||||
@ApplicationContext private val context: Context
|
||||
): ViewModel() {
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory {
|
||||
fun create(permissions: List<String>): DetailsPermissionViewModel
|
||||
}
|
||||
|
||||
private val _permissionsInfo = MutableStateFlow<Map<String, PermissionInfo?>>(emptyMap())
|
||||
val permissionsInfo = _permissionsInfo.asStateFlow()
|
||||
|
||||
init {
|
||||
fetchPermissions()
|
||||
}
|
||||
|
||||
private fun fetchPermissions() {
|
||||
_permissionsInfo.value = permissions.associateWith { getPermissionInfo(it) }
|
||||
}
|
||||
|
||||
private fun getPermissionInfo(permissionName: String): PermissionInfo? {
|
||||
return try {
|
||||
context.packageManager.getPermissionInfo(permissionName, 0)
|
||||
} catch (_: PackageManager.NameNotFoundException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user