Adds Track-Only App Support (Addresses #119 and Sets Groundwork for #44) (#123)

- All Sources now have a "Track-Only" option that will prevent Obtainium from looking for APKs (though the App must still have a release of some kind so that a version string can be grabbed).
    - These Apps cannot be installed through Obtainium, but update notifications will still be sent.
    - The user needs to manually mark them as updated when appropriate.
    - This addresses issue #119.
    - It also partially addresses #44 by allowing some sources to be configured as "Track-Only"-only. The first such source (APKMirror) will be added later.
- Includes various UI changes to accommodate the above change.
- Also makes App loading a bit more responsive (sending Obtainium to the background then returning will now cause App re-load to pick up changes in App versioning that may have been made in the meantime, for instance through update checking).
This commit is contained in:
Imran Remtulla
2022-11-24 21:12:46 -05:00
committed by GitHub
parent 868ba84c9a
commit b04d2fad5c
16 changed files with 341 additions and 145 deletions

View File

@@ -135,6 +135,22 @@ class AppsPageState extends State<AppsPage> {
: selectedApps.map((e) => e.id).contains(element))
.toList();
List<String> trackOnlyUpdateIdsAllOrSelected = [];
existingUpdateIdsAllOrSelected = existingUpdateIdsAllOrSelected.where((id) {
if (appsProvider.apps[id]!.app.trackOnly) {
trackOnlyUpdateIdsAllOrSelected.add(id);
return false;
}
return true;
}).toList();
newInstallIdsAllOrSelected = newInstallIdsAllOrSelected.where((id) {
if (appsProvider.apps[id]!.app.trackOnly) {
trackOnlyUpdateIdsAllOrSelected.add(id);
return false;
}
return true;
}).toList();
if (settingsProvider.pinUpdates) {
var temp = [];
sortedApps = sortedApps.where((sa) {
@@ -245,7 +261,7 @@ class AppsPageState extends State<AppsPage> {
children: [
Text(appsProvider.areDownloadsRunning()
? 'Please Wait...'
: 'Update Available'),
: 'Update Available${sortedApps[index].app.trackOnly ? ' (Est.)' : ''}'),
SourceProvider()
.getSource(sortedApps[index].app.url)
.changeLogPageFromStandardUrl(
@@ -276,8 +292,7 @@ class AppsPageState extends State<AppsPage> {
child: SizedBox(
width: 80,
child: Text(
sortedApps[index].app.installedVersion ??
'Not Installed',
'${sortedApps[index].app.installedVersion ?? 'Not Installed'} ${sortedApps[index].app.trackOnly == true ? '(Estimate)' : ''}',
overflow: TextOverflow.fade,
textAlign: TextAlign.end,
)))),
@@ -349,50 +364,70 @@ class AppsPageState extends State<AppsPage> {
visualDensity: VisualDensity.compact,
onPressed: appsProvider.areDownloadsRunning() ||
(existingUpdateIdsAllOrSelected.isEmpty &&
newInstallIdsAllOrSelected.isEmpty)
newInstallIdsAllOrSelected.isEmpty &&
trackOnlyUpdateIdsAllOrSelected.isEmpty)
? null
: () {
HapticFeedback.heavyImpact();
List<List<GeneratedFormItem>> formInputs = [];
if (existingUpdateIdsAllOrSelected.isNotEmpty &&
newInstallIdsAllOrSelected.isNotEmpty) {
formInputs.add([
GeneratedFormItem(
label:
'Update ${existingUpdateIdsAllOrSelected.length} App${existingUpdateIdsAllOrSelected.length == 1 ? '' : 's'}',
type: FormItemType.bool)
]);
formInputs.add([
GeneratedFormItem(
label:
'Install ${newInstallIdsAllOrSelected.length} new App${newInstallIdsAllOrSelected.length == 1 ? '' : 's'}',
type: FormItemType.bool)
]);
List<GeneratedFormItem> formInputs = [];
List<String> defaultValues = [];
if (existingUpdateIdsAllOrSelected.isNotEmpty) {
formInputs.add(GeneratedFormItem(
label:
'Update ${existingUpdateIdsAllOrSelected.length} App${existingUpdateIdsAllOrSelected.length == 1 ? '' : 's'}',
type: FormItemType.bool,
key: 'updates'));
defaultValues.add('true');
}
if (newInstallIdsAllOrSelected.isNotEmpty) {
formInputs.add(GeneratedFormItem(
label:
'Install ${newInstallIdsAllOrSelected.length} new App${newInstallIdsAllOrSelected.length == 1 ? '' : 's'}',
type: FormItemType.bool,
key: 'installs'));
defaultValues
.add(defaultValues.isEmpty ? 'true' : '');
}
if (trackOnlyUpdateIdsAllOrSelected.isNotEmpty) {
formInputs.add(GeneratedFormItem(
label:
'Mark ${trackOnlyUpdateIdsAllOrSelected.length} Track-Only\nApp${trackOnlyUpdateIdsAllOrSelected.length == 1 ? '' : 's'} as Updated',
type: FormItemType.bool,
key: 'trackonlies'));
defaultValues
.add(defaultValues.isEmpty ? 'true' : '');
}
showDialog<List<String>?>(
context: context,
builder: (BuildContext ctx) {
var totalApps = existingUpdateIdsAllOrSelected
.length +
newInstallIdsAllOrSelected.length +
trackOnlyUpdateIdsAllOrSelected.length;
return GeneratedFormModal(
title:
'Install${selectedApps.isEmpty ? ' ' : ' Selected '}Apps?',
message:
'${existingUpdateIdsAllOrSelected.length} update${existingUpdateIdsAllOrSelected.length == 1 ? '' : 's'} and ${newInstallIdsAllOrSelected.length} new install${newInstallIdsAllOrSelected.length == 1 ? '' : 's'}.',
items: formInputs,
defaultValues: [
'true',
existingUpdateIdsAllOrSelected.isEmpty
? 'true'
: ''
],
'Change $totalApps App${totalApps == 1 ? '' : 's'}',
items: formInputs.map((e) => [e]).toList(),
defaultValues: defaultValues,
initValid: true,
);
}).then((values) {
if (values != null) {
if (values.isEmpty) {
values = ['true', 'true'];
values = defaultValues;
}
bool shouldInstallUpdates = values[0] == 'true';
bool shouldInstallNew = values[1] == 'true';
bool shouldInstallUpdates =
findGeneratedFormValueByKey(
formInputs, values, 'updates') ==
'true';
bool shouldInstallNew =
findGeneratedFormValueByKey(
formInputs, values, 'installs') ==
'true';
bool shouldMarkTrackOnlies =
findGeneratedFormValueByKey(formInputs,
values, 'trackonlies') ==
'true';
settingsProvider
.getInstallPermission()
.then((_) {
@@ -405,6 +440,10 @@ class AppsPageState extends State<AppsPage> {
toInstall
.addAll(newInstallIdsAllOrSelected);
}
if (shouldMarkTrackOnlies) {
toInstall.addAll(
trackOnlyUpdateIdsAllOrSelected);
}
appsProvider
.downloadAndInstallLatestApps(
toInstall, context)