feat: better composable stability
This commit is contained in:
parent
a85f9adeb1
commit
b60d4bcbca
11 changed files with 61 additions and 31 deletions
|
|
@ -19,7 +19,9 @@ android {
|
|||
versionCode = 1
|
||||
versionName = "0.0.1"
|
||||
|
||||
vectorDrawables.useSupportLibrary = true
|
||||
vectorDrawables {
|
||||
useSupportLibrary = true
|
||||
}
|
||||
|
||||
buildConfigField("String", "TAG", "\"AliucordManager\"")
|
||||
buildConfigField("String", "SUPPORT_SERVER", "\"EsNDvBaHVU\"")
|
||||
|
|
@ -68,11 +70,20 @@ android {
|
|||
|
||||
kotlinOptions {
|
||||
jvmTarget = "11"
|
||||
freeCompilerArgs += "-Xcontext-receivers"
|
||||
freeCompilerArgs += listOf(
|
||||
"-Xcontext-receivers",
|
||||
"-P",
|
||||
"plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=${buildDir.resolve("report").absolutePath}",
|
||||
)
|
||||
}
|
||||
|
||||
buildFeatures.compose = true
|
||||
composeOptions.kotlinCompilerExtensionVersion = "1.3.1"
|
||||
buildFeatures {
|
||||
compose = true
|
||||
}
|
||||
|
||||
composeOptions {
|
||||
kotlinCompilerExtensionVersion = "1.3.1"
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
|
@ -114,6 +125,7 @@ dependencies {
|
|||
implementation("com.aliucord:axml:1.0.1")
|
||||
implementation("com.android.tools.build:apksig:7.4.0-beta04")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.0")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.5")
|
||||
}
|
||||
|
||||
fun getCurrentBranch(): String? =
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import com.aliucord.manager.ui.screen.*
|
|||
import com.aliucord.manager.ui.theme.ManagerTheme
|
||||
import com.aliucord.manager.ui.theme.Theme
|
||||
import dev.olshevski.navigation.reimagined.*
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import org.koin.android.ext.android.inject
|
||||
|
||||
val aliucordDir = Environment.getExternalStorageDirectory().resolve("Aliucord")
|
||||
|
|
@ -63,7 +64,7 @@ class MainActivity : ComponentActivity() {
|
|||
when (val dest = this.currentHostEntry.destination) {
|
||||
is BaseScreenDestination -> BaseScreen(
|
||||
currentNavItem = dest,
|
||||
bottomNavItems = listOf(AppDestination.Home, AppDestination.Plugins, AppDestination.Settings),
|
||||
bottomNavItems = persistentListOf(AppDestination.Home, AppDestination.Plugins, AppDestination.Settings),
|
||||
onNavChanged = { navController.replaceLast(it) }
|
||||
) {
|
||||
when (dest) {
|
||||
|
|
|
|||
|
|
@ -5,9 +5,10 @@
|
|||
|
||||
package com.aliucord.manager.domain.model
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.JsonObject
|
||||
|
||||
@Immutable
|
||||
@Serializable
|
||||
data class Manifest(
|
||||
val name: String,
|
||||
|
|
@ -17,7 +18,6 @@ data class Manifest(
|
|||
val updateUrl: String,
|
||||
val changelog: String?,
|
||||
val changelogMedia: String?,
|
||||
val links: JsonObject
|
||||
) {
|
||||
val repositoryUrl = updateUrl
|
||||
.replace("raw.githubusercontent.com", "github.com")
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
package com.aliucord.manager.domain.model
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.decodeFromStream
|
||||
|
|
@ -17,6 +18,7 @@ private val json = Json {
|
|||
}
|
||||
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
@Immutable
|
||||
data class Plugin(val file: File) {
|
||||
val manifest: Manifest
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import com.aliucord.manager.R
|
|||
import com.aliucord.manager.network.dto.Commit
|
||||
import com.aliucord.manager.ui.component.LoadFailure
|
||||
import com.aliucord.manager.ui.util.annotatingStringResource
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Composable
|
||||
|
|
@ -142,8 +143,10 @@ fun CommitItem(
|
|||
Text(
|
||||
annotatingStringResource(
|
||||
R.string.contributors_commit_title,
|
||||
commit.author.name,
|
||||
commit.sha.take(8)
|
||||
persistentListOf(
|
||||
commit.author.name,
|
||||
commit.sha.take(8),
|
||||
)
|
||||
) {
|
||||
when (it) {
|
||||
"name" -> SpanStyle(
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import androidx.compose.material.icons.Icons
|
|||
import androidx.compose.material.icons.filled.*
|
||||
import androidx.compose.material.icons.outlined.Circle
|
||||
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.clip
|
||||
|
|
@ -21,6 +21,7 @@ import androidx.compose.ui.semantics.semantics
|
|||
import androidx.compose.ui.text.font.FontStyle
|
||||
import androidx.compose.ui.unit.*
|
||||
import com.aliucord.manager.R
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlin.math.floor
|
||||
|
||||
enum class InstallStatus {
|
||||
|
|
@ -30,18 +31,23 @@ enum class InstallStatus {
|
|||
QUEUED
|
||||
}
|
||||
|
||||
data class InstallStepData(
|
||||
var nameResId: Int,
|
||||
var status: InstallStatus,
|
||||
var duration: Float = 0f,
|
||||
var cached: Boolean = false
|
||||
)
|
||||
@Stable
|
||||
class InstallStepData(
|
||||
val nameResId: Int,
|
||||
status: InstallStatus,
|
||||
duration: Float = 0f,
|
||||
cached: Boolean = false
|
||||
) {
|
||||
var status by mutableStateOf(status)
|
||||
var duration by mutableStateOf(duration)
|
||||
var cached by mutableStateOf(cached)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun InstallGroup(
|
||||
name: String,
|
||||
isCurrent: Boolean,
|
||||
subSteps: List<InstallStepData>,
|
||||
subSteps: ImmutableList<InstallStepData>,
|
||||
onClick: () -> Unit
|
||||
) {
|
||||
val status = when {
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import com.aliucord.manager.R
|
|||
import com.aliucord.manager.domain.model.Plugin
|
||||
import com.aliucord.manager.ui.util.annotatingStringResource
|
||||
import com.aliucord.manager.ui.util.joinToAnnotatedString
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
@Composable
|
||||
fun PluginCard(
|
||||
|
|
@ -51,8 +52,10 @@ fun PluginCard(
|
|||
Text(
|
||||
annotatingStringResource(
|
||||
R.string.plugins_plugin_title,
|
||||
plugin.manifest.name,
|
||||
plugin.manifest.version
|
||||
persistentListOf(
|
||||
plugin.manifest.name,
|
||||
plugin.manifest.version,
|
||||
)
|
||||
) {
|
||||
when (it) {
|
||||
"plugin" -> SpanStyle(fontWeight = FontWeight.Bold)
|
||||
|
|
|
|||
|
|
@ -15,11 +15,12 @@ import androidx.compose.ui.res.stringResource
|
|||
import com.aliucord.manager.BuildConfig
|
||||
import com.aliucord.manager.R
|
||||
import com.aliucord.manager.ui.screen.*
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
@Composable
|
||||
fun BaseScreen(
|
||||
currentNavItem: BaseScreenDestination,
|
||||
bottomNavItems: List<BaseScreenDestination>,
|
||||
bottomNavItems: ImmutableList<BaseScreenDestination>,
|
||||
onNavChanged: (AppDestination) -> Unit,
|
||||
content: @Composable () -> Unit
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -26,11 +26,13 @@ import com.aliucord.manager.ui.dialog.DiscordType
|
|||
import com.aliucord.manager.ui.dialog.DownloadMethod
|
||||
import com.aliucord.manager.ui.viewmodel.InstallViewModel
|
||||
import com.aliucord.manager.ui.viewmodel.InstallViewModel.InstallStepGroup
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import org.koin.androidx.compose.getViewModel
|
||||
import org.koin.core.parameter.parametersOf
|
||||
import java.util.*
|
||||
|
||||
@Immutable // this isn't *really* stable, but this never gets modified after being passed to a composable, so...
|
||||
@Parcelize
|
||||
data class InstallData(
|
||||
val downloadMethod: DownloadMethod,
|
||||
|
|
@ -91,7 +93,7 @@ fun InstallerScreen(
|
|||
name = stringResource(group.nameResId),
|
||||
isCurrent = expandedGroup == group,
|
||||
onClick = { expandedGroup = group },
|
||||
subSteps = viewModel.getSteps(group)
|
||||
subSteps = viewModel.getSteps(group).toImmutableList(),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import androidx.annotation.StringRes
|
|||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.*
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
context(AnnotatedString.Builder)
|
||||
inline fun <T> Iterable<T>.joinToAnnotatedString(
|
||||
|
|
@ -35,12 +36,11 @@ context(AnnotatedString.Builder)
|
|||
@Composable
|
||||
inline fun annotatingStringResource(
|
||||
@StringRes id: Int,
|
||||
vararg args: Any,
|
||||
crossinline annotationHandler: @Composable (annotationName: String) -> SpanStyle?
|
||||
args: ImmutableList<Any>,
|
||||
crossinline annotationHandler: @Composable (annotationName: String) -> SpanStyle?,
|
||||
): AnnotatedString {
|
||||
val string = stringResource(id, *args)
|
||||
val string = stringResource(id, *args.toTypedArray())
|
||||
|
||||
// TODO: figure out a way to put this in remember {} while still having @Composable annotationHandler
|
||||
val markerIndexes = string
|
||||
.mapIndexedNotNull { index, elem -> index.takeIf { elem == '§' } }
|
||||
.takeIf { it.isNotEmpty() && it.size % 3 == 0 }
|
||||
|
|
|
|||
|
|
@ -583,8 +583,7 @@ class InstallViewModel(
|
|||
|
||||
@OptIn(ExperimentalTime::class)
|
||||
private inline fun <T> step(step: InstallStep, block: InstallStepData.() -> T): T {
|
||||
steps[step] = steps[step]!!.copy(status = InstallStatus.ONGOING)
|
||||
|
||||
steps[step]!!.status = InstallStatus.ONGOING
|
||||
currentStep = step
|
||||
|
||||
try {
|
||||
|
|
@ -596,15 +595,15 @@ class InstallViewModel(
|
|||
Thread.sleep(1000 - millis)
|
||||
}
|
||||
|
||||
steps[step] = steps[step]!!.copy(
|
||||
duration = millis.div(1000f),
|
||||
steps[step]!!.apply {
|
||||
duration = millis.div(1000f)
|
||||
status = InstallStatus.SUCCESSFUL
|
||||
)
|
||||
}
|
||||
|
||||
currentStep = step
|
||||
return value.value
|
||||
} catch (t: Throwable) {
|
||||
steps[step] = steps[step]!!.copy(status = InstallStatus.UNSUCCESSFUL)
|
||||
steps[step]!!.status = InstallStatus.UNSUCCESSFUL
|
||||
|
||||
currentStep = step
|
||||
throw t
|
||||
|
|
@ -656,6 +655,7 @@ class InstallViewModel(
|
|||
var currentStep: InstallStep? by mutableStateOf(null)
|
||||
val steps = mutableStateMapOf<InstallStep, InstallStepData>()
|
||||
|
||||
// TODO: cache this instead
|
||||
fun getSteps(group: InstallStepGroup): List<InstallStepData> {
|
||||
return steps
|
||||
.filterKeys { it.group == group }.entries
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue