From 7c7fb7b343bf09fb92f5c870269bdbe41595b2a0 Mon Sep 17 00:00:00 2001 From: Ax333l Date: Fri, 5 Jul 2024 19:06:10 +0200 Subject: [PATCH 01/11] feat: dont ask for root on launch --- .../revanced/manager/ManagerApplication.kt | 8 - .../app/revanced/manager/di/RootModule.kt | 2 - .../manager/domain/installer/RootInstaller.kt | 197 +++++++++++------- .../revanced/manager/service/RootService.kt | 22 +- .../ui/screen/InstalledAppInfoScreen.kt | 2 +- .../ui/viewmodel/InstalledAppInfoViewModel.kt | 10 +- .../manager/ui/viewmodel/PatcherViewModel.kt | 22 +- 7 files changed, 144 insertions(+), 119 deletions(-) diff --git a/app/src/main/java/app/revanced/manager/ManagerApplication.kt b/app/src/main/java/app/revanced/manager/ManagerApplication.kt index 8a2811bd..66ab2483 100644 --- a/app/src/main/java/app/revanced/manager/ManagerApplication.kt +++ b/app/src/main/java/app/revanced/manager/ManagerApplication.kt @@ -1,23 +1,18 @@ package app.revanced.manager import android.app.Application -import android.content.Intent import app.revanced.manager.di.* import app.revanced.manager.domain.manager.PreferencesManager import app.revanced.manager.domain.repository.PatchBundleRepository -import app.revanced.manager.service.ManagerRootService -import app.revanced.manager.service.RootConnection import kotlinx.coroutines.Dispatchers import coil.Coil import coil.ImageLoader import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.internal.BuilderImpl -import com.topjohnwu.superuser.ipc.RootService import kotlinx.coroutines.MainScope import kotlinx.coroutines.launch import me.zhanghai.android.appiconloader.coil.AppIconFetcher import me.zhanghai.android.appiconloader.coil.AppIconKeyer -import org.koin.android.ext.android.get import org.koin.android.ext.android.inject import org.koin.android.ext.koin.androidContext import org.koin.android.ext.koin.androidLogger @@ -61,9 +56,6 @@ class ManagerApplication : Application() { val shellBuilder = BuilderImpl.create().setFlags(Shell.FLAG_MOUNT_MASTER) Shell.setDefaultBuilder(shellBuilder) - val intent = Intent(this, ManagerRootService::class.java) - RootService.bind(intent, get()) - scope.launch { prefs.preload() } diff --git a/app/src/main/java/app/revanced/manager/di/RootModule.kt b/app/src/main/java/app/revanced/manager/di/RootModule.kt index acfad58d..1e27555b 100644 --- a/app/src/main/java/app/revanced/manager/di/RootModule.kt +++ b/app/src/main/java/app/revanced/manager/di/RootModule.kt @@ -1,11 +1,9 @@ package app.revanced.manager.di import app.revanced.manager.domain.installer.RootInstaller -import app.revanced.manager.service.RootConnection import org.koin.core.module.dsl.singleOf import org.koin.dsl.module val rootModule = module { - singleOf(::RootConnection) singleOf(::RootInstaller) } \ No newline at end of file diff --git a/app/src/main/java/app/revanced/manager/domain/installer/RootInstaller.kt b/app/src/main/java/app/revanced/manager/domain/installer/RootInstaller.kt index 0b2ee413..9ca6cd9b 100644 --- a/app/src/main/java/app/revanced/manager/domain/installer/RootInstaller.kt +++ b/app/src/main/java/app/revanced/manager/domain/installer/RootInstaller.kt @@ -1,49 +1,93 @@ package app.revanced.manager.domain.installer import android.app.Application -import app.revanced.manager.service.RootConnection +import android.content.ComponentName +import android.content.Intent +import android.content.ServiceConnection +import android.os.IBinder +import app.revanced.manager.IRootSystemService +import app.revanced.manager.service.ManagerRootService import app.revanced.manager.util.PM import com.topjohnwu.superuser.Shell +import com.topjohnwu.superuser.ipc.RootService +import com.topjohnwu.superuser.nio.FileSystemManager +import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.time.withTimeoutOrNull import kotlinx.coroutines.withContext import java.io.File +import java.time.Duration class RootInstaller( private val app: Application, - private val rootConnection: RootConnection, private val pm: PM -) { +) : ServiceConnection { + private var remoteFS = CompletableDeferred() + + override fun onServiceConnected(name: ComponentName?, service: IBinder?) { + val ipc = IRootSystemService.Stub.asInterface(service) + val binder = ipc.fileSystemService + + remoteFS.complete(FileSystemManager.getRemote(binder)) + } + + override fun onServiceDisconnected(name: ComponentName?) { + remoteFS = CompletableDeferred() + } + + private suspend fun awaitRemoteFS(): FileSystemManager { + if (remoteFS.isActive) { + withContext(Dispatchers.Main) { + val intent = Intent(app, ManagerRootService::class.java) + RootService.bind(intent, this@RootInstaller) + } + } + + return withTimeoutOrNull(Duration.ofSeconds(120L)) { + remoteFS.await() + } ?: throw RootServiceException() + } + + private suspend fun getShell() = with(CompletableDeferred()) { + Shell.getShell(::complete) + + await() + } + + suspend fun execute(vararg commands: String) = getShell().newJob().add(*commands).exec() + fun hasRootAccess() = Shell.isAppGrantedRoot() ?: false - fun isAppInstalled(packageName: String) = - rootConnection.remoteFS?.getFile("$modulesPath/$packageName-revanced") - ?.exists() ?: throw RootServiceException() + suspend fun isAppInstalled(packageName: String) = + awaitRemoteFS().getFile("$modulesPath/$packageName-revanced").exists() - fun isAppMounted(packageName: String): Boolean { - return pm.getPackageInfo(packageName)?.applicationInfo?.sourceDir?.let { - Shell.cmd("mount | grep \"$it\"").exec().isSuccess + suspend fun isAppMounted(packageName: String) = withContext(Dispatchers.IO) { + pm.getPackageInfo(packageName)?.applicationInfo?.sourceDir?.let { + execute("mount | grep \"$it\"").isSuccess } ?: false } - fun mount(packageName: String) { + suspend fun mount(packageName: String) { if (isAppMounted(packageName)) return - val stockAPK = pm.getPackageInfo(packageName)?.applicationInfo?.sourceDir - ?: throw Exception("Failed to load application info") - val patchedAPK = "$modulesPath/$packageName-revanced/$packageName.apk" + withContext(Dispatchers.IO) { + val stockAPK = pm.getPackageInfo(packageName)?.applicationInfo?.sourceDir + ?: throw Exception("Failed to load application info") + val patchedAPK = "$modulesPath/$packageName-revanced/$packageName.apk" - Shell.cmd("mount -o bind \"$patchedAPK\" \"$stockAPK\"").exec() - .also { if (!it.isSuccess) throw Exception("Failed to mount APK") } + execute("mount -o bind \"$patchedAPK\" \"$stockAPK\"").assertSuccess("Failed to mount APK") + } } - fun unmount(packageName: String) { + suspend fun unmount(packageName: String) { if (!isAppMounted(packageName)) return - val stockAPK = pm.getPackageInfo(packageName)?.applicationInfo?.sourceDir - ?: throw Exception("Failed to load application info") + withContext(Dispatchers.IO) { + val stockAPK = pm.getPackageInfo(packageName)?.applicationInfo?.sourceDir + ?: throw Exception("Failed to load application info") - Shell.cmd("umount -l \"$stockAPK\"").exec() - .also { if (!it.isSuccess) throw Exception("Failed to unmount APK") } + execute("umount -l \"$stockAPK\"").assertSuccess("Failed to unmount APK") + } } suspend fun install( @@ -52,80 +96,77 @@ class RootInstaller( packageName: String, version: String, label: String - ) { - withContext(Dispatchers.IO) { - rootConnection.remoteFS?.let { remoteFS -> - val assets = app.assets - val modulePath = "$modulesPath/$packageName-revanced" + ) = withContext(Dispatchers.IO) { + val remoteFS = awaitRemoteFS() + val assets = app.assets + val modulePath = "$modulesPath/$packageName-revanced" - unmount(packageName) + unmount(packageName) - stockAPK?.let { stockApp -> - pm.getPackageInfo(packageName)?.let { packageInfo -> - if (packageInfo.versionName <= version) - Shell.cmd("pm uninstall -k --user 0 $packageName").exec() - .also { if (!it.isSuccess) throw Exception("Failed to uninstall stock app") } + stockAPK?.let { stockApp -> + pm.getPackageInfo(packageName)?.let { packageInfo -> + if (packageInfo.versionName <= version) + execute("pm uninstall -k --user 0 $packageName").assertSuccess("Failed to uninstall stock app") + } + + execute("pm install \"${stockApp.absolutePath}\"").assertSuccess("Failed to install stock app") + } + + remoteFS.getFile(modulePath).mkdir() + + listOf( + "service.sh", + "module.prop", + ).forEach { file -> + assets.open("root/$file").use { inputStream -> + remoteFS.getFile("$modulePath/$file").newOutputStream() + .use { outputStream -> + val content = String(inputStream.readBytes()) + .replace("__PKG_NAME__", packageName) + .replace("__VERSION__", version) + .replace("__LABEL__", label) + .toByteArray() + + outputStream.write(content) } + } + } - Shell.cmd("pm install \"${stockApp.absolutePath}\"").exec() - .also { if (!it.isSuccess) throw Exception("Failed to install stock app") } - } + "$modulePath/$packageName.apk".let { apkPath -> - remoteFS.getFile(modulePath).mkdir() - - listOf( - "service.sh", - "module.prop", - ).forEach { file -> - assets.open("root/$file").use { inputStream -> - remoteFS.getFile("$modulePath/$file").newOutputStream() - .use { outputStream -> - val content = String(inputStream.readBytes()) - .replace("__PKG_NAME__", packageName) - .replace("__VERSION__", version) - .replace("__LABEL__", label) - .toByteArray() - - outputStream.write(content) - } + remoteFS.getFile(patchedAPK.absolutePath) + .also { if (!it.exists()) throw Exception("File doesn't exist") } + .newInputStream().use { inputStream -> + remoteFS.getFile(apkPath).newOutputStream().use { outputStream -> + inputStream.copyTo(outputStream) } } - "$modulePath/$packageName.apk".let { apkPath -> - - remoteFS.getFile(patchedAPK.absolutePath) - .also { if (!it.exists()) throw Exception("File doesn't exist") } - .newInputStream().use { inputStream -> - remoteFS.getFile(apkPath).newOutputStream().use { outputStream -> - inputStream.copyTo(outputStream) - } - } - - Shell.cmd( - "chmod 644 $apkPath", - "chown system:system $apkPath", - "chcon u:object_r:apk_data_file:s0 $apkPath", - "chmod +x $modulePath/service.sh" - ).exec() - .let { if (!it.isSuccess) throw Exception("Failed to set file permissions") } - } - } ?: throw RootServiceException() + execute( + "chmod 644 $apkPath", + "chown system:system $apkPath", + "chcon u:object_r:apk_data_file:s0 $apkPath", + "chmod +x $modulePath/service.sh" + ).assertSuccess("Failed to set file permissions") } } - fun uninstall(packageName: String) { - rootConnection.remoteFS?.let { remoteFS -> - if (isAppMounted(packageName)) - unmount(packageName) + suspend fun uninstall(packageName: String) { + val remoteFS = awaitRemoteFS() + if (isAppMounted(packageName)) + unmount(packageName) - remoteFS.getFile("$modulesPath/$packageName-revanced").deleteRecursively() - .also { if (!it) throw Exception("Failed to delete files") } - } ?: throw RootServiceException() + remoteFS.getFile("$modulesPath/$packageName-revanced").deleteRecursively() + .also { if (!it) throw Exception("Failed to delete files") } } companion object { const val modulesPath = "/data/adb/modules" + + private fun Shell.Result.assertSuccess(errorMessage: String) { + if (!isSuccess) throw Exception(errorMessage) + } } } -class RootServiceException: Exception("Root not available") \ No newline at end of file +class RootServiceException : Exception("Root not available") \ No newline at end of file diff --git a/app/src/main/java/app/revanced/manager/service/RootService.kt b/app/src/main/java/app/revanced/manager/service/RootService.kt index 6fa68b6c..ed475e50 100644 --- a/app/src/main/java/app/revanced/manager/service/RootService.kt +++ b/app/src/main/java/app/revanced/manager/service/RootService.kt @@ -1,8 +1,6 @@ package app.revanced.manager.service -import android.content.ComponentName import android.content.Intent -import android.content.ServiceConnection import android.os.IBinder import app.revanced.manager.IRootSystemService import com.topjohnwu.superuser.ipc.RootService @@ -14,23 +12,5 @@ class ManagerRootService : RootService() { FileSystemManager.getService() } - override fun onBind(intent: Intent): IBinder { - return RootSystemService() - } -} - -class RootConnection : ServiceConnection { - var remoteFS: FileSystemManager? = null - private set - - override fun onServiceConnected(name: ComponentName?, service: IBinder?) { - val ipc = IRootSystemService.Stub.asInterface(service) - val binder = ipc.fileSystemService - - remoteFS = FileSystemManager.getRemote(binder) - } - - override fun onServiceDisconnected(name: ComponentName?) { - remoteFS = null - } + override fun onBind(intent: Intent): IBinder = RootSystemService() } \ No newline at end of file diff --git a/app/src/main/java/app/revanced/manager/ui/screen/InstalledAppInfoScreen.kt b/app/src/main/java/app/revanced/manager/ui/screen/InstalledAppInfoScreen.kt index cd2752ca..2727e290 100644 --- a/app/src/main/java/app/revanced/manager/ui/screen/InstalledAppInfoScreen.kt +++ b/app/src/main/java/app/revanced/manager/ui/screen/InstalledAppInfoScreen.kt @@ -83,7 +83,7 @@ fun InstalledAppInfoScreen( if (viewModel.installedApp.installType == InstallType.ROOT) { Text( - text = if (viewModel.rootInstaller.isAppMounted(viewModel.installedApp.currentPackageName)) { + text = if (viewModel.isMounted) { stringResource(R.string.mounted) } else { stringResource(R.string.not_mounted) diff --git a/app/src/main/java/app/revanced/manager/ui/viewmodel/InstalledAppInfoViewModel.kt b/app/src/main/java/app/revanced/manager/ui/viewmodel/InstalledAppInfoViewModel.kt index aa0a8203..7e610f55 100644 --- a/app/src/main/java/app/revanced/manager/ui/viewmodel/InstalledAppInfoViewModel.kt +++ b/app/src/main/java/app/revanced/manager/ui/viewmodel/InstalledAppInfoViewModel.kt @@ -44,12 +44,18 @@ class InstalledAppInfoViewModel( var appInfo: PackageInfo? by mutableStateOf(null) private set var appliedPatches: PatchSelection? by mutableStateOf(null) - var isMounted by mutableStateOf(rootInstaller.isAppMounted(installedApp.currentPackageName)) + var isMounted by mutableStateOf(false) private set + init { + viewModelScope.launch { + isMounted = rootInstaller.isAppMounted(installedApp.currentPackageName) + } + } + fun launch() = pm.launch(installedApp.currentPackageName) - fun mountOrUnmount() { + fun mountOrUnmount() = viewModelScope.launch { try { if (isMounted) rootInstaller.unmount(installedApp.currentPackageName) diff --git a/app/src/main/java/app/revanced/manager/ui/viewmodel/PatcherViewModel.kt b/app/src/main/java/app/revanced/manager/ui/viewmodel/PatcherViewModel.kt index 15a51a20..27049127 100644 --- a/app/src/main/java/app/revanced/manager/ui/viewmodel/PatcherViewModel.kt +++ b/app/src/main/java/app/revanced/manager/ui/viewmodel/PatcherViewModel.kt @@ -39,15 +39,21 @@ import app.revanced.manager.util.PM import app.revanced.manager.util.simpleMessage import app.revanced.manager.util.tag import app.revanced.manager.util.toast +import app.revanced.manager.util.uiSafe +import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.launch +import kotlinx.coroutines.time.withTimeout import kotlinx.coroutines.withContext +import kotlinx.coroutines.withTimeout import org.koin.core.component.KoinComponent import org.koin.core.component.inject import java.io.File import java.nio.file.Files +import java.time.Duration import java.util.UUID @Stable @@ -177,6 +183,7 @@ class PatcherViewModel( } } + @OptIn(DelicateCoroutinesApi::class) override fun onCleared() { super.onCleared() app.unregisterReceiver(installBroadcastReceiver) @@ -188,15 +195,16 @@ class PatcherViewModel( } is SelectedApp.Installed -> { - try { - installedApp?.let { - if (it.installType == InstallType.ROOT) { - rootInstaller.mount(packageName) + 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) + } + } } } - } catch (e: Exception) { - Log.e(tag, "Failed to mount", e) - app.toast(app.getString(R.string.failed_to_mount, e.simpleMessage())) } } From e6e043f16870c2ca46a5da82e9719311c5ec52d7 Mon Sep 17 00:00:00 2001 From: Ax333l Date: Fri, 5 Jul 2024 19:41:27 +0200 Subject: [PATCH 02/11] fix: cleanup advanced settings screen --- .../revanced/manager/di/ViewModelModule.kt | 1 + .../ui/destination/SettingsDestination.kt | 23 +++++----- .../manager/ui/screen/SettingsScreen.kt | 5 ++- .../ui/screen/settings/AboutSettingsScreen.kt | 8 ++-- .../screen/settings/AdvancedSettingsScreen.kt | 30 +++++-------- .../screen/settings/DeveloperOptionsScreen.kt | 44 +++++++++++++++++++ .../ui/viewmodel/AdvancedSettingsViewModel.kt | 12 ----- .../ui/viewmodel/DeveloperOptionsViewModel.kt | 27 ++++++++++++ app/src/main/res/values/strings.xml | 1 + 9 files changed, 105 insertions(+), 46 deletions(-) create mode 100644 app/src/main/java/app/revanced/manager/ui/screen/settings/DeveloperOptionsScreen.kt create mode 100644 app/src/main/java/app/revanced/manager/ui/viewmodel/DeveloperOptionsViewModel.kt diff --git a/app/src/main/java/app/revanced/manager/di/ViewModelModule.kt b/app/src/main/java/app/revanced/manager/di/ViewModelModule.kt index 9bce104c..0c69767c 100644 --- a/app/src/main/java/app/revanced/manager/di/ViewModelModule.kt +++ b/app/src/main/java/app/revanced/manager/di/ViewModelModule.kt @@ -18,6 +18,7 @@ val viewModelModule = module { viewModelOf(::ChangelogsViewModel) viewModelOf(::ImportExportViewModel) viewModelOf(::AboutViewModel) + viewModelOf(::DeveloperOptionsViewModel) viewModelOf(::ContributorViewModel) viewModelOf(::DownloadsViewModel) viewModelOf(::InstalledAppsViewModel) diff --git a/app/src/main/java/app/revanced/manager/ui/destination/SettingsDestination.kt b/app/src/main/java/app/revanced/manager/ui/destination/SettingsDestination.kt index 6f880de6..e62ab4f4 100644 --- a/app/src/main/java/app/revanced/manager/ui/destination/SettingsDestination.kt +++ b/app/src/main/java/app/revanced/manager/ui/destination/SettingsDestination.kt @@ -6,35 +6,38 @@ import kotlinx.parcelize.Parcelize sealed interface SettingsDestination : Parcelable { @Parcelize - object Settings : SettingsDestination + data object Settings : SettingsDestination @Parcelize - object General : SettingsDestination + data object General : SettingsDestination @Parcelize - object Advanced : SettingsDestination + data object Advanced : SettingsDestination @Parcelize - object Updates : SettingsDestination + data object Updates : SettingsDestination @Parcelize - object Downloads : SettingsDestination + data object Downloads : SettingsDestination @Parcelize - object ImportExport : SettingsDestination + data object ImportExport : SettingsDestination @Parcelize - object About : SettingsDestination + data object About : SettingsDestination @Parcelize data class Update(val downloadOnScreenEntry: Boolean = false) : SettingsDestination @Parcelize - object Changelogs : SettingsDestination + data object Changelogs : SettingsDestination @Parcelize - object Contributors: SettingsDestination + data object Contributors: SettingsDestination @Parcelize - object Licenses: SettingsDestination + data object Licenses: SettingsDestination + + @Parcelize + data object DeveloperOptions: SettingsDestination } \ No newline at end of file diff --git a/app/src/main/java/app/revanced/manager/ui/screen/SettingsScreen.kt b/app/src/main/java/app/revanced/manager/ui/screen/SettingsScreen.kt index 08468808..690b2016 100644 --- a/app/src/main/java/app/revanced/manager/ui/screen/SettingsScreen.kt +++ b/app/src/main/java/app/revanced/manager/ui/screen/SettingsScreen.kt @@ -122,7 +122,8 @@ fun SettingsScreen( is SettingsDestination.About -> AboutSettingsScreen( onBackClick = backClick, onContributorsClick = { navController.navigate(SettingsDestination.Contributors) }, - onLicensesClick = { navController.navigate(SettingsDestination.Licenses) } + onDeveloperOptionsClick = { navController.navigate(SettingsDestination.DeveloperOptions) }, + onLicensesClick = { navController.navigate(SettingsDestination.Licenses) }, ) is SettingsDestination.Update -> UpdateScreen( @@ -146,6 +147,8 @@ fun SettingsScreen( onBackClick = backClick, ) + is SettingsDestination.DeveloperOptions -> DeveloperOptionsScreen(onBackClick = backClick) + is SettingsDestination.Settings -> { Scaffold( topBar = { diff --git a/app/src/main/java/app/revanced/manager/ui/screen/settings/AboutSettingsScreen.kt b/app/src/main/java/app/revanced/manager/ui/screen/settings/AboutSettingsScreen.kt index c4425913..7ee21609 100644 --- a/app/src/main/java/app/revanced/manager/ui/screen/settings/AboutSettingsScreen.kt +++ b/app/src/main/java/app/revanced/manager/ui/screen/settings/AboutSettingsScreen.kt @@ -39,7 +39,6 @@ import app.revanced.manager.ui.component.ColumnWithScrollbar import app.revanced.manager.ui.component.settings.SettingsListItem import app.revanced.manager.ui.viewmodel.AboutViewModel import app.revanced.manager.ui.viewmodel.AboutViewModel.Companion.getSocialIcon -import app.revanced.manager.util.isDebuggable import app.revanced.manager.util.openUrl import com.google.accompanist.drawablepainter.rememberDrawablePainter import org.koin.androidx.compose.koinViewModel @@ -50,6 +49,7 @@ fun AboutSettingsScreen( onBackClick: () -> Unit, onContributorsClick: () -> Unit, onLicensesClick: () -> Unit, + onDeveloperOptionsClick: () -> Unit, viewModel: AboutViewModel = koinViewModel() ) { val context = LocalContext.current @@ -116,9 +116,11 @@ fun AboutSettingsScreen( stringResource(R.string.contributors_description), third = onContributorsClick ), - Triple(stringResource(R.string.developer_options), + Triple( + stringResource(R.string.developer_options), stringResource(R.string.developer_options_description), - third = { /*TODO*/ }).takeIf { context.isDebuggable }, + third = onDeveloperOptionsClick + ), Triple( stringResource(R.string.opensource_licenses), stringResource(R.string.opensource_licenses_description), diff --git a/app/src/main/java/app/revanced/manager/ui/screen/settings/AdvancedSettingsScreen.kt b/app/src/main/java/app/revanced/manager/ui/screen/settings/AdvancedSettingsScreen.kt index 3817bd12..146ff325 100644 --- a/app/src/main/java/app/revanced/manager/ui/screen/settings/AdvancedSettingsScreen.kt +++ b/app/src/main/java/app/revanced/manager/ui/screen/settings/AdvancedSettingsScreen.kt @@ -71,6 +71,8 @@ fun AdvancedSettingsScreen( .fillMaxSize() .padding(paddingValues) ) { + GroupHeader(stringResource(R.string.manager)) + val apiUrl by vm.prefs.api.getAsState() var showApiUrlDialog by rememberSaveable { mutableStateOf(false) } @@ -110,6 +112,14 @@ fun AdvancedSettingsScreen( headline = R.string.process_runtime_memory_limit, description = R.string.process_runtime_memory_limit_description, ) + BooleanItem( + preference = vm.prefs.multithreadingDexFileWriter, + coroutineScope = vm.viewModelScope, + headline = R.string.multithreaded_dex_file_writer, + description = R.string.multithreaded_dex_file_writer_description, + ) + + GroupHeader(stringResource(R.string.safeguards)) BooleanItem( preference = vm.prefs.disablePatchVersionCompatCheck, coroutineScope = vm.viewModelScope, @@ -122,26 +132,6 @@ fun AdvancedSettingsScreen( headline = R.string.suggested_version_safeguard, description = R.string.suggested_version_safeguard_description ) - BooleanItem( - preference = vm.prefs.multithreadingDexFileWriter, - coroutineScope = vm.viewModelScope, - headline = R.string.multithreaded_dex_file_writer, - description = R.string.multithreaded_dex_file_writer_description, - ) - - GroupHeader(stringResource(R.string.patch_bundles_section)) - SettingsListItem( - headlineContent = stringResource(R.string.patch_bundles_redownload), - modifier = Modifier.clickable { - vm.redownloadBundles() - } - ) - SettingsListItem( - headlineContent = stringResource(R.string.patch_bundles_reset), - modifier = Modifier.clickable { - vm.resetBundles() - } - ) GroupHeader(stringResource(R.string.device)) SettingsListItem( diff --git a/app/src/main/java/app/revanced/manager/ui/screen/settings/DeveloperOptionsScreen.kt b/app/src/main/java/app/revanced/manager/ui/screen/settings/DeveloperOptionsScreen.kt new file mode 100644 index 00000000..f8f1e0cf --- /dev/null +++ b/app/src/main/java/app/revanced/manager/ui/screen/settings/DeveloperOptionsScreen.kt @@ -0,0 +1,44 @@ +package app.revanced.manager.ui.screen.settings + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Scaffold +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import app.revanced.manager.R +import app.revanced.manager.ui.component.AppTopBar +import app.revanced.manager.ui.component.GroupHeader +import app.revanced.manager.ui.component.settings.SettingsListItem +import app.revanced.manager.ui.viewmodel.DeveloperOptionsViewModel +import org.koin.androidx.compose.koinViewModel + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun DeveloperOptionsScreen( + onBackClick: () -> Unit, + vm: DeveloperOptionsViewModel = koinViewModel() +) { + Scaffold( + topBar = { + AppTopBar( + title = stringResource(R.string.developer_options), + onBackClick = onBackClick + ) + } + ) { paddingValues -> + Column(modifier = Modifier.padding(paddingValues)) { + GroupHeader(stringResource(R.string.patch_bundles_section)) + SettingsListItem( + headlineContent = stringResource(R.string.patch_bundles_redownload), + modifier = Modifier.clickable(onClick = vm::redownloadBundles) + ) + SettingsListItem( + headlineContent = stringResource(R.string.patch_bundles_reset), + modifier = Modifier.clickable(onClick = vm::redownloadBundles) + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/app/revanced/manager/ui/viewmodel/AdvancedSettingsViewModel.kt b/app/src/main/java/app/revanced/manager/ui/viewmodel/AdvancedSettingsViewModel.kt index 5db843c0..cbad0045 100644 --- a/app/src/main/java/app/revanced/manager/ui/viewmodel/AdvancedSettingsViewModel.kt +++ b/app/src/main/java/app/revanced/manager/ui/viewmodel/AdvancedSettingsViewModel.kt @@ -6,12 +6,10 @@ import android.util.Log import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import app.revanced.manager.R -import app.revanced.manager.domain.bundles.RemotePatchBundle import app.revanced.manager.domain.manager.PreferencesManager import app.revanced.manager.domain.repository.PatchBundleRepository import app.revanced.manager.util.tag import app.revanced.manager.util.toast -import app.revanced.manager.util.uiSafe import com.github.pgreze.process.Redirect import com.github.pgreze.process.process import kotlinx.coroutines.CancellationException @@ -43,16 +41,6 @@ class AdvancedSettingsViewModel( patchBundleRepository.reloadApiBundles() } - fun redownloadBundles() = viewModelScope.launch { - uiSafe(app, R.string.source_download_fail, RemotePatchBundle.updateFailMsg) { - patchBundleRepository.redownloadRemoteBundles() - } - } - - fun resetBundles() = viewModelScope.launch { - patchBundleRepository.reset() - } - fun exportDebugLogs(target: Uri) = viewModelScope.launch { val exitCode = try { withContext(Dispatchers.IO) { diff --git a/app/src/main/java/app/revanced/manager/ui/viewmodel/DeveloperOptionsViewModel.kt b/app/src/main/java/app/revanced/manager/ui/viewmodel/DeveloperOptionsViewModel.kt new file mode 100644 index 00000000..bc8d0527 --- /dev/null +++ b/app/src/main/java/app/revanced/manager/ui/viewmodel/DeveloperOptionsViewModel.kt @@ -0,0 +1,27 @@ +package app.revanced.manager.ui.viewmodel + +import android.app.Application +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import app.revanced.manager.R +import app.revanced.manager.domain.bundles.RemotePatchBundle +import app.revanced.manager.domain.manager.PreferencesManager +import app.revanced.manager.domain.repository.PatchBundleRepository +import app.revanced.manager.util.uiSafe +import kotlinx.coroutines.launch + +class DeveloperOptionsViewModel( + val prefs: PreferencesManager, + private val app: Application, + private val patchBundleRepository: PatchBundleRepository +) : ViewModel() { + fun redownloadBundles() = viewModelScope.launch { + uiSafe(app, R.string.source_download_fail, RemotePatchBundle.updateFailMsg) { + patchBundleRepository.redownloadRemoteBundles() + } + } + + fun resetBundles() = viewModelScope.launch { + patchBundleRepository.reset() + } +} \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 95ca818b..f1ef966c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -71,6 +71,7 @@ Choose between light or dark theme Multi-threaded DEX file writer Use multiple cores to write DEX files. This is faster, but uses more memory + Safeguards Disable version compatibility check The check restricts patches to supported app versions Require suggested app version From 6f9a984541374499cf8592280bfff2aa7d0c1f18 Mon Sep 17 00:00:00 2001 From: Ax333l Date: Fri, 5 Jul 2024 20:31:49 +0200 Subject: [PATCH 03/11] fix: improve bundle page strings --- .../manager/ui/component/bundle/BaseBundleDialog.kt | 8 ++++---- app/src/main/res/values/plurals.xml | 4 ++++ app/src/main/res/values/strings.xml | 6 ++---- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/app/revanced/manager/ui/component/bundle/BaseBundleDialog.kt b/app/src/main/java/app/revanced/manager/ui/component/bundle/BaseBundleDialog.kt index c2e1feca..f2bb3de5 100644 --- a/app/src/main/java/app/revanced/manager/ui/component/bundle/BaseBundleDialog.kt +++ b/app/src/main/java/app/revanced/manager/ui/component/bundle/BaseBundleDialog.kt @@ -19,6 +19,7 @@ import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.pluralStringResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import app.revanced.manager.R @@ -115,8 +116,8 @@ fun BaseBundleDialog( if (remoteUrl != null) { BundleListItem( - headlineText = stringResource(R.string.automatically_update), - supportingText = stringResource(R.string.automatically_update_description), + headlineText = stringResource(R.string.bundle_auto_update), + supportingText = stringResource(R.string.bundle_auto_update_description), trailingContent = { Switch( checked = autoUpdate, @@ -163,8 +164,7 @@ fun BaseBundleDialog( val patchesClickable = LocalContext.current.isDebuggable && patchCount > 0 BundleListItem( headlineText = stringResource(R.string.patches), - supportingText = if (patchCount == 0) stringResource(R.string.no_patches) - else stringResource(R.string.patches_available, patchCount), + supportingText = pluralStringResource(R.plurals.bundle_patches_available, patchCount, patchCount), modifier = Modifier.clickable(enabled = patchesClickable, onClick = onPatchesClick) ) { if (patchesClickable) diff --git a/app/src/main/res/values/plurals.xml b/app/src/main/res/values/plurals.xml index d0178073..9bcfcc08 100644 --- a/app/src/main/res/values/plurals.xml +++ b/app/src/main/res/values/plurals.xml @@ -11,4 +11,8 @@ %d selected + + %d patch available + %d patches available + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f1ef966c..68d3dd00 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -182,8 +182,6 @@ Failed to load updated patch bundle: %s Failed to update integrations: %s No patched apps found - No patches available to view - %d Patches available, tap to view Tap on the patches to get more information about them %s selected Unsupported app @@ -300,8 +298,8 @@ Source URL Successfully updated %s No update available for %s - Automatically update - Automatically update this bundle when ReVanced starts + Auto update + Automatically update this bundle when ReVanced starts Bundle type Choose the type of bundle you want About ReVanced Manager From 032ca39cf661af15dafad6a874bab2f1c98ab9a2 Mon Sep 17 00:00:00 2001 From: Pun Butrach Date: Sat, 6 Jul 2024 01:34:13 +0700 Subject: [PATCH 04/11] feat: Automatic language detection (#2032) --- app/build.gradle.kts | 9 ++++++--- app/src/main/res/resources.properties | 1 + 2 files changed, 7 insertions(+), 3 deletions(-) create mode 100644 app/src/main/res/resources.properties diff --git a/app/build.gradle.kts b/app/build.gradle.kts index c44dd2da..ee855884 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -20,9 +20,6 @@ android { targetSdk = 34 versionCode = 1 versionName = "0.0.1" - resourceConfigurations.addAll(listOf( - "en", - )) vectorDrawables.useSupportLibrary = true } @@ -88,6 +85,12 @@ android { buildFeatures.aidl = true buildFeatures.buildConfig=true + android { + androidResources { + generateLocaleConfig = true + } + } + composeOptions.kotlinCompilerExtensionVersion = "1.5.10" externalNativeBuild { cmake { diff --git a/app/src/main/res/resources.properties b/app/src/main/res/resources.properties new file mode 100644 index 00000000..467b3efe --- /dev/null +++ b/app/src/main/res/resources.properties @@ -0,0 +1 @@ +unqualifiedResLocale=en-US From 3f4a23491512e3d16c15ee1bebd21b53c63673ce Mon Sep 17 00:00:00 2001 From: Ax333l Date: Fri, 5 Jul 2024 20:41:29 +0200 Subject: [PATCH 05/11] fix: run props flow on correct dispatcher (#2035) --- .../revanced/manager/domain/bundles/PatchBundleSource.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/app/revanced/manager/domain/bundles/PatchBundleSource.kt b/app/src/main/java/app/revanced/manager/domain/bundles/PatchBundleSource.kt index 712d6534..1ded6d43 100644 --- a/app/src/main/java/app/revanced/manager/domain/bundles/PatchBundleSource.kt +++ b/app/src/main/java/app/revanced/manager/domain/bundles/PatchBundleSource.kt @@ -9,9 +9,11 @@ import app.revanced.manager.R import app.revanced.manager.domain.repository.PatchBundlePersistenceRepository import app.revanced.manager.patcher.patch.PatchBundle import app.revanced.manager.util.tag +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map import org.koin.core.component.KoinComponent import org.koin.core.component.inject @@ -80,8 +82,8 @@ sealed class PatchBundleSource(initialName: String, val uid: Int, directory: Fil * Create a flow that emits the [app.revanced.manager.data.room.bundles.BundleProperties] of this [PatchBundleSource]. * The flow will emit null if the associated [PatchBundleSource] is deleted. */ - fun propsFlow() = configRepository.getProps(uid) - suspend fun getProps() = configRepository.getProps(uid).first()!! + fun propsFlow() = configRepository.getProps(uid).flowOn(Dispatchers.Default) + suspend fun getProps() = propsFlow().first()!! suspend fun currentVersion() = getProps().versionInfo protected suspend fun saveVersion(patches: String?, integrations: String?) = From 1ee1330e4718f1ef26715d0461297696612c7d49 Mon Sep 17 00:00:00 2001 From: Ax333l Date: Sat, 6 Jul 2024 17:43:37 +0200 Subject: [PATCH 06/11] feat: improve the safeguards (#2038) --- .../domain/manager/PreferencesManager.kt | 5 +- .../manager/ui/component/Countdown.kt | 26 ------ .../ui/component/DangerousActionDialogBase.kt | 91 ------------------- .../ui/component/NonSuggestedVersionDialog.kt | 23 ----- .../manager/ui/component/SafeguardDialog.kt | 51 +++++++++++ .../manager/ui/screen/AppSelectorScreen.kt | 3 +- .../ui/screen/PatchesSelectorScreen.kt | 87 ++++++++++-------- .../ui/screen/VersionSelectorScreen.kt | 3 +- .../screen/settings/AdvancedSettingsScreen.kt | 12 +++ .../ui/viewmodel/AppSelectorViewModel.kt | 12 +-- .../ui/viewmodel/PatchesSelectorViewModel.kt | 24 +++-- .../ui/viewmodel/VersionSelectorViewModel.kt | 6 -- app/src/main/res/values/strings.xml | 11 ++- 13 files changed, 136 insertions(+), 218 deletions(-) delete mode 100644 app/src/main/java/app/revanced/manager/ui/component/Countdown.kt delete mode 100644 app/src/main/java/app/revanced/manager/ui/component/DangerousActionDialogBase.kt delete mode 100644 app/src/main/java/app/revanced/manager/ui/component/NonSuggestedVersionDialog.kt create mode 100644 app/src/main/java/app/revanced/manager/ui/component/SafeguardDialog.kt diff --git a/app/src/main/java/app/revanced/manager/domain/manager/PreferencesManager.kt b/app/src/main/java/app/revanced/manager/domain/manager/PreferencesManager.kt index dc6d713c..08b6a94d 100644 --- a/app/src/main/java/app/revanced/manager/domain/manager/PreferencesManager.kt +++ b/app/src/main/java/app/revanced/manager/domain/manager/PreferencesManager.kt @@ -15,7 +15,6 @@ class PreferencesManager( val multithreadingDexFileWriter = booleanPreference("multithreading_dex_file_writer", true) val useProcessRuntime = booleanPreference("use_process_runtime", false) val patcherProcessMemoryLimit = intPreference("process_runtime_memory_limit", 700) - val disablePatchVersionCompatCheck = booleanPreference("disable_patch_version_compatibility_check", false) val keystoreCommonName = stringPreference("keystore_cn", KeystoreManager.DEFAULT) val keystorePass = stringPreference("keystore_pass", KeystoreManager.DEFAULT) @@ -25,8 +24,8 @@ class PreferencesManager( val firstLaunch = booleanPreference("first_launch", true) val managerAutoUpdates = booleanPreference("manager_auto_updates", false) + val disablePatchVersionCompatCheck = booleanPreference("disable_patch_version_compatibility_check", false) val disableSelectionWarning = booleanPreference("disable_selection_warning", false) - val enableSelectionWarningCountdown = booleanPreference("enable_selection_warning_countdown", true) - + val disableUniversalPatchWarning = booleanPreference("disable_universal_patch_warning", false) val suggestedVersionSafeguard = booleanPreference("suggested_version_safeguard", true) } diff --git a/app/src/main/java/app/revanced/manager/ui/component/Countdown.kt b/app/src/main/java/app/revanced/manager/ui/component/Countdown.kt deleted file mode 100644 index 0fb23c27..00000000 --- a/app/src/main/java/app/revanced/manager/ui/component/Countdown.kt +++ /dev/null @@ -1,26 +0,0 @@ -package app.revanced.manager.ui.component - -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.runtime.setValue -import kotlinx.coroutines.delay - -@Composable -fun Countdown(start: Int, content: @Composable (Int) -> Unit) { - var timer by rememberSaveable(start) { - mutableStateOf(start) - } - LaunchedEffect(timer) { - if (timer == 0) { - return@LaunchedEffect - } - - delay(1000L) - timer -= 1 - } - - content(timer) -} \ No newline at end of file diff --git a/app/src/main/java/app/revanced/manager/ui/component/DangerousActionDialogBase.kt b/app/src/main/java/app/revanced/manager/ui/component/DangerousActionDialogBase.kt deleted file mode 100644 index ca11b31d..00000000 --- a/app/src/main/java/app/revanced/manager/ui/component/DangerousActionDialogBase.kt +++ /dev/null @@ -1,91 +0,0 @@ -package app.revanced.manager.ui.component - -import androidx.annotation.StringRes -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.outlined.WarningAmber -import androidx.compose.material3.AlertDialog -import androidx.compose.material3.Checkbox -import androidx.compose.material3.Icon -import androidx.compose.material3.MaterialTheme -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.saveable.rememberSaveable -import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.unit.dp -import app.revanced.manager.R - -@Composable -fun DangerousActionDialogBase( - onCancel: () -> Unit, - confirmButton: @Composable (Boolean) -> Unit, - @StringRes title: Int, - body: String, -) { - var dismissPermanently by rememberSaveable { - mutableStateOf(false) - } - - AlertDialog( - onDismissRequest = onCancel, - confirmButton = { - confirmButton(dismissPermanently) - }, - dismissButton = { - TextButton(onClick = onCancel) { - Text(stringResource(R.string.cancel)) - } - }, - icon = { - Icon(Icons.Outlined.WarningAmber, null) - }, - title = { - Text( - text = stringResource(title), - style = MaterialTheme.typography.headlineSmall.copy(textAlign = TextAlign.Center), - color = MaterialTheme.colorScheme.onSurface, - ) - }, - text = { - Column( - verticalArrangement = Arrangement.spacedBy(16.dp), - horizontalAlignment = Alignment.Start - ) { - Text( - text = body, - style = MaterialTheme.typography.bodyMedium, - color = MaterialTheme.colorScheme.onSurfaceVariant - ) - - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(0.dp), - modifier = Modifier - .fillMaxWidth() - .clickable { - dismissPermanently = !dismissPermanently - } - ) { - Checkbox( - checked = dismissPermanently, - onCheckedChange = { - dismissPermanently = it - } - ) - Text(stringResource(R.string.permanent_dismiss)) - } - } - } - ) -} \ No newline at end of file diff --git a/app/src/main/java/app/revanced/manager/ui/component/NonSuggestedVersionDialog.kt b/app/src/main/java/app/revanced/manager/ui/component/NonSuggestedVersionDialog.kt deleted file mode 100644 index b55dd5f5..00000000 --- a/app/src/main/java/app/revanced/manager/ui/component/NonSuggestedVersionDialog.kt +++ /dev/null @@ -1,23 +0,0 @@ -package app.revanced.manager.ui.component - -import androidx.compose.material3.Text -import androidx.compose.material3.TextButton -import androidx.compose.runtime.Composable -import androidx.compose.ui.res.stringResource -import app.revanced.manager.R - -@Composable -fun NonSuggestedVersionDialog(suggestedVersion: String, onCancel: () -> Unit, onContinue: (Boolean) -> Unit) { - DangerousActionDialogBase( - onCancel = onCancel, - confirmButton = { dismissPermanently -> - TextButton( - onClick = { onContinue(dismissPermanently) } - ) { - Text(stringResource(R.string.continue_)) - } - }, - title = R.string.non_suggested_version_warning_title, - body = stringResource(R.string.non_suggested_version_warning_description, suggestedVersion), - ) -} \ No newline at end of file diff --git a/app/src/main/java/app/revanced/manager/ui/component/SafeguardDialog.kt b/app/src/main/java/app/revanced/manager/ui/component/SafeguardDialog.kt new file mode 100644 index 00000000..6aabe12a --- /dev/null +++ b/app/src/main/java/app/revanced/manager/ui/component/SafeguardDialog.kt @@ -0,0 +1,51 @@ +package app.revanced.manager.ui.component + +import androidx.annotation.StringRes +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.WarningAmber +import androidx.compose.material3.AlertDialog +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.runtime.Composable +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import app.revanced.manager.R + +@Composable +fun SafeguardDialog( + onDismiss: () -> Unit, + @StringRes title: Int, + body: String, +) { + AlertDialog( + onDismissRequest = onDismiss, + confirmButton = { + TextButton(onClick = onDismiss) { + Text(stringResource(R.string.ok)) + } + }, + icon = { + Icon(Icons.Outlined.WarningAmber, null) + }, + title = { + Text( + text = stringResource(title), + style = MaterialTheme.typography.headlineSmall.copy(textAlign = TextAlign.Center) + ) + }, + text = { + Text(body) + } + ) +} + +@Composable +fun NonSuggestedVersionDialog(suggestedVersion: String, onDismiss: () -> Unit) { + SafeguardDialog( + onDismiss = onDismiss, + title = R.string.non_suggested_version_warning_title, + body = stringResource(R.string.non_suggested_version_warning_description, suggestedVersion), + ) +} \ No newline at end of file diff --git a/app/src/main/java/app/revanced/manager/ui/screen/AppSelectorScreen.kt b/app/src/main/java/app/revanced/manager/ui/screen/AppSelectorScreen.kt index c8011744..6d2e1d5f 100644 --- a/app/src/main/java/app/revanced/manager/ui/screen/AppSelectorScreen.kt +++ b/app/src/main/java/app/revanced/manager/ui/screen/AppSelectorScreen.kt @@ -70,8 +70,7 @@ fun AppSelectorScreen( vm.nonSuggestedVersionDialogSubject?.let { NonSuggestedVersionDialog( suggestedVersion = suggestedVersions[it.packageName].orEmpty(), - onCancel = vm::dismissNonSuggestedVersionDialog, - onContinue = vm::continueWithNonSuggestedVersion, + onDismiss = vm::dismissNonSuggestedVersionDialog ) } diff --git a/app/src/main/java/app/revanced/manager/ui/screen/PatchesSelectorScreen.kt b/app/src/main/java/app/revanced/manager/ui/screen/PatchesSelectorScreen.kt index 12d02425..e6a32f25 100644 --- a/app/src/main/java/app/revanced/manager/ui/screen/PatchesSelectorScreen.kt +++ b/app/src/main/java/app/revanced/manager/ui/screen/PatchesSelectorScreen.kt @@ -20,6 +20,7 @@ import androidx.compose.material.icons.outlined.Restore 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 @@ -37,7 +38,6 @@ 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 @@ -48,17 +48,16 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha 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 androidx.compose.ui.window.DialogProperties import androidx.lifecycle.compose.collectAsStateWithLifecycle import app.revanced.manager.R -import app.revanced.manager.domain.manager.PreferencesManager import app.revanced.manager.patcher.patch.Option import app.revanced.manager.patcher.patch.PatchInfo import app.revanced.manager.ui.component.AppTopBar -import app.revanced.manager.ui.component.Countdown -import app.revanced.manager.ui.component.DangerousActionDialogBase +import app.revanced.manager.ui.component.SafeguardDialog import app.revanced.manager.ui.component.LazyColumnWithScrollbar import app.revanced.manager.ui.component.SearchView import app.revanced.manager.ui.component.patches.OptionItem @@ -70,7 +69,6 @@ import app.revanced.manager.util.Options import app.revanced.manager.util.PatchSelection import app.revanced.manager.util.isScrollingUp import kotlinx.coroutines.launch -import org.koin.compose.koinInject @OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class) @Composable @@ -160,10 +158,16 @@ fun PatchesSelectorScreen( ) } - vm.pendingSelectionAction?.let { - SelectionWarningDialog( - onCancel = vm::dismissSelectionWarning, - onConfirm = vm::confirmSelectionWarning + var showSelectionWarning by rememberSaveable { + mutableStateOf(false) + } + if (showSelectionWarning) { + SelectionWarningDialog(onDismiss = { showSelectionWarning = false }) + } + vm.pendingUniversalPatchAction?.let { + UniversalPatchWarningDialog( + onCancel = vm::dismissUniversalPatchWarning, + onConfirm = vm::confirmUniversalPatchWarning ) } @@ -196,9 +200,9 @@ fun PatchesSelectorScreen( ), onToggle = { if (vm.selectionWarningEnabled) { - vm.pendingSelectionAction = { - vm.togglePatch(uid, patch) - } + showSelectionWarning = true + } else if (vm.universalPatchWarningEnabled && patch.compatiblePackages == null) { + vm.pendingUniversalPatchAction = { vm.togglePatch(uid, patch) } } else { vm.togglePatch(uid, patch) } @@ -369,36 +373,43 @@ fun PatchesSelectorScreen( } @Composable -fun SelectionWarningDialog( +fun SelectionWarningDialog(onDismiss: () -> Unit) { + SafeguardDialog( + onDismiss = onDismiss, + title = R.string.warning, + body = stringResource(R.string.selection_warning_description), + ) +} + +@Composable +fun UniversalPatchWarningDialog( onCancel: () -> Unit, - onConfirm: (Boolean) -> Unit + onConfirm: () -> Unit ) { - val prefs: PreferencesManager = koinInject() - - DangerousActionDialogBase( - onCancel = onCancel, - confirmButton = { dismissPermanently -> - val enableCountdown by prefs.enableSelectionWarningCountdown.getAsState() - - Countdown(start = if (enableCountdown) 3 else 0) { timer -> - LaunchedEffect(timer) { - if (timer == 0) prefs.enableSelectionWarningCountdown.update(false) - } - - TextButton( - onClick = { onConfirm(dismissPermanently) }, - enabled = timer == 0 - ) { - val text = - if (timer == 0) stringResource(R.string.continue_) else stringResource( - R.string.selection_warning_continue_countdown, timer - ) - Text(text, color = MaterialTheme.colorScheme.error) - } + AlertDialog( + onDismissRequest = onCancel, + confirmButton = { + TextButton(onClick = onConfirm) { + Text(stringResource(R.string.continue_)) } }, - title = R.string.selection_warning_title, - body = stringResource(R.string.selection_warning_description), + dismissButton = { + TextButton(onClick = onCancel) { + Text(stringResource(R.string.cancel)) + } + }, + icon = { + Icon(Icons.Outlined.WarningAmber, null) + }, + title = { + Text( + text = stringResource(R.string.warning), + style = MaterialTheme.typography.headlineSmall.copy(textAlign = TextAlign.Center) + ) + }, + text = { + Text(stringResource(R.string.universal_patch_warning_description)) + } ) } diff --git a/app/src/main/java/app/revanced/manager/ui/screen/VersionSelectorScreen.kt b/app/src/main/java/app/revanced/manager/ui/screen/VersionSelectorScreen.kt index 388b5dee..69548d3c 100644 --- a/app/src/main/java/app/revanced/manager/ui/screen/VersionSelectorScreen.kt +++ b/app/src/main/java/app/revanced/manager/ui/screen/VersionSelectorScreen.kt @@ -69,8 +69,7 @@ fun VersionSelectorScreen( if (viewModel.showNonSuggestedVersionDialog) NonSuggestedVersionDialog( suggestedVersion = viewModel.requiredVersion.orEmpty(), - onCancel = viewModel::dismissNonSuggestedVersionDialog, - onContinue = viewModel::continueWithNonSuggestedVersion, + onDismiss = viewModel::dismissNonSuggestedVersionDialog ) val lazyListState = rememberLazyListState() diff --git a/app/src/main/java/app/revanced/manager/ui/screen/settings/AdvancedSettingsScreen.kt b/app/src/main/java/app/revanced/manager/ui/screen/settings/AdvancedSettingsScreen.kt index 146ff325..e596ea3e 100644 --- a/app/src/main/java/app/revanced/manager/ui/screen/settings/AdvancedSettingsScreen.kt +++ b/app/src/main/java/app/revanced/manager/ui/screen/settings/AdvancedSettingsScreen.kt @@ -126,12 +126,24 @@ fun AdvancedSettingsScreen( headline = R.string.patch_compat_check, description = R.string.patch_compat_check_description ) + BooleanItem( + preference = vm.prefs.disableUniversalPatchWarning, + coroutineScope = vm.viewModelScope, + headline = R.string.universal_patches_safeguard, + description = R.string.universal_patches_safeguard_description + ) BooleanItem( preference = vm.prefs.suggestedVersionSafeguard, coroutineScope = vm.viewModelScope, headline = R.string.suggested_version_safeguard, description = R.string.suggested_version_safeguard_description ) + BooleanItem( + preference = vm.prefs.disableSelectionWarning, + coroutineScope = vm.viewModelScope, + headline = R.string.patch_selection_safeguard, + description = R.string.patch_selection_safeguard_description + ) GroupHeader(stringResource(R.string.device)) SettingsListItem( diff --git a/app/src/main/java/app/revanced/manager/ui/viewmodel/AppSelectorViewModel.kt b/app/src/main/java/app/revanced/manager/ui/viewmodel/AppSelectorViewModel.kt index 24a63960..a2174852 100644 --- a/app/src/main/java/app/revanced/manager/ui/viewmodel/AppSelectorViewModel.kt +++ b/app/src/main/java/app/revanced/manager/ui/viewmodel/AppSelectorViewModel.kt @@ -3,14 +3,12 @@ package app.revanced.manager.ui.viewmodel import android.app.Application import android.content.pm.PackageInfo import android.net.Uri -import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import app.revanced.manager.R -import app.revanced.manager.domain.manager.PreferencesManager import app.revanced.manager.domain.repository.PatchBundleRepository import app.revanced.manager.ui.model.SelectedApp import app.revanced.manager.util.PM @@ -25,8 +23,7 @@ import java.nio.file.Files class AppSelectorViewModel( private val app: Application, private val pm: PM, - private val patchBundleRepository: PatchBundleRepository, - private val prefs: PreferencesManager, + private val patchBundleRepository: PatchBundleRepository ) : ViewModel() { private val inputFile = File(app.cacheDir, "input.apk").also { it.delete() @@ -46,13 +43,6 @@ class AppSelectorViewModel( nonSuggestedVersionDialogSubject = null } - fun continueWithNonSuggestedVersion(dismissPermanently: Boolean) = viewModelScope.launch { - if (dismissPermanently) prefs.suggestedVersionSafeguard.update(false) - - nonSuggestedVersionDialogSubject?.let(onStorageClick) - dismissNonSuggestedVersionDialog() - } - fun handleStorageResult(uri: Uri) = viewModelScope.launch { val selectedApp = withContext(Dispatchers.IO) { loadSelectedFile(uri) diff --git a/app/src/main/java/app/revanced/manager/ui/viewmodel/PatchesSelectorViewModel.kt b/app/src/main/java/app/revanced/manager/ui/viewmodel/PatchesSelectorViewModel.kt index 47fbc556..331548d6 100644 --- a/app/src/main/java/app/revanced/manager/ui/viewmodel/PatchesSelectorViewModel.kt +++ b/app/src/main/java/app/revanced/manager/ui/viewmodel/PatchesSelectorViewModel.kt @@ -47,10 +47,12 @@ class PatchesSelectorViewModel(input: Params) : ViewModel(), KoinComponent { private val packageName = input.app.packageName val appVersion = input.app.version - var pendingSelectionAction by mutableStateOf<(() -> Unit)?>(null) + var pendingUniversalPatchAction by mutableStateOf<(() -> Unit)?>(null) var selectionWarningEnabled by mutableStateOf(true) private set + var universalPatchWarningEnabled by mutableStateOf(true) + private set val allowIncompatiblePatches = get().disablePatchVersionCompatCheck.getBlocking() @@ -59,6 +61,8 @@ class PatchesSelectorViewModel(input: Params) : ViewModel(), KoinComponent { init { viewModelScope.launch { + universalPatchWarningEnabled = !prefs.disableUniversalPatchWarning.get() + if (prefs.disableSelectionWarning.get()) { selectionWarningEnabled = false return@launch @@ -131,21 +135,15 @@ class PatchesSelectorViewModel(input: Params) : ViewModel(), KoinComponent { customPatchSelection = selection.put(bundle, newPatches) } - fun confirmSelectionWarning(dismissPermanently: Boolean) { - selectionWarningEnabled = false + fun confirmUniversalPatchWarning() { + universalPatchWarningEnabled = false - pendingSelectionAction?.invoke() - pendingSelectionAction = null - - if (!dismissPermanently) return - - viewModelScope.launch { - prefs.disableSelectionWarning.update(true) - } + pendingUniversalPatchAction?.invoke() + pendingUniversalPatchAction = null } - fun dismissSelectionWarning() { - pendingSelectionAction = null + fun dismissUniversalPatchWarning() { + pendingUniversalPatchAction = null } fun reset() { diff --git a/app/src/main/java/app/revanced/manager/ui/viewmodel/VersionSelectorViewModel.kt b/app/src/main/java/app/revanced/manager/ui/viewmodel/VersionSelectorViewModel.kt index 306397ad..d9f73264 100644 --- a/app/src/main/java/app/revanced/manager/ui/viewmodel/VersionSelectorViewModel.kt +++ b/app/src/main/java/app/revanced/manager/ui/viewmodel/VersionSelectorViewModel.kt @@ -162,12 +162,6 @@ class VersionSelectorViewModel( nonSuggestedVersionDialogSubject = null } - fun continueWithNonSuggestedVersion(dismissPermanently: Boolean) = viewModelScope.launch { - if (dismissPermanently) prefs.suggestedVersionSafeguard.update(false) - selectedVersion = nonSuggestedVersionDialogSubject - dismissNonSuggestedVersionDialog() - } - fun select(app: SelectedApp) { if (requiredVersion != null && app.version != requiredVersion) { nonSuggestedVersionDialogSubject = app diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 68d3dd00..a1451563 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -76,6 +76,10 @@ The check restricts patches to supported app versions Require suggested app version Enforce selection of the suggested app version + Allow changing patch selection + Do not prevent selecting or deselecting patches + Disable universal patch warning + Disables the warning that appears when you try to select universal patches Import keystore Import a custom keystore Enter keystore credentials @@ -134,6 +138,7 @@ Apply Help Back + Warning Add Close System @@ -190,10 +195,10 @@ Patch selection and options has been reset to recommended defaults Patch options have been reset Non suggested version - The version of the app you have selected does not match the suggested version.\nPlease use the suggested version: %s + The version of the app you have selected does not match the suggested version.\nPlease use the suggested version: %s\n\nTo continue anyway, disable \"Require suggested app version\" in the advanced settings. Stop using defaults? - You may encounter issues when not using the default patch selection and options. - Continue (%ds) + It is recommended to use the default patch selection and options. Changing them may result in unexpected issues.\n\nYou need to turn on \"Allow changing patch selection\" in the advanced settings before toggling patches. + Universal patches have a more generalized use and do not work as reliably as patches that target specific apps. You may encounter issues while using them.\n\nThis warning can be disabled in the advanced settings. Supported Universal Unsupported From a995f43b7b0a97e23e25564317261898e97365a5 Mon Sep 17 00:00:00 2001 From: Ax333l Date: Sat, 6 Jul 2024 18:12:27 +0200 Subject: [PATCH 07/11] fix: move battery warning to dashboard --- .../manager/ui/screen/DashboardScreen.kt | 21 +++++++++++ .../manager/ui/screen/SettingsScreen.kt | 35 ------------------- .../ui/viewmodel/DashboardViewModel.kt | 20 ++++++++--- app/src/main/res/values/strings.xml | 2 +- 4 files changed, 37 insertions(+), 41 deletions(-) diff --git a/app/src/main/java/app/revanced/manager/ui/screen/DashboardScreen.kt b/app/src/main/java/app/revanced/manager/ui/screen/DashboardScreen.kt index 5f5ff1fa..288bc0e1 100644 --- a/app/src/main/java/app/revanced/manager/ui/screen/DashboardScreen.kt +++ b/app/src/main/java/app/revanced/manager/ui/screen/DashboardScreen.kt @@ -1,5 +1,9 @@ package app.revanced.manager.ui.screen +import android.annotation.SuppressLint +import android.content.Intent +import android.net.Uri +import android.provider.Settings import androidx.activity.compose.BackHandler import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.layout.Arrangement @@ -10,6 +14,7 @@ import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add +import androidx.compose.material.icons.filled.BatteryAlert import androidx.compose.material.icons.filled.Close import androidx.compose.material.icons.outlined.Apps import androidx.compose.material.icons.outlined.DeleteOutline @@ -69,6 +74,7 @@ enum class DashboardPage( BUNDLES(R.string.tab_bundles, Icons.Outlined.Source), } +@SuppressLint("BatteryLife") @OptIn(ExperimentalFoundationApi::class, ExperimentalMaterial3Api::class) @Composable fun DashboardScreen( @@ -229,6 +235,21 @@ fun DashboardScreen( ) } } else null, + if (vm.showBatteryOptimizationsWarning) { + { + NotificationCard( + modifier = Modifier.padding(16.dp), + isWarning = true, + icon = Icons.Default.BatteryAlert, + text = stringResource(R.string.battery_optimization_notification), + onClick = { + androidContext.startActivity(Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS).apply { + data = Uri.parse("package:${androidContext.packageName}") + }) + } + ) + } + } else null, vm.updatedManagerVersion?.let { { NotificationCard( diff --git a/app/src/main/java/app/revanced/manager/ui/screen/SettingsScreen.kt b/app/src/main/java/app/revanced/manager/ui/screen/SettingsScreen.kt index 690b2016..f43ecb4b 100644 --- a/app/src/main/java/app/revanced/manager/ui/screen/SettingsScreen.kt +++ b/app/src/main/java/app/revanced/manager/ui/screen/SettingsScreen.kt @@ -1,32 +1,17 @@ package app.revanced.manager.ui.screen -import android.annotation.SuppressLint -import android.content.Context -import android.content.Intent -import android.net.Uri -import android.os.PowerManager -import android.provider.Settings -import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.BatteryAlert import androidx.compose.material.icons.outlined.* import androidx.compose.material3.* import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource -import androidx.compose.ui.unit.dp import app.revanced.manager.R import app.revanced.manager.ui.component.AppTopBar import app.revanced.manager.ui.component.ColumnWithScrollbar -import app.revanced.manager.ui.component.NotificationCard import app.revanced.manager.ui.component.settings.SettingsListItem import app.revanced.manager.ui.destination.SettingsDestination import app.revanced.manager.ui.screen.settings.* @@ -38,7 +23,6 @@ import dev.olshevski.navigation.reimagined.* import org.koin.androidx.compose.koinViewModel import org.koin.core.parameter.parametersOf -@SuppressLint("BatteryLife") @OptIn(ExperimentalMaterial3Api::class) @Composable fun SettingsScreen( @@ -54,10 +38,6 @@ fun SettingsScreen( else navController.pop() } - val context = LocalContext.current - val pm = context.getSystemService(Context.POWER_SERVICE) as PowerManager - var showBatteryButton by remember { mutableStateOf(!pm.isIgnoringBatteryOptimizations(context.packageName)) } - val settingsSections = listOf( Triple( R.string.general, @@ -163,21 +143,6 @@ fun SettingsScreen( .padding(paddingValues) .fillMaxSize() ) { - AnimatedVisibility(visible = showBatteryButton) { - NotificationCard( - modifier = Modifier.padding(16.dp), - isWarning = true, - icon = Icons.Default.BatteryAlert, - text = stringResource(R.string.battery_optimization_notification), - onClick = { - context.startActivity(Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS).apply { - data = Uri.parse("package:${context.packageName}") - }) - showBatteryButton = - !pm.isIgnoringBatteryOptimizations(context.packageName) - } - ) - } settingsSections.forEach { (titleDescIcon, destination) -> SettingsListItem( modifier = Modifier.clickable { navController.navigate(destination) }, diff --git a/app/src/main/java/app/revanced/manager/ui/viewmodel/DashboardViewModel.kt b/app/src/main/java/app/revanced/manager/ui/viewmodel/DashboardViewModel.kt index c2dd6d64..9d2e1224 100644 --- a/app/src/main/java/app/revanced/manager/ui/viewmodel/DashboardViewModel.kt +++ b/app/src/main/java/app/revanced/manager/ui/viewmodel/DashboardViewModel.kt @@ -3,10 +3,12 @@ package app.revanced.manager.ui.viewmodel import android.app.Application import android.content.ContentResolver import android.net.Uri +import android.os.PowerManager import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue +import androidx.core.content.getSystemService import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import app.revanced.manager.R @@ -33,15 +35,21 @@ class DashboardViewModel( val availablePatches = patchBundleRepository.bundles.map { it.values.sumOf { bundle -> bundle.patches.size } } private val contentResolver: ContentResolver = app.contentResolver + private val powerManager = app.getSystemService()!! val sources = patchBundleRepository.sources val selectedSources = mutableStateListOf() - var updatedManagerVersion: String? by mutableStateOf(null) private set + var showBatteryOptimizationsWarning by mutableStateOf(false) + private set init { - viewModelScope.launch { checkForManagerUpdates() } + viewModelScope.launch { + checkForManagerUpdates() + showBatteryOptimizationsWarning = + !powerManager.isIgnoringBatteryOptimizations(app.packageName) + } } fun dismissUpdateDialog() { @@ -80,12 +88,14 @@ class DashboardViewModel( fun cancelSourceSelection() { selectedSources.clear() } + fun createLocalSource(patchBundle: Uri, integrations: Uri?) = viewModelScope.launch { contentResolver.openInputStream(patchBundle)!!.use { patchesStream -> - integrations?.let { contentResolver.openInputStream(it) }.use { integrationsStream -> - patchBundleRepository.createLocal(patchesStream, integrationsStream) - } + integrations?.let { contentResolver.openInputStream(it) } + .use { integrationsStream -> + patchBundleRepository.createLocal(patchesStream, integrationsStream) + } } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a1451563..80743ccc 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -323,7 +323,7 @@ Loading changelog Failed to download changelog: %s Check out the latest changes in this update - Battery optimization must be turned off in order for ReVanced Manager to work correctly in the background. Click here to turn off. + Battery optimizations must be turned off in order for ReVanced Manager to work correctly in the background. Click here to turn off optimizations. Installing update… Downloading update… Failed to download update: %s From 36f864efbb272582b7fc612af2738bdfae18d5c0 Mon Sep 17 00:00:00 2001 From: Ax333l Date: Sat, 6 Jul 2024 22:47:27 +0200 Subject: [PATCH 08/11] chore: update dependencies --- .../manager/ui/viewmodel/MainViewModel.kt | 3 ++- gradle/libs.versions.toml | 18 +++++++++--------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/app/revanced/manager/ui/viewmodel/MainViewModel.kt b/app/src/main/java/app/revanced/manager/ui/viewmodel/MainViewModel.kt index 4f0fbcd9..1b9aab30 100644 --- a/app/src/main/java/app/revanced/manager/ui/viewmodel/MainViewModel.kt +++ b/app/src/main/java/app/revanced/manager/ui/viewmodel/MainViewModel.kt @@ -1,5 +1,6 @@ package app.revanced.manager.ui.viewmodel +import android.app.Activity import android.app.Application import android.content.ActivityNotFoundException import android.content.Intent @@ -39,7 +40,7 @@ class MainViewModel( val launcher = componentActivity.registerForActivityResult( ActivityResultContracts.StartActivityForResult() ) { result: ActivityResult -> - if (result.resultCode == ComponentActivity.RESULT_OK) { + if (result.resultCode == Activity.RESULT_OK) { result.data?.getStringExtra("data")?.let { applyLegacySettings(it) } ?: app.toast(app.getString(R.string.legacy_import_failed)) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e448af17..ee400881 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,14 +1,14 @@ [versions] -ktx = "1.12.0" +ktx = "1.13.1" material3 = "1.2.1" -ui-tooling = "1.6.4" -viewmodel-lifecycle = "2.7.0" +ui-tooling = "1.6.8" +viewmodel-lifecycle = "2.8.3" splash-screen = "1.0.1" -compose-activity = "1.8.2" -paging = "3.2.1" -preferences-datastore = "1.0.0" +compose-activity = "1.9.0" +paging = "3.3.0" +preferences-datastore = "1.1.1" work-runtime = "2.9.0" -compose-bom = "2024.03.00" +compose-bom = "2024.06.00" accompanist = "0.34.0" placeholder = "1.1.2" reorderable = "1.5.2" @@ -21,9 +21,9 @@ koin-version = "3.5.3" koin-version-compose = "3.5.3" reimagined-navigation = "1.5.0" ktor = "2.3.9" -markdown-renderer = "0.13.0" +markdown-renderer = "0.22.0" fading-edges = "1.0.4" -androidGradlePlugin = "8.3.0" +androidGradlePlugin = "8.3.2" kotlinGradlePlugin = "1.9.22" devToolsGradlePlugin = "1.9.22-1.0.17" aboutLibrariesGradlePlugin = "11.1.1" From f655a6e03a5a113abfc6b189ea79c9a135b65f92 Mon Sep 17 00:00:00 2001 From: Pun Butrach Date: Sun, 7 Jul 2024 15:42:56 +0700 Subject: [PATCH 09/11] ci: Bump dependencies to latest (#2039) --- .github/workflows/pr-build.yml | 6 +++--- .github/workflows/release-build.yml | 6 ++---- .github/workflows/update-documentation.yml | 2 +- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/.github/workflows/pr-build.yml b/.github/workflows/pr-build.yml index e4a04351..f912fedb 100644 --- a/.github/workflows/pr-build.yml +++ b/.github/workflows/pr-build.yml @@ -23,8 +23,8 @@ jobs: java-version: '17' distribution: 'temurin' - - name: Setup Gradle - uses: gradle/gradle-build-action@v2 + - name: Set up Gradle + uses: gradle/actions/setup-gradle@v3 - name: Build with Gradle env: @@ -38,7 +38,7 @@ jobs: run: mv app/build/outputs/apk/release/app-release.apk revanced-manager-${{ env.COMMIT_HASH }}.apk - name: Upload build - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: revanced-manager path: revanced-manager-${{ env.COMMIT_HASH }}.apk diff --git a/.github/workflows/release-build.yml b/.github/workflows/release-build.yml index 8e273987..9574e59b 100644 --- a/.github/workflows/release-build.yml +++ b/.github/workflows/release-build.yml @@ -20,10 +20,8 @@ jobs: java-version: '17' distribution: 'temurin' - - name: Setup Gradle - uses: gradle/gradle-build-action@v2 - with: - cache-disabled: true + - name: Set up Gradle + uses: gradle/actions/setup-gradle@v3 - name: Build with Gradle env: diff --git a/.github/workflows/update-documentation.yml b/.github/workflows/update-documentation.yml index 77097e2f..541a7aa5 100644 --- a/.github/workflows/update-documentation.yml +++ b/.github/workflows/update-documentation.yml @@ -11,7 +11,7 @@ jobs: name: Dispatch event to documentation repository if: github.ref == 'refs/heads/main' steps: - - uses: peter-evans/repository-dispatch@v2 + - uses: peter-evans/repository-dispatch@v3 with: token: ${{ secrets.DOCUMENTATION_REPO_ACCESS_TOKEN }} repository: revanced/revanced-documentation From 40492b67d16696fcea051b1fb1d2d5e0d3dae926 Mon Sep 17 00:00:00 2001 From: validcube Date: Sun, 7 Jul 2024 17:54:04 +0700 Subject: [PATCH 10/11] refactor: Use TextButton instead of FilledButton for consistency --- .../manager/ui/screen/settings/GeneralSettingsScreen.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/app/revanced/manager/ui/screen/settings/GeneralSettingsScreen.kt b/app/src/main/java/app/revanced/manager/ui/screen/settings/GeneralSettingsScreen.kt index 4fb32ea7..f41e6a66 100644 --- a/app/src/main/java/app/revanced/manager/ui/screen/settings/GeneralSettingsScreen.kt +++ b/app/src/main/java/app/revanced/manager/ui/screen/settings/GeneralSettingsScreen.kt @@ -112,7 +112,7 @@ private fun ThemePicker( } }, confirmButton = { - Button( + TextButton( onClick = { onConfirm(selectedTheme) onDismiss() From 37e9630b9c8ed50b83cbd615f133336e8220d109 Mon Sep 17 00:00:00 2001 From: validcube Date: Sun, 7 Jul 2024 17:58:51 +0700 Subject: [PATCH 11/11] fix: Inconsistent padding for battery optimisation warning The problem came after moving the card to DashboardScreen, this is because the card specified padding modifier but others does not. This commit remove the modifier completely. --- .../main/java/app/revanced/manager/ui/screen/DashboardScreen.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/app/revanced/manager/ui/screen/DashboardScreen.kt b/app/src/main/java/app/revanced/manager/ui/screen/DashboardScreen.kt index 288bc0e1..4ee44a4b 100644 --- a/app/src/main/java/app/revanced/manager/ui/screen/DashboardScreen.kt +++ b/app/src/main/java/app/revanced/manager/ui/screen/DashboardScreen.kt @@ -238,7 +238,6 @@ fun DashboardScreen( if (vm.showBatteryOptimizationsWarning) { { NotificationCard( - modifier = Modifier.padding(16.dp), isWarning = true, icon = Icons.Default.BatteryAlert, text = stringResource(R.string.battery_optimization_notification),