feat: better composable stability

This commit is contained in:
Diamond 2022-12-14 19:21:40 -08:00
parent a85f9adeb1
commit b60d4bcbca
No known key found for this signature in database
GPG key ID: DCBE5952BB3B6420
11 changed files with 61 additions and 31 deletions

View file

@ -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? =

View file

@ -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) {

View file

@ -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")

View file

@ -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

View file

@ -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(

View file

@ -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 {

View file

@ -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)

View file

@ -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
) {

View file

@ -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(),
)
}

View file

@ -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 }

View file

@ -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