mirror of
https://github.com/revanced/revanced-manager.git
synced 2025-05-01 14:34:24 +02:00
Merge branch 'compose-dev' into compose/downloader-system
This commit is contained in:
commit
ce38745dd3
2
.github/workflows/pr-build.yml
vendored
2
.github/workflows/pr-build.yml
vendored
@ -24,7 +24,7 @@ jobs:
|
|||||||
distribution: 'temurin'
|
distribution: 'temurin'
|
||||||
|
|
||||||
- name: Set up Gradle
|
- name: Set up Gradle
|
||||||
uses: gradle/actions/setup-gradle@v3
|
uses: gradle/actions/setup-gradle@v4
|
||||||
|
|
||||||
- name: Build with Gradle
|
- name: Build with Gradle
|
||||||
env:
|
env:
|
||||||
|
2
.github/workflows/release-build.yml
vendored
2
.github/workflows/release-build.yml
vendored
@ -21,7 +21,7 @@ jobs:
|
|||||||
distribution: 'temurin'
|
distribution: 'temurin'
|
||||||
|
|
||||||
- name: Set up Gradle
|
- name: Set up Gradle
|
||||||
uses: gradle/actions/setup-gradle@v3
|
uses: gradle/actions/setup-gradle@v4
|
||||||
|
|
||||||
- name: Build with Gradle
|
- name: Build with Gradle
|
||||||
env:
|
env:
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
"formatVersion": 1,
|
"formatVersion": 1,
|
||||||
"database": {
|
"database": {
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"identityHash": "ab113134d89f2c5e412e87775510b327",
|
"identityHash": "393045599eb516fc7ef99f142485e9a2",
|
||||||
"entities": [
|
"entities": [
|
||||||
{
|
{
|
||||||
"tableName": "patch_bundles",
|
"tableName": "patch_bundles",
|
||||||
@ -51,17 +51,7 @@
|
|||||||
"uid"
|
"uid"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"indices": [
|
"indices": [],
|
||||||
{
|
|
||||||
"name": "index_patch_bundles_name",
|
|
||||||
"unique": true,
|
|
||||||
"columnNames": [
|
|
||||||
"name"
|
|
||||||
],
|
|
||||||
"orders": [],
|
|
||||||
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_patch_bundles_name` ON `${TABLE_NAME}` (`name`)"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"foreignKeys": []
|
"foreignKeys": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -433,7 +423,7 @@
|
|||||||
"views": [],
|
"views": [],
|
||||||
"setupQueries": [
|
"setupQueries": [
|
||||||
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
||||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'ab113134d89f2c5e412e87775510b327')"
|
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '393045599eb516fc7ef99f142485e9a2')"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,10 +1,11 @@
|
|||||||
package app.revanced.manager.data.platform
|
package app.revanced.manager.data.platform
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.pm.PackageManager
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Environment
|
import android.os.Environment
|
||||||
import android.Manifest
|
|
||||||
import android.content.pm.PackageManager
|
|
||||||
import androidx.activity.result.contract.ActivityResultContract
|
import androidx.activity.result.contract.ActivityResultContract
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import app.revanced.manager.util.RequestManageStorageContract
|
import app.revanced.manager.util.RequestManageStorageContract
|
||||||
@ -16,7 +17,7 @@ class Filesystem(private val app: Application) {
|
|||||||
* A directory that gets cleared when the app restarts.
|
* A directory that gets cleared when the app restarts.
|
||||||
* Do not store paths to this directory in a parcel.
|
* Do not store paths to this directory in a parcel.
|
||||||
*/
|
*/
|
||||||
val tempDir = app.cacheDir.resolve("ephemeral").apply {
|
val tempDir = app.getDir("ephemeral", Context.MODE_PRIVATE).apply {
|
||||||
deleteRecursively()
|
deleteRecursively()
|
||||||
mkdirs()
|
mkdirs()
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ sealed class Source {
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun from(value: String) = when(value) {
|
fun from(value: String) = when (value) {
|
||||||
Local.SENTINEL -> Local
|
Local.SENTINEL -> Local
|
||||||
API.SENTINEL -> API
|
API.SENTINEL -> API
|
||||||
else -> Remote(Url(value))
|
else -> Remote(Url(value))
|
||||||
@ -34,7 +34,7 @@ data class VersionInfo(
|
|||||||
@ColumnInfo(name = "integrations_version") val integrations: String? = null,
|
@ColumnInfo(name = "integrations_version") val integrations: String? = null,
|
||||||
)
|
)
|
||||||
|
|
||||||
@Entity(tableName = "patch_bundles", indices = [Index(value = ["name"], unique = true)])
|
@Entity(tableName = "patch_bundles")
|
||||||
data class PatchBundleEntity(
|
data class PatchBundleEntity(
|
||||||
@PrimaryKey val uid: Int,
|
@PrimaryKey val uid: Int,
|
||||||
@ColumnInfo(name = "name") val name: String,
|
@ColumnInfo(name = "name") val name: String,
|
||||||
|
@ -21,6 +21,7 @@ class PreferencesManager(
|
|||||||
|
|
||||||
val firstLaunch = booleanPreference("first_launch", true)
|
val firstLaunch = booleanPreference("first_launch", true)
|
||||||
val managerAutoUpdates = booleanPreference("manager_auto_updates", false)
|
val managerAutoUpdates = booleanPreference("manager_auto_updates", false)
|
||||||
|
val showManagerUpdateDialogOnLaunch = booleanPreference("show_manager_update_dialog_on_launch", true)
|
||||||
|
|
||||||
val disablePatchVersionCompatCheck = booleanPreference("disable_patch_version_compatibility_check", false)
|
val disablePatchVersionCompatCheck = booleanPreference("disable_patch_version_compatibility_check", false)
|
||||||
val disableSelectionWarning = booleanPreference("disable_selection_warning", false)
|
val disableSelectionWarning = booleanPreference("disable_selection_warning", false)
|
||||||
|
@ -63,7 +63,7 @@ class EditorContext(private val prefs: MutablePreferences) {
|
|||||||
|
|
||||||
abstract class Preference<T>(
|
abstract class Preference<T>(
|
||||||
private val dataStore: DataStore<Preferences>,
|
private val dataStore: DataStore<Preferences>,
|
||||||
protected val default: T
|
val default: T
|
||||||
) {
|
) {
|
||||||
internal abstract fun Preferences.read(): T
|
internal abstract fun Preferences.read(): T
|
||||||
internal abstract fun MutablePreferences.write(value: T)
|
internal abstract fun MutablePreferences.write(value: T)
|
||||||
|
@ -4,7 +4,7 @@ import android.content.Context
|
|||||||
import app.revanced.manager.patcher.LibraryResolver
|
import app.revanced.manager.patcher.LibraryResolver
|
||||||
import android.os.Build.SUPPORTED_ABIS as DEVICE_ABIS
|
import android.os.Build.SUPPORTED_ABIS as DEVICE_ABIS
|
||||||
object Aapt : LibraryResolver() {
|
object Aapt : LibraryResolver() {
|
||||||
private val WORKING_ABIS = setOf("arm64-v8a", "x86", "x86_64")
|
private val WORKING_ABIS = setOf("arm64-v8a", "x86", "x86_64", "armeabi-v7a")
|
||||||
|
|
||||||
fun supportsDevice() = (DEVICE_ABIS intersect WORKING_ABIS).isNotEmpty()
|
fun supportsDevice() = (DEVICE_ABIS intersect WORKING_ABIS).isNotEmpty()
|
||||||
|
|
||||||
|
@ -234,6 +234,9 @@ class PatcherWorker(
|
|||||||
Result.failure()
|
Result.failure()
|
||||||
} finally {
|
} finally {
|
||||||
patchedApk.delete()
|
patchedApk.delete()
|
||||||
|
if (args.input is SelectedApp.Local && args.input.temporary) {
|
||||||
|
args.input.file.delete()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ fun AlertDialogExtended(
|
|||||||
) {
|
) {
|
||||||
Column(modifier = Modifier.padding(vertical = 24.dp)) {
|
Column(modifier = Modifier.padding(vertical = 24.dp)) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.padding(horizontal = 24.dp)
|
modifier = Modifier.padding(horizontal = 24.dp).fillMaxWidth()
|
||||||
) {
|
) {
|
||||||
icon?.let {
|
icon?.let {
|
||||||
ContentStyle(color = iconContentColor) {
|
ContentStyle(color = iconContentColor) {
|
||||||
|
@ -33,11 +33,9 @@ fun AppIcon(
|
|||||||
Image(
|
Image(
|
||||||
image,
|
image,
|
||||||
contentDescription,
|
contentDescription,
|
||||||
Modifier.placeholder(visible = showPlaceHolder, color = MaterialTheme.colorScheme.inverseOnSurface, shape = RoundedCornerShape(100)).then(modifier),
|
modifier,
|
||||||
colorFilter = colorFilter
|
colorFilter = colorFilter
|
||||||
)
|
)
|
||||||
|
|
||||||
showPlaceHolder = false
|
|
||||||
} else {
|
} else {
|
||||||
AsyncImage(
|
AsyncImage(
|
||||||
packageInfo,
|
packageInfo,
|
||||||
|
@ -13,10 +13,16 @@ import androidx.compose.ui.res.stringResource
|
|||||||
import app.revanced.manager.R
|
import app.revanced.manager.R
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ArrowButton(modifier: Modifier = Modifier, expanded: Boolean, onClick: (() -> Unit)?) {
|
fun ArrowButton(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
expanded: Boolean,
|
||||||
|
onClick: (() -> Unit)?,
|
||||||
|
rotationInitial: Float = 0f,
|
||||||
|
rotationFinal: Float = 180f
|
||||||
|
) {
|
||||||
val description = if (expanded) R.string.collapse_content else R.string.expand_content
|
val description = if (expanded) R.string.collapse_content else R.string.expand_content
|
||||||
val rotation by animateFloatAsState(
|
val rotation by animateFloatAsState(
|
||||||
targetValue = if (expanded) 0f else 180f,
|
targetValue = if (expanded) rotationInitial else rotationFinal,
|
||||||
label = "rotation"
|
label = "rotation"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -0,0 +1,81 @@
|
|||||||
|
package app.revanced.manager.ui.component
|
||||||
|
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.outlined.Update
|
||||||
|
import androidx.compose.material3.*
|
||||||
|
import androidx.compose.runtime.*
|
||||||
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import app.revanced.manager.R
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
fun AvailableUpdateDialog(
|
||||||
|
onDismiss: () -> Unit,
|
||||||
|
onConfirm: () -> Unit,
|
||||||
|
setShowManagerUpdateDialogOnLaunch: (Boolean) -> Unit,
|
||||||
|
newVersion: String
|
||||||
|
) {
|
||||||
|
var dontShowAgain by rememberSaveable { mutableStateOf(false) }
|
||||||
|
val dismissDialog = {
|
||||||
|
setShowManagerUpdateDialogOnLaunch(!dontShowAgain)
|
||||||
|
onDismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
AlertDialogExtended(
|
||||||
|
onDismissRequest = dismissDialog,
|
||||||
|
confirmButton = {
|
||||||
|
TextButton(
|
||||||
|
onClick = {
|
||||||
|
dismissDialog()
|
||||||
|
onConfirm()
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Text(stringResource(R.string.show))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dismissButton = {
|
||||||
|
TextButton(
|
||||||
|
onClick = dismissDialog
|
||||||
|
) {
|
||||||
|
Text(stringResource(R.string.dismiss))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
icon = {
|
||||||
|
Icon(imageVector = Icons.Outlined.Update, contentDescription = null)
|
||||||
|
},
|
||||||
|
title = {
|
||||||
|
Text(stringResource(R.string.update_available))
|
||||||
|
},
|
||||||
|
text = {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(horizontal = 8.dp),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(4.dp),
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
modifier = Modifier.padding(horizontal = 16.dp),
|
||||||
|
text = stringResource(R.string.update_available_dialog_description, newVersion)
|
||||||
|
)
|
||||||
|
ListItem(
|
||||||
|
modifier = Modifier.clickable { dontShowAgain = !dontShowAgain },
|
||||||
|
headlineContent = {
|
||||||
|
Text(stringResource(R.string.never_show_again))
|
||||||
|
},
|
||||||
|
leadingContent = {
|
||||||
|
CompositionLocalProvider(LocalMinimumInteractiveComponentEnforcement provides false) {
|
||||||
|
Checkbox(checked = dontShowAgain, onCheckedChange = { dontShowAgain = it })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
textHorizontalPadding = PaddingValues(0.dp)
|
||||||
|
)
|
||||||
|
}
|
@ -46,11 +46,6 @@ fun BaseBundleDialog(
|
|||||||
ColumnWithScrollbar(
|
ColumnWithScrollbar(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(
|
|
||||||
start = 8.dp,
|
|
||||||
top = 8.dp,
|
|
||||||
end = 4.dp,
|
|
||||||
)
|
|
||||||
.then(modifier)
|
.then(modifier)
|
||||||
) {
|
) {
|
||||||
if (name != null) {
|
if (name != null) {
|
||||||
|
@ -572,7 +572,12 @@ private class ListOptionEditor<T : Serializable>(private val elementEditor: Opti
|
|||||||
|
|
||||||
ExtendedFloatingActionButton(
|
ExtendedFloatingActionButton(
|
||||||
text = { Text(stringResource(R.string.add)) },
|
text = { Text(stringResource(R.string.add)) },
|
||||||
icon = { Icon(Icons.Outlined.Add, null) },
|
icon = {
|
||||||
|
Icon(
|
||||||
|
Icons.Outlined.Add,
|
||||||
|
stringResource(R.string.add)
|
||||||
|
)
|
||||||
|
},
|
||||||
expanded = lazyListState.isScrollingUp,
|
expanded = lazyListState.isScrollingUp,
|
||||||
onClick = { items.add(Item(null)) }
|
onClick = { items.add(Item(null)) }
|
||||||
)
|
)
|
||||||
|
@ -6,44 +6,17 @@ import android.net.Uri
|
|||||||
import android.provider.Settings
|
import android.provider.Settings
|
||||||
import androidx.activity.compose.BackHandler
|
import androidx.activity.compose.BackHandler
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.layout.Column
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.foundation.pager.HorizontalPager
|
import androidx.compose.foundation.pager.HorizontalPager
|
||||||
import androidx.compose.foundation.pager.rememberPagerState
|
import androidx.compose.foundation.pager.rememberPagerState
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.Add
|
import androidx.compose.material.icons.filled.Add
|
||||||
import androidx.compose.material.icons.filled.BatteryAlert
|
import androidx.compose.material.icons.filled.BatteryAlert
|
||||||
import androidx.compose.material.icons.filled.Close
|
import androidx.compose.material.icons.filled.Close
|
||||||
import androidx.compose.material.icons.outlined.Apps
|
import androidx.compose.material.icons.outlined.*
|
||||||
import androidx.compose.material.icons.outlined.DeleteOutline
|
import androidx.compose.material3.*
|
||||||
import androidx.compose.material.icons.outlined.Download
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.material.icons.outlined.Refresh
|
|
||||||
import androidx.compose.material.icons.outlined.Settings
|
|
||||||
import androidx.compose.material.icons.outlined.Source
|
|
||||||
import androidx.compose.material.icons.outlined.Update
|
|
||||||
import androidx.compose.material.icons.outlined.WarningAmber
|
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
|
||||||
import androidx.compose.material3.FloatingActionButton
|
|
||||||
import androidx.compose.material3.Icon
|
|
||||||
import androidx.compose.material3.IconButton
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.material3.Scaffold
|
|
||||||
import androidx.compose.material3.Tab
|
|
||||||
import androidx.compose.material3.TabRow
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.material3.TextButton
|
|
||||||
import androidx.compose.material3.surfaceColorAtElevation
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
|
||||||
import androidx.compose.runtime.derivedStateOf
|
|
||||||
import androidx.compose.runtime.getValue
|
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import androidx.compose.runtime.setValue
|
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
@ -56,6 +29,7 @@ import app.revanced.manager.domain.bundles.PatchBundleSource.Extensions.isDefaul
|
|||||||
import app.revanced.manager.patcher.aapt.Aapt
|
import app.revanced.manager.patcher.aapt.Aapt
|
||||||
import app.revanced.manager.ui.component.AppTopBar
|
import app.revanced.manager.ui.component.AppTopBar
|
||||||
import app.revanced.manager.ui.component.AutoUpdatesDialog
|
import app.revanced.manager.ui.component.AutoUpdatesDialog
|
||||||
|
import app.revanced.manager.ui.component.AvailableUpdateDialog
|
||||||
import app.revanced.manager.ui.component.NotificationCard
|
import app.revanced.manager.ui.component.NotificationCard
|
||||||
import app.revanced.manager.ui.component.bundle.BundleItem
|
import app.revanced.manager.ui.component.bundle.BundleItem
|
||||||
import app.revanced.manager.ui.component.bundle.BundleTopBar
|
import app.revanced.manager.ui.component.bundle.BundleTopBar
|
||||||
@ -118,6 +92,20 @@ fun DashboardScreen(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var showDialog by rememberSaveable { mutableStateOf(vm.prefs.showManagerUpdateDialogOnLaunch.getBlocking()) }
|
||||||
|
val availableUpdate by remember {
|
||||||
|
derivedStateOf { vm.updatedManagerVersion.takeIf { showDialog } }
|
||||||
|
}
|
||||||
|
|
||||||
|
availableUpdate?.let { version ->
|
||||||
|
AvailableUpdateDialog(
|
||||||
|
onDismiss = { showDialog = false },
|
||||||
|
setShowManagerUpdateDialogOnLaunch = vm::setShowManagerUpdateDialogOnLaunch,
|
||||||
|
onConfirm = onUpdateClick,
|
||||||
|
newVersion = version
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {
|
topBar = {
|
||||||
if (bundlesSelectable) {
|
if (bundlesSelectable) {
|
||||||
@ -159,6 +147,23 @@ fun DashboardScreen(
|
|||||||
AppTopBar(
|
AppTopBar(
|
||||||
title = stringResource(R.string.app_name),
|
title = stringResource(R.string.app_name),
|
||||||
actions = {
|
actions = {
|
||||||
|
if (!vm.updatedManagerVersion.isNullOrEmpty()) {
|
||||||
|
IconButton(
|
||||||
|
onClick = onUpdateClick,
|
||||||
|
) {
|
||||||
|
BadgedBox(
|
||||||
|
badge = {
|
||||||
|
Badge(
|
||||||
|
// A size value above 6.dp forces the Badge icon to be closer to the center, fixing a clipping issue
|
||||||
|
modifier = Modifier.size(7.dp),
|
||||||
|
containerColor = MaterialTheme.colorScheme.primary,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Icon(Icons.Outlined.Update, stringResource(R.string.update))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
IconButton(onClick = onSettingsClick) {
|
IconButton(onClick = onSettingsClick) {
|
||||||
Icon(Icons.Outlined.Settings, stringResource(R.string.settings))
|
Icon(Icons.Outlined.Settings, stringResource(R.string.settings))
|
||||||
}
|
}
|
||||||
@ -236,22 +241,6 @@ fun DashboardScreen(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else null,
|
} else null,
|
||||||
vm.updatedManagerVersion?.let {
|
|
||||||
{
|
|
||||||
NotificationCard(
|
|
||||||
text = stringResource(R.string.update_available_dialog_description, it),
|
|
||||||
icon = Icons.Outlined.Update,
|
|
||||||
actions = {
|
|
||||||
TextButton(onClick = vm::dismissUpdateDialog) {
|
|
||||||
Text(stringResource(R.string.dismiss))
|
|
||||||
}
|
|
||||||
TextButton(onClick = onUpdateClick) {
|
|
||||||
Text(stringResource(R.string.show))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
if (showNewDownloaderPluginsNotification) {
|
if (showNewDownloaderPluginsNotification) {
|
||||||
{
|
{
|
||||||
NotificationCard(
|
NotificationCard(
|
||||||
|
@ -2,12 +2,7 @@ package app.revanced.manager.ui.screen
|
|||||||
|
|
||||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.layout.Column
|
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.foundation.lazy.LazyListScope
|
import androidx.compose.foundation.lazy.LazyListScope
|
||||||
import androidx.compose.foundation.lazy.LazyListState
|
import androidx.compose.foundation.lazy.LazyListState
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
@ -15,28 +10,8 @@ import androidx.compose.foundation.pager.HorizontalPager
|
|||||||
import androidx.compose.foundation.pager.rememberPagerState
|
import androidx.compose.foundation.pager.rememberPagerState
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.automirrored.outlined.HelpOutline
|
import androidx.compose.material.icons.automirrored.outlined.HelpOutline
|
||||||
import androidx.compose.material.icons.outlined.FilterList
|
import androidx.compose.material.icons.outlined.*
|
||||||
import androidx.compose.material.icons.outlined.Restore
|
import androidx.compose.material3.*
|
||||||
import androidx.compose.material.icons.outlined.Save
|
|
||||||
import androidx.compose.material.icons.outlined.Search
|
|
||||||
import androidx.compose.material.icons.outlined.Settings
|
|
||||||
import androidx.compose.material.icons.outlined.WarningAmber
|
|
||||||
import androidx.compose.material3.AlertDialog
|
|
||||||
import androidx.compose.material3.Checkbox
|
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
|
||||||
import androidx.compose.material3.ExtendedFloatingActionButton
|
|
||||||
import androidx.compose.material3.FilterChip
|
|
||||||
import androidx.compose.material3.Icon
|
|
||||||
import androidx.compose.material3.IconButton
|
|
||||||
import androidx.compose.material3.ListItem
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.material3.ModalBottomSheet
|
|
||||||
import androidx.compose.material3.Scaffold
|
|
||||||
import androidx.compose.material3.ScrollableTabRow
|
|
||||||
import androidx.compose.material3.Tab
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.material3.TextButton
|
|
||||||
import androidx.compose.material3.surfaceColorAtElevation
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.derivedStateOf
|
import androidx.compose.runtime.derivedStateOf
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
@ -57,8 +32,8 @@ import app.revanced.manager.R
|
|||||||
import app.revanced.manager.patcher.patch.Option
|
import app.revanced.manager.patcher.patch.Option
|
||||||
import app.revanced.manager.patcher.patch.PatchInfo
|
import app.revanced.manager.patcher.patch.PatchInfo
|
||||||
import app.revanced.manager.ui.component.AppTopBar
|
import app.revanced.manager.ui.component.AppTopBar
|
||||||
import app.revanced.manager.ui.component.SafeguardDialog
|
|
||||||
import app.revanced.manager.ui.component.LazyColumnWithScrollbar
|
import app.revanced.manager.ui.component.LazyColumnWithScrollbar
|
||||||
|
import app.revanced.manager.ui.component.SafeguardDialog
|
||||||
import app.revanced.manager.ui.component.SearchView
|
import app.revanced.manager.ui.component.SearchView
|
||||||
import app.revanced.manager.ui.component.patches.OptionItem
|
import app.revanced.manager.ui.component.patches.OptionItem
|
||||||
import app.revanced.manager.ui.viewmodel.PatchesSelectorViewModel
|
import app.revanced.manager.ui.viewmodel.PatchesSelectorViewModel
|
||||||
@ -94,6 +69,21 @@ fun PatchesSelectorScreen(
|
|||||||
derivedStateOf { vm.selectionIsValid(bundles) }
|
derivedStateOf { vm.selectionIsValid(bundles) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val availablePatchCount by remember {
|
||||||
|
derivedStateOf {
|
||||||
|
bundles.sumOf { it.patchCount }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val defaultPatchSelectionCount by vm.defaultSelectionCount
|
||||||
|
.collectAsStateWithLifecycle(initialValue = 0)
|
||||||
|
|
||||||
|
val selectedPatchCount by remember {
|
||||||
|
derivedStateOf {
|
||||||
|
vm.customPatchSelection?.values?.sumOf { it.size } ?: defaultPatchSelectionCount
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val patchLazyListStates = remember(bundles) { List(bundles.size) { LazyListState() } }
|
val patchLazyListStates = remember(bundles) { List(bundles.size) { LazyListState() } }
|
||||||
|
|
||||||
if (showBottomSheet) {
|
if (showBottomSheet) {
|
||||||
@ -142,12 +132,21 @@ fun PatchesSelectorScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: properly handle appVersion == null
|
||||||
if (vm.compatibleVersions.isNotEmpty() && vm.appVersion != null)
|
if (vm.compatibleVersions.isNotEmpty() && vm.appVersion != null)
|
||||||
UnsupportedDialog(
|
UnsupportedPatchDialog(
|
||||||
appVersion = vm.appVersion,
|
appVersion = vm.appVersion,
|
||||||
supportedVersions = vm.compatibleVersions,
|
supportedVersions = vm.compatibleVersions,
|
||||||
onDismissRequest = vm::dismissDialogs
|
onDismissRequest = vm::dismissDialogs
|
||||||
)
|
)
|
||||||
|
var showUnsupportedPatchesDialog by rememberSaveable {
|
||||||
|
mutableStateOf(false)
|
||||||
|
}
|
||||||
|
if (showUnsupportedPatchesDialog && vm.appVersion != null)
|
||||||
|
UnsupportedPatchesDialog(
|
||||||
|
appVersion = vm.appVersion,
|
||||||
|
onDismissRequest = { showUnsupportedPatchesDialog = false }
|
||||||
|
)
|
||||||
|
|
||||||
vm.optionsDialog?.let { (bundle, patch) ->
|
vm.optionsDialog?.let { (bundle, patch) ->
|
||||||
OptionsDialog(
|
OptionsDialog(
|
||||||
@ -165,7 +164,7 @@ fun PatchesSelectorScreen(
|
|||||||
if (showSelectionWarning) {
|
if (showSelectionWarning) {
|
||||||
SelectionWarningDialog(onDismiss = { showSelectionWarning = false })
|
SelectionWarningDialog(onDismiss = { showSelectionWarning = false })
|
||||||
}
|
}
|
||||||
vm.pendingUniversalPatchAction?.let {
|
vm.pendingUniversalPatchAction?.let {
|
||||||
UniversalPatchWarningDialog(
|
UniversalPatchWarningDialog(
|
||||||
onCancel = vm::dismissUniversalPatchWarning,
|
onCancel = vm::dismissUniversalPatchWarning,
|
||||||
onConfirm = vm::confirmUniversalPatchWarning
|
onConfirm = vm::confirmUniversalPatchWarning
|
||||||
@ -200,12 +199,20 @@ fun PatchesSelectorScreen(
|
|||||||
patch
|
patch
|
||||||
),
|
),
|
||||||
onToggle = {
|
onToggle = {
|
||||||
if (vm.selectionWarningEnabled) {
|
when {
|
||||||
showSelectionWarning = true
|
// Open unsupported dialog if the patch is not supported
|
||||||
} else if (vm.universalPatchWarningEnabled && patch.compatiblePackages == null) {
|
!supported -> vm.openUnsupportedDialog(patch)
|
||||||
vm.pendingUniversalPatchAction = { vm.togglePatch(uid, patch) }
|
|
||||||
} else {
|
// Show selection warning if enabled
|
||||||
vm.togglePatch(uid, patch)
|
vm.selectionWarningEnabled -> showSelectionWarning = true
|
||||||
|
|
||||||
|
// Set pending universal patch action if the universal patch warning is enabled and there are no compatible packages
|
||||||
|
vm.universalPatchWarningEnabled && patch.compatiblePackages == null -> {
|
||||||
|
vm.pendingUniversalPatchAction = { vm.togglePatch(uid, patch) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toggle the patch otherwise
|
||||||
|
else -> vm.togglePatch(uid, patch)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
supported = supported
|
supported = supported
|
||||||
@ -256,7 +263,7 @@ fun PatchesSelectorScreen(
|
|||||||
) {
|
) {
|
||||||
ListHeader(
|
ListHeader(
|
||||||
title = stringResource(R.string.unsupported_patches),
|
title = stringResource(R.string.unsupported_patches),
|
||||||
onHelpClick = { vm.openUnsupportedDialog(bundle.unsupported) }
|
onHelpClick = { showUnsupportedPatchesDialog = true }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -266,7 +273,11 @@ fun PatchesSelectorScreen(
|
|||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {
|
topBar = {
|
||||||
AppTopBar(
|
AppTopBar(
|
||||||
title = stringResource(R.string.select_patches),
|
title = stringResource(
|
||||||
|
R.string.patches_selected,
|
||||||
|
selectedPatchCount,
|
||||||
|
availablePatchCount
|
||||||
|
),
|
||||||
onBackClick = onBackClick,
|
onBackClick = onBackClick,
|
||||||
actions = {
|
actions = {
|
||||||
IconButton(onClick = vm::reset) {
|
IconButton(onClick = vm::reset) {
|
||||||
@ -290,8 +301,14 @@ fun PatchesSelectorScreen(
|
|||||||
|
|
||||||
ExtendedFloatingActionButton(
|
ExtendedFloatingActionButton(
|
||||||
text = { Text(stringResource(R.string.save)) },
|
text = { Text(stringResource(R.string.save)) },
|
||||||
icon = { Icon(Icons.Outlined.Save, null) },
|
icon = {
|
||||||
expanded = patchLazyListStates.getOrNull(pagerState.currentPage)?.isScrollingUp ?: true,
|
Icon(
|
||||||
|
Icons.Outlined.Save,
|
||||||
|
stringResource(R.string.save)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
expanded = patchLazyListStates.getOrNull(pagerState.currentPage)?.isScrollingUp
|
||||||
|
?: true,
|
||||||
onClick = {
|
onClick = {
|
||||||
// TODO: only allow this if all required options have been set.
|
// TODO: only allow this if all required options have been set.
|
||||||
onSave(vm.getCustomSelection(), vm.getOptions())
|
onSave(vm.getCustomSelection(), vm.getOptions())
|
||||||
@ -363,7 +380,7 @@ fun PatchesSelectorScreen(
|
|||||||
) {
|
) {
|
||||||
ListHeader(
|
ListHeader(
|
||||||
title = stringResource(R.string.unsupported_patches),
|
title = stringResource(R.string.unsupported_patches),
|
||||||
onHelpClick = { vm.openUnsupportedDialog(bundle.unsupported) }
|
onHelpClick = { showUnsupportedPatchesDialog = true }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -374,7 +391,7 @@ fun PatchesSelectorScreen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SelectionWarningDialog(onDismiss: () -> Unit) {
|
private fun SelectionWarningDialog(onDismiss: () -> Unit) {
|
||||||
SafeguardDialog(
|
SafeguardDialog(
|
||||||
onDismiss = onDismiss,
|
onDismiss = onDismiss,
|
||||||
title = R.string.warning,
|
title = R.string.warning,
|
||||||
@ -383,7 +400,7 @@ fun SelectionWarningDialog(onDismiss: () -> Unit) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun UniversalPatchWarningDialog(
|
private fun UniversalPatchWarningDialog(
|
||||||
onCancel: () -> Unit,
|
onCancel: () -> Unit,
|
||||||
onConfirm: () -> Unit
|
onConfirm: () -> Unit
|
||||||
) {
|
) {
|
||||||
@ -415,7 +432,7 @@ fun UniversalPatchWarningDialog(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun PatchItem(
|
private fun PatchItem(
|
||||||
patch: PatchInfo,
|
patch: PatchInfo,
|
||||||
onOptionsDialog: () -> Unit,
|
onOptionsDialog: () -> Unit,
|
||||||
selected: Boolean,
|
selected: Boolean,
|
||||||
@ -424,7 +441,7 @@ fun PatchItem(
|
|||||||
) = ListItem(
|
) = ListItem(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.let { if (!supported) it.alpha(0.5f) else it }
|
.let { if (!supported) it.alpha(0.5f) else it }
|
||||||
.clickable(enabled = supported, onClick = onToggle)
|
.clickable(onClick = onToggle)
|
||||||
.fillMaxSize(),
|
.fillMaxSize(),
|
||||||
leadingContent = {
|
leadingContent = {
|
||||||
Checkbox(
|
Checkbox(
|
||||||
@ -446,7 +463,7 @@ fun PatchItem(
|
|||||||
)
|
)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ListHeader(
|
private fun ListHeader(
|
||||||
title: String,
|
title: String,
|
||||||
onHelpClick: (() -> Unit)? = null
|
onHelpClick: (() -> Unit)? = null
|
||||||
) {
|
) {
|
||||||
@ -473,18 +490,46 @@ fun ListHeader(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun UnsupportedDialog(
|
private fun UnsupportedPatchesDialog(
|
||||||
appVersion: String,
|
appVersion: String,
|
||||||
supportedVersions: List<String>,
|
|
||||||
onDismissRequest: () -> Unit
|
onDismissRequest: () -> Unit
|
||||||
) = AlertDialog(
|
) = AlertDialog(
|
||||||
|
icon = {
|
||||||
|
Icon(Icons.Outlined.WarningAmber, null)
|
||||||
|
},
|
||||||
onDismissRequest = onDismissRequest,
|
onDismissRequest = onDismissRequest,
|
||||||
confirmButton = {
|
confirmButton = {
|
||||||
TextButton(onClick = onDismissRequest) {
|
TextButton(onClick = onDismissRequest) {
|
||||||
Text(stringResource(R.string.ok))
|
Text(stringResource(R.string.ok))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
title = { Text(stringResource(R.string.unsupported_app)) },
|
title = { Text(stringResource(R.string.unsupported_patches)) },
|
||||||
|
text = {
|
||||||
|
Text(
|
||||||
|
stringResource(
|
||||||
|
R.string.unsupported_patches_dialog,
|
||||||
|
appVersion
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun UnsupportedPatchDialog(
|
||||||
|
appVersion: String,
|
||||||
|
supportedVersions: List<String>,
|
||||||
|
onDismissRequest: () -> Unit
|
||||||
|
) = AlertDialog(
|
||||||
|
icon = {
|
||||||
|
Icon(Icons.Outlined.WarningAmber, null)
|
||||||
|
},
|
||||||
|
onDismissRequest = onDismissRequest,
|
||||||
|
confirmButton = {
|
||||||
|
TextButton(onClick = onDismissRequest) {
|
||||||
|
Text(stringResource(R.string.ok))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
title = { Text(stringResource(R.string.unsupported_patch)) },
|
||||||
text = {
|
text = {
|
||||||
Text(
|
Text(
|
||||||
stringResource(
|
stringResource(
|
||||||
@ -498,7 +543,7 @@ fun UnsupportedDialog(
|
|||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun OptionsDialog(
|
private fun OptionsDialog(
|
||||||
patch: PatchInfo,
|
patch: PatchInfo,
|
||||||
values: Map<String, Any?>?,
|
values: Map<String, Any?>?,
|
||||||
reset: () -> Unit,
|
reset: () -> Unit,
|
||||||
@ -535,8 +580,14 @@ fun OptionsDialog(
|
|||||||
if (values == null || !values.contains(key)) option.default else values[key]
|
if (values == null || !values.contains(key)) option.default else values[key]
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
OptionItem(option = option as Option<Any>, value = value, setValue = { set(key, it) })
|
OptionItem(
|
||||||
|
option = option as Option<Any>,
|
||||||
|
value = value,
|
||||||
|
setValue = {
|
||||||
|
set(key, it)
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,11 +69,6 @@ fun SelectedAppInfoScreen(
|
|||||||
patches.values.sumOf { it.size }
|
patches.values.sumOf { it.size }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val availablePatchCount by remember {
|
|
||||||
derivedStateOf {
|
|
||||||
bundles.sumOf { it.patchCount }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val navController =
|
val navController =
|
||||||
rememberNavController<SelectedAppInfoDestination>(startDestination = SelectedAppInfoDestination.Main)
|
rememberNavController<SelectedAppInfoDestination>(startDestination = SelectedAppInfoDestination.Main)
|
||||||
@ -111,7 +106,6 @@ fun SelectedAppInfoScreen(
|
|||||||
// navController.navigate(SelectedAppInfoDestination.VersionSelector)
|
// navController.navigate(SelectedAppInfoDestination.VersionSelector)
|
||||||
},
|
},
|
||||||
onBackClick = onBackClick,
|
onBackClick = onBackClick,
|
||||||
availablePatchCount = availablePatchCount,
|
|
||||||
selectedPatchCount = selectedPatchCount,
|
selectedPatchCount = selectedPatchCount,
|
||||||
packageName = packageName,
|
packageName = packageName,
|
||||||
version = version,
|
version = version,
|
||||||
@ -145,7 +139,6 @@ private fun SelectedAppInfoScreen(
|
|||||||
onPatchSelectorClick: () -> Unit,
|
onPatchSelectorClick: () -> Unit,
|
||||||
onVersionSelectorClick: () -> Unit,
|
onVersionSelectorClick: () -> Unit,
|
||||||
onBackClick: () -> Unit,
|
onBackClick: () -> Unit,
|
||||||
availablePatchCount: Int,
|
|
||||||
selectedPatchCount: Int,
|
selectedPatchCount: Int,
|
||||||
packageName: String,
|
packageName: String,
|
||||||
version: String?,
|
version: String?,
|
||||||
@ -161,7 +154,12 @@ private fun SelectedAppInfoScreen(
|
|||||||
floatingActionButton = {
|
floatingActionButton = {
|
||||||
ExtendedFloatingActionButton(
|
ExtendedFloatingActionButton(
|
||||||
text = { Text(stringResource(R.string.patch)) },
|
text = { Text(stringResource(R.string.patch)) },
|
||||||
icon = { Icon(Icons.Default.AutoFixHigh, null) },
|
icon = {
|
||||||
|
Icon(
|
||||||
|
Icons.Default.AutoFixHigh,
|
||||||
|
stringResource(R.string.patch)
|
||||||
|
)
|
||||||
|
},
|
||||||
onClick = onPatchClick
|
onClick = onPatchClick
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -173,13 +171,7 @@ private fun SelectedAppInfoScreen(
|
|||||||
) {
|
) {
|
||||||
AppInfo(packageInfo, placeholderLabel = packageName) {
|
AppInfo(packageInfo, placeholderLabel = packageName) {
|
||||||
Text(
|
Text(
|
||||||
version?.let {
|
version ?: stringResource(R.string.selected_app_meta_any_version),
|
||||||
stringResource(
|
|
||||||
R.string.selected_app_meta_version,
|
|
||||||
it,
|
|
||||||
availablePatchCount
|
|
||||||
)
|
|
||||||
} ?: stringResource(R.string.selected_app_meta_no_version, availablePatchCount),
|
|
||||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
)
|
)
|
||||||
|
@ -5,26 +5,13 @@ import android.os.Build
|
|||||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.layout.Column
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.outlined.Api
|
import androidx.compose.material.icons.outlined.Api
|
||||||
import androidx.compose.material3.AlertDialog
|
import androidx.compose.material.icons.outlined.Restore
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.*
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.material3.OutlinedTextField
|
|
||||||
import androidx.compose.material3.Scaffold
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.material3.TextButton
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.runtime.getValue
|
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import androidx.compose.runtime.setValue
|
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
@ -78,14 +65,18 @@ fun AdvancedSettingsScreen(
|
|||||||
var showApiUrlDialog by rememberSaveable { mutableStateOf(false) }
|
var showApiUrlDialog by rememberSaveable { mutableStateOf(false) }
|
||||||
|
|
||||||
if (showApiUrlDialog) {
|
if (showApiUrlDialog) {
|
||||||
APIUrlDialog(apiUrl) {
|
APIUrlDialog(
|
||||||
showApiUrlDialog = false
|
currentUrl = apiUrl,
|
||||||
it?.let(vm::setApiUrl)
|
defaultUrl = vm.prefs.api.default,
|
||||||
}
|
onSubmit = {
|
||||||
|
showApiUrlDialog = false
|
||||||
|
it?.let(vm::setApiUrl)
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
SettingsListItem(
|
SettingsListItem(
|
||||||
headlineContent = stringResource(R.string.api_url),
|
headlineContent = stringResource(R.string.api_url),
|
||||||
supportingContent = apiUrl,
|
supportingContent = stringResource(R.string.api_url_description),
|
||||||
modifier = Modifier.clickable {
|
modifier = Modifier.clickable {
|
||||||
showApiUrlDialog = true
|
showApiUrlDialog = true
|
||||||
}
|
}
|
||||||
@ -163,7 +154,7 @@ fun AdvancedSettingsScreen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun APIUrlDialog(currentUrl: String, onSubmit: (String?) -> Unit) {
|
private fun APIUrlDialog(currentUrl: String, defaultUrl: String, onSubmit: (String?) -> Unit) {
|
||||||
var url by rememberSaveable(currentUrl) { mutableStateOf(currentUrl) }
|
var url by rememberSaveable(currentUrl) { mutableStateOf(currentUrl) }
|
||||||
|
|
||||||
AlertDialog(
|
AlertDialog(
|
||||||
@ -207,9 +198,15 @@ private fun APIUrlDialog(currentUrl: String, onSubmit: (String?) -> Unit) {
|
|||||||
color = MaterialTheme.colorScheme.error
|
color = MaterialTheme.colorScheme.error
|
||||||
)
|
)
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
value = url,
|
value = url,
|
||||||
onValueChange = { url = it },
|
onValueChange = { url = it },
|
||||||
label = { Text(stringResource(R.string.api_url)) }
|
label = { Text(stringResource(R.string.api_url)) },
|
||||||
|
trailingIcon = {
|
||||||
|
IconButton(onClick = { url = defaultUrl }) {
|
||||||
|
Icon(Icons.Outlined.Restore, stringResource(R.string.api_url_dialog_reset))
|
||||||
|
}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,6 +64,12 @@ fun UpdatesSettingsScreen(
|
|||||||
headline = R.string.update_checking_manager,
|
headline = R.string.update_checking_manager,
|
||||||
description = R.string.update_checking_manager_description
|
description = R.string.update_checking_manager_description
|
||||||
)
|
)
|
||||||
|
|
||||||
|
BooleanItem(
|
||||||
|
preference = vm.showManagerUpdateDialogOnLaunch,
|
||||||
|
headline = R.string.show_manager_update_dialog_on_launch,
|
||||||
|
description = R.string.update_checking_manager_description
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -29,7 +29,7 @@ class AppSelectorViewModel(
|
|||||||
private val pm: PM,
|
private val pm: PM,
|
||||||
private val patchBundleRepository: PatchBundleRepository
|
private val patchBundleRepository: PatchBundleRepository
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
private val inputFile = File(app.cacheDir, "input.apk").also {
|
private val inputFile = File(app.filesDir, "input.apk").also {
|
||||||
it.delete()
|
it.delete()
|
||||||
}
|
}
|
||||||
val appList = pm.appList
|
val appList = pm.appList
|
||||||
|
@ -72,6 +72,12 @@ class DashboardViewModel(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun setShowManagerUpdateDialogOnLaunch(value: Boolean) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
prefs.showManagerUpdateDialogOnLaunch.update(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun applyAutoUpdatePrefs(manager: Boolean, patches: Boolean) = viewModelScope.launch {
|
fun applyAutoUpdatePrefs(manager: Boolean, patches: Boolean) = viewModelScope.launch {
|
||||||
prefs.firstLaunch.update(false)
|
prefs.firstLaunch.update(false)
|
||||||
|
|
||||||
|
@ -218,26 +218,14 @@ class PatcherViewModel(
|
|||||||
app.unregisterReceiver(installBroadcastReceiver)
|
app.unregisterReceiver(installBroadcastReceiver)
|
||||||
workManager.cancelWorkById(patcherWorkerId)
|
workManager.cancelWorkById(patcherWorkerId)
|
||||||
|
|
||||||
when (val selectedApp = input.selectedApp) {
|
if (input.selectedApp is SelectedApp.Installed && installedApp?.installType == InstallType.ROOT) {
|
||||||
is SelectedApp.Local -> {
|
GlobalScope.launch(Dispatchers.Main) {
|
||||||
if (selectedApp.temporary) selectedApp.file.delete()
|
uiSafe(app, R.string.failed_to_mount, "Failed to mount") {
|
||||||
}
|
withTimeout(Duration.ofMinutes(1L)) {
|
||||||
|
rootInstaller.mount(packageName)
|
||||||
is SelectedApp.Installed -> {
|
|
||||||
GlobalScope.launch(Dispatchers.Main) {
|
|
||||||
uiSafe(app, R.string.failed_to_mount, "Failed to mount") {
|
|
||||||
installedApp?.let {
|
|
||||||
if (it.installType == InstallType.ROOT) {
|
|
||||||
withTimeout(Duration.ofMinutes(1L)) {
|
|
||||||
rootInstaller.mount(packageName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> Unit
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tempDir.deleteRecursively()
|
tempDir.deleteRecursively()
|
||||||
|
@ -36,6 +36,7 @@ import kotlinx.coroutines.launch
|
|||||||
import org.koin.core.component.KoinComponent
|
import org.koin.core.component.KoinComponent
|
||||||
import org.koin.core.component.get
|
import org.koin.core.component.get
|
||||||
import kotlinx.collections.immutable.*
|
import kotlinx.collections.immutable.*
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
@OptIn(SavedStateHandleSaveableApi::class)
|
@OptIn(SavedStateHandleSaveableApi::class)
|
||||||
@ -77,7 +78,7 @@ class PatchesSelectorViewModel(input: Params) : ViewModel(), KoinComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private var hasModifiedSelection = false
|
private var hasModifiedSelection = false
|
||||||
private var customPatchSelection: PersistentPatchSelection? by savedStateHandle.saveable(
|
var customPatchSelection: PersistentPatchSelection? by savedStateHandle.saveable(
|
||||||
key = "selection",
|
key = "selection",
|
||||||
stateSaver = selectionSaver,
|
stateSaver = selectionSaver,
|
||||||
) {
|
) {
|
||||||
@ -100,15 +101,16 @@ class PatchesSelectorViewModel(input: Params) : ViewModel(), KoinComponent {
|
|||||||
|
|
||||||
val compatibleVersions = mutableStateListOf<String>()
|
val compatibleVersions = mutableStateListOf<String>()
|
||||||
|
|
||||||
var filter by mutableIntStateOf(SHOW_SUPPORTED or SHOW_UNIVERSAL or SHOW_UNSUPPORTED)
|
var filter by mutableIntStateOf(0)
|
||||||
private set
|
private set
|
||||||
|
|
||||||
private suspend fun generateDefaultSelection(): PersistentPatchSelection {
|
private val defaultPatchSelection = bundlesFlow.map { bundles ->
|
||||||
val bundles = bundlesFlow.first()
|
bundles.toPatchSelection(allowIncompatiblePatches) { _, patch -> patch.include }
|
||||||
val generatedSelection =
|
.toPersistentPatchSelection()
|
||||||
bundles.toPatchSelection(allowIncompatiblePatches) { _, patch -> patch.include }
|
}
|
||||||
|
|
||||||
return generatedSelection.toPersistentPatchSelection()
|
val defaultSelectionCount = defaultPatchSelection.map { selection ->
|
||||||
|
selection.values.sumOf { it.size }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun selectionIsValid(bundles: List<BundleInfo>) = bundles.any { bundle ->
|
fun selectionIsValid(bundles: List<BundleInfo>) = bundles.any { bundle ->
|
||||||
@ -124,7 +126,7 @@ class PatchesSelectorViewModel(input: Params) : ViewModel(), KoinComponent {
|
|||||||
fun togglePatch(bundle: Int, patch: PatchInfo) = viewModelScope.launch {
|
fun togglePatch(bundle: Int, patch: PatchInfo) = viewModelScope.launch {
|
||||||
hasModifiedSelection = true
|
hasModifiedSelection = true
|
||||||
|
|
||||||
val selection = customPatchSelection ?: generateDefaultSelection()
|
val selection = customPatchSelection ?: defaultPatchSelection.first()
|
||||||
val newPatches = selection[bundle]?.let { patches ->
|
val newPatches = selection[bundle]?.let { patches ->
|
||||||
if (patch.name in patches)
|
if (patch.name in patches)
|
||||||
patches.remove(patch.name)
|
patches.remove(patch.name)
|
||||||
@ -188,10 +190,8 @@ class PatchesSelectorViewModel(input: Params) : ViewModel(), KoinComponent {
|
|||||||
compatibleVersions.clear()
|
compatibleVersions.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun openUnsupportedDialog(unsupportedPatches: List<PatchInfo>) {
|
fun openUnsupportedDialog(unsupportedPatch: PatchInfo) {
|
||||||
compatibleVersions.addAll(unsupportedPatches.flatMap { patch ->
|
compatibleVersions.addAll(unsupportedPatch.compatiblePackages?.find { it.packageName == packageName }?.versions.orEmpty())
|
||||||
patch.compatiblePackages?.find { it.packageName == packageName }?.versions.orEmpty()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun toggleFlag(flag: Int) {
|
fun toggleFlag(flag: Int) {
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package app.revanced.manager.ui.viewmodel
|
package app.revanced.manager.ui.viewmodel
|
||||||
|
|
||||||
import android.app.Application
|
|
||||||
import android.content.pm.PackageInfo
|
import android.content.pm.PackageInfo
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import androidx.compose.runtime.MutableState
|
import androidx.compose.runtime.MutableState
|
||||||
@ -38,7 +37,6 @@ class SelectedAppInfoViewModel(input: Params) : ViewModel(), KoinComponent {
|
|||||||
private val optionsRepository: PatchOptionsRepository = get()
|
private val optionsRepository: PatchOptionsRepository = get()
|
||||||
private val pm: PM = get()
|
private val pm: PM = get()
|
||||||
private val savedStateHandle: SavedStateHandle = get()
|
private val savedStateHandle: SavedStateHandle = get()
|
||||||
private val app: Application = get()
|
|
||||||
val prefs: PreferencesManager = get()
|
val prefs: PreferencesManager = get()
|
||||||
|
|
||||||
private val persistConfiguration = input.patches == null
|
private val persistConfiguration = input.patches == null
|
||||||
@ -82,20 +80,17 @@ class SelectedAppInfoViewModel(input: Params) : ViewModel(), KoinComponent {
|
|||||||
private set
|
private set
|
||||||
|
|
||||||
private var selectionState by savedStateHandle.saveable {
|
private var selectionState by savedStateHandle.saveable {
|
||||||
if (input.patches != null) {
|
if (input.patches != null)
|
||||||
return@saveable mutableStateOf(SelectionState.Customized(input.patches))
|
return@saveable mutableStateOf(SelectionState.Customized(input.patches))
|
||||||
}
|
|
||||||
|
|
||||||
val selection: MutableState<SelectionState> = mutableStateOf(SelectionState.Default)
|
val selection: MutableState<SelectionState> = mutableStateOf(SelectionState.Default)
|
||||||
|
|
||||||
// Get previous selection (if present).
|
// Try to get the previous selection if customization is enabled.
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
|
if (!prefs.disableSelectionWarning.get()) return@launch
|
||||||
|
|
||||||
val previous = selectionRepository.getSelection(selectedApp.packageName)
|
val previous = selectionRepository.getSelection(selectedApp.packageName)
|
||||||
|
if (previous.values.sumOf { it.size } == 0) return@launch
|
||||||
if (previous.values.sumOf { it.size } == 0) {
|
|
||||||
return@launch
|
|
||||||
}
|
|
||||||
|
|
||||||
selection.value = SelectionState.Customized(previous)
|
selection.value = SelectionState.Customized(previous)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ class UpdatesSettingsViewModel(
|
|||||||
private val reVancedAPI: ReVancedAPI,
|
private val reVancedAPI: ReVancedAPI,
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
val managerAutoUpdates = prefs.managerAutoUpdates
|
val managerAutoUpdates = prefs.managerAutoUpdates
|
||||||
|
val showManagerUpdateDialogOnLaunch = prefs.showManagerUpdateDialogOnLaunch
|
||||||
|
|
||||||
suspend fun checkForUpdates(): Boolean {
|
suspend fun checkForUpdates(): Boolean {
|
||||||
uiSafe(app, R.string.failed_to_check_updates, "Failed to check for updates") {
|
uiSafe(app, R.string.failed_to_check_updates, "Failed to check for updates") {
|
||||||
|
BIN
app/src/main/jniLibs/armeabi-v7a/libaapt2.so
Normal file
BIN
app/src/main/jniLibs/armeabi-v7a/libaapt2.so
Normal file
Binary file not shown.
@ -12,10 +12,10 @@
|
|||||||
<string name="dashboard">Dashboard</string>
|
<string name="dashboard">Dashboard</string>
|
||||||
<string name="settings">Settings</string>
|
<string name="settings">Settings</string>
|
||||||
<string name="select_app">Select an app</string>
|
<string name="select_app">Select an app</string>
|
||||||
<string name="select_patches">Select patches</string>
|
<string name="patches_selected">%1$d/%2$d selected</string>
|
||||||
|
|
||||||
<string name="unsupported_architecture_warning">Patching on ARMv7 devices is not yet supported and will most likely fail.</string>
|
|
||||||
<string name="new_downloader_plugins_notification">New downloader plugins available. Click here to configure them.</string>
|
<string name="new_downloader_plugins_notification">New downloader plugins available. Click here to configure them.</string>
|
||||||
|
<string name="unsupported_architecture_warning">Patching on this device architecture is unsupported and will most likely fail.</string>
|
||||||
|
|
||||||
<string name="import_">Import</string>
|
<string name="import_">Import</string>
|
||||||
<string name="import_bundle">Import patch bundle</string>
|
<string name="import_bundle">Import patch bundle</string>
|
||||||
@ -34,8 +34,7 @@
|
|||||||
<string name="bundle_name_default">Default</string>
|
<string name="bundle_name_default">Default</string>
|
||||||
<string name="bundle_name_fallback">Unnamed</string>
|
<string name="bundle_name_fallback">Unnamed</string>
|
||||||
|
|
||||||
<string name="selected_app_meta_version">%1$s • %2$d available patches</string>
|
<string name="selected_app_meta_any_version">Any available version</string>
|
||||||
<string name="selected_app_meta_no_version">%d available patches</string>
|
|
||||||
|
|
||||||
<string name="patch_item_description">Start patching the application</string>
|
<string name="patch_item_description">Start patching the application</string>
|
||||||
<string name="patch_selector_item">Patch selection and options</string>
|
<string name="patch_selector_item">Patch selection and options</string>
|
||||||
@ -166,10 +165,12 @@
|
|||||||
<string name="debug_logs_export_failed">Failed to export logs</string>
|
<string name="debug_logs_export_failed">Failed to export logs</string>
|
||||||
<string name="debug_logs_export_success">Exported logs</string>
|
<string name="debug_logs_export_success">Exported logs</string>
|
||||||
<string name="api_url">API URL</string>
|
<string name="api_url">API URL</string>
|
||||||
|
<string name="api_url_description">The API used to download necessary files.</string>
|
||||||
<string name="api_url_dialog_title">Set custom API URL</string>
|
<string name="api_url_dialog_title">Set custom API URL</string>
|
||||||
<string name="api_url_dialog_description">You may have issues with features when using a custom API URL.</string>
|
<string name="api_url_dialog_description">Set the API URL of ReVanced Manager. ReVanced Manager uses the API to download patches and updates.</string>
|
||||||
<string name="api_url_dialog_warning">Only use API\'s you trust!</string>
|
<string name="api_url_dialog_warning">ReVanced Manager connects to the API to download patches and updates. Make sure that you trust it.</string>
|
||||||
<string name="api_url_dialog_save">Set</string>
|
<string name="api_url_dialog_save">Set</string>
|
||||||
|
<string name="api_url_dialog_reset">Reset API URL</string>
|
||||||
<string name="device">Device</string>
|
<string name="device">Device</string>
|
||||||
<string name="device_android_version">Android version</string>
|
<string name="device_android_version">Android version</string>
|
||||||
<string name="device_model">Model</string>
|
<string name="device_model">Model</string>
|
||||||
@ -199,7 +200,6 @@
|
|||||||
<string name="no_patched_apps_found">No patched apps found</string>
|
<string name="no_patched_apps_found">No patched apps found</string>
|
||||||
<string name="tap_on_patches">Tap on the patches to get more information about them</string>
|
<string name="tap_on_patches">Tap on the patches to get more information about them</string>
|
||||||
<string name="bundles_selected">%s selected</string>
|
<string name="bundles_selected">%s selected</string>
|
||||||
<string name="unsupported_app">Unsupported app</string>
|
|
||||||
<string name="unsupported_patches">Unsupported patches</string>
|
<string name="unsupported_patches">Unsupported patches</string>
|
||||||
<string name="universal_patches">Universal patches</string>
|
<string name="universal_patches">Universal patches</string>
|
||||||
<string name="patch_selection_reset_toast">Patch selection and options has been reset to recommended defaults</string>
|
<string name="patch_selection_reset_toast">Patch selection and options has been reset to recommended defaults</string>
|
||||||
@ -213,7 +213,7 @@
|
|||||||
<string name="universal">Universal</string>
|
<string name="universal">Universal</string>
|
||||||
<string name="unsupported">Unsupported</string>
|
<string name="unsupported">Unsupported</string>
|
||||||
<string name="search_patches">Patch name</string>
|
<string name="search_patches">Patch name</string>
|
||||||
<string name="app_not_supported">Some of the patches do not support this app version (%1$s). The patches only support the following version(s): %2$s.</string>
|
<string name="app_not_supported">This patch is not compatible with the selected app version (%1$s).\n\nIt only supports the following version(s): %2$s.</string>
|
||||||
<string name="continue_with_version">Continue with this version?</string>
|
<string name="continue_with_version">Continue with this version?</string>
|
||||||
<string name="version_not_supported">Not all patches support this version (%s). Do you want to continue anyway?</string>
|
<string name="version_not_supported">Not all patches support this version (%s). Do you want to continue anyway?</string>
|
||||||
<string name="download_application">Download application?</string>
|
<string name="download_application">Download application?</string>
|
||||||
@ -333,9 +333,9 @@
|
|||||||
<string name="install_update_manager_failed">Failed to install update</string>
|
<string name="install_update_manager_failed">Failed to install update</string>
|
||||||
<string name="manual_update_check">Check for updates</string>
|
<string name="manual_update_check">Check for updates</string>
|
||||||
<string name="manual_update_check_description">Manually check for updates</string>
|
<string name="manual_update_check_description">Manually check for updates</string>
|
||||||
<string name="update_checking_manager">Update checking</string>
|
<string name="update_checking_manager">Auto check for updates</string>
|
||||||
<string name="update_checking_manager_description">Check for new versions of ReVanced Manager when the application starts</string>
|
<string name="update_checking_manager_description">Check for new versions of ReVanced Manager when the application starts</string>
|
||||||
<string name="changelog">Changelog</string>
|
<string name="changelog">View changelogs</string>
|
||||||
<string name="changelog_loading">Loading changelog</string>
|
<string name="changelog_loading">Loading changelog</string>
|
||||||
<string name="changelog_download_fail">Failed to download changelog: %s</string>
|
<string name="changelog_download_fail">Failed to download changelog: %s</string>
|
||||||
<string name="changelog_description">Check out the latest changes in this update</string>
|
<string name="changelog_description">Check out the latest changes in this update</string>
|
||||||
@ -382,4 +382,9 @@
|
|||||||
<string name="add_patch_bundle">Add patch bundle</string>
|
<string name="add_patch_bundle">Add patch bundle</string>
|
||||||
<string name="bundle_url">Bundle URL</string>
|
<string name="bundle_url">Bundle URL</string>
|
||||||
<string name="auto_update">Auto update</string>
|
<string name="auto_update">Auto update</string>
|
||||||
|
<string name="unsupported_patches_dialog">These patches are not compatible with the selected app version (%1$s).\n\nClick on the patches to see more details.</string>
|
||||||
|
<string name="unsupported_patch">Unsupported patch</string>
|
||||||
|
<string name="never_show_again">Never show again</string>
|
||||||
|
<string name="show_manager_update_dialog_on_launch">Show update message on launch</string>
|
||||||
|
<string name="show_manager_update_dialog_on_launch_description">Shows a popup notification whenever there is a new update available on launch.</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -5,9 +5,6 @@ In order to use ReVanced Manager, certain requirements must be met.
|
|||||||
## 🤝 Requirements
|
## 🤝 Requirements
|
||||||
|
|
||||||
- An Android device running Android 8 or higher
|
- An Android device running Android 8 or higher
|
||||||
- Any device architecture except ARMv7[^1]
|
|
||||||
|
|
||||||
[^1]: This constraint only applies to patches, that require patching APK resources which is why some patches may or may not work on ARMv7 architecture. You can find out, which architectures your device supports here: [⚙️ Configuring ReVanced Manager](2_4_settings.md#%E2%84%B9%EF%B8%8F-about).
|
|
||||||
|
|
||||||
## ⏭️ What's next
|
## ⏭️ What's next
|
||||||
|
|
||||||
|
@ -21,4 +21,6 @@ kotlin.code.style=official
|
|||||||
# resources declared in the library itself and none from the library's dependencies,
|
# resources declared in the library itself and none from the library's dependencies,
|
||||||
# thereby reducing the size of the R class for that library
|
# thereby reducing the size of the R class for that library
|
||||||
android.nonTransitiveRClass=true
|
android.nonTransitiveRClass=true
|
||||||
android.nonFinalResIds=false
|
android.nonFinalResIds=false
|
||||||
|
org.gradle.configuration-cache=true
|
||||||
|
org.gradle.caching=true
|
||||||
|
Loading…
x
Reference in New Issue
Block a user