mirror of
https://github.com/ImranR98/Obtainium.git
synced 2025-11-01 05:53:27 +01:00
Apps bottom bar tweaks (#216)
This commit is contained in:
@@ -348,8 +348,9 @@ class AppsPageState extends State<AppsPage> {
|
|||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
selectedApps.isEmpty
|
selectedApps.isEmpty
|
||||||
? IconButton(
|
? TextButton.icon(
|
||||||
visualDensity: VisualDensity.compact,
|
style:
|
||||||
|
const ButtonStyle(visualDensity: VisualDensity.compact),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
selectThese(sortedApps.map((e) => e.app).toList());
|
selectThese(sortedApps.map((e) => e.app).toList());
|
||||||
},
|
},
|
||||||
@@ -357,7 +358,7 @@ class AppsPageState extends State<AppsPage> {
|
|||||||
Icons.select_all_outlined,
|
Icons.select_all_outlined,
|
||||||
color: Theme.of(context).colorScheme.primary,
|
color: Theme.of(context).colorScheme.primary,
|
||||||
),
|
),
|
||||||
tooltip: tr('selectAll'))
|
label: Text(sortedApps.length.toString()))
|
||||||
: TextButton.icon(
|
: TextButton.icon(
|
||||||
style:
|
style:
|
||||||
const ButtonStyle(visualDensity: VisualDensity.compact),
|
const ButtonStyle(visualDensity: VisualDensity.compact),
|
||||||
@@ -375,31 +376,36 @@ class AppsPageState extends State<AppsPage> {
|
|||||||
label: Text(selectedApps.length.toString())),
|
label: Text(selectedApps.length.toString())),
|
||||||
const VerticalDivider(),
|
const VerticalDivider(),
|
||||||
Expanded(
|
Expanded(
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
scrollDirection: Axis.horizontal,
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
children: [
|
children: [
|
||||||
selectedApps.isEmpty
|
IconButton(
|
||||||
? const SizedBox()
|
|
||||||
: IconButton(
|
|
||||||
visualDensity: VisualDensity.compact,
|
visualDensity: VisualDensity.compact,
|
||||||
onPressed: () {
|
onPressed: selectedApps.isEmpty
|
||||||
|
? null
|
||||||
|
: () {
|
||||||
showDialog<Map<String, dynamic>?>(
|
showDialog<Map<String, dynamic>?>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext ctx) {
|
builder: (BuildContext ctx) {
|
||||||
return GeneratedFormModal(
|
return GeneratedFormModal(
|
||||||
title: tr('removeSelectedAppsQuestion'),
|
title:
|
||||||
|
tr('removeSelectedAppsQuestion'),
|
||||||
items: const [],
|
items: const [],
|
||||||
initValid: true,
|
initValid: true,
|
||||||
message: tr(
|
message: tr(
|
||||||
'xWillBeRemovedButRemainInstalled',
|
'xWillBeRemovedButRemainInstalled',
|
||||||
args: [
|
args: [
|
||||||
plural('apps', selectedApps.length)
|
plural(
|
||||||
|
'apps', selectedApps.length)
|
||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
}).then((values) {
|
}).then((values) {
|
||||||
if (values != null) {
|
if (values != null) {
|
||||||
appsProvider.removeApps(
|
appsProvider.removeApps(selectedApps
|
||||||
selectedApps.map((e) => e.id).toList());
|
.map((e) => e.id)
|
||||||
|
.toList());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@@ -416,50 +422,71 @@ class AppsPageState extends State<AppsPage> {
|
|||||||
: () {
|
: () {
|
||||||
HapticFeedback.heavyImpact();
|
HapticFeedback.heavyImpact();
|
||||||
List<GeneratedFormItem> formItems = [];
|
List<GeneratedFormItem> formItems = [];
|
||||||
if (existingUpdateIdsAllOrSelected.isNotEmpty) {
|
if (existingUpdateIdsAllOrSelected
|
||||||
formItems.add(GeneratedFormSwitch('updates',
|
.isNotEmpty) {
|
||||||
|
formItems.add(GeneratedFormSwitch(
|
||||||
|
'updates',
|
||||||
label: tr('updateX', args: [
|
label: tr('updateX', args: [
|
||||||
plural('apps',
|
plural(
|
||||||
existingUpdateIdsAllOrSelected.length)
|
'apps',
|
||||||
|
existingUpdateIdsAllOrSelected
|
||||||
|
.length)
|
||||||
]),
|
]),
|
||||||
defaultValue: true));
|
defaultValue: true));
|
||||||
}
|
}
|
||||||
if (newInstallIdsAllOrSelected.isNotEmpty) {
|
if (newInstallIdsAllOrSelected.isNotEmpty) {
|
||||||
formItems.add(GeneratedFormSwitch('installs',
|
formItems.add(GeneratedFormSwitch(
|
||||||
|
'installs',
|
||||||
label: tr('installX', args: [
|
label: tr('installX', args: [
|
||||||
plural('apps',
|
plural(
|
||||||
newInstallIdsAllOrSelected.length)
|
'apps',
|
||||||
|
newInstallIdsAllOrSelected
|
||||||
|
.length)
|
||||||
]),
|
]),
|
||||||
defaultValue: existingUpdateIdsAllOrSelected
|
defaultValue:
|
||||||
|
existingUpdateIdsAllOrSelected
|
||||||
.isNotEmpty));
|
.isNotEmpty));
|
||||||
}
|
}
|
||||||
if (trackOnlyUpdateIdsAllOrSelected.isNotEmpty) {
|
if (trackOnlyUpdateIdsAllOrSelected
|
||||||
formItems.add(GeneratedFormSwitch('trackonlies',
|
.isNotEmpty) {
|
||||||
label: tr('markXTrackOnlyAsUpdated', args: [
|
formItems.add(GeneratedFormSwitch(
|
||||||
plural('apps',
|
'trackonlies',
|
||||||
trackOnlyUpdateIdsAllOrSelected.length)
|
label: tr('markXTrackOnlyAsUpdated',
|
||||||
|
args: [
|
||||||
|
plural(
|
||||||
|
'apps',
|
||||||
|
trackOnlyUpdateIdsAllOrSelected
|
||||||
|
.length)
|
||||||
]),
|
]),
|
||||||
defaultValue: existingUpdateIdsAllOrSelected
|
defaultValue:
|
||||||
|
existingUpdateIdsAllOrSelected
|
||||||
.isNotEmpty ||
|
.isNotEmpty ||
|
||||||
newInstallIdsAllOrSelected.isNotEmpty));
|
newInstallIdsAllOrSelected
|
||||||
|
.isNotEmpty));
|
||||||
}
|
}
|
||||||
showDialog<Map<String, dynamic>?>(
|
showDialog<Map<String, dynamic>?>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext ctx) {
|
builder: (BuildContext ctx) {
|
||||||
var totalApps = existingUpdateIdsAllOrSelected
|
var totalApps =
|
||||||
|
existingUpdateIdsAllOrSelected.length +
|
||||||
|
newInstallIdsAllOrSelected
|
||||||
.length +
|
.length +
|
||||||
newInstallIdsAllOrSelected.length +
|
trackOnlyUpdateIdsAllOrSelected
|
||||||
trackOnlyUpdateIdsAllOrSelected.length;
|
.length;
|
||||||
return GeneratedFormModal(
|
return GeneratedFormModal(
|
||||||
title: tr('changeX',
|
title: tr('changeX', args: [
|
||||||
args: [plural('apps', totalApps)]),
|
plural('apps', totalApps)
|
||||||
items: formItems.map((e) => [e]).toList(),
|
]),
|
||||||
|
items: formItems
|
||||||
|
.map((e) => [e])
|
||||||
|
.toList(),
|
||||||
initValid: true,
|
initValid: true,
|
||||||
);
|
);
|
||||||
}).then((values) {
|
}).then((values) {
|
||||||
if (values != null) {
|
if (values != null) {
|
||||||
if (values.isEmpty) {
|
if (values.isEmpty) {
|
||||||
values = getDefaultValuesFromFormItems(
|
values =
|
||||||
|
getDefaultValuesFromFormItems(
|
||||||
[formItems]);
|
[formItems]);
|
||||||
}
|
}
|
||||||
bool shouldInstallUpdates =
|
bool shouldInstallUpdates =
|
||||||
@@ -478,20 +505,22 @@ class AppsPageState extends State<AppsPage> {
|
|||||||
.then((_) {
|
.then((_) {
|
||||||
List<String> toInstall = [];
|
List<String> toInstall = [];
|
||||||
if (shouldInstallUpdates) {
|
if (shouldInstallUpdates) {
|
||||||
toInstall
|
toInstall.addAll(
|
||||||
.addAll(existingUpdateIdsAllOrSelected);
|
existingUpdateIdsAllOrSelected);
|
||||||
}
|
}
|
||||||
if (shouldInstallNew) {
|
if (shouldInstallNew) {
|
||||||
toInstall
|
toInstall.addAll(
|
||||||
.addAll(newInstallIdsAllOrSelected);
|
newInstallIdsAllOrSelected);
|
||||||
}
|
}
|
||||||
if (shouldMarkTrackOnlies) {
|
if (shouldMarkTrackOnlies) {
|
||||||
toInstall.addAll(
|
toInstall.addAll(
|
||||||
trackOnlyUpdateIdsAllOrSelected);
|
trackOnlyUpdateIdsAllOrSelected);
|
||||||
}
|
}
|
||||||
appsProvider
|
appsProvider
|
||||||
.downloadAndInstallLatestApps(toInstall,
|
.downloadAndInstallLatestApps(
|
||||||
globalNavigatorKey.currentContext)
|
toInstall,
|
||||||
|
globalNavigatorKey
|
||||||
|
.currentContext)
|
||||||
.catchError((e) {
|
.catchError((e) {
|
||||||
showError(e, context);
|
showError(e, context);
|
||||||
});
|
});
|
||||||
@@ -505,16 +534,17 @@ class AppsPageState extends State<AppsPage> {
|
|||||||
icon: const Icon(
|
icon: const Icon(
|
||||||
Icons.file_download_outlined,
|
Icons.file_download_outlined,
|
||||||
)),
|
)),
|
||||||
selectedApps.isEmpty
|
IconButton(
|
||||||
? const SizedBox()
|
|
||||||
: IconButton(
|
|
||||||
visualDensity: VisualDensity.compact,
|
visualDensity: VisualDensity.compact,
|
||||||
onPressed: () async {
|
onPressed: selectedApps.isEmpty
|
||||||
|
? null
|
||||||
|
: () async {
|
||||||
try {
|
try {
|
||||||
Set<String>? preselected;
|
Set<String>? preselected;
|
||||||
var showPrompt = false;
|
var showPrompt = false;
|
||||||
for (var element in selectedApps) {
|
for (var element in selectedApps) {
|
||||||
var currentCats = element.categories.toSet();
|
var currentCats =
|
||||||
|
element.categories.toSet();
|
||||||
if (preselected == null) {
|
if (preselected == null) {
|
||||||
preselected = currentCats;
|
preselected = currentCats;
|
||||||
} else {
|
} else {
|
||||||
@@ -527,15 +557,16 @@ class AppsPageState extends State<AppsPage> {
|
|||||||
}
|
}
|
||||||
var cont = true;
|
var cont = true;
|
||||||
if (showPrompt) {
|
if (showPrompt) {
|
||||||
cont = await showDialog<Map<String, dynamic>?>(
|
cont = await showDialog<
|
||||||
|
Map<String, dynamic>?>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext ctx) {
|
builder: (BuildContext ctx) {
|
||||||
return GeneratedFormModal(
|
return GeneratedFormModal(
|
||||||
title: tr('categorize'),
|
title: tr('categorize'),
|
||||||
items: const [],
|
items: const [],
|
||||||
initValid: true,
|
initValid: true,
|
||||||
message:
|
message: tr(
|
||||||
tr('selectedCategorizeWarning'),
|
'selectedCategorizeWarning'),
|
||||||
);
|
);
|
||||||
}) !=
|
}) !=
|
||||||
null;
|
null;
|
||||||
@@ -548,7 +579,8 @@ class AppsPageState extends State<AppsPage> {
|
|||||||
title: tr('categorize'),
|
title: tr('categorize'),
|
||||||
items: const [],
|
items: const [],
|
||||||
initValid: true,
|
initValid: true,
|
||||||
singleNullReturnButton: tr('continue'),
|
singleNullReturnButton:
|
||||||
|
tr('continue'),
|
||||||
additionalWidgets: [
|
additionalWidgets: [
|
||||||
CategoryEditorSelector(
|
CategoryEditorSelector(
|
||||||
preselected: !showPrompt
|
preselected: !showPrompt
|
||||||
@@ -556,8 +588,8 @@ class AppsPageState extends State<AppsPage> {
|
|||||||
: {},
|
: {},
|
||||||
showLabelWhenNotEmpty: false,
|
showLabelWhenNotEmpty: false,
|
||||||
onSelected: (categories) {
|
onSelected: (categories) {
|
||||||
appsProvider
|
appsProvider.saveApps(
|
||||||
.saveApps(selectedApps.map((e) {
|
selectedApps.map((e) {
|
||||||
e.categories = categories;
|
e.categories = categories;
|
||||||
return e;
|
return e;
|
||||||
}).toList());
|
}).toList());
|
||||||
@@ -574,30 +606,32 @@ class AppsPageState extends State<AppsPage> {
|
|||||||
tooltip: tr('categorize'),
|
tooltip: tr('categorize'),
|
||||||
icon: const Icon(Icons.category_outlined),
|
icon: const Icon(Icons.category_outlined),
|
||||||
),
|
),
|
||||||
selectedApps.isEmpty
|
IconButton(
|
||||||
? const SizedBox()
|
|
||||||
: IconButton(
|
|
||||||
visualDensity: VisualDensity.compact,
|
visualDensity: VisualDensity.compact,
|
||||||
onPressed: () {
|
onPressed: selectedApps.isEmpty
|
||||||
|
? null
|
||||||
|
: () {
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext ctx) {
|
builder: (BuildContext ctx) {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
scrollable: true,
|
scrollable: true,
|
||||||
content: Padding(
|
content: Padding(
|
||||||
padding: const EdgeInsets.only(top: 6),
|
padding:
|
||||||
|
const EdgeInsets.only(top: 6),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment:
|
mainAxisAlignment:
|
||||||
MainAxisAlignment.spaceAround,
|
MainAxisAlignment
|
||||||
|
.spaceAround,
|
||||||
children: [
|
children: [
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed:
|
onPressed: appsProvider
|
||||||
appsProvider
|
|
||||||
.areDownloadsRunning()
|
.areDownloadsRunning()
|
||||||
? null
|
? null
|
||||||
: () {
|
: () {
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context:
|
||||||
|
context,
|
||||||
builder:
|
builder:
|
||||||
(BuildContext
|
(BuildContext
|
||||||
ctx) {
|
ctx) {
|
||||||
@@ -605,47 +639,39 @@ class AppsPageState extends State<AppsPage> {
|
|||||||
title: Text(tr(
|
title: Text(tr(
|
||||||
'markXSelectedAppsAsUpdated',
|
'markXSelectedAppsAsUpdated',
|
||||||
args: [
|
args: [
|
||||||
selectedApps
|
selectedApps.length.toString()
|
||||||
.length
|
|
||||||
.toString()
|
|
||||||
])),
|
])),
|
||||||
content: Text(
|
content:
|
||||||
|
Text(
|
||||||
tr('onlyWorksWithNonEVDApps'),
|
tr('onlyWorksWithNonEVDApps'),
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontWeight:
|
fontWeight:
|
||||||
FontWeight
|
FontWeight.bold,
|
||||||
.bold,
|
fontStyle: FontStyle.italic),
|
||||||
fontStyle:
|
|
||||||
FontStyle.italic),
|
|
||||||
),
|
),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed:
|
onPressed:
|
||||||
() {
|
() {
|
||||||
Navigator.of(context)
|
Navigator.of(context).pop();
|
||||||
.pop();
|
|
||||||
},
|
},
|
||||||
child: Text(
|
child:
|
||||||
tr('no'))),
|
Text(tr('no'))),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed:
|
onPressed:
|
||||||
() {
|
() {
|
||||||
HapticFeedback
|
HapticFeedback.selectionClick();
|
||||||
.selectionClick();
|
appsProvider.saveApps(selectedApps.map((a) {
|
||||||
appsProvider
|
if (a.installedVersion != null) {
|
||||||
.saveApps(selectedApps.map((a) {
|
|
||||||
if (a.installedVersion !=
|
|
||||||
null) {
|
|
||||||
a.installedVersion = a.latestVersion;
|
a.installedVersion = a.latestVersion;
|
||||||
}
|
}
|
||||||
return a;
|
return a;
|
||||||
}).toList());
|
}).toList());
|
||||||
|
|
||||||
Navigator.of(context)
|
Navigator.of(context).pop();
|
||||||
.pop();
|
|
||||||
},
|
},
|
||||||
child: Text(
|
child:
|
||||||
tr('yes')))
|
Text(tr('yes')))
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}).whenComplete(() {
|
}).whenComplete(() {
|
||||||
@@ -654,21 +680,25 @@ class AppsPageState extends State<AppsPage> {
|
|||||||
.pop();
|
.pop();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
tooltip:
|
tooltip: tr(
|
||||||
tr('markSelectedAppsUpdated'),
|
'markSelectedAppsUpdated'),
|
||||||
icon: const Icon(Icons.done)),
|
icon: const Icon(
|
||||||
|
Icons.done)),
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
var pinStatus = selectedApps
|
var pinStatus =
|
||||||
|
selectedApps
|
||||||
.where((element) =>
|
.where((element) =>
|
||||||
element.pinned)
|
element
|
||||||
|
.pinned)
|
||||||
.isEmpty;
|
.isEmpty;
|
||||||
appsProvider.saveApps(
|
appsProvider.saveApps(
|
||||||
selectedApps.map((e) {
|
selectedApps.map((e) {
|
||||||
e.pinned = pinStatus;
|
e.pinned = pinStatus;
|
||||||
return e;
|
return e;
|
||||||
}).toList());
|
}).toList());
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context)
|
||||||
|
.pop();
|
||||||
},
|
},
|
||||||
tooltip: selectedApps
|
tooltip: selectedApps
|
||||||
.where((element) =>
|
.where((element) =>
|
||||||
@@ -680,14 +710,16 @@ class AppsPageState extends State<AppsPage> {
|
|||||||
.where((element) =>
|
.where((element) =>
|
||||||
element.pinned)
|
element.pinned)
|
||||||
.isEmpty
|
.isEmpty
|
||||||
? Icons.bookmark_outline_rounded
|
? Icons
|
||||||
|
.bookmark_outline_rounded
|
||||||
: Icons
|
: Icons
|
||||||
.bookmark_remove_outlined),
|
.bookmark_remove_outlined),
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
String urls = '';
|
String urls = '';
|
||||||
for (var a in selectedApps) {
|
for (var a
|
||||||
|
in selectedApps) {
|
||||||
urls += '${a.url}\n';
|
urls += '${a.url}\n';
|
||||||
}
|
}
|
||||||
urls = urls.substring(
|
urls = urls.substring(
|
||||||
@@ -695,16 +727,20 @@ class AppsPageState extends State<AppsPage> {
|
|||||||
Share.share(urls,
|
Share.share(urls,
|
||||||
subject: tr(
|
subject: tr(
|
||||||
'selectedAppURLsFromObtainium'));
|
'selectedAppURLsFromObtainium'));
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context)
|
||||||
|
.pop();
|
||||||
},
|
},
|
||||||
tooltip: tr('shareSelectedAppURLs'),
|
tooltip: tr(
|
||||||
icon: const Icon(Icons.share),
|
'shareSelectedAppURLs'),
|
||||||
|
icon:
|
||||||
|
const Icon(Icons.share),
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext ctx) {
|
builder: (BuildContext
|
||||||
|
ctx) {
|
||||||
return GeneratedFormModal(
|
return GeneratedFormModal(
|
||||||
title: tr(
|
title: tr(
|
||||||
'resetInstallStatusForSelectedAppsQuestion'),
|
'resetInstallStatusForSelectedAppsQuestion'),
|
||||||
@@ -722,18 +758,22 @@ class AppsPageState extends State<AppsPage> {
|
|||||||
}).then((values) {
|
}).then((values) {
|
||||||
if (values != null) {
|
if (values != null) {
|
||||||
appsProvider.saveApps(
|
appsProvider.saveApps(
|
||||||
selectedApps.map((e) {
|
selectedApps
|
||||||
e.installedVersion = null;
|
.map((e) {
|
||||||
|
e.installedVersion =
|
||||||
|
null;
|
||||||
return e;
|
return e;
|
||||||
}).toList());
|
}).toList());
|
||||||
}
|
}
|
||||||
}).whenComplete(() {
|
}).whenComplete(() {
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context)
|
||||||
|
.pop();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
tooltip: tr('resetInstallStatus'),
|
tooltip: tr(
|
||||||
icon: const Icon(
|
'resetInstallStatus'),
|
||||||
Icons.restore_page_outlined),
|
icon: const Icon(Icons
|
||||||
|
.restore_page_outlined),
|
||||||
),
|
),
|
||||||
]),
|
]),
|
||||||
),
|
),
|
||||||
@@ -744,7 +784,7 @@ class AppsPageState extends State<AppsPage> {
|
|||||||
icon: const Icon(Icons.more_horiz),
|
icon: const Icon(Icons.more_horiz),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)),
|
))),
|
||||||
const VerticalDivider(),
|
const VerticalDivider(),
|
||||||
IconButton(
|
IconButton(
|
||||||
visualDensity: VisualDensity.compact,
|
visualDensity: VisualDensity.compact,
|
||||||
|
|||||||
Reference in New Issue
Block a user