From a580375078264d5ab2423e35a80f23008f1fff16 Mon Sep 17 00:00:00 2001 From: Alberto Ponces Date: Thu, 1 Sep 2022 01:25:19 +0100 Subject: [PATCH] fix: add animations and fix some UI incoherences --- assets/i18n/en.json | 3 +- lib/main.dart | 17 ++++- .../views/app_selector/app_selector_view.dart | 9 ++- lib/ui/views/installer/installer_view.dart | 2 +- lib/ui/views/patcher/patcher_view.dart | 66 ++++++++++++++----- lib/ui/views/patcher/patcher_viewmodel.dart | 17 ----- .../patches_selector_view.dart | 34 +++++----- .../views/root_checker/root_checker_view.dart | 58 ++++++++-------- .../root_checker/root_checker_viewmodel.dart | 13 ++-- .../contributorsView/contributors_card.dart | 2 +- .../widgets/homeView/dashboard_raw_chip.dart | 2 +- .../patchesSelectorView/patch_item.dart | 28 ++++---- .../rootCheckerView/magisk_button.dart | 11 ++-- lib/ui/widgets/shared/application_item.dart | 4 +- lib/ui/widgets/shared/search_bar.dart | 8 ++- pubspec.yaml | 1 + 16 files changed, 153 insertions(+), 122 deletions(-) diff --git a/assets/i18n/en.json b/assets/i18n/en.json index 8e63059e..fb9f81f1 100644 --- a/assets/i18n/en.json +++ b/assets/i18n/en.json @@ -91,6 +91,7 @@ "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}" + "grantedPermission": "Magisk permission granted: {isRooted}", + "nonRootButton": "Nonroot" } } diff --git a/lib/main.dart b/lib/main.dart index 026c7ff2..68e6f18d 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,3 +1,4 @@ +import 'package:animations/animations.dart'; import 'package:flutter/material.dart'; import 'package:flutter_i18n/flutter_i18n.dart'; // ignore: depend_on_referenced_packages @@ -89,7 +90,21 @@ class Navigation extends StatelessWidget { return ViewModelBuilder.reactive( viewModelBuilder: () => locator(), builder: (context, model, child) => Scaffold( - body: getViewForIndex(model.currentIndex), + body: PageTransitionSwitcher( + duration: const Duration(milliseconds: 400), + transitionBuilder: ( + Widget child, + Animation animation, + Animation secondaryAnimation, + ) { + return FadeThroughTransition( + animation: animation, + secondaryAnimation: secondaryAnimation, + child: child, + ); + }, + child: getViewForIndex(model.currentIndex), + ), bottomNavigationBar: NavigationBar( onDestinationSelected: model.setIndex, selectedIndex: model.currentIndex, diff --git a/lib/ui/views/app_selector/app_selector_view.dart b/lib/ui/views/app_selector/app_selector_view.dart index a7a1546e..7e875080 100644 --- a/lib/ui/views/app_selector/app_selector_view.dart +++ b/lib/ui/views/app_selector/app_selector_view.dart @@ -29,13 +29,11 @@ class _AppSelectorViewState extends State { model.selectAppFromStorage(context); Navigator.of(context).pop(); }, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all( - Radius.circular(16.0), - ), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), ), backgroundColor: Theme.of(context).colorScheme.secondary, - foregroundColor: Colors.white, + foregroundColor: Theme.of(context).colorScheme.surface, ), body: SafeArea( child: Padding( @@ -73,6 +71,7 @@ class _AppSelectorViewState extends State { const SizedBox(height: 12), Expanded( child: ListView( + padding: const EdgeInsets.only(bottom: 80), children: model .getFilteredApps(_query) .map((app) => InkWell( diff --git a/lib/ui/views/installer/installer_view.dart b/lib/ui/views/installer/installer_view.dart index 82a8fbbd..62b3b95e 100644 --- a/lib/ui/views/installer/installer_view.dart +++ b/lib/ui/views/installer/installer_view.dart @@ -70,7 +70,7 @@ class InstallerView extends StatelessWidget { width: double.infinity, decoration: BoxDecoration( color: Theme.of(context).colorScheme.primary, - borderRadius: BorderRadius.circular(8), + borderRadius: BorderRadius.circular(12), ), child: Text( model.logs, diff --git a/lib/ui/views/patcher/patcher_view.dart b/lib/ui/views/patcher/patcher_view.dart index f8e45077..65e05fe7 100644 --- a/lib/ui/views/patcher/patcher_view.dart +++ b/lib/ui/views/patcher/patcher_view.dart @@ -1,9 +1,13 @@ +import 'package:animations/animations.dart'; import 'package:flutter/material.dart'; import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:revanced_manager/app/app.locator.dart'; import 'package:revanced_manager/theme.dart'; +import 'package:revanced_manager/ui/views/app_selector/app_selector_view.dart'; +import 'package:revanced_manager/ui/views/installer/installer_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/widgets/patcherView/app_selector_card.dart'; import 'package:revanced_manager/ui/widgets/patcherView/patch_selector_card.dart'; import 'package:stacked/stacked.dart'; @@ -19,17 +23,24 @@ class PatcherView extends StatelessWidget { builder: (context, model, child) => Scaffold( floatingActionButton: Visibility( visible: model.showPatchButton(), - child: FloatingActionButton.extended( - label: I18nText('patcherView.patchButton'), - icon: const Icon(Icons.build), - onPressed: () => model.navigateToInstaller(), - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all( - Radius.circular(16.0), - ), + child: OpenContainer( + transitionDuration: const Duration(milliseconds: 400), + openBuilder: (_, openContainer) => const InstallerView(), + openColor: Theme.of(context).colorScheme.primary, + closedColor: Colors.transparent, + closedShape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + closedBuilder: (_, openContainer) => FloatingActionButton.extended( + label: I18nText('patcherView.patchButton'), + icon: const Icon(Icons.build), + onPressed: openContainer, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + backgroundColor: Theme.of(context).colorScheme.secondary, + foregroundColor: Theme.of(context).colorScheme.surface, ), - backgroundColor: Theme.of(context).colorScheme.secondary, - foregroundColor: Colors.white, ), ), body: CustomScrollView( @@ -69,20 +80,39 @@ class PatcherView extends StatelessWidget { sliver: SliverList( delegate: SliverChildListDelegate.fixed( [ - AppSelectorCard( - onPressed: model.navigateToAppSelector, - color: Theme.of(context).colorScheme.primary, + OpenContainer( + transitionDuration: const Duration(milliseconds: 400), + openBuilder: (_, openContainer) => + const AppSelectorView(), + openColor: Theme.of(context).colorScheme.primary, + closedColor: Colors.transparent, + closedShape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + closedBuilder: (_, openContainer) => AppSelectorCard( + onPressed: openContainer, + color: Theme.of(context).colorScheme.primary, + ), ), const SizedBox(height: 16), Opacity( opacity: isDark ? (model.dimPatchesCard() ? 0.5 : 1) : (model.dimPatchesCard() ? 0.75 : 1), - child: PatchSelectorCard( - onPressed: model.dimPatchesCard() - ? () => {} - : model.navigateToPatchesSelector, - color: Theme.of(context).colorScheme.primary, + child: OpenContainer( + transitionDuration: const Duration(milliseconds: 400), + openBuilder: (_, openContainer) => + const PatchesSelectorView(), + openColor: Theme.of(context).colorScheme.primary, + closedColor: Colors.transparent, + closedShape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + closedBuilder: (_, openContainer) => PatchSelectorCard( + onPressed: + model.dimPatchesCard() ? () => {} : openContainer, + 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 9d26bce4..ab319c07 100644 --- a/lib/ui/views/patcher/patcher_viewmodel.dart +++ b/lib/ui/views/patcher/patcher_viewmodel.dart @@ -1,30 +1,13 @@ import 'package:injectable/injectable.dart'; -import 'package:revanced_manager/app/app.locator.dart'; -import 'package:revanced_manager/app/app.router.dart'; import 'package:revanced_manager/models/patch.dart'; import 'package:revanced_manager/models/patched_application.dart'; import 'package:stacked/stacked.dart'; -import 'package:stacked_services/stacked_services.dart'; @lazySingleton class PatcherViewModel extends BaseViewModel { PatchedApplication? selectedApp; List selectedPatches = []; - final NavigationService _navigationService = locator(); - - void navigateToAppSelector() { - _navigationService.navigateTo(Routes.appSelectorView); - } - - void navigateToPatchesSelector() { - _navigationService.navigateTo(Routes.patchesSelectorView); - } - - void navigateToInstaller() { - _navigationService.navigateTo(Routes.installerView); - } - bool showPatchButton() { return selectedPatches.isNotEmpty; } diff --git a/lib/ui/views/patches_selector/patches_selector_view.dart b/lib/ui/views/patches_selector/patches_selector_view.dart index 07d76250..cbeb626d 100644 --- a/lib/ui/views/patches_selector/patches_selector_view.dart +++ b/lib/ui/views/patches_selector/patches_selector_view.dart @@ -22,6 +22,22 @@ class _PatchesSelectorViewState extends State { onModelReady: (model) => model.initialize(), viewModelBuilder: () => PatchesSelectorViewModel(), builder: (context, model, child) => Scaffold( + floatingActionButton: Visibility( + visible: model.patches.isNotEmpty, + child: FloatingActionButton.extended( + label: I18nText('patchesSelectorView.doneButton'), + icon: const Icon(Icons.check), + onPressed: () { + model.selectPatches(); + Navigator.of(context).pop(); + }, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + backgroundColor: Theme.of(context).colorScheme.secondary, + foregroundColor: Theme.of(context).colorScheme.surface, + ), + ), body: SafeArea( child: Padding( padding: @@ -53,6 +69,7 @@ class _PatchesSelectorViewState extends State { const SizedBox(height: 12), Expanded( child: ListView( + padding: const EdgeInsets.only(bottom: 80), children: model .getQueriedPatches(_query) .map((patch) => PatchItem( @@ -72,23 +89,6 @@ class _PatchesSelectorViewState extends State { .toList(), ), ), - MaterialButton( - textColor: Colors.white, - color: Theme.of(context).colorScheme.secondary, - minWidth: double.infinity, - padding: const EdgeInsets.symmetric( - vertical: 12, - horizontal: 8, - ), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - onPressed: () { - model.selectPatches(); - Navigator.of(context).pop(); - }, - child: I18nText('patchesSelectorView.doneButton'), - ), ], ), ), diff --git a/lib/ui/views/root_checker/root_checker_view.dart b/lib/ui/views/root_checker/root_checker_view.dart index fd01aaba..895b0879 100644 --- a/lib/ui/views/root_checker/root_checker_view.dart +++ b/lib/ui/views/root_checker/root_checker_view.dart @@ -13,30 +13,20 @@ class RootCheckerView extends StatelessWidget { return ViewModelBuilder.reactive( 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, - ), - ), - ], + floatingActionButton: FloatingActionButton.extended( + label: I18nText('rootCheckerView.nonRootButton'), + icon: const Icon(Icons.keyboard_arrow_right), + onPressed: () => model.navigateAsNonRoot(), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + backgroundColor: Theme.of(context).colorScheme.secondary, + foregroundColor: Theme.of(context).colorScheme.surface, ), 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( @@ -60,18 +50,24 @@ class RootCheckerView extends StatelessWidget { ), ), ), - const SizedBox(height: 170), - MagiskButton( - onPressed: () => model.checkRoot(), - ), - I18nText( - 'rootCheckerView.grantedPermission', - translationParams: { - 'isRooted': model.isRooted.toString(), - }, - child: Text( - '', - style: GoogleFonts.poppins(), + Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + MagiskButton( + onPressed: () => model.navigateAsRoot(), + ), + I18nText( + 'rootCheckerView.grantedPermission', + translationParams: { + 'isRooted': model.isRooted.toString(), + }, + child: Text( + '', + 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 index d2c36c86..296610c2 100644 --- a/lib/ui/views/root_checker/root_checker_viewmodel.dart +++ b/lib/ui/views/root_checker/root_checker_viewmodel.dart @@ -9,19 +9,24 @@ class RootCheckerViewModel extends BaseViewModel { final NavigationService _navigationService = locator(); bool isRooted = false; - Future checkRoot() async { + Future navigateAsRoot() async { bool? res = await Root.isRooted(); isRooted = res != null && res == true; if (isRooted) { - navigateToHome(); + await navigateToHome(); + } else { + notifyListeners(); } - notifyListeners(); + } + + Future navigateAsNonRoot() async { + isRooted = false; + await navigateToHome(); } Future navigateToHome() async { final prefs = await SharedPreferences.getInstance(); await prefs.setBool('isRooted', isRooted); _navigationService.navigateTo(Routes.navigation); - notifyListeners(); } } diff --git a/lib/ui/widgets/contributorsView/contributors_card.dart b/lib/ui/widgets/contributorsView/contributors_card.dart index 6d755fd0..869f46de 100644 --- a/lib/ui/widgets/contributorsView/contributors_card.dart +++ b/lib/ui/widgets/contributorsView/contributors_card.dart @@ -40,7 +40,7 @@ class _ContributorsCardState extends State { padding: const EdgeInsets.all(4.0), decoration: BoxDecoration( color: Theme.of(context).colorScheme.tertiary, - borderRadius: BorderRadius.circular(8.0), + borderRadius: BorderRadius.circular(12), ), height: widget.height, child: GridView.builder( diff --git a/lib/ui/widgets/homeView/dashboard_raw_chip.dart b/lib/ui/widgets/homeView/dashboard_raw_chip.dart index 2685813c..ac995802 100644 --- a/lib/ui/widgets/homeView/dashboard_raw_chip.dart +++ b/lib/ui/widgets/homeView/dashboard_raw_chip.dart @@ -34,7 +34,7 @@ class DashboardChip extends StatelessWidget { isDark ? Theme.of(context).colorScheme.background : Colors.white, selectedColor: const Color.fromRGBO(118, 155, 209, 0.42), shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10), + borderRadius: BorderRadius.circular(12), side: BorderSide( width: 1, color: isDark diff --git a/lib/ui/widgets/patchesSelectorView/patch_item.dart b/lib/ui/widgets/patchesSelectorView/patch_item.dart index c6243a8d..f55765ca 100644 --- a/lib/ui/widgets/patchesSelectorView/patch_item.dart +++ b/lib/ui/widgets/patchesSelectorView/patch_item.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:google_fonts/google_fonts.dart'; -import 'package:revanced_manager/theme.dart'; +import 'package:revanced_manager/ui/widgets/shared/patch_text_button.dart'; // ignore: must_be_immutable class PatchItem extends StatefulWidget { @@ -87,7 +87,7 @@ class _PatchItemState extends State { scale: 1.2, child: Checkbox( value: widget.isSelected, - activeColor: Colors.blueGrey[500], + activeColor: Theme.of(context).colorScheme.secondary, onChanged: (newValue) { setState(() => widget.isSelected = newValue!); widget.onChanged(widget.isSelected); @@ -117,9 +117,7 @@ class _PatchItemState extends State { ), ), backgroundColor: MaterialStateProperty.all( - isDark - ? Theme.of(context).colorScheme.background - : Colors.white, + Colors.transparent, ), foregroundColor: MaterialStateProperty.all( Theme.of(context).colorScheme.secondary, @@ -137,10 +135,12 @@ class _PatchItemState extends State { } Future _showUnsupportedWarningDialog() { - return showDialog( + return showGeneralDialog( context: context, - builder: (context) { - return AlertDialog( + pageBuilder: (ctx, a1, a2) => Container(), + transitionBuilder: (ctx, a1, a2, child) => Transform.scale( + scale: Curves.easeInOut.transform(a1.value), + child: AlertDialog( title: I18nText('patchItem.alertDialogTitle'), content: I18nText( 'patchItem.alertDialogText', @@ -151,13 +151,17 @@ class _PatchItemState extends State { }, ), actions: [ - TextButton( - child: I18nText('okButton'), + PatchTextButton( + text: FlutterI18n.translate(context, 'okButton'), onPressed: () => Navigator.of(context).pop(), + backgroundColor: Theme.of(context).colorScheme.secondary, + borderColor: Theme.of(context).colorScheme.secondary, ) ], - ); - }, + backgroundColor: Theme.of(context).colorScheme.surface, + ), + ), + transitionDuration: const Duration(milliseconds: 400), ); } } diff --git a/lib/ui/widgets/rootCheckerView/magisk_button.dart b/lib/ui/widgets/rootCheckerView/magisk_button.dart index ed26ab30..bd9d1d23 100644 --- a/lib/ui/widgets/rootCheckerView/magisk_button.dart +++ b/lib/ui/widgets/rootCheckerView/magisk_button.dart @@ -2,7 +2,6 @@ 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; @@ -20,14 +19,12 @@ class MagiskButton extends StatelessWidget { onTap: onPressed, child: CircleAvatar( radius: 32, - backgroundColor: isDark - ? Theme.of(context).colorScheme.secondary - : const Color(0xffCBDFFC), + backgroundColor: Theme.of(context).colorScheme.secondary, child: SvgPicture.asset( 'assets/images/magisk.svg', - color: isDark ? Colors.white70 : Colors.grey[900], - height: 50, - width: 50, + color: Theme.of(context).colorScheme.surface, + height: 40, + width: 40, ), ), ), diff --git a/lib/ui/widgets/shared/application_item.dart b/lib/ui/widgets/shared/application_item.dart index 7c495e6f..3bfbd2d2 100644 --- a/lib/ui/widgets/shared/application_item.dart +++ b/lib/ui/widgets/shared/application_item.dart @@ -36,9 +36,7 @@ class ApplicationItem extends StatelessWidget { header: Container( height: 60, decoration: BoxDecoration( - borderRadius: const BorderRadius.all( - Radius.circular(16), - ), + borderRadius: BorderRadius.circular(12), color: Theme.of(context).colorScheme.primary, ), padding: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 12.0), diff --git a/lib/ui/widgets/shared/search_bar.dart b/lib/ui/widgets/shared/search_bar.dart index 220cda75..759beb13 100644 --- a/lib/ui/widgets/shared/search_bar.dart +++ b/lib/ui/widgets/shared/search_bar.dart @@ -49,6 +49,7 @@ class _SearchBarState extends State { child: TextFormField( onChanged: widget.onQueryChanged, controller: _textController, + cursorColor: Theme.of(context).textTheme.headline5!.color, decoration: InputDecoration( fillColor: widget.fillColor, filled: true, @@ -58,9 +59,10 @@ class _SearchBarState extends State { color: widget.hintTextColor, fontWeight: FontWeight.w400, ), - prefixIcon: const Icon( + prefixIcon: Icon( Icons.search, size: 24.0, + color: Theme.of(context).iconTheme.color, ), suffixIcon: _textController.text.isNotEmpty ? IconButton( @@ -88,12 +90,12 @@ class _SearchBarState extends State { ) : null, border: OutlineInputBorder( - borderRadius: BorderRadius.circular(10), + borderRadius: BorderRadius.circular(12), borderSide: BorderSide.none, ), ), style: GoogleFonts.poppins( - color: Colors.white, + color: Theme.of(context).textTheme.headline5!.color, fontWeight: FontWeight.w400, fontSize: 16, ), diff --git a/pubspec.yaml b/pubspec.yaml index f0e7afd1..6885c423 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -10,6 +10,7 @@ environment: sdk: ">=2.17.5 <3.0.0" dependencies: + animations: ^2.0.4 app_installer: ^1.1.0 cupertino_icons: ^1.0.2 device_apps: