feat: root installation (wip)

This commit is contained in:
Alberto Ponces 2022-08-14 19:40:34 +01:00
parent 6061d900ed
commit 9ce0f81a89
16 changed files with 231 additions and 69 deletions

View File

@ -70,6 +70,7 @@
"rootCheckerView": { "rootCheckerView": {
"widgetTitle": "Is your device rooted?", "widgetTitle": "Is your device rooted?",
"widgetDescription": "Don't know what's this or prefer to use non-root version? Just click button below!", "widgetDescription": "Don't know what's this or prefer to use non-root version? Just click button below!",
"grantPermission": "Grant Root Permission" "grantPermission": "Grant Root Permission",
"grantedPermission": "Magisk permission granted: {isRooted}"
} }
} }

View File

@ -1,8 +1,10 @@
import 'package:revanced_manager/main.dart';
import 'package:revanced_manager/services/manager_api.dart';
import 'package:revanced_manager/services/patcher_api.dart'; import 'package:revanced_manager/services/patcher_api.dart';
import 'package:revanced_manager/services/root_api.dart';
import 'package:revanced_manager/ui/views/app_selector/app_selector_view.dart'; import 'package:revanced_manager/ui/views/app_selector/app_selector_view.dart';
import 'package:revanced_manager/ui/views/app_selector/app_selector_viewmodel.dart'; import 'package:revanced_manager/ui/views/app_selector/app_selector_viewmodel.dart';
import 'package:revanced_manager/ui/views/contributors/contributors_view.dart'; import 'package:revanced_manager/ui/views/contributors/contributors_view.dart';
import 'package:revanced_manager/ui/views/home/home_view.dart';
import 'package:revanced_manager/ui/views/installer/installer_view.dart'; import 'package:revanced_manager/ui/views/installer/installer_view.dart';
import 'package:revanced_manager/ui/views/installer/installer_viewmodel.dart'; import 'package:revanced_manager/ui/views/installer/installer_viewmodel.dart';
import 'package:revanced_manager/ui/views/patcher/patcher_viewmodel.dart'; import 'package:revanced_manager/ui/views/patcher/patcher_viewmodel.dart';
@ -16,7 +18,7 @@ import 'package:stacked_themes/stacked_themes.dart';
@StackedApp( @StackedApp(
routes: [ routes: [
MaterialRoute(page: HomeView), MaterialRoute(page: Navigation),
MaterialRoute(page: AppSelectorView), MaterialRoute(page: AppSelectorView),
MaterialRoute(page: PatchesSelectorView), MaterialRoute(page: PatchesSelectorView),
MaterialRoute(page: InstallerView), MaterialRoute(page: InstallerView),
@ -27,12 +29,16 @@ import 'package:stacked_themes/stacked_themes.dart';
dependencies: [ dependencies: [
LazySingleton(classType: NavigationService), LazySingleton(classType: NavigationService),
LazySingleton(classType: PatcherAPI), LazySingleton(classType: PatcherAPI),
LazySingleton(classType: ManagerAPI),
LazySingleton(classType: RootAPI),
LazySingleton(classType: PatcherViewModel), LazySingleton(classType: PatcherViewModel),
LazySingleton(classType: AppSelectorViewModel), LazySingleton(classType: AppSelectorViewModel),
LazySingleton(classType: PatchesSelectorViewModel), LazySingleton(classType: PatchesSelectorViewModel),
LazySingleton(classType: InstallerViewModel), LazySingleton(classType: InstallerViewModel),
LazySingleton( LazySingleton(
classType: ThemeService, resolveUsing: ThemeService.getInstance), classType: ThemeService,
resolveUsing: ThemeService.getInstance,
),
], ],
) )
class AppSetup {} class AppSetup {}

View File

@ -4,13 +4,15 @@
// StackedLocatorGenerator // StackedLocatorGenerator
// ************************************************************************** // **************************************************************************
// ignore_for_file: public_member_api_docs // ignore_for_file: public_member_api_docs, depend_on_referenced_packages
import 'package:stacked_core/stacked_core.dart'; import 'package:stacked_core/stacked_core.dart';
import 'package:stacked_services/stacked_services.dart'; import 'package:stacked_services/stacked_services.dart';
import 'package:stacked_themes/stacked_themes.dart'; import 'package:stacked_themes/stacked_themes.dart';
import '../services/manager_api.dart';
import '../services/patcher_api.dart'; import '../services/patcher_api.dart';
import '../services/root_api.dart';
import '../ui/views/app_selector/app_selector_viewmodel.dart'; import '../ui/views/app_selector/app_selector_viewmodel.dart';
import '../ui/views/installer/installer_viewmodel.dart'; import '../ui/views/installer/installer_viewmodel.dart';
import '../ui/views/patcher/patcher_viewmodel.dart'; import '../ui/views/patcher/patcher_viewmodel.dart';
@ -27,6 +29,8 @@ Future<void> setupLocator(
// Register dependencies // Register dependencies
locator.registerLazySingleton(() => NavigationService()); locator.registerLazySingleton(() => NavigationService());
locator.registerLazySingleton(() => PatcherAPI()); locator.registerLazySingleton(() => PatcherAPI());
locator.registerLazySingleton(() => ManagerAPI());
locator.registerLazySingleton(() => RootAPI());
locator.registerLazySingleton(() => PatcherViewModel()); locator.registerLazySingleton(() => PatcherViewModel());
locator.registerLazySingleton(() => AppSelectorViewModel()); locator.registerLazySingleton(() => AppSelectorViewModel());
locator.registerLazySingleton(() => PatchesSelectorViewModel()); locator.registerLazySingleton(() => PatchesSelectorViewModel());

View File

@ -10,16 +10,16 @@ import 'package:flutter/material.dart';
import 'package:stacked/stacked.dart'; import 'package:stacked/stacked.dart';
import 'package:stacked_services/stacked_services.dart'; import 'package:stacked_services/stacked_services.dart';
import '../main.dart';
import '../ui/views/app_selector/app_selector_view.dart'; import '../ui/views/app_selector/app_selector_view.dart';
import '../ui/views/contributors/contributors_view.dart'; import '../ui/views/contributors/contributors_view.dart';
import '../ui/views/home/home_view.dart';
import '../ui/views/installer/installer_view.dart'; import '../ui/views/installer/installer_view.dart';
import '../ui/views/patches_selector/patches_selector_view.dart'; import '../ui/views/patches_selector/patches_selector_view.dart';
import '../ui/views/root_checker/root_checker_view.dart'; import '../ui/views/root_checker/root_checker_view.dart';
import '../ui/views/settings/settings_view.dart'; import '../ui/views/settings/settings_view.dart';
class Routes { class Routes {
static const String homeView = '/home-view'; static const String navigation = '/Navigation';
static const String appSelectorView = '/app-selector-view'; static const String appSelectorView = '/app-selector-view';
static const String patchesSelectorView = '/patches-selector-view'; static const String patchesSelectorView = '/patches-selector-view';
static const String installerView = '/installer-view'; static const String installerView = '/installer-view';
@ -27,7 +27,7 @@ class Routes {
static const String contributorsView = '/contributors-view'; static const String contributorsView = '/contributors-view';
static const String rootCheckerView = '/root-checker-view'; static const String rootCheckerView = '/root-checker-view';
static const all = <String>{ static const all = <String>{
homeView, navigation,
appSelectorView, appSelectorView,
patchesSelectorView, patchesSelectorView,
installerView, installerView,
@ -41,7 +41,7 @@ class StackedRouter extends RouterBase {
@override @override
List<RouteDef> get routes => _routes; List<RouteDef> get routes => _routes;
final _routes = <RouteDef>[ final _routes = <RouteDef>[
RouteDef(Routes.homeView, page: HomeView), RouteDef(Routes.navigation, page: Navigation),
RouteDef(Routes.appSelectorView, page: AppSelectorView), RouteDef(Routes.appSelectorView, page: AppSelectorView),
RouteDef(Routes.patchesSelectorView, page: PatchesSelectorView), RouteDef(Routes.patchesSelectorView, page: PatchesSelectorView),
RouteDef(Routes.installerView, page: InstallerView), RouteDef(Routes.installerView, page: InstallerView),
@ -52,9 +52,9 @@ class StackedRouter extends RouterBase {
@override @override
Map<Type, StackedRouteFactory> get pagesMap => _pagesMap; Map<Type, StackedRouteFactory> get pagesMap => _pagesMap;
final _pagesMap = <Type, StackedRouteFactory>{ final _pagesMap = <Type, StackedRouteFactory>{
HomeView: (data) { Navigation: (data) {
return MaterialPageRoute<dynamic>( return MaterialPageRoute<dynamic>(
builder: (context) => const HomeView(), builder: (context) => const Navigation(),
settings: data, settings: data,
); );
}, },
@ -115,7 +115,7 @@ class InstallerViewArguments {
/// ************************************************************************* /// *************************************************************************
extension NavigatorStateExtension on NavigationService { extension NavigatorStateExtension on NavigationService {
Future<dynamic> navigateToHomeView({ Future<dynamic> navigateToNavigation({
int? routerId, int? routerId,
bool preventDuplicates = true, bool preventDuplicates = true,
Map<String, String>? parameters, Map<String, String>? parameters,
@ -123,7 +123,7 @@ extension NavigatorStateExtension on NavigationService {
transition, transition,
}) async { }) async {
return navigateTo( return navigateTo(
Routes.homeView, Routes.navigation,
id: routerId, id: routerId,
preventDuplicates: preventDuplicates, preventDuplicates: preventDuplicates,
parameters: parameters, parameters: parameters,

View File

@ -8,7 +8,9 @@ import 'package:revanced_manager/main_viewmodel.dart';
import 'package:revanced_manager/theme.dart'; import 'package:revanced_manager/theme.dart';
import 'package:revanced_manager/ui/views/home/home_view.dart'; import 'package:revanced_manager/ui/views/home/home_view.dart';
import 'package:revanced_manager/ui/views/patcher/patcher_view.dart'; import 'package:revanced_manager/ui/views/patcher/patcher_view.dart';
import 'package:revanced_manager/ui/views/root_checker/root_checker_view.dart';
import 'package:revanced_manager/ui/views/settings/settings_view.dart'; import 'package:revanced_manager/ui/views/settings/settings_view.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:stacked/stacked.dart'; import 'package:stacked/stacked.dart';
import 'package:stacked_services/stacked_services.dart'; import 'package:stacked_services/stacked_services.dart';
import 'package:stacked_themes/stacked_themes.dart'; import 'package:stacked_themes/stacked_themes.dart';
@ -37,7 +39,20 @@ class MyApp extends StatelessWidget {
themeMode: themeMode, themeMode: themeMode,
navigatorKey: StackedService.navigatorKey, navigatorKey: StackedService.navigatorKey,
onGenerateRoute: StackedRouter().onGenerateRoute, onGenerateRoute: StackedRouter().onGenerateRoute,
home: const Navigation(), home: FutureBuilder<Widget>(
future: _init(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return snapshot.data!;
} else {
return Center(
child: CircularProgressIndicator(
color: Theme.of(context).colorScheme.secondary,
),
);
}
},
),
localizationsDelegates: [ localizationsDelegates: [
FlutterI18nDelegate( FlutterI18nDelegate(
translationLoader: FileTranslationLoader( translationLoader: FileTranslationLoader(
@ -51,6 +66,15 @@ class MyApp extends StatelessWidget {
), ),
); );
} }
Future<Widget> _init() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
bool? isRooted = prefs.getBool('isRooted');
if (isRooted != null) {
return const Navigation();
}
return const RootCheckerView();
}
} }
class Navigation extends StatelessWidget { class Navigation extends StatelessWidget {

View File

@ -1,13 +0,0 @@
class ApplicationInfo {
final String name;
final String packageName;
final String version;
final String apkFilePath;
ApplicationInfo({
required this.name,
required this.packageName,
required this.version,
required this.apkFilePath,
});
}

View File

@ -0,0 +1,21 @@
import 'package:revanced_manager/models/patch.dart';
class PatchedApplication {
final String name;
final String packageName;
final String version;
final String apkFilePath;
final bool isRooted;
final bool isFromStorage;
final List<Patch> appliedPatches;
PatchedApplication({
required this.name,
required this.packageName,
required this.version,
required this.apkFilePath,
required this.isRooted,
required this.isFromStorage,
this.appliedPatches = const <Patch>[],
});
}

View File

@ -7,8 +7,8 @@ import 'package:revanced_manager/services/github_api.dart';
@lazySingleton @lazySingleton
class ManagerAPI { class ManagerAPI {
Dio dio = Dio(); final Dio dio = Dio();
GithubAPI githubAPI = GithubAPI(); final GithubAPI githubAPI = GithubAPI();
Future<String?> getPath() async { Future<String?> getPath() async {
final path = await p.getApplicationSupportDirectory(); final path = await p.getApplicationSupportDirectory();

View File

@ -6,9 +6,10 @@ import 'package:flutter_cache_manager/flutter_cache_manager.dart';
import 'package:injectable/injectable.dart'; import 'package:injectable/injectable.dart';
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
import 'package:revanced_manager/app/app.locator.dart'; import 'package:revanced_manager/app/app.locator.dart';
import 'package:revanced_manager/models/application_info.dart';
import 'package:revanced_manager/models/patch.dart'; import 'package:revanced_manager/models/patch.dart';
import 'package:revanced_manager/models/patched_application.dart';
import 'package:revanced_manager/services/github_api.dart'; import 'package:revanced_manager/services/github_api.dart';
import 'package:revanced_manager/services/root_api.dart';
import 'package:revanced_manager/ui/views/installer/installer_viewmodel.dart'; import 'package:revanced_manager/ui/views/installer/installer_viewmodel.dart';
import 'package:revanced_manager/utils/string.dart'; import 'package:revanced_manager/utils/string.dart';
import 'package:share_extend/share_extend.dart'; import 'package:share_extend/share_extend.dart';
@ -17,9 +18,10 @@ import 'package:share_extend/share_extend.dart';
class PatcherAPI { class PatcherAPI {
static const platform = MethodChannel('app.revanced.manager/patcher'); static const platform = MethodChannel('app.revanced.manager/patcher');
final GithubAPI githubAPI = GithubAPI(); final GithubAPI githubAPI = GithubAPI();
final RootAPI rootAPI = RootAPI();
final List<ApplicationWithIcon> _filteredPackages = []; final List<ApplicationWithIcon> _filteredPackages = [];
final Map<String, List<Patch>> _filteredPatches = <String, List<Patch>>{}; final Map<String, List<Patch>> _filteredPatches = <String, List<Patch>>{};
bool isRoot = false; Directory? _tmpDir;
Directory? _workDir; Directory? _workDir;
Directory? _cacheDir; Directory? _cacheDir;
File? _patchBundleFile; File? _patchBundleFile;
@ -89,7 +91,9 @@ class PatcherAPI {
return _filteredPackages; return _filteredPackages;
} }
Future<List<Patch>?> getFilteredPatches(ApplicationInfo? selectedApp) async { Future<List<Patch>?> getFilteredPatches(
PatchedApplication? selectedApp,
) async {
if (_patchBundleFile != null && selectedApp != null) { if (_patchBundleFile != null && selectedApp != null) {
if (_filteredPatches[selectedApp.packageName] == null || if (_filteredPatches[selectedApp.packageName] == null ||
_filteredPatches[selectedApp.packageName]!.isEmpty) { _filteredPatches[selectedApp.packageName]!.isEmpty) {
@ -146,8 +150,8 @@ class PatcherAPI {
try { try {
_integrations = await downloadIntegrations(); _integrations = await downloadIntegrations();
if (_integrations != null) { if (_integrations != null) {
Directory tmpDir = await getTemporaryDirectory(); _tmpDir = await getTemporaryDirectory();
_workDir = tmpDir.createTempSync('tmp-'); _workDir = _tmpDir!.createTempSync('tmp-');
_inputFile = File('${_workDir!.path}/base.apk'); _inputFile = File('${_workDir!.path}/base.apk');
_patchedFile = File('${_workDir!.path}/patched.apk'); _patchedFile = File('${_workDir!.path}/patched.apk');
_outFile = File('${_workDir!.path}/out.apk'); _outFile = File('${_workDir!.path}/out.apk');
@ -256,15 +260,19 @@ class PatcherAPI {
return false; return false;
} }
Future<bool> installPatchedFile() async { Future<bool> installPatchedFile(PatchedApplication patchedApp) async {
if (_outFile != null) { if (_outFile != null) {
try { try {
if (isRoot) { if (patchedApp.isRooted && !patchedApp.isFromStorage) {
// TBD return rootAPI.installApp(
patchedApp.packageName,
patchedApp.apkFilePath,
_outFile!.path,
);
} else { } else {
await AppInstaller.installApk(_outFile!.path); await AppInstaller.installApk(_outFile!.path);
return true;
} }
return true;
} on Exception { } on Exception {
return false; return false;
} }
@ -280,11 +288,11 @@ class PatcherAPI {
bool sharePatchedFile(String appName, String version) { bool sharePatchedFile(String appName, String version) {
if (_outFile != null) { if (_outFile != null) {
String path = _outFile!.parent.path; String path = _tmpDir!.path;
String prefix = appName.toLowerCase().replaceAll(' ', '-'); String prefix = appName.toLowerCase().replaceAll(' ', '-');
String sharePath = '$path/$prefix-revanced_v$version.apk'; String sharePath = '$path/$prefix-revanced_v$version.apk';
File share = _outFile!.copySync(sharePath); File share = _outFile!.copySync(sharePath);
ShareExtend.share(share.path, "file"); ShareExtend.share(share.path, 'file');
return true; return true;
} else { } else {
return false; return false;

View File

@ -0,0 +1,85 @@
import 'dart:io';
import 'package:injectable/injectable.dart';
import 'package:root/root.dart';
@lazySingleton
class RootAPI {
final String managerDirPath = "/data/adb/revanced_manager";
final String postFsDataDirPath = "/data/adb/post-fs-data.d";
final String serviceDDirPath = "/data/adb/service.d";
bool deleteApp(String packageName) {
try {
File('$managerDirPath/$packageName.apk').deleteSync();
File('$serviceDDirPath/$packageName.sh').deleteSync();
File('$postFsDataDirPath/$packageName.sh').deleteSync();
return true;
} on Exception {
return false;
}
}
Future<bool> installApp(
String packageName,
String originalFilePath,
String patchedFilePath,
) async {
try {
Directory managerDir = Directory(managerDirPath);
managerDir.createSync();
String newPatchedFilePath = '$managerDirPath/$packageName.apk';
installServiceDScript(
packageName,
originalFilePath,
newPatchedFilePath,
);
installPostFsDataScript(
packageName,
originalFilePath,
newPatchedFilePath,
);
File(patchedFilePath).renameSync(newPatchedFilePath);
await Root.exec(
cmd: 'chmod 644 $newPatchedFilePath',
);
await Root.exec(
cmd: 'chown system:system $newPatchedFilePath',
);
await Root.exec(
cmd: 'chcon u:object_r:apk_data_file:s0 $newPatchedFilePath',
);
return true;
} on Exception {
return false;
}
}
Future<void> installServiceDScript(
String packageName,
String originalFilePath,
String patchedFilePath,
) async {
String content = '#!/system/bin/sh\n'
'while [ "\$(getprop sys.boot_completed | tr -d \'\r\')" != "1" ]; do sleep 1; done\n'
'sleep 1\n'
'chcon u:object_r:apk_data_file:s0 $patchedFilePath\n'
'mount -o bind $patchedFilePath $originalFilePath';
File scriptFile = File('$serviceDDirPath/$packageName.sh');
await scriptFile.writeAsString(content);
await Root.exec(cmd: 'chmod 744 ${scriptFile.path}');
}
Future<void> installPostFsDataScript(
String packageName,
String originalFilePath,
String patchedFilePath,
) async {
String content = '#!/system/bin/sh\n'
'while read line; do echo \$line | grep $originalFilePath | '
'awk \'{print \$2}\' | xargs umount -l; done< /proc/mounts';
File scriptFile = File('$postFsDataDirPath/$packageName.sh');
await scriptFile.writeAsString(content);
await Root.exec(cmd: 'chmod 744 ${scriptFile.path}');
}
}

View File

@ -6,19 +6,24 @@ import 'package:flutter_i18n/flutter_i18n.dart';
import 'package:fluttertoast/fluttertoast.dart'; import 'package:fluttertoast/fluttertoast.dart';
import 'package:package_archive_info/package_archive_info.dart'; import 'package:package_archive_info/package_archive_info.dart';
import 'package:revanced_manager/app/app.locator.dart'; import 'package:revanced_manager/app/app.locator.dart';
import 'package:revanced_manager/models/application_info.dart'; import 'package:revanced_manager/models/patched_application.dart';
import 'package:revanced_manager/services/patcher_api.dart'; import 'package:revanced_manager/services/patcher_api.dart';
import 'package:revanced_manager/ui/views/patcher/patcher_viewmodel.dart'; import 'package:revanced_manager/ui/views/patcher/patcher_viewmodel.dart';
import 'package:revanced_manager/ui/views/patches_selector/patches_selector_viewmodel.dart'; import 'package:revanced_manager/ui/views/patches_selector/patches_selector_viewmodel.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:stacked/stacked.dart'; import 'package:stacked/stacked.dart';
class AppSelectorViewModel extends BaseViewModel { class AppSelectorViewModel extends BaseViewModel {
final PatcherAPI patcherAPI = locator<PatcherAPI>(); final PatcherAPI patcherAPI = locator<PatcherAPI>();
bool isRooted = false;
bool isFromStorage = false;
List<ApplicationWithIcon> apps = []; List<ApplicationWithIcon> apps = [];
ApplicationInfo? selectedApp; PatchedApplication? selectedApp;
Future<void> initialize() async { Future<void> initialize() async {
await getApps(); await getApps();
SharedPreferences prefs = await SharedPreferences.getInstance();
isRooted = prefs.getBool('isRooted') ?? false;
notifyListeners(); notifyListeners();
} }
@ -27,12 +32,15 @@ class AppSelectorViewModel extends BaseViewModel {
apps = await patcherAPI.getFilteredInstalledApps(); apps = await patcherAPI.getFilteredInstalledApps();
} }
void selectApp(ApplicationWithIcon application) { void selectApp(ApplicationWithIcon application) async {
ApplicationInfo app = ApplicationInfo( isFromStorage = false;
PatchedApplication app = PatchedApplication(
name: application.appName, name: application.appName,
packageName: application.packageName, packageName: application.packageName,
version: application.versionName!, version: application.versionName!,
apkFilePath: application.apkFilePath, apkFilePath: application.apkFilePath,
isRooted: isRooted,
isFromStorage: isFromStorage,
); );
locator<AppSelectorViewModel>().selectedApp = app; locator<AppSelectorViewModel>().selectedApp = app;
locator<PatchesSelectorViewModel>().selectedPatches.clear(); locator<PatchesSelectorViewModel>().selectedPatches.clear();
@ -41,6 +49,7 @@ class AppSelectorViewModel extends BaseViewModel {
} }
Future<void> selectAppFromStorage(BuildContext context) async { Future<void> selectAppFromStorage(BuildContext context) async {
isFromStorage = true;
try { try {
FilePickerResult? result = await FilePicker.platform.pickFiles( FilePickerResult? result = await FilePicker.platform.pickFiles(
type: FileType.custom, type: FileType.custom,
@ -50,11 +59,13 @@ class AppSelectorViewModel extends BaseViewModel {
File apkFile = File(result.files.single.path!); File apkFile = File(result.files.single.path!);
PackageArchiveInfo? packageArchiveInfo = PackageArchiveInfo? packageArchiveInfo =
await PackageArchiveInfo.fromPath(apkFile.path); await PackageArchiveInfo.fromPath(apkFile.path);
ApplicationInfo app = ApplicationInfo( PatchedApplication app = PatchedApplication(
name: packageArchiveInfo.appName, name: packageArchiveInfo.appName,
packageName: packageArchiveInfo.packageName, packageName: packageArchiveInfo.packageName,
version: packageArchiveInfo.version, version: packageArchiveInfo.version,
apkFilePath: result.files.single.path!, apkFilePath: result.files.single.path!,
isRooted: isRooted,
isFromStorage: isFromStorage,
); );
locator<AppSelectorViewModel>().selectedApp = app; locator<AppSelectorViewModel>().selectedApp = app;
locator<PatchesSelectorViewModel>().selectedPatches.clear(); locator<PatchesSelectorViewModel>().selectedPatches.clear();

View File

@ -1,6 +1,6 @@
import 'package:revanced_manager/app/app.locator.dart'; import 'package:revanced_manager/app/app.locator.dart';
import 'package:revanced_manager/models/application_info.dart';
import 'package:revanced_manager/models/patch.dart'; import 'package:revanced_manager/models/patch.dart';
import 'package:revanced_manager/models/patched_application.dart';
import 'package:revanced_manager/services/patcher_api.dart'; import 'package:revanced_manager/services/patcher_api.dart';
import 'package:revanced_manager/ui/views/app_selector/app_selector_viewmodel.dart'; import 'package:revanced_manager/ui/views/app_selector/app_selector_viewmodel.dart';
import 'package:revanced_manager/ui/views/patcher/patcher_viewmodel.dart'; import 'package:revanced_manager/ui/views/patcher/patcher_viewmodel.dart';
@ -38,7 +38,8 @@ class InstallerViewModel extends BaseViewModel {
Future<void> runPatcher() async { Future<void> runPatcher() async {
updateProgress(0.0); updateProgress(0.0);
ApplicationInfo? selectedApp = locator<AppSelectorViewModel>().selectedApp; PatchedApplication? selectedApp =
locator<AppSelectorViewModel>().selectedApp;
if (selectedApp != null) { if (selectedApp != null) {
String apkFilePath = selectedApp.apkFilePath; String apkFilePath = selectedApp.apkFilePath;
List<Patch> selectedPatches = List<Patch> selectedPatches =
@ -111,11 +112,16 @@ class InstallerViewModel extends BaseViewModel {
} }
void installResult() async { void installResult() async {
await locator<PatcherAPI>().installPatchedFile(); PatchedApplication? selectedApp =
locator<AppSelectorViewModel>().selectedApp;
if (selectedApp != null) {
await locator<PatcherAPI>().installPatchedFile(selectedApp);
}
} }
void shareResult() { void shareResult() {
ApplicationInfo? selectedApp = locator<AppSelectorViewModel>().selectedApp; PatchedApplication? selectedApp =
locator<AppSelectorViewModel>().selectedApp;
if (selectedApp != null) { if (selectedApp != null) {
locator<PatcherAPI>().sharePatchedFile( locator<PatcherAPI>().sharePatchedFile(
selectedApp.name, selectedApp.name,

View File

@ -1,6 +1,6 @@
import 'package:revanced_manager/app/app.locator.dart'; import 'package:revanced_manager/app/app.locator.dart';
import 'package:revanced_manager/models/application_info.dart';
import 'package:revanced_manager/models/patch.dart'; import 'package:revanced_manager/models/patch.dart';
import 'package:revanced_manager/models/patched_application.dart';
import 'package:revanced_manager/services/patcher_api.dart'; import 'package:revanced_manager/services/patcher_api.dart';
import 'package:revanced_manager/ui/views/app_selector/app_selector_viewmodel.dart'; import 'package:revanced_manager/ui/views/app_selector/app_selector_viewmodel.dart';
import 'package:revanced_manager/ui/views/patcher/patcher_viewmodel.dart'; import 'package:revanced_manager/ui/views/patcher/patcher_viewmodel.dart';
@ -18,7 +18,7 @@ class PatchesSelectorViewModel extends BaseViewModel {
} }
Future<void> getPatches() async { Future<void> getPatches() async {
ApplicationInfo? app = locator<AppSelectorViewModel>().selectedApp; PatchedApplication? app = locator<AppSelectorViewModel>().selectedApp;
patches = await patcherAPI.getFilteredPatches(app); patches = await patcherAPI.getFilteredPatches(app);
} }

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_i18n/widgets/I18nText.dart'; import 'package:flutter_i18n/widgets/I18nText.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
import 'package:revanced_manager/app/app.locator.dart';
import 'package:revanced_manager/ui/views/root_checker/root_checker_viewmodel.dart'; import 'package:revanced_manager/ui/views/root_checker/root_checker_viewmodel.dart';
import 'package:revanced_manager/ui/widgets/magisk_button.dart'; import 'package:revanced_manager/ui/widgets/magisk_button.dart';
import 'package:stacked/stacked.dart'; import 'package:stacked/stacked.dart';
@ -11,8 +12,9 @@ class RootCheckerView extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ViewModelBuilder<RootCheckerViewModel>.reactive( return ViewModelBuilder<RootCheckerViewModel>.reactive(
disposeViewModel: false,
onModelReady: (model) => model.initialize, onModelReady: (model) => model.initialize,
viewModelBuilder: () => RootCheckerViewModel(), viewModelBuilder: () => locator<RootCheckerViewModel>(),
builder: (context, model, child) => Scaffold( builder: (context, model, child) => Scaffold(
floatingActionButton: Column( floatingActionButton: Column(
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.end,
@ -64,15 +66,20 @@ class RootCheckerView extends StatelessWidget {
const SizedBox(height: 170), const SizedBox(height: 170),
MagiskButton( MagiskButton(
onPressed: () { onPressed: () {
model.getMagiskPermissions(); model
Future.delayed(const Duration(seconds: 5), () { .getMagiskPermissions()
model.checkRoot(); .then((value) => model.checkRoot());
});
}, },
), ),
Text( I18nText(
"Magisk permission granted: ${model.isRooted.toString()}", 'rootCheckerView.grantedPermission',
style: GoogleFonts.poppins(), translationParams: {
'isRooted': model.isRooted.toString(),
},
child: Text(
'',
style: GoogleFonts.poppins(),
),
), ),
], ],
), ),

View File

@ -1,7 +1,5 @@
import 'package:fluttertoast/fluttertoast.dart';
import 'package:revanced_manager/app/app.locator.dart'; import 'package:revanced_manager/app/app.locator.dart';
import 'package:revanced_manager/app/app.router.dart'; import 'package:revanced_manager/app/app.router.dart';
import 'package:revanced_manager/ui/views/home/home_view.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:stacked/stacked.dart'; import 'package:stacked/stacked.dart';
import 'package:root/root.dart'; import 'package:root/root.dart';
@ -18,21 +16,25 @@ class RootCheckerViewModel extends BaseViewModel {
Future<void> checkRoot() async { Future<void> checkRoot() async {
isRooted = await Root.isRooted(); isRooted = await Root.isRooted();
if (isRooted == true) {
navigateToHome();
}
notifyListeners(); notifyListeners();
} }
Future<void> getMagiskPermissions() async { Future<bool> getMagiskPermissions() async {
if (isRooted == true) { try {
Fluttertoast.showToast(msg: 'Magisk permission already granted!'); await Root.exec(cmd: 'cat /proc/version');
} on Exception {
return false;
} }
await Root.exec(cmd: "adb shell su -c exit"); return true;
notifyListeners();
} }
Future<void> navigateToHome() async { Future<void> navigateToHome() async {
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
prefs.setBool('showHome', true); prefs.setBool('isRooted', isRooted!);
_navigationService.navigateTo(Routes.homeView); _navigationService.navigateTo(Routes.navigation);
notifyListeners(); notifyListeners();
} }
} }

View File

@ -17,7 +17,7 @@ class LatestCommitCard extends StatefulWidget {
} }
class _LatestCommitCardState extends State<LatestCommitCard> { class _LatestCommitCardState extends State<LatestCommitCard> {
GithubAPI githubAPI = GithubAPI(); final GithubAPI githubAPI = GithubAPI();
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {