feat: remove RN install

This commit is contained in:
rushiiMachine 2024-01-12 15:14:40 -08:00
parent 4617e5ec56
commit 4953947e1d
No known key found for this signature in database
GPG key ID: DCBE5952BB3B6420
8 changed files with 108 additions and 461 deletions

View file

@ -25,9 +25,6 @@ class DownloadManager(
suspend fun downloadDiscordApk(version: String, out: File): File =
download("$BACKEND_HOST/download/discord?v=$version", out)
suspend fun downloadSplit(version: String, split: String, out: File): File =
download("$BACKEND_HOST/download/discord?v=$version&split=$split", out)
// Aliucord Kotlin downloads
suspend fun downloadKtInjector(out: File): File =
download(AliucordGithubService.KT_INJECTOR_URL, out)
@ -38,9 +35,6 @@ class DownloadManager(
suspend fun downloadKotlinDex(out: File): File =
download(AliucordGithubService.KOTLIN_DEX_URL, out)
suspend fun downloadBootstrap(out: File): File =
download(AliucordGithubService.BOOTSTRAP_URL, out)
suspend fun download(url: String, out: File): File {
out.parentFile?.mkdirs()

View file

@ -13,8 +13,5 @@ class GithubRepository(
suspend fun getDataJson() = service.getDataJson()
suspend fun getHermesRelease() = service.getLatestHermesRelease()
suspend fun getAliucordNativeRelease() = service.getLatestAliucordNativeRelease()
suspend fun getManagerReleases() = service.getManagerReleases()
suspend fun getLatestBootstrapCommit() = service.getLatestBootstrapCommit()
}

View file

@ -1,10 +1,8 @@
package com.aliucord.manager.network.service
import com.aliucord.manager.network.dto.Commit
import com.aliucord.manager.network.dto.Version
import com.aliucord.manager.network.utils.ApiResponse
import com.aliucord.manager.network.utils.transform
import io.ktor.client.request.*
import io.ktor.client.request.url
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@ -20,31 +18,15 @@ class AliucordGithubService(
}
}
suspend fun getLatestBootstrapCommit(): ApiResponse<String> {
return withContext(Dispatchers.IO) {
http.request<List<Commit>> {
url("https://api.github.com/repos/$ORG/$RN_REPO/commits?sha=builds&path=bootstrap.js&per_page=1")
}.transform {
it.single().sha
}
}
}
suspend fun getCommits(page: Int = 0) = github.getCommits(ORG, MAIN_REPO, page)
suspend fun getLatestHermesRelease() = github.getLatestRelease(ORG, HERMES_REPO)
suspend fun getLatestAliucordNativeRelease() = github.getLatestRelease(ORG, ALIUNATIVE_REPO)
suspend fun getManagerReleases() = github.getReleases(ORG, MANAGER_REPO)
suspend fun getContributors() = github.getContributors(ORG, MAIN_REPO)
companion object {
private const val ORG = "Aliucord"
private const val MAIN_REPO = "Aliucord"
private const val RN_REPO = "AliucordRN"
private const val HERMES_REPO = "Hermes"
private const val ALIUNATIVE_REPO = "AliucordNative"
private const val MANAGER_REPO = "AliucordManager"
private const val MANAGER_REPO = "Manager"
const val BOOTSTRAP_URL = "https://raw.githubusercontent.com/$ORG/$RN_REPO/builds/bootstrap.js"
const val KT_INJECTOR_URL = "https://raw.githubusercontent.com/$ORG/$MAIN_REPO/builds/Injector.dex"
const val KOTLIN_DEX_URL = "https://raw.githubusercontent.com/$ORG/$MAIN_REPO/main/installer/android/app/src/main/assets/kotlin/classes.dex"
}

View file

@ -5,25 +5,11 @@
package com.aliucord.manager.ui.dialog
import androidx.compose.foundation.layout.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Download
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import com.aliucord.manager.BuildConfig
import com.aliucord.manager.R
import com.aliucord.manager.ui.screen.InstallData
enum class DownloadMethod { DOWNLOAD }
enum class DiscordType { KOTLIN, REACT_NATIVE }
@Composable
fun InstallerDialog(
@ -31,104 +17,104 @@ fun InstallerDialog(
onConfirm: (InstallData) -> Unit
) {
val downloadMethod by rememberSaveable { mutableStateOf(DownloadMethod.DOWNLOAD) }
var discordType by rememberSaveable { mutableStateOf<DiscordType?>(null) }
fun triggerConfirm() {
onDismiss()
onConfirm(
InstallData(
downloadMethod,
discordType ?: return
)
InstallData(downloadMethod)
)
}
Dialog(
onDismissRequest = onDismiss,
) {
Surface(
color = AlertDialogDefaults.containerColor,
tonalElevation = AlertDialogDefaults.TonalElevation,
shape = AlertDialogDefaults.shape,
) {
Column(
modifier = Modifier
.sizeIn(minWidth = 380.dp)
.padding(24.dp)
) {
// Icon
Box(
Modifier
.align(Alignment.CenterHorizontally)
.padding(bottom = 16.dp)
) {
Icon(
imageVector = Icons.Default.Download,
tint = AlertDialogDefaults.iconContentColor,
contentDescription = null
)
}
SideEffect(::triggerConfirm)
// Title
Box(
modifier = Modifier
.align(Alignment.CenterHorizontally)
.padding(bottom = 30.dp)
) {
Text(
stringResource(R.string.selector_discord_type),
color = AlertDialogDefaults.titleContentColor,
style = MaterialTheme.typography.headlineSmall
)
}
// TODO: local install option
// Body
Box(
modifier = Modifier
.padding(bottom = 30.dp)
) {
Text(
stringResource(R.string.selector_discord_type_body),
textAlign = TextAlign.Center,
color = AlertDialogDefaults.textContentColor,
style = MaterialTheme.typography.bodyMedium
)
}
// Buttons
Column(
verticalArrangement = Arrangement.spacedBy(4.dp),
modifier = Modifier.clip(MaterialTheme.shapes.large)
) {
ProvideTextStyle(MaterialTheme.typography.labelMedium) {
Button(
shape = MaterialTheme.shapes.extraSmall,
enabled = BuildConfig.RN_ENABLED,
onClick = {
discordType = DiscordType.REACT_NATIVE
triggerConfirm()
},
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
) {
Text(stringResource(R.string.selector_discord_type_kotlin))
}
Button(
shape = MaterialTheme.shapes.extraSmall,
onClick = {
discordType = DiscordType.KOTLIN
triggerConfirm()
},
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
) {
Text(stringResource(R.string.selector_discord_type_old))
}
}
}
}
}
}
// Dialog(
// onDismissRequest = onDismiss,
// ) {
// Surface(
// color = AlertDialogDefaults.containerColor,
// tonalElevation = AlertDialogDefaults.TonalElevation,
// shape = AlertDialogDefaults.shape,
// ) {
// Column(
// modifier = Modifier
// .sizeIn(minWidth = 380.dp)
// .padding(24.dp)
// ) {
// // Icon
// Box(
// Modifier
// .align(Alignment.CenterHorizontally)
// .padding(bottom = 16.dp)
// ) {
// Icon(
// imageVector = Icons.Default.Check, // TODO: move away from icon lib
// tint = AlertDialogDefaults.iconContentColor,
// contentDescription = null
// )
// }
//
// // Title
// Box(
// modifier = Modifier
// .align(Alignment.CenterHorizontally)
// .padding(bottom = 30.dp)
// ) {
// Text(
// stringResource(R.string.selector_discord_type),
// color = AlertDialogDefaults.titleContentColor,
// style = MaterialTheme.typography.headlineSmall
// )
// }
//
// // Body
// Box(
// modifier = Modifier
// .padding(bottom = 30.dp)
// ) {
// Text(
// stringResource(R.string.selector_discord_type_body),
// textAlign = TextAlign.Center,
// color = AlertDialogDefaults.textContentColor,
// style = MaterialTheme.typography.bodyMedium
// )
// }
//
// Buttons
// Column(
// verticalArrangement = Arrangement.spacedBy(4.dp),
// modifier = Modifier.clip(MaterialTheme.shapes.large)
// ) {
// ProvideTextStyle(MaterialTheme.typography.labelMedium) {
// Button(
// shape = MaterialTheme.shapes.extraSmall,
// enabled = BuildConfig.RN_ENABLED,
// onClick = {
// discordType = DiscordType.REACT_NATIVE
// triggerConfirm()
// },
// modifier = Modifier
// .fillMaxWidth()
// .height(50.dp)
// ) {
// Text(stringResource(R.string.selector_discord_type_kotlin))
// }
// Button(
// shape = MaterialTheme.shapes.extraSmall,
// onClick = {
// discordType = DiscordType.KOTLIN
// triggerConfirm()
// },
// modifier = Modifier
// .fillMaxWidth()
// .height(50.dp)
// ) {
// Text(stringResource(R.string.selector_discord_type_old))
// }
// }
// }
// }
// }
// }
}

View file

@ -11,7 +11,7 @@ import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.NavigateBefore
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
@ -22,7 +22,6 @@ import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.unit.dp
import com.aliucord.manager.R
import com.aliucord.manager.ui.component.installer.*
import com.aliucord.manager.ui.dialog.DiscordType
import com.aliucord.manager.ui.dialog.DownloadMethod
import com.aliucord.manager.ui.viewmodel.InstallViewModel
import com.aliucord.manager.ui.viewmodel.InstallViewModel.InstallStepGroup
@ -30,13 +29,11 @@ import kotlinx.collections.immutable.toImmutableList
import kotlinx.parcelize.Parcelize
import org.koin.androidx.compose.getViewModel
import org.koin.core.parameter.parametersOf
import java.util.*
@Immutable // this isn't *really* stable, but this never gets modified after being passed to a composable, so...
@Parcelize
data class InstallData(
val downloadMethod: DownloadMethod,
val discordType: DiscordType,
var baseApk: String? = null,
var splits: List<String>? = null
) : Parcelable
@ -50,7 +47,7 @@ fun InstallerScreen(
) {
if (viewModel.returnToHome) onBackClick()
var expandedGroup by mutableStateOf<InstallStepGroup?>(null)
var expandedGroup by remember { mutableStateOf<InstallStepGroup?>(null) }
LaunchedEffect(viewModel.currentStep) {
expandedGroup = viewModel.currentStep?.group
@ -63,7 +60,7 @@ fun InstallerScreen(
navigationIcon = {
IconButton(onClick = onBackClick) {
Icon(
imageVector = Icons.Default.NavigateBefore,
imageVector = Icons.Default.ArrowBack,
contentDescription = stringResource(R.string.navigation_back)
)
}
@ -88,7 +85,7 @@ fun InstallerScreen(
.fillMaxWidth()
.padding(16.dp)
) {
for (group in InstallStepGroup.values()) {
for (group in InstallStepGroup.entries) {
InstallGroup(
name = stringResource(group.nameResId),
isCurrent = expandedGroup == group,

View file

@ -1,5 +1,6 @@
package com.aliucord.manager.ui.viewmodel
import android.annotation.SuppressLint
import android.app.Application
import android.os.Build
import android.util.Log
@ -17,15 +18,13 @@ import com.aliucord.manager.installer.util.*
import com.aliucord.manager.network.utils.getOrThrow
import com.aliucord.manager.ui.component.installer.InstallStatus
import com.aliucord.manager.ui.component.installer.InstallStepData
import com.aliucord.manager.ui.dialog.DiscordType
import com.aliucord.manager.ui.screen.InstallData
import com.aliucord.manager.util.*
import com.github.diamondminer88.zip.*
import kotlinx.coroutines.*
import java.text.SimpleDateFormat
import java.util.*
import java.util.Date
import java.util.concurrent.atomic.AtomicBoolean
import kotlin.time.ExperimentalTime
import kotlin.time.measureTimedValue
class InstallViewModel(
@ -55,7 +54,7 @@ class InstallViewModel(
Running Android ${Build.VERSION.RELEASE}, API level ${Build.VERSION.SDK_INT}
Supported ABIs: ${Build.SUPPORTED_ABIS.joinToString()}
Installing ${installData.discordType} with the ${installData.downloadMethod} apk method
Installing Aliucord kt with the ${installData.downloadMethod} apk method
Failed on: ${currentStep?.name}
""".trimIndent()
@ -69,11 +68,13 @@ class InstallViewModel(
}
private var debugLogPath by mutableStateOf<String?>(null)
@SuppressLint("SimpleDateFormat")
fun saveDebugToFile() {
val name = if (debugLogPath != null) {
debugLogPath!!
} else {
"Aliucord Manager ${SimpleDateFormat("YYYY-MM-dd hh-mm-s a").format(Date())}.log"
"Aliucord Manager ${SimpleDateFormat("yyyy-MM-dd hh-mm-s a").format(Date())}.log"
.also { debugLogPath = it }
}
@ -92,10 +93,7 @@ class InstallViewModel(
withContext(Dispatchers.IO) {
try {
when (installData.discordType) {
DiscordType.REACT_NATIVE -> installReactNative()
DiscordType.KOTLIN -> installKotlin()
}
installKotlin()
isFinished = true
delay(20000)
@ -145,304 +143,6 @@ class InstallViewModel(
}
}
private suspend fun installReactNative() {
steps += listOfNotNull(
InstallStep.DL_BASE_APK,
InstallStep.DL_LIBS_APK,
InstallStep.DL_LANG_APK,
InstallStep.DL_RESC_APK,
InstallStep.DL_HERMES,
InstallStep.DL_ALIUNATIVE,
InstallStep.DL_BOOTSTRAP,
if (preferences.replaceIcon) InstallStep.PATCH_APP_ICON else null,
InstallStep.PATCH_MANIFEST,
InstallStep.PATCH_DEX,
InstallStep.PATCH_LIBS,
InstallStep.SIGN_APK,
InstallStep.INSTALL_APK,
).map {
it to InstallStepData(it.nameResId, InstallStatus.QUEUED)
}
val supportedVersion = preferences.version
val arch = Build.SUPPORTED_ABIS.first()
val cacheDir = externalCacheDir
val discordCacheDir = externalCacheDir.resolve(supportedVersion)
val patchedDir = discordCacheDir.resolve("patched").also { it.deleteRecursively() }
clearOldCache(supportedVersion.toInt())
uninstallNewAliucord(supportedVersion.toInt())
// Download base.apk
val baseApkFile = step(InstallStep.DL_BASE_APK) {
discordCacheDir.resolve("base-${supportedVersion}.apk").let { file ->
if (file.exists()) {
cached = true
} else {
downloadManager.downloadDiscordApk(supportedVersion, file)
}
file.copyTo(
patchedDir.resolve(file.name),
true
)
}
}
// Download the native libraries split
val libsApkFile = step(InstallStep.DL_LIBS_APK) {
val libArch = arch.replace("-v", "_v")
discordCacheDir.resolve("config.$libArch-${supportedVersion}.apk").let { file ->
if (file.exists()) {
cached = true
} else downloadManager.downloadSplit(
version = supportedVersion,
split = "config.$libArch",
out = file
)
file.copyTo(
patchedDir.resolve(file.name),
true
)
}
}
// Download the locale split
val localeApkFile = step(InstallStep.DL_LANG_APK) {
discordCacheDir.resolve("config.en-${supportedVersion}.apk").let { file ->
if (file.exists()) {
cached = true
} else downloadManager.downloadSplit(
version = supportedVersion,
split = "config.en",
out = file
)
file.copyTo(
patchedDir.resolve(file.name),
true
)
}
}
// Download the drawables split
val resApkFile = step(InstallStep.DL_RESC_APK) {
// TODO: download the appropriate dpi res apk
discordCacheDir.resolve("config.xxhdpi-${supportedVersion}.apk").let { file ->
if (file.exists()) {
cached = true
} else downloadManager.downloadSplit(
version = supportedVersion,
split = "config.xxhdpi",
out = file
)
file.copyTo(
patchedDir.resolve(file.name),
true
)
}
}
// Download hermes & c++ runtime lib
val (hermesLibrary, cppRuntimeLibrary) = step(InstallStep.DL_HERMES) {
// Fetch gh releases for Aliucord/Hermes
val latestHermesRelease = githubRepository.getHermesRelease().getOrThrow()
// Download the hermes-release.aar file to replace in the apk
val hermes = cacheDir.resolve("hermes-release-${latestHermesRelease.tagName}.aar").also { file ->
if (file.exists()) {
cached = true
return@also
}
latestHermesRelease.assets
.find { it.name == "hermes-release.aar" }!!.browserDownloadUrl
.also { downloadManager.download(it, file) }
}
// Download the hermes-cppruntime-release.aar file to replace in the apk
val cppRuntime = if (!preferences.hermesReplaceLibCpp) null else {
cacheDir.resolve("hermes-cppruntime-release-${latestHermesRelease.tagName}.aar").also { file ->
if (file.exists()) return@also
cached = false
latestHermesRelease.assets
.find { it.name == "hermes-cppruntime-release.aar" }!!.browserDownloadUrl
.also { downloadManager.download(it, file) }
}
}
hermes to cppRuntime
}
// Download Aliucord Native lib
val aliucordDexFile = step(InstallStep.DL_ALIUNATIVE) {
// Fetch the gh releases for Aliucord/AliucordNative
val latestAliucordNativeRelease = githubRepository.getAliucordNativeRelease().getOrThrow()
// Download the Aliucord classes.dex file to add to the apk
cacheDir.resolve("aliucord-${latestAliucordNativeRelease.tagName}.dex").also { file ->
if (file.exists()) {
cached = true
return@also
}
latestAliucordNativeRelease.assets
.find { it.name == "classes.dex" }!!.browserDownloadUrl
.also { downloadManager.download(it, file) }
}
}
// Download AliucordRN bootstrap
val aliucordBootstrap = step(InstallStep.DL_BOOTSTRAP) {
// Fetch latest commit for bootstrap.js
val commit = githubRepository.getLatestBootstrapCommit().getOrThrow()
cacheDir.resolve("bootstrap-$commit.js").also {
if (it.exists()) {
cached = true
return@also
}
downloadManager.downloadBootstrap(it)
}
}
val apks = arrayOf(baseApkFile, libsApkFile, localeApkFile, resApkFile)
// Replace app icons
if (preferences.replaceIcon) {
step(InstallStep.PATCH_APP_ICON) {
ZipWriter(baseApkFile, true).use { baseApk ->
val mipmaps = arrayOf("mipmap-xhdpi-v4", "mipmap-xxhdpi-v4", "mipmap-xxxhdpi-v4")
val icons = arrayOf("ic_logo_foreground.png", "ic_logo_square.png", "ic_logo_foreground.png")
for (icon in icons) {
val newIcon = application.assets.open("icons/$icon")
.use { it.readBytes() }
for (mipmap in mipmaps) {
val path = "res/$mipmap/$icon"
baseApk.deleteEntry(path)
baseApk.writeEntry(path, newIcon)
}
}
}
}
}
// Patch manifests
step(InstallStep.PATCH_MANIFEST) {
apks.forEach { apk ->
val manifest = ZipReader(apk)
.use { zip -> zip.openEntry("AndroidManifest.xml")?.read() }
?: throw IllegalStateException("No manifest in ${apk.name}")
ZipWriter(apk, true).use { zip ->
val patchedManifestBytes = if (apk == baseApkFile) {
ManifestPatcher.patchManifest(
manifestBytes = manifest,
packageName = preferences.packageName,
appName = preferences.appName,
debuggable = preferences.debuggable,
)
} else {
ManifestPatcher.renamePackage(manifest, preferences.packageName)
}
zip.deleteEntry("AndroidManifest.xml", apk == libsApkFile) // Preserve alignment in libs apk
zip.writeEntry("AndroidManifest.xml", patchedManifestBytes)
}
}
}
// Re-order dex files
step(InstallStep.PATCH_DEX) {
val (dexCount, firstDexBytes) = ZipReader(baseApkFile).use { zip ->
Pair(
// Find the amount of .dex files in apk
zip.entryNames.count { it.endsWith(".dex") },
// Get the first classes.dex bytes
zip.openEntry("classes.dex")?.read()
?: throw IllegalStateException("No classes.dex in base apk")
)
}
ZipWriter(baseApkFile, true).use { zip ->
// Move first classes.dex to the dex file count + 1 to make place for Aliucord's .dex
zip.deleteEntry("classes.dex")
zip.writeEntry("classes${dexCount + 1}.dex", firstDexBytes)
// Add Aliucord's .dex and make it load first by being the first .dex
zip.writeEntry("classes.dex", aliucordDexFile.readBytes())
// Add bootstrap
zip.writeEntry("bootstrap.js", aliucordBootstrap.readBytes(), ZipCompression.NONE)
}
}
// Replace libs
step(InstallStep.PATCH_LIBS) {
ZipWriter(libsApkFile, true).use { libsApk ->
// Process the hermes and cpp runtime library
for (libFile in arrayOf(hermesLibrary, cppRuntimeLibrary)) {
libFile ?: continue
// Map .aar to the embedded .so inside
val binaryName = with(libFile.name) {
when {
startsWith("hermes-release") -> "libhermes.so"
startsWith("hermes-cppruntime-release") -> "libc++_shared.so"
else -> throw Error("Unable to map $this to embedded .so")
}
}
// Read the embedded .so inside the .aar library
val libBytes = ZipReader(libFile).use { libZip ->
libZip.openEntry("jni/$arch/$binaryName")?.read()
?: throw IllegalStateException("Failed to read jni/$arch/$binaryName from ${libFile.name}")
}
// Delete the old binary and add the new one instead
libsApk.deleteEntry("lib/$arch/$binaryName", true)
libsApk.writeEntry("lib/$arch/$binaryName", libBytes, ZipCompression.NONE, 4096)
}
}
}
step(InstallStep.SIGN_APK) {
// Align resources.arsc due to targeting api 30 for silent install
if (Build.VERSION.SDK_INT >= 31) {
for (file in apks) {
val bytes = ZipReader(file).use {
if (it.entryNames.contains("resources.arsc")) {
it.openEntry("resources.arsc")?.read()
} else {
null
}
} ?: continue
ZipWriter(file, true).use {
it.deleteEntry("resources.arsc", true)
it.writeEntry("resources.arsc", bytes, ZipCompression.NONE, 4096)
}
}
}
apks.forEach(Signer::signApk)
}
step(InstallStep.INSTALL_APK) {
application.installApks(silent = !preferences.devMode, *apks)
if (!preferences.keepPatchedApks) {
patchedDir.deleteRecursively()
}
}
}
private suspend fun installKotlin() {
steps += listOfNotNull(
InstallStep.FETCH_KT_VERSION,
@ -645,7 +345,6 @@ class InstallViewModel(
}
}
@OptIn(ExperimentalTime::class)
private inline fun <T> step(step: InstallStep, block: InstallStepData.() -> T): T {
steps[step]!!.status = InstallStatus.ONGOING
currentStep = step
@ -691,16 +390,6 @@ class InstallViewModel(
@StringRes
val nameResId: Int
) {
// React Native
DL_BASE_APK(InstallStepGroup.APK_DL, R.string.install_step_dl_apk_base),
DL_LIBS_APK(InstallStepGroup.APK_DL, R.string.install_step_dl_apk_lib),
DL_LANG_APK(InstallStepGroup.APK_DL, R.string.install_step_dl_apk_locale),
DL_RESC_APK(InstallStepGroup.APK_DL, R.string.install_step_dl_apk_resource),
DL_HERMES(InstallStepGroup.LIB_DL, R.string.install_step_dl_lib_hermes),
DL_ALIUNATIVE(InstallStepGroup.LIB_DL, R.string.install_step_dl_lib_aliunative),
DL_BOOTSTRAP(InstallStepGroup.LIB_DL, R.string.install_step_dl_bootstrap),
// Kotlin
FETCH_KT_VERSION(InstallStepGroup.APK_DL, R.string.install_step_fetch_kt_version),
DL_KT_APK(InstallStepGroup.APK_DL, R.string.install_step_dl_kt_apk),

View file

@ -119,7 +119,7 @@
<string name="install_group_apk_dl">Download APKs</string>
<string name="install_group_lib_dl">Download Libraries</string>
<string name="install_group_patch">Patch APKs</string>
<string name="install_group_install">Install</string>
<string name="install_group_install">Install APK</string>
<string name="install_step_patch_icons">Patching app icons</string>
<string name="install_step_patch_manifests">Patching apk manifests</string>

View file

@ -29,7 +29,7 @@ accompanist-systemUiController = { module = "com.google.accompanist:accompanist-
androidx-activity = { module = "androidx.activity:activity-compose", version.ref = "androidx-activity" }
androidx-core = { module = "androidx.core:core-ktx", version.ref = "androidx-core" }
androidx-splashscreen = { module = "androidx.core:core-splashscreen", version.ref = "androidx-splashscreen" }
androidx-paging = "androidx.paging:paging-compose:3.3.0-alpha02" # TODO: remove paging
androidx-paging = "androidx.paging:paging-compose:1.0.0-alpha17" # TODO: remove paging
# Compose
compose-runtime = { module = "androidx.compose.runtime:runtime", version.ref = "compose" }
@ -37,6 +37,7 @@ compose-foundation = { module = "androidx.compose.foundation:foundation", versio
compose-animations = { module = "androidx.compose.animation:animation-graphics", version.ref = "compose" }
compose-ui = { module = "androidx.compose.ui:ui", version.ref = "compose" }
compose-ui-tooling = { module = "androidx.compose.ui:ui-tooling", version.ref = "compose" }
compose-icons = { module = "androidx.compose.material:material-icons-extended", version.ref = "compose" }
compose-material3 = { module = "androidx.compose.material3:material3", version.ref = "compose-material3" }
# Compose debug tooling
@ -81,6 +82,7 @@ compose = [
"compose-runtime",
"compose-ui",
"compose-foundation",
"compose-icons",
"compose-material3",
"compose-animations",
]