feat: home screen compose previews
This commit is contained in:
parent
fdf3470973
commit
bb876526d0
7 changed files with 237 additions and 47 deletions
|
|
@ -0,0 +1,22 @@
|
|||
package com.aliucord.manager.ui.previews.screens.home
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.aliucord.manager.ui.components.ManagerTheme
|
||||
import com.aliucord.manager.ui.screens.home.HomeScreenFailureContent
|
||||
import com.aliucord.manager.ui.screens.home.components.HomeAppBar
|
||||
|
||||
@Composable
|
||||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO)
|
||||
private fun HomeScreenFailedPreview() {
|
||||
ManagerTheme {
|
||||
Scaffold(
|
||||
topBar = { HomeAppBar() },
|
||||
) { padding ->
|
||||
HomeScreenFailureContent(padding = padding)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
package com.aliucord.manager.ui.previews.screens.home
|
||||
|
||||
import android.content.res.Configuration
|
||||
import android.graphics.BitmapFactory
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.asImageBitmap
|
||||
import androidx.compose.ui.graphics.painter.BitmapPainter
|
||||
import androidx.compose.ui.tooling.preview.*
|
||||
import com.aliucord.manager.ui.components.ManagerTheme
|
||||
import com.aliucord.manager.ui.screens.home.*
|
||||
import com.aliucord.manager.ui.screens.home.components.HomeAppBar
|
||||
import com.aliucord.manager.ui.util.DiscordVersion
|
||||
import io.ktor.util.decodeBase64Bytes
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
// This preview has animations that cannot be properly viewed from an IDE
|
||||
|
||||
@Composable
|
||||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO)
|
||||
private fun HomeScreenLoadedPreview(
|
||||
@PreviewParameter(TextBannerParametersProvider::class)
|
||||
parameters: HomeScreenParameters,
|
||||
) {
|
||||
ManagerTheme {
|
||||
Scaffold(
|
||||
topBar = { HomeAppBar() },
|
||||
) { padding ->
|
||||
HomeScreenLoadedContent(
|
||||
state = parameters.state,
|
||||
supportedVersion = parameters.supportedVersion,
|
||||
padding = padding,
|
||||
onClickInstall = {},
|
||||
onUpdate = {},
|
||||
onOpenApp = {},
|
||||
onOpenAppInfo = {},
|
||||
onOpenPlugins = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private data class HomeScreenParameters(
|
||||
val state: InstallsState.Fetched,
|
||||
val supportedVersion: DiscordVersion,
|
||||
)
|
||||
|
||||
private class TextBannerParametersProvider : PreviewParameterProvider<HomeScreenParameters> {
|
||||
private val stableVersion = DiscordVersion.Existing(DiscordVersion.Type.STABLE, "126.21", 126021)
|
||||
private val aliucordIconBytes =
|
||||
"/9j/4AAQSkZJRgABAQAAAQABAAD/4gHYSUNDX1BST0ZJTEUAAQEAAAHIAAAAAAQwAABtbnRyUkdCIFhZWiAH4AABAAEAAAAAAABhY3NwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAA9tYAAQAAAADTLQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlkZXNjAAAA8AAAACRyWFlaAAABFAAAABRnWFlaAAABKAAAABRiWFlaAAABPAAAABR3dHB0AAABUAAAABRyVFJDAAABZAAAAChnVFJDAAABZAAAAChiVFJDAAABZAAAAChjcHJ0AAABjAAAADxtbHVjAAAAAAAAAAEAAAAMZW5VUwAAAAgAAAAcAHMAUgBHAEJYWVogAAAAAAAAb6IAADj1AAADkFhZWiAAAAAAAABimQAAt4UAABjaWFlaIAAAAAAAACSgAAAPhAAAts9YWVogAAAAAAAA9tYAAQAAAADTLXBhcmEAAAAAAAQAAAACZmYAAPKnAAANWQAAE9AAAApbAAAAAAAAAABtbHVjAAAAAAAAAAEAAAAMZW5VUwAAACAAAAAcAEcAbwBvAGcAbABlACAASQBuAGMALgAgADIAMAAxADb/2wBDAKBueIx4ZKCMgoy0qqC+8P//8Nzc8P//////////////////////////////////////////////////////////2wBDAaq0tPDS8P//////////////////////////////////////////////////////////////////////////////wAARCAC9AL0DASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAIDAf/EACIQAQEAAgEFAAIDAAAAAAAAAAABAhEhAxIxQVETMiJhcf/EABcBAQEBAQAAAAAAAAAAAAAAAAABAgP/xAAZEQEBAQEBAQAAAAAAAAAAAAAAARECEjH/2gAMAwEAAhEDEQA/AMsce7/Gkkngk1NOoxboAIAAAAAAAAAAAAAAAAAAm4ys7NXVbJyx2LKoAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHZLfRcbJug4AABJugDtxs9OAAAAAAAAAAAAAA7jN0HccN81cxk9OityBZuaAVP459OyKBMifxwxw1dqAyBrYCpuEvhFmq1TnNwZsZgIyAAAAAAAANcJqM8ZutRrkAVoAAAAAAAAABnnNVLTObjNGKACAAAAAAL6c9rcxmsY6rcALdTYrlyk8kzlZeRGPTYThdzSlbC2TyMsruiW4vvimK+nedIkqwFaGN4rZnnP5DPSQEZAAAAAJ5BtPACug5n+tdAYi8sL6cmFqOeO9P2sk1NCtwYtk5Yb5gljNWH7Odt+NMce2IkjoCtiOp6WjqeIJfiAEYAAAACeYANgllnAroA5lbJxAdEzOe+FblDQAAAAcuUntyZW3iCaoAUT1PEUjOy8CX4gBGAAAAAACWzw0mf1mBLjYZS2eFTqfVa9O9TWv7Zu27u3EZtd7r9O/L64Brvdfrm79AHZ55asVY56mhZWjlykRc7Ui3pWWdqQGQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHMbuOsZbLw0xy2LYoAQAAAAAAAAAAAAAAAAAARnlzqGWdnEQNSP/2Q=="
|
||||
.decodeBase64Bytes()
|
||||
private val aliucordIcon = BitmapFactory
|
||||
.decodeByteArray(aliucordIconBytes, 0, aliucordIconBytes.size)
|
||||
.asImageBitmap()
|
||||
.let(::BitmapPainter)
|
||||
|
||||
override val values = sequenceOf(
|
||||
HomeScreenParameters(
|
||||
supportedVersion = stableVersion,
|
||||
state = InstallsState.Fetched(
|
||||
persistentListOf(
|
||||
InstallData(
|
||||
name = "Aliucord",
|
||||
packageName = "com.aliucord",
|
||||
version = stableVersion,
|
||||
icon = aliucordIcon,
|
||||
isUpToDate = true,
|
||||
)
|
||||
)
|
||||
),
|
||||
),
|
||||
HomeScreenParameters(
|
||||
supportedVersion = stableVersion,
|
||||
state = InstallsState.Fetched(
|
||||
persistentListOf(
|
||||
InstallData(
|
||||
name = "Discord",
|
||||
packageName = "com.discord",
|
||||
version = stableVersion,
|
||||
icon = aliucordIcon,
|
||||
isUpToDate = false,
|
||||
)
|
||||
)
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package com.aliucord.manager.ui.previews.screens.home
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.aliucord.manager.ui.components.ManagerTheme
|
||||
import com.aliucord.manager.ui.screens.home.HomeScreenLoadingContent
|
||||
import com.aliucord.manager.ui.screens.home.components.HomeAppBar
|
||||
|
||||
// This preview cannot be properly viewed from an IDE
|
||||
|
||||
@Composable
|
||||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO)
|
||||
private fun HomeScreenLoadingPreview() {
|
||||
ManagerTheme {
|
||||
Scaffold(
|
||||
topBar = { HomeAppBar() },
|
||||
) { padding ->
|
||||
HomeScreenLoadingContent(padding = padding)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package com.aliucord.manager.ui.previews.screens.home
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.aliucord.manager.ui.components.ManagerTheme
|
||||
import com.aliucord.manager.ui.screens.home.HomeScreenNoneContent
|
||||
import com.aliucord.manager.ui.screens.home.components.HomeAppBar
|
||||
|
||||
@Composable
|
||||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO)
|
||||
private fun HomeScreenNonePreview() {
|
||||
ManagerTheme {
|
||||
Scaffold(
|
||||
topBar = { HomeAppBar() },
|
||||
) { padding ->
|
||||
HomeScreenNoneContent(
|
||||
padding = padding,
|
||||
onClickInstall = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -13,7 +13,6 @@ import androidx.core.graphics.drawable.toBitmap
|
|||
import androidx.core.net.toUri
|
||||
import cafe.adriel.voyager.core.model.ScreenModel
|
||||
import cafe.adriel.voyager.core.model.screenModelScope
|
||||
import cafe.adriel.voyager.navigator.Navigator
|
||||
import com.aliucord.manager.BuildConfig
|
||||
import com.aliucord.manager.R
|
||||
import com.aliucord.manager.network.models.BuildInfo
|
||||
|
|
@ -43,7 +42,7 @@ class HomeModel(
|
|||
var supportedVersion by mutableStateOf<DiscordVersion>(DiscordVersion.None)
|
||||
private set
|
||||
|
||||
var installations by mutableStateOf<InstallsState>(InstallsState.Fetching)
|
||||
var state by mutableStateOf<InstallsState>(InstallsState.Fetching)
|
||||
private set
|
||||
|
||||
private var remoteDataJson: BuildInfo? = null
|
||||
|
|
@ -58,7 +57,7 @@ class HomeModel(
|
|||
}
|
||||
}
|
||||
|
||||
fun launchApp(packageName: String) {
|
||||
fun openApp(packageName: String) {
|
||||
val launchIntent = application.packageManager
|
||||
.getLaunchIntentForPackage(packageName)
|
||||
|
||||
|
|
@ -78,7 +77,7 @@ class HomeModel(
|
|||
}
|
||||
|
||||
fun fetchInstallations() = screenModelScope.launchBlock {
|
||||
installations = InstallsState.Fetching
|
||||
state = InstallsState.Fetching
|
||||
|
||||
try {
|
||||
val packageManager = application.packageManager
|
||||
|
|
@ -120,39 +119,40 @@ class HomeModel(
|
|||
)
|
||||
}.toImmutableList()
|
||||
|
||||
installations = if (aliucordInstallations.isNotEmpty()) {
|
||||
state = if (aliucordInstallations.isNotEmpty()) {
|
||||
InstallsState.Fetched(data = aliucordInstallations)
|
||||
} else {
|
||||
InstallsState.None
|
||||
}
|
||||
} catch (t: Throwable) {
|
||||
Log.e(BuildConfig.TAG, "Failed to query Aliucord installations", t)
|
||||
installations = InstallsState.Error
|
||||
state = InstallsState.Error
|
||||
}
|
||||
}
|
||||
|
||||
// Launches the patching screen with prefilled options according to the existing APK
|
||||
fun updateAliucord(data: InstallData, navigator: Navigator) = screenModelScope.launchBlock {
|
||||
/**
|
||||
* Creates a [PatchOptionsScreen] that can be navigated to,
|
||||
* with prefilled options from an existing installation.
|
||||
*/
|
||||
fun createPrefilledPatchOptsScreen(packageName: String): PatchOptionsScreen {
|
||||
val metadata = try {
|
||||
val applicationInfo = application.packageManager.getApplicationInfo(data.packageName, 0)
|
||||
val applicationInfo = application.packageManager.getApplicationInfo(packageName, 0)
|
||||
val metadataFile = ZipReader(applicationInfo.publicSourceDir)
|
||||
.use { it.openEntry("aliucord.json")?.read() }
|
||||
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
metadataFile?.let { json.decodeFromStream<InstallMetadata>(it.inputStream()) }
|
||||
} catch (t: Throwable) {
|
||||
Log.w(BuildConfig.TAG, "Failed to parse Aliucord install metadata from package ${data.packageName}", t)
|
||||
Log.w(BuildConfig.TAG, "Failed to parse Aliucord install metadata from package ${packageName}", t)
|
||||
null
|
||||
}
|
||||
|
||||
val patchOptions = metadata?.options
|
||||
?: PatchOptions.Default.copy(packageName = data.packageName)
|
||||
?: PatchOptions.Default.copy(packageName = packageName)
|
||||
|
||||
navigator.push(
|
||||
PatchOptionsScreen(
|
||||
prefilledOptions = patchOptions,
|
||||
supportedVersion = supportedVersion,
|
||||
)
|
||||
return PatchOptionsScreen(
|
||||
prefilledOptions = patchOptions,
|
||||
supportedVersion = supportedVersion,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,11 +8,13 @@ package com.aliucord.manager.ui.screens.home
|
|||
|
||||
import android.os.Parcelable
|
||||
import androidx.compose.animation.*
|
||||
import androidx.compose.animation.core.MutableTransitionState
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
|
|
@ -32,6 +34,7 @@ import com.aliucord.manager.ui.screens.plugins.PluginsScreen
|
|||
import com.aliucord.manager.ui.util.DiscordVersion
|
||||
import com.aliucord.manager.ui.util.paddings.PaddingValuesSides
|
||||
import com.aliucord.manager.ui.util.paddings.exclude
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.parcelize.IgnoredOnParcel
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
|
|
@ -43,7 +46,9 @@ class HomeScreen : Screen, Parcelable {
|
|||
@Composable
|
||||
override fun Content() {
|
||||
val navigator = LocalNavigator.currentOrThrow
|
||||
val scope = rememberCoroutineScope()
|
||||
val model = getScreenModel<HomeModel>()
|
||||
val onClickInstall = remember { { navigator.push(PatchOptionsScreen(supportedVersion = model.supportedVersion)) } }
|
||||
|
||||
// Refresh installations list when the screen changes or activity resumes
|
||||
LifecycleResumeEffect(Unit) {
|
||||
|
|
@ -55,29 +60,37 @@ class HomeScreen : Screen, Parcelable {
|
|||
Scaffold(
|
||||
topBar = { HomeAppBar() },
|
||||
) { padding ->
|
||||
when (model.installations) {
|
||||
is InstallsState.Fetched -> LoadedContent(
|
||||
model = model,
|
||||
when (val state = model.state) {
|
||||
is InstallsState.Fetched -> HomeScreenLoadedContent(
|
||||
state = state,
|
||||
supportedVersion = model.supportedVersion,
|
||||
padding = padding,
|
||||
onClickInstall = { navigator.push(PatchOptionsScreen(supportedVersion = model.supportedVersion)) },
|
||||
onClickInstall = onClickInstall,
|
||||
onUpdate = {
|
||||
scope.launch {
|
||||
navigator.push(model.createPrefilledPatchOptsScreen(it))
|
||||
}
|
||||
},
|
||||
onOpenApp = model::openApp,
|
||||
onOpenAppInfo = model::openAppInfo,
|
||||
onOpenPlugins = { navigator.push(PluginsScreen()) }, // TODO: install-specific plugins
|
||||
)
|
||||
|
||||
InstallsState.Fetching -> LoadingContent(padding = padding)
|
||||
InstallsState.Fetching -> HomeScreenLoadingContent(padding = padding)
|
||||
|
||||
InstallsState.None -> NoInstallsContent(
|
||||
onClickInstall = { navigator.push(PatchOptionsScreen(supportedVersion = model.supportedVersion)) },
|
||||
modifier = Modifier
|
||||
.padding(padding.exclude(PaddingValuesSides.Bottom)),
|
||||
InstallsState.None -> HomeScreenNoneContent(
|
||||
padding = padding,
|
||||
onClickInstall = onClickInstall,
|
||||
)
|
||||
|
||||
InstallsState.Error -> FailureContent(padding = padding)
|
||||
InstallsState.Error -> HomeScreenFailureContent(padding = padding)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun LoadingContent(padding: PaddingValues) {
|
||||
fun HomeScreenLoadingContent(padding: PaddingValues) {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = Modifier
|
||||
|
|
@ -86,14 +99,32 @@ private fun LoadingContent(padding: PaddingValues) {
|
|||
.padding(top = 16.dp, start = 16.dp, end = 16.dp)
|
||||
) {
|
||||
ProjectHeader()
|
||||
|
||||
AnimatedVisibility(
|
||||
visibleState = remember { MutableTransitionState(false) }.apply { targetState = true },
|
||||
enter = fadeIn(animationSpec = tween(durationMillis = 800)),
|
||||
exit = ExitTransition.None,
|
||||
) {
|
||||
Box(
|
||||
contentAlignment = Alignment.Center,
|
||||
content = { CircularProgressIndicator() },
|
||||
modifier = Modifier
|
||||
.fillMaxSize(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun LoadedContent(
|
||||
model: HomeModel,
|
||||
fun HomeScreenLoadedContent(
|
||||
state: InstallsState.Fetched,
|
||||
supportedVersion: DiscordVersion,
|
||||
padding: PaddingValues,
|
||||
onClickInstall: () -> Unit,
|
||||
onUpdate: (packageName: String) -> Unit,
|
||||
onOpenApp: (packageName: String) -> Unit,
|
||||
onOpenAppInfo: (packageName: String) -> Unit,
|
||||
onOpenPlugins: (packageName: String) -> Unit,
|
||||
) {
|
||||
LazyColumn(
|
||||
verticalArrangement = Arrangement.spacedBy(6.dp),
|
||||
|
|
@ -122,28 +153,26 @@ private fun LoadedContent(
|
|||
|
||||
item(key = "SUPPORTED_VERSION") {
|
||||
AnimatedVersionDisplay(
|
||||
version = model.supportedVersion,
|
||||
version = supportedVersion,
|
||||
modifier = Modifier.padding(bottom = 30.dp),
|
||||
)
|
||||
}
|
||||
|
||||
val installations = (model.installations as? InstallsState.Fetched)?.data
|
||||
val installations = (state as? InstallsState.Fetched)?.data
|
||||
?: return@LazyColumn
|
||||
|
||||
items(installations, key = { it.packageName }) {
|
||||
AnimatedVisibility(
|
||||
enter = fadeIn() + slideInHorizontally { it * -2 },
|
||||
exit = fadeOut() + slideOutHorizontally { it * 2 },
|
||||
visible = model.supportedVersion !is DiscordVersion.None,
|
||||
visible = supportedVersion !is DiscordVersion.None,
|
||||
) {
|
||||
val navigator = LocalNavigator.currentOrThrow
|
||||
|
||||
InstalledItemCard(
|
||||
data = it,
|
||||
onUpdate = { model.updateAliucord(it, navigator) },
|
||||
onOpenApp = { model.launchApp(it.packageName) },
|
||||
onOpenInfo = { model.openAppInfo(it.packageName) },
|
||||
onOpenPlugins = { navigator.push(PluginsScreen()) }, // TODO: install-specific plugins
|
||||
onUpdate = { onUpdate(it.packageName) },
|
||||
onOpenApp = { onOpenApp(it.packageName) },
|
||||
onOpenInfo = { onOpenAppInfo(it.packageName) },
|
||||
onOpenPlugins = { onOpenPlugins(it.packageName) },
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
}
|
||||
|
|
@ -152,7 +181,8 @@ private fun LoadedContent(
|
|||
}
|
||||
|
||||
@Composable
|
||||
private fun NoInstallsContent(
|
||||
fun HomeScreenNoneContent(
|
||||
padding: PaddingValues,
|
||||
onClickInstall: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
|
|
@ -160,8 +190,9 @@ private fun NoInstallsContent(
|
|||
verticalArrangement = Arrangement.spacedBy(6.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.padding(16.dp),
|
||||
.padding(padding)
|
||||
.padding(16.dp)
|
||||
.fillMaxSize(),
|
||||
) {
|
||||
ProjectHeader()
|
||||
|
||||
|
|
@ -198,7 +229,7 @@ private fun NoInstallsContent(
|
|||
}
|
||||
|
||||
@Composable
|
||||
fun FailureContent(
|
||||
fun HomeScreenFailureContent(
|
||||
padding: PaddingValues,
|
||||
) {
|
||||
Column(
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||
import com.aliucord.manager.R
|
||||
import com.aliucord.manager.ui.screens.about.AboutScreen
|
||||
import com.aliucord.manager.ui.screens.settings.SettingsScreen
|
||||
|
|
@ -15,16 +14,16 @@ fun HomeAppBar() {
|
|||
TopAppBar(
|
||||
title = {},
|
||||
actions = {
|
||||
val navigator = LocalNavigator.currentOrThrow
|
||||
val navigator = LocalNavigator.current
|
||||
|
||||
IconButton(onClick = { navigator.push(AboutScreen()) }) {
|
||||
IconButton(onClick = { navigator?.push(AboutScreen()) }) {
|
||||
Icon(
|
||||
painter = painterResource(R.drawable.ic_info),
|
||||
contentDescription = stringResource(R.string.navigation_about)
|
||||
)
|
||||
}
|
||||
|
||||
IconButton(onClick = { navigator.push(SettingsScreen()) }) {
|
||||
IconButton(onClick = { navigator?.push(SettingsScreen()) }) {
|
||||
Icon(
|
||||
painter = painterResource(R.drawable.ic_settings),
|
||||
contentDescription = stringResource(R.string.navigation_settings)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue