diff --git a/assets/i18n/en.json b/assets/i18n/en.json
index 45cc0b79..e19930ec 100644
--- a/assets/i18n/en.json
+++ b/assets/i18n/en.json
@@ -66,5 +66,10 @@
"versionLabel": "Version",
"aboutLabel": "About",
"contributorsLabel": "Contributors"
+ },
+ "rootCheckerView": {
+ "widgetTitle": "Is your device rooted?",
+ "widgetDescription": "Don't know what's this or prefer to use non-root version? Just click button below!",
+ "grantPermission": "Grant Root Permission"
}
}
\ No newline at end of file
diff --git a/assets/images/magisk.svg b/assets/images/magisk.svg
new file mode 100644
index 00000000..8395e80c
--- /dev/null
+++ b/assets/images/magisk.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/lib/app/app.dart b/lib/app/app.dart
index f94544a1..d42f7bb8 100644
--- a/lib/app/app.dart
+++ b/lib/app/app.dart
@@ -2,11 +2,13 @@ import 'package:revanced_manager/services/patcher_api.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/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_viewmodel.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/patches_selector/patches_selector_viewmodel.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:stacked/stacked_annotations.dart';
import 'package:stacked_services/stacked_services.dart';
@@ -14,11 +16,13 @@ import 'package:stacked_themes/stacked_themes.dart';
@StackedApp(
routes: [
+ MaterialRoute(page: HomeView),
MaterialRoute(page: AppSelectorView),
MaterialRoute(page: PatchesSelectorView),
MaterialRoute(page: InstallerView),
MaterialRoute(page: SettingsView),
- MaterialRoute(page: ContributorsView)
+ MaterialRoute(page: ContributorsView),
+ MaterialRoute(page: RootCheckerView),
],
dependencies: [
LazySingleton(classType: NavigationService),
diff --git a/lib/app/app.locator.dart b/lib/app/app.locator.dart
index 8a5d9aab..7b2ee8cf 100644
--- a/lib/app/app.locator.dart
+++ b/lib/app/app.locator.dart
@@ -4,7 +4,7 @@
// StackedLocatorGenerator
// **************************************************************************
-// ignore_for_file: public_member_api_docs, depend_on_referenced_packages
+// ignore_for_file: public_member_api_docs
import 'package:stacked_core/stacked_core.dart';
import 'package:stacked_services/stacked_services.dart';
diff --git a/lib/app/app.router.dart b/lib/app/app.router.dart
index 1d074b86..2105676d 100644
--- a/lib/app/app.router.dart
+++ b/lib/app/app.router.dart
@@ -12,22 +12,28 @@ import 'package:stacked_services/stacked_services.dart';
import '../ui/views/app_selector/app_selector_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/patches_selector/patches_selector_view.dart';
+import '../ui/views/root_checker/root_checker_view.dart';
import '../ui/views/settings/settings_view.dart';
class Routes {
+ static const String homeView = '/home-view';
static const String appSelectorView = '/app-selector-view';
static const String patchesSelectorView = '/patches-selector-view';
static const String installerView = '/installer-view';
static const String settingsView = '/settings-view';
static const String contributorsView = '/contributors-view';
+ static const String rootCheckerView = '/root-checker-view';
static const all = {
+ homeView,
appSelectorView,
patchesSelectorView,
installerView,
settingsView,
contributorsView,
+ rootCheckerView,
};
}
@@ -35,15 +41,23 @@ class StackedRouter extends RouterBase {
@override
List get routes => _routes;
final _routes = [
+ RouteDef(Routes.homeView, page: HomeView),
RouteDef(Routes.appSelectorView, page: AppSelectorView),
RouteDef(Routes.patchesSelectorView, page: PatchesSelectorView),
RouteDef(Routes.installerView, page: InstallerView),
RouteDef(Routes.settingsView, page: SettingsView),
RouteDef(Routes.contributorsView, page: ContributorsView),
+ RouteDef(Routes.rootCheckerView, page: RootCheckerView),
];
@override
Map get pagesMap => _pagesMap;
final _pagesMap = {
+ HomeView: (data) {
+ return MaterialPageRoute(
+ builder: (context) => const HomeView(),
+ settings: data,
+ );
+ },
AppSelectorView: (data) {
return MaterialPageRoute(
builder: (context) => const AppSelectorView(),
@@ -77,6 +91,12 @@ class StackedRouter extends RouterBase {
settings: data,
);
},
+ RootCheckerView: (data) {
+ return MaterialPageRoute(
+ builder: (context) => const RootCheckerView(),
+ settings: data,
+ );
+ },
};
}
@@ -95,6 +115,22 @@ class InstallerViewArguments {
/// *************************************************************************
extension NavigatorStateExtension on NavigationService {
+ Future navigateToHomeView({
+ int? routerId,
+ bool preventDuplicates = true,
+ Map? parameters,
+ Widget Function(BuildContext, Animation, Animation, Widget)?
+ transition,
+ }) async {
+ return navigateTo(
+ Routes.homeView,
+ id: routerId,
+ preventDuplicates: preventDuplicates,
+ parameters: parameters,
+ transition: transition,
+ );
+ }
+
Future navigateToAppSelectorView({
int? routerId,
bool preventDuplicates = true,
@@ -176,4 +212,20 @@ extension NavigatorStateExtension on NavigationService {
transition: transition,
);
}
+
+ Future navigateToRootCheckerView({
+ int? routerId,
+ bool preventDuplicates = true,
+ Map? parameters,
+ Widget Function(BuildContext, Animation, Animation, Widget)?
+ transition,
+ }) async {
+ return navigateTo(
+ Routes.rootCheckerView,
+ id: routerId,
+ preventDuplicates: preventDuplicates,
+ parameters: parameters,
+ transition: transition,
+ );
+ }
}
diff --git a/lib/main.dart b/lib/main.dart
index af039fdf..5534ac1b 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -54,7 +54,9 @@ class MyApp extends StatelessWidget {
}
class Navigation extends StatelessWidget {
- const Navigation({Key? key}) : super(key: key);
+ const Navigation({
+ Key? key,
+ }) : super(key: key);
@override
Widget build(BuildContext context) {
diff --git a/lib/ui/views/root_checker/root_checker_view.dart b/lib/ui/views/root_checker/root_checker_view.dart
new file mode 100644
index 00000000..4ec4e9ca
--- /dev/null
+++ b/lib/ui/views/root_checker/root_checker_view.dart
@@ -0,0 +1,83 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_i18n/widgets/I18nText.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/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: Column(
+ mainAxisAlignment: MainAxisAlignment.end,
+ children: [
+ const Text('nonroot'),
+ const SizedBox(height: 8),
+ FloatingActionButton(
+ onPressed: model.navigateToHome,
+ backgroundColor: Theme.of(context).colorScheme.secondary,
+ foregroundColor: Colors.white,
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(48),
+ ),
+ child: const Icon(
+ Icons.keyboard_arrow_right,
+ size: 32,
+ ),
+ ),
+ ],
+ ),
+ body: Container(
+ height: double.infinity,
+ padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 28.0),
+ child: Column(
+ mainAxisSize: MainAxisSize.max,
+ children: [
+ const SizedBox(height: 120),
+ I18nText(
+ 'rootCheckerView.widgetTitle',
+ child: Text(
+ '',
+ style: GoogleFonts.jetBrainsMono(
+ fontSize: 24,
+ ),
+ ),
+ ),
+ const SizedBox(height: 24),
+ I18nText(
+ 'rootCheckerView.widgetDescription',
+ child: Text(
+ '',
+ textAlign: TextAlign.center,
+ style: GoogleFonts.roboto(
+ fontSize: 17,
+ letterSpacing: 1.1,
+ ),
+ ),
+ ),
+ const SizedBox(height: 170),
+ MagiskButton(
+ onPressed: () {
+ model.getMagiskPermissions();
+ Future.delayed(const Duration(seconds: 5), () {
+ model.checkRoot();
+ });
+ },
+ ),
+ Text(
+ "Magisk permission granted: ${model.isRooted.toString()}",
+ style: GoogleFonts.poppins(),
+ ),
+ ],
+ ),
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/ui/views/root_checker/root_checker_viewmodel.dart b/lib/ui/views/root_checker/root_checker_viewmodel.dart
new file mode 100644
index 00000000..7aff462d
--- /dev/null
+++ b/lib/ui/views/root_checker/root_checker_viewmodel.dart
@@ -0,0 +1,38 @@
+import 'package:fluttertoast/fluttertoast.dart';
+import 'package:revanced_manager/app/app.locator.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:stacked/stacked.dart';
+import 'package:root/root.dart';
+import 'package:stacked_services/stacked_services.dart';
+
+class RootCheckerViewModel extends BaseViewModel {
+ final _navigationService = locator();
+ bool? isRooted = false;
+
+ Future initialize() async {
+ await checkRoot();
+ notifyListeners();
+ }
+
+ Future checkRoot() async {
+ isRooted = await Root.isRooted();
+ notifyListeners();
+ }
+
+ Future getMagiskPermissions() async {
+ if (isRooted == true) {
+ Fluttertoast.showToast(msg: 'Magisk permission already granted!');
+ }
+ await Root.exec(cmd: "adb shell su -c exit");
+ notifyListeners();
+ }
+
+ Future navigateToHome() async {
+ final prefs = await SharedPreferences.getInstance();
+ prefs.setBool('showHome', true);
+ _navigationService.navigateTo(Routes.homeView);
+ notifyListeners();
+ }
+}
diff --git a/lib/ui/widgets/magisk_button.dart b/lib/ui/widgets/magisk_button.dart
new file mode 100644
index 00000000..973eea65
--- /dev/null
+++ b/lib/ui/widgets/magisk_button.dart
@@ -0,0 +1,47 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_i18n/widgets/I18nText.dart';
+import 'package:flutter_svg/flutter_svg.dart';
+import 'package:google_fonts/google_fonts.dart';
+import 'package:revanced_manager/theme.dart';
+
+class MagiskButton extends StatelessWidget {
+ final Function()? onPressed;
+ const MagiskButton({
+ Key? key,
+ this.onPressed,
+ }) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ return Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ GestureDetector(
+ onTap: onPressed,
+ child: CircleAvatar(
+ radius: 32,
+ backgroundColor: isDark
+ ? Theme.of(context).colorScheme.secondary
+ : const Color(0xffCBDFFC),
+ child: SvgPicture.asset(
+ 'assets/images/magisk.svg',
+ color: isDark ? Colors.white70 : Colors.grey[900],
+ height: 50,
+ width: 50,
+ ),
+ ),
+ ),
+ const SizedBox(height: 8),
+ I18nText(
+ 'rootCheckerView.grantPermission',
+ child: Text(
+ '',
+ style: GoogleFonts.poppins(
+ fontSize: 15,
+ ),
+ ),
+ ),
+ ],
+ );
+ }
+}
diff --git a/pubspec.yaml b/pubspec.yaml
index 7841562e..86a98033 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -32,6 +32,7 @@ dependencies:
path_provider: ^2.0.11
root: ^2.0.2
share_extend: ^2.0.0
+ shared_preferences: ^2.0.15
stacked: ^2.3.15
stacked_generator: ^0.7.14
stacked_services: ^0.9.3