From 9d9a0e81dbc9e73e6e3181f6bea9cabb69e49ea8 Mon Sep 17 00:00:00 2001 From: Ax333l Date: Tue, 6 Jan 2026 22:37:25 +0100 Subject: [PATCH] fix: allow updating patches on metered networks --- .../manager/data/platform/NetworkInfo.kt | 2 +- .../domain/manager/PreferencesManager.kt | 2 + .../repository/PatchBundleRepository.kt | 51 +++++++++++-------- .../screen/settings/GeneralSettingsScreen.kt | 8 +++ .../ui/viewmodel/BundleListViewModel.kt | 3 +- .../manager/ui/viewmodel/UpdateViewModel.kt | 2 +- app/src/main/res/values/strings.xml | 4 ++ 7 files changed, 47 insertions(+), 25 deletions(-) diff --git a/app/src/main/java/app/revanced/manager/data/platform/NetworkInfo.kt b/app/src/main/java/app/revanced/manager/data/platform/NetworkInfo.kt index f5d3dd89..d8381bb8 100644 --- a/app/src/main/java/app/revanced/manager/data/platform/NetworkInfo.kt +++ b/app/src/main/java/app/revanced/manager/data/platform/NetworkInfo.kt @@ -15,5 +15,5 @@ class NetworkInfo(app: Application) { /** * Returns true if it is safe to download large files. */ - fun isSafe() = isConnected() && isUnmetered() + fun isSafe(ignoreMetered: Boolean) = isConnected() && (ignoreMetered || isUnmetered()) } \ No newline at end of file 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 ef69c3e2..c629370d 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 @@ -34,4 +34,6 @@ class PreferencesManager( val acknowledgedDownloaderPlugins = stringSetPreference("acknowledged_downloader_plugins", emptySet()) val showDeveloperSettings = booleanPreference("show_developer_settings", context.isDebuggable) + + val allowMeteredNetworks = booleanPreference("allow_metered_networks", false) } diff --git a/app/src/main/java/app/revanced/manager/domain/repository/PatchBundleRepository.kt b/app/src/main/java/app/revanced/manager/domain/repository/PatchBundleRepository.kt index ab8dbb19..54325dd0 100644 --- a/app/src/main/java/app/revanced/manager/domain/repository/PatchBundleRepository.kt +++ b/app/src/main/java/app/revanced/manager/domain/repository/PatchBundleRepository.kt @@ -286,28 +286,29 @@ class PatchBundleRepository( State(sources.toPersistentMap(), info.toPersistentMap()) } - suspend fun createLocal(createStream: suspend () -> InputStream) = dispatchAction("Add bundle") { - with(createEntity("", SourceInfo.Local).load() as LocalPatchBundle) { - try { - createStream().use { patches -> replace(patches) } - } catch (e: Exception) { - if (e is CancellationException) throw e - Log.e(tag, "Got exception while importing bundle", e) - withContext(Dispatchers.Main) { - app.toast(app.getString(R.string.patches_replace_fail, e.simpleMessage())) + suspend fun createLocal(createStream: suspend () -> InputStream) = + dispatchAction("Add bundle") { + with(createEntity("", SourceInfo.Local).load() as LocalPatchBundle) { + try { + createStream().use { patches -> replace(patches) } + } catch (e: Exception) { + if (e is CancellationException) throw e + Log.e(tag, "Got exception while importing bundle", e) + withContext(Dispatchers.Main) { + app.toast(app.getString(R.string.patches_replace_fail, e.simpleMessage())) + } + + deleteLocalFile() } - - deleteLocalFile() } - } - doReload() - } + doReload() + } suspend fun createRemote(url: String, autoUpdate: Boolean) = dispatchAction("Add bundle ($url)") { state -> val src = createEntity("", SourceInfo.from(url), autoUpdate).load() as RemotePatchBundle - update(src) + update(src, force = true) state.copy(sources = state.sources.put(src.uid, src)) } @@ -329,32 +330,38 @@ class PatchBundleRepository( state.copy(sources = state.sources.put(uid, newSrc)) } - suspend fun update(vararg sources: RemotePatchBundle, showToast: Boolean = false) { + suspend fun update( + vararg sources: RemotePatchBundle, + showToast: Boolean = false, + force: Boolean = false + ) { val uids = sources.map { it.uid }.toSet() - store.dispatch(Update(showToast = showToast) { it.uid in uids }) + store.dispatch(Update(showToast = showToast, force = force) { it.uid in uids }) } - suspend fun redownloadRemoteBundles() = store.dispatch(Update(force = true)) + suspend fun redownloadRemoteBundles() = store.dispatch(Update(force = true, redownload = true)) /** * Updates all bundles that should be automatically updated. */ - suspend fun updateCheck() = store.dispatch(Update { it.autoUpdate }) + suspend fun updateCheck() = + store.dispatch(Update(force = prefs.allowMeteredNetworks.get()) { it.autoUpdate }) private inner class Update( private val force: Boolean = false, + private val redownload: Boolean = false, private val showToast: Boolean = false, private val predicate: (bundle: RemotePatchBundle) -> Boolean = { true }, ) : Action { private suspend fun toast(@StringRes id: Int, vararg args: Any?) = withContext(Dispatchers.Main) { app.toast(app.getString(id, *args)) } - override fun toString() = if (force) "Redownload remote bundles" else "Update check" + override fun toString() = if (redownload) "Redownload remote bundles" else "Update check" override suspend fun ActionContext.execute( current: State ) = coroutineScope { - if (!networkInfo.isSafe()) { + if (!networkInfo.isSafe(force)) { Log.d(tag, "Skipping update check because the network is down or metered.") return@coroutineScope current } @@ -367,7 +374,7 @@ class PatchBundleRepository( Log.d(tag, "Updating patch bundle: ${it.name}") val newVersion = with(it) { - if (force) downloadLatest() else update() + if (redownload) downloadLatest() else update() } ?: return@async null it to newVersion 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 4fc00c17..8e0b7baf 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 @@ -105,6 +105,14 @@ fun GeneralSettingsScreen( description = R.string.pure_black_theme_description ) } + + GroupHeader(stringResource(R.string.networking)) + BooleanItem( + preference = prefs.allowMeteredNetworks, + coroutineScope = coroutineScope, + headline = R.string.allow_metered_networks, + description = R.string.allow_metered_networks_description + ) } } } diff --git a/app/src/main/java/app/revanced/manager/ui/viewmodel/BundleListViewModel.kt b/app/src/main/java/app/revanced/manager/ui/viewmodel/BundleListViewModel.kt index 49bc0c4b..5f609295 100644 --- a/app/src/main/java/app/revanced/manager/ui/viewmodel/BundleListViewModel.kt +++ b/app/src/main/java/app/revanced/manager/ui/viewmodel/BundleListViewModel.kt @@ -54,6 +54,7 @@ class BundleListViewModel : ViewModel(), KoinComponent { patchBundleRepository.update( *getSelectedSources().filterIsInstance().toTypedArray(), showToast = true, + force = true ) } } @@ -65,7 +66,7 @@ class BundleListViewModel : ViewModel(), KoinComponent { fun update(src: PatchBundleSource) = viewModelScope.launch { if (src !is RemotePatchBundle) return@launch - patchBundleRepository.update(src, showToast = true) + patchBundleRepository.update(src, showToast = true, force = true) } enum class Event { diff --git a/app/src/main/java/app/revanced/manager/ui/viewmodel/UpdateViewModel.kt b/app/src/main/java/app/revanced/manager/ui/viewmodel/UpdateViewModel.kt index 186d9619..321bf94f 100644 --- a/app/src/main/java/app/revanced/manager/ui/viewmodel/UpdateViewModel.kt +++ b/app/src/main/java/app/revanced/manager/ui/viewmodel/UpdateViewModel.kt @@ -82,7 +82,7 @@ class UpdateViewModel( uiSafe(app, R.string.failed_to_download_update, "Failed to download update") { val release = releaseInfo!! withContext(Dispatchers.IO) { - if (!networkInfo.isSafe() && !ignoreInternetCheck) { + if (!networkInfo.isSafe(false) && !ignoreInternetCheck) { showInternetCheckDialog = true } else { state = State.DOWNLOADING diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 35364e02..eeb52799 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -217,6 +217,10 @@ You will not be able to update the previously installed apps from this source."< Light Dark Appearance + Networking + Allow metered networks + Permits automatic updates on metered networks. + The application might still warn about metered networks for manual operations. Downloaded apps Run Patcher in another process (experimental) This is faster and allows Patcher to use more memory