feat: switch to reimagined compose nav (#40)

This commit is contained in:
rushii 2022-11-05 11:28:18 -07:00 • committed by GitHub
parent 4373ff771d
commit dfbdb9092d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 160 additions and 149 deletions

View file

@ -79,15 +79,15 @@ dependencies {
// AndroidX
implementation("androidx.core:core-ktx:1.9.0")
implementation("androidx.core:core-splashscreen:1.0.0")
implementation("androidx.activity:activity-compose:1.6.0")
implementation("androidx.paging:paging-compose:1.0.0-alpha16")
implementation("androidx.activity:activity-compose:1.6.1")
implementation("androidx.paging:paging-compose:1.0.0-alpha17")
// Compose
val composeVersion = "1.3.0-beta02"
implementation("androidx.compose.ui:ui:$composeVersion")
implementation("androidx.compose.ui:ui-tooling:$composeVersion")
implementation("androidx.compose.material:material-icons-extended:$composeVersion")
implementation("androidx.compose.material3:material3:1.0.0-rc01")
implementation("androidx.compose.material3:material3:1.0.0")
// accompanist dependencies
val accompanistVersion = "0.26.3-beta"
@ -107,17 +107,17 @@ dependencies {
implementation("io.insert-koin:koin-androidx-compose:$koinVersion")
// Other
implementation("dev.olshevski.navigation:reimagined:1.3.0")
implementation("io.coil-kt:coil-compose:2.2.1")
implementation("com.github.X1nto:Taxi:1.2.0")
implementation("org.bouncycastle:bcpkix-jdk15on:1.70")
implementation("io.github.diamondminer88:zip-android:2.1.0@aar")
implementation("com.aliucord:axml:1.0.1")
implementation("com.android.tools.build:apksig:7.4.0-beta02")
implementation("com.android.tools.build:apksig:7.4.0-beta04")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.0")
}
fun getCurrentBranch(): String? =
exec("git", "name-rev", "--name-only", "HEAD")
exec("git", "symbolic-ref", "--short", "HEAD")
fun getLatestCommit(): String? =
exec("git", "rev-parse", "--short", "HEAD")

View file

@ -11,18 +11,16 @@ import androidx.activity.compose.BackHandler
import androidx.activity.compose.setContent
import androidx.compose.animation.*
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.ui.Modifier
import androidx.compose.foundation.layout.*
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import com.aliucord.manager.domain.manager.PreferencesManager
import com.aliucord.manager.ui.dialog.StoragePermissionsDialog
import com.aliucord.manager.ui.dialog.UpdaterDialog
import com.aliucord.manager.ui.navigation.AppDestination
import com.aliucord.manager.ui.navigation.HomeDestination
import com.aliucord.manager.ui.navigation.*
import com.aliucord.manager.ui.screen.*
import com.aliucord.manager.ui.theme.ManagerTheme
import com.aliucord.manager.ui.theme.Theme
import com.xinto.taxi.*
import dev.olshevski.navigation.reimagined.*
import org.koin.android.ext.android.inject
val aliucordDir = Environment.getExternalStorageDirectory().resolve("Aliucord")
@ -41,16 +39,10 @@ class MainActivity : ComponentActivity() {
isDarkTheme = preferences.theme == Theme.DARK || preferences.theme == Theme.SYSTEM && isSystemInDarkTheme(),
isDynamicColor = preferences.dynamicColor
) {
val navigator = rememberBackstackNavigator<AppDestination>(AppDestination.Home)
val homeRootNavigator = rememberNavigator(HomeDestination.HOME)
val navController = rememberNavController<AppDestination>(AppDestination.Home)
BackHandler {
if (!navigator.pop()) {
if (homeRootNavigator.currentDestination == HomeDestination.HOME)
finish()
else
homeRootNavigator.replace(HomeDestination.HOME)
}
navController.back()
}
StoragePermissionsDialog()
@ -64,28 +56,34 @@ class MainActivity : ComponentActivity() {
UpdaterDialog()
}
Taxi(
modifier = Modifier.fillMaxSize(),
navigator = navigator,
transitionSpec = { fadeIn() with fadeOut() }
) { destination ->
when (destination) {
is AppDestination.Home -> MainRootScreen(
mainRootNavigator = homeRootNavigator,
onInstallClick = { navigator.push(AppDestination.Install(it)) },
onAboutClick = { navigator.push(AppDestination.About) }
)
AnimatedNavHost(
controller = navController,
transitionSpec = { _, _, _ -> fadeIn() with fadeOut() }
) {
when (val dest = this.currentHostEntry.destination) {
is BaseScreenDestination -> BaseScreen(
currentNavItem = dest,
bottomNavItems = listOf(AppDestination.Home, AppDestination.Plugins, AppDestination.Settings),
onNavChanged = { navController.navigate(it) }
) {
when (dest) {
is AppDestination.Home -> HomeScreen(
onClickInstall = { data ->
navController.replaceAll(AppDestination.Install(data))
}
)
is AppDestination.Plugins -> PluginsScreen()
is AppDestination.Settings -> SettingsScreen()
}
}
is AppDestination.Install -> InstallerScreen(
installData = destination.installData,
onBackClick = navigator::pop
installData = dest.installData,
onBackClick = { navController.back() }
)
is AppDestination.About -> AboutScreen(
onBackClick = navigator::pop
onBackClick = { navController.back() }
)
else -> {}
}
}
}

View file

@ -1,5 +1,7 @@
package com.aliucord.manager.ui.navigation
import android.app.Activity
import android.os.Parcelable
import androidx.annotation.StringRes
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.*
@ -7,32 +9,58 @@ import androidx.compose.material.icons.outlined.*
import androidx.compose.ui.graphics.vector.ImageVector
import com.aliucord.manager.R
import com.aliucord.manager.ui.screen.InstallData
import com.xinto.taxi.Destination
import dev.olshevski.navigation.reimagined.*
import kotlinx.parcelize.Parcelize
import kotlinx.parcelize.RawValue
@Parcelize
sealed interface AppDestination : Destination {
sealed class BaseScreenDestination(
val selectedIcon: @RawValue ImageVector,
val unselectedIcon: @RawValue ImageVector,
@StringRes val label: Int
) : AppDestination
@Parcelize
sealed interface AppDestination : Parcelable {
@Parcelize
object Home : AppDestination
object Home : BaseScreenDestination(
Icons.Default.Home,
Icons.Outlined.Home,
R.string.navigation_home
)
@Parcelize
object Plugins : BaseScreenDestination(
Icons.Default.Extension,
Icons.Outlined.Extension,
R.string.plugins_title
)
@Parcelize
object Settings : BaseScreenDestination(
Icons.Default.Settings,
Icons.Outlined.Settings,
R.string.navigation_settings
)
@Parcelize
data class Install(val installData: InstallData) : AppDestination
@Parcelize
object About : AppDestination
@Parcelize
object Settings : AppDestination
}
@Parcelize
enum class HomeDestination(
val selectedIcon: @RawValue ImageVector,
val unselectedIcon: @RawValue ImageVector,
@StringRes val label: Int
) : Destination {
HOME(Icons.Default.Home, Icons.Outlined.Home, R.string.navigation_home),
PLUGINS(Icons.Default.Extension, Icons.Outlined.Extension, R.string.plugins_title),
SETTINGS(Icons.Default.Settings, Icons.Outlined.Settings, R.string.navigation_settings)
context(Activity)
fun NavController<AppDestination>.back() {
val topDest = backstack.entries.lastOrNull()?.destination
if (topDest == AppDestination.Home) {
finish()
} else if (topDest is BaseScreenDestination) {
replaceAll(AppDestination.Home)
} else if (backstack.entries.size > 1) {
pop()
} else {
replaceAll(AppDestination.Home)
}
}

View file

@ -0,0 +1,83 @@
@file:OptIn(ExperimentalMaterial3Api::class)
package com.aliucord.manager.ui.navigation
import androidx.compose.animation.*
import androidx.compose.foundation.layout.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Info
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import com.aliucord.manager.BuildConfig
import com.aliucord.manager.R
import com.aliucord.manager.ui.screen.*
@Composable
fun BaseScreen(
currentNavItem: BaseScreenDestination,
bottomNavItems: List<BaseScreenDestination>,
onNavChanged: (AppDestination) -> Unit,
content: @Composable () -> Unit
) {
Scaffold(
topBar = {
TopAppBar(
title = { Text(stringResource(currentNavItem.label)) },
actions = {
val localUriHandler = LocalUriHandler.current
IconButton(
onClick = {
localUriHandler.openUri("https://discord.gg/${BuildConfig.SUPPORT_SERVER}")
}
) {
Icon(
painter = painterResource(R.drawable.ic_discord),
contentDescription = stringResource(R.string.support_server)
)
}
IconButton(onClick = { onNavChanged(AppDestination.About) }) {
Icon(
imageVector = Icons.Default.Info,
contentDescription = stringResource(R.string.navigation_about)
)
}
}
)
},
bottomBar = {
NavigationBar {
for (navItem in bottomNavItems) {
NavigationBarItem(
selected = currentNavItem == navItem,
icon = {
Icon(
imageVector = if (currentNavItem == navItem) {
navItem.selectedIcon
} else {
navItem.unselectedIcon
},
contentDescription = null,
)
},
label = { Text(stringResource(navItem.label)) },
onClick = { onNavChanged(navItem) }
)
}
}
}
) { paddingValues ->
Box(
modifier = Modifier
.padding(paddingValues)
.fillMaxSize()
) {
content()
}
}
}

View file

@ -1,98 +0,0 @@
package com.aliucord.manager.ui.screen
import androidx.compose.animation.*
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Info
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import com.aliucord.manager.BuildConfig
import com.aliucord.manager.R
import com.aliucord.manager.ui.navigation.HomeDestination
import com.xinto.taxi.RegularNavigator
import com.xinto.taxi.Taxi
@OptIn(ExperimentalMaterial3Api::class, ExperimentalAnimationApi::class)
@Composable
fun MainRootScreen(
mainRootNavigator: RegularNavigator<HomeDestination>,
onInstallClick: (InstallData) -> Unit,
onAboutClick: () -> Unit
) {
Scaffold(
topBar = {
TopAppBar(
title = { Text(stringResource(mainRootNavigator.currentDestination.label)) },
actions = {
val localUriHandler = LocalUriHandler.current
IconButton(
onClick = {
localUriHandler.openUri("https://discord.gg/${BuildConfig.SUPPORT_SERVER}")
}
) {
Icon(
painter = painterResource(R.drawable.ic_discord),
contentDescription = stringResource(R.string.support_server)
)
}
IconButton(onClick = onAboutClick) {
Icon(
imageVector = Icons.Default.Info,
contentDescription = stringResource(R.string.navigation_about)
)
}
}
)
},
bottomBar = {
val currentDestination = mainRootNavigator.currentDestination
NavigationBar {
HomeDestination.values().forEach { destination ->
NavigationBarItem(
selected = currentDestination == destination,
icon = {
if (currentDestination == destination) {
Icon(
imageVector = destination.selectedIcon,
contentDescription = stringResource(destination.label)
)
} else {
Icon(
imageVector = destination.unselectedIcon,
contentDescription = stringResource(destination.label)
)
}
},
label = { Text(stringResource(destination.label)) },
onClick = { mainRootNavigator.replace(destination) }
)
}
}
}
) { paddingValues ->
Taxi(
modifier = Modifier
.padding(paddingValues)
.fillMaxSize(),
navigator = mainRootNavigator,
transitionSpec = { fadeIn() with fadeOut() }
) { destination ->
when (destination) {
HomeDestination.HOME -> HomeScreen(
onClickInstall = onInstallClick
)
HomeDestination.PLUGINS -> PluginsScreen()
HomeDestination.SETTINGS -> SettingsScreen()
}
}
}
}