From 45e5544c5be575babc055bb3288c8a2d042e1774 Mon Sep 17 00:00:00 2001 From: Imran Remtulla Date: Sat, 24 Sep 2022 21:10:29 -0400 Subject: [PATCH] Added apps list selection (actions incomplete) --- lib/main.dart | 2 +- lib/pages/apps.dart | 304 +++++++++++++++++++++++++++----------------- lib/pages/home.dart | 8 +- 3 files changed, 195 insertions(+), 119 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 17864a7..95e3da4 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -99,7 +99,7 @@ class MyApp extends StatelessWidget { if (settingsProvider.updateInterval > 0) { Workmanager().registerPeriodicTask('bg-update-check', 'bg-update-check', frequency: Duration(minutes: settingsProvider.updateInterval), - // initialDelay: Duration(minutes: settingsProvider.updateInterval), + initialDelay: Duration(minutes: settingsProvider.updateInterval), constraints: Constraints(networkType: NetworkType.connected), existingWorkPolicy: ExistingWorkPolicy.replace); } else { diff --git a/lib/pages/apps.dart b/lib/pages/apps.dart index 86c37ab..84be9b9 100644 --- a/lib/pages/apps.dart +++ b/lib/pages/apps.dart @@ -12,11 +12,32 @@ class AppsPage extends StatefulWidget { const AppsPage({super.key}); @override - State createState() => _AppsPageState(); + State createState() => AppsPageState(); } -class _AppsPageState extends State { +class AppsPageState extends State { AppsFilter? filter; + Set selectedIds = {}; + + clearSelected() { + if (selectedIds.isNotEmpty) { + setState(() { + selectedIds.clear(); + }); + return true; + } + return false; + } + + selectThese(List appIds) { + if (selectedIds.isEmpty) { + setState(() { + for (var a in appIds) { + selectedIds.add(a); + } + }); + } + } @override Widget build(BuildContext context) { @@ -25,6 +46,20 @@ class _AppsPageState extends State { var existingUpdateAppIds = appsProvider.getExistingUpdates(); var sortedApps = appsProvider.apps.values.toList(); + selectedIds = selectedIds + .where((element) => sortedApps.map((e) => e.app.id).contains(element)) + .toSet(); + + toggleAppSelected(String appId) { + setState(() { + if (selectedIds.contains(appId)) { + selectedIds.remove(appId); + } else { + selectedIds.add(appId); + } + }); + } + if (filter != null) { sortedApps = sortedApps.where((app) { if (app.app.installedVersion == app.app.latestVersion && @@ -74,126 +109,163 @@ class _AppsPageState extends State { } return Scaffold( - backgroundColor: Theme.of(context).colorScheme.surface, - floatingActionButton: - Row(mainAxisAlignment: MainAxisAlignment.end, children: [ - existingUpdateAppIds.isEmpty || filter != null - ? const SizedBox() - : ElevatedButton.icon( - onPressed: appsProvider.areDownloadsRunning() - ? null - : () { - HapticFeedback.heavyImpact(); - settingsProvider.getInstallPermission().then((_) { - appsProvider.downloadAndInstallLatestApp( - existingUpdateAppIds, context); - }); - }, - icon: const Icon(Icons.install_mobile_outlined), - label: const Text('Install All')), - const SizedBox( - width: 16, - ), - appsProvider.apps.isEmpty - ? const SizedBox() - : ElevatedButton.icon( - onPressed: () { - showDialog?>( - context: context, - builder: (BuildContext ctx) { - return GeneratedFormModal( - title: 'Filter Apps', - items: [ - [ - GeneratedFormItem( - label: "App Name", required: false), - GeneratedFormItem( - label: "Author", required: false) - ], - [ - GeneratedFormItem( - label: "Ignore Up-to-Date Apps", - type: FormItemType.bool) - ] - ], - defaultValues: filter == null - ? [] - : [ - filter!.nameFilter, - filter!.authorFilter, - filter!.onlyNonLatest ? 'true' : '' - ]); - }).then((values) { - if (values != null && - values - .where((element) => element.isNotEmpty) - .isNotEmpty) { - setState(() { - filter = AppsFilter( - nameFilter: values[0], - authorFilter: values[1], - onlyNonLatest: values[2] == "true"); - }); - } else { - setState(() { - filter = null; - }); - } - }); - }, - label: Text(filter == null ? 'Search' : 'Modify Search'), - icon: Icon( - filter == null ? Icons.search : Icons.manage_search)), - ]), - body: RefreshIndicator( - onRefresh: () { - HapticFeedback.lightImpact(); - return appsProvider.checkUpdates().catchError((e) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text(e.toString())), - ); - }); - }, - child: CustomScrollView(slivers: [ - const CustomAppBar(title: 'Apps'), - if (appsProvider.loadingApps || sortedApps.isEmpty) - SliverFillRemaining( - child: Center( - child: appsProvider.loadingApps - ? const CircularProgressIndicator() - : Text( - appsProvider.apps.isEmpty - ? 'No Apps' - : 'No Search Results', - style: - Theme.of(context).textTheme.headlineMedium, - ))), - SliverList( - delegate: SliverChildBuilderDelegate( - (BuildContext context, int index) { - return ListTile( - title: Text(sortedApps[index].app.name), - subtitle: Text('By ${sortedApps[index].app.author}'), - trailing: sortedApps[index].downloadProgress != null - ? Text( - 'Downloading - ${sortedApps[index].downloadProgress?.toInt()}%') - : (sortedApps[index].app.installedVersion != null && - sortedApps[index].app.installedVersion != - sortedApps[index].app.latestVersion - ? const Text('Update Available') - : Text(sortedApps[index].app.installedVersion ?? - 'Not Installed')), - onTap: () { + backgroundColor: Theme.of(context).colorScheme.surface, + body: RefreshIndicator( + onRefresh: () { + HapticFeedback.lightImpact(); + return appsProvider.checkUpdates().catchError((e) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text(e.toString())), + ); + }); + }, + child: CustomScrollView(slivers: [ + const CustomAppBar(title: 'Apps'), + if (appsProvider.loadingApps || sortedApps.isEmpty) + SliverFillRemaining( + child: Center( + child: appsProvider.loadingApps + ? const CircularProgressIndicator() + : Text( + appsProvider.apps.isEmpty + ? 'No Apps' + : 'No Search Results', + style: Theme.of(context).textTheme.headlineMedium, + ))), + SliverList( + delegate: SliverChildBuilderDelegate( + (BuildContext context, int index) { + return ListTile( + selectedTileColor: + Theme.of(context).colorScheme.primary.withOpacity(0.1), + selected: selectedIds.contains(sortedApps[index].app.id), + onLongPress: () { + toggleAppSelected(sortedApps[index].app.id); + }, + title: Text(sortedApps[index].app.name), + subtitle: Text('By ${sortedApps[index].app.author}'), + trailing: sortedApps[index].downloadProgress != null + ? Text( + 'Downloading - ${sortedApps[index].downloadProgress?.toInt()}%') + : (sortedApps[index].app.installedVersion != null && + sortedApps[index].app.installedVersion != + sortedApps[index].app.latestVersion + ? const Text('Update Available') + : Text(sortedApps[index].app.installedVersion ?? + 'Not Installed')), + onTap: () { + if (selectedIds.isNotEmpty) { + toggleAppSelected(sortedApps[index].app.id); + } else { Navigator.push( context, MaterialPageRoute( builder: (context) => AppPage(appId: sortedApps[index].app.id)), ); - }, - ); - }, childCount: sortedApps.length)) - ]))); + } + }, + ); + }, childCount: sortedApps.length)) + ])), + persistentFooterButtons: [ + Row( + children: [ + TextButton.icon( + onPressed: () { + selectedIds.isEmpty + ? selectThese(sortedApps.map((e) => e.app.id).toList()) + : clearSelected(); + }, + icon: Icon(selectedIds.isEmpty + ? Icons.select_all_outlined + : Icons.deselect_outlined), + label: Text(selectedIds.isEmpty + ? 'Select All' + : 'Deselect ${selectedIds.length.toString()}')), + const VerticalDivider(), + const Spacer(), + selectedIds.isEmpty + ? const SizedBox() + : IconButton( + onPressed: () { + // TODO: Delete selected Apps after confirming + }, + icon: const Icon(Icons.install_mobile_outlined)), + selectedIds.isEmpty + ? const SizedBox() + : IconButton( + onPressed: () { + // TODO: Install selected Apps if they are not up to date after confirming (replace existing button) + }, + icon: const Icon(Icons.delete_outline_rounded)), + existingUpdateAppIds.isEmpty || filter != null + ? const SizedBox() + : IconButton( + onPressed: appsProvider.areDownloadsRunning() + ? null + : () { + HapticFeedback.heavyImpact(); + settingsProvider.getInstallPermission().then((_) { + appsProvider.downloadAndInstallLatestApp( + existingUpdateAppIds, context); + }); + }, + icon: const Icon(Icons.install_mobile_outlined), + ), + appsProvider.apps.isEmpty + ? const SizedBox() + : IconButton( + onPressed: () { + showDialog?>( + context: context, + builder: (BuildContext ctx) { + return GeneratedFormModal( + title: 'Filter Apps', + items: [ + [ + GeneratedFormItem( + label: "App Name", required: false), + GeneratedFormItem( + label: "Author", required: false) + ], + [ + GeneratedFormItem( + label: "Ignore Up-to-Date Apps", + type: FormItemType.bool) + ] + ], + defaultValues: filter == null + ? [] + : [ + filter!.nameFilter, + filter!.authorFilter, + filter!.onlyNonLatest ? 'true' : '' + ]); + }).then((values) { + if (values != null && + values + .where((element) => element.isNotEmpty) + .isNotEmpty) { + setState(() { + filter = AppsFilter( + nameFilter: values[0], + authorFilter: values[1], + onlyNonLatest: values[2] == "true"); + }); + } else { + setState(() { + filter = null; + }); + } + }); + }, + icon: Icon( + filter == null ? Icons.search : Icons.manage_search)) + ], + ), + ], + ); } } diff --git a/lib/pages/home.dart b/lib/pages/home.dart index 96d5683..c1718de 100644 --- a/lib/pages/home.dart +++ b/lib/pages/home.dart @@ -25,7 +25,8 @@ class _HomePageState extends State { List selectedIndexHistory = []; List pages = [ - NavigationPageItem('Apps', Icons.apps, const AppsPage()), + NavigationPageItem( + 'Apps', Icons.apps, AppsPage(key: GlobalKey())), NavigationPageItem('Add App', Icons.add, const AddAppPage()), NavigationPageItem( 'Import/Export', Icons.import_export, const ImportExportPage()), @@ -88,7 +89,10 @@ class _HomePageState extends State { }); return false; } - return true; + return !(pages[0].widget.key as GlobalKey) + .currentState + ?.clearSelected(); + // return !appsPageKey.currentState?.clearSelected(); }); } }