diff --git a/assets/i18n/en.json b/assets/i18n/en.json
index e4b8ffeb..5e611243 100644
--- a/assets/i18n/en.json
+++ b/assets/i18n/en.json
@@ -3,6 +3,8 @@
"cancelButton": "Cancel",
"enabledLabel": "Enabled",
"disabledLabel": "Disabled",
+ "yesLabel": "Yes",
+ "noLabel": "No",
"main": {
"dashboardTab": "Dashboard",
"patcherTab": "Patcher",
@@ -79,10 +81,13 @@
"installerView": {
"widgetTitle": "Installer",
"installButton": "Install",
+ "installRootButton": "Install as Root",
"openButton": "Open",
"shareButton": "Share file",
"notificationTitle": "ReVanced Manager is patching",
- "notificationText": "Tap to return to the installer"
+ "notificationText": "Tap to return to the installer",
+ "shareApkMenuOption": "Share APK",
+ "shareLogMenuOption": "Share log"
},
"settingsView": {
"widgetTitle": "Settings",
@@ -97,20 +102,11 @@
"languageLabel": "Language",
"englishOption": "English",
"frenchOption": "French",
- "rootModeLabel": "Root Mode",
- "rootModeHint": "Do you want to patch applications as rooted?",
"contributorsLabel": "Contributors",
"contributorsHint": "A list of contributors of ReVanced",
"aboutLabel": "About",
"versionLabel": "Version"
},
- "rootCheckerView": {
- "widgetTitle": "Is your device rooted?",
- "widgetDescription": "Don't know what this means or prefer to use non-root version? Just click on the button below!",
- "grantPermission": "Grant Root Permission",
- "grantedPermission": "Magisk permission granted: {isRooted}",
- "nonRootButton": "Nonroot"
- },
"appInfoView": {
"widgetTitle": "App Info",
"openButton": "Open",
@@ -120,7 +116,9 @@
"alertDialogText": "Are you sure you want to uninstall this app?",
"errorDialogText": "App was installed with root mode enabled but currently root mode is disabled.\nPlease enable root mode first.",
"packageNameLabel": "Package Name",
- "rootModeLabel": "Root Mode",
+ "installTypeLabel": "Installation Type",
+ "rootTypeLabel": "Root",
+ "nonRootTypeLabel": "Non-root",
"patchedDateLabel": "Patched Date",
"patchedDateHint": "{date} at {time}",
"appliedPatchesLabel": "Applied Patches",
diff --git a/assets/images/magisk.svg b/assets/images/magisk.svg
deleted file mode 100644
index 8395e80c..00000000
--- a/assets/images/magisk.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/lib/app/app.dart b/lib/app/app.dart
index 95405a24..653162dd 100644
--- a/lib/app/app.dart
+++ b/lib/app/app.dart
@@ -9,7 +9,6 @@ import 'package:revanced_manager/ui/views/navigation/navigation_viewmodel.dart';
import 'package:revanced_manager/ui/views/patcher/patcher_view.dart';
import 'package:revanced_manager/ui/views/patcher/patcher_viewmodel.dart';
import 'package:revanced_manager/ui/views/patches_selector/patches_selector_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/widgets/appInfoView/app_info_view.dart';
import 'package:stacked/stacked_annotations.dart';
@@ -24,7 +23,6 @@ import 'package:stacked_services/stacked_services.dart';
MaterialRoute(page: InstallerView),
MaterialRoute(page: SettingsView),
MaterialRoute(page: ContributorsView),
- MaterialRoute(page: RootCheckerView),
MaterialRoute(page: AppInfoView),
],
dependencies: [
diff --git a/lib/main.dart b/lib/main.dart
index a44aa11e..925d9415 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -7,7 +7,6 @@ import 'package:revanced_manager/services/manager_api.dart';
import 'package:revanced_manager/services/patcher_api.dart';
import 'package:revanced_manager/ui/theme/dynamic_theme_builder.dart';
import 'package:revanced_manager/ui/views/navigation/navigation_view.dart';
-import 'package:revanced_manager/ui/views/root_checker/root_checker_view.dart';
import 'package:stacked_themes/stacked_themes.dart';
Future main() async {
@@ -15,6 +14,7 @@ Future main() async {
await setupLocator();
WidgetsFlutterBinding.ensureInitialized();
await locator().initialize();
+ await locator().initialize();
runApp(const MyApp());
}
@@ -25,20 +25,7 @@ class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return DynamicThemeBuilder(
title: 'ReVanced Manager',
- home: FutureBuilder(
- future: _init(context),
- builder: (context, snapshot) {
- if (snapshot.hasData) {
- return snapshot.data!;
- } else {
- return Center(
- child: CircularProgressIndicator(
- color: Theme.of(context).colorScheme.secondary,
- ),
- );
- }
- },
- ),
+ home: const NavigationView(),
localizationsDelegates: [
FlutterI18nDelegate(
translationLoader: FileTranslationLoader(
@@ -51,14 +38,4 @@ class MyApp extends StatelessWidget {
],
);
}
-
- Future _init(BuildContext context) async {
- await locator().initialize();
- await locator().initialize();
- bool? isRooted = locator().isRooted();
- if (isRooted != null) {
- return const NavigationView();
- }
- return const RootCheckerView();
- }
}
diff --git a/lib/models/patched_application.dart b/lib/models/patched_application.dart
index 3b97a642..35066087 100644
--- a/lib/models/patched_application.dart
+++ b/lib/models/patched_application.dart
@@ -16,7 +16,7 @@ class PatchedApplication {
)
Uint8List icon;
DateTime patchDate;
- final bool isRooted;
+ bool isRooted;
bool hasUpdates;
List appliedPatches;
List changelog;
diff --git a/lib/services/manager_api.dart b/lib/services/manager_api.dart
index 70f7fc1b..31fc7f8a 100644
--- a/lib/services/manager_api.dart
+++ b/lib/services/manager_api.dart
@@ -65,14 +65,6 @@ class ManagerAPI {
await _prefs.setBool('useDarkTheme', value);
}
- bool? isRooted() {
- return _prefs.getBool('isRooted');
- }
-
- Future setIsRooted(bool value) async {
- await _prefs.setBool('isRooted', value);
- }
-
List getPatchedApps() {
List apps = _prefs.getStringList('patchedApps') ?? [];
return apps
@@ -109,11 +101,10 @@ class ManagerAPI {
}
Future reAssessSavedApps() async {
- bool isRooted = this.isRooted() ?? false;
List patchedApps = getPatchedApps();
List toRemove = [];
for (PatchedApplication app in patchedApps) {
- bool isRemove = await isAppUninstalled(app, isRooted);
+ bool isRemove = await isAppUninstalled(app);
if (isRemove) {
toRemove.add(app);
} else {
@@ -139,9 +130,9 @@ class ManagerAPI {
await setPatchedApps(patchedApps);
}
- Future isAppUninstalled(PatchedApplication app, bool isRooted) async {
+ Future isAppUninstalled(PatchedApplication app) async {
bool existsRoot = false;
- if (isRooted) {
+ if (app.isRooted) {
existsRoot = await _rootAPI.isAppInstalled(app.packageName);
}
bool existsNonRoot = await DeviceApps.isAppInstalled(app.packageName);
diff --git a/lib/services/patcher_api.dart b/lib/services/patcher_api.dart
index a70cc2f2..9c5cb9ea 100644
--- a/lib/services/patcher_api.dart
+++ b/lib/services/patcher_api.dart
@@ -147,11 +147,16 @@ class PatcherAPI {
if (_outFile != null) {
try {
if (patchedApp.isRooted) {
- return _rootAPI.installApp(
- patchedApp.packageName,
- patchedApp.apkFilePath,
- _outFile!.path,
- );
+ bool hasRootPermissions = await _rootAPI.hasRootPermissions();
+ if (hasRootPermissions) {
+ return _rootAPI.installApp(
+ patchedApp.packageName,
+ patchedApp.apkFilePath,
+ _outFile!.path,
+ );
+ } else {
+ return false;
+ }
} else {
await AppInstaller.installApk(_outFile!.path);
return await DeviceApps.isAppInstalled(patchedApp.packageName);
@@ -163,14 +168,15 @@ class PatcherAPI {
return false;
}
- bool sharePatchedFile(String appName, String version) {
+ void sharePatchedFile(String appName, String version) {
if (_outFile != null) {
String prefix = appName.toLowerCase().replaceAll(' ', '-');
- File share = _outFile!.renameSync('$prefix-revanced_v$version.apk');
+ String newName = '$prefix-revanced_v$version.apk';
+ int lastSeparator = _outFile!.path.lastIndexOf('/');
+ File share = _outFile!.renameSync(
+ _outFile!.path.substring(0, lastSeparator + 1) + newName,
+ );
ShareExtend.share(share.path, 'file');
- return true;
- } else {
- return false;
}
}
@@ -186,4 +192,8 @@ class PatcherAPI {
await _rootAPI.deleteApp(patchedApp.packageName, patchedApp.apkFilePath);
}
}
+
+ void shareLog(String logs) {
+ ShareExtend.share(logs, 'text');
+ }
}
diff --git a/lib/services/root_api.dart b/lib/services/root_api.dart
index 33735a04..8e454ab7 100644
--- a/lib/services/root_api.dart
+++ b/lib/services/root_api.dart
@@ -5,6 +5,11 @@ class RootAPI {
final String _postFsDataDirPath = '/data/adb/post-fs-data.d';
final String _serviceDDirPath = '/data/adb/service.d';
+ Future hasRootPermissions() async {
+ bool? isRooted = await Root.isRooted();
+ return isRooted != null && isRooted;
+ }
+
Future isAppInstalled(String packageName) async {
if (packageName.isNotEmpty) {
String? res = await Root.exec(
diff --git a/lib/ui/views/app_selector/app_selector_viewmodel.dart b/lib/ui/views/app_selector/app_selector_viewmodel.dart
index 329993fc..95b8063f 100644
--- a/lib/ui/views/app_selector/app_selector_viewmodel.dart
+++ b/lib/ui/views/app_selector/app_selector_viewmodel.dart
@@ -6,23 +6,19 @@ import 'package:flutter_i18n/flutter_i18n.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:revanced_manager/app/app.locator.dart';
import 'package:revanced_manager/models/patched_application.dart';
-import 'package:revanced_manager/services/manager_api.dart';
import 'package:revanced_manager/services/patcher_api.dart';
import 'package:revanced_manager/ui/views/patcher/patcher_viewmodel.dart';
import 'package:stacked/stacked.dart';
class AppSelectorViewModel extends BaseViewModel {
- final ManagerAPI _managerAPI = locator();
final PatcherAPI _patcherAPI = locator();
final List apps = [];
bool noApps = false;
- bool _isRooted = false;
Future initialize() async {
apps.addAll(await _patcherAPI.getFilteredInstalledApps());
apps.sort((a, b) => a.appName.compareTo(b.appName));
noApps = apps.isEmpty;
- _isRooted = _managerAPI.isRooted() ?? false;
notifyListeners();
}
@@ -34,7 +30,7 @@ class AppSelectorViewModel extends BaseViewModel {
apkFilePath: application.apkFilePath,
icon: application.icon,
patchDate: DateTime.now(),
- isRooted: _isRooted,
+ isRooted: false,
);
locator().selectedPatches.clear();
locator().notifyListeners();
diff --git a/lib/ui/views/installer/installer_view.dart b/lib/ui/views/installer/installer_view.dart
index 8729c735..8c875b11 100644
--- a/lib/ui/views/installer/installer_view.dart
+++ b/lib/ui/views/installer/installer_view.dart
@@ -4,6 +4,7 @@ import 'package:google_fonts/google_fonts.dart';
import 'package:revanced_manager/ui/views/installer/installer_viewmodel.dart';
import 'package:revanced_manager/ui/widgets/installerView/custom_material_button.dart';
import 'package:revanced_manager/ui/widgets/shared/custom_card.dart';
+import 'package:revanced_manager/ui/widgets/shared/custom_popup_menu.dart';
import 'package:revanced_manager/ui/widgets/shared/custom_sliver_app_bar.dart';
import 'package:stacked/stacked.dart';
@@ -27,6 +28,34 @@ class InstallerView extends StatelessWidget {
color: Theme.of(context).textTheme.headline6!.color,
),
),
+ actions: [
+ Visibility(
+ visible: !model.isPatching,
+ child: CustomPopupMenu(
+ onSelected: (value) => model.onMenuSelection(value),
+ children: {
+ 0: I18nText(
+ 'installerView.shareApkMenuOption',
+ child: const Text(
+ '',
+ style: TextStyle(
+ fontWeight: FontWeight.bold,
+ ),
+ ),
+ ),
+ 1: I18nText(
+ 'installerView.shareLogMenuOption',
+ child: const Text(
+ '',
+ style: TextStyle(
+ fontWeight: FontWeight.bold,
+ ),
+ ),
+ ),
+ },
+ ),
+ ),
+ ],
bottom: PreferredSize(
preferredSize: const Size(double.infinity, 1.0),
child: LinearProgressIndicator(
@@ -60,26 +89,42 @@ class InstallerView extends StatelessWidget {
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
- CustomMaterialButton(
- label: I18nText('installerView.shareButton'),
- isFilled: false,
- onPressed: () => model.shareResult(),
- ),
- const SizedBox(width: 16),
- CustomMaterialButton(
- label: model.isInstalled
- ? I18nText('installerView.openButton')
- : I18nText('installerView.installButton'),
- isExpanded: true,
- onPressed: () {
- if (model.isInstalled) {
+ Visibility(
+ visible: model.isInstalled,
+ child: CustomMaterialButton(
+ label: I18nText('installerView.openButton'),
+ isExpanded: true,
+ onPressed: () {
model.openApp();
model.cleanPatcher();
Navigator.of(context).pop();
- } else {
- model.installResult();
- }
- },
+ },
+ ),
+ ),
+ Visibility(
+ visible: !model.isInstalled,
+ child: CustomMaterialButton(
+ isFilled: false,
+ label:
+ I18nText('installerView.installButton'),
+ isExpanded: true,
+ onPressed: () => model.installResult(false),
+ ),
+ ),
+ Visibility(
+ visible: !model.isInstalled,
+ child: const SizedBox(
+ width: 16,
+ ),
+ ),
+ Visibility(
+ visible: !model.isInstalled,
+ child: CustomMaterialButton(
+ label: I18nText(
+ 'installerView.installRootButton'),
+ isExpanded: true,
+ onPressed: () => model.installResult(true),
+ ),
),
],
),
diff --git a/lib/ui/views/installer/installer_viewmodel.dart b/lib/ui/views/installer/installer_viewmodel.dart
index 71683708..4463c604 100644
--- a/lib/ui/views/installer/installer_viewmodel.dart
+++ b/lib/ui/views/installer/installer_viewmodel.dart
@@ -14,7 +14,7 @@ import 'package:stacked/stacked.dart';
class InstallerViewModel extends BaseViewModel {
final ManagerAPI _managerAPI = locator();
final PatcherAPI _patcherAPI = locator();
- final PatchedApplication? _app = locator().selectedApp;
+ final PatchedApplication _app = locator().selectedApp!;
final List _patches = locator().selectedPatches;
static const _installerChannel = MethodChannel(
'app.revanced.manager/installer',
@@ -98,19 +98,19 @@ class InstallerViewModel extends BaseViewModel {
Future runPatcher() async {
update(0.0, 'Initializing...', 'Initializing installer');
- if (_app != null && _patches.isNotEmpty) {
- String apkFilePath = _app!.apkFilePath;
+ if (_patches.isNotEmpty) {
+ String apkFilePath = _app.apkFilePath;
try {
- if (_app!.isRooted) {
+ if (_app.isRooted) {
update(0.0, '', 'Checking if an old patched version exists');
- bool oldExists = await _patcherAPI.checkOldPatch(_app!);
+ bool oldExists = await _patcherAPI.checkOldPatch(_app);
if (oldExists) {
update(0.0, '', 'Deleting old patched version');
- await _patcherAPI.deleteOldPatch(_app!);
+ await _patcherAPI.deleteOldPatch(_app);
}
}
update(0.0, '', 'Creating working directory');
- await _patcherAPI.runPatcher(_app!.packageName, apkFilePath, _patches);
+ await _patcherAPI.runPatcher(_app.packageName, apkFilePath, _patches);
} on Exception {
update(1.0, 'Aborting...', 'An error occurred! Aborting');
}
@@ -124,31 +124,32 @@ class InstallerViewModel extends BaseViewModel {
}
}
- void installResult() async {
- if (_app != null) {
- update(
- 1.0,
- 'Installing...',
- _app!.isRooted
- ? 'Installing patched file using root method'
- : 'Installing patched file using nonroot method',
- );
- isInstalled = await _patcherAPI.installPatchedFile(_app!);
- if (isInstalled) {
- update(1.0, 'Installed!', 'Installed!');
- _app!.patchDate = DateTime.now();
- _app!.appliedPatches = _patches.map((p) => p.name).toList();
- await _managerAPI.savePatchedApp(_app!);
- } else {
- update(1.0, 'Aborting...', 'An error occurred! Aborting');
- }
+ void installResult(bool installAsRoot) async {
+ _app.isRooted = installAsRoot;
+ update(
+ 1.0,
+ 'Installing...',
+ _app.isRooted
+ ? 'Installing patched file using root method'
+ : 'Installing patched file using nonroot method',
+ );
+ isInstalled = await _patcherAPI.installPatchedFile(_app);
+ if (isInstalled) {
+ update(1.0, 'Installed!', 'Installed!');
+ _app.patchDate = DateTime.now();
+ _app.appliedPatches = _patches.map((p) => p.name).toList();
+ await _managerAPI.savePatchedApp(_app);
+ } else {
+ update(1.0, 'Aborting...', 'An error occurred! Aborting');
}
}
void shareResult() {
- if (_app != null) {
- _patcherAPI.sharePatchedFile(_app!.name, _app!.version);
- }
+ _patcherAPI.sharePatchedFile(_app.name, _app.version);
+ }
+
+ void shareLog() {
+ _patcherAPI.shareLog(logs);
}
Future cleanPatcher() async {
@@ -159,8 +160,17 @@ class InstallerViewModel extends BaseViewModel {
}
void openApp() {
- if (_app != null) {
- DeviceApps.openApp(_app!.packageName);
+ DeviceApps.openApp(_app.packageName);
+ }
+
+ void onMenuSelection(int value) {
+ switch (value) {
+ case 0:
+ shareResult();
+ break;
+ case 1:
+ shareLog();
+ break;
}
}
}
diff --git a/lib/ui/views/root_checker/root_checker_view.dart b/lib/ui/views/root_checker/root_checker_view.dart
deleted file mode 100644
index 4879848c..00000000
--- a/lib/ui/views/root_checker/root_checker_view.dart
+++ /dev/null
@@ -1,71 +0,0 @@
-import 'package:flutter/material.dart';
-import 'package:flutter_i18n/flutter_i18n.dart';
-import 'package:google_fonts/google_fonts.dart';
-import 'package:revanced_manager/ui/views/root_checker/root_checker_viewmodel.dart';
-import 'package:revanced_manager/ui/widgets/rootCheckerView/magisk_button.dart';
-import 'package:stacked/stacked.dart';
-
-class RootCheckerView extends StatelessWidget {
- const RootCheckerView({Key? key}) : super(key: key);
-
- @override
- Widget build(BuildContext context) {
- return ViewModelBuilder.reactive(
- onModelReady: (model) => model.initialize(),
- viewModelBuilder: () => RootCheckerViewModel(),
- builder: (context, model, child) => Scaffold(
- floatingActionButton: FloatingActionButton.extended(
- label: I18nText('rootCheckerView.nonRootButton'),
- icon: const Icon(Icons.keyboard_arrow_right),
- onPressed: () => model.navigateAsNonRoot(),
- ),
- body: Container(
- height: double.infinity,
- padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 28.0),
- child: Column(
- children: [
- const SizedBox(height: 120),
- I18nText(
- 'rootCheckerView.widgetTitle',
- child: Text(
- '',
- style: GoogleFonts.jetBrainsMono(
- fontSize: 24,
- ),
- ),
- ),
- const SizedBox(height: 24),
- I18nText(
- 'rootCheckerView.widgetDescription',
- child: const Text(
- '',
- textAlign: TextAlign.center,
- style: TextStyle(
- fontSize: 17,
- letterSpacing: 1.1,
- ),
- ),
- ),
- Expanded(
- child: Column(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- MagiskButton(
- onPressed: () => model.navigateAsRoot(),
- ),
- I18nText(
- 'rootCheckerView.grantedPermission',
- translationParams: {
- 'isRooted': model.isRooted.toString(),
- },
- ),
- ],
- ),
- ),
- ],
- ),
- ),
- ),
- );
- }
-}
diff --git a/lib/ui/views/root_checker/root_checker_viewmodel.dart b/lib/ui/views/root_checker/root_checker_viewmodel.dart
deleted file mode 100644
index 93684b70..00000000
--- a/lib/ui/views/root_checker/root_checker_viewmodel.dart
+++ /dev/null
@@ -1,36 +0,0 @@
-import 'package:revanced_manager/app/app.locator.dart';
-import 'package:revanced_manager/app/app.router.dart';
-import 'package:revanced_manager/services/manager_api.dart';
-import 'package:stacked/stacked.dart';
-import 'package:root/root.dart';
-import 'package:stacked_services/stacked_services.dart';
-
-class RootCheckerViewModel extends BaseViewModel {
- final NavigationService _navigationService = locator();
- final ManagerAPI _managerAPI = locator();
- bool isRooted = false;
-
- void initialize() {
- isRooted = _managerAPI.isRooted() ?? false;
- }
-
- Future navigateAsRoot() async {
- bool? res = await Root.isRooted();
- isRooted = res != null && res == true;
- if (isRooted) {
- await navigateToHome();
- } else {
- notifyListeners();
- }
- }
-
- Future navigateAsNonRoot() async {
- isRooted = false;
- await navigateToHome();
- }
-
- Future navigateToHome() async {
- _managerAPI.setIsRooted(isRooted);
- _navigationService.navigateTo(Routes.navigationView);
- }
-}
diff --git a/lib/ui/views/settings/settings_view.dart b/lib/ui/views/settings/settings_view.dart
index d1a4ba0d..cef8871e 100644
--- a/lib/ui/views/settings/settings_view.dart
+++ b/lib/ui/views/settings/settings_view.dart
@@ -113,21 +113,6 @@ class SettingsView extends StatelessWidget {
SettingsSection(
title: 'settingsView.patcherSectionTitle',
children: [
- ListTile(
- contentPadding: EdgeInsets.zero,
- title: I18nText(
- 'settingsView.rootModeLabel',
- child: const Text(
- '',
- style: TextStyle(
- fontSize: 20,
- fontWeight: FontWeight.w500,
- ),
- ),
- ),
- subtitle: I18nText('settingsView.rootModeHint'),
- onTap: () => model.navigateToRootChecker(),
- ),
SourcesWidget(
title: 'settingsView.sourcesLabel',
organizationController: organizationController,
diff --git a/lib/ui/views/settings/settings_viewmodel.dart b/lib/ui/views/settings/settings_viewmodel.dart
index 53c3c4a6..bec01446 100644
--- a/lib/ui/views/settings/settings_viewmodel.dart
+++ b/lib/ui/views/settings/settings_viewmodel.dart
@@ -18,10 +18,6 @@ class SettingsViewModel extends BaseViewModel {
notifyListeners();
}
- void navigateToRootChecker() {
- _navigationService.navigateTo(Routes.rootCheckerView);
- }
-
void navigateToContributors() {
_navigationService.navigateTo(Routes.contributorsView);
}
diff --git a/lib/ui/widgets/appInfoView/app_info_view.dart b/lib/ui/widgets/appInfoView/app_info_view.dart
index 2e5cb676..77445822 100644
--- a/lib/ui/widgets/appInfoView/app_info_view.dart
+++ b/lib/ui/widgets/appInfoView/app_info_view.dart
@@ -1,4 +1,3 @@
-import 'package:device_apps/device_apps.dart';
import 'package:flutter/material.dart';
import 'package:flutter_i18n/flutter_i18n.dart';
import 'package:google_fonts/google_fonts.dart';
@@ -19,7 +18,6 @@ class AppInfoView extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ViewModelBuilder.reactive(
- onModelReady: (model) => model.initialize(),
viewModelBuilder: () => AppInfoViewModel(),
builder: (context, model, child) => Scaffold(
body: CustomScrollView(
@@ -68,9 +66,7 @@ class AppInfoView extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
InkWell(
- onTap: () => DeviceApps.openApp(
- app.packageName,
- ),
+ onTap: () => model.openApp(app),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
@@ -180,7 +176,7 @@ class AppInfoView extends StatelessWidget {
ListTile(
contentPadding: EdgeInsets.zero,
title: I18nText(
- 'appInfoView.rootModeLabel',
+ 'appInfoView.installTypeLabel',
child: const Text(
'',
style: TextStyle(
@@ -189,9 +185,9 @@ class AppInfoView extends StatelessWidget {
),
),
),
- subtitle: model.isRooted
- ? I18nText('enabledLabel')
- : I18nText('disabledLabel'),
+ subtitle: app.isRooted
+ ? I18nText('appInfoView.rootTypeLabel')
+ : I18nText('appInfoView.nonRootTypeLabel'),
),
const SizedBox(height: 4),
ListTile(
diff --git a/lib/ui/widgets/appInfoView/app_info_viewmodel.dart b/lib/ui/widgets/appInfoView/app_info_viewmodel.dart
index 179442d5..0ae8172a 100644
--- a/lib/ui/widgets/appInfoView/app_info_viewmodel.dart
+++ b/lib/ui/widgets/appInfoView/app_info_viewmodel.dart
@@ -17,11 +17,6 @@ class AppInfoViewModel extends BaseViewModel {
final ManagerAPI _managerAPI = locator();
final PatcherAPI _patcherAPI = locator();
final RootAPI _rootAPI = RootAPI();
- bool isRooted = false;
-
- void initialize() {
- isRooted = _managerAPI.isRooted() ?? false;
- }
void uninstallApp(PatchedApplication app) {
if (app.isRooted) {
@@ -45,7 +40,8 @@ class AppInfoViewModel extends BaseViewModel {
BuildContext context,
PatchedApplication app,
) async {
- if (app.isRooted && !isRooted) {
+ bool hasRootPermissions = await _rootAPI.hasRootPermissions();
+ if (app.isRooted && !hasRootPermissions) {
return showDialog(
context: context,
builder: (context) => AlertDialog(
@@ -129,4 +125,8 @@ class AppInfoViewModel extends BaseViewModel {
.toList();
return '\u2022 ${names.join('\n\u2022 ')}';
}
+
+ void openApp(PatchedApplication app) {
+ DeviceApps.openApp(app.packageName);
+ }
}
diff --git a/lib/ui/widgets/installerView/custom_material_button.dart b/lib/ui/widgets/installerView/custom_material_button.dart
index 772e66a2..b8b0690e 100644
--- a/lib/ui/widgets/installerView/custom_material_button.dart
+++ b/lib/ui/widgets/installerView/custom_material_button.dart
@@ -23,7 +23,16 @@ class CustomMaterialButton extends StatelessWidget {
? const EdgeInsets.symmetric(horizontal: 24, vertical: 12)
: const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
),
- shape: MaterialStateProperty.all(const StadiumBorder()),
+ shape: MaterialStateProperty.all(
+ StadiumBorder(
+ side: isFilled
+ ? BorderSide.none
+ : BorderSide(
+ width: 1,
+ color: Theme.of(context).colorScheme.primary,
+ ),
+ ),
+ ),
backgroundColor: MaterialStateProperty.all(
isFilled ? Theme.of(context).colorScheme.primary : Colors.transparent,
),
diff --git a/lib/ui/widgets/rootCheckerView/magisk_button.dart b/lib/ui/widgets/rootCheckerView/magisk_button.dart
deleted file mode 100644
index cf678f3f..00000000
--- a/lib/ui/widgets/rootCheckerView/magisk_button.dart
+++ /dev/null
@@ -1,42 +0,0 @@
-import 'package:flutter/material.dart';
-import 'package:flutter_i18n/flutter_i18n.dart';
-import 'package:flutter_svg/flutter_svg.dart';
-
-class MagiskButton extends StatelessWidget {
- final Function() onPressed;
-
- const MagiskButton({
- Key? key,
- required this.onPressed,
- }) : super(key: key);
-
- @override
- Widget build(BuildContext context) {
- return Column(
- mainAxisSize: MainAxisSize.min,
- children: [
- GestureDetector(
- onTap: onPressed,
- child: CircleAvatar(
- radius: 32,
- backgroundColor: Theme.of(context).colorScheme.primary,
- child: SvgPicture.asset(
- 'assets/images/magisk.svg',
- color: Theme.of(context).colorScheme.surface,
- height: 40,
- width: 40,
- ),
- ),
- ),
- const SizedBox(height: 8),
- I18nText(
- 'rootCheckerView.grantPermission',
- child: const Text(
- '',
- style: TextStyle(fontSize: 15),
- ),
- ),
- ],
- );
- }
-}
diff --git a/lib/ui/widgets/shared/custom_popup_menu.dart b/lib/ui/widgets/shared/custom_popup_menu.dart
new file mode 100644
index 00000000..67dbd784
--- /dev/null
+++ b/lib/ui/widgets/shared/custom_popup_menu.dart
@@ -0,0 +1,36 @@
+import 'package:flutter/material.dart';
+
+class CustomPopupMenu extends StatelessWidget {
+ final Function(dynamic) onSelected;
+ final Map children;
+
+ const CustomPopupMenu({
+ Key? key,
+ required this.onSelected,
+ required this.children,
+ }) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ return Theme(
+ data: Theme.of(context).copyWith(useMaterial3: false),
+ child: PopupMenuButton(
+ onSelected: onSelected,
+ itemBuilder: (context) => children.entries
+ .map(
+ (entry) => PopupMenuItem(
+ padding: const EdgeInsets.all(16.0).copyWith(right: 20),
+ value: entry.key,
+ child: entry.value,
+ ),
+ )
+ .toList(),
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(24),
+ ),
+ color: Theme.of(context).colorScheme.secondaryContainer,
+ position: PopupMenuPosition.under,
+ ),
+ );
+ }
+}
diff --git a/lib/ui/widgets/shared/custom_sliver_app_bar.dart b/lib/ui/widgets/shared/custom_sliver_app_bar.dart
index 34304f09..be683e79 100644
--- a/lib/ui/widgets/shared/custom_sliver_app_bar.dart
+++ b/lib/ui/widgets/shared/custom_sliver_app_bar.dart
@@ -2,11 +2,13 @@ import 'package:flutter/material.dart';
class CustomSliverAppBar extends StatelessWidget {
final Widget title;
+ final List? actions;
final PreferredSizeWidget? bottom;
const CustomSliverAppBar({
Key? key,
required this.title,
+ this.actions,
this.bottom,
}) : super(key: key);
@@ -30,6 +32,7 @@ class CustomSliverAppBar extends StatelessWidget {
),
title: title,
),
+ actions: actions,
bottom: bottom,
);
}
diff --git a/pubspec.yaml b/pubspec.yaml
index 04d60209..b39b6d6f 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -63,5 +63,4 @@ dev_dependencies:
flutter:
uses-material-design: true
assets:
- - assets/images/
- assets/i18n/