Compare commits

...

2 Commits

Author SHA1 Message Date
77e1768f3b Bugfix 2022-09-25 11:46:25 -04:00
da9e5aed5e Apps page UI improvements 2022-09-25 11:32:57 -04:00
3 changed files with 161 additions and 145 deletions

View File

@ -13,7 +13,7 @@ import 'package:dynamic_color/dynamic_color.dart';
import 'package:device_info_plus/device_info_plus.dart';
const String currentReleaseTag =
'v0.4.0-beta'; // KEEP THIS IN SYNC WITH GITHUB RELEASES
'v0.4.1-beta'; // KEEP THIS IN SYNC WITH GITHUB RELEASES
@pragma('vm:entry-point')
void bgTaskCallback() {

View File

@ -18,6 +18,8 @@ class AppsPage extends StatefulWidget {
class AppsPageState extends State<AppsPage> {
AppsFilter? filter;
var updatesOnlyFilter =
AppsFilter(includeUptodate: false, includeNonInstalled: false);
Set<String> selectedIds = {};
clearSelected() {
@ -45,6 +47,8 @@ class AppsPageState extends State<AppsPage> {
var appsProvider = context.watch<AppsProvider>();
var settingsProvider = context.watch<SettingsProvider>();
var sortedApps = appsProvider.apps.values.toList();
var currentFilterIsUpdatesOnly =
filter?.isIdenticalTo(updatesOnlyFilter) ?? false;
selectedIds = selectedIds
.where((element) => sortedApps.map((e) => e.app.id).contains(element))
@ -112,6 +116,19 @@ class AppsPageState extends State<AppsPage> {
sortedApps = sortedApps.reversed.toList();
}
var existingUpdateIdsAllOrSelected = appsProvider
.getExistingUpdates(installedOnly: true)
.where((element) => selectedIds.isEmpty
? sortedApps.where((a) => a.app.id == element).isNotEmpty
: selectedIds.contains(element))
.toList();
var newInstallIdsAllOrSelected = appsProvider
.getExistingUpdates(nonInstalledOnly: true)
.where((element) => selectedIds.isEmpty
? sortedApps.where((a) => a.app.id == element).isNotEmpty
: selectedIds.contains(element))
.toList();
return Scaffold(
backgroundColor: Theme.of(context).colorScheme.surface,
body: RefreshIndicator(
@ -133,8 +150,9 @@ class AppsPageState extends State<AppsPage> {
: Text(
appsProvider.apps.isEmpty
? 'No Apps'
: 'No Search Results',
: 'No Apps for Filter',
style: Theme.of(context).textTheme.headlineMedium,
textAlign: TextAlign.center,
))),
SliverList(
delegate: SliverChildBuilderDelegate(
@ -175,26 +193,29 @@ class AppsPageState extends State<AppsPage> {
persistentFooterButtons: [
Row(
children: [
TextButton.icon(
IconButton(
onPressed: () {
selectedIds.isEmpty
? selectThese(sortedApps.map((e) => e.app.id).toList())
: clearSelected();
},
icon: Icon(selectedIds.isEmpty
icon: Icon(
selectedIds.isEmpty
? Icons.select_all_outlined
: Icons.deselect_outlined),
label: Text(selectedIds.isEmpty
: Icons.deselect_outlined,
color: Theme.of(context).colorScheme.primary,
),
tooltip: selectedIds.isEmpty
? 'Select All'
: 'Deselect ${selectedIds.length.toString()}')),
: 'Deselect ${selectedIds.length.toString()}'),
const VerticalDivider(),
Expanded(
child: selectedIds.isEmpty
? Container()
: Row(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
IconButton(
selectedIds.isEmpty
? const SizedBox()
: IconButton(
visualDensity: VisualDensity.compact,
onPressed: () {
showDialog<List<String>?>(
@ -220,44 +241,24 @@ class AppsPageState extends State<AppsPage> {
IconButton(
visualDensity: VisualDensity.compact,
onPressed: appsProvider.areDownloadsRunning() ||
selectedIds
.where((id) =>
appsProvider.apps[id]!.app
.installedVersion !=
appsProvider
.apps[id]!.app.latestVersion)
.isEmpty
(existingUpdateIdsAllOrSelected.isEmpty &&
newInstallIdsAllOrSelected.isEmpty)
? null
: () {
HapticFeedback.heavyImpact();
var existingUpdateIdsSelected =
appsProvider
.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) {
List<List<GeneratedFormItem>> formInputs = [];
if (existingUpdateIdsAllOrSelected.isNotEmpty &&
newInstallIdsAllOrSelected.isNotEmpty) {
formInputs.add([
GeneratedFormItem(
label:
'Update ${existingUpdateIdsSelected.length} Apps?',
'Update ${existingUpdateIdsAllOrSelected.length} App${existingUpdateIdsAllOrSelected.length == 1 ? '' : 's'}',
type: FormItemType.bool)
]);
formInputs.add([
GeneratedFormItem(
label:
'Install ${newInstallIdsSelected.length} new Apps?',
'Install ${newInstallIdsAllOrSelected.length} new App${newInstallIdsAllOrSelected.length == 1 ? '' : 's'}',
type: FormItemType.bool)
]);
}
@ -265,48 +266,46 @@ class AppsPageState extends State<AppsPage> {
context: context,
builder: (BuildContext ctx) {
return GeneratedFormModal(
title: 'Install Selected Apps?',
title:
'Install${selectedIds.isEmpty ? ' ' : ' Selected '}Apps?',
message:
'${existingUpdateIdsSelected.length} update${existingUpdateIdsSelected.length == 1 ? '' : 's'} and ${newInstallIdsSelected.length} new install${newInstallIdsSelected.length == 1 ? '' : 's'}.',
'${existingUpdateIdsAllOrSelected.length} update${existingUpdateIdsAllOrSelected.length == 1 ? '' : 's'} and ${newInstallIdsAllOrSelected.length} new install${newInstallIdsAllOrSelected.length == 1 ? '' : 's'}.',
items: formInputs,
defaultValues: const [
'true',
'true'
],
defaultValues: const ['true', 'true'],
initValid: true,
);
}).then((values) {
if (values != null) {
bool shouldInstallUpdates =
values.length < 2 ||
values[0] == 'true';
values.length < 2 || values[0] == 'true';
bool shouldInstallNew =
values.length < 2 ||
values[1] == 'true';
values.length < 2 || values[1] == 'true';
settingsProvider
.getInstallPermission()
.then((_) {
List<String> toInstall = [];
if (shouldInstallUpdates) {
toInstall.addAll(
existingUpdateIdsSelected);
toInstall
.addAll(existingUpdateIdsAllOrSelected);
}
if (shouldInstallNew) {
toInstall.addAll(
newInstallIdsSelected);
toInstall
.addAll(newInstallIdsAllOrSelected);
}
appsProvider
.downloadAndInstallLatestApp(
appsProvider.downloadAndInstallLatestApp(
toInstall, context);
});
}
});
},
tooltip: 'Install/Update Selected Apps',
tooltip:
'Install/Update${selectedIds.isEmpty ? ' ' : ' Selected '}Apps',
icon: const Icon(
Icons.file_download_outlined,
)),
IconButton(
selectedIds.isEmpty
? const SizedBox()
: IconButton(
visualDensity: VisualDensity.compact,
onPressed: () {
String urls = '';
@ -323,6 +322,27 @@ class AppsPageState extends State<AppsPage> {
],
)),
const VerticalDivider(),
IconButton(
visualDensity: VisualDensity.compact,
onPressed: () {
setState(() {
if (currentFilterIsUpdatesOnly) {
filter = null;
} else {
filter = updatesOnlyFilter;
}
});
},
tooltip: currentFilterIsUpdatesOnly
? 'Remove Out-of-Date App Filter'
: 'Show Out-of-Date Apps Only',
icon: Icon(
currentFilterIsUpdatesOnly
? Icons.update_disabled_rounded
: Icons.update_rounded,
color: Theme.of(context).colorScheme.primary,
),
),
appsProvider.apps.isEmpty
? const SizedBox()
: TextButton.icon(
@ -368,10 +388,6 @@ class AppsPageState extends State<AppsPage> {
filter = null;
}
});
} else {
setState(() {
filter = null;
});
}
});
},

View File

@ -17,7 +17,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix.
version: 0.4.0+19 # When changing this, update the tag in main() accordingly
version: 0.4.1+20 # When changing this, update the tag in main() accordingly
environment:
sdk: '>=2.19.0-79.0.dev <3.0.0'