compose: onboarding: Add back microG page for required flavors
Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
This commit is contained in:
136
app/src/main/java/com/aurora/store/compose/composable/MicroG.kt
Normal file
136
app/src/main/java/com/aurora/store/compose/composable/MicroG.kt
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 The Calyx Institute
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.aurora.store.compose.composable
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material3.Button
|
||||||
|
import androidx.compose.material3.Checkbox
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
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
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.util.fastForEach
|
||||||
|
import com.aurora.extensions.browse
|
||||||
|
import com.aurora.store.R
|
||||||
|
import com.aurora.store.compose.preview.PreviewTemplate
|
||||||
|
import com.aurora.store.data.model.Link
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Composable to display suggestion to install microG
|
||||||
|
* @param modifier Modifier for the composable
|
||||||
|
* @param isTOSChecked Whether the TOS checkbox is checked
|
||||||
|
* @param onInstall Callback when user requests installing microG bundle
|
||||||
|
*/
|
||||||
|
@Composable
|
||||||
|
fun MicroG(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
isTOSChecked: Boolean = false,
|
||||||
|
onInstall: () -> Unit = {}
|
||||||
|
) {
|
||||||
|
val context = LocalContext.current
|
||||||
|
var isChecked by rememberSaveable { mutableStateOf(isTOSChecked) }
|
||||||
|
val links = listOf(
|
||||||
|
Link(
|
||||||
|
id = 2,
|
||||||
|
title = stringResource(R.string.details_dev_website),
|
||||||
|
subtitle = stringResource(R.string.microg_website),
|
||||||
|
icon = R.drawable.ic_network,
|
||||||
|
url = "https://microG.org"
|
||||||
|
),
|
||||||
|
Link(
|
||||||
|
id = 4,
|
||||||
|
title = stringResource(R.string.privacy_policy_title),
|
||||||
|
subtitle = stringResource(R.string.microg_privacy_policy),
|
||||||
|
icon = R.drawable.ic_privacy,
|
||||||
|
url = "https://microg.org/privacy.html"
|
||||||
|
),
|
||||||
|
Link(
|
||||||
|
id = 5,
|
||||||
|
title = stringResource(R.string.menu_disclaimer),
|
||||||
|
subtitle = stringResource(R.string.microg_license_agreement),
|
||||||
|
icon = R.drawable.ic_disclaimer,
|
||||||
|
url = "https://raw.githubusercontent.com/microg/GmsCore/refs/heads/master/LICENSE"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(
|
||||||
|
horizontal = dimensionResource(R.dimen.padding_small),
|
||||||
|
vertical = dimensionResource(R.dimen.padding_xxsmall)
|
||||||
|
),
|
||||||
|
verticalArrangement = Arrangement.SpaceBetween
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
verticalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_xxsmall))
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.onboarding_gms_microg),
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
)
|
||||||
|
|
||||||
|
links.fastForEach { link ->
|
||||||
|
LinkListItem(
|
||||||
|
link = link,
|
||||||
|
onClick = { context.browse(link.url) },
|
||||||
|
iconTint = MaterialTheme.colorScheme.primary
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(vertical = dimensionResource(R.dimen.padding_xlarge)),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
verticalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_small))
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(
|
||||||
|
dimensionResource(R.dimen.padding_small)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
Checkbox(checked = isChecked, onCheckedChange = { isChecked = !isChecked })
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.onboarding_gms_agreement),
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
maxLines = 2,
|
||||||
|
overflow = TextOverflow.Ellipsis
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Button(onClick = onInstall, enabled = isChecked) {
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.action_install_microG)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview(showBackground = true)
|
||||||
|
@Composable
|
||||||
|
private fun MicroGPreview() {
|
||||||
|
PreviewTemplate {
|
||||||
|
MicroG(isTOSChecked = true)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 The Calyx Institute
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.aurora.store.compose.ui.onboarding
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.res.dimensionResource
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
||||||
|
import com.aurora.store.R
|
||||||
|
import com.aurora.store.compose.composable.MicroG
|
||||||
|
import com.aurora.store.compose.preview.PreviewTemplate
|
||||||
|
import com.aurora.store.viewmodel.onboarding.MicroGViewModel
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun MicroGPage(viewModel: MicroGViewModel = hiltViewModel()) {
|
||||||
|
ScreenContent(
|
||||||
|
onInstall = { viewModel.downloadMicroG() }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ScreenContent(onInstall: () -> Unit = {}) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(horizontal = dimensionResource(R.dimen.padding_medium))
|
||||||
|
.verticalScroll(rememberScrollState()),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_medium))
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(dimensionResource(R.dimen.padding_medium))
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.onboarding_title_gsf),
|
||||||
|
style = MaterialTheme.typography.headlineLargeEmphasized,
|
||||||
|
maxLines = 1,
|
||||||
|
overflow = TextOverflow.Ellipsis
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.onboarding_title_gsf_desc),
|
||||||
|
style = MaterialTheme.typography.titleLarge,
|
||||||
|
maxLines = 2,
|
||||||
|
overflow = TextOverflow.Ellipsis
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
MicroG(onInstall = onInstall)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview(showBackground = true)
|
||||||
|
@Composable
|
||||||
|
private fun MicroGPagePreview() {
|
||||||
|
PreviewTemplate {
|
||||||
|
ScreenContent()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,6 +25,7 @@ import androidx.compose.runtime.Composable
|
|||||||
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
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.dimensionResource
|
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
|
||||||
@@ -36,14 +37,17 @@ import com.aurora.store.compose.composable.Logo
|
|||||||
import com.aurora.store.compose.composable.PageIndicator
|
import com.aurora.store.compose.composable.PageIndicator
|
||||||
import com.aurora.store.compose.preview.PreviewTemplate
|
import com.aurora.store.compose.preview.PreviewTemplate
|
||||||
import com.aurora.store.compose.ui.onboarding.navigation.OnboardingPage
|
import com.aurora.store.compose.ui.onboarding.navigation.OnboardingPage
|
||||||
|
import com.aurora.store.util.FlavouredUtil
|
||||||
import com.aurora.store.viewmodel.onboarding.OnboardingViewModel
|
import com.aurora.store.viewmodel.onboarding.OnboardingViewModel
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun OnboardingScreen(viewModel: OnboardingViewModel = hiltViewModel()) {
|
fun OnboardingScreen(viewModel: OnboardingViewModel = hiltViewModel()) {
|
||||||
|
val context = LocalContext.current
|
||||||
val pages = listOfNotNull(
|
val pages = listOfNotNull(
|
||||||
OnboardingPage.WELCOME,
|
OnboardingPage.WELCOME,
|
||||||
OnboardingPage.PERMISSIONS
|
OnboardingPage.PERMISSIONS,
|
||||||
|
if (FlavouredUtil.promptMicroGInstall(context)) OnboardingPage.MICRO_G else null
|
||||||
)
|
)
|
||||||
|
|
||||||
ScreenContent(
|
ScreenContent(
|
||||||
@@ -171,6 +175,7 @@ private fun ScreenContent(
|
|||||||
when (pages[page]) {
|
when (pages[page]) {
|
||||||
OnboardingPage.WELCOME -> WelcomePage()
|
OnboardingPage.WELCOME -> WelcomePage()
|
||||||
OnboardingPage.PERMISSIONS -> PermissionsPage()
|
OnboardingPage.PERMISSIONS -> PermissionsPage()
|
||||||
|
OnboardingPage.MICRO_G -> MicroGPage()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ private fun PageContent(
|
|||||||
header = {
|
header = {
|
||||||
Surface(modifier = Modifier.fillMaxWidth()) {
|
Surface(modifier = Modifier.fillMaxWidth()) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.padding(dimensionResource(R.dimen.padding_normal))
|
modifier = Modifier.padding(dimensionResource(R.dimen.padding_medium))
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(R.string.onboarding_title_permissions),
|
text = stringResource(R.string.onboarding_title_permissions),
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ private fun PageContent(onAboutAurora: () -> Unit = {}) {
|
|||||||
stickyHeader {
|
stickyHeader {
|
||||||
Surface(modifier = Modifier.fillMaxWidth()) {
|
Surface(modifier = Modifier.fillMaxWidth()) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.padding(dimensionResource(R.dimen.padding_normal))
|
modifier = Modifier.padding(dimensionResource(R.dimen.padding_medium))
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(R.string.onboarding_title_welcome),
|
text = stringResource(R.string.onboarding_title_welcome),
|
||||||
|
|||||||
@@ -11,4 +11,5 @@ package com.aurora.store.compose.ui.onboarding.navigation
|
|||||||
enum class OnboardingPage {
|
enum class OnboardingPage {
|
||||||
WELCOME,
|
WELCOME,
|
||||||
PERMISSIONS,
|
PERMISSIONS,
|
||||||
|
MICRO_G
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,52 +5,32 @@
|
|||||||
|
|
||||||
package com.aurora.store.viewmodel.onboarding
|
package com.aurora.store.viewmodel.onboarding
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.aurora.Constants.PACKAGE_NAME_GMS
|
import com.aurora.Constants.PACKAGE_NAME_GMS
|
||||||
import com.aurora.Constants.PACKAGE_NAME_PLAY_STORE
|
import com.aurora.Constants.PACKAGE_NAME_PLAY_STORE
|
||||||
import com.aurora.gplayapi.data.models.PlayFile
|
import com.aurora.gplayapi.data.models.PlayFile
|
||||||
import com.aurora.store.AuroraApp
|
|
||||||
import com.aurora.store.data.event.InstallerEvent
|
|
||||||
import com.aurora.store.data.helper.DownloadHelper
|
import com.aurora.store.data.helper.DownloadHelper
|
||||||
import com.aurora.store.data.room.suite.ExternalApk
|
import com.aurora.store.data.room.suite.ExternalApk
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
|
||||||
import kotlinx.coroutines.flow.asSharedFlow
|
|
||||||
import kotlinx.coroutines.flow.combine
|
|
||||||
import kotlinx.coroutines.flow.stateIn
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class MicroGViewModel @Inject constructor(
|
class MicroGViewModel @Inject constructor(
|
||||||
@ApplicationContext private val context: Context,
|
|
||||||
private val downloadHelper: DownloadHelper
|
private val downloadHelper: DownloadHelper
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val MICROG_DOWNLOAD_URL = "https://github.com/microg/GmsCore/releases/download"
|
private const val MICROG_DOWNLOAD_URL =
|
||||||
const val MICROG_VERSION = "v0.3.6.244735"
|
"https://github.com/microg/GmsCore/releases/download"
|
||||||
const val GMS_VERSION_CODE = 244735012
|
private const val MICROG_VERSION = "v0.3.6.244735"
|
||||||
const val COMPANION_VERSION_CODE = 84022612
|
private const val GMS_VERSION_CODE = 244735012
|
||||||
|
private const val COMPANION_VERSION_CODE = 84022612
|
||||||
}
|
}
|
||||||
|
|
||||||
private val _packageNames = MutableSharedFlow<List<String>>()
|
private val microGServiceApk = ExternalApk(
|
||||||
val packageNames = _packageNames.asSharedFlow()
|
|
||||||
|
|
||||||
private val _checked = MutableStateFlow(false)
|
|
||||||
val checked: StateFlow<Boolean> = _checked
|
|
||||||
|
|
||||||
val download = combine(packageNames, downloadHelper.downloadsList) { apps, list ->
|
|
||||||
list.find { d -> apps.any { it == d.packageName } }
|
|
||||||
}.stateIn(viewModelScope, SharingStarted.Eagerly, null)
|
|
||||||
|
|
||||||
val microGServiceApk = ExternalApk(
|
|
||||||
packageName = PACKAGE_NAME_GMS,
|
packageName = PACKAGE_NAME_GMS,
|
||||||
versionCode = GMS_VERSION_CODE.toLong(),
|
versionCode = GMS_VERSION_CODE.toLong(),
|
||||||
versionName = MICROG_VERSION,
|
versionName = MICROG_VERSION,
|
||||||
@@ -67,7 +47,7 @@ class MicroGViewModel @Inject constructor(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
val microGCompanionApk = ExternalApk(
|
private val microGCompanionApk = ExternalApk(
|
||||||
packageName = PACKAGE_NAME_PLAY_STORE,
|
packageName = PACKAGE_NAME_PLAY_STORE,
|
||||||
versionCode = COMPANION_VERSION_CODE.toLong(),
|
versionCode = COMPANION_VERSION_CODE.toLong(),
|
||||||
versionName = MICROG_VERSION,
|
versionName = MICROG_VERSION,
|
||||||
@@ -84,41 +64,10 @@ class MicroGViewModel @Inject constructor(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
fun markAgreement(checked: Boolean) {
|
|
||||||
viewModelScope.launch {
|
|
||||||
_checked.emit(checked)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun downloadMicroG() {
|
fun downloadMicroG() {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
try {
|
downloadHelper.enqueueStandalone(microGServiceApk)
|
||||||
_packageNames.emit(listOf(PACKAGE_NAME_GMS))
|
downloadHelper.enqueueStandalone(microGCompanionApk)
|
||||||
|
|
||||||
if (microGServiceApk.isInstalled(context)) {
|
|
||||||
AuroraApp.events.send(InstallerEvent.Installed(PACKAGE_NAME_GMS))
|
|
||||||
} else {
|
|
||||||
downloadHelper.enqueueStandalone(microGServiceApk)
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun downloadCompanion() {
|
|
||||||
viewModelScope.launch {
|
|
||||||
try {
|
|
||||||
_packageNames.emit(listOf(PACKAGE_NAME_PLAY_STORE))
|
|
||||||
|
|
||||||
if (microGCompanionApk.isInstalled(context)) {
|
|
||||||
AuroraApp.events.send(InstallerEvent.Installed(PACKAGE_NAME_PLAY_STORE))
|
|
||||||
} else {
|
|
||||||
downloadHelper.enqueueStandalone(microGCompanionApk)
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user