mirror of
				https://github.com/ImranR98/Obtainium.git
				synced 2025-10-30 21:13:28 +01:00 
			
		
		
		
	Done w/ filter and multi select stuff
This commit is contained in:
		| @@ -7,11 +7,15 @@ class GeneratedFormModal extends StatefulWidget { | |||||||
|       {super.key, |       {super.key, | ||||||
|       required this.title, |       required this.title, | ||||||
|       required this.items, |       required this.items, | ||||||
|       required this.defaultValues}); |       required this.defaultValues, | ||||||
|  |       this.initValid = false, | ||||||
|  |       this.message = ""}); | ||||||
|  |  | ||||||
|   final String title; |   final String title; | ||||||
|  |   final String message; | ||||||
|   final List<List<GeneratedFormItem>> items; |   final List<List<GeneratedFormItem>> items; | ||||||
|   final List<String> defaultValues; |   final List<String> defaultValues; | ||||||
|  |   final bool initValid; | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   State<GeneratedFormModal> createState() => _GeneratedFormModalState(); |   State<GeneratedFormModal> createState() => _GeneratedFormModalState(); | ||||||
| @@ -21,12 +25,25 @@ class _GeneratedFormModalState extends State<GeneratedFormModal> { | |||||||
|   List<String> values = []; |   List<String> values = []; | ||||||
|   bool valid = false; |   bool valid = false; | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   void initState() { | ||||||
|  |     super.initState(); | ||||||
|  |     valid = widget.initValid; | ||||||
|  |   } | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   Widget build(BuildContext context) { |   Widget build(BuildContext context) { | ||||||
|     return AlertDialog( |     return AlertDialog( | ||||||
|       scrollable: true, |       scrollable: true, | ||||||
|       title: Text(widget.title), |       title: Text(widget.title), | ||||||
|       content: GeneratedForm( |       content: | ||||||
|  |           Column(crossAxisAlignment: CrossAxisAlignment.stretch, children: [ | ||||||
|  |         if (widget.message.isNotEmpty) Text(widget.message), | ||||||
|  |         if (widget.message.isNotEmpty) | ||||||
|  |           SizedBox( | ||||||
|  |             height: 16, | ||||||
|  |           ), | ||||||
|  |         GeneratedForm( | ||||||
|             items: widget.items, |             items: widget.items, | ||||||
|             onValueChanges: (values, valid) { |             onValueChanges: (values, valid) { | ||||||
|               setState(() { |               setState(() { | ||||||
| @@ -34,7 +51,8 @@ class _GeneratedFormModalState extends State<GeneratedFormModal> { | |||||||
|                 this.valid = valid; |                 this.valid = valid; | ||||||
|               }); |               }); | ||||||
|             }, |             }, | ||||||
|           defaultValues: widget.defaultValues), |             defaultValues: widget.defaultValues) | ||||||
|  |       ]), | ||||||
|       actions: [ |       actions: [ | ||||||
|         TextButton( |         TextButton( | ||||||
|             onPressed: () { |             onPressed: () { | ||||||
|   | |||||||
| @@ -247,9 +247,8 @@ class _AppPageState extends State<AppPage> { | |||||||
|                                                 onPressed: () { |                                                 onPressed: () { | ||||||
|                                                   HapticFeedback |                                                   HapticFeedback | ||||||
|                                                       .selectionClick(); |                                                       .selectionClick(); | ||||||
|                                                   appsProvider |                                                   appsProvider.removeApps( | ||||||
|                                                       .removeApp(app!.app.id) |                                                       [app!.app.id]).then((_) { | ||||||
|                                                       .then((_) { |  | ||||||
|                                                     int count = 0; |                                                     int count = 0; | ||||||
|                                                     Navigator.of(context) |                                                     Navigator.of(context) | ||||||
|                                                         .popUntil((_) => |                                                         .popUntil((_) => | ||||||
|   | |||||||
| @@ -43,7 +43,6 @@ class AppsPageState extends State<AppsPage> { | |||||||
|   Widget build(BuildContext context) { |   Widget build(BuildContext context) { | ||||||
|     var appsProvider = context.watch<AppsProvider>(); |     var appsProvider = context.watch<AppsProvider>(); | ||||||
|     var settingsProvider = context.watch<SettingsProvider>(); |     var settingsProvider = context.watch<SettingsProvider>(); | ||||||
|     var existingUpdateAppIds = appsProvider.getExistingUpdates(); |  | ||||||
|     var sortedApps = appsProvider.apps.values.toList(); |     var sortedApps = appsProvider.apps.values.toList(); | ||||||
|  |  | ||||||
|     selectedIds = selectedIds |     selectedIds = selectedIds | ||||||
| @@ -63,7 +62,11 @@ class AppsPageState extends State<AppsPage> { | |||||||
|     if (filter != null) { |     if (filter != null) { | ||||||
|       sortedApps = sortedApps.where((app) { |       sortedApps = sortedApps.where((app) { | ||||||
|         if (app.app.installedVersion == app.app.latestVersion && |         if (app.app.installedVersion == app.app.latestVersion && | ||||||
|             filter!.onlyNonLatest) { |             !(filter!.includeUptodate)) { | ||||||
|  |           return false; | ||||||
|  |         } | ||||||
|  |         if (app.app.installedVersion == null && | ||||||
|  |             !(filter!.includeNonInstalled)) { | ||||||
|           return false; |           return false; | ||||||
|         } |         } | ||||||
|         if (filter!.nameFilter.isEmpty && filter!.authorFilter.isEmpty) { |         if (filter!.nameFilter.isEmpty && filter!.authorFilter.isEmpty) { | ||||||
| @@ -184,38 +187,133 @@ class AppsPageState extends State<AppsPage> { | |||||||
|                     ? 'Select All' |                     ? 'Select All' | ||||||
|                     : 'Deselect ${selectedIds.length.toString()}')), |                     : 'Deselect ${selectedIds.length.toString()}')), | ||||||
|             const VerticalDivider(), |             const VerticalDivider(), | ||||||
|             const Spacer(), |             Expanded( | ||||||
|             selectedIds.isEmpty |                 child: selectedIds.isEmpty | ||||||
|                 ? const SizedBox() |                     ? Container() | ||||||
|                 : IconButton( |                     : Row( | ||||||
|  |                         mainAxisAlignment: MainAxisAlignment.spaceEvenly, | ||||||
|  |                         children: [ | ||||||
|  |                           IconButton( | ||||||
|                             onPressed: () { |                             onPressed: () { | ||||||
|                       // TODO: Delete selected Apps after confirming |                               showDialog<List<String>?>( | ||||||
|  |                                   context: context, | ||||||
|  |                                   builder: (BuildContext ctx) { | ||||||
|  |                                     return GeneratedFormModal( | ||||||
|  |                                       title: 'Remove Selected Apps?', | ||||||
|  |                                       items: const [], | ||||||
|  |                                       defaultValues: const [], | ||||||
|  |                                       initValid: true, | ||||||
|  |                                       message: | ||||||
|  |                                           '${selectedIds.length} App${selectedIds.length == 1 ? '' : 's'} will be removed from Obtainium but remain installed. You still need to uninstall ${selectedIds.length == 1 ? 'it' : 'them'} manually.', | ||||||
|  |                                     ); | ||||||
|  |                                   }).then((values) { | ||||||
|  |                                 if (values != null) { | ||||||
|  |                                   appsProvider.removeApps(selectedIds.toList()); | ||||||
|  |                                 } | ||||||
|  |                               }); | ||||||
|                             }, |                             }, | ||||||
|                     icon: const Icon(Icons.install_mobile_outlined)), |                             icon: const Icon(Icons.delete_outline_outlined), | ||||||
|             selectedIds.isEmpty |                           ), | ||||||
|                 ? const SizedBox() |                           IconButton( | ||||||
|                 : IconButton( |                               onPressed: appsProvider.areDownloadsRunning() || | ||||||
|                     onPressed: () { |                                       selectedIds | ||||||
|                       // TODO: Install selected Apps if they are not up to date after confirming (replace existing button) |                                           .where((id) => | ||||||
|                     }, |                                               appsProvider.apps[id]!.app | ||||||
|                     icon: const Icon(Icons.delete_outline_rounded)), |                                                   .installedVersion != | ||||||
|             existingUpdateAppIds.isEmpty || filter != null |                                               appsProvider | ||||||
|                 ? const SizedBox() |                                                   .apps[id]!.app.latestVersion) | ||||||
|                 : IconButton( |                                           .isEmpty | ||||||
|                     onPressed: appsProvider.areDownloadsRunning() |  | ||||||
|                                   ? null |                                   ? null | ||||||
|                                   : () { |                                   : () { | ||||||
|                                       HapticFeedback.heavyImpact(); |                                       HapticFeedback.heavyImpact(); | ||||||
|                             settingsProvider.getInstallPermission().then((_) { |                                       var existingUpdateIdsSelected = | ||||||
|                               appsProvider.downloadAndInstallLatestApp( |                                           appsProvider | ||||||
|                                   existingUpdateAppIds, context); |                                               .getExistingUpdates( | ||||||
|  |                                                   installedOnly: true) | ||||||
|  |                                               .where((element) => | ||||||
|  |                                                   selectedIds.contains(element)) | ||||||
|  |                                               .toList(); | ||||||
|  |                                       var newInstallIdsSelected = appsProvider | ||||||
|  |                                           .getExistingUpdates( | ||||||
|  |                                               nonInstalledOnly: true) | ||||||
|  |                                           .where((element) => | ||||||
|  |                                               selectedIds.contains(element)) | ||||||
|  |                                           .toList(); | ||||||
|  |                                       List<List<GeneratedFormItem>> formInputs = | ||||||
|  |                                           []; | ||||||
|  |                                       if (existingUpdateIdsSelected | ||||||
|  |                                               .isNotEmpty && | ||||||
|  |                                           newInstallIdsSelected.isNotEmpty) { | ||||||
|  |                                         formInputs.add([ | ||||||
|  |                                           GeneratedFormItem( | ||||||
|  |                                               label: | ||||||
|  |                                                   "Update ${existingUpdateIdsSelected.length} Apps?", | ||||||
|  |                                               type: FormItemType.bool) | ||||||
|  |                                         ]); | ||||||
|  |                                         formInputs.add([ | ||||||
|  |                                           GeneratedFormItem( | ||||||
|  |                                               label: | ||||||
|  |                                                   "Install ${newInstallIdsSelected.length} new Apps?", | ||||||
|  |                                               type: FormItemType.bool) | ||||||
|  |                                         ]); | ||||||
|  |                                       } | ||||||
|  |                                       showDialog<List<String>?>( | ||||||
|  |                                           context: context, | ||||||
|  |                                           builder: (BuildContext ctx) { | ||||||
|  |                                             return GeneratedFormModal( | ||||||
|  |                                               title: "Install Selected Apps?", | ||||||
|  |                                               message: | ||||||
|  |                                                   "${existingUpdateIdsSelected.length} update${existingUpdateIdsSelected.length == 1 ? '' : 's'} and ${newInstallIdsSelected.length} new install${newInstallIdsSelected.length == 1 ? '' : 's'}.", | ||||||
|  |                                               items: formInputs, | ||||||
|  |                                               defaultValues: const [ | ||||||
|  |                                                 "true", | ||||||
|  |                                                 "true" | ||||||
|  |                                               ], | ||||||
|  |                                               initValid: true, | ||||||
|  |                                             ); | ||||||
|  |                                           }).then((values) { | ||||||
|  |                                         if (values != null) { | ||||||
|  |                                           bool shouldInstallUpdates = | ||||||
|  |                                               values.length < 2 || | ||||||
|  |                                                   values[0] == "true"; | ||||||
|  |                                           bool shouldInstallNew = | ||||||
|  |                                               values.length < 2 || | ||||||
|  |                                                   values[1] == "true"; | ||||||
|  |                                           settingsProvider | ||||||
|  |                                               .getInstallPermission() | ||||||
|  |                                               .then((_) { | ||||||
|  |                                             List<String> toInstall = []; | ||||||
|  |                                             if (shouldInstallUpdates) { | ||||||
|  |                                               toInstall.addAll( | ||||||
|  |                                                   existingUpdateIdsSelected); | ||||||
|  |                                             } | ||||||
|  |                                             if (shouldInstallNew) { | ||||||
|  |                                               toInstall.addAll( | ||||||
|  |                                                   newInstallIdsSelected); | ||||||
|  |                                             } | ||||||
|  |                                             appsProvider | ||||||
|  |                                                 .downloadAndInstallLatestApp( | ||||||
|  |                                                     toInstall, context); | ||||||
|  |                                           }); | ||||||
|  |                                         } | ||||||
|                                       }); |                                       }); | ||||||
|                                     }, |                                     }, | ||||||
|                     icon: const Icon(Icons.install_mobile_outlined), |                               icon: const Icon( | ||||||
|                   ), |                                 Icons.file_download_outlined, | ||||||
|  |                               )), | ||||||
|  |                         ], | ||||||
|  |                       )), | ||||||
|  |             const VerticalDivider(), | ||||||
|             appsProvider.apps.isEmpty |             appsProvider.apps.isEmpty | ||||||
|                 ? const SizedBox() |                 ? const SizedBox() | ||||||
|                 : IconButton( |                 : TextButton.icon( | ||||||
|  |                     label: Text( | ||||||
|  |                       filter == null ? 'Filter' : 'Filter *', | ||||||
|  |                       style: TextStyle( | ||||||
|  |                           fontWeight: filter == null | ||||||
|  |                               ? FontWeight.normal | ||||||
|  |                               : FontWeight.bold), | ||||||
|  |                     ), | ||||||
|                     onPressed: () { |                     onPressed: () { | ||||||
|                       showDialog<List<String>?>( |                       showDialog<List<String>?>( | ||||||
|                           context: context, |                           context: context, | ||||||
| @@ -231,27 +329,25 @@ class AppsPageState extends State<AppsPage> { | |||||||
|                                   ], |                                   ], | ||||||
|                                   [ |                                   [ | ||||||
|                                     GeneratedFormItem( |                                     GeneratedFormItem( | ||||||
|                                         label: "Ignore Up-to-Date Apps", |                                         label: "Up to Date Apps", | ||||||
|  |                                         type: FormItemType.bool) | ||||||
|  |                                   ], | ||||||
|  |                                   [ | ||||||
|  |                                     GeneratedFormItem( | ||||||
|  |                                         label: "Non-Installed Apps", | ||||||
|                                         type: FormItemType.bool) |                                         type: FormItemType.bool) | ||||||
|                                   ] |                                   ] | ||||||
|                                 ], |                                 ], | ||||||
|                                 defaultValues: filter == null |                                 defaultValues: filter == null | ||||||
|                                     ? [] |                                     ? AppsFilter().toValuesArray() | ||||||
|                                     : [ |                                     : filter!.toValuesArray()); | ||||||
|                                         filter!.nameFilter, |  | ||||||
|                                         filter!.authorFilter, |  | ||||||
|                                         filter!.onlyNonLatest ? 'true' : '' |  | ||||||
|                                       ]); |  | ||||||
|                           }).then((values) { |                           }).then((values) { | ||||||
|                         if (values != null && |                         if (values != null) { | ||||||
|                             values |  | ||||||
|                                 .where((element) => element.isNotEmpty) |  | ||||||
|                                 .isNotEmpty) { |  | ||||||
|                           setState(() { |                           setState(() { | ||||||
|                             filter = AppsFilter( |                             filter = AppsFilter.fromValuesArray(values); | ||||||
|                                 nameFilter: values[0], |                             if (AppsFilter().isIdenticalTo(filter!)) { | ||||||
|                                 authorFilter: values[1], |                               filter = null; | ||||||
|                                 onlyNonLatest: values[2] == "true"); |                             } | ||||||
|                           }); |                           }); | ||||||
|                         } else { |                         } else { | ||||||
|                           setState(() { |                           setState(() { | ||||||
| @@ -260,8 +356,7 @@ class AppsPageState extends State<AppsPage> { | |||||||
|                         } |                         } | ||||||
|                       }); |                       }); | ||||||
|                     }, |                     }, | ||||||
|                     icon: Icon( |                     icon: const Icon(Icons.filter_list_rounded)) | ||||||
|                         filter == null ? Icons.search : Icons.manage_search)) |  | ||||||
|           ], |           ], | ||||||
|         ), |         ), | ||||||
|       ], |       ], | ||||||
| @@ -272,10 +367,34 @@ class AppsPageState extends State<AppsPage> { | |||||||
| class AppsFilter { | class AppsFilter { | ||||||
|   late String nameFilter; |   late String nameFilter; | ||||||
|   late String authorFilter; |   late String authorFilter; | ||||||
|   late bool onlyNonLatest; |   late bool includeUptodate; | ||||||
|  |   late bool includeNonInstalled; | ||||||
|  |  | ||||||
|   AppsFilter( |   AppsFilter( | ||||||
|       {this.nameFilter = "", |       {this.nameFilter = "", | ||||||
|       this.authorFilter = "", |       this.authorFilter = "", | ||||||
|       this.onlyNonLatest = false}); |       this.includeUptodate = true, | ||||||
|  |       this.includeNonInstalled = true}); | ||||||
|  |  | ||||||
|  |   List<String> toValuesArray() { | ||||||
|  |     return [ | ||||||
|  |       nameFilter, | ||||||
|  |       authorFilter, | ||||||
|  |       includeUptodate ? "true" : "", | ||||||
|  |       includeNonInstalled ? "true" : "" | ||||||
|  |     ]; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   AppsFilter.fromValuesArray(List<String> values) { | ||||||
|  |     nameFilter = values[0]; | ||||||
|  |     authorFilter = values[1]; | ||||||
|  |     includeUptodate = values[2] == "true"; | ||||||
|  |     includeNonInstalled = values[3] == "true"; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   bool isIdenticalTo(AppsFilter other) => | ||||||
|  |       authorFilter.trim() == other.authorFilter.trim() && | ||||||
|  |       nameFilter.trim() == other.nameFilter.trim() && | ||||||
|  |       includeUptodate == other.includeUptodate && | ||||||
|  |       includeNonInstalled == other.includeNonInstalled; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -98,7 +98,7 @@ class AppsProvider with ChangeNotifier { | |||||||
|       .isNotEmpty; |       .isNotEmpty; | ||||||
|  |  | ||||||
|   Future<bool> canInstallSilently(App app) async { |   Future<bool> canInstallSilently(App app) async { | ||||||
|     // TODO: This is unreliable - try to get from OS |     // TODO: This is unreliable - try to get from OS in the future | ||||||
|     var osInfo = await DeviceInfoPlugin().androidInfo; |     var osInfo = await DeviceInfoPlugin().androidInfo; | ||||||
|     return app.installedVersion != null && |     return app.installedVersion != null && | ||||||
|         osInfo.version.sdkInt! >= 30 && |         osInfo.version.sdkInt! >= 30 && | ||||||
| @@ -203,9 +203,11 @@ class AppsProvider with ChangeNotifier { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (context != null) { |     if (context != null) { | ||||||
|       for (var i in regularInstalls) { |       if (regularInstalls.isNotEmpty) { | ||||||
|         // ignore: use_build_context_synchronously |         // ignore: use_build_context_synchronously | ||||||
|         await askUserToReturnToForeground(context); |         await askUserToReturnToForeground(context); | ||||||
|  |       } | ||||||
|  |       for (var i in regularInstalls) { | ||||||
|         await installApk(i); |         await installApk(i); | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
| @@ -256,7 +258,8 @@ class AppsProvider with ChangeNotifier { | |||||||
|     notifyListeners(); |     notifyListeners(); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   Future<void> removeApp(String appId) async { |   Future<void> removeApps(List<String> appIds) async { | ||||||
|  |     for (var appId in appIds) { | ||||||
|       File file = File('${(await getAppsDir()).path}/$appId.json'); |       File file = File('${(await getAppsDir()).path}/$appId.json'); | ||||||
|       if (file.existsSync()) { |       if (file.existsSync()) { | ||||||
|         file.deleteSync(); |         file.deleteSync(); | ||||||
| @@ -264,8 +267,11 @@ class AppsProvider with ChangeNotifier { | |||||||
|       if (apps.containsKey(appId)) { |       if (apps.containsKey(appId)) { | ||||||
|         apps.remove(appId); |         apps.remove(appId); | ||||||
|       } |       } | ||||||
|  |     } | ||||||
|  |     if (appIds.isNotEmpty) { | ||||||
|       notifyListeners(); |       notifyListeners(); | ||||||
|     } |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|   bool checkAppObjectForUpdate(App app) { |   bool checkAppObjectForUpdate(App app) { | ||||||
|     if (!apps.containsKey(app.id)) { |     if (!apps.containsKey(app.id)) { | ||||||
| @@ -309,16 +315,22 @@ class AppsProvider with ChangeNotifier { | |||||||
|     return updates; |     return updates; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   List<String> getExistingUpdates({bool installedOnly = false}) { |   List<String> getExistingUpdates( | ||||||
|  |       {bool installedOnly = false, bool nonInstalledOnly = false}) { | ||||||
|     List<String> updateAppIds = []; |     List<String> updateAppIds = []; | ||||||
|     List<String> appIds = apps.keys.toList(); |     List<String> appIds = apps.keys.toList(); | ||||||
|     for (int i = 0; i < appIds.length; i++) { |     for (int i = 0; i < appIds.length; i++) { | ||||||
|       App? app = apps[appIds[i]]!.app; |       App? app = apps[appIds[i]]!.app; | ||||||
|       if (app.installedVersion != app.latestVersion && |       if (app.installedVersion != app.latestVersion && | ||||||
|           (app.installedVersion != null || !installedOnly)) { |           (!installedOnly || !nonInstalledOnly)) { | ||||||
|  |         if ((app.installedVersion == null && | ||||||
|  |                 (nonInstalledOnly || !installedOnly) || | ||||||
|  |             (app.installedVersion != null && | ||||||
|  |                 (installedOnly || !nonInstalledOnly)))) { | ||||||
|           updateAppIds.add(app.id); |           updateAppIds.add(app.id); | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|  |     } | ||||||
|     return updateAppIds; |     return updateAppIds; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user