diff --git a/android/app/src/main/kotlin/app/revanced/manager/MainActivity.kt b/android/app/src/main/kotlin/app/revanced/manager/MainActivity.kt index ba725783..7859dafe 100644 --- a/android/app/src/main/kotlin/app/revanced/manager/MainActivity.kt +++ b/android/app/src/main/kotlin/app/revanced/manager/MainActivity.kt @@ -1,5 +1,7 @@ package app.revanced.manager +import android.os.Handler +import android.os.Looper import androidx.annotation.NonNull import app.revanced.manager.utils.Aapt import app.revanced.manager.utils.aligning.ZipAligner @@ -19,92 +21,76 @@ import dalvik.system.DexClassLoader import io.flutter.embedding.android.FlutterActivity import io.flutter.embedding.engine.FlutterEngine import io.flutter.plugin.common.MethodChannel +import io.flutter.plugin.common.MethodChannel.Result import java.io.File import java.nio.file.Files import java.nio.file.StandardCopyOption class MainActivity : FlutterActivity() { - private val CHANNEL = "app.revanced.manager/patcher" + private val PATCHER_CHANNEL = "app.revanced.manager/patcher" + private val INSTALLER_CHANNEL = "app.revanced.manager/installer" private var patches = mutableListOf>>() - private val tag = "Patcher" - private lateinit var methodChannel: MethodChannel - private lateinit var patcher: Patcher + private val handler = Handler(Looper.getMainLooper()) + private lateinit var installerChannel: MethodChannel override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { super.configureFlutterEngine(flutterEngine) - methodChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL) - methodChannel.setMethodCallHandler { call, result -> + val mainChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, PATCHER_CHANNEL) + installerChannel = + MethodChannel(flutterEngine.dartExecutor.binaryMessenger, INSTALLER_CHANNEL) + mainChannel.setMethodCallHandler { call, result -> when (call.method) { "loadPatches" -> { val pathBundlesPaths = call.argument>("pathBundlesPaths") if (pathBundlesPaths != null) { - result.success(loadPatches(pathBundlesPaths)) + loadPatches(result, pathBundlesPaths) } else { result.notImplemented() } } - "getCompatiblePackages" -> result.success(getCompatiblePackages()) + "getCompatiblePackages" -> getCompatiblePackages(result) "getFilteredPatches" -> { val targetPackage = call.argument("targetPackage") val targetVersion = call.argument("targetVersion") val ignoreVersion = call.argument("ignoreVersion") if (targetPackage != null && targetVersion != null && ignoreVersion != null) { - result.success( - getFilteredPatches(targetPackage, targetVersion, ignoreVersion) - ) + getFilteredPatches(result, targetPackage, targetVersion, ignoreVersion) } else { result.notImplemented() } } - "copyInputFile" -> { + "runPatcher" -> { val originalFilePath = call.argument("originalFilePath") val inputFilePath = call.argument("inputFilePath") - if (originalFilePath != null && inputFilePath != null) { - result.success(copyInputFile(originalFilePath, inputFilePath)) - } else { - result.notImplemented() - } - } - "createPatcher" -> { - val inputFilePath = call.argument("inputFilePath") - val cacheDirPath = call.argument("cacheDirPath") - val resourcePatching = call.argument("resourcePatching") - if (inputFilePath != null && cacheDirPath != null && resourcePatching != null) { - result.success(createPatcher(inputFilePath, cacheDirPath, resourcePatching)) - } else { - result.notImplemented() - } - } - "mergeIntegrations" -> { - val integrationsPath = call.argument("integrationsPath") - if (integrationsPath != null) { - result.success(mergeIntegrations(integrationsPath)) - } else { - result.notImplemented() - } - } - "applyPatches" -> { - val selectedPatches = call.argument>("selectedPatches") - if (selectedPatches != null) { - result.success(applyPatches(selectedPatches)) - } else { - result.notImplemented() - } - } - "repackPatchedFile" -> { - val inputFilePath = call.argument("inputFilePath") - val patchedFilePath = call.argument("patchedFilePath") - if (inputFilePath != null && patchedFilePath != null) { - result.success(repackPatchedFile(inputFilePath, patchedFilePath)) - } else { - result.notImplemented() - } - } - "signPatchedFile" -> { val patchedFilePath = call.argument("patchedFilePath") val outFilePath = call.argument("outFilePath") - if (patchedFilePath != null && outFilePath != null) { - result.success(signPatchedFile(patchedFilePath, outFilePath)) + val integrationsPath = call.argument("integrationsPath") + val selectedPatches = call.argument>("selectedPatches") + val cacheDirPath = call.argument("cacheDirPath") + val mergeIntegrations = call.argument("mergeIntegrations") + val resourcePatching = call.argument("resourcePatching") + if (originalFilePath != null && + inputFilePath != null && + patchedFilePath != null && + outFilePath != null && + integrationsPath != null && + selectedPatches != null && + cacheDirPath != null && + mergeIntegrations != null && + resourcePatching != null + ) { + runPatcher( + result, + originalFilePath, + inputFilePath, + patchedFilePath, + outFilePath, + integrationsPath, + selectedPatches, + cacheDirPath, + mergeIntegrations, + resourcePatching + ) } else { result.notImplemented() } @@ -114,157 +100,221 @@ class MainActivity : FlutterActivity() { } } - fun loadPatches(pathBundlesPaths: List): Boolean { - try { - pathBundlesPaths.forEach { path -> - patches.addAll( - DexPatchBundle( - path, - DexClassLoader( - path, - applicationContext.cacheDir.path, - null, - javaClass.classLoader - ) + fun loadPatches(result: MethodChannel.Result, pathBundlesPaths: List) { + Thread( + Runnable { + pathBundlesPaths.forEach { path -> + patches.addAll( + DexPatchBundle( + path, + DexClassLoader( + path, + applicationContext.cacheDir.path, + null, + javaClass.classLoader + ) + ) + .loadPatches() ) - .loadPatches() + } + handler.post { result.success(null) } + } ) - } - } catch (e: Exception) { - return false - } - return true + .start() } - fun getCompatiblePackages(): List { - val filteredPackages = mutableListOf() - patches.forEach patch@{ patch -> - patch.compatiblePackages?.forEach { pkg -> filteredPackages.add(pkg.name) } - } - return filteredPackages.distinct() + fun getCompatiblePackages(result: MethodChannel.Result) { + Thread( + Runnable { + val filteredPackages = mutableListOf() + patches.forEach patch@{ patch -> + patch.compatiblePackages?.forEach { pkg -> + filteredPackages.add(pkg.name) + } + } + handler.post { result.success(filteredPackages.distinct()) } + } + ) + .start() } fun getFilteredPatches( + result: MethodChannel.Result, targetPackage: String, targetVersion: String, ignoreVersion: Boolean - ): List> { - val filteredPatches = mutableListOf>() - patches.forEach patch@{ patch -> - patch.compatiblePackages?.forEach { pkg -> - if (pkg.name == targetPackage && - (ignoreVersion || - pkg.versions.isNotEmpty() || - pkg.versions.contains(targetVersion)) - ) { - var p = mutableMapOf() - p.put("name", patch.patchName) - p.put("version", patch.version) - p.put("description", patch.description) - filteredPatches.add(p) - } - } - } - return filteredPatches + ) { + Thread( + Runnable { + val filteredPatches = mutableListOf>() + patches.forEach patch@{ patch -> + patch.compatiblePackages?.forEach { pkg -> + if (pkg.name == targetPackage && + (ignoreVersion || + pkg.versions.isNotEmpty() || + pkg.versions.contains(targetVersion)) + ) { + var p = mutableMapOf() + p.put("name", patch.patchName) + p.put("version", patch.version) + p.put("description", patch.description) + filteredPatches.add(p) + } + } + } + handler.post { result.success(filteredPatches) } + } + ) + .start() } - private fun findPatchesByIds(ids: Iterable): List>> { - return patches.filter { patch -> ids.any { it == patch.patchName } } - } - - fun copyInputFile(originalFilePath: String, inputFilePath: String): Boolean { + fun runPatcher( + result: MethodChannel.Result, + originalFilePath: String, + inputFilePath: String, + patchedFilePath: String, + outFilePath: String, + integrationsPath: String, + selectedPatches: List, + cacheDirPath: String, + mergeIntegrations: Boolean, + resourcePatching: Boolean + ) { val originalFile = File(originalFilePath) val inputFile = File(inputFilePath) - Files.copy(originalFile.toPath(), inputFile.toPath(), StandardCopyOption.REPLACE_EXISTING) - return true - } - - fun createPatcher( - inputFilePath: String, - cacheDirPath: String, - resourcePatching: Boolean - ): Boolean { - val inputFile = File(inputFilePath) - val aaptPath = Aapt.binary(applicationContext).absolutePath - patcher = - Patcher( - PatcherOptions( - inputFile, - cacheDirPath, - resourcePatching, - aaptPath, - cacheDirPath, - logger = - object : app.revanced.patcher.logging.Logger { - override fun error(msg: String) { - methodChannel.invokeMethod("updateInstallerLog", msg) - } - - override fun warn(msg: String) { - methodChannel.invokeMethod("updateInstallerLog", msg) - } - - override fun info(msg: String) { - methodChannel.invokeMethod("updateInstallerLog", msg) - } - - override fun trace(msg: String) { - methodChannel.invokeMethod("updateInstallerLog", msg) - } - } - ) - ) - return true - } - - fun mergeIntegrations(integrationsPath: String): Boolean { - val integrations = File(integrationsPath) - if (patcher == null) return false - patcher.addFiles(listOf(integrations)) {} - return true - } - - fun applyPatches(selectedPatches: List): Boolean { - val patches = findPatchesByIds(selectedPatches) - if (patches.isEmpty()) return false - if (patcher == null) return false - patcher.addPatches(patches) - patcher.applyPatches().forEach { (patch, result) -> - if (result.isSuccess) { - val msg = "[success] $patch" - methodChannel.invokeMethod("updateInstallerLog", msg) - return@forEach - } - val msg = "[error] $patch:" + result.exceptionOrNull()!! - methodChannel.invokeMethod("updateInstallerLog", msg) - } - return true - } - - fun repackPatchedFile(inputFilePath: String, patchedFilePath: String): Boolean { - val inputFile = File(inputFilePath) - val patchedFile = File(patchedFilePath) - if (patcher == null) return false - val result = patcher.save() - ZipFile(patchedFile).use { file -> - result.dexFiles.forEach { - file.addEntryCompressData( - ZipEntry.createWithName(it.name), - it.dexFileInputStream.readBytes() - ) - } - result.resourceFile?.let { - file.copyEntriesFromFileAligned(ZipFile(it), ZipAligner::getEntryAlignment) - } - file.copyEntriesFromFileAligned(ZipFile(inputFile), ZipAligner::getEntryAlignment) - } - return true - } - - fun signPatchedFile(patchedFilePath: String, outFilePath: String): Boolean { val patchedFile = File(patchedFilePath) val outFile = File(outFilePath) - Signer("ReVanced", "s3cur3p@ssw0rd").signApk(patchedFile, outFile) - return true + val integrations = File(integrationsPath) + val filteredPatches = patches.filter { patch -> selectedPatches.any { it == patch.patchName } } + + Thread( + Runnable { + handler.post { + installerChannel.invokeMethod("updateProgress", 0.1) + installerChannel.invokeMethod("updateLog", "Copying original apk") + } + Files.copy( + originalFile.toPath(), + inputFile.toPath(), + StandardCopyOption.REPLACE_EXISTING + ) + + handler.post { + installerChannel.invokeMethod("updateProgress", 0.2) + installerChannel.invokeMethod("updateLog", "Creating patcher") + } + val patcher = + Patcher( + PatcherOptions( + inputFile, + cacheDirPath, + resourcePatching, + Aapt.binary(applicationContext).absolutePath, + cacheDirPath, + logger = + object : + app.revanced.patcher.logging.Logger { + override fun error(msg: String) { + handler.post { + installerChannel + .invokeMethod( + "updateLog", + msg + ) + } + } + + override fun warn(msg: String) { + handler.post { + installerChannel + .invokeMethod( + "updateLog", + msg + ) + } + } + + override fun info(msg: String) { + handler.post { + installerChannel + .invokeMethod( + "updateLog", + msg + ) + } + } + + override fun trace(msg: String) { + handler.post { + installerChannel + .invokeMethod( + "updateLog", + msg + ) + } + } + } + ) + ) + + handler.post { installerChannel.invokeMethod("updateProgress", 0.3) } + if (mergeIntegrations) { + handler.post { + installerChannel.invokeMethod( + "updateLog", + "Merging integrations" + ) + } + patcher.addFiles(listOf(integrations)) {} + } + + handler.post { installerChannel.invokeMethod("updateProgress", 0.5) } + patcher.addPatches(filteredPatches) + patcher.applyPatches().forEach { (patch, res) -> + if (res.isSuccess) { + val msg = "[success] $patch" + handler.post { installerChannel.invokeMethod("updateLog", msg) } + return@forEach + } + val msg = "[error] $patch:" + res.exceptionOrNull()!! + handler.post { installerChannel.invokeMethod("updateLog", msg) } + } + + handler.post { + installerChannel.invokeMethod("updateProgress", 0.7) + installerChannel.invokeMethod("updateLog", "Repacking patched apk") + } + val res = patcher.save() + ZipFile(patchedFile).use { file -> + res.dexFiles.forEach { + file.addEntryCompressData( + ZipEntry.createWithName(it.name), + it.dexFileInputStream.readBytes() + ) + } + res.resourceFile?.let { + file.copyEntriesFromFileAligned( + ZipFile(it), + ZipAligner::getEntryAlignment + ) + } + file.copyEntriesFromFileAligned( + ZipFile(inputFile), + ZipAligner::getEntryAlignment + ) + } + + handler.post { installerChannel.invokeMethod("updateProgress", 0.9) } + Signer("ReVanced", "s3cur3p@ssw0rd").signApk(patchedFile, outFile) + + handler.post { + installerChannel.invokeMethod("updateProgress", 1.0) + installerChannel.invokeMethod("updateLog", "Finished") + } + + handler.post { result.success(null) } + } + ) + .start() } } diff --git a/lib/services/patcher_api.dart b/lib/services/patcher_api.dart index d201bc88..5c1223a0 100644 --- a/lib/services/patcher_api.dart +++ b/lib/services/patcher_api.dart @@ -16,7 +16,12 @@ import 'package:share_extend/share_extend.dart'; @lazySingleton class PatcherAPI { - static const platform = MethodChannel('app.revanced.manager/patcher'); + static const patcherChannel = MethodChannel( + 'app.revanced.manager/patcher', + ); + static const installerChannel = MethodChannel( + 'app.revanced.manager/installer', + ); final GithubAPI githubAPI = GithubAPI(); final RootAPI rootAPI = RootAPI(); final List _filteredPackages = []; @@ -31,9 +36,18 @@ class PatcherAPI { File? _outFile; Future handlePlatformChannelMethods() async { - platform.setMethodCallHandler((call) async { - if (call.method == 'updateInstallerLog' && call.arguments != null) { - locator().addLog(call.arguments); + installerChannel.setMethodCallHandler((call) async { + switch (call.method) { + case 'updateProgress': + if (call.arguments != null) { + locator().updateProgress(call.arguments); + } + break; + case 'updateLog': + if (call.arguments != null) { + locator().updateLog(call.arguments); + } + break; } }); } @@ -46,7 +60,7 @@ class PatcherAPI { try { _patchBundleFile = await DefaultCacheManager().getSingleFile(dexFileUrl); - return await platform.invokeMethod( + return await patcherChannel.invokeMethod( 'loadPatches', { 'pathBundlesPaths': [_patchBundleFile!.absolute.path], @@ -65,8 +79,8 @@ class PatcherAPI { Future> getFilteredInstalledApps() async { if (_patchBundleFile != null && _filteredPackages.isEmpty) { try { - List? patchesPackages = - await platform.invokeListMethod('getCompatiblePackages'); + List? patchesPackages = await patcherChannel + .invokeListMethod('getCompatiblePackages'); if (patchesPackages != null) { for (String package in patchesPackages) { try { @@ -96,7 +110,8 @@ class PatcherAPI { _filteredPatches[selectedApp.packageName]!.isEmpty) { _filteredPatches[selectedApp.packageName] = []; try { - var patches = await platform.invokeListMethod>( + var patches = + await patcherChannel.invokeListMethod>( 'getFilteredPatches', { 'targetPackage': selectedApp.packageName, @@ -143,118 +158,41 @@ class PatcherAPI { return null; } - Future initPatcher() async { - try { + Future initPatcher(bool mergeIntegrations) async { + if (mergeIntegrations) { _integrations = await downloadIntegrations(); - if (_integrations != null) { - _tmpDir = await getTemporaryDirectory(); - _workDir = _tmpDir!.createTempSync('tmp-'); - _inputFile = File('${_workDir!.path}/base.apk'); - _patchedFile = File('${_workDir!.path}/patched.apk'); - _outFile = File('${_workDir!.path}/out.apk'); - _cacheDir = Directory('${_workDir!.path}/cache'); - _cacheDir!.createSync(); - return true; - } - } on Exception { - return false; + } else { + _integrations = File(''); } - return false; + _tmpDir = await getTemporaryDirectory(); + _workDir = _tmpDir!.createTempSync('tmp-'); + _inputFile = File('${_workDir!.path}/base.apk'); + _patchedFile = File('${_workDir!.path}/patched.apk'); + _outFile = File('${_workDir!.path}/out.apk'); + _cacheDir = Directory('${_workDir!.path}/cache'); + _cacheDir!.createSync(); } - Future copyInputFile(String originalFilePath) async { - if (_inputFile != null) { - try { - return await platform.invokeMethod( - 'copyInputFile', - { - 'originalFilePath': originalFilePath, - 'inputFilePath': _inputFile!.path, - }, - ); - } on Exception { - return false; - } - } - return false; - } - - Future createPatcher(bool resourcePatching) async { - if (_inputFile != null && _cacheDir != null) { - try { - return await platform.invokeMethod( - 'createPatcher', - { - 'inputFilePath': _inputFile!.path, - 'cacheDirPath': _cacheDir!.path, - 'resourcePatching': resourcePatching, - }, - ); - } on Exception { - return false; - } - } - return false; - } - - Future mergeIntegrations() async { - try { - return await platform.invokeMethod( - 'mergeIntegrations', - { - 'integrationsPath': _integrations!.path, - }, - ); - } on Exception { - return false; - } - } - - Future applyPatches(List selectedPatches) async { - try { - return await platform.invokeMethod( - 'applyPatches', - { - 'selectedPatches': selectedPatches.map((e) => e.name).toList(), - }, - ); - } on Exception { - return false; - } - } - - Future repackPatchedFile() async { - if (_inputFile != null && _patchedFile != null) { - try { - return await platform.invokeMethod( - 'repackPatchedFile', - { - 'inputFilePath': _inputFile!.path, - 'patchedFilePath': _patchedFile!.path, - }, - ); - } on Exception { - return false; - } - } - return false; - } - - Future signPatchedFile() async { - if (_patchedFile != null && _outFile != null) { - try { - return await platform.invokeMethod( - 'signPatchedFile', - { - 'patchedFilePath': _patchedFile!.path, - 'outFilePath': _outFile!.path, - }, - ); - } on Exception { - return false; - } - } - return false; + Future runPatcher( + String originalFilePath, + List selectedPatches, + bool mergeIntegrations, + bool resourcePatching, + ) async { + await patcherChannel.invokeMethod( + 'runPatcher', + { + 'originalFilePath': originalFilePath, + 'inputFilePath': _inputFile!.path, + 'patchedFilePath': _patchedFile!.path, + 'outFilePath': _outFile!.path, + 'integrationsPath': _integrations!.path, + 'selectedPatches': selectedPatches.map((e) => e.name).toList(), + 'cacheDirPath': _cacheDir!.path, + 'mergeIntegrations': mergeIntegrations, + 'resourcePatching': resourcePatching, + }, + ); } Future installPatchedFile(PatchedApplication patchedApp) async { diff --git a/lib/ui/views/app_selector/app_selector_viewmodel.dart b/lib/ui/views/app_selector/app_selector_viewmodel.dart index 27cf1c4a..5bb78b1b 100644 --- a/lib/ui/views/app_selector/app_selector_viewmodel.dart +++ b/lib/ui/views/app_selector/app_selector_viewmodel.dart @@ -45,7 +45,6 @@ class AppSelectorViewModel extends BaseViewModel { ); locator().selectedApp = app; locator().selectedPatches.clear(); - locator().dimPatchCard = false; locator().notifyListeners(); } @@ -74,7 +73,6 @@ class AppSelectorViewModel extends BaseViewModel { ); locator().selectedApp = app; locator().selectedPatches.clear(); - locator().dimPatchCard = false; locator().notifyListeners(); } } diff --git a/lib/ui/views/installer/installer_view.dart b/lib/ui/views/installer/installer_view.dart index ef359925..5aaadbcd 100644 --- a/lib/ui/views/installer/installer_view.dart +++ b/lib/ui/views/installer/installer_view.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_i18n/flutter_i18n.dart'; +import 'package:fluttertoast/fluttertoast.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:revanced_manager/app/app.locator.dart'; import 'package:revanced_manager/ui/views/installer/installer_viewmodel.dart'; @@ -21,7 +22,7 @@ class InstallerView extends StatelessWidget { builder: (context, model, child) => WillPopScope( child: Scaffold( floatingActionButton: Visibility( - visible: model.showButtons, + visible: !model.isPatching, child: FloatingActionButton.extended( onPressed: () => model.isInstalled ? model.openApp() : model.installResult(), @@ -54,7 +55,7 @@ class InstallerView extends StatelessWidget { ), ), Visibility( - visible: model.showButtons, + visible: !model.isPatching, child: IconButton( icon: const Icon(Icons.share), onPressed: () => model.shareResult(), diff --git a/lib/ui/views/installer/installer_viewmodel.dart b/lib/ui/views/installer/installer_viewmodel.dart index 557a898c..fb8bb7f2 100644 --- a/lib/ui/views/installer/installer_viewmodel.dart +++ b/lib/ui/views/installer/installer_viewmodel.dart @@ -11,11 +11,10 @@ import 'package:shared_preferences/shared_preferences.dart'; import 'package:stacked/stacked.dart'; class InstallerViewModel extends BaseViewModel { - double? progress = 0.2; + double? progress = 0.0; String logs = ''; bool isPatching = false; bool isInstalled = false; - bool showButtons = false; Future initialize() async { await FlutterBackground.initialize( @@ -31,10 +30,20 @@ class InstallerViewModel extends BaseViewModel { ); await FlutterBackground.enableBackgroundExecution(); await locator().handlePlatformChannelMethods(); - runPatcher(); + await runPatcher(); } - void addLog(String message) { + void updateProgress(double value) { + progress = value; + isInstalled = false; + isPatching = progress == 1.0 ? false : true; + if (progress == 0.0) { + logs = ''; + } + notifyListeners(); + } + + void updateLog(String message) { if (message.isNotEmpty && !message.startsWith('Merging L')) { if (logs.isNotEmpty) { logs += '\n'; @@ -44,91 +53,47 @@ class InstallerViewModel extends BaseViewModel { } } - void updateProgress(double value) { - progress = value; - isInstalled = false; - isPatching = progress == 1.0 ? false : true; - showButtons = progress == 1.0 ? true : false; - if (progress == 0.0) { - logs = ''; - } - notifyListeners(); - } - Future runPatcher() async { updateProgress(0.0); PatchedApplication? selectedApp = locator().selectedApp; - if (selectedApp != null) { + List selectedPatches = + locator().selectedPatches; + if (selectedApp != null && selectedPatches.isNotEmpty) { String apkFilePath = selectedApp.apkFilePath; - List selectedPatches = - locator().selectedPatches; - if (selectedPatches.isNotEmpty) { - addLog('Initializing installer'); + try { + updateLog('Initializing installer'); if (selectedApp.isRooted && !selectedApp.isFromStorage) { - addLog('Checking if an old patched version exists'); + updateLog('Checking if an old patched version exists'); bool oldExists = await locator().checkOldPatch(selectedApp); if (oldExists) { - addLog('Deleting old patched version'); + updateLog('Deleting old patched version'); await locator().deleteOldPatch(selectedApp); } } - addLog('Creating working directory'); - bool? isSuccess = await locator().initPatcher(); - if (isSuccess != null && isSuccess) { - updateProgress(0.1); - addLog('Copying original apk'); - isSuccess = await locator().copyInputFile(apkFilePath); - if (isSuccess != null && isSuccess) { - updateProgress(0.2); - addLog('Creating patcher'); - bool resourcePatching = false; - if (selectedApp.packageName == 'com.google.android.youtube' || - selectedApp.packageName == - 'com.google.android.apps.youtube.music') { - resourcePatching = true; - } - isSuccess = await locator().createPatcher( - resourcePatching, - ); - if (isSuccess != null && isSuccess) { - if (selectedApp.packageName == 'com.google.android.youtube') { - updateProgress(0.3); - addLog('Merging integrations'); - isSuccess = await locator().mergeIntegrations(); - } - if (isSuccess != null && isSuccess) { - updateProgress(0.5); - isSuccess = - await locator().applyPatches(selectedPatches); - if (isSuccess != null && isSuccess) { - updateProgress(0.7); - addLog('Repacking patched apk'); - isSuccess = await locator().repackPatchedFile(); - if (isSuccess != null && isSuccess) { - updateProgress(0.9); - addLog('Signing patched apk'); - isSuccess = await locator().signPatchedFile(); - if (isSuccess != null && isSuccess) { - showButtons = true; - updateProgress(1.0); - addLog('Finished'); - } - } - } - } - } - } + updateLog('Creating working directory'); + bool mergeIntegrations = false; + bool resourcePatching = false; + if (selectedApp.packageName == 'com.google.android.youtube') { + mergeIntegrations = true; + resourcePatching = true; + } else if (selectedApp.packageName == + 'com.google.android.apps.youtube.music') { + resourcePatching = true; } - if (isSuccess == null || !isSuccess) { - addLog('An error occurred! Aborting'); - } - } else { - addLog('No patches selected! Aborting'); + await locator().initPatcher(mergeIntegrations); + await locator().runPatcher( + apkFilePath, + selectedPatches, + mergeIntegrations, + resourcePatching, + ); + } on Exception { + updateLog('An error occurred! Aborting'); } } else { - addLog('No app selected! Aborting'); + updateLog('No app or patches selected! Aborting'); } await FlutterBackground.disableBackgroundExecution(); isPatching = false; @@ -138,15 +103,15 @@ class InstallerViewModel extends BaseViewModel { PatchedApplication? selectedApp = locator().selectedApp; if (selectedApp != null) { - addLog(selectedApp.isRooted + updateLog(selectedApp.isRooted ? 'Installing patched file using root method' : 'Installing patched file using nonroot method'); isInstalled = await locator().installPatchedFile(selectedApp); if (isInstalled) { - addLog('Done'); + updateLog('Done'); await saveApp(selectedApp); } else { - addLog('An error occurred! Aborting'); + updateLog('An error occurred! Aborting'); } } } diff --git a/lib/ui/views/patcher/patcher_view.dart b/lib/ui/views/patcher/patcher_view.dart index 5ace4a71..0033d256 100644 --- a/lib/ui/views/patcher/patcher_view.dart +++ b/lib/ui/views/patcher/patcher_view.dart @@ -18,7 +18,7 @@ class PatcherView extends StatelessWidget { viewModelBuilder: () => locator(), builder: (context, model, child) => Scaffold( floatingActionButton: Visibility( - visible: locator().showFabButton, + visible: model.showFabButton(), child: FloatingActionButton.extended( onPressed: () => model.navigateToInstaller(), label: I18nText('patcherView.fabButton'), @@ -52,8 +52,8 @@ class PatcherView extends StatelessWidget { const SizedBox(height: 16), Opacity( opacity: isDark - ? (model.dimPatchCard ? 0.5 : 1) - : (model.dimPatchCard ? 0.75 : 1), + ? (model.dimPatchesCard() ? 0.5 : 1) + : (model.dimPatchesCard() ? 0.75 : 1), child: PatchSelectorCard( onPressed: model.navigateToPatchesSelector, color: Theme.of(context).colorScheme.primary, diff --git a/lib/ui/views/patcher/patcher_viewmodel.dart b/lib/ui/views/patcher/patcher_viewmodel.dart index 4f8a6460..8a87c9d9 100644 --- a/lib/ui/views/patcher/patcher_viewmodel.dart +++ b/lib/ui/views/patcher/patcher_viewmodel.dart @@ -1,12 +1,12 @@ import 'package:revanced_manager/app/app.locator.dart'; import 'package:revanced_manager/app/app.router.dart'; +import 'package:revanced_manager/ui/views/app_selector/app_selector_viewmodel.dart'; +import 'package:revanced_manager/ui/views/patches_selector/patches_selector_viewmodel.dart'; import 'package:stacked/stacked.dart'; import 'package:stacked_services/stacked_services.dart'; class PatcherViewModel extends BaseViewModel { final _navigationService = locator(); - bool dimPatchCard = true; - bool showFabButton = false; void navigateToAppSelector() { _navigationService.navigateTo(Routes.appSelectorView); @@ -19,4 +19,12 @@ class PatcherViewModel extends BaseViewModel { void navigateToInstaller() { _navigationService.navigateTo(Routes.installerView); } + + bool showFabButton() { + return locator().selectedPatches.isNotEmpty; + } + + bool dimPatchesCard() { + return locator().selectedApp == null; + } } diff --git a/lib/ui/views/patches_selector/patches_selector_viewmodel.dart b/lib/ui/views/patches_selector/patches_selector_viewmodel.dart index 1bb79e68..23143dfa 100644 --- a/lib/ui/views/patches_selector/patches_selector_viewmodel.dart +++ b/lib/ui/views/patches_selector/patches_selector_viewmodel.dart @@ -35,8 +35,6 @@ class PatchesSelectorViewModel extends BaseViewModel { } } } - locator().showFabButton = - selectedPatches.isNotEmpty ? true : false; locator().notifyListeners(); } }