From 645589fa0e5c853d3799fb5cc29b736caabbf835 Mon Sep 17 00:00:00 2001 From: Aunali321 Date: Sun, 7 Aug 2022 23:35:44 +0530 Subject: [PATCH 1/2] feat: Patch Item Widget. --- lib/ui/widgets/patch_item.dart | 76 ++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 lib/ui/widgets/patch_item.dart diff --git a/lib/ui/widgets/patch_item.dart b/lib/ui/widgets/patch_item.dart new file mode 100644 index 00000000..3ffe7c85 --- /dev/null +++ b/lib/ui/widgets/patch_item.dart @@ -0,0 +1,76 @@ +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; + +class PatchItem extends StatelessWidget { + final String name; + final String description; + final String version; + final bool isSelected; + + PatchItem({ + Key? key, + required this.name, + required this.description, + required this.version, + required this.isSelected, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + decoration: BoxDecoration( + color: const Color(0xFF1A1A1A), + borderRadius: BorderRadius.circular(10), + ), + padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 12), + margin: const EdgeInsets.symmetric(vertical: 4, horizontal: 8), + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Flexible( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Text( + name, + style: GoogleFonts.inter( + fontSize: 16, + fontWeight: FontWeight.w600, + ), + ), + const SizedBox(width: 4), + Text(version) + ], + ), + const SizedBox(height: 4), + Text( + description, + softWrap: true, + maxLines: 3, + overflow: TextOverflow.visible, + style: GoogleFonts.roboto( + fontSize: 14, + ), + ), + ], + ), + ), + Transform.scale( + scale: 1.2, + child: Checkbox( + value: isSelected, + onChanged: (newValue) {}, + ), + ) + ], + ) + ], + ), + ); + } +} From cceb7e64490079d53fdb6513f6847501d0f85911 Mon Sep 17 00:00:00 2001 From: Aunali321 Date: Mon, 8 Aug 2022 00:45:52 +0530 Subject: [PATCH 2/2] feat: Patches Selector Screen. --- lib/app/app.dart | 4 + lib/app/app.locator.dart | 5 +- lib/app/app.router.dart | 37 +++++++- .../views/app_selector/app_selector_view.dart | 1 + lib/ui/views/patcher/patcher_view.dart | 4 +- lib/ui/views/patcher/patcher_viewmodel.dart | 8 +- .../patches_selector_view.dart | 88 +++++++++++++++++++ .../patches_selector_viewmodel.dart | 23 +++++ lib/ui/widgets/patch_item.dart | 26 ++++-- lib/ui/widgets/search_bar.dart | 17 ++-- 10 files changed, 191 insertions(+), 22 deletions(-) create mode 100644 lib/ui/views/patches_selector/patches_selector_view.dart create mode 100644 lib/ui/views/patches_selector/patches_selector_viewmodel.dart diff --git a/lib/app/app.dart b/lib/app/app.dart index f0012276..ae53bd13 100644 --- a/lib/app/app.dart +++ b/lib/app/app.dart @@ -1,6 +1,8 @@ +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/home/home_view.dart'; import 'package:revanced_manager/ui/views/patcher/patcher_view.dart'; +import 'package:revanced_manager/ui/views/patches_selector/patches_selector_view.dart'; import 'package:stacked/stacked_annotations.dart'; import 'package:stacked_services/stacked_services.dart'; @@ -8,7 +10,9 @@ import 'package:stacked_services/stacked_services.dart'; MaterialRoute(page: HomeView), MaterialRoute(page: AppSelectorView), MaterialRoute(page: PatcherView), + MaterialRoute(page: PatchesSelectorView), ], dependencies: [ LazySingleton(classType: NavigationService), + LazySingleton(classType: PatcherService), ]) class AppSetup {} diff --git a/lib/app/app.locator.dart b/lib/app/app.locator.dart index 968c2790..17f0de78 100644 --- a/lib/app/app.locator.dart +++ b/lib/app/app.locator.dart @@ -6,11 +6,11 @@ // ignore_for_file: public_member_api_docs -// ignore: depend_on_referenced_packages import 'package:stacked_core/stacked_core.dart'; -// ignore: implementation_imports import 'package:stacked_services/src/navigation/navigation_service.dart'; +import '../services/patcher_api.dart'; + final locator = StackedLocator.instance; Future setupLocator( @@ -21,4 +21,5 @@ Future setupLocator( // Register dependencies locator.registerLazySingleton(() => NavigationService()); + locator.registerLazySingleton(() => PatcherService()); } diff --git a/lib/app/app.router.dart b/lib/app/app.router.dart index 3dd06437..f24aabaf 100644 --- a/lib/app/app.router.dart +++ b/lib/app/app.router.dart @@ -7,11 +7,12 @@ // ignore_for_file: no_leading_underscores_for_library_prefixes import 'package:flutter/material.dart'; import 'package:stacked/stacked.dart' as _i1; -import 'package:stacked_services/stacked_services.dart' as _i5; +import 'package:stacked_services/stacked_services.dart' as _i6; import '../ui/views/app_selector/app_selector_view.dart' as _i3; import '../ui/views/home/home_view.dart' as _i2; import '../ui/views/patcher/patcher_view.dart' as _i4; +import '../ui/views/patches_selector/patches_selector_view.dart' as _i5; class Routes { static const homeView = '/home-view'; @@ -20,14 +21,22 @@ class Routes { static const patcherView = '/patcher-view'; - static const all = {homeView, appSelectorView, patcherView}; + static const patchesSelectorView = '/patches-selector-view'; + + static const all = { + homeView, + appSelectorView, + patcherView, + patchesSelectorView + }; } class StackedRouter extends _i1.RouterBase { final _routes = <_i1.RouteDef>[ _i1.RouteDef(Routes.homeView, page: _i2.HomeView), _i1.RouteDef(Routes.appSelectorView, page: _i3.AppSelectorView), - _i1.RouteDef(Routes.patcherView, page: _i4.PatcherView) + _i1.RouteDef(Routes.patcherView, page: _i4.PatcherView), + _i1.RouteDef(Routes.patchesSelectorView, page: _i5.PatchesSelectorView) ]; final _pagesMap = { @@ -48,6 +57,12 @@ class StackedRouter extends _i1.RouterBase { builder: (context) => const _i4.PatcherView(), settings: data, ); + }, + _i5.PatchesSelectorView: (data) { + return MaterialPageRoute( + builder: (context) => const _i5.PatchesSelectorView(), + settings: data, + ); } }; @@ -57,7 +72,7 @@ class StackedRouter extends _i1.RouterBase { Map get pagesMap => _pagesMap; } -extension NavigatorStateExtension on _i5.NavigationService { +extension NavigatorStateExtension on _i6.NavigationService { Future navigateToHomeView( [int? routerId, bool preventDuplicates = true, @@ -99,4 +114,18 @@ extension NavigatorStateExtension on _i5.NavigationService { parameters: parameters, transition: transition); } + + Future navigateToPatchesSelectorView( + [int? routerId, + bool preventDuplicates = true, + Map? parameters, + Widget Function( + BuildContext, Animation, Animation, Widget)? + transition]) async { + navigateTo(Routes.patchesSelectorView, + id: routerId, + preventDuplicates: preventDuplicates, + parameters: parameters, + transition: transition); + } } diff --git a/lib/ui/views/app_selector/app_selector_view.dart b/lib/ui/views/app_selector/app_selector_view.dart index e31ad7c8..2c62d2e1 100644 --- a/lib/ui/views/app_selector/app_selector_view.dart +++ b/lib/ui/views/app_selector/app_selector_view.dart @@ -39,6 +39,7 @@ class _AppSelectorViewState extends State { child: Column( children: [ SearchBar( + hintText: "Search applications", onQueryChanged: (searchQuery) { setState(() { query = searchQuery; diff --git a/lib/ui/views/patcher/patcher_view.dart b/lib/ui/views/patcher/patcher_view.dart index 78bdd7e8..ff179133 100644 --- a/lib/ui/views/patcher/patcher_view.dart +++ b/lib/ui/views/patcher/patcher_view.dart @@ -43,7 +43,9 @@ class PatcherView extends StatelessWidget { onPressed: model.navigateToAppSelector, ), const SizedBox(height: 16), - const PatchSelectorCard(), + PatchSelectorCard( + onPressed: model.navigateToPatchesSelector, + ), ], ), ), diff --git a/lib/ui/views/patcher/patcher_viewmodel.dart b/lib/ui/views/patcher/patcher_viewmodel.dart index fcada627..407d038f 100644 --- a/lib/ui/views/patcher/patcher_viewmodel.dart +++ b/lib/ui/views/patcher/patcher_viewmodel.dart @@ -4,9 +4,13 @@ import 'package:stacked/stacked.dart'; import 'package:stacked_services/stacked_services.dart'; class PatcherViewModel extends BaseViewModel { - final _naviagtionService = locator(); + final _navigationService = locator(); void navigateToAppSelector() { - _naviagtionService.navigateTo(Routes.appSelectorView); + _navigationService.navigateTo(Routes.appSelectorView); + } + + void navigateToPatchesSelector() { + _navigationService.navigateTo(Routes.patchesSelectorView); } } diff --git a/lib/ui/views/patches_selector/patches_selector_view.dart b/lib/ui/views/patches_selector/patches_selector_view.dart new file mode 100644 index 00000000..4cc87d96 --- /dev/null +++ b/lib/ui/views/patches_selector/patches_selector_view.dart @@ -0,0 +1,88 @@ +import 'package:flutter/material.dart'; +import 'package:revanced_manager/models/patch.dart'; +import 'package:revanced_manager/ui/views/patches_selector/patches_selector_viewmodel.dart'; +import 'package:revanced_manager/ui/widgets/patch_item.dart'; +import 'package:revanced_manager/ui/widgets/search_bar.dart'; +import 'package:stacked/stacked.dart'; + +class PatchesSelectorView extends StatefulWidget { + const PatchesSelectorView({Key? key}) : super(key: key); + + @override + State createState() => _PatchesSelectorViewState(); +} + +class _PatchesSelectorViewState extends State { + String query = ''; + + @override + Widget build(BuildContext context) { + return ViewModelBuilder.reactive( + viewModelBuilder: () => PatchesSelectorViewModel(), + builder: (context, PatchesSelectorViewModel model, child) => Scaffold( + body: Container( + margin: const EdgeInsets.fromLTRB(6.0, 26.0, 6.0, 0), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only(top: 8.0, left: 8.0, right: 8.0), + child: SearchBar( + hintText: "Search patches", + onQueryChanged: (searchQuery) { + setState( + () { + query = searchQuery; + }, + ); + }, + ), + ), + Expanded( + child: FutureBuilder?>( + future: model.getPatches(), + builder: (context, snapshot) { + if (snapshot.hasData) { + return ListView.builder( + itemCount: snapshot.data!.length, + itemBuilder: (context, index) { + if (query.isEmpty || + query.length < 2) { + return PatchItem( + name: snapshot.data![index].simpleName, + version: snapshot.data![index].version, + description: snapshot.data![index].description, + isSelected: false, + ); + } + else if(query.isNotEmpty && + query.length >= 2 && + snapshot.data![index].simpleName.toLowerCase().contains(query.toLowerCase())) { + return PatchItem( + name: snapshot.data![index].simpleName, + version: snapshot.data![index].version, + description: snapshot.data![index].description, + isSelected: false, + ); + } + else {return Container();} + + }, + ); + } else if (snapshot.hasError) { + return Text("${snapshot.error}"); + } else { + return const Center( + child: CircularProgressIndicator(), + ); + } + }, + ), + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/ui/views/patches_selector/patches_selector_viewmodel.dart b/lib/ui/views/patches_selector/patches_selector_viewmodel.dart new file mode 100644 index 00000000..4c4c3b4f --- /dev/null +++ b/lib/ui/views/patches_selector/patches_selector_viewmodel.dart @@ -0,0 +1,23 @@ +import 'package:installed_apps/app_info.dart'; +import 'package:installed_apps/installed_apps.dart'; +import 'package:revanced_manager/models/patch.dart'; +import 'package:revanced_manager/services/patcher_api.dart'; +import 'package:stacked/stacked.dart'; + +class PatchesSelectorViewModel extends BaseViewModel { + PatcherService patcherService = PatcherService(); + List? patches = []; + AppInfo? appInfo; + + Future getApp() async { + AppInfo app = await InstalledApps.getAppInfo("com.google.android.youtube"); + appInfo = app; + } + Future?>? getPatches() async { + getApp(); + PatcherService patcherService = PatcherService(); + patcherService.loadPatches(); + return patcherService.getFilteredPatches(appInfo); + } + +} \ No newline at end of file diff --git a/lib/ui/widgets/patch_item.dart b/lib/ui/widgets/patch_item.dart index 3ffe7c85..eed9abbd 100644 --- a/lib/ui/widgets/patch_item.dart +++ b/lib/ui/widgets/patch_item.dart @@ -1,11 +1,11 @@ import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; -class PatchItem extends StatelessWidget { +class PatchItem extends StatefulWidget { final String name; final String description; final String version; - final bool isSelected; + bool isSelected; PatchItem({ Key? key, @@ -15,11 +15,16 @@ class PatchItem extends StatelessWidget { required this.isSelected, }) : super(key: key); + @override + State createState() => _PatchItemState(); +} + +class _PatchItemState extends State { @override Widget build(BuildContext context) { return Container( decoration: BoxDecoration( - color: const Color(0xFF1A1A1A), + color: const Color(0xff1B222B), borderRadius: BorderRadius.circular(10), ), padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 12), @@ -37,19 +42,19 @@ class PatchItem extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.end, children: [ Text( - name, + widget.name, style: GoogleFonts.inter( fontSize: 16, fontWeight: FontWeight.w600, ), ), const SizedBox(width: 4), - Text(version) + Text(widget.version) ], ), const SizedBox(height: 4), Text( - description, + widget.description, softWrap: true, maxLines: 3, overflow: TextOverflow.visible, @@ -63,8 +68,13 @@ class PatchItem extends StatelessWidget { Transform.scale( scale: 1.2, child: Checkbox( - value: isSelected, - onChanged: (newValue) {}, + value: widget.isSelected, + activeColor: Colors.blueGrey[500], + onChanged: (newValue) { + setState(() { + widget.isSelected = newValue!; + }); + }, ), ) ], diff --git a/lib/ui/widgets/search_bar.dart b/lib/ui/widgets/search_bar.dart index eb701809..2d617ab6 100644 --- a/lib/ui/widgets/search_bar.dart +++ b/lib/ui/widgets/search_bar.dart @@ -2,7 +2,14 @@ import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; class SearchBar extends StatefulWidget { - const SearchBar({ + String? hintText = "Search"; + Color? backgroundColor; + Color? hintTextColor; + + SearchBar({ + required this.hintText, + this.backgroundColor = const Color(0xff1B222B), + this.hintTextColor = Colors.white, Key? key, required this.onQueryChanged, }) : super(key: key); @@ -19,9 +26,9 @@ class _SearchBarState extends State { return Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(12), - color: const Color(0xff1B222B), + color: widget.backgroundColor, border: Border.all( - color: const Color(0xff1B222B), + color: widget.backgroundColor != null ? widget.backgroundColor! : Colors.white, width: 1, ), ), @@ -34,9 +41,9 @@ class _SearchBarState extends State { fillColor: Colors.blueGrey[700], filled: true, contentPadding: const EdgeInsets.all(12.0), - hintText: 'Search applications', + hintText: widget.hintText, hintStyle: GoogleFonts.poppins( - color: Colors.white, + color: widget.hintTextColor, fontWeight: FontWeight.w400, ), prefixIcon: const Icon(