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 androidx.core.net.toUri
|
||||||
import cafe.adriel.voyager.core.model.ScreenModel
|
import cafe.adriel.voyager.core.model.ScreenModel
|
||||||
import cafe.adriel.voyager.core.model.screenModelScope
|
import cafe.adriel.voyager.core.model.screenModelScope
|
||||||
import cafe.adriel.voyager.navigator.Navigator
|
|
||||||
import com.aliucord.manager.BuildConfig
|
import com.aliucord.manager.BuildConfig
|
||||||
import com.aliucord.manager.R
|
import com.aliucord.manager.R
|
||||||
import com.aliucord.manager.network.models.BuildInfo
|
import com.aliucord.manager.network.models.BuildInfo
|
||||||
|
|
@ -43,7 +42,7 @@ class HomeModel(
|
||||||
var supportedVersion by mutableStateOf<DiscordVersion>(DiscordVersion.None)
|
var supportedVersion by mutableStateOf<DiscordVersion>(DiscordVersion.None)
|
||||||
private set
|
private set
|
||||||
|
|
||||||
var installations by mutableStateOf<InstallsState>(InstallsState.Fetching)
|
var state by mutableStateOf<InstallsState>(InstallsState.Fetching)
|
||||||
private set
|
private set
|
||||||
|
|
||||||
private var remoteDataJson: BuildInfo? = null
|
private var remoteDataJson: BuildInfo? = null
|
||||||
|
|
@ -58,7 +57,7 @@ class HomeModel(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun launchApp(packageName: String) {
|
fun openApp(packageName: String) {
|
||||||
val launchIntent = application.packageManager
|
val launchIntent = application.packageManager
|
||||||
.getLaunchIntentForPackage(packageName)
|
.getLaunchIntentForPackage(packageName)
|
||||||
|
|
||||||
|
|
@ -78,7 +77,7 @@ class HomeModel(
|
||||||
}
|
}
|
||||||
|
|
||||||
fun fetchInstallations() = screenModelScope.launchBlock {
|
fun fetchInstallations() = screenModelScope.launchBlock {
|
||||||
installations = InstallsState.Fetching
|
state = InstallsState.Fetching
|
||||||
|
|
||||||
try {
|
try {
|
||||||
val packageManager = application.packageManager
|
val packageManager = application.packageManager
|
||||||
|
|
@ -120,39 +119,40 @@ class HomeModel(
|
||||||
)
|
)
|
||||||
}.toImmutableList()
|
}.toImmutableList()
|
||||||
|
|
||||||
installations = if (aliucordInstallations.isNotEmpty()) {
|
state = if (aliucordInstallations.isNotEmpty()) {
|
||||||
InstallsState.Fetched(data = aliucordInstallations)
|
InstallsState.Fetched(data = aliucordInstallations)
|
||||||
} else {
|
} else {
|
||||||
InstallsState.None
|
InstallsState.None
|
||||||
}
|
}
|
||||||
} catch (t: Throwable) {
|
} catch (t: Throwable) {
|
||||||
Log.e(BuildConfig.TAG, "Failed to query Aliucord installations", t)
|
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 metadata = try {
|
||||||
val applicationInfo = application.packageManager.getApplicationInfo(data.packageName, 0)
|
val applicationInfo = application.packageManager.getApplicationInfo(packageName, 0)
|
||||||
val metadataFile = ZipReader(applicationInfo.publicSourceDir)
|
val metadataFile = ZipReader(applicationInfo.publicSourceDir)
|
||||||
.use { it.openEntry("aliucord.json")?.read() }
|
.use { it.openEntry("aliucord.json")?.read() }
|
||||||
|
|
||||||
@OptIn(ExperimentalSerializationApi::class)
|
@OptIn(ExperimentalSerializationApi::class)
|
||||||
metadataFile?.let { json.decodeFromStream<InstallMetadata>(it.inputStream()) }
|
metadataFile?.let { json.decodeFromStream<InstallMetadata>(it.inputStream()) }
|
||||||
} catch (t: Throwable) {
|
} 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
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
val patchOptions = metadata?.options
|
val patchOptions = metadata?.options
|
||||||
?: PatchOptions.Default.copy(packageName = data.packageName)
|
?: PatchOptions.Default.copy(packageName = packageName)
|
||||||
|
|
||||||
navigator.push(
|
return PatchOptionsScreen(
|
||||||
PatchOptionsScreen(
|
prefilledOptions = patchOptions,
|
||||||
prefilledOptions = patchOptions,
|
supportedVersion = supportedVersion,
|
||||||
supportedVersion = supportedVersion,
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,13 @@ package com.aliucord.manager.ui.screens.home
|
||||||
|
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import androidx.compose.animation.*
|
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.layout.*
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.alpha
|
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.DiscordVersion
|
||||||
import com.aliucord.manager.ui.util.paddings.PaddingValuesSides
|
import com.aliucord.manager.ui.util.paddings.PaddingValuesSides
|
||||||
import com.aliucord.manager.ui.util.paddings.exclude
|
import com.aliucord.manager.ui.util.paddings.exclude
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.parcelize.IgnoredOnParcel
|
import kotlinx.parcelize.IgnoredOnParcel
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
|
|
@ -43,7 +46,9 @@ class HomeScreen : Screen, Parcelable {
|
||||||
@Composable
|
@Composable
|
||||||
override fun Content() {
|
override fun Content() {
|
||||||
val navigator = LocalNavigator.currentOrThrow
|
val navigator = LocalNavigator.currentOrThrow
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
val model = getScreenModel<HomeModel>()
|
val model = getScreenModel<HomeModel>()
|
||||||
|
val onClickInstall = remember { { navigator.push(PatchOptionsScreen(supportedVersion = model.supportedVersion)) } }
|
||||||
|
|
||||||
// Refresh installations list when the screen changes or activity resumes
|
// Refresh installations list when the screen changes or activity resumes
|
||||||
LifecycleResumeEffect(Unit) {
|
LifecycleResumeEffect(Unit) {
|
||||||
|
|
@ -55,29 +60,37 @@ class HomeScreen : Screen, Parcelable {
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = { HomeAppBar() },
|
topBar = { HomeAppBar() },
|
||||||
) { padding ->
|
) { padding ->
|
||||||
when (model.installations) {
|
when (val state = model.state) {
|
||||||
is InstallsState.Fetched -> LoadedContent(
|
is InstallsState.Fetched -> HomeScreenLoadedContent(
|
||||||
model = model,
|
state = state,
|
||||||
|
supportedVersion = model.supportedVersion,
|
||||||
padding = padding,
|
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(
|
InstallsState.None -> HomeScreenNoneContent(
|
||||||
onClickInstall = { navigator.push(PatchOptionsScreen(supportedVersion = model.supportedVersion)) },
|
padding = padding,
|
||||||
modifier = Modifier
|
onClickInstall = onClickInstall,
|
||||||
.padding(padding.exclude(PaddingValuesSides.Bottom)),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
InstallsState.Error -> FailureContent(padding = padding)
|
InstallsState.Error -> HomeScreenFailureContent(padding = padding)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun LoadingContent(padding: PaddingValues) {
|
fun HomeScreenLoadingContent(padding: PaddingValues) {
|
||||||
Column(
|
Column(
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|
@ -86,14 +99,32 @@ private fun LoadingContent(padding: PaddingValues) {
|
||||||
.padding(top = 16.dp, start = 16.dp, end = 16.dp)
|
.padding(top = 16.dp, start = 16.dp, end = 16.dp)
|
||||||
) {
|
) {
|
||||||
ProjectHeader()
|
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
|
@Composable
|
||||||
private fun LoadedContent(
|
fun HomeScreenLoadedContent(
|
||||||
model: HomeModel,
|
state: InstallsState.Fetched,
|
||||||
|
supportedVersion: DiscordVersion,
|
||||||
padding: PaddingValues,
|
padding: PaddingValues,
|
||||||
onClickInstall: () -> Unit,
|
onClickInstall: () -> Unit,
|
||||||
|
onUpdate: (packageName: String) -> Unit,
|
||||||
|
onOpenApp: (packageName: String) -> Unit,
|
||||||
|
onOpenAppInfo: (packageName: String) -> Unit,
|
||||||
|
onOpenPlugins: (packageName: String) -> Unit,
|
||||||
) {
|
) {
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
verticalArrangement = Arrangement.spacedBy(6.dp),
|
verticalArrangement = Arrangement.spacedBy(6.dp),
|
||||||
|
|
@ -122,28 +153,26 @@ private fun LoadedContent(
|
||||||
|
|
||||||
item(key = "SUPPORTED_VERSION") {
|
item(key = "SUPPORTED_VERSION") {
|
||||||
AnimatedVersionDisplay(
|
AnimatedVersionDisplay(
|
||||||
version = model.supportedVersion,
|
version = supportedVersion,
|
||||||
modifier = Modifier.padding(bottom = 30.dp),
|
modifier = Modifier.padding(bottom = 30.dp),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val installations = (model.installations as? InstallsState.Fetched)?.data
|
val installations = (state as? InstallsState.Fetched)?.data
|
||||||
?: return@LazyColumn
|
?: return@LazyColumn
|
||||||
|
|
||||||
items(installations, key = { it.packageName }) {
|
items(installations, key = { it.packageName }) {
|
||||||
AnimatedVisibility(
|
AnimatedVisibility(
|
||||||
enter = fadeIn() + slideInHorizontally { it * -2 },
|
enter = fadeIn() + slideInHorizontally { it * -2 },
|
||||||
exit = fadeOut() + slideOutHorizontally { it * 2 },
|
exit = fadeOut() + slideOutHorizontally { it * 2 },
|
||||||
visible = model.supportedVersion !is DiscordVersion.None,
|
visible = supportedVersion !is DiscordVersion.None,
|
||||||
) {
|
) {
|
||||||
val navigator = LocalNavigator.currentOrThrow
|
|
||||||
|
|
||||||
InstalledItemCard(
|
InstalledItemCard(
|
||||||
data = it,
|
data = it,
|
||||||
onUpdate = { model.updateAliucord(it, navigator) },
|
onUpdate = { onUpdate(it.packageName) },
|
||||||
onOpenApp = { model.launchApp(it.packageName) },
|
onOpenApp = { onOpenApp(it.packageName) },
|
||||||
onOpenInfo = { model.openAppInfo(it.packageName) },
|
onOpenInfo = { onOpenAppInfo(it.packageName) },
|
||||||
onOpenPlugins = { navigator.push(PluginsScreen()) }, // TODO: install-specific plugins
|
onOpenPlugins = { onOpenPlugins(it.packageName) },
|
||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier.fillMaxWidth()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -152,7 +181,8 @@ private fun LoadedContent(
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun NoInstallsContent(
|
fun HomeScreenNoneContent(
|
||||||
|
padding: PaddingValues,
|
||||||
onClickInstall: () -> Unit,
|
onClickInstall: () -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
|
|
@ -160,8 +190,9 @@ private fun NoInstallsContent(
|
||||||
verticalArrangement = Arrangement.spacedBy(6.dp),
|
verticalArrangement = Arrangement.spacedBy(6.dp),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.fillMaxSize()
|
.padding(padding)
|
||||||
.padding(16.dp),
|
.padding(16.dp)
|
||||||
|
.fillMaxSize(),
|
||||||
) {
|
) {
|
||||||
ProjectHeader()
|
ProjectHeader()
|
||||||
|
|
||||||
|
|
@ -198,7 +229,7 @@ private fun NoInstallsContent(
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun FailureContent(
|
fun HomeScreenFailureContent(
|
||||||
padding: PaddingValues,
|
padding: PaddingValues,
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
|
||||||
import com.aliucord.manager.R
|
import com.aliucord.manager.R
|
||||||
import com.aliucord.manager.ui.screens.about.AboutScreen
|
import com.aliucord.manager.ui.screens.about.AboutScreen
|
||||||
import com.aliucord.manager.ui.screens.settings.SettingsScreen
|
import com.aliucord.manager.ui.screens.settings.SettingsScreen
|
||||||
|
|
@ -15,16 +14,16 @@ fun HomeAppBar() {
|
||||||
TopAppBar(
|
TopAppBar(
|
||||||
title = {},
|
title = {},
|
||||||
actions = {
|
actions = {
|
||||||
val navigator = LocalNavigator.currentOrThrow
|
val navigator = LocalNavigator.current
|
||||||
|
|
||||||
IconButton(onClick = { navigator.push(AboutScreen()) }) {
|
IconButton(onClick = { navigator?.push(AboutScreen()) }) {
|
||||||
Icon(
|
Icon(
|
||||||
painter = painterResource(R.drawable.ic_info),
|
painter = painterResource(R.drawable.ic_info),
|
||||||
contentDescription = stringResource(R.string.navigation_about)
|
contentDescription = stringResource(R.string.navigation_about)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
IconButton(onClick = { navigator.push(SettingsScreen()) }) {
|
IconButton(onClick = { navigator?.push(SettingsScreen()) }) {
|
||||||
Icon(
|
Icon(
|
||||||
painter = painterResource(R.drawable.ic_settings),
|
painter = painterResource(R.drawable.ic_settings),
|
||||||
contentDescription = stringResource(R.string.navigation_settings)
|
contentDescription = stringResource(R.string.navigation_settings)
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue