fix: add animations and fix some UI incoherences

This commit is contained in:
Alberto Ponces 2022-09-01 01:25:19 +01:00
parent 596d4f0def
commit a580375078
16 changed files with 153 additions and 122 deletions

View File

@ -91,6 +91,7 @@
"widgetTitle": "Is your device rooted?", "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!", "widgetDescription": "Don't know what this means or prefer to use non-root version? Just click on the button below!",
"grantPermission": "Grant Root Permission", "grantPermission": "Grant Root Permission",
"grantedPermission": "Magisk permission granted: {isRooted}" "grantedPermission": "Magisk permission granted: {isRooted}",
"nonRootButton": "Nonroot"
} }
} }

View File

@ -1,3 +1,4 @@
import 'package:animations/animations.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:flutter_i18n/flutter_i18n.dart';
// ignore: depend_on_referenced_packages // ignore: depend_on_referenced_packages
@ -89,7 +90,21 @@ class Navigation extends StatelessWidget {
return ViewModelBuilder<MainViewModel>.reactive( return ViewModelBuilder<MainViewModel>.reactive(
viewModelBuilder: () => locator<MainViewModel>(), viewModelBuilder: () => locator<MainViewModel>(),
builder: (context, model, child) => Scaffold( builder: (context, model, child) => Scaffold(
body: getViewForIndex(model.currentIndex), body: PageTransitionSwitcher(
duration: const Duration(milliseconds: 400),
transitionBuilder: (
Widget child,
Animation<double> animation,
Animation<double> secondaryAnimation,
) {
return FadeThroughTransition(
animation: animation,
secondaryAnimation: secondaryAnimation,
child: child,
);
},
child: getViewForIndex(model.currentIndex),
),
bottomNavigationBar: NavigationBar( bottomNavigationBar: NavigationBar(
onDestinationSelected: model.setIndex, onDestinationSelected: model.setIndex,
selectedIndex: model.currentIndex, selectedIndex: model.currentIndex,

View File

@ -29,13 +29,11 @@ class _AppSelectorViewState extends State<AppSelectorView> {
model.selectAppFromStorage(context); model.selectAppFromStorage(context);
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },
shape: const RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all( borderRadius: BorderRadius.circular(12),
Radius.circular(16.0),
),
), ),
backgroundColor: Theme.of(context).colorScheme.secondary, backgroundColor: Theme.of(context).colorScheme.secondary,
foregroundColor: Colors.white, foregroundColor: Theme.of(context).colorScheme.surface,
), ),
body: SafeArea( body: SafeArea(
child: Padding( child: Padding(
@ -73,6 +71,7 @@ class _AppSelectorViewState extends State<AppSelectorView> {
const SizedBox(height: 12), const SizedBox(height: 12),
Expanded( Expanded(
child: ListView( child: ListView(
padding: const EdgeInsets.only(bottom: 80),
children: model children: model
.getFilteredApps(_query) .getFilteredApps(_query)
.map((app) => InkWell( .map((app) => InkWell(

View File

@ -70,7 +70,7 @@ class InstallerView extends StatelessWidget {
width: double.infinity, width: double.infinity,
decoration: BoxDecoration( decoration: BoxDecoration(
color: Theme.of(context).colorScheme.primary, color: Theme.of(context).colorScheme.primary,
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(12),
), ),
child: Text( child: Text(
model.logs, model.logs,

View File

@ -1,9 +1,13 @@
import 'package:animations/animations.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:flutter_i18n/flutter_i18n.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/app/app.locator.dart';
import 'package:revanced_manager/theme.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/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/app_selector_card.dart';
import 'package:revanced_manager/ui/widgets/patcherView/patch_selector_card.dart'; import 'package:revanced_manager/ui/widgets/patcherView/patch_selector_card.dart';
import 'package:stacked/stacked.dart'; import 'package:stacked/stacked.dart';
@ -19,17 +23,24 @@ class PatcherView extends StatelessWidget {
builder: (context, model, child) => Scaffold( builder: (context, model, child) => Scaffold(
floatingActionButton: Visibility( floatingActionButton: Visibility(
visible: model.showPatchButton(), visible: model.showPatchButton(),
child: FloatingActionButton.extended( child: OpenContainer(
label: I18nText('patcherView.patchButton'), transitionDuration: const Duration(milliseconds: 400),
icon: const Icon(Icons.build), openBuilder: (_, openContainer) => const InstallerView(),
onPressed: () => model.navigateToInstaller(), openColor: Theme.of(context).colorScheme.primary,
shape: const RoundedRectangleBorder( closedColor: Colors.transparent,
borderRadius: BorderRadius.all( closedShape: RoundedRectangleBorder(
Radius.circular(16.0), 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( body: CustomScrollView(
@ -69,20 +80,39 @@ class PatcherView extends StatelessWidget {
sliver: SliverList( sliver: SliverList(
delegate: SliverChildListDelegate.fixed( delegate: SliverChildListDelegate.fixed(
<Widget>[ <Widget>[
AppSelectorCard( OpenContainer(
onPressed: model.navigateToAppSelector, transitionDuration: const Duration(milliseconds: 400),
color: Theme.of(context).colorScheme.primary, 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), const SizedBox(height: 16),
Opacity( Opacity(
opacity: isDark opacity: isDark
? (model.dimPatchesCard() ? 0.5 : 1) ? (model.dimPatchesCard() ? 0.5 : 1)
: (model.dimPatchesCard() ? 0.75 : 1), : (model.dimPatchesCard() ? 0.75 : 1),
child: PatchSelectorCard( child: OpenContainer(
onPressed: model.dimPatchesCard() transitionDuration: const Duration(milliseconds: 400),
? () => {} openBuilder: (_, openContainer) =>
: model.navigateToPatchesSelector, const PatchesSelectorView(),
color: Theme.of(context).colorScheme.primary, 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,
),
), ),
), ),
], ],

View File

@ -1,30 +1,13 @@
import 'package:injectable/injectable.dart'; 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/patch.dart';
import 'package:revanced_manager/models/patched_application.dart'; import 'package:revanced_manager/models/patched_application.dart';
import 'package:stacked/stacked.dart'; import 'package:stacked/stacked.dart';
import 'package:stacked_services/stacked_services.dart';
@lazySingleton @lazySingleton
class PatcherViewModel extends BaseViewModel { class PatcherViewModel extends BaseViewModel {
PatchedApplication? selectedApp; PatchedApplication? selectedApp;
List<Patch> selectedPatches = []; List<Patch> selectedPatches = [];
final NavigationService _navigationService = locator<NavigationService>();
void navigateToAppSelector() {
_navigationService.navigateTo(Routes.appSelectorView);
}
void navigateToPatchesSelector() {
_navigationService.navigateTo(Routes.patchesSelectorView);
}
void navigateToInstaller() {
_navigationService.navigateTo(Routes.installerView);
}
bool showPatchButton() { bool showPatchButton() {
return selectedPatches.isNotEmpty; return selectedPatches.isNotEmpty;
} }

View File

@ -22,6 +22,22 @@ class _PatchesSelectorViewState extends State<PatchesSelectorView> {
onModelReady: (model) => model.initialize(), onModelReady: (model) => model.initialize(),
viewModelBuilder: () => PatchesSelectorViewModel(), viewModelBuilder: () => PatchesSelectorViewModel(),
builder: (context, model, child) => Scaffold( 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( body: SafeArea(
child: Padding( child: Padding(
padding: padding:
@ -53,6 +69,7 @@ class _PatchesSelectorViewState extends State<PatchesSelectorView> {
const SizedBox(height: 12), const SizedBox(height: 12),
Expanded( Expanded(
child: ListView( child: ListView(
padding: const EdgeInsets.only(bottom: 80),
children: model children: model
.getQueriedPatches(_query) .getQueriedPatches(_query)
.map((patch) => PatchItem( .map((patch) => PatchItem(
@ -72,23 +89,6 @@ class _PatchesSelectorViewState extends State<PatchesSelectorView> {
.toList(), .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'),
),
], ],
), ),
), ),

View File

@ -13,30 +13,20 @@ class RootCheckerView extends StatelessWidget {
return ViewModelBuilder<RootCheckerViewModel>.reactive( return ViewModelBuilder<RootCheckerViewModel>.reactive(
viewModelBuilder: () => RootCheckerViewModel(), viewModelBuilder: () => RootCheckerViewModel(),
builder: (context, model, child) => Scaffold( builder: (context, model, child) => Scaffold(
floatingActionButton: Column( floatingActionButton: FloatingActionButton.extended(
mainAxisAlignment: MainAxisAlignment.end, label: I18nText('rootCheckerView.nonRootButton'),
children: [ icon: const Icon(Icons.keyboard_arrow_right),
const Text('nonroot'), onPressed: () => model.navigateAsNonRoot(),
const SizedBox(height: 8), shape: RoundedRectangleBorder(
FloatingActionButton( borderRadius: BorderRadius.circular(12),
onPressed: model.navigateToHome, ),
backgroundColor: Theme.of(context).colorScheme.secondary, backgroundColor: Theme.of(context).colorScheme.secondary,
foregroundColor: Colors.white, foregroundColor: Theme.of(context).colorScheme.surface,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(48),
),
child: const Icon(
Icons.keyboard_arrow_right,
size: 32,
),
),
],
), ),
body: Container( body: Container(
height: double.infinity, height: double.infinity,
padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 28.0), padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 28.0),
child: Column( child: Column(
mainAxisSize: MainAxisSize.max,
children: [ children: [
const SizedBox(height: 120), const SizedBox(height: 120),
I18nText( I18nText(
@ -60,18 +50,24 @@ class RootCheckerView extends StatelessWidget {
), ),
), ),
), ),
const SizedBox(height: 170), Expanded(
MagiskButton( child: Column(
onPressed: () => model.checkRoot(), mainAxisAlignment: MainAxisAlignment.center,
), children: [
I18nText( MagiskButton(
'rootCheckerView.grantedPermission', onPressed: () => model.navigateAsRoot(),
translationParams: { ),
'isRooted': model.isRooted.toString(), I18nText(
}, 'rootCheckerView.grantedPermission',
child: Text( translationParams: {
'', 'isRooted': model.isRooted.toString(),
style: GoogleFonts.poppins(), },
child: Text(
'',
style: GoogleFonts.poppins(),
),
),
],
), ),
), ),
], ],

View File

@ -9,19 +9,24 @@ class RootCheckerViewModel extends BaseViewModel {
final NavigationService _navigationService = locator<NavigationService>(); final NavigationService _navigationService = locator<NavigationService>();
bool isRooted = false; bool isRooted = false;
Future<void> checkRoot() async { Future<void> navigateAsRoot() async {
bool? res = await Root.isRooted(); bool? res = await Root.isRooted();
isRooted = res != null && res == true; isRooted = res != null && res == true;
if (isRooted) { if (isRooted) {
navigateToHome(); await navigateToHome();
} else {
notifyListeners();
} }
notifyListeners(); }
Future<void> navigateAsNonRoot() async {
isRooted = false;
await navigateToHome();
} }
Future<void> navigateToHome() async { Future<void> navigateToHome() async {
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
await prefs.setBool('isRooted', isRooted); await prefs.setBool('isRooted', isRooted);
_navigationService.navigateTo(Routes.navigation); _navigationService.navigateTo(Routes.navigation);
notifyListeners();
} }
} }

View File

@ -40,7 +40,7 @@ class _ContributorsCardState extends State<ContributorsCard> {
padding: const EdgeInsets.all(4.0), padding: const EdgeInsets.all(4.0),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Theme.of(context).colorScheme.tertiary, color: Theme.of(context).colorScheme.tertiary,
borderRadius: BorderRadius.circular(8.0), borderRadius: BorderRadius.circular(12),
), ),
height: widget.height, height: widget.height,
child: GridView.builder( child: GridView.builder(

View File

@ -34,7 +34,7 @@ class DashboardChip extends StatelessWidget {
isDark ? Theme.of(context).colorScheme.background : Colors.white, isDark ? Theme.of(context).colorScheme.background : Colors.white,
selectedColor: const Color.fromRGBO(118, 155, 209, 0.42), selectedColor: const Color.fromRGBO(118, 155, 209, 0.42),
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(12),
side: BorderSide( side: BorderSide(
width: 1, width: 1,
color: isDark color: isDark

View File

@ -1,7 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:flutter_i18n/flutter_i18n.dart';
import 'package:google_fonts/google_fonts.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 // ignore: must_be_immutable
class PatchItem extends StatefulWidget { class PatchItem extends StatefulWidget {
@ -87,7 +87,7 @@ class _PatchItemState extends State<PatchItem> {
scale: 1.2, scale: 1.2,
child: Checkbox( child: Checkbox(
value: widget.isSelected, value: widget.isSelected,
activeColor: Colors.blueGrey[500], activeColor: Theme.of(context).colorScheme.secondary,
onChanged: (newValue) { onChanged: (newValue) {
setState(() => widget.isSelected = newValue!); setState(() => widget.isSelected = newValue!);
widget.onChanged(widget.isSelected); widget.onChanged(widget.isSelected);
@ -117,9 +117,7 @@ class _PatchItemState extends State<PatchItem> {
), ),
), ),
backgroundColor: MaterialStateProperty.all( backgroundColor: MaterialStateProperty.all(
isDark Colors.transparent,
? Theme.of(context).colorScheme.background
: Colors.white,
), ),
foregroundColor: MaterialStateProperty.all( foregroundColor: MaterialStateProperty.all(
Theme.of(context).colorScheme.secondary, Theme.of(context).colorScheme.secondary,
@ -137,10 +135,12 @@ class _PatchItemState extends State<PatchItem> {
} }
Future<void> _showUnsupportedWarningDialog() { Future<void> _showUnsupportedWarningDialog() {
return showDialog( return showGeneralDialog(
context: context, context: context,
builder: (context) { pageBuilder: (ctx, a1, a2) => Container(),
return AlertDialog( transitionBuilder: (ctx, a1, a2, child) => Transform.scale(
scale: Curves.easeInOut.transform(a1.value),
child: AlertDialog(
title: I18nText('patchItem.alertDialogTitle'), title: I18nText('patchItem.alertDialogTitle'),
content: I18nText( content: I18nText(
'patchItem.alertDialogText', 'patchItem.alertDialogText',
@ -151,13 +151,17 @@ class _PatchItemState extends State<PatchItem> {
}, },
), ),
actions: [ actions: [
TextButton( PatchTextButton(
child: I18nText('okButton'), text: FlutterI18n.translate(context, 'okButton'),
onPressed: () => Navigator.of(context).pop(), 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),
); );
} }
} }

View File

@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
import 'package:flutter_i18n/widgets/I18nText.dart'; import 'package:flutter_i18n/widgets/I18nText.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
import 'package:revanced_manager/theme.dart';
class MagiskButton extends StatelessWidget { class MagiskButton extends StatelessWidget {
final Function() onPressed; final Function() onPressed;
@ -20,14 +19,12 @@ class MagiskButton extends StatelessWidget {
onTap: onPressed, onTap: onPressed,
child: CircleAvatar( child: CircleAvatar(
radius: 32, radius: 32,
backgroundColor: isDark backgroundColor: Theme.of(context).colorScheme.secondary,
? Theme.of(context).colorScheme.secondary
: const Color(0xffCBDFFC),
child: SvgPicture.asset( child: SvgPicture.asset(
'assets/images/magisk.svg', 'assets/images/magisk.svg',
color: isDark ? Colors.white70 : Colors.grey[900], color: Theme.of(context).colorScheme.surface,
height: 50, height: 40,
width: 50, width: 40,
), ),
), ),
), ),

View File

@ -36,9 +36,7 @@ class ApplicationItem extends StatelessWidget {
header: Container( header: Container(
height: 60, height: 60,
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: const BorderRadius.all( borderRadius: BorderRadius.circular(12),
Radius.circular(16),
),
color: Theme.of(context).colorScheme.primary, color: Theme.of(context).colorScheme.primary,
), ),
padding: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 12.0), padding: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 12.0),

View File

@ -49,6 +49,7 @@ class _SearchBarState extends State<SearchBar> {
child: TextFormField( child: TextFormField(
onChanged: widget.onQueryChanged, onChanged: widget.onQueryChanged,
controller: _textController, controller: _textController,
cursorColor: Theme.of(context).textTheme.headline5!.color,
decoration: InputDecoration( decoration: InputDecoration(
fillColor: widget.fillColor, fillColor: widget.fillColor,
filled: true, filled: true,
@ -58,9 +59,10 @@ class _SearchBarState extends State<SearchBar> {
color: widget.hintTextColor, color: widget.hintTextColor,
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,
), ),
prefixIcon: const Icon( prefixIcon: Icon(
Icons.search, Icons.search,
size: 24.0, size: 24.0,
color: Theme.of(context).iconTheme.color,
), ),
suffixIcon: _textController.text.isNotEmpty suffixIcon: _textController.text.isNotEmpty
? IconButton( ? IconButton(
@ -88,12 +90,12 @@ class _SearchBarState extends State<SearchBar> {
) )
: null, : null,
border: OutlineInputBorder( border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(12),
borderSide: BorderSide.none, borderSide: BorderSide.none,
), ),
), ),
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
color: Colors.white, color: Theme.of(context).textTheme.headline5!.color,
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,
fontSize: 16, fontSize: 16,
), ),

View File

@ -10,6 +10,7 @@ environment:
sdk: ">=2.17.5 <3.0.0" sdk: ">=2.17.5 <3.0.0"
dependencies: dependencies:
animations: ^2.0.4
app_installer: ^1.1.0 app_installer: ^1.1.0
cupertino_icons: ^1.0.2 cupertino_icons: ^1.0.2
device_apps: device_apps: