diff --git a/app/src/main/kotlin/com/aliucord/manager/di/Http.kt b/app/src/main/kotlin/com/aliucord/manager/di/Http.kt index 44ec4fe..023045d 100644 --- a/app/src/main/kotlin/com/aliucord/manager/di/Http.kt +++ b/app/src/main/kotlin/com/aliucord/manager/di/Http.kt @@ -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)) diff --git a/app/src/main/kotlin/com/aliucord/manager/network/models/BuildInfo.kt b/app/src/main/kotlin/com/aliucord/manager/network/models/BuildInfo.kt index 7ed9a92..69234e5 100644 --- a/app/src/main/kotlin/com/aliucord/manager/network/models/BuildInfo.kt +++ b/app/src/main/kotlin/com/aliucord/manager/network/models/BuildInfo.kt @@ -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, ) diff --git a/app/src/main/kotlin/com/aliucord/manager/network/models/Contributor.kt b/app/src/main/kotlin/com/aliucord/manager/network/models/Contributor.kt index 86d3391..46c761f 100644 --- a/app/src/main/kotlin/com/aliucord/manager/network/models/Contributor.kt +++ b/app/src/main/kotlin/com/aliucord/manager/network/models/Contributor.kt @@ -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 diff --git a/app/src/main/kotlin/com/aliucord/manager/patcher/steps/prepare/DowngradeCheckStep.kt b/app/src/main/kotlin/com/aliucord/manager/patcher/steps/prepare/DowngradeCheckStep.kt index b988935..49af6cd 100644 --- a/app/src/main/kotlin/com/aliucord/manager/patcher/steps/prepare/DowngradeCheckStep.kt +++ b/app/src/main/kotlin/com/aliucord/manager/patcher/steps/prepare/DowngradeCheckStep.kt @@ -43,8 +43,7 @@ class DowngradeCheckStep(private val options: PatchOptions) : Step(), KoinCompon val targetVersion = container .getStep() - .data.discordVersionCode.toIntOrNull() - ?: throw IllegalArgumentException("Invalid remote target Discord version") + .data.discordVersionCode container.log("Target discord version: $targetVersion") diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/previews/screens/about/AboutScreenLoadedPreview.kt b/app/src/main/kotlin/com/aliucord/manager/ui/previews/screens/about/AboutScreenLoadedPreview.kt index 657b356..7b0df16 100644 --- a/app/src/main/kotlin/com/aliucord/manager/ui/previews/screens/about/AboutScreenLoadedPreview.kt +++ b/app/src/main/kotlin/com/aliucord/manager/ui/previews/screens/about/AboutScreenLoadedPreview.kt @@ -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 diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/previews/screens/home/HomeScreenLoadedPreview.kt b/app/src/main/kotlin/com/aliucord/manager/ui/previews/screens/home/HomeScreenLoadedPreview.kt index cb8cd89..d1f3ee5 100644 --- a/app/src/main/kotlin/com/aliucord/manager/ui/previews/screens/home/HomeScreenLoadedPreview.kt +++ b/app/src/main/kotlin/com/aliucord/manager/ui/previews/screens/home/HomeScreenLoadedPreview.kt @@ -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 { +private class HomeScreenParametersProvider : PreviewParameterProvider { 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(DiscordVersion.None) - private set - var installsState by mutableStateOf(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 diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/home/HomeScreen.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screens/home/HomeScreen.kt index 41c19cb..f08cf61 100644 --- a/app/src/main/kotlin/com/aliucord/manager/ui/screens/home/HomeScreen.kt +++ b/app/src/main/kotlin/com/aliucord/manager/ui/screens/home/HomeScreen.kt @@ -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() + ) } } } diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/patchopts/PatchOptions.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screens/patchopts/PatchOptions.kt index 46f7ffd..f5a7b54 100644 --- a/app/src/main/kotlin/com/aliucord/manager/ui/screens/patchopts/PatchOptions.kt +++ b/app/src/main/kotlin/com/aliucord/manager/ui/screens/patchopts/PatchOptions.kt @@ -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 diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/plugins/model/PluginManifest.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screens/plugins/model/PluginManifest.kt index 9b36c57..9687bdf 100644 --- a/app/src/main/kotlin/com/aliucord/manager/ui/screens/plugins/model/PluginManifest.kt +++ b/app/src/main/kotlin/com/aliucord/manager/ui/screens/plugins/model/PluginManifest.kt @@ -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 diff --git a/app/src/main/kotlin/com/aliucord/manager/util/ColorParceler.kt b/app/src/main/kotlin/com/aliucord/manager/util/serialization/ColorParceler.kt similarity index 90% rename from app/src/main/kotlin/com/aliucord/manager/util/ColorParceler.kt rename to app/src/main/kotlin/com/aliucord/manager/util/serialization/ColorParceler.kt index ce540d9..e9fe9ec 100644 --- a/app/src/main/kotlin/com/aliucord/manager/util/ColorParceler.kt +++ b/app/src/main/kotlin/com/aliucord/manager/util/serialization/ColorParceler.kt @@ -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 diff --git a/app/src/main/kotlin/com/aliucord/manager/util/ColorSerializer.kt b/app/src/main/kotlin/com/aliucord/manager/util/serialization/ColorSerializer.kt similarity index 94% rename from app/src/main/kotlin/com/aliucord/manager/util/ColorSerializer.kt rename to app/src/main/kotlin/com/aliucord/manager/util/serialization/ColorSerializer.kt index 71699ec..294c490 100644 --- a/app/src/main/kotlin/com/aliucord/manager/util/ColorSerializer.kt +++ b/app/src/main/kotlin/com/aliucord/manager/util/serialization/ColorSerializer.kt @@ -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 diff --git a/app/src/main/kotlin/com/aliucord/manager/util/ImmutableListSerializer.kt b/app/src/main/kotlin/com/aliucord/manager/util/serialization/ImmutableListSerializer.kt similarity index 96% rename from app/src/main/kotlin/com/aliucord/manager/util/ImmutableListSerializer.kt rename to app/src/main/kotlin/com/aliucord/manager/util/serialization/ImmutableListSerializer.kt index 93e9adc..58418c9 100644 --- a/app/src/main/kotlin/com/aliucord/manager/util/ImmutableListSerializer.kt +++ b/app/src/main/kotlin/com/aliucord/manager/util/serialization/ImmutableListSerializer.kt @@ -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 diff --git a/app/src/main/kotlin/com/aliucord/manager/util/serialization/IntAsStringSerializer.kt b/app/src/main/kotlin/com/aliucord/manager/util/serialization/IntAsStringSerializer.kt new file mode 100644 index 0000000..bf7fd1b --- /dev/null +++ b/app/src/main/kotlin/com/aliucord/manager/util/serialization/IntAsStringSerializer.kt @@ -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 { + 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) + } + } +} diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3ce951f..0e2aa2e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -151,6 +151,8 @@ Download failed (File exists) Download failed (Insufficient space) + Failed to fetch data! + Aliucord provides several customizations at installation time that are not able to be changed once installed. Package Name The package name is a unique identifier for all apps. Using different ones can allow for multiple installations of Aliucord.