feat: improve home screen data fetching
This commit is contained in:
parent
46fed98175
commit
5edc39f289
15 changed files with 98 additions and 93 deletions
|
|
@ -5,6 +5,7 @@ import com.aliucord.manager.BuildConfig
|
|||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.call.HttpClientCall
|
||||
import io.ktor.client.engine.okhttp.OkHttp
|
||||
import io.ktor.client.plugins.HttpTimeout
|
||||
import io.ktor.client.plugins.cache.HttpCache
|
||||
import io.ktor.client.plugins.cache.storage.FileStorage
|
||||
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
|
||||
|
|
@ -62,6 +63,11 @@ fun Scope.provideHttpClient() = HttpClient(OkHttp) {
|
|||
json(json)
|
||||
}
|
||||
|
||||
install(HttpTimeout) {
|
||||
connectTimeoutMillis = 20000
|
||||
requestTimeoutMillis = 10000
|
||||
}
|
||||
|
||||
install(HttpCache) {
|
||||
val dir = application.cacheDir.resolve("ktor")
|
||||
publicStorage(FileStorage(dir))
|
||||
|
|
|
|||
|
|
@ -6,16 +6,22 @@
|
|||
package com.aliucord.manager.network.models
|
||||
|
||||
import com.aliucord.manager.network.utils.SemVer
|
||||
import com.aliucord.manager.util.serialization.IntAsStringSerializer
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class BuildInfo(
|
||||
@Serializable(with = IntAsStringSerializer::class)
|
||||
@SerialName("versionCode")
|
||||
val discordVersionCode: String,
|
||||
@SerialName("versionName")
|
||||
val discordVersionName: String,
|
||||
val discordVersionCode: Int,
|
||||
|
||||
// @SerialName("versionName")
|
||||
// val discordVersionName: Int,
|
||||
|
||||
@SerialName("injectorVersion")
|
||||
val injectorVersion: SemVer,
|
||||
|
||||
@SerialName("patchesVersion")
|
||||
val patchesVersion: SemVer,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package com.aliucord.manager.network.models
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.aliucord.manager.util.ImmutableListSerializer
|
||||
import com.aliucord.manager.util.serialization.ImmutableListSerializer
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
|
|
|
|||
|
|
@ -43,8 +43,7 @@ class DowngradeCheckStep(private val options: PatchOptions) : Step(), KoinCompon
|
|||
|
||||
val targetVersion = container
|
||||
.getStep<FetchInfoStep>()
|
||||
.data.discordVersionCode.toIntOrNull()
|
||||
?: throw IllegalArgumentException("Invalid remote target Discord version")
|
||||
.data.discordVersionCode
|
||||
|
||||
container.log("Target discord version: $targetVersion")
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import com.aliucord.manager.ui.components.ManagerTheme
|
|||
import com.aliucord.manager.ui.screens.about.AboutScreenContent
|
||||
import com.aliucord.manager.ui.screens.about.AboutScreenState
|
||||
import com.aliucord.manager.ui.util.emptyImmutableList
|
||||
import com.aliucord.manager.util.ImmutableListSerializer
|
||||
import com.aliucord.manager.util.serialization.ImmutableListSerializer
|
||||
import kotlinx.collections.immutable.*
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
|
|
|
|||
|
|
@ -21,15 +21,14 @@ import kotlinx.collections.immutable.persistentListOf
|
|||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO)
|
||||
private fun HomeScreenLoadedPreview(
|
||||
@PreviewParameter(HomeScreenParametersProvider::class)
|
||||
parameters: HomeScreenParameters,
|
||||
state: InstallsState.Fetched,
|
||||
) {
|
||||
ManagerTheme {
|
||||
Scaffold(
|
||||
topBar = { HomeAppBar() },
|
||||
) { padding ->
|
||||
HomeScreenLoadedContent(
|
||||
state = parameters.state,
|
||||
supportedVersion = parameters.supportedVersion,
|
||||
state = state,
|
||||
padding = padding,
|
||||
onClickInstall = {},
|
||||
onUpdate = {},
|
||||
|
|
@ -41,12 +40,7 @@ private fun HomeScreenLoadedPreview(
|
|||
}
|
||||
}
|
||||
|
||||
private data class HomeScreenParameters(
|
||||
val state: InstallsState.Fetched,
|
||||
val supportedVersion: DiscordVersion,
|
||||
)
|
||||
|
||||
private class HomeScreenParametersProvider : PreviewParameterProvider<HomeScreenParameters> {
|
||||
private class HomeScreenParametersProvider : PreviewParameterProvider<InstallsState.Fetched> {
|
||||
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=="
|
||||
|
|
@ -57,33 +51,27 @@ private class HomeScreenParametersProvider : PreviewParameterProvider<HomeScreen
|
|||
.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,
|
||||
)
|
||||
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,
|
||||
)
|
||||
InstallsState.Fetched(
|
||||
persistentListOf(
|
||||
InstallData(
|
||||
name = "Discord",
|
||||
packageName = "com.discord",
|
||||
version = stableVersion,
|
||||
icon = aliucordIcon,
|
||||
isUpToDate = false,
|
||||
)
|
||||
),
|
||||
)
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,9 +42,6 @@ class HomeModel(
|
|||
private val maven: AliucordMavenService,
|
||||
private val json: Json,
|
||||
) : ScreenModel {
|
||||
var supportedVersion by mutableStateOf<DiscordVersion>(DiscordVersion.None)
|
||||
private set
|
||||
|
||||
var installsState by mutableStateOf<InstallsState>(InstallsState.Fetching)
|
||||
private set
|
||||
|
||||
|
|
@ -176,37 +173,25 @@ class HomeModel(
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME: Properly show state when one of these fetches fail,
|
||||
// to ensure the people know that the up-to-date check does not work
|
||||
private suspend fun fetchRemoteData() {
|
||||
github.getBuildData().fold(
|
||||
success = {
|
||||
val versionCode = it.discordVersionCode.toIntOrNull()
|
||||
if (versionCode == null) {
|
||||
supportedVersion = DiscordVersion.Error
|
||||
return
|
||||
}
|
||||
|
||||
remoteDataJson = it
|
||||
supportedVersion = DiscordVersion.Existing(
|
||||
type = DiscordVersion.parseVersionType(versionCode),
|
||||
name = it.discordVersionName.split("-")[0].trim(),
|
||||
code = versionCode,
|
||||
listOf(
|
||||
screenModelScope.launch {
|
||||
github.getBuildData().fold(
|
||||
success = { remoteDataJson = it },
|
||||
fail = { Log.w(BuildConfig.TAG, "Failed to fetch remote build data", it) },
|
||||
)
|
||||
},
|
||||
fail = {
|
||||
Log.w(BuildConfig.TAG, "Failed to fetch remote build data", it)
|
||||
supportedVersion = DiscordVersion.Error
|
||||
screenModelScope.launch {
|
||||
maven.getAliuhookVersion().fold(
|
||||
success = { latestAliuhookVersion = it },
|
||||
fail = { Log.w(BuildConfig.TAG, "Failed to fetch latest Aliuhook version", it) },
|
||||
)
|
||||
},
|
||||
)
|
||||
).joinAll()
|
||||
|
||||
maven.getAliuhookVersion().fold(
|
||||
success = { latestAliuhookVersion = it },
|
||||
fail = {
|
||||
Log.w(BuildConfig.TAG, "Failed to fetch latest Aliuhook version", it)
|
||||
supportedVersion = DiscordVersion.Error
|
||||
},
|
||||
)
|
||||
if (remoteDataJson == null || latestAliuhookVersion == null) {
|
||||
application.showToast(R.string.home_network_fail)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -238,7 +223,7 @@ class HomeModel(
|
|||
val versionCode = pkg.versionCode
|
||||
|
||||
// Check if the base APK version is a mismatch
|
||||
if (remoteBuildData.discordVersionCode.toIntOrNull() != versionCode) return false
|
||||
if (remoteBuildData.discordVersionCode != versionCode) return false
|
||||
|
||||
// Try to parse install metadata. If none present, install was made via legacy installer.
|
||||
val apkPath = pkg.applicationInfo?.publicSourceDir ?: return false
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@ import com.aliucord.manager.ui.components.ProjectHeader
|
|||
import com.aliucord.manager.ui.screens.home.components.*
|
||||
import com.aliucord.manager.ui.screens.patchopts.PatchOptionsScreen
|
||||
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 com.aliucord.manager.util.pushOnce
|
||||
|
|
@ -64,7 +63,6 @@ class HomeScreen : Screen, Parcelable {
|
|||
when (val state = model.installsState) {
|
||||
is InstallsState.Fetched -> HomeScreenLoadedContent(
|
||||
state = state,
|
||||
supportedVersion = model.supportedVersion,
|
||||
padding = padding,
|
||||
onClickInstall = { navigator.pushOnce(PatchOptionsScreen()) },
|
||||
onUpdate = {
|
||||
|
|
@ -119,7 +117,6 @@ fun HomeScreenLoadingContent(padding: PaddingValues) {
|
|||
@Composable
|
||||
fun HomeScreenLoadedContent(
|
||||
state: InstallsState.Fetched,
|
||||
supportedVersion: DiscordVersion,
|
||||
padding: PaddingValues,
|
||||
onClickInstall: () -> Unit,
|
||||
onUpdate: (packageName: String) -> Unit,
|
||||
|
|
@ -153,20 +150,14 @@ fun HomeScreenLoadedContent(
|
|||
}
|
||||
|
||||
items(state.data, key = { it.packageName }) { item ->
|
||||
AnimatedVisibility(
|
||||
enter = fadeIn() + slideInHorizontally { it * -2 },
|
||||
exit = fadeOut() + slideOutHorizontally { it * 2 },
|
||||
visible = supportedVersion !is DiscordVersion.None,
|
||||
) {
|
||||
InstalledItemCard(
|
||||
data = item,
|
||||
onUpdate = { onUpdate(item.packageName) },
|
||||
onOpenApp = { onOpenApp(item.packageName) },
|
||||
onOpenInfo = { onOpenAppInfo(item.packageName) },
|
||||
onOpenPlugins = { onOpenPlugins(item.packageName) },
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
}
|
||||
InstalledItemCard(
|
||||
data = item,
|
||||
onUpdate = { onUpdate(item.packageName) },
|
||||
onOpenApp = { onOpenApp(item.packageName) },
|
||||
onOpenInfo = { onOpenAppInfo(item.packageName) },
|
||||
onOpenPlugins = { onOpenPlugins(item.packageName) },
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ package com.aliucord.manager.ui.screens.patchopts
|
|||
import android.os.Parcelable
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import com.aliucord.manager.util.ColorParceler
|
||||
import com.aliucord.manager.util.ColorSerializer
|
||||
import com.aliucord.manager.util.serialization.ColorParceler
|
||||
import com.aliucord.manager.util.serialization.ColorSerializer
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import kotlinx.parcelize.TypeParceler
|
||||
import kotlinx.serialization.SerialName
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package com.aliucord.manager.ui.screens.plugins.model
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.aliucord.manager.util.ImmutableListSerializer
|
||||
import com.aliucord.manager.util.serialization.ImmutableListSerializer
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package com.aliucord.manager.util
|
||||
package com.aliucord.manager.util.serialization
|
||||
|
||||
import android.os.Parcel
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.aliucord.manager.util
|
||||
package com.aliucord.manager.util.serialization
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.aliucord.manager.util
|
||||
package com.aliucord.manager.util.serialization
|
||||
|
||||
import com.aliucord.manager.ui.util.toUnsafeImmutable
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package com.aliucord.manager.util.serialization
|
||||
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.SerializationException
|
||||
import kotlinx.serialization.descriptors.*
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
|
||||
/**
|
||||
* (De)serializes an integer as a string.
|
||||
*/
|
||||
object IntAsStringSerializer : KSerializer<Int> {
|
||||
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("Int", PrimitiveKind.STRING)
|
||||
|
||||
override fun serialize(encoder: Encoder, value: Int) {
|
||||
encoder.encodeString(value.toString())
|
||||
}
|
||||
|
||||
override fun deserialize(decoder: Decoder): Int {
|
||||
val stringValue = decoder.decodeString()
|
||||
|
||||
return try {
|
||||
stringValue.toInt()
|
||||
} catch (e: NumberFormatException) {
|
||||
throw SerializationException(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -151,6 +151,8 @@
|
|||
<string name="downloader_err_file_exists">Download failed (File exists)</string>
|
||||
<string name="downloader_err_storage_space">Download failed (Insufficient space)</string>
|
||||
|
||||
<string name="home_network_fail">Failed to fetch data!</string>
|
||||
|
||||
<string name="patchopts_title">Aliucord provides several customizations at installation time that are not able to be changed once installed.</string>
|
||||
<string name="patchopts_pkgname_title">Package Name</string>
|
||||
<string name="patchopts_pkgname_desc">The package name is a unique identifier for all apps. Using different ones can allow for multiple installations of Aliucord.</string>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue