mirror of
				https://github.com/ImranR98/Obtainium.git
				synced 2025-11-04 15:23:28 +01:00 
			
		
		
		
	Started switching additionaldata to map
This commit is contained in:
		@@ -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) {
 | 
			
		||||
 
 | 
			
		||||
@@ -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(
 | 
			
		||||
 
 | 
			
		||||
@@ -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();
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -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'));
 | 
			
		||||
 
 | 
			
		||||
@@ -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) {
 | 
			
		||||
 
 | 
			
		||||
@@ -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(
 | 
			
		||||
 
 | 
			
		||||
@@ -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) {
 | 
			
		||||
 
 | 
			
		||||
@@ -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'));
 | 
			
		||||
 
 | 
			
		||||
@@ -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) {
 | 
			
		||||
 
 | 
			
		||||
@@ -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();
 | 
			
		||||
      }
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -200,7 +200,7 @@ class _ObtainiumState extends State<Obtainium> {
 | 
			
		||||
              currentReleaseTag,
 | 
			
		||||
              [],
 | 
			
		||||
              0,
 | 
			
		||||
              ['true'],
 | 
			
		||||
              {},
 | 
			
		||||
              null,
 | 
			
		||||
              false,
 | 
			
		||||
              false)
 | 
			
		||||
 
 | 
			
		||||
@@ -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,
 | 
			
		||||
 
 | 
			
		||||
@@ -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(
 | 
			
		||||
 
 | 
			
		||||
@@ -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) =>
 | 
			
		||||
 
 | 
			
		||||
@@ -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) {
 | 
			
		||||
 
 | 
			
		||||
@@ -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();
 | 
			
		||||
      }
 | 
			
		||||
 
 | 
			
		||||
@@ -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 {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user