Started switching additionaldata to map

This commit is contained in:
Imran Remtulla
2022-12-19 19:34:43 -05:00
parent dbd6dec0a6
commit 1fe9e4f91e
19 changed files with 155 additions and 188 deletions

View File

@ -25,7 +25,7 @@ class APKMirror extends AppSource {
@override
Future<APKDetails> getLatestAPKDetails(
String standardUrl, List<String> additionalData,
String standardUrl, Map<String, String> additionalData,
{bool trackOnly = false}) async {
Response res = await get(Uri.parse('$standardUrl/feed'));
if (res.statusCode == 200) {

View File

@ -32,7 +32,7 @@ class FDroid extends AppSource {
@override
String? tryInferringAppId(String standardUrl,
{List<String> additionalData = const []}) {
{Map<String, String> additionalData = const {}}) {
return Uri.parse(standardUrl).pathSegments.last;
}
@ -60,7 +60,7 @@ class FDroid extends AppSource {
@override
Future<APKDetails> getLatestAPKDetails(
String standardUrl, List<String> additionalData,
String standardUrl, Map<String, String> additionalData,
{bool trackOnly = false}) async {
String? appId = tryInferringAppId(standardUrl);
return getAPKUrlsFromFDroidPackagesAPIResponse(

View File

@ -11,11 +11,10 @@ class FDroidRepo extends AppSource {
additionalSourceAppSpecificFormItems = [
[
GeneratedFormItem(
GeneratedFormItem('appIdOrName',
label: tr('appIdOrName'),
hint: tr('reposHaveMultipleApps'),
required: true,
key: 'appIdOrName')
required: true)
]
];
}
@ -33,13 +32,9 @@ class FDroidRepo extends AppSource {
@override
Future<APKDetails> getLatestAPKDetails(
String standardUrl, List<String> additionalData,
String standardUrl, Map<String, String> additionalData,
{bool trackOnly = false}) async {
String? appIdOrName = findGeneratedFormValueByKey(
additionalSourceAppSpecificFormItems
.reduce((value, element) => [...value, ...element]),
additionalData,
'appIdOrName');
String? appIdOrName = additionalData['appIdOrName'];
if (appIdOrName == null) {
throw NoReleasesError();
}

View File

@ -12,12 +12,9 @@ class GitHub extends AppSource {
GitHub() {
host = 'github.com';
additionalSourceAppSpecificDefaults = ['true', 'true', ''];
additionalSourceSpecificSettingFormItems = [
GeneratedFormItem(
GeneratedFormItem('github-creds',
label: tr('githubPATLabel'),
id: 'github-creds',
required: false,
additionalValidators: [
(value) {
@ -52,17 +49,23 @@ class GitHub extends AppSource {
])
];
additionalSourceAppSpecificDefaults = {
'includePrereleases': 'true',
'fallbackToOlderReleases': 'true',
'filterReleaseTitlesByRegEx': ''
};
additionalSourceAppSpecificFormItems = [
[
GeneratedFormItem(
GeneratedFormItem('includePrereleases',
label: tr('includePrereleases'), type: FormItemType.bool)
],
[
GeneratedFormItem(
GeneratedFormItem('fallbackToOlderReleases',
label: tr('fallbackToOlderReleases'), type: FormItemType.bool)
],
[
GeneratedFormItem(
GeneratedFormItem('filterReleaseTitlesByRegEx',
label: tr('filterReleaseTitlesByRegEx'),
type: FormItemType.string,
required: false,
@ -99,7 +102,7 @@ class GitHub extends AppSource {
SettingsProvider settingsProvider = SettingsProvider();
await settingsProvider.initializeSettings();
String? creds = settingsProvider
.getSettingString(additionalSourceSpecificSettingFormItems[0].id);
.getSettingString(additionalSourceSpecificSettingFormItems[0].key);
return creds != null && creds.isNotEmpty ? '$creds@' : '';
}
@ -109,14 +112,14 @@ class GitHub extends AppSource {
@override
Future<APKDetails> getLatestAPKDetails(
String standardUrl, List<String> additionalData,
String standardUrl, Map<String, String> additionalData,
{bool trackOnly = false}) async {
var includePrereleases =
additionalData.isNotEmpty && additionalData[0] == 'true';
var includePrereleases = additionalData['includePrereleases'] == 'true';
var fallbackToOlderReleases =
additionalData.length >= 2 && additionalData[1] == 'true';
var regexFilter = additionalData.length >= 3 && additionalData[2].isNotEmpty
? additionalData[2]
additionalData['fallbackToOlderReleases'] == 'true';
var regexFilter =
additionalData['filterReleaseTitlesByRegEx']?.isNotEmpty == true
? additionalData['filterReleaseTitlesByRegEx']
: null;
Response res = await get(Uri.parse(
'https://${await getCredentialPrefixIfAny()}api.$host/repos${standardUrl.substring('https://$host'.length)}/releases'));

View File

@ -25,7 +25,7 @@ class GitLab extends AppSource {
@override
Future<APKDetails> getLatestAPKDetails(
String standardUrl, List<String> additionalData,
String standardUrl, Map<String, String> additionalData,
{bool trackOnly = false}) async {
Response res = await get(Uri.parse('$standardUrl/-/tags?format=atom'));
if (res.statusCode == 200) {

View File

@ -23,13 +23,13 @@ class IzzyOnDroid extends AppSource {
@override
String? tryInferringAppId(String standardUrl,
{List<String> additionalData = const []}) {
{Map<String, String> additionalData = const {}}) {
return FDroid().tryInferringAppId(standardUrl);
}
@override
Future<APKDetails> getLatestAPKDetails(
String standardUrl, List<String> additionalData,
String standardUrl, Map<String, String> additionalData,
{bool trackOnly = false}) async {
String? appId = tryInferringAppId(standardUrl);
return FDroid().getAPKUrlsFromFDroidPackagesAPIResponse(

View File

@ -24,7 +24,7 @@ class Mullvad extends AppSource {
@override
Future<APKDetails> getLatestAPKDetails(
String standardUrl, List<String> additionalData,
String standardUrl, Map<String, String> additionalData,
{bool trackOnly = false}) async {
Response res = await get(Uri.parse('$standardUrl/en/download/android'));
if (res.statusCode == 200) {

View File

@ -18,7 +18,7 @@ class Signal extends AppSource {
@override
Future<APKDetails> getLatestAPKDetails(
String standardUrl, List<String> additionalData,
String standardUrl, Map<String, String> additionalData,
{bool trackOnly = false}) async {
Response res =
await get(Uri.parse('https://updates.$host/android/latest.json'));

View File

@ -23,7 +23,7 @@ class SourceForge extends AppSource {
@override
Future<APKDetails> getLatestAPKDetails(
String standardUrl, List<String> additionalData,
String standardUrl, Map<String, String> additionalData,
{bool trackOnly = false}) async {
Response res = await get(Uri.parse('$standardUrl/rss?path=/'));
if (res.statusCode == 200) {

View File

@ -11,11 +11,8 @@ class SteamMobile extends AppSource {
name = tr('steam');
additionalSourceAppSpecificFormItems = [
[
GeneratedFormItem(
label: tr('app'),
key: 'app',
required: true,
opts: apks.entries.toList())
GeneratedFormItem('app',
label: tr('app'), required: true, opts: apks.entries.toList())
]
];
}
@ -32,15 +29,11 @@ class SteamMobile extends AppSource {
@override
Future<APKDetails> getLatestAPKDetails(
String standardUrl, List<String> additionalData,
String standardUrl, Map<String, String> additionalData,
{bool trackOnly = false}) async {
Response res = await get(Uri.parse('https://$host/mobile'));
if (res.statusCode == 200) {
var apkNamePrefix = findGeneratedFormValueByKey(
additionalSourceAppSpecificFormItems
.reduce((value, element) => [...value, ...element]),
additionalData,
'app');
var apkNamePrefix = additionalData['app'];
if (apkNamePrefix == null) {
throw NoReleasesError();
}

View File

@ -4,7 +4,7 @@ import 'package:flutter/material.dart';
enum FormItemType { string, bool }
typedef OnValueChanges = void Function(
List<String> values, bool valid, bool isBuilding);
Map<String, String> values, bool valid, bool isBuilding);
class GeneratedFormItem {
late String key;
@ -13,22 +13,19 @@ class GeneratedFormItem {
late bool required;
late int max;
late List<String? Function(String? value)> additionalValidators;
late String id;
late List<Widget> belowWidgets;
late String? hint;
late List<MapEntry<String, String>>? opts;
GeneratedFormItem(
GeneratedFormItem(this.key,
{this.label = 'Input',
this.type = FormItemType.string,
this.required = true,
this.max = 1,
this.additionalValidators = const [],
this.id = 'input',
this.belowWidgets = const [],
this.hint,
this.opts,
this.key = 'default'}) {
this.opts}) {
if (type != FormItemType.string) {
required = false;
}
@ -44,7 +41,7 @@ class GeneratedForm extends StatefulWidget {
final List<List<GeneratedFormItem>> items;
final OnValueChanges onValueChanges;
final List<String> defaultValues;
final Map<String, String> defaultValues;
@override
State<GeneratedForm> createState() => _GeneratedFormState();
@ -52,17 +49,18 @@ class GeneratedForm extends StatefulWidget {
class _GeneratedFormState extends State<GeneratedForm> {
final _formKey = GlobalKey<FormState>();
late List<List<String>> values;
Map<String, String> values = {};
late List<List<Widget>> formInputs;
List<List<Widget>> rows = [];
// If any value changes, call this to update the parent with value and validity
void someValueChanged({bool isBuilding = false}) {
List<String> returnValues = [];
Map<String, String> returnValues = {};
var valid = true;
for (int r = 0; r < values.length; r++) {
for (int i = 0; i < values[r].length; i++) {
returnValues.add(values[r][i]);
for (int r = 0; r < widget.items.length; r++) {
for (int i = 0; i < widget.items[r].length; i++) {
returnValues[widget.items[r][i].key] =
values[widget.items[r][i].key] ?? '';
if (formInputs[r][i] is TextFormField) {
valid = valid &&
((formInputs[r][i].key as GlobalKey<FormFieldState>)
@ -80,16 +78,13 @@ class _GeneratedFormState extends State<GeneratedForm> {
super.initState();
// Initialize form values as all empty
values.clear();
int j = 0;
values = widget.items
.map((row) => row.map((e) {
return j < widget.defaultValues.length
? widget.defaultValues[j++]
: e.opts != null
? e.opts!.first.key
: '';
}).toList())
.toList();
for (var row in widget.items) {
for (var e in row) {
values[e.key] = widget.defaultValues[e.key] ?? e.opts?.first.key ?? '';
}
}
// Dynamically create form inputs
formInputs = widget.items.asMap().entries.map((row) {
@ -98,11 +93,11 @@ class _GeneratedFormState extends State<GeneratedForm> {
final formFieldKey = GlobalKey<FormFieldState>();
return TextFormField(
key: formFieldKey,
initialValue: values[row.key][e.key],
initialValue: values[e.value.key],
autovalidateMode: AutovalidateMode.onUserInteraction,
onChanged: (value) {
setState(() {
values[row.key][e.key] = value;
values[e.value.key] = value;
someValueChanged();
});
},
@ -131,14 +126,14 @@ class _GeneratedFormState extends State<GeneratedForm> {
}
return DropdownButtonFormField(
decoration: InputDecoration(labelText: e.value.label),
value: values[row.key][e.key],
value: values[e.value.key],
items: e.value.opts!
.map((e) =>
DropdownMenuItem(value: e.key, child: Text(e.value)))
.toList(),
onChanged: (value) {
setState(() {
values[row.key][e.key] = value ?? e.value.opts!.first.key;
values[e.value.key] = value ?? e.value.opts!.first.key;
someValueChanged();
});
});
@ -160,10 +155,10 @@ class _GeneratedFormState extends State<GeneratedForm> {
children: [
Text(widget.items[r][e].label),
Switch(
value: values[r][e] == 'true',
value: values[widget.items[r][e].key] == 'true',
onChanged: (value) {
setState(() {
values[r][e] = value ? 'true' : '';
values[widget.items[r][e].key] = value ? 'true' : '';
someValueChanged();
});
})
@ -217,18 +212,3 @@ class _GeneratedFormState extends State<GeneratedForm> {
));
}
}
String? findGeneratedFormValueByKey(
List<GeneratedFormItem> items, List<String> values, String key) {
var foundIndex = -1;
for (var i = 0; i < items.length; i++) {
if (items[i].key == key) {
foundIndex = i;
break;
}
}
if (foundIndex >= 0 && foundIndex < values.length) {
return values[foundIndex];
}
return null;
}

View File

@ -15,7 +15,7 @@ class GeneratedFormModal extends StatefulWidget {
final String title;
final String message;
final List<List<GeneratedFormItem>> items;
final List<String> defaultValues;
final Map<String, String> defaultValues;
final bool initValid;
@override
@ -23,13 +23,15 @@ class GeneratedFormModal extends StatefulWidget {
}
class _GeneratedFormModalState extends State<GeneratedFormModal> {
List<String> values = [];
Map<String, String> values = {};
bool valid = false;
@override
void initState() {
super.initState();
values = widget.defaultValues;
widget.defaultValues.forEach((key, value) {
values[key] = value;
});
valid = widget.initValid || widget.items.isEmpty;
}

View File

@ -200,7 +200,7 @@ class _ObtainiumState extends State<Obtainium> {
currentReleaseTag,
[],
0,
['true'],
{},
null,
false,
false)

View File

@ -27,9 +27,9 @@ class _AddAppPageState extends State<AddAppPage> {
String userInput = '';
String searchQuery = '';
AppSource? pickedSource;
List<String> sourceSpecificAdditionalData = [];
Map<String, String> sourceSpecificAdditionalData = {};
bool sourceSpecificDataIsValid = true;
List<String> otherAdditionalData = [];
Map<String, String> otherAdditionalData = {};
bool otherAdditionalDataIsValid = true;
@override
@ -44,7 +44,7 @@ class _AddAppPageState extends State<AddAppPage> {
if (pickedSource.runtimeType != source.runtimeType) {
pickedSource = source;
sourceSpecificAdditionalData =
source != null ? source.additionalSourceAppSpecificDefaults : [];
source != null ? source.additionalSourceAppSpecificDefaults : {};
sourceSpecificDataIsValid = source != null
? !sourceProvider.ifSourceAppsRequireAdditionalData(source)
: true;
@ -66,16 +66,10 @@ class _AddAppPageState extends State<AddAppPage> {
});
var settingsProvider = context.read<SettingsProvider>();
() async {
var userPickedTrackOnly = findGeneratedFormValueByKey(
pickedSource!.additionalAppSpecificSourceAgnosticFormItems,
otherAdditionalData,
'trackOnlyFormItemKey') ==
'true';
var userPickedNoVersionDetection = findGeneratedFormValueByKey(
pickedSource!.additionalAppSpecificSourceAgnosticFormItems,
otherAdditionalData,
'noVersionDetectionKey') ==
'true';
var userPickedTrackOnly =
otherAdditionalData['trackOnlyFormItemKey'] == 'true';
var userPickedNoVersionDetection =
otherAdditionalData['noVersionDetectionKey'] == 'true';
var cont = true;
if ((userPickedTrackOnly || pickedSource!.enforceTrackOnly) &&
await showDialog(
@ -88,7 +82,7 @@ class _AddAppPageState extends State<AddAppPage> {
: tr('app')
]),
items: const [],
defaultValues: const [],
defaultValues: const {},
message:
'${pickedSource!.enforceTrackOnly ? tr('appsFromSourceAreTrackOnly') : tr('youPickedTrackOnly')}\n\n${tr('trackOnlyAppDescription')}',
);
@ -100,10 +94,10 @@ class _AddAppPageState extends State<AddAppPage> {
await showDialog(
context: context,
builder: (BuildContext ctx) {
return GeneratedFormModal(
return const GeneratedFormModal(
title: 'Disable Version Detection', // TODO
items: const [],
defaultValues: const [],
items: [],
defaultValues: {},
message: 'TODO',
);
}) ==
@ -177,7 +171,7 @@ class _AddAppPageState extends State<AddAppPage> {
child: GeneratedForm(
items: [
[
GeneratedFormItem(
GeneratedFormItem('appSourceURL',
label: tr('appSourceURL'),
additionalValidators: [
(value) {
@ -200,10 +194,10 @@ class _AddAppPageState extends State<AddAppPage> {
]
],
onValueChanges: (values, valid, isBuilding) {
changeUserInput(
values[0], valid, isBuilding);
changeUserInput(values['appSourceURL']!,
valid, isBuilding);
},
defaultValues: const [])),
defaultValues: const {'appSourceURL': ''})),
const SizedBox(
width: 16,
),
@ -244,7 +238,7 @@ class _AddAppPageState extends State<AddAppPage> {
child: GeneratedForm(
items: [
[
GeneratedFormItem(
GeneratedFormItem('searchSomeSources',
label: tr('searchSomeSourcesLabel'),
required: false),
]
@ -252,11 +246,14 @@ class _AddAppPageState extends State<AddAppPage> {
onValueChanges: (values, valid, isBuilding) {
if (values.isNotEmpty && valid) {
setState(() {
searchQuery = values[0].trim();
searchQuery =
values['searchSomeSources']!.trim();
});
}
},
defaultValues: const ['']),
defaultValues: const {
'searchSomeSources': ''
}),
),
const SizedBox(
width: 16,

View File

@ -208,7 +208,7 @@ class _AppPageState extends State<AppPage> {
onPressed: app?.downloadProgress != null
? null
: () {
showDialog<List<String>>(
showDialog<Map<String, String>>(
context: context,
builder: (BuildContext ctx) {
return GeneratedFormModal(

View File

@ -349,7 +349,7 @@ class AppsPageState extends State<AppsPage> {
return GeneratedFormModal(
title: tr('removeSelectedAppsQuestion'),
items: const [],
defaultValues: const [],
defaultValues: const {},
initValid: true,
message: tr(
'xWillBeRemovedButRemainInstalled',
@ -377,40 +377,37 @@ class AppsPageState extends State<AppsPage> {
: () {
HapticFeedback.heavyImpact();
List<GeneratedFormItem> formInputs = [];
List<String> defaultValues = [];
Map<String, String> defaultValues = {};
if (existingUpdateIdsAllOrSelected.isNotEmpty) {
formInputs.add(GeneratedFormItem(
formInputs.add(GeneratedFormItem('updates',
label: tr('updateX', args: [
plural('apps',
existingUpdateIdsAllOrSelected.length)
]),
type: FormItemType.bool,
key: 'updates'));
defaultValues.add('true');
type: FormItemType.bool));
defaultValues['updates'] = 'true';
}
if (newInstallIdsAllOrSelected.isNotEmpty) {
formInputs.add(GeneratedFormItem(
formInputs.add(GeneratedFormItem('installs',
label: tr('installX', args: [
plural('apps',
newInstallIdsAllOrSelected.length)
]),
type: FormItemType.bool,
key: 'installs'));
defaultValues
.add(defaultValues.isEmpty ? 'true' : '');
type: FormItemType.bool));
defaultValues['installs'] =
defaultValues.isEmpty ? 'true' : '';
}
if (trackOnlyUpdateIdsAllOrSelected.isNotEmpty) {
formInputs.add(GeneratedFormItem(
formInputs.add(GeneratedFormItem('trackonlies',
label: tr('markXTrackOnlyAsUpdated', args: [
plural('apps',
trackOnlyUpdateIdsAllOrSelected.length)
]),
type: FormItemType.bool,
key: 'trackonlies'));
defaultValues
.add(defaultValues.isEmpty ? 'true' : '');
type: FormItemType.bool));
defaultValues['trackonlies'] =
defaultValues.isEmpty ? 'true' : '';
}
showDialog<List<String>?>(
showDialog<Map<String, String>?>(
context: context,
builder: (BuildContext ctx) {
var totalApps = existingUpdateIdsAllOrSelected
@ -430,17 +427,11 @@ class AppsPageState extends State<AppsPage> {
values = defaultValues;
}
bool shouldInstallUpdates =
findGeneratedFormValueByKey(
formInputs, values, 'updates') ==
'true';
values['updates'] == 'true';
bool shouldInstallNew =
findGeneratedFormValueByKey(
formInputs, values, 'installs') ==
'true';
values['installs'] == 'true';
bool shouldMarkTrackOnlies =
findGeneratedFormValueByKey(formInputs,
values, 'trackonlies') ==
'true';
values['trackonlies'] == 'true';
(() async {
if (shouldInstallNew ||
shouldInstallUpdates) {
@ -613,7 +604,7 @@ class AppsPageState extends State<AppsPage> {
title: tr(
'resetInstallStatusForSelectedAppsQuestion'),
items: const [],
defaultValues: const [],
defaultValues: const {},
initValid: true,
message: tr(
'installStatusOfXWillBeResetExplanation',
@ -683,36 +674,36 @@ class AppsPageState extends State<AppsPage> {
: FontWeight.bold),
),
onPressed: () {
showDialog<List<String>?>(
showDialog<Map<String, String>?>(
context: context,
builder: (BuildContext ctx) {
return GeneratedFormModal(
title: tr('filterApps'),
items: [
[
GeneratedFormItem(
GeneratedFormItem('appName',
label: tr('appName'), required: false),
GeneratedFormItem(
GeneratedFormItem('author',
label: tr('author'), required: false)
],
[
GeneratedFormItem(
GeneratedFormItem('upToDateApps',
label: tr('upToDateApps'),
type: FormItemType.bool)
],
[
GeneratedFormItem(
GeneratedFormItem('nonInstalledApps',
label: tr('nonInstalledApps'),
type: FormItemType.bool)
]
],
defaultValues: filter == null
? AppsFilter().toValuesArray()
: filter!.toValuesArray());
? AppsFilter().toValuesMap()
: filter!.toValuesMap());
}).then((values) {
if (values != null) {
setState(() {
filter = AppsFilter.fromValuesArray(values);
filter = AppsFilter.fromValuesMap(values);
if (AppsFilter().isIdenticalTo(filter!)) {
filter = null;
}
@ -740,20 +731,20 @@ class AppsFilter {
this.includeUptodate = true,
this.includeNonInstalled = true});
List<String> toValuesArray() {
return [
nameFilter,
authorFilter,
includeUptodate ? 'true' : '',
includeNonInstalled ? 'true' : ''
];
Map<String, String> toValuesMap() {
return {
'appName': nameFilter,
'author': authorFilter,
'upToDateApps': includeUptodate ? 'true' : '',
'nonInstalledApps': includeNonInstalled ? 'true' : ''
};
}
AppsFilter.fromValuesArray(List<String> values) {
nameFilter = values[0];
authorFilter = values[1];
includeUptodate = values[2] == 'true';
includeNonInstalled = values[3] == 'true';
AppsFilter.fromValuesMap(Map<String, String> values) {
nameFilter = values['appName']!;
authorFilter = values['author']!;
includeUptodate = values['upToDateApps'] == 'true';
includeNonInstalled = values['nonInstalledApps'] == 'true';
}
bool isIdenticalTo(AppsFilter other) =>

View File

@ -145,7 +145,7 @@ class _ImportExportPageState extends State<ImportExportPage> {
title: tr('importFromURLList'),
items: [
[
GeneratedFormItem(
GeneratedFormItem('appURLList',
label: tr('appURLList'),
max: 7,
additionalValidators: [
@ -172,7 +172,7 @@ class _ImportExportPageState extends State<ImportExportPage> {
])
]
],
defaultValues: const [],
defaultValues: const {},
);
}).then((values) {
if (values != null) {
@ -237,11 +237,12 @@ class _ImportExportPageState extends State<ImportExportPage> {
items: [
[
GeneratedFormItem(
'searchQuery',
label: tr(
'searchQuery'))
]
],
defaultValues: const [],
defaultValues: const {},
);
});
if (values != null &&
@ -346,10 +347,11 @@ class _ImportExportPageState extends State<ImportExportPage> {
.requiredArgs
.map(
(e) => [
GeneratedFormItem(label: e)
GeneratedFormItem(e,
label: e)
])
.toList(),
defaultValues: const [],
defaultValues: const {},
);
});
if (values != null) {

View File

@ -143,16 +143,16 @@ class _SettingsPageState extends State<SettingsPage> {
.toList(),
onValueChanges: (values, valid, isBuilding) {
if (valid) {
for (var i = 0; i < values.length; i++) {
settingsProvider.setSettingString(
e.additionalSourceSpecificSettingFormItems[i].id,
values[i]);
}
values.forEach((key, value) {
settingsProvider.setSettingString(key, value);
});
}
},
defaultValues: e.additionalSourceSpecificSettingFormItems.map((e) {
return settingsProvider.getSettingString(e.id) ?? '';
}).toList());
defaultValues: Map.fromEntries(
e.additionalSourceSpecificSettingFormItems.map((e) {
return MapEntry(
e.key, settingsProvider.getSettingString(e.key) ?? '');
})));
} else {
return Container();
}

View File

@ -44,7 +44,7 @@ class App {
late String latestVersion;
List<String> apkUrls = [];
late int preferredApkIndex;
late List<String> additionalData;
late Map<String, String> additionalData;
late DateTime? lastUpdateCheck;
bool pinned = false;
bool trackOnly = false;
@ -86,7 +86,7 @@ class App {
? SourceProvider()
.getSource(json['url'])
.additionalSourceAppSpecificDefaults
: List<String>.from(jsonDecode(json['additionalData'])),
: Map<String, String>.from(jsonDecode(json['additionalData'])),
json['lastUpdateCheck'] == null
? null
: DateTime.fromMicrosecondsSinceEpoch(json['lastUpdateCheck']),
@ -155,27 +155,30 @@ class AppSource {
}
Future<APKDetails> getLatestAPKDetails(
String standardUrl, List<String> additionalData,
String standardUrl, Map<String, String> additionalData,
{bool trackOnly = false}) {
throw NotImplementedError();
}
// Different Sources may need different kinds of additional data for Apps
List<List<GeneratedFormItem>> additionalSourceAppSpecificFormItems = [];
List<String> additionalSourceAppSpecificDefaults = [];
Map<String, String> additionalSourceAppSpecificDefaults = {};
// Some additional data may be needed for Apps regardless of Source
final List<GeneratedFormItem> additionalAppSpecificSourceAgnosticFormItems = [
GeneratedFormItem(
'trackOnlyFormItemKey',
label: tr('trackOnly'),
type: FormItemType.bool,
key: 'trackOnlyFormItemKey'),
GeneratedFormItem(
),
GeneratedFormItem('noVersionDetectionKey',
label: 'Do not attempt version detection', // TODO
type: FormItemType.bool,
key: 'noVersionDetectionKey')
type: FormItemType.bool)
];
final List<String> additionalAppSpecificSourceAgnosticDefaults = ['', ''];
final Map<String, String> additionalAppSpecificSourceAgnosticDefaults = {
'trackOnlyFormItemKey': '',
'noVersionDetectionKey': ''
};
// Some Sources may have additional settings at the Source level (not specific to Apps) - these use SettingsProvider
List<GeneratedFormItem> additionalSourceSpecificSettingFormItems = [];
@ -194,7 +197,7 @@ class AppSource {
}
String? tryInferringAppId(String standardUrl,
{List<String> additionalData = const []}) {
{Map<String, String> additionalData = const {}}) {
return null;
}
}
@ -282,7 +285,8 @@ class SourceProvider {
return true;
}
Future<App> getApp(AppSource source, String url, List<String> additionalData,
Future<App> getApp(
AppSource source, String url, Map<String, String> additionalData,
{App? currentApp,
bool trackOnlyOverride = false,
noVersionDetectionOverride = false}) async {