mirror of
https://github.com/whyorean/AuroraStore.git
synced 2026-06-11 17:26:53 -04:00
compose: rewire navigation as the single entry point
ComposeActivity becomes the sole launch target; the legacy MainActivity is removed. Destination / Screen pair drives navigation3, NavDisplay handles deep links plus microG-aware resume rechecks, and Theme.kt is tightened for edge-to-edge.
This commit is contained in:
@@ -82,9 +82,9 @@
|
||||
tools:targetApi="tiramisu">
|
||||
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:name=".ComposeActivity"
|
||||
android:exported="true"
|
||||
android:windowSoftInputMode="adjustPan">
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
@@ -103,16 +103,28 @@
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SHOW_APP_INFO" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
<nav-graph android:value="@navigation/mobile_navigation" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
|
||||
<data android:scheme="market" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
|
||||
<data android:scheme="http" />
|
||||
<data android:scheme="https" />
|
||||
<data android:host="market.android.com" />
|
||||
<data android:host="play.google.com" />
|
||||
<data android:host="play.google.com" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<!-- Activity to host composable screens -->
|
||||
<activity
|
||||
android:name=".ComposeActivity"
|
||||
android:exported="false"
|
||||
android:windowSoftInputMode="adjustResize" />
|
||||
|
||||
<!-- Notification Action (Download Complete) -->
|
||||
<activity
|
||||
android:name=".data.activity.InstallActivity"
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
package com.aurora.store
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
@@ -18,31 +19,22 @@ import com.aurora.store.compose.composition.UI
|
||||
import com.aurora.store.compose.navigation.NavDisplay
|
||||
import com.aurora.store.compose.navigation.Screen
|
||||
import com.aurora.store.compose.theme.AuroraTheme
|
||||
import com.aurora.store.data.receiver.MigrationReceiver
|
||||
import com.aurora.store.util.PackageUtil
|
||||
import com.aurora.store.util.Preferences
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
|
||||
@AndroidEntryPoint
|
||||
class ComposeActivity : ComponentActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
MigrationReceiver.runMigrationsIfRequired(this)
|
||||
enableEdgeToEdge()
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
// Ensure the classloader is set for the Screen parcelable
|
||||
intent.setExtrasClassLoader(Screen::class.java.classLoader)
|
||||
|
||||
var startDestination = IntentCompat.getParcelableExtra(
|
||||
intent,
|
||||
Screen.PARCEL_KEY,
|
||||
Screen::class.java
|
||||
) ?: Screen.Onboarding
|
||||
|
||||
// If the intent contains a package name for app details,
|
||||
// Override the start destination to be the app details screen for that package.
|
||||
val packageName = intent.getPackageName()
|
||||
if (packageName != null) {
|
||||
startDestination = Screen.AppDetails(packageName)
|
||||
}
|
||||
val startDestination = resolveStartDestination()
|
||||
|
||||
val localUI = when {
|
||||
PackageUtil.isTv(this) -> UI.TV
|
||||
@@ -57,4 +49,32 @@ class ComposeActivity : ComponentActivity() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun resolveStartDestination(): Screen {
|
||||
// Parcel-based navigation (e.g. from NotificationUtil)
|
||||
IntentCompat.getParcelableExtra(intent, Screen.PARCEL_KEY, Screen::class.java)
|
||||
?.let { return it }
|
||||
|
||||
// Deep links via ACTION_VIEW
|
||||
if (intent.action == Intent.ACTION_VIEW) {
|
||||
val data = intent.data
|
||||
val path = data?.path.orEmpty()
|
||||
val id = data?.getQueryParameter("id")
|
||||
return when {
|
||||
id != null && path.contains("/apps/dev") -> Screen.DevProfile(id)
|
||||
id != null -> Screen.AppDetails(id)
|
||||
else -> defaultStart()
|
||||
}
|
||||
}
|
||||
|
||||
// SEND / SHOW_APP_INFO — getPackageName() handles both
|
||||
intent.getPackageName()?.let { return Screen.AppDetails(it) }
|
||||
|
||||
return defaultStart()
|
||||
}
|
||||
|
||||
private fun defaultStart(): Screen = when {
|
||||
!Preferences.getBoolean(this, Preferences.PREFERENCE_INTRO) -> Screen.Onboarding
|
||||
else -> Screen.Splash
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,157 +0,0 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
* Copyright (C) 2022, The Calyx Institute
|
||||
*
|
||||
* Aurora Store is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.activity.addCallback
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat.Type.displayCutout
|
||||
import androidx.core.view.WindowInsetsCompat.Type.ime
|
||||
import androidx.core.view.WindowInsetsCompat.Type.systemBars
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.FloatingWindow
|
||||
import androidx.navigation.fragment.NavHostFragment
|
||||
import androidx.navigation.ui.setupWithNavController
|
||||
import com.aurora.store.data.model.NetworkStatus
|
||||
import com.aurora.store.data.receiver.MigrationReceiver
|
||||
import com.aurora.store.databinding.ActivityMainBinding
|
||||
import com.aurora.store.util.PackageUtil
|
||||
import com.aurora.store.util.Preferences
|
||||
import com.aurora.store.util.Preferences.PREFERENCE_DEFAULT_SELECTED_TAB
|
||||
import com.aurora.store.view.ui.sheets.NetworkDialogSheet
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@AndroidEntryPoint
|
||||
class MainActivity : AppCompatActivity() {
|
||||
|
||||
private val viewModel: MainViewModel by viewModels()
|
||||
|
||||
private lateinit var binding: ActivityMainBinding
|
||||
|
||||
// TopLevelFragments
|
||||
private val topLevelFrags = listOf(
|
||||
R.id.appsContainerFragment,
|
||||
R.id.gamesContainerFragment,
|
||||
R.id.updatesFragment
|
||||
)
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
// Check and run migrations first if required
|
||||
// This is needed thanks to OEMs breaking the MY_PACKAGE_REPLACED API
|
||||
MigrationReceiver.runMigrationsIfRequired(this)
|
||||
|
||||
enableEdgeToEdge()
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
binding = ActivityMainBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
// Adjust root view's paddings for edgeToEdge display
|
||||
ViewCompat.setOnApplyWindowInsetsListener(binding.root) { root, windowInsets ->
|
||||
val insets = windowInsets.getInsets(systemBars() or displayCutout() or ime())
|
||||
root.setPadding(insets.left, insets.top, insets.right, 0)
|
||||
windowInsets
|
||||
}
|
||||
|
||||
val navHostFragment =
|
||||
supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
|
||||
val navController = navHostFragment.navController
|
||||
|
||||
if (!PackageUtil.isTv(this)) {
|
||||
viewModel.networkProvider.status.onEach { networkStatus ->
|
||||
when (networkStatus) {
|
||||
NetworkStatus.AVAILABLE -> {
|
||||
if (!supportFragmentManager.isDestroyed && isIntroDone()) {
|
||||
val fragment = supportFragmentManager
|
||||
.findFragmentByTag(NetworkDialogSheet.TAG)
|
||||
fragment?.let {
|
||||
supportFragmentManager.beginTransaction()
|
||||
.remove(fragment)
|
||||
.commitAllowingStateLoss()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NetworkStatus.UNAVAILABLE -> {
|
||||
if (!supportFragmentManager.isDestroyed && isIntroDone()) {
|
||||
supportFragmentManager.beginTransaction()
|
||||
.add(NetworkDialogSheet.newInstance(), NetworkDialogSheet.TAG)
|
||||
.commitAllowingStateLoss()
|
||||
}
|
||||
}
|
||||
}
|
||||
}.launchIn(AuroraApp.scope)
|
||||
}
|
||||
|
||||
binding.navView.setupWithNavController(navController)
|
||||
|
||||
// Handle quick exit from back actions
|
||||
val defaultTab = when (Preferences.getInteger(this, PREFERENCE_DEFAULT_SELECTED_TAB)) {
|
||||
1 -> R.id.gamesContainerFragment
|
||||
2 -> R.id.updatesFragment
|
||||
else -> R.id.appsContainerFragment
|
||||
}
|
||||
onBackPressedDispatcher.addCallback(this) {
|
||||
if (navController.currentDestination?.id in topLevelFrags) {
|
||||
if (navController.currentDestination?.id == defaultTab) {
|
||||
finish()
|
||||
} else {
|
||||
navController.navigate(defaultTab)
|
||||
}
|
||||
} else if (navHostFragment.childFragmentManager.backStackEntryCount == 0) {
|
||||
// We are on either on onboarding or splash fragment
|
||||
finish()
|
||||
} else {
|
||||
navController.navigateUp()
|
||||
}
|
||||
}
|
||||
|
||||
// Handle views on fragments
|
||||
navController.addOnDestinationChangedListener { _, navDestination, _ ->
|
||||
if (navDestination !is FloatingWindow) {
|
||||
when (navDestination.id) {
|
||||
in topLevelFrags -> binding.navView.visibility = View.VISIBLE
|
||||
else -> binding.navView.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Updates
|
||||
lifecycleScope.launch {
|
||||
viewModel.updateHelper.updates.collectLatest { list ->
|
||||
binding.navView.getOrCreateBadge(R.id.updatesFragment).apply {
|
||||
isVisible = !list.isNullOrEmpty()
|
||||
number = list?.size ?: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun isIntroDone(): Boolean = Preferences.getBoolean(this, Preferences.PREFERENCE_INTRO)
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Aurora OSS
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
package com.aurora.store.compose.navigation
|
||||
|
||||
import com.aurora.gplayapi.data.models.Category
|
||||
import com.aurora.gplayapi.data.models.StreamCluster
|
||||
import com.aurora.store.data.model.MinimalApp
|
||||
import com.aurora.store.data.model.PermissionType
|
||||
|
||||
/**
|
||||
* All navigation actions available to composable screens.
|
||||
* Screens emit one of these via a single `onNavigateTo: (Destination) -> Unit` callback.
|
||||
*/
|
||||
sealed class Destination {
|
||||
data object Splash : Destination()
|
||||
data class Main(val initialTab: Int) : Destination()
|
||||
|
||||
data class AppDetails(val packageName: String) : Destination()
|
||||
data class DevProfile(val devId: String) : Destination()
|
||||
data class AppMenu(val app: MinimalApp) : Destination()
|
||||
|
||||
data object Search : Destination()
|
||||
data object Downloads : Destination()
|
||||
|
||||
data class StreamBrowse(val cluster: StreamCluster) : Destination()
|
||||
data class ExpandedStreamBrowse(val title: String, val browseUrl: String) : Destination()
|
||||
data class CategoryBrowse(val category: Category) : Destination()
|
||||
data class PermissionRationale(val permissions: Set<PermissionType>) : Destination()
|
||||
|
||||
data object Accounts : Destination()
|
||||
data object GoogleLogin : Destination()
|
||||
data object About : Destination()
|
||||
data object Favourite : Destination()
|
||||
data object Spoof : Destination()
|
||||
data object Installed : Destination()
|
||||
data object Blacklist : Destination()
|
||||
|
||||
data object Settings : Destination()
|
||||
data object InstallationPreference : Destination()
|
||||
data object Installer : Destination()
|
||||
data object NetworkPreference : Destination()
|
||||
data object Dispenser : Destination()
|
||||
data object UIPreference : Destination()
|
||||
data object UpdatesPreference : Destination()
|
||||
}
|
||||
@@ -7,16 +7,23 @@
|
||||
package com.aurora.store.compose.navigation
|
||||
|
||||
import android.content.Intent
|
||||
import androidx.activity.compose.LocalActivity
|
||||
import androidx.compose.animation.EnterTransition
|
||||
import androidx.compose.animation.ExitTransition
|
||||
import androidx.compose.animation.core.spring
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.slideInHorizontally
|
||||
import androidx.compose.animation.slideOutHorizontally
|
||||
import androidx.compose.animation.slideOutVertically
|
||||
import androidx.compose.animation.togetherWith
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.compose.LifecycleEventEffect
|
||||
import androidx.lifecycle.viewmodel.navigation3.rememberViewModelStoreNavEntryDecorator
|
||||
import androidx.navigation.NavDeepLinkBuilder
|
||||
import androidx.navigation3.runtime.NavKey
|
||||
import androidx.navigation3.runtime.entryProvider
|
||||
import androidx.navigation3.runtime.metadata
|
||||
import androidx.navigation3.runtime.rememberNavBackStack
|
||||
import androidx.navigation3.runtime.rememberSaveableStateHolderNavEntryDecorator
|
||||
import androidx.navigation3.ui.NavDisplay
|
||||
@@ -24,11 +31,13 @@ import com.aurora.Constants.PACKAGE_NAME_GMS
|
||||
import com.aurora.extensions.toast
|
||||
import com.aurora.store.AuroraApp
|
||||
import com.aurora.store.ComposeActivity
|
||||
import com.aurora.store.MainActivity
|
||||
import com.aurora.store.R
|
||||
import com.aurora.store.compose.ui.about.AboutScreen
|
||||
import com.aurora.store.compose.ui.accounts.AccountsScreen
|
||||
import com.aurora.store.compose.ui.accounts.GoogleLoginScreen
|
||||
import com.aurora.store.compose.ui.blacklist.BlacklistScreen
|
||||
import com.aurora.store.compose.ui.commons.CategoryBrowseScreen
|
||||
import com.aurora.store.compose.ui.commons.ExpandedStreamBrowseScreen
|
||||
import com.aurora.store.compose.ui.commons.PermissionRationaleScreen
|
||||
import com.aurora.store.compose.ui.commons.StreamBrowseScreen
|
||||
import com.aurora.store.compose.ui.details.AppDetailsScreen
|
||||
@@ -37,9 +46,16 @@ import com.aurora.store.compose.ui.dispenser.DispenserScreen
|
||||
import com.aurora.store.compose.ui.downloads.DownloadsScreen
|
||||
import com.aurora.store.compose.ui.favourite.FavouriteScreen
|
||||
import com.aurora.store.compose.ui.installed.InstalledScreen
|
||||
import com.aurora.store.compose.ui.main.MainScreen
|
||||
import com.aurora.store.compose.ui.onboarding.OnboardingScreen
|
||||
import com.aurora.store.compose.ui.preferences.SettingsScreen
|
||||
import com.aurora.store.compose.ui.preferences.UIPreferenceScreen
|
||||
import com.aurora.store.compose.ui.preferences.installation.InstallationPreferenceScreen
|
||||
import com.aurora.store.compose.ui.preferences.installation.InstallerScreen
|
||||
import com.aurora.store.compose.ui.preferences.network.NetworkPreferenceScreen
|
||||
import com.aurora.store.compose.ui.preferences.updates.UpdatesPreferenceScreen
|
||||
import com.aurora.store.compose.ui.search.SearchScreen
|
||||
import com.aurora.store.compose.ui.splash.SplashScreen
|
||||
import com.aurora.store.compose.ui.spoof.SpoofScreen
|
||||
import com.aurora.store.data.event.InstallerEvent
|
||||
import com.aurora.store.data.model.AccountType
|
||||
@@ -54,23 +70,6 @@ import com.aurora.store.util.Preferences
|
||||
@Composable
|
||||
fun NavDisplay(startDestination: NavKey) {
|
||||
val backstack = rememberNavBackStack(startDestination)
|
||||
|
||||
// TODO: Rework when migrating splash fragment to compose
|
||||
val splashIntent = NavDeepLinkBuilder(LocalContext.current)
|
||||
.setGraph(R.navigation.mobile_navigation)
|
||||
.setDestination(R.id.splashFragment)
|
||||
.setComponentName(MainActivity::class.java)
|
||||
.createTaskStackBuilder()
|
||||
.intents
|
||||
.first()
|
||||
.apply { addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK) }
|
||||
|
||||
// TODO: Drop this logic once everything is in compose
|
||||
val activity = LocalActivity.current
|
||||
fun onNavigateUp() {
|
||||
if (backstack.size == 1) activity?.finish() else backstack.removeLastOrNull()
|
||||
}
|
||||
|
||||
val context = LocalContext.current
|
||||
|
||||
fun isMicroGAuthInvalidated(): Boolean =
|
||||
@@ -101,114 +100,169 @@ fun NavDisplay(startDestination: NavKey) {
|
||||
}
|
||||
}
|
||||
|
||||
fun navigate(destination: Destination) {
|
||||
when (destination) {
|
||||
Destination.Splash -> {
|
||||
// Clear the backstack when navigating to Splash to prevent going back to the previous screen when the user is sent back to the splash screen (e.g. after logout).
|
||||
backstack.clear()
|
||||
backstack.add(Screen.Splash)
|
||||
}
|
||||
|
||||
is Destination.Main -> {
|
||||
// Clear the backstack when navigating to Main to prevent going back to the splash screen or other screens.
|
||||
backstack.clear()
|
||||
backstack.add(Screen.Main(destination.initialTab))
|
||||
}
|
||||
|
||||
is Destination.ExpandedStreamBrowse -> backstack.add(
|
||||
Screen.ExpandedStreamBrowse(destination.title, destination.browseUrl)
|
||||
)
|
||||
|
||||
is Destination.CategoryBrowse -> backstack.add(
|
||||
Screen.CategoryBrowse(destination.category.title, destination.category.browseUrl)
|
||||
)
|
||||
|
||||
is Destination.PermissionRationale -> backstack.add(
|
||||
Screen.PermissionRationale(destination.permissions)
|
||||
)
|
||||
|
||||
is Destination.AppDetails -> backstack.add(Screen.AppDetails(destination.packageName))
|
||||
is Destination.DevProfile -> backstack.add(Screen.DevProfile(destination.devId))
|
||||
is Destination.AppMenu -> Unit
|
||||
is Destination.StreamBrowse -> backstack.add(Screen.StreamBrowse(destination.cluster))
|
||||
|
||||
Destination.Search -> backstack.add(Screen.Search)
|
||||
Destination.Downloads -> backstack.add(Screen.Downloads)
|
||||
Destination.Accounts -> backstack.add(Screen.Accounts)
|
||||
Destination.GoogleLogin -> backstack.add(Screen.GoogleLogin)
|
||||
Destination.About -> backstack.add(Screen.About)
|
||||
Destination.Favourite -> backstack.add(Screen.Favourite)
|
||||
Destination.Spoof -> backstack.add(Screen.Spoof)
|
||||
Destination.Installed -> backstack.add(Screen.Installed)
|
||||
Destination.Blacklist -> backstack.add(Screen.Blacklist)
|
||||
Destination.Settings -> backstack.add(Screen.Settings)
|
||||
Destination.InstallationPreference -> backstack.add(Screen.InstallationPreference)
|
||||
Destination.Installer -> backstack.add(Screen.Installer)
|
||||
Destination.NetworkPreference -> backstack.add(Screen.NetworkPreference)
|
||||
Destination.Dispenser -> backstack.add(Screen.Dispenser)
|
||||
Destination.UIPreference -> backstack.add(Screen.UIPreference)
|
||||
Destination.UpdatesPreference -> backstack.add(Screen.UpdatesPreference)
|
||||
}
|
||||
}
|
||||
|
||||
NavDisplay(
|
||||
onBack = { backstack.removeLastOrNull() },
|
||||
backStack = backstack,
|
||||
entryDecorators = listOf(
|
||||
rememberSaveableStateHolderNavEntryDecorator(),
|
||||
rememberViewModelStoreNavEntryDecorator()
|
||||
),
|
||||
transitionSpec = {
|
||||
slideInHorizontally(
|
||||
animationSpec = spring(dampingRatio = 0.8f, stiffness = 380f),
|
||||
initialOffsetX = { it }
|
||||
) togetherWith slideOutHorizontally(targetOffsetX = { -it })
|
||||
},
|
||||
popTransitionSpec = {
|
||||
slideInHorizontally(
|
||||
animationSpec = spring(dampingRatio = 0.8f, stiffness = 380f),
|
||||
initialOffsetX = { -it }
|
||||
) togetherWith slideOutHorizontally(targetOffsetX = { it })
|
||||
},
|
||||
predictivePopTransitionSpec = {
|
||||
slideInHorizontally(
|
||||
animationSpec = spring(dampingRatio = 0.8f, stiffness = 380f),
|
||||
initialOffsetX = { -it }
|
||||
) togetherWith slideOutHorizontally(targetOffsetX = { it })
|
||||
},
|
||||
entryProvider = entryProvider {
|
||||
entry<Screen.Blacklist> {
|
||||
BlacklistScreen(onNavigateUp = ::onNavigateUp)
|
||||
}
|
||||
|
||||
entry<Screen.Search> {
|
||||
SearchScreen(onNavigateUp = ::onNavigateUp)
|
||||
entry<Screen.Main> { screen ->
|
||||
MainScreen(
|
||||
initialTab = screen.initialTab,
|
||||
onNavigateTo = ::navigate
|
||||
)
|
||||
}
|
||||
|
||||
entry<Screen.AppDetails> { screen ->
|
||||
AppDetailsScreen(
|
||||
packageName = screen.packageName,
|
||||
onNavigateUp = ::onNavigateUp,
|
||||
onNavigateToAppDetails = { packageName ->
|
||||
backstack.add(Screen.AppDetails(packageName))
|
||||
}
|
||||
onNavigateTo = ::navigate
|
||||
)
|
||||
}
|
||||
|
||||
entry<Screen.DevProfile> { screen ->
|
||||
DevProfileScreen(
|
||||
developerId = screen.developerId,
|
||||
onNavigateUp = ::onNavigateUp,
|
||||
onNavigateToAppDetails = { packageName ->
|
||||
backstack.add(Screen.AppDetails(packageName))
|
||||
}
|
||||
onNavigateTo = ::navigate
|
||||
)
|
||||
}
|
||||
|
||||
entry<Screen.PermissionRationale> { screen ->
|
||||
PermissionRationaleScreen(
|
||||
onNavigateUp = ::onNavigateUp,
|
||||
requiredPermissions = screen.requiredPermissions
|
||||
)
|
||||
}
|
||||
|
||||
entry<Screen.Downloads> {
|
||||
DownloadsScreen(
|
||||
onNavigateUp = ::onNavigateUp,
|
||||
onNavigateToAppDetails = { packageName ->
|
||||
backstack.add(Screen.AppDetails(packageName))
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
entry<Screen.Accounts> {
|
||||
AccountsScreen(
|
||||
onNavigateUp = ::onNavigateUp,
|
||||
onNavigateToSplash = { activity?.startActivity(splashIntent) }
|
||||
)
|
||||
}
|
||||
|
||||
entry<Screen.About> {
|
||||
AboutScreen(onNavigateUp = ::onNavigateUp)
|
||||
}
|
||||
|
||||
entry<Screen.Favourite> {
|
||||
FavouriteScreen(
|
||||
onNavigateUp = ::onNavigateUp,
|
||||
onNavigateToAppDetails = { packageName ->
|
||||
backstack.add(Screen.AppDetails(packageName))
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
entry<Screen.Onboarding> {
|
||||
OnboardingScreen()
|
||||
}
|
||||
|
||||
entry<Screen.Spoof> {
|
||||
SpoofScreen(
|
||||
onNavigateUp = ::onNavigateUp,
|
||||
onNavigateToSplash = { activity?.startActivity(splashIntent) }
|
||||
)
|
||||
}
|
||||
|
||||
entry<Screen.Dispenser> {
|
||||
DispenserScreen(onNavigateUp = ::onNavigateUp)
|
||||
}
|
||||
|
||||
entry<Screen.Installer> {
|
||||
InstallerScreen(onNavigateUp = ::onNavigateUp)
|
||||
}
|
||||
|
||||
entry<Screen.Installed> {
|
||||
InstalledScreen(
|
||||
onNavigateUp = ::onNavigateUp,
|
||||
onNavigateToAppDetails = { packageName ->
|
||||
backstack.add(Screen.AppDetails(packageName))
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
entry<Screen.StreamBrowse> { screen ->
|
||||
StreamBrowseScreen(
|
||||
streamCluster = screen.streamCluster,
|
||||
onNavigateUp = ::onNavigateUp,
|
||||
onNavigateToAppDetails = { packageName ->
|
||||
backstack.add(Screen.AppDetails(packageName))
|
||||
}
|
||||
onNavigateTo = ::navigate
|
||||
)
|
||||
}
|
||||
|
||||
entry<Screen.ExpandedStreamBrowse> { screen ->
|
||||
ExpandedStreamBrowseScreen(
|
||||
browseUrl = screen.browseUrl,
|
||||
defaultTitle = screen.title,
|
||||
onNavigateTo = ::navigate
|
||||
)
|
||||
}
|
||||
|
||||
entry<Screen.CategoryBrowse> { screen ->
|
||||
CategoryBrowseScreen(
|
||||
title = screen.title,
|
||||
browseUrl = screen.browseUrl,
|
||||
onNavigateTo = ::navigate
|
||||
)
|
||||
}
|
||||
|
||||
entry<Screen.InstallationPreference> {
|
||||
InstallationPreferenceScreen(onNavigateTo = ::navigate)
|
||||
}
|
||||
|
||||
entry<Screen.Search>(
|
||||
metadata = metadata {
|
||||
put(NavDisplay.TransitionKey) {
|
||||
fadeIn() togetherWith
|
||||
ExitTransition.KeepUntilTransitionsFinished
|
||||
}
|
||||
put(NavDisplay.PopTransitionKey) {
|
||||
EnterTransition.None togetherWith
|
||||
slideOutVertically(targetOffsetY = { it })
|
||||
}
|
||||
put(NavDisplay.PredictivePopTransitionKey) {
|
||||
EnterTransition.None togetherWith
|
||||
slideOutVertically(targetOffsetY = { it })
|
||||
}
|
||||
}
|
||||
) { SearchScreen() }
|
||||
|
||||
entry<Screen.Splash> { SplashScreen(onNavigateTo = ::navigate) }
|
||||
entry<Screen.Onboarding> { OnboardingScreen() }
|
||||
entry<Screen.Blacklist> { BlacklistScreen() }
|
||||
entry<Screen.Downloads> { DownloadsScreen(onNavigateTo = ::navigate) }
|
||||
entry<Screen.Accounts> { AccountsScreen(onNavigateTo = ::navigate) }
|
||||
entry<Screen.GoogleLogin> { GoogleLoginScreen(onNavigateTo = ::navigate) }
|
||||
entry<Screen.About> { AboutScreen() }
|
||||
entry<Screen.Favourite> { FavouriteScreen(onNavigateTo = ::navigate) }
|
||||
entry<Screen.Spoof> { SpoofScreen(onNavigateTo = ::navigate) }
|
||||
entry<Screen.Dispenser> { DispenserScreen() }
|
||||
entry<Screen.Installer> { InstallerScreen() }
|
||||
entry<Screen.Installed> { InstalledScreen(onNavigateTo = ::navigate) }
|
||||
entry<Screen.Settings> { SettingsScreen(onNavigateTo = ::navigate) }
|
||||
entry<Screen.NetworkPreference> { NetworkPreferenceScreen(onNavigateTo = ::navigate) }
|
||||
entry<Screen.UIPreference> { UIPreferenceScreen() }
|
||||
entry<Screen.UpdatesPreference> { UpdatesPreferenceScreen() }
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@@ -44,6 +44,9 @@ sealed class Screen : NavKey, Parcelable {
|
||||
@Serializable
|
||||
data object Accounts : Screen()
|
||||
|
||||
@Serializable
|
||||
data object GoogleLogin : Screen()
|
||||
|
||||
@Serializable
|
||||
data object About : Screen()
|
||||
|
||||
@@ -67,4 +70,31 @@ sealed class Screen : NavKey, Parcelable {
|
||||
|
||||
@Serializable
|
||||
data class StreamBrowse(val streamCluster: StreamCluster) : Screen()
|
||||
|
||||
@Serializable
|
||||
data class ExpandedStreamBrowse(val title: String, val browseUrl: String) : Screen()
|
||||
|
||||
@Serializable
|
||||
data class CategoryBrowse(val title: String, val browseUrl: String) : Screen()
|
||||
|
||||
@Serializable
|
||||
data object Settings : Screen()
|
||||
|
||||
@Serializable
|
||||
data object InstallationPreference : Screen()
|
||||
|
||||
@Serializable
|
||||
data object NetworkPreference : Screen()
|
||||
|
||||
@Serializable
|
||||
data object UIPreference : Screen()
|
||||
|
||||
@Serializable
|
||||
data object UpdatesPreference : Screen()
|
||||
|
||||
@Serializable
|
||||
data object Splash : Screen()
|
||||
|
||||
@Serializable
|
||||
data class Main(val initialTab: Int = 0) : Screen()
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
package com.aurora.store.compose.theme
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import android.os.Build
|
||||
import androidx.activity.compose.LocalActivity
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
@@ -16,7 +17,12 @@ import androidx.compose.material3.dynamicDarkColorScheme
|
||||
import androidx.compose.material3.dynamicLightColorScheme
|
||||
import androidx.compose.material3.lightColorScheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.SideEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalView
|
||||
import androidx.compose.ui.res.colorResource
|
||||
@@ -31,7 +37,19 @@ import com.aurora.store.util.Preferences
|
||||
fun AuroraTheme(content: @Composable () -> Unit) {
|
||||
val context = LocalContext.current
|
||||
|
||||
val themeStyle = Preferences.getInteger(context, Preferences.PREFERENCE_THEME_STYLE)
|
||||
var themeStyle by remember {
|
||||
mutableIntStateOf(Preferences.getInteger(context, Preferences.PREFERENCE_THEME_STYLE))
|
||||
}
|
||||
DisposableEffect(Unit) {
|
||||
val prefs = Preferences.getPrefs(context)
|
||||
val listener = SharedPreferences.OnSharedPreferenceChangeListener { _, key ->
|
||||
if (key == Preferences.PREFERENCE_THEME_STYLE) {
|
||||
themeStyle = Preferences.getInteger(context, Preferences.PREFERENCE_THEME_STYLE)
|
||||
}
|
||||
}
|
||||
prefs.registerOnSharedPreferenceChangeListener(listener)
|
||||
onDispose { prefs.unregisterOnSharedPreferenceChangeListener(listener) }
|
||||
}
|
||||
val isDynamicColorSupported = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
|
||||
|
||||
val lightScheme = if (isDynamicColorSupported) {
|
||||
@@ -69,11 +87,9 @@ fun AuroraTheme(content: @Composable () -> Unit) {
|
||||
val currentActivity = activity ?: return@SideEffect
|
||||
val window = currentActivity.window
|
||||
|
||||
// Transparent system bars
|
||||
window.statusBarColor = android.graphics.Color.TRANSPARENT
|
||||
window.navigationBarColor = android.graphics.Color.TRANSPARENT
|
||||
|
||||
// Control icon colors explicitly
|
||||
WindowCompat
|
||||
.getInsetsController(window, view)
|
||||
.apply {
|
||||
|
||||
Reference in New Issue
Block a user