diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index a6c4bfc..6412ebf 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -1,13 +1,12 @@
-val pagingVersion = "3.1.0"
-val accompanistVersion = "0.23.0"
-val composeVersion = "1.1.1"
+val accompanistVersion = "0.24.7-alpha"
+val composeVersion = "1.2.0-alpha08"
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"
+ id("com.google.devtools.ksp") version "1.6.20-1.0.4"
+ kotlin("plugin.serialization") version "1.6.20"
}
android {
@@ -40,24 +39,21 @@ android {
kotlinOptions {
jvmTarget = "11"
- freeCompilerArgs = freeCompilerArgs + "-Xopt-in=kotlin.RequiresOptIn"
+ freeCompilerArgs = freeCompilerArgs + "-opt-in=kotlin.RequiresOptIn"
+ }
+
+ applicationVariants.all {
+ kotlin.sourceSets {
+ getByName(name) {
+ kotlin.srcDir("build/generated/ksp/$name/kotlin")
+ }
+ }
}
buildFeatures.compose = true
composeOptions.kotlinCompilerExtensionVersion = composeVersion
}
-kotlin {
- sourceSets {
- debug {
- kotlin.srcDir("build/generated/ksp/debug/kotlin")
- }
- release {
- kotlin.srcDir("build/generated/ksp/release/kotlin")
- }
- }
-}
-
dependencies {
implementation(fileTree("./libs"))
@@ -65,12 +61,15 @@ dependencies {
implementation("androidx.appcompat:appcompat:1.4.1")
implementation("androidx.core:core-ktx:1.7.0")
implementation("androidx.core:core-splashscreen:1.0.0-beta02")
+ implementation("com.android:zipflinger:7.3.0-alpha09")
+// implementation("com.github.Aliucord:libzip:1.0.0")
// 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-alpha09")
+ implementation("androidx.compose.material:material-icons-extended:${composeVersion}")
+ implementation("androidx.compose.material3:material3:1.0.0-alpha10")
implementation("androidx.paging:paging-compose:1.0.0-alpha14")
// accompanist dependencies
@@ -78,11 +77,11 @@ dependencies {
implementation("com.google.accompanist:accompanist-permissions:${accompanistVersion}")
// compose destinations
- implementation("io.github.raamcosta.compose-destinations:core:1.4.2-beta")
- ksp("io.github.raamcosta.compose-destinations:ksp:1.4.2-beta")
+ implementation("io.github.raamcosta.compose-destinations:core:1.5.2-beta")
+ ksp("io.github.raamcosta.compose-destinations:ksp:1.5.2-beta")
// other dependencies
- implementation("io.coil-kt:coil-compose:1.4.0")
+ implementation("io.coil-kt:coil-compose:2.0.0-rc03")
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.3")
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index eedcb50..6544d1a 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -7,6 +7,7 @@
+
+
, LGPL3.0, see https://www.gnu.org/licenses/lgpl-3.0.en.html
-
-See https://github.com/Aliucord/hook
diff --git a/app/src/main/assets/aliuhook/arm64-v8a/libaliuhook.so b/app/src/main/assets/aliuhook/arm64-v8a/libaliuhook.so
deleted file mode 100644
index 34ec1a4..0000000
Binary files a/app/src/main/assets/aliuhook/arm64-v8a/libaliuhook.so and /dev/null differ
diff --git a/app/src/main/assets/aliuhook/arm64-v8a/libc++_shared.so b/app/src/main/assets/aliuhook/arm64-v8a/libc++_shared.so
deleted file mode 100644
index 6bdccac..0000000
Binary files a/app/src/main/assets/aliuhook/arm64-v8a/libc++_shared.so and /dev/null differ
diff --git a/app/src/main/assets/aliuhook/arm64-v8a/liblsplant.so b/app/src/main/assets/aliuhook/arm64-v8a/liblsplant.so
deleted file mode 100644
index d53ba87..0000000
Binary files a/app/src/main/assets/aliuhook/arm64-v8a/liblsplant.so and /dev/null differ
diff --git a/app/src/main/assets/aliuhook/armeabi-v7a/libaliuhook.so b/app/src/main/assets/aliuhook/armeabi-v7a/libaliuhook.so
deleted file mode 100644
index ad4d85b..0000000
Binary files a/app/src/main/assets/aliuhook/armeabi-v7a/libaliuhook.so and /dev/null differ
diff --git a/app/src/main/assets/aliuhook/armeabi-v7a/libc++_shared.so b/app/src/main/assets/aliuhook/armeabi-v7a/libc++_shared.so
deleted file mode 100644
index f633c88..0000000
Binary files a/app/src/main/assets/aliuhook/armeabi-v7a/libc++_shared.so and /dev/null differ
diff --git a/app/src/main/assets/aliuhook/armeabi-v7a/liblsplant.so b/app/src/main/assets/aliuhook/armeabi-v7a/liblsplant.so
deleted file mode 100644
index 1557380..0000000
Binary files a/app/src/main/assets/aliuhook/armeabi-v7a/liblsplant.so and /dev/null differ
diff --git a/app/src/main/assets/aliuhook/classes.dex b/app/src/main/assets/aliuhook/classes.dex
deleted file mode 100644
index 105afcf..0000000
Binary files a/app/src/main/assets/aliuhook/classes.dex and /dev/null differ
diff --git a/app/src/main/assets/aliuhook/x86/libaliuhook.so b/app/src/main/assets/aliuhook/x86/libaliuhook.so
deleted file mode 100644
index b91f567..0000000
Binary files a/app/src/main/assets/aliuhook/x86/libaliuhook.so and /dev/null differ
diff --git a/app/src/main/assets/aliuhook/x86/libc++_shared.so b/app/src/main/assets/aliuhook/x86/libc++_shared.so
deleted file mode 100644
index 99d0522..0000000
Binary files a/app/src/main/assets/aliuhook/x86/libc++_shared.so and /dev/null differ
diff --git a/app/src/main/assets/aliuhook/x86/liblsplant.so b/app/src/main/assets/aliuhook/x86/liblsplant.so
deleted file mode 100644
index 075dfae..0000000
Binary files a/app/src/main/assets/aliuhook/x86/liblsplant.so and /dev/null differ
diff --git a/app/src/main/assets/aliuhook/x86_64/libaliuhook.so b/app/src/main/assets/aliuhook/x86_64/libaliuhook.so
deleted file mode 100644
index c1fa2d5..0000000
Binary files a/app/src/main/assets/aliuhook/x86_64/libaliuhook.so and /dev/null differ
diff --git a/app/src/main/assets/aliuhook/x86_64/libc++_shared.so b/app/src/main/assets/aliuhook/x86_64/libc++_shared.so
deleted file mode 100644
index 0ca6a48..0000000
Binary files a/app/src/main/assets/aliuhook/x86_64/libc++_shared.so and /dev/null differ
diff --git a/app/src/main/assets/aliuhook/x86_64/liblsplant.so b/app/src/main/assets/aliuhook/x86_64/liblsplant.so
deleted file mode 100644
index 43fe031..0000000
Binary files a/app/src/main/assets/aliuhook/x86_64/liblsplant.so and /dev/null differ
diff --git a/app/src/main/assets/kotlin/LICENSE.txt b/app/src/main/assets/kotlin/LICENSE.txt
deleted file mode 100644
index 9c308d9..0000000
--- a/app/src/main/assets/kotlin/LICENSE.txt
+++ /dev/null
@@ -1,202 +0,0 @@
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright 2000-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/app/src/main/assets/kotlin/classes.dex b/app/src/main/assets/kotlin/classes.dex
deleted file mode 100644
index add9e1b..0000000
Binary files a/app/src/main/assets/kotlin/classes.dex and /dev/null differ
diff --git a/app/src/main/assets/lib/arm64-v8a/libc++_shared.so b/app/src/main/assets/lib/arm64-v8a/libc++_shared.so
new file mode 100644
index 0000000..42b418c
Binary files /dev/null and b/app/src/main/assets/lib/arm64-v8a/libc++_shared.so differ
diff --git a/app/src/main/assets/lib/arm64-v8a/libhermes.so b/app/src/main/assets/lib/arm64-v8a/libhermes.so
new file mode 100644
index 0000000..3ca47a9
Binary files /dev/null and b/app/src/main/assets/lib/arm64-v8a/libhermes.so differ
diff --git a/app/src/main/assets/lib/armeabi-v7a/libc++_shared.so b/app/src/main/assets/lib/armeabi-v7a/libc++_shared.so
new file mode 100644
index 0000000..906f251
Binary files /dev/null and b/app/src/main/assets/lib/armeabi-v7a/libc++_shared.so differ
diff --git a/app/src/main/assets/lib/armeabi-v7a/libhermes.so b/app/src/main/assets/lib/armeabi-v7a/libhermes.so
new file mode 100644
index 0000000..72a0e8f
Binary files /dev/null and b/app/src/main/assets/lib/armeabi-v7a/libhermes.so differ
diff --git a/app/src/main/assets/lib/x86/libc++_shared.so b/app/src/main/assets/lib/x86/libc++_shared.so
new file mode 100644
index 0000000..379ead8
Binary files /dev/null and b/app/src/main/assets/lib/x86/libc++_shared.so differ
diff --git a/app/src/main/assets/lib/x86/libhermes.so b/app/src/main/assets/lib/x86/libhermes.so
new file mode 100644
index 0000000..ac63754
Binary files /dev/null and b/app/src/main/assets/lib/x86/libhermes.so differ
diff --git a/app/src/main/assets/lib/x86_64/libc++_shared.so b/app/src/main/assets/lib/x86_64/libc++_shared.so
new file mode 100644
index 0000000..e37b298
Binary files /dev/null and b/app/src/main/assets/lib/x86_64/libc++_shared.so differ
diff --git a/app/src/main/assets/lib/x86_64/libhermes.so b/app/src/main/assets/lib/x86_64/libhermes.so
new file mode 100644
index 0000000..f6b0320
Binary files /dev/null and b/app/src/main/assets/lib/x86_64/libhermes.so differ
diff --git a/app/src/main/kotlin/com/aliucord/manager/installer/service/InstallService.kt b/app/src/main/kotlin/com/aliucord/manager/installer/service/InstallService.kt
new file mode 100644
index 0000000..e232f02
--- /dev/null
+++ b/app/src/main/kotlin/com/aliucord/manager/installer/service/InstallService.kt
@@ -0,0 +1,41 @@
+package com.aliucord.manager.installer.service
+
+import android.app.Service
+import android.content.Intent
+import android.content.pm.PackageInstaller
+import android.os.IBinder
+import android.util.Log
+import android.widget.Toast
+
+class InstallService : Service() {
+ override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
+ when (val statusCode = intent.getIntExtra(PackageInstaller.EXTRA_STATUS, -999)) {
+ PackageInstaller.STATUS_PENDING_USER_ACTION -> {
+ val confirmationIntent = intent.getParcelableExtra(Intent.EXTRA_INTENT)
+ confirmationIntent!!.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+
+ startActivity(confirmationIntent)
+ }
+ PackageInstaller.STATUS_SUCCESS -> Toast.makeText(
+ this,
+ "Successfully installed Aliucord!",
+ Toast.LENGTH_LONG
+ ).show()
+ PackageInstaller.STATUS_FAILURE_ABORTED -> Toast.makeText(
+ this,
+ "Aborted installation",
+ Toast.LENGTH_LONG
+ ).show()
+ else -> {
+ Log.i("Installer", "Installation failed: error code $statusCode")
+ Toast.makeText(this, "Failed: Error $statusCode", Toast.LENGTH_LONG).show()
+ }
+ }
+
+ stopSelf()
+
+ return START_NOT_STICKY
+ }
+
+ override fun onBind(intent: Intent): IBinder? = null
+}
diff --git a/app/src/main/kotlin/com/aliucord/manager/utils/DownloadUtils.kt b/app/src/main/kotlin/com/aliucord/manager/installer/util/DownloadUtils.kt
similarity index 68%
rename from app/src/main/kotlin/com/aliucord/manager/utils/DownloadUtils.kt
rename to app/src/main/kotlin/com/aliucord/manager/installer/util/DownloadUtils.kt
index dbdd320..6855bd4 100644
--- a/app/src/main/kotlin/com/aliucord/manager/utils/DownloadUtils.kt
+++ b/app/src/main/kotlin/com/aliucord/manager/installer/util/DownloadUtils.kt
@@ -3,7 +3,7 @@
* Licensed under the Open Software License version 3.0
*/
-package com.aliucord.manager.utils
+package com.aliucord.manager.installer.util
import android.app.DownloadManager
import android.content.*
@@ -13,24 +13,13 @@ import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
object DownloadUtils {
- private const val org = "Aliucord"
- private const val repo = "Aliucord"
-
private const val backendHost = "https://aliucord.com/"
- private const val contentUrl = "https://raw.githubusercontent.com/${org}/${repo}"
suspend fun downloadDiscordApk(ctx: Context, version: String) =
- download(ctx, "$backendHost/download/discord?v=$version", "discord-$version.apk")
+ download(ctx, "$backendHost/download/discord?v=$version", "base-$version.apk")
- suspend fun downloadManifest(ctx: Context, useDebuggableManifest: Boolean) {
- if (useDebuggableManifest)
- download(ctx, "$contentUrl/main/.assets/AndroidManifest-debuggable.xml", "AndroidManifest-debuggable.xml")
- else {
- download(ctx, "$contentUrl/main/.assets/AndroidManifest.xml", "AndroidManifest.xml")
- }
- }
-
- suspend fun downloadInjector(ctx: Context) = download(ctx, "$contentUrl/builds/Injector.dex", "Injector.dex")
+ suspend fun downloadSplit(ctx: Context, version: String, split: String) =
+ download(ctx, "$backendHost/download/discord?v=$version&split=$split", "$split-$version.apk")
private suspend fun download(ctx: Context, url: String, fileName: String): File {
val downloadManager = ctx.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
@@ -52,7 +41,7 @@ object DownloadUtils {
ctx.registerReceiver(receiver, IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE))
receiver.downloadId = DownloadManager.Request(url.toUri()).run {
- setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE)
+ setNotificationVisibility(DownloadManager.Request.VISIBILITY_HIDDEN)
setDestinationUri(ctx.externalCacheDir!!.resolve(fileName).toUri())
downloadManager.enqueue(this)
}
diff --git a/app/src/main/kotlin/com/aliucord/manager/installer/util/ManifestPatcher.kt b/app/src/main/kotlin/com/aliucord/manager/installer/util/ManifestPatcher.kt
new file mode 100644
index 0000000..518b11d
--- /dev/null
+++ b/app/src/main/kotlin/com/aliucord/manager/installer/util/ManifestPatcher.kt
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2022 Juby210 & zt
+ * Licensed under the Open Software License version 3.0
+ */
+
+package com.aliucord.manager.installer.util
+
+import com.aliucord.manager.preferences.Prefs
+import pxb.android.axml.*
+
+object ManifestPatcher {
+ private const val MANAGE_EXTERNAL_STORAGE = "android.permission.MANAGE_EXTERNAL_STORAGE"
+ private const val ANDROID_NAMESPACE = "http://schemas.android.com/apk/res/android"
+ private const val USES_CLEARTEXT_TRAFFIC = "usesCleartextTraffic"
+ private const val DEBUGGABLE = "debuggable"
+ private const val LABEL = "label"
+
+ fun patchManifest(manifestBytes: ByteArray): ByteArray {
+ val packageName = Prefs.packageName.get()
+ val reader = AxmlReader(manifestBytes)
+ val writer = AxmlWriter()
+
+ reader.accept(object : AxmlVisitor(writer) {
+ override fun child(ns: String?, name: String?) =
+ object : ReplaceAttrsVisitor(super.child(ns, name), mapOf("package" to packageName)) {
+ private var addManagePerm = true
+
+ override fun attr(ns: String?, name: String, resourceId: Int, type: Int, value: Any?) {
+ super.attr(ns, name, resourceId, type, value)
+
+ if (value == MANAGE_EXTERNAL_STORAGE) addManagePerm = false
+ }
+
+ override fun child(ns: String?, name: String): NodeVisitor {
+ val nv = super.child(ns, name)
+
+ return when (name) {
+ "application" -> object : ReplaceAttrsVisitor(
+ nv,
+ mapOf(
+ LABEL to Prefs.appName.get(),
+ DEBUGGABLE to Prefs.debuggable.get(),
+ USES_CLEARTEXT_TRAFFIC to true
+ )
+ ) {
+ private var addDebuggable = Prefs.debuggable.get()
+ private var addUseClearTextTraffic = true
+
+ override fun attr(ns: String?, name: String, resourceId: Int, type: Int, value: Any?) {
+ super.attr(ns, name, resourceId, type, value)
+ if (name == DEBUGGABLE) addDebuggable = false
+ if (name == USES_CLEARTEXT_TRAFFIC) addUseClearTextTraffic = false
+ }
+
+ override fun child(ns: String?, name: String): NodeVisitor {
+ val visitor = super.child(ns, name)
+
+ return when (name) {
+ "activity" -> ReplaceAttrsVisitor(visitor, mapOf("label" to Prefs.appName.get()))
+ "provider" -> object : NodeVisitor(visitor) {
+ override fun attr(ns: String?, name: String, resourceId: Int, type: Int, value: Any?) {
+ super.attr(
+ ns, name, resourceId, type,
+ if (name == "authorities") (value as String).replace("com.discord", packageName) else value
+ )
+ }
+ }
+ else -> visitor
+ }
+ }
+
+ override fun end() {
+ if (addDebuggable) super.attr(ANDROID_NAMESPACE, DEBUGGABLE, -1, TYPE_INT_BOOLEAN, 1)
+ if (addUseClearTextTraffic) super.attr(ANDROID_NAMESPACE, USES_CLEARTEXT_TRAFFIC, -1, TYPE_INT_BOOLEAN, 1)
+ super.end()
+ }
+ }
+ else -> nv
+ }
+ }
+
+ override fun end() {
+ if (addManagePerm) super.child(null, "uses-permission").attr(
+ ANDROID_NAMESPACE, "name", -1, TYPE_STRING, MANAGE_EXTERNAL_STORAGE
+ )
+ super.end()
+ }
+ }
+ })
+
+ return writer.toByteArray()
+ }
+
+ fun renamePackage(manifestBytes: ByteArray): ByteArray {
+ val packageName = Prefs.packageName.get()
+ val reader = AxmlReader(manifestBytes)
+ val writer = AxmlWriter()
+
+ reader.accept(object : AxmlVisitor(writer) {
+ override fun child(ns: String?, name: String?): ReplaceAttrsVisitor {
+ return ReplaceAttrsVisitor(super.child(ns, name), mapOf("package" to packageName))
+ }
+ })
+
+ return writer.toByteArray()
+ }
+
+ private open class ReplaceAttrsVisitor(
+ nv: NodeVisitor,
+ private val attrs: Map
+ ) : NodeVisitor(nv) {
+ override fun attr(ns: String?, name: String, resourceId: Int, type: Int, value: Any?) {
+ val replace = attrs.containsKey(name)
+ val newValue = attrs[name]
+
+ super.attr(ns, name, resourceId, if (newValue is String) TYPE_STRING else type, if (replace) newValue else value)
+ }
+ }
+}
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 ad13d86..9153204 100644
--- a/app/src/main/kotlin/com/aliucord/manager/models/Plugin.kt
+++ b/app/src/main/kotlin/com/aliucord/manager/models/Plugin.kt
@@ -7,8 +7,8 @@ package com.aliucord.manager.models
import android.util.Log
import com.aliucord.manager.BuildConfig
+import com.aliucord.manager.utils.aliucordDir
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
@@ -29,6 +29,8 @@ data class Plugin(val file: File) {
}
companion object {
+ private val pluginsDir = aliucordDir.resolve("plugins")
+
fun loadAll(): List {
if (!pluginsDir.exists() && !pluginsDir.mkdirs()) {
Log.e(BuildConfig.TAG, "Failed to create plugins dir. Missing Permissions?")
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 d70aa23..96ec796 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
@@ -10,7 +10,8 @@ import kotlinx.serialization.Serializable
@Serializable
data class Commit(
- @SerialName("html_url") val htmlUrl: String,
+ @SerialName("html_url")
+ val htmlUrl: String,
val sha: String,
val commit: Commit,
val author: Author
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 ee6f2be..a9701f3 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
@@ -10,6 +10,7 @@ import kotlinx.serialization.Serializable
@Serializable
data class GithubUser(
- @SerialName("login") val name: String,
+ @SerialName("login")
+ val name: String,
val contributions: Int
)
diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/components/ManagerScaffold.kt b/app/src/main/kotlin/com/aliucord/manager/ui/components/ManagerScaffold.kt
index 28bc7ea..81a6a22 100644
--- a/app/src/main/kotlin/com/aliucord/manager/ui/components/ManagerScaffold.kt
+++ b/app/src/main/kotlin/com/aliucord/manager/ui/components/ManagerScaffold.kt
@@ -30,22 +30,22 @@ fun ManagerScaffold() {
val storagePermissionState = rememberPermissionState(Manifest.permission.WRITE_EXTERNAL_STORAGE)
- Scaffold(
- topBar = { if (storagePermissionState.hasPermission) AppBar(navController) }
- ) { paddingValues ->
- PermissionRequired(
- permissionState = storagePermissionState,
- permissionNotAvailableContent = { GrantPermission(storagePermissionState) },
- permissionNotGrantedContent = { GrantPermission(storagePermissionState) }
- ) {
- DestinationsNavHost(
- modifier = Modifier
- .padding(paddingValues)
- .padding(horizontal = 12.dp, vertical = 14.dp),
- navGraph = NavGraphs.root,
- navController = navController,
- engine = rememberNavHostEngine()
- )
+ when (storagePermissionState.status) {
+ is PermissionStatus.Denied -> GrantPermission(storagePermissionState)
+ PermissionStatus.Granted -> {
+ Scaffold(
+ topBar = { AppBar(navController) }
+ ) { paddingValues ->
+ DestinationsNavHost(
+ modifier = Modifier
+ .padding(paddingValues)
+ .padding(horizontal = 12.dp, vertical = 14.dp),
+ navGraph = NavGraphs.root,
+ navController = navController,
+ engine = rememberNavHostEngine()
+ )
+ }
}
}
+
}
diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/components/PluginsList.kt b/app/src/main/kotlin/com/aliucord/manager/ui/components/PluginsList.kt
index ca86335..64bf98e 100644
--- a/app/src/main/kotlin/com/aliucord/manager/ui/components/PluginsList.kt
+++ b/app/src/main/kotlin/com/aliucord/manager/ui/components/PluginsList.kt
@@ -83,9 +83,7 @@ fun PluginsList() = Column(
},
dismissButton = {
Button(
- onClick = {
- showDeleteDialog = false
- },
+ onClick = { showDeleteDialog = false },
colors = ButtonDefaults.buttonColors(
containerColor = MaterialTheme.colorScheme.secondaryContainer,
contentColor = MaterialTheme.colorScheme.onSecondaryContainer
diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/components/about/ContributorEntry.kt b/app/src/main/kotlin/com/aliucord/manager/ui/components/about/ContributorEntry.kt
index 7af4779..a601a30 100644
--- a/app/src/main/kotlin/com/aliucord/manager/ui/components/about/ContributorEntry.kt
+++ b/app/src/main/kotlin/com/aliucord/manager/ui/components/about/ContributorEntry.kt
@@ -5,32 +5,27 @@
package com.aliucord.manager.ui.components.about
-import androidx.compose.foundation.Image
import androidx.compose.foundation.clickable
-import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.shape.CircleShape
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.res.stringResource
-import androidx.compose.ui.unit.dp
-import coil.compose.rememberImagePainter
-import coil.transform.CircleCropTransformation
+import coil.compose.AsyncImage
import com.aliucord.manager.R
@Composable
fun ContributorEntry(name: String) {
val uriHandler = LocalUriHandler.current
- Image(
+ AsyncImage(
modifier = Modifier
- .size(48.dp)
+ .fillMaxSize()
+ .clip(CircleShape)
.clickable { uriHandler.openUri("https://github.com/$name") },
- painter = rememberImagePainter(
- data = "https://github.com/$name.png",
- builder = {
- transformations(CircleCropTransformation())
- }
- ),
+ model = "https://github.com/$name.png",
contentDescription = stringResource(R.string.contributor)
)
}
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 dc07817..123a982 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
@@ -7,7 +7,7 @@ package com.aliucord.manager.ui.components.about
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.layout.*
-import androidx.compose.foundation.lazy.*
+import androidx.compose.foundation.lazy.grid.*
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
@@ -19,35 +19,42 @@ import com.aliucord.manager.models.github.GithubUser
@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class)
@Composable
-fun ContributorsCard(
- contributors: List,
-) = ElevatedCard(
- modifier = Modifier.wrapContentHeight().fillMaxWidth()
-) {
- Column(
- modifier = Modifier.padding(16.dp).fillMaxWidth(),
- verticalArrangement = Arrangement.spacedBy(12.dp)
+fun ContributorsCard(contributors: List) {
+ ElevatedCard(
+ modifier = Modifier
+ .wrapContentHeight()
+ .fillMaxWidth()
) {
- Text(
- text = stringResource(R.string.contributors),
- style = MaterialTheme.typography.titleLarge,
- color = MaterialTheme.colorScheme.primary
- )
-
- if (contributors.isNotEmpty()) {
- LazyVerticalGrid(
- cells = GridCells.Adaptive(48.dp),
- verticalArrangement = Arrangement.spacedBy(4.dp),
- horizontalArrangement = Arrangement.spacedBy(4.dp)
- ) {
- items(contributors) { user -> ContributorEntry(user.name) }
- }
- } else {
- Box(
- modifier = Modifier.fillMaxWidth().padding(12.dp),
- contentAlignment = Alignment.Center,
- content = { CircularProgressIndicator() }
+ Column(
+ modifier = Modifier
+ .padding(16.dp)
+ .fillMaxWidth(),
+ verticalArrangement = Arrangement.spacedBy(12.dp)
+ ) {
+ Text(
+ text = stringResource(R.string.contributors),
+ style = MaterialTheme.typography.titleLarge,
+ color = MaterialTheme.colorScheme.primary
)
+
+ if (contributors.isNotEmpty()) {
+ LazyVerticalGrid(
+ columns = GridCells.Adaptive(48.dp),
+ verticalArrangement = Arrangement.spacedBy(4.dp),
+ horizontalArrangement = Arrangement.spacedBy(4.dp),
+ userScrollEnabled = false
+ ) {
+ items(contributors) { user -> ContributorEntry(user.name) }
+ }
+ } else {
+ Box(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(12.dp),
+ contentAlignment = Alignment.Center,
+ content = { CircularProgressIndicator() }
+ )
+ }
}
}
}
diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/components/about/TeamCard.kt b/app/src/main/kotlin/com/aliucord/manager/ui/components/about/TeamCard.kt
index 45145c2..a5e3fed 100644
--- a/app/src/main/kotlin/com/aliucord/manager/ui/components/about/TeamCard.kt
+++ b/app/src/main/kotlin/com/aliucord/manager/ui/components/about/TeamCard.kt
@@ -33,7 +33,6 @@ fun TeamCard() = ElevatedCard(
) {
UserEntry("Juby210", "Fox")
UserEntry("Vendicated", "the ven")
- UserEntry("mwittrien", "your memory gon")
}
}
}
diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/components/plugins/Changelog.kt b/app/src/main/kotlin/com/aliucord/manager/ui/components/plugins/Changelog.kt
index af4e97e..697f294 100644
--- a/app/src/main/kotlin/com/aliucord/manager/ui/components/plugins/Changelog.kt
+++ b/app/src/main/kotlin/com/aliucord/manager/ui/components/plugins/Changelog.kt
@@ -6,14 +6,19 @@
package com.aliucord.manager.ui.components.plugins
import android.annotation.SuppressLint
-import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
+import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.ClickableText
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Person
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.vector.rememberVectorPainter
+import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
@@ -21,8 +26,8 @@ import androidx.compose.ui.text.*
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.unit.dp
-import coil.compose.rememberImagePainter
-import coil.transform.RoundedCornersTransformation
+import coil.compose.AsyncImage
+import coil.request.ImageRequest
import com.aliucord.manager.R
import com.aliucord.manager.models.Plugin
@@ -81,11 +86,15 @@ fun Changelog(
text = {
Column {
plugin.manifest.changelogMedia?.let { mediaUrl ->
- Image(
- modifier = Modifier.fillMaxWidth().heightIn(max = 90.dp),
- painter = rememberImagePainter(mediaUrl) {
- transformations(RoundedCornersTransformation(14.dp.value))
- },
+ AsyncImage(
+ modifier = Modifier
+ .fillMaxWidth()
+ .heightIn(max = 90.dp)
+ .clip(RoundedCornerShape(14.dp)),
+ model = ImageRequest.Builder(LocalContext.current)
+ .data(mediaUrl)
+ .build(),
+ placeholder = rememberVectorPainter(image = Icons.Default.Person),
contentDescription = stringResource(R.string.changelog_media)
)
}
diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/components/settings/ThemeDialog.kt b/app/src/main/kotlin/com/aliucord/manager/ui/components/settings/ThemeDialog.kt
index 0ddce97..a98125c 100644
--- a/app/src/main/kotlin/com/aliucord/manager/ui/components/settings/ThemeDialog.kt
+++ b/app/src/main/kotlin/com/aliucord/manager/ui/components/settings/ThemeDialog.kt
@@ -7,6 +7,8 @@ package com.aliucord.manager.ui.components.settings
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Style
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
@@ -26,6 +28,12 @@ fun ThemeDialog(
AlertDialog(
onDismissRequest = onDismissRequest,
+ icon = {
+ Icon(
+ imageVector = Icons.Default.Style,
+ contentDescription = "Theme"
+ )
+ },
title = { Text(stringResource(R.string.theme)) },
text = {
Column {
diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/AboutScreen.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screens/AboutScreen.kt
index 5cff35e..48b934c 100644
--- a/app/src/main/kotlin/com/aliucord/manager/ui/screens/AboutScreen.kt
+++ b/app/src/main/kotlin/com/aliucord/manager/ui/screens/AboutScreen.kt
@@ -25,6 +25,7 @@ import com.ramcosta.composedestinations.annotation.Destination
fun AboutScreen() {
val uriHandler = LocalUriHandler.current
val viewModel: AboutViewModel = viewModel()
+
Column(
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
@@ -42,7 +43,7 @@ fun AboutScreen() {
contentDescription = "GitHub"
)
Spacer(Modifier.padding(4.dp))
- Text(stringResource(R.string.source_code))
+ Text(stringResource(R.string.github))
}
}
}
diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/CommitsScreen.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screens/CommitsScreen.kt
index 549261c..66661f1 100644
--- a/app/src/main/kotlin/com/aliucord/manager/ui/screens/CommitsScreen.kt
+++ b/app/src/main/kotlin/com/aliucord/manager/ui/screens/CommitsScreen.kt
@@ -77,14 +77,12 @@ fun CommitsScreen() {
}
items(lazyPagingItems) { commitData ->
- val localUriHandler = LocalUriHandler.current
-
if (commitData == null) return@items
+ val localUriHandler = LocalUriHandler.current
+
ListItem(
- modifier = Modifier.clickable {
- localUriHandler.openUri(commitData.htmlUrl)
- },
+ modifier = Modifier.clickable { localUriHandler.openUri(commitData.htmlUrl) },
overlineText = { Text(commitData.sha.substring(0, 7)) },
text = { Text("${commitData.commit.message.split("\n").first()} - ${commitData.author.name}") }
)
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 e1fea42..d79e014 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
@@ -20,7 +20,6 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.*
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
-import androidx.core.net.toFile
import androidx.lifecycle.viewmodel.compose.viewModel
import com.aliucord.manager.R
import com.aliucord.manager.preferences.Prefs
@@ -31,10 +30,12 @@ import com.aliucord.manager.ui.screens.destinations.CommitsScreenDestination
import com.aliucord.manager.ui.screens.destinations.InstallerScreenDestination
import com.aliucord.manager.ui.viewmodels.HomeViewModel
import com.ramcosta.composedestinations.annotation.Destination
+import com.ramcosta.composedestinations.annotation.RootNavGraph
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
@OptIn(ExperimentalMaterial3Api::class)
-@Destination(start = true)
+@RootNavGraph(start = true)
+@Destination
@Composable
fun HomeScreen(navigator: DestinationsNavigator) {
val viewModel: HomeViewModel = viewModel()
@@ -45,7 +46,7 @@ fun HomeScreen(navigator: DestinationsNavigator) {
val filePicker = rememberLauncherForActivityResult(ActivityResultContracts.OpenDocument()) { uri ->
if (uri == null) return@rememberLauncherForActivityResult
- navigator.navigate(InstallerScreenDestination(uri.toFile()))
+ navigator.navigate(InstallerScreenDestination)
}
InstallerDialog(
diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/InstallScreen.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screens/InstallScreen.kt
index a2b6247..f73d264 100644
--- a/app/src/main/kotlin/com/aliucord/manager/ui/screens/InstallScreen.kt
+++ b/app/src/main/kotlin/com/aliucord/manager/ui/screens/InstallScreen.kt
@@ -9,7 +9,6 @@ import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
-import androidx.compose.foundation.lazy.items
import androidx.compose.material3.LinearProgressIndicator
import androidx.compose.material3.Text
import androidx.compose.runtime.*
@@ -20,21 +19,18 @@ import com.aliucord.manager.ui.screens.destinations.HomeScreenDestination
import com.aliucord.manager.ui.viewmodels.InstallViewModel
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
-import java.io.File
@OptIn(ExperimentalFoundationApi::class)
@Destination
@Composable
-fun InstallerScreen(navigator: DestinationsNavigator, apk: File?) {
+fun InstallerScreen(navigator: DestinationsNavigator) {
val viewModel: InstallViewModel = viewModel()
val navigateMain by viewModel.returnToHome.collectAsState(initial = false)
- if (navigateMain) {
- navigator.navigate(HomeScreenDestination)
- }
+ if (navigateMain) navigator.navigate(HomeScreenDestination)
LaunchedEffect(Unit) {
- viewModel.startInstallation(apk)
+ viewModel.startInstallation()
}
LazyColumn(
@@ -45,9 +41,9 @@ fun InstallerScreen(navigator: DestinationsNavigator, apk: File?) {
modifier = Modifier.fillParentMaxWidth()
)
}
- items(viewModel.logs) { log ->
+ item {
Text(
- text = log,
+ text = viewModel.log,
modifier = Modifier.padding(8.dp)
)
}
diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/SettingsScreen.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screens/SettingsScreen.kt
index c16ef05..b880617 100644
--- a/app/src/main/kotlin/com/aliucord/manager/ui/screens/SettingsScreen.kt
+++ b/app/src/main/kotlin/com/aliucord/manager/ui/screens/SettingsScreen.kt
@@ -5,25 +5,21 @@
package com.aliucord.manager.ui.screens
-import androidx.activity.compose.rememberLauncherForActivityResult
-import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.shrinkVertically
-import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
-import androidx.compose.material.ContentAlpha
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.verticalScroll
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.aliucord.manager.R
import com.aliucord.manager.preferences.Prefs
-import com.aliucord.manager.ui.components.ListItem
import com.aliucord.manager.ui.components.settings.*
import com.aliucord.manager.ui.viewmodels.SettingsViewModel
import com.ramcosta.composedestinations.annotation.Destination
@@ -102,32 +98,6 @@ fun SettingsScreen() = Column(
description = { Text(stringResource(R.string.debuggable_description)) },
preference = Prefs.debuggable
)
-
- val udfs = Prefs.useDexFromStorage
-
- PreferenceItem(
- title = { Text(stringResource(R.string.use_dex_from_storage)) },
- preference = Prefs.useDexFromStorage
- )
-
- val picker = rememberLauncherForActivityResult(ActivityResultContracts.OpenDocument()) { uri ->
- if (uri != null) Prefs.dexLocation.set(uri.path!!)
- }
-
- val color = if (udfs.get()) {
- Color.Unspecified
- } else {
- MaterialTheme.colorScheme.onBackground.copy(ContentAlpha.disabled)
- }
-
- // TODO: Make installer use selected dex file
- ListItem(
- modifier = if (udfs.get()) Modifier.clickable {
- picker.launch(arrayOf("application/octet-stream"))
- } else Modifier,
- text = { Text(stringResource(R.string.dex_location), color = color) },
- secondaryText = { Text(Prefs.dexLocation.get(), color = color) }
- )
}
}
diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/theme/Theme.kt b/app/src/main/kotlin/com/aliucord/manager/ui/theme/Theme.kt
index 7704053..5c1c640 100644
--- a/app/src/main/kotlin/com/aliucord/manager/ui/theme/Theme.kt
+++ b/app/src/main/kotlin/com/aliucord/manager/ui/theme/Theme.kt
@@ -60,7 +60,9 @@ fun ManagerTheme(
)
}
-enum class Theme(val displayName: String) {
+enum class Theme(
+ val displayName: String
+) {
SYSTEM("System"),
LIGHT("Light"),
DARK("Dark");
diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/viewmodels/HomeViewModel.kt b/app/src/main/kotlin/com/aliucord/manager/ui/viewmodels/HomeViewModel.kt
index 10a1659..030d8a5 100644
--- a/app/src/main/kotlin/com/aliucord/manager/ui/viewmodels/HomeViewModel.kt
+++ b/app/src/main/kotlin/com/aliucord/manager/ui/viewmodels/HomeViewModel.kt
@@ -12,12 +12,10 @@ import com.aliucord.manager.preferences.Prefs
import com.aliucord.manager.utils.*
import io.ktor.client.request.*
import io.ktor.client.statement.*
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.launch
+import kotlinx.coroutines.*
import kotlinx.serialization.decodeFromString
class HomeViewModel(application: Application) : AndroidViewModel(application) {
-
private val packageManager = getApplication().packageManager
var supportedVersion by mutableStateOf("")
@@ -26,20 +24,22 @@ class HomeViewModel(application: Application) : AndroidViewModel(application) {
var installedVersion by mutableStateOf("-")
private set
- fun load() {
+ private fun load() {
viewModelScope.launch(Dispatchers.IO) {
val version = json.decodeFromString(httpClient.get(Github.dataUrl).bodyAsText())
- supportedVersion = "${version.versionName} - " + when (version.versionCode[3]) {
- '0' -> "Stable"
- '1' -> "Beta"
- '2' -> "Alpha"
- else -> throw NoWhenBranchMatchedException()
- }
- installedVersion = try {
- packageManager.getPackageInfo(Prefs.packageName.get(), 0).versionName
- } catch (th: Throwable) {
- "-"
+ withContext(Dispatchers.Main) {
+ supportedVersion = "${version.versionName} - " + when (version.versionCode[3]) {
+ '0' -> "Stable"
+ '1' -> "Beta"
+ '2' -> "Alpha"
+ else -> throw NoWhenBranchMatchedException()
+ }
+ installedVersion = try {
+ packageManager.getPackageInfo(Prefs.packageName.get(), 0).versionName
+ } catch (th: Throwable) {
+ "-"
+ }
}
}
}
@@ -63,5 +63,4 @@ class HomeViewModel(application: Application) : AndroidViewModel(application) {
init {
load()
}
-
}
diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/viewmodels/InstallViewModel.kt b/app/src/main/kotlin/com/aliucord/manager/ui/viewmodels/InstallViewModel.kt
index fdd0cb8..bae4aad 100644
--- a/app/src/main/kotlin/com/aliucord/manager/ui/viewmodels/InstallViewModel.kt
+++ b/app/src/main/kotlin/com/aliucord/manager/ui/viewmodels/InstallViewModel.kt
@@ -1,200 +1,178 @@
package com.aliucord.manager.ui.viewmodels
+import android.annotation.SuppressLint
import android.app.Application
+import android.app.PendingIntent
import android.content.Intent
-import androidx.compose.runtime.mutableStateListOf
-import androidx.core.content.FileProvider
+import android.content.pm.PackageInstaller
+import android.os.Build
+import androidx.annotation.RequiresApi
+import androidx.compose.runtime.*
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.viewModelScope
-import com.aliucord.libzip.Zip
-import com.aliucord.manager.BuildConfig
-import com.aliucord.manager.preferences.Prefs
-import com.aliucord.manager.utils.*
+import com.aliucord.manager.installer.service.InstallService
+import com.aliucord.manager.installer.util.DownloadUtils
+import com.aliucord.manager.installer.util.ManifestPatcher
+import com.aliucord.manager.utils.Signer
+import com.android.zipflinger.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.launch
import java.io.File
-import java.io.FileNotFoundException
+import java.util.zip.Deflater
class InstallViewModel(application: Application) : AndroidViewModel(application) {
-
private val _returnToHome = MutableSharedFlow()
val returnToHome = _returnToHome.asSharedFlow()
private var installationRunning: Boolean = false
- val logs = mutableStateListOf()
+ var log by mutableStateOf("")
+ private set
- fun startInstallation(apk: File?) {
+ @RequiresApi(Build.VERSION_CODES.O)
+ fun startInstallation() {
if (installationRunning) return
viewModelScope.launch(Dispatchers.IO) {
installationRunning = true
- val supportedVersion = Github.version.versionCode
- val discordApk = apk ?: run {
- logs.add("Checking for cached APK...")
+ val context = getApplication().applicationContext
+ val assetManager = context.assets
+ val externalCacheDir = context.externalCacheDir!!
+ val arch = Build.SUPPORTED_ABIS.first()
+ val supportedVersion = "124206"
- getApplication().externalCacheDir!!.resolve("discord-${supportedVersion}.apk").also { file ->
- val archiveInfo = getApplication().packageManager.getPackageArchiveInfo(file.path, 0)
+ val baseApk = externalCacheDir.resolve("base-${supportedVersion}.apk").also { file ->
+ val archiveInfo = context.packageManager.getPackageArchiveInfo(file.path, 0)
- if (archiveInfo?.versionCode.toString().startsWith(supportedVersion)) return@also
+ if (archiveInfo?.versionCode.toString().startsWith(supportedVersion)) return@also run { log += "Using cached base APK\n"}
- logs.add("Downloading Discord APK...")
+ log += "Downloading Discord APK... "
- DownloadUtils.downloadDiscordApk(getApplication(), supportedVersion)
+ DownloadUtils.downloadDiscordApk(context, supportedVersion)
- logs.add("Done")
+ log += "Done\n"
+ }
+
+ val libArch = arch.replace("-v", "_v")
+ val libsApk = externalCacheDir.resolve("config.$libArch-${supportedVersion}.apk").also { file ->
+ if (file.exists()) return@also run { log += "Used cached libs APK\n" }
+
+ log += "Downloading libs APK... "
+
+ DownloadUtils.downloadSplit(context, supportedVersion, "config.$libArch")
+
+ log += "Done\n"
+ }
+
+ val localeApk = externalCacheDir.resolve("config.en-${supportedVersion}.apk").also { file ->
+ if (file.exists()) return@also run { log += "Using cached locale APK\n" }
+
+ log += "Downloading locale APK... "
+
+ DownloadUtils.downloadSplit(context, supportedVersion, "config.en")
+
+ log += "Done\n"
+ }
+
+ val xxhdpiApk = externalCacheDir.resolve("config.xxhdpi-${supportedVersion}.apk").also { file ->
+ if (file.exists()) return@also run { log += "Using cached drawables APK\n"}
+
+ log += "Downloading drawables APK... "
+
+ DownloadUtils.downloadSplit(context, supportedVersion, "config.xxhdpi")
+
+ log += "Done\n"
+ }
+
+ val apks = listOf(baseApk, libsApk, localeApk, xxhdpiApk)
+
+ log += "Patching manifest...\n"
+
+ try {
+ val byteArray = ZipRepo(baseApk.absolutePath)
+ .use { zip -> zip.getContent("AndroidManifest.xml") }
+ .array()
+
+ ZipArchive(baseApk.toPath()).use { zip ->
+ val source = BytesSource(ManifestPatcher.patchManifest(byteArray), "AndroidManifest.xml", Deflater.DEFAULT_COMPRESSION)
+
+ zip.delete("AndroidManifest.xml")
+ zip.add(source)
}
- }
- val injector = getApplication().externalCacheDir!!.resolve("Injector.dex").also { file ->
- if (file.exists()) return@also
+ apks.forEach { apk ->
+ val byteArray = ZipRepo(apk.absolutePath)
+ .use { zip -> zip.getContent("AndroidManifest.xml") }
+ .array()
- logs.add("Downloading injector...")
+ ZipArchive(apk.toPath()).use { zip ->
+ val source = BytesSource(ManifestPatcher.renamePackage(byteArray), "AndroidManifest.xml", Deflater.DEFAULT_COMPRESSION)
- DownloadUtils.downloadInjector(getApplication())
-
- logs.add("Done")
- }
-
- val outputDir = aliucordDir.also {
- if (!it.exists() && !it.mkdirs()) throw FileNotFoundException()
- }
-
- val outputApk = outputDir.resolve("Aliucord.apk")
- discordApk.copyTo(outputApk, true)
-
- logs.add("Repacking APK")
-
- var patched = false
- var manifestBytes: ByteArray?
-
- with(Zip(outputApk.absolutePath, 6, 'r')) {
- for (index in 0 until totalEntries) {
- openEntryByIndex(index)
- val name = entryName
- closeEntry()
- if (name == "classes5.dex") {
- patched = true
- break
+ zip.delete("AndroidManifest.xml")
+ zip.add(source)
}
}
-
- val cacheDir = getApplication().cacheDir.absolutePath
-
- if (!patched) (1..3).forEach { i ->
- openEntry("classes${if (i == 1) "" else i}.dex")
- extractEntry("$cacheDir/classes${i + 1}.dex")
- closeEntry()
- }
-
- openEntry("AndroidManifest.xml")
- manifestBytes = readEntry()
- closeEntry()
-
- close()
+ } catch (e: Exception) {
+ log += "An error has occurred"
+ e.printStackTrace()
}
- val assetManager = getApplication().assets
+ log += "Patching libraries...\n"
- with(Zip(outputApk.absolutePath, 6, 'a')) {
- if (patched) {
- deleteEntry("classes.dex")
- deleteEntry("classes5.dex")
- deleteEntry("classes6.dex")
- } else {
- (1..3).forEach { i -> deleteEntry("classes${if (i == 1) "" else i}.dex") }
- }
+ ZipArchive(libsApk.toPath()).use { zip ->
+ val libs = listOf("libhermes.so", "libc++_shared.so")
- deleteEntry("AndroidManifest.xml")
-
- listOf("arm64-v8a", "armeabi-v7a", "x86", "x86_64").forEach { arch ->
- listOf("/libaliuhook.so", "/liblsplant.so", "/libc++_shared.so").forEach { file ->
- deleteEntry("lib/$arch$file")
+ libs.forEach { lib -> zip.delete("lib/$arch/$lib") }
+ libs.forEach { lib ->
+ val source = BytesSource(assetManager.open("lib/$arch/$lib"), "lib/$arch/$lib", Deflater.NO_COMPRESSION).apply {
+ align(4096)
}
- }
- if (!patched) for (i in 2..4) {
- val name = "classes$i.dex"
- val cacheFile = getApplication().cacheDir.resolve(name)
-
- openEntry(name)
- compressFile(cacheFile.absolutePath)
- closeEntry()
- cacheFile.delete()
- }
-
- openEntry("classes.dex")
- compressFile(injector.absolutePath)
- closeEntry()
-
- writeEntry("classes5.dex", assetManager.open("aliuhook/classes.dex"))
-
- listOf("arm64-v8a", "armeabi-v7a", "x86", "x86_64").forEach { arch ->
- listOf("/libaliuhook.so", "/liblsplant.so", "/libc++_shared.so").forEach { file ->
- writeEntry("lib/$arch$file", assetManager.open("aliuhook/$arch$file"))
- }
- }
-
- writeEntry("classes6.dex", assetManager.open("kotlin/classes.dex"))
-
- manifestBytes?.let { bytes ->
- logs.add("Patching manifest")
- val newManifestBytes = patchManifest(bytes)
- openEntry("AndroidManifest.xml")
- writeEntry(newManifestBytes, newManifestBytes.size.toLong())
- closeEntry()
- }
-
- close()
- }
-
- if (Prefs.replaceBg.get()) {
- logs.add("Replacing icon background")
-
- val icon1Bytes = assetManager.open("icon1.png").readBytes()
- val icon2Bytes = assetManager.open("icon2.png").readBytes()
-
- // use androguard to figure out entries
- // androguard arsc resources.arsc --id 0x7f0f0000 (icon1)
- // androguard arsc resources.arsc --id 0x7f0f0002 and androguard arsc resources.arsc --id 0x7f0f0006 (icon2)
- val icon1Entries = listOf("MbV.png", "kbF.png", "_eu.png", "EtS.png")
- val icon2Entries =
- listOf("_h_.png", "9MB.png", "Dy7.png", "kC0.png", "oEH.png", "RG0.png", "ud_.png", "W_3.png")
-
- with(Zip(outputApk.absolutePath, 0, 'a')) {
- icon1Entries.forEach { entry -> deleteEntry("res/$entry") }
- icon2Entries.forEach { entry -> deleteEntry("res/$entry") }
-
- icon1Entries.forEach { entry -> writeEntry("res/$entry", icon1Bytes) }
- icon2Entries.forEach { entry -> writeEntry("res/$entry", icon2Bytes) }
-
- close()
+ zip.add(source)
}
}
- logs.add("Signing APK...")
+ log += "Signing APKs... "
- Signer.signApk(outputApk)
+ apks.forEach(Signer::signApk)
- logs.add("Signed APK")
+ log += "Done\n"
- val intent = Intent(Intent.ACTION_VIEW).apply {
- flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_GRANT_READ_URI_PERMISSION
-
- setDataAndType(
- FileProvider.getUriForFile(getApplication(), "${BuildConfig.APPLICATION_ID}.provider", outputApk),
- "application/vnd.android.package-archive"
- )
- }
-
- getApplication().startActivity(intent)
+ installApks(*apks.toTypedArray())
_returnToHome.emit(true)
installationRunning = false
}
}
+ private fun installApks(vararg apks: File) {
+ val context = getApplication().applicationContext
+ val params = PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL)
+ val packageInstaller = context.packageManager.packageInstaller
+ val sessionId = packageInstaller.createSession(params)
+ val session = packageInstaller.openSession(sessionId)
+
+ apks.forEach { apk ->
+ session.openWrite(apk.name, 0, apk.length()).use {
+ it.write(apk.readBytes())
+
+ session.fsync(it)
+ }
+ }
+
+ val callbackIntent = Intent(context, InstallService::class.java)
+
+ @SuppressLint("UnspecifiedImmutableFlag")
+ val contentIntent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+ PendingIntent.getService(context, 0, callbackIntent, PendingIntent.FLAG_MUTABLE)
+ } else {
+ PendingIntent.getService(context, 0, callbackIntent, 0)
+ }
+
+ session.commit(contentIntent.intentSender)
+ session.close()
+ }
}
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 4e1f7cb..61c841e 100644
--- a/app/src/main/kotlin/com/aliucord/manager/utils/Const.kt
+++ b/app/src/main/kotlin/com/aliucord/manager/utils/Const.kt
@@ -11,11 +11,6 @@ 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 json = Json {
prettyPrint = true
ignoreUnknownKeys = true
@@ -27,4 +22,3 @@ val httpClient = HttpClient {
}
}
val aliucordDir = Environment.getExternalStorageDirectory().resolve("Aliucord")
-val pluginsDir = aliucordDir.resolve("plugins")
diff --git a/app/src/main/kotlin/com/aliucord/manager/utils/ManifestPatcher.kt b/app/src/main/kotlin/com/aliucord/manager/utils/ManifestPatcher.kt
deleted file mode 100644
index 290a208..0000000
--- a/app/src/main/kotlin/com/aliucord/manager/utils/ManifestPatcher.kt
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (c) 2022 Juby210 & zt
- * Licensed under the Open Software License version 3.0
- */
-
-package com.aliucord.manager.utils
-
-import com.aliucord.manager.preferences.Prefs
-import pxb.android.axml.*
-
-fun patchManifest(manifestBytes: ByteArray): ByteArray {
- val packageName = Prefs.packageName.get()
-
- val reader = AxmlReader(manifestBytes)
- val writer = AxmlWriter()
- reader.accept(object : AxmlVisitor(writer) {
- override fun child(ns: String?, name: String?) =
- object : ReplaceAttrsVisitor(super.child(ns, name), mapOf("package" to packageName)) {
- private var addManagePerm = true
-
- override fun attr(ns: String?, name: String, resourceId: Int, type: Int, value: Any?) {
- super.attr(ns, name, resourceId, type, value)
- if (value == MANAGE_EXTERNAL_STORAGE) addManagePerm = false
- }
-
- override fun child(ns: String?, name: String): NodeVisitor {
- val nv = super.child(ns, name)
- return when (name) {
- "uses-sdk" -> ReplaceAttrsVisitor(nv, mapOf("targetSdkVersion" to 29))
- "permission" -> ReplaceAttrsVisitor(nv, mapOf("name" to "$packageName.permission.CONNECT"))
- "application" -> object : ReplaceAttrsVisitor(
- nv,
- mapOf(REQUEST_LEGACY_STORAGE to 1, "label" to Prefs.appName.get(), DEBUGGABLE to Prefs.debuggable.get())
- ) {
- private var addLegacyStorage = true
- private var addDebuggable = Prefs.debuggable.get()
-
- override fun attr(ns: String?, name: String, resourceId: Int, type: Int, value: Any?) {
- super.attr(ns, name, resourceId, type, value)
- if (name == REQUEST_LEGACY_STORAGE) addLegacyStorage = false
- else if (name == DEBUGGABLE) addDebuggable = false
- }
-
- override fun child(ns: String?, name: String): NodeVisitor {
- val visitor = super.child(ns, name)
- return when (name) {
- "activity" -> ReplaceAttrsVisitor(visitor, mapOf("label" to Prefs.appName.get()))
- "service" -> object : NodeVisitor(visitor) {
- private var disableService = false
-
- override fun attr(ns: String?, name: String, resourceId: Int, type: Int, value: Any?) {
- if (name == "name" && (
- value == "com.google.android.gms.analytics.AnalyticsService" ||
- value == "com.google.android.gms.analytics.AnalyticsJobService")
- ) disableService = true
- super.attr(
- ns, name, resourceId, type,
- if (value is String && value.endsWith("CONNECT"))
- "$packageName.permission.CONNECT"
- else if (disableService && name == "enabled") 0
- else value
- )
- }
- }
- "provider" -> object : NodeVisitor(visitor) {
- override fun attr(ns: String?, name: String, resourceId: Int, type: Int, value: Any?) {
- super.attr(
- ns, name, resourceId, type,
- if (name == "authorities") (value as String).replace("com.discord", packageName) else value
- )
- }
- }
- "meta-data" -> object : NodeVisitor(visitor) {
- private var crashlytics = false
-
- override fun attr(ns: String?, name: String, resourceId: Int, type: Int, value: Any?) {
- if (name == "name" && value == "firebase_crashlytics_collection_enabled") crashlytics = true
- super.attr(
- ns, name, resourceId, type,
- if (name == "value" && crashlytics) 0 else value
- )
- }
- }
- else -> visitor
- }
- }
-
- override fun end() {
- if (addLegacyStorage)
- super.attr(ANDROID_NAMESPACE, REQUEST_LEGACY_STORAGE, -1, TYPE_INT_BOOLEAN, 1)
- if (addDebuggable)
- super.attr(ANDROID_NAMESPACE, DEBUGGABLE, -1, TYPE_INT_BOOLEAN, 1)
- super.end()
- }
- }
- else -> nv
- }
- }
-
- override fun end() {
- if (addManagePerm) super.child(null, "uses-permission").attr(
- ANDROID_NAMESPACE, "name", -1, TYPE_STRING, MANAGE_EXTERNAL_STORAGE
- )
- super.end()
- }
- }
- })
- return writer.toByteArray()
-}
diff --git a/app/src/main/kotlin/com/aliucord/manager/utils/ReplaceAttrsVisitor.kt b/app/src/main/kotlin/com/aliucord/manager/utils/ReplaceAttrsVisitor.kt
deleted file mode 100644
index a076ee3..0000000
--- a/app/src/main/kotlin/com/aliucord/manager/utils/ReplaceAttrsVisitor.kt
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (c) 2022 Juby210 & zt
- * Licensed under the Open Software License version 3.0
- */
-
-
-package com.aliucord.manager.utils
-
-import pxb.android.axml.NodeVisitor
-
-open class ReplaceAttrsVisitor(
- nv: NodeVisitor,
- private val attrs: Map
-) : NodeVisitor(nv) {
- override fun attr(ns: String?, name: String, resourceId: Int, type: Int, value: Any?) {
- val replace = attrs.containsKey(name)
- val newValue = attrs[name]
- super.attr(ns, name, resourceId, if (newValue is String) TYPE_STRING else type, if (replace) newValue else value)
- }
-}
diff --git a/app/src/main/kotlin/com/aliucord/manager/utils/Signer.kt b/app/src/main/kotlin/com/aliucord/manager/utils/Signer.kt
index cfb613e..b9a5bdb 100644
--- a/app/src/main/kotlin/com/aliucord/manager/utils/Signer.kt
+++ b/app/src/main/kotlin/com/aliucord/manager/utils/Signer.kt
@@ -76,13 +76,12 @@ object Signer {
}
fun signApk(apkFile: File) {
- val outputApk = aliucordDir.resolve("Aliucord-Signed.apk")
+ val outputApk = aliucordDir.resolve(apkFile.name)
ApkSigner.Builder(listOf(signerConfig))
.setV1SigningEnabled(false)
.setV2SigningEnabled(true)
.setV3SigningEnabled(false)
- .setOtherSignersSignaturesPreserved(false)
.setInputApk(apkFile)
.setOutputApk(outputApk)
.build()
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 6daa6c7..901785e 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -10,7 +10,7 @@
Settings
Show menu
Theme
- Use Aliucord.dex from storage
+ Use Injector.dex from storage
Plugins
Uninstall %1$s
Search
@@ -25,12 +25,12 @@
Update
Developer Mode
Debuggable
- Use debuggable manifest
+ Enable debuggable flag
About
Team
Contributors
Search Plugins
- Source Code
+ GitHub
Installer
Use black
Use black colors for dark mode
diff --git a/build.gradle.kts b/build.gradle.kts
index c08ff27..49d45e0 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -7,7 +7,7 @@ buildscript {
dependencies {
classpath("com.android.tools.build:gradle:7.1.3")
- classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.10")
+ classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.20")
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle.kts files