diff --git a/app/build.gradle.kts b/app/build.gradle.kts index bfb4c3c..a6c4bfc 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,12 +1,13 @@ val pagingVersion = "3.1.0" val accompanistVersion = "0.23.0" -val composeVersion = "1.1.0" -val ktorVersion = "1.6.7" +val composeVersion = "1.1.1" +val ktorVersion = "2.0.0" plugins { id("com.android.application") id("kotlin-android") id("com.google.devtools.ksp") version "1.6.10-1.0.4" + kotlin("plugin.serialization") version "1.6.10" } android { @@ -63,13 +64,13 @@ dependencies { // core dependencies implementation("androidx.appcompat:appcompat:1.4.1") implementation("androidx.core:core-ktx:1.7.0") - implementation("androidx.core:core-splashscreen:1.0.0-beta01") + implementation("androidx.core:core-splashscreen:1.0.0-beta02") // compose dependencies implementation("androidx.compose.ui:ui:${composeVersion}") implementation("androidx.compose.ui:ui-tooling:${composeVersion}") implementation("androidx.compose.material:material:${composeVersion}") - implementation("androidx.compose.material3:material3:1.0.0-alpha08") + implementation("androidx.compose.material3:material3:1.0.0-alpha09") implementation("androidx.paging:paging-compose:1.0.0-alpha14") // accompanist dependencies @@ -77,18 +78,18 @@ dependencies { implementation("com.google.accompanist:accompanist-permissions:${accompanistVersion}") // compose destinations - implementation("io.github.raamcosta.compose-destinations:core:1.3.5-beta") - ksp("io.github.raamcosta.compose-destinations:ksp:1.3.5-beta") + implementation("io.github.raamcosta.compose-destinations:core:1.4.2-beta") + ksp("io.github.raamcosta.compose-destinations:ksp:1.4.2-beta") // other dependencies - implementation("com.google.code.gson:gson:2.9.0") implementation("io.coil-kt:coil-compose:1.4.0") - implementation("org.bouncycastle:bcpkix-jdk15on:1.65") + implementation("org.bouncycastle:bcpkix-jdk15on:1.70") implementation("de.upb.cs.swt:axml:2.1.1") // 2.1.2 is broken btw - implementation("com.android.tools.build:apksig:7.1.2") + implementation("com.android.tools.build:apksig:7.1.3") // ktor implementation("io.ktor:ktor-client-core:$ktorVersion") implementation("io.ktor:ktor-client-android:$ktorVersion") - implementation("io.ktor:ktor-client-gson:$ktorVersion") + implementation("io.ktor:ktor-client-content-negotiation:$ktorVersion") + implementation("io.ktor:ktor-serialization-kotlinx-json:$ktorVersion") } diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 6992941..1ea4fee 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -1,21 +1,26 @@ -# Add project specific ProGuard rules here. -# You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html +# Keep `Companion` object fields of serializable classes. +# This avoids serializer lookup through `getDeclaredClasses` as done for named companion objects. +-if @kotlinx.serialization.Serializable class ** +-keepclassmembers class <1> { + static <1>$Companion Companion; +} -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} +# Keep `serializer()` on companion objects (both default and named) of serializable classes. +-if @kotlinx.serialization.Serializable class ** { + static **$* *; +} +-keepclassmembers class <2>$<3> { + kotlinx.serialization.KSerializer serializer(...); +} -# Uncomment this to preserve the line number information for -# debugging stack traces. --keepattributes SourceFile,LineNumberTable --renamesourcefileattribute SourceFile +# Keep `INSTANCE.serializer()` of serializable objects. +-if @kotlinx.serialization.Serializable class ** { + public static ** INSTANCE; +} +-keepclassmembers class <1> { + public static <1> INSTANCE; + kotlinx.serialization.KSerializer serializer(...); +} --keep class com.aliucord.manager.models.** { private final *; } --keep class com.aliucord.libzip.Zip { private final *; } \ No newline at end of file +# @Serializable and @Polymorphic are used at runtime for polymorphic serialization. +-keepattributes RuntimeVisibleAnnotations,AnnotationDefault diff --git a/app/src/main/kotlin/com/aliucord/manager/models/Manifest.kt b/app/src/main/kotlin/com/aliucord/manager/models/Manifest.kt index 62dd2a4..4f4f622 100644 --- a/app/src/main/kotlin/com/aliucord/manager/models/Manifest.kt +++ b/app/src/main/kotlin/com/aliucord/manager/models/Manifest.kt @@ -5,6 +5,9 @@ package com.aliucord.manager.models +import kotlinx.serialization.Serializable + +@Serializable data class Manifest( val name: String, val authors: ArrayList, @@ -14,5 +17,6 @@ data class Manifest( val changelog: String?, val changelogMedia: String? ) { + @Serializable data class Author(val name: String, val id: Long) } diff --git a/app/src/main/kotlin/com/aliucord/manager/models/Plugin.kt b/app/src/main/kotlin/com/aliucord/manager/models/Plugin.kt index 66ab63a..ad13d86 100644 --- a/app/src/main/kotlin/com/aliucord/manager/models/Plugin.kt +++ b/app/src/main/kotlin/com/aliucord/manager/models/Plugin.kt @@ -7,12 +7,15 @@ package com.aliucord.manager.models import android.util.Log import com.aliucord.manager.BuildConfig -import com.aliucord.manager.utils.gson +import com.aliucord.manager.utils.json import com.aliucord.manager.utils.pluginsDir +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.json.decodeFromStream import java.io.File import java.util.zip.ZipException import java.util.zip.ZipFile +@OptIn(ExperimentalSerializationApi::class) data class Plugin(val file: File) { val manifest: Manifest @@ -21,9 +24,7 @@ data class Plugin(val file: File) { val entry = zipFile.getEntry("manifest.json") ?: throw ZipException("Plugin ${file.nameWithoutExtension} has no manifest.") - manifest = zipFile.getInputStream(entry).use { zis -> - gson.fromJson(zis.reader(), Manifest::class.java) - } + manifest = zipFile.getInputStream(entry).use { zis -> json.decodeFromStream(zis) } } } diff --git a/app/src/main/kotlin/com/aliucord/manager/models/github/Commit.kt b/app/src/main/kotlin/com/aliucord/manager/models/github/Commit.kt index 17d824f..d70aa23 100644 --- a/app/src/main/kotlin/com/aliucord/manager/models/github/Commit.kt +++ b/app/src/main/kotlin/com/aliucord/manager/models/github/Commit.kt @@ -5,14 +5,16 @@ package com.aliucord.manager.models.github -import com.google.gson.annotations.SerializedName +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +@Serializable data class Commit( - @SerializedName("html_url") val htmlUrl: String, + @SerialName("html_url") val htmlUrl: String, val sha: String, val commit: Commit, val author: Author ) { - data class Author(@SerializedName("login") val name: String) - data class Commit(val message: String) + @Serializable data class Author(@SerialName("login") val name: String) + @Serializable data class Commit(val message: String) } diff --git a/app/src/main/kotlin/com/aliucord/manager/models/github/GithubUser.kt b/app/src/main/kotlin/com/aliucord/manager/models/github/GithubUser.kt index 63c969e..ee6f2be 100644 --- a/app/src/main/kotlin/com/aliucord/manager/models/github/GithubUser.kt +++ b/app/src/main/kotlin/com/aliucord/manager/models/github/GithubUser.kt @@ -5,9 +5,11 @@ package com.aliucord.manager.models.github -import com.google.gson.annotations.SerializedName +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +@Serializable data class GithubUser( - @SerializedName("login") val name: String, + @SerialName("login") val name: String, val contributions: Int ) diff --git a/app/src/main/kotlin/com/aliucord/manager/models/github/Version.kt b/app/src/main/kotlin/com/aliucord/manager/models/github/Version.kt index 779ee7f..5992589 100644 --- a/app/src/main/kotlin/com/aliucord/manager/models/github/Version.kt +++ b/app/src/main/kotlin/com/aliucord/manager/models/github/Version.kt @@ -5,6 +5,9 @@ package com.aliucord.manager.models.github +import kotlinx.serialization.Serializable + +@Serializable data class Version( val versionCode: String, val versionName: String, diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/components/Switch.kt b/app/src/main/kotlin/com/aliucord/manager/ui/components/Switch.kt deleted file mode 100644 index 4e6497f..0000000 --- a/app/src/main/kotlin/com/aliucord/manager/ui/components/Switch.kt +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2022 Juby210 & zt - * Licensed under the Open Software License version 3.0 - */ - -package com.aliucord.manager.ui.components - -import androidx.compose.foundation.interaction.MutableInteractionSource -import androidx.compose.material.SwitchDefaults -import androidx.compose.material3.MaterialTheme -import androidx.compose.runtime.Composable -import androidx.compose.runtime.remember -import androidx.compose.ui.Modifier -import androidx.compose.material.Switch as M2Switch - -@Composable -fun Switch( - checked: Boolean, - onCheckedChange: ((Boolean) -> Unit)?, - modifier: Modifier = Modifier, - enabled: Boolean = true, - interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, -) { - val colors = MaterialTheme.colorScheme - - M2Switch( - checked = checked, - onCheckedChange = onCheckedChange, - modifier = modifier, - enabled = enabled, - interactionSource = interactionSource, - colors = SwitchDefaults.colors( - checkedTrackColor = colors.primary, - uncheckedTrackColor = colors.secondary, - checkedThumbColor = colors.primary, - uncheckedThumbColor = colors.secondary - ) - ) -} diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/components/about/ContributorsCard.kt b/app/src/main/kotlin/com/aliucord/manager/ui/components/about/ContributorsCard.kt index f1974ae..e4c1308 100644 --- a/app/src/main/kotlin/com/aliucord/manager/ui/components/about/ContributorsCard.kt +++ b/app/src/main/kotlin/com/aliucord/manager/ui/components/about/ContributorsCard.kt @@ -18,6 +18,7 @@ import com.aliucord.manager.R import com.aliucord.manager.models.github.GithubUser import com.aliucord.manager.utils.Github import com.aliucord.manager.utils.httpClient +import io.ktor.client.call.* import io.ktor.client.request.* import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -56,7 +57,7 @@ fun ContributorsCard() = ElevatedCard( LaunchedEffect(Unit) { launch(Dispatchers.IO) { - contributors.addAll(httpClient.get>(Github.contributorsUrl).sortedByDescending { it.contributions }) + contributors.addAll(httpClient.get(Github.contributorsUrl).body>().sortedByDescending { it.contributions }) } } } diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/components/plugins/PluginCard.kt b/app/src/main/kotlin/com/aliucord/manager/ui/components/plugins/PluginCard.kt index ef92a6b..a4cd9d7 100644 --- a/app/src/main/kotlin/com/aliucord/manager/ui/components/plugins/PluginCard.kt +++ b/app/src/main/kotlin/com/aliucord/manager/ui/components/plugins/PluginCard.kt @@ -20,7 +20,6 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import com.aliucord.manager.R import com.aliucord.manager.models.Plugin -import com.aliucord.manager.ui.components.Switch @OptIn(ExperimentalMaterial3Api::class) @Composable diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/components/settings/Setting.kt b/app/src/main/kotlin/com/aliucord/manager/ui/components/settings/Setting.kt index 92de257..5ef0df5 100644 --- a/app/src/main/kotlin/com/aliucord/manager/ui/components/settings/Setting.kt +++ b/app/src/main/kotlin/com/aliucord/manager/ui/components/settings/Setting.kt @@ -6,11 +6,11 @@ package com.aliucord.manager.ui.components.settings import androidx.compose.foundation.clickable +import androidx.compose.material3.Switch import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import com.aliucord.manager.preferences.Preference import com.aliucord.manager.ui.components.ListItem -import com.aliucord.manager.ui.components.Switch @Composable fun PreferenceItem( diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/HomeScreen.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screens/HomeScreen.kt index ecca905..7a7249d 100644 --- a/app/src/main/kotlin/com/aliucord/manager/ui/screens/HomeScreen.kt +++ b/app/src/main/kotlin/com/aliucord/manager/ui/screens/HomeScreen.kt @@ -37,8 +37,10 @@ import com.aliucord.manager.utils.* import com.ramcosta.composedestinations.annotation.Destination import com.ramcosta.composedestinations.navigation.DestinationsNavigator import io.ktor.client.request.* +import io.ktor.client.statement.* import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import kotlinx.serialization.decodeFromString @OptIn(ExperimentalMaterial3Api::class) @Destination(start = true) @@ -56,7 +58,7 @@ fun HomeScreen(navigator: DestinationsNavigator) { LaunchedEffect(Unit) { launch(Dispatchers.IO) { - val version = gson.fromJson(httpClient.get(Github.dataUrl), Version::class.java) + val version = json.decodeFromString(httpClient.get(Github.dataUrl).bodyAsText()) supportedVersion = "${version.versionName} - " + when (version.versionCode[3].toString()) { "0" -> "Stable" diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/StoreScreen.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screens/StoreScreen.kt index 9aaab14..916d5cf 100644 --- a/app/src/main/kotlin/com/aliucord/manager/ui/screens/StoreScreen.kt +++ b/app/src/main/kotlin/com/aliucord/manager/ui/screens/StoreScreen.kt @@ -16,6 +16,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import com.aliucord.manager.utils.httpClient import com.ramcosta.composedestinations.annotation.Destination +import io.ktor.client.call.* import io.ktor.client.request.* import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -47,10 +48,9 @@ fun StoreScreen() { LaunchedEffect(Unit) { launch(Dispatchers.IO) { - val content = - httpClient.get("https://api.github.com/repos/DiamondMiner88/AllACPlugins/git/trees/master") { - header("accept", "application/json") - } + val content = httpClient.get("https://api.github.com/repos/DiamondMiner88/AllACPlugins/git/trees/master") { + header("accept", "application/json") + }.body() plugins.addAll(content.tree.filter { it.mode == "160000" }) } diff --git a/app/src/main/kotlin/com/aliucord/manager/utils/Const.kt b/app/src/main/kotlin/com/aliucord/manager/utils/Const.kt index 8fd59ec..4e1f7cb 100644 --- a/app/src/main/kotlin/com/aliucord/manager/utils/Const.kt +++ b/app/src/main/kotlin/com/aliucord/manager/utils/Const.kt @@ -6,19 +6,25 @@ package com.aliucord.manager.utils import android.os.Environment -import com.google.gson.Gson import io.ktor.client.* -import io.ktor.client.engine.android.* -import io.ktor.client.features.json.* +import io.ktor.client.plugins.contentnegotiation.* +import io.ktor.serialization.kotlinx.json.* +import kotlinx.serialization.json.Json const val MANAGE_EXTERNAL_STORAGE = "android.permission.MANAGE_EXTERNAL_STORAGE" const val ANDROID_NAMESPACE = "http://schemas.android.com/apk/res/android" const val REQUEST_LEGACY_STORAGE = "requestLegacyExternalStorage" const val DEBUGGABLE = "debuggable" -val httpClient = HttpClient(Android) { - install(JsonFeature) +val json = Json { + prettyPrint = true + ignoreUnknownKeys = true +} + +val httpClient = HttpClient { + install(ContentNegotiation) { + json(json) + } } val aliucordDir = Environment.getExternalStorageDirectory().resolve("Aliucord") val pluginsDir = aliucordDir.resolve("plugins") -val gson = Gson() diff --git a/app/src/main/kotlin/com/aliucord/manager/utils/Github.kt b/app/src/main/kotlin/com/aliucord/manager/utils/Github.kt index 844a8f4..f5f1f21 100644 --- a/app/src/main/kotlin/com/aliucord/manager/utils/Github.kt +++ b/app/src/main/kotlin/com/aliucord/manager/utils/Github.kt @@ -7,8 +7,10 @@ package com.aliucord.manager.utils import com.aliucord.manager.models.github.Commit import com.aliucord.manager.models.github.Version +import io.ktor.client.call.* import io.ktor.client.request.* -import java.io.InputStreamReader +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.json.decodeFromStream import java.net.URL import kotlin.collections.set @@ -24,8 +26,9 @@ object Github { // TODO } + @OptIn(ExperimentalSerializationApi::class) val version: Version by lazy { - gson.fromJson(InputStreamReader(URL(dataUrl).openStream()), Version::class.java) + json.decodeFromStream(URL(dataUrl).openStream()) } private val commitsCache = HashMap>() @@ -35,9 +38,9 @@ object Github { if (commitsCache.containsKey(query)) return commitsCache[query] ?: emptyList() - val res = httpClient.get>(commitsUrl) { + val res = httpClient.get(commitsUrl) { params.forEach { (key, value) -> parameter(key, value) } - } + }.body>() commitsCache[query] = res diff --git a/build.gradle.kts b/build.gradle.kts index 87b65ba..c08ff27 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -6,8 +6,7 @@ buildscript { } dependencies { - // please do not update to 7.1+, it breaks compatibility with arctic fox android studio - classpath("com.android.tools.build:gradle:7.0.4") + classpath("com.android.tools.build:gradle:7.1.3") classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.10") // NOTE: Do not place your application dependencies here; they belong diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 1c566d4..829155b 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Sat Mar 12 19:39:38 CET 2022 +#Sat Apr 09 23:53:16 EDT 2022 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip distributionPath=wrapper/dists zipStorePath=wrapper/dists zipStoreBase=GRADLE_USER_HOME