diff --git a/assets/translations/de.json b/assets/translations/de.json index 5a3bc13..ac7da30 100644 --- a/assets/translations/de.json +++ b/assets/translations/de.json @@ -211,6 +211,7 @@ "language": "Sprache", "storagePermissionDenied": "Storage permission denied", "selectedCategorizeWarning": "This will replace any existing category settings for the selected Apps.", + "filterAPKsByRegEx": "Filter APKs by Regular Expression", "tooManyRequestsTryAgainInMinutes": { "one": "Zu viele Anfragen (Rate begrenzt) - versuchen Sie es in {} Minute erneut", "other": "Zu viele Anfragen (Rate begrenzt) - versuchen Sie es in {} Minuten erneut" diff --git a/assets/translations/en.json b/assets/translations/en.json index 1fae8c8..274947e 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -211,6 +211,7 @@ "language": "Language", "storagePermissionDenied": "Storage permission denied", "selectedCategorizeWarning": "This will replace any existing category settings for the selected Apps.", + "filterAPKsByRegEx": "Filter APKs by Regular Expression", "tooManyRequestsTryAgainInMinutes": { "one": "Too many requests (rate limited) - try again in {} minute", "other": "Too many requests (rate limited) - try again in {} minutes" diff --git a/assets/translations/hu.json b/assets/translations/hu.json index 54e82e7..c6466fd 100644 --- a/assets/translations/hu.json +++ b/assets/translations/hu.json @@ -210,6 +210,7 @@ "language": "Nyelv", "storagePermissionDenied": "Tárhely engedély megtagadva", "selectedCategorizeWarning": "Ez felváltja a kiválasztott alkalmazások meglévő kategória-beállításait.", + "filterAPKsByRegEx": "Filter APKs by Regular Expression", "tooManyRequestsTryAgainInMinutes": { "one": "Túl sok kérés (korlátozott arány) – próbálja újra {} perc múlva", "other": "Túl sok kérés (korlátozott arány) – próbálja újra {} perc múlva" diff --git a/assets/translations/it.json b/assets/translations/it.json index a0f01f0..4a56c8a 100644 --- a/assets/translations/it.json +++ b/assets/translations/it.json @@ -211,6 +211,7 @@ "language": "Lingua", "storagePermissionDenied": "Storage permission denied", "selectedCategorizeWarning": "This will replace any existing category settings for the selected Apps.", + "filterAPKsByRegEx": "Filter APKs by Regular Expression", "tooManyRequestsTryAgainInMinutes": { "one": "Troppe richieste (traffico limitato) - riprova tra {} minuto", "other": "Troppe richieste (traffico limitato) - riprova tra {} minuti" diff --git a/assets/translations/ja.json b/assets/translations/ja.json index 7aadadb..ba1e5c1 100644 --- a/assets/translations/ja.json +++ b/assets/translations/ja.json @@ -211,6 +211,7 @@ "language": "言語", "storagePermissionDenied": "ストレージ権限が拒否されました", "selectedCategorizeWarning": "これにより、選択したアプリの既存のカテゴリ設定がすべて置き換えられます。", + "filterAPKsByRegEx": "Filter APKs by Regular Expression", "tooManyRequestsTryAgainInMinutes": { "one": "リクエストが多すぎます(レート制限)- {}分後に再試行してください", "other": "リクエストが多すぎます(レート制限)- {}分後に再試行してください" diff --git a/assets/translations/zh.json b/assets/translations/zh.json index 0d271b1..8f103a8 100644 --- a/assets/translations/zh.json +++ b/assets/translations/zh.json @@ -211,6 +211,7 @@ "language": "语言", "storagePermissionDenied": "存储权限已被拒绝", "selectedCategorizeWarning": "这将取代所选应用程序的任何现有类别", + "filterAPKsByRegEx": "Filter APKs by Regular Expression", "tooManyRequestsTryAgainInMinutes": { "one": "请求过多 (API 限制) - 在 {} 分钟后重试", "other": "请求过多 (API 限制) - 在 {} 分钟后重试" diff --git a/lib/app_sources/codeberg.dart b/lib/app_sources/codeberg.dart index 1e38a4e..d00bcd8 100644 --- a/lib/app_sources/codeberg.dart +++ b/lib/app_sources/codeberg.dart @@ -26,15 +26,7 @@ class Codeberg extends AppSource { required: false, additionalValidators: [ (value) { - if (value == null || value.isEmpty) { - return null; - } - try { - RegExp(value); - } catch (e) { - return tr('invalidRegEx'); - } - return null; + return regExValidator(value); } ]) ] diff --git a/lib/app_sources/github.dart b/lib/app_sources/github.dart index f17adf9..1169d88 100644 --- a/lib/app_sources/github.dart +++ b/lib/app_sources/github.dart @@ -65,15 +65,7 @@ class GitHub extends AppSource { required: false, additionalValidators: [ (value) { - if (value == null || value.isEmpty) { - return null; - } - try { - RegExp(value); - } catch (e) { - return tr('invalidRegEx'); - } - return null; + return regExValidator(value); } ]) ] diff --git a/lib/pages/add_app.dart b/lib/pages/add_app.dart index ff3f75e..a216a7e 100644 --- a/lib/pages/add_app.dart +++ b/lib/pages/add_app.dart @@ -70,6 +70,7 @@ class _AddAppPageState extends State { additionalSettings['noVersionDetection'] == true; var cont = true; if ((userPickedTrackOnly || pickedSource!.enforceTrackOnly) && + // ignore: use_build_context_synchronously await showDialog( context: context, builder: (BuildContext ctx) { @@ -88,6 +89,7 @@ class _AddAppPageState extends State { cont = false; } if (userPickedNoVersionDetection && + // ignore: use_build_context_synchronously await showDialog( context: context, builder: (BuildContext ctx) { diff --git a/lib/pages/apps.dart b/lib/pages/apps.dart index 1b422f8..56f569a 100644 --- a/lib/pages/apps.dart +++ b/lib/pages/apps.dart @@ -344,538 +344,564 @@ class AppsPageState extends State { )); }, childCount: sortedApps.length)) ])), - persistentFooterButtons: [ - Row( - children: [ - selectedApps.isEmpty - ? TextButton.icon( - style: - const ButtonStyle(visualDensity: VisualDensity.compact), - onPressed: () { - selectThese(sortedApps.map((e) => e.app).toList()); - }, - icon: Icon( - Icons.select_all_outlined, - color: Theme.of(context).colorScheme.primary, - ), - label: Text(sortedApps.length.toString())) - : TextButton.icon( - style: - const ButtonStyle(visualDensity: VisualDensity.compact), - onPressed: () { - selectedApps.isEmpty - ? selectThese(sortedApps.map((e) => e.app).toList()) - : clearSelected(); - }, - icon: Icon( - selectedApps.isEmpty - ? Icons.select_all_outlined - : Icons.deselect_outlined, - color: Theme.of(context).colorScheme.primary, - ), - label: Text(selectedApps.length.toString())), - const VerticalDivider(), - Expanded( - child: SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - IconButton( - visualDensity: VisualDensity.compact, - onPressed: selectedApps.isEmpty - ? null - : () { - showDialog?>( - context: context, - builder: (BuildContext ctx) { - return GeneratedFormModal( - title: - tr('removeSelectedAppsQuestion'), - items: const [], - initValid: true, - message: tr( - 'xWillBeRemovedButRemainInstalled', - args: [ - plural( - 'apps', selectedApps.length) - ]), - ); - }).then((values) { - if (values != null) { - appsProvider.removeApps(selectedApps - .map((e) => e.id) - .toList()); - } - }); - }, - tooltip: tr('removeSelectedApps'), - icon: const Icon(Icons.delete_outline_outlined), - ), - IconButton( - visualDensity: VisualDensity.compact, - onPressed: appsProvider.areDownloadsRunning() || - (existingUpdateIdsAllOrSelected.isEmpty && - newInstallIdsAllOrSelected.isEmpty && - trackOnlyUpdateIdsAllOrSelected.isEmpty) - ? null - : () { - HapticFeedback.heavyImpact(); - List formItems = []; - if (existingUpdateIdsAllOrSelected - .isNotEmpty) { - formItems.add(GeneratedFormSwitch( - 'updates', - label: tr('updateX', args: [ - plural( - 'apps', - existingUpdateIdsAllOrSelected - .length) - ]), - defaultValue: true)); - } - if (newInstallIdsAllOrSelected.isNotEmpty) { - formItems.add(GeneratedFormSwitch( - 'installs', - label: tr('installX', args: [ - plural( - 'apps', - newInstallIdsAllOrSelected - .length) - ]), - defaultValue: - existingUpdateIdsAllOrSelected - .isNotEmpty)); - } - if (trackOnlyUpdateIdsAllOrSelected - .isNotEmpty) { - formItems.add(GeneratedFormSwitch( - 'trackonlies', - label: tr('markXTrackOnlyAsUpdated', - args: [ - plural( - 'apps', - trackOnlyUpdateIdsAllOrSelected - .length) - ]), - defaultValue: - existingUpdateIdsAllOrSelected - .isNotEmpty || - newInstallIdsAllOrSelected - .isNotEmpty)); - } - showDialog?>( - context: context, - builder: (BuildContext ctx) { - var totalApps = - existingUpdateIdsAllOrSelected.length + - newInstallIdsAllOrSelected - .length + - trackOnlyUpdateIdsAllOrSelected - .length; - return GeneratedFormModal( - title: tr('changeX', args: [ - plural('apps', totalApps) - ]), - items: formItems - .map((e) => [e]) - .toList(), - initValid: true, - ); - }).then((values) { - if (values != null) { - if (values.isEmpty) { - values = - getDefaultValuesFromFormItems( - [formItems]); - } - bool shouldInstallUpdates = - values['updates'] == true; - bool shouldInstallNew = - values['installs'] == true; - bool shouldMarkTrackOnlies = - values['trackonlies'] == true; - (() async { - if (shouldInstallNew || - shouldInstallUpdates) { - await settingsProvider - .getInstallPermission(); + persistentFooterButtons: appsProvider.apps.isEmpty + ? null + : [ + Row( + children: [ + selectedApps.isEmpty + ? TextButton.icon( + style: const ButtonStyle( + visualDensity: VisualDensity.compact), + onPressed: () { + selectThese(sortedApps.map((e) => e.app).toList()); + }, + icon: Icon( + Icons.select_all_outlined, + color: Theme.of(context).colorScheme.primary, + ), + label: Text(sortedApps.length.toString())) + : TextButton.icon( + style: const ButtonStyle( + visualDensity: VisualDensity.compact), + onPressed: () { + selectedApps.isEmpty + ? selectThese( + sortedApps.map((e) => e.app).toList()) + : clearSelected(); + }, + icon: Icon( + selectedApps.isEmpty + ? Icons.select_all_outlined + : Icons.deselect_outlined, + color: Theme.of(context).colorScheme.primary, + ), + label: Text(selectedApps.length.toString())), + const VerticalDivider(), + Expanded( + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + IconButton( + visualDensity: VisualDensity.compact, + onPressed: selectedApps.isEmpty + ? null + : () { + showDialog?>( + context: context, + builder: (BuildContext ctx) { + return GeneratedFormModal( + title: tr( + 'removeSelectedAppsQuestion'), + items: const [], + initValid: true, + message: tr( + 'xWillBeRemovedButRemainInstalled', + args: [ + plural('apps', + selectedApps.length) + ]), + ); + }).then((values) { + if (values != null) { + appsProvider.removeApps(selectedApps + .map((e) => e.id) + .toList()); } - })() - .then((_) { - List toInstall = []; - if (shouldInstallUpdates) { - toInstall.addAll( - existingUpdateIdsAllOrSelected); - } - if (shouldInstallNew) { - toInstall.addAll( - newInstallIdsAllOrSelected); - } - if (shouldMarkTrackOnlies) { - toInstall.addAll( - trackOnlyUpdateIdsAllOrSelected); - } - appsProvider - .downloadAndInstallLatestApps( - toInstall, - globalNavigatorKey - .currentContext) - .catchError((e) { - showError(e, context); - }); }); - } - }); - }, - tooltip: selectedApps.isEmpty - ? tr('installUpdateApps') - : tr('installUpdateSelectedApps'), - icon: const Icon( - Icons.file_download_outlined, - )), - IconButton( - visualDensity: VisualDensity.compact, - onPressed: selectedApps.isEmpty - ? null - : () async { - try { - Set? preselected; - var showPrompt = false; - for (var element in selectedApps) { - var currentCats = - element.categories.toSet(); - if (preselected == null) { - preselected = currentCats; - } else { - if (!settingsProvider.setEqual( - currentCats, preselected)) { - showPrompt = true; - break; - } - } - } - var cont = true; - if (showPrompt) { - cont = await showDialog< - Map?>( + }, + tooltip: tr('removeSelectedApps'), + icon: const Icon(Icons.delete_outline_outlined), + ), + IconButton( + visualDensity: VisualDensity.compact, + onPressed: appsProvider + .areDownloadsRunning() || + (existingUpdateIdsAllOrSelected + .isEmpty && + newInstallIdsAllOrSelected + .isEmpty && + trackOnlyUpdateIdsAllOrSelected + .isEmpty) + ? null + : () { + HapticFeedback.heavyImpact(); + List formItems = + []; + if (existingUpdateIdsAllOrSelected + .isNotEmpty) { + formItems.add(GeneratedFormSwitch( + 'updates', + label: tr('updateX', args: [ + plural( + 'apps', + existingUpdateIdsAllOrSelected + .length) + ]), + defaultValue: true)); + } + if (newInstallIdsAllOrSelected + .isNotEmpty) { + formItems.add(GeneratedFormSwitch( + 'installs', + label: tr('installX', args: [ + plural( + 'apps', + newInstallIdsAllOrSelected + .length) + ]), + defaultValue: + existingUpdateIdsAllOrSelected + .isNotEmpty)); + } + if (trackOnlyUpdateIdsAllOrSelected + .isNotEmpty) { + formItems.add(GeneratedFormSwitch( + 'trackonlies', + label: tr( + 'markXTrackOnlyAsUpdated', + args: [ + plural( + 'apps', + trackOnlyUpdateIdsAllOrSelected + .length) + ]), + defaultValue: + existingUpdateIdsAllOrSelected + .isNotEmpty || + newInstallIdsAllOrSelected + .isNotEmpty)); + } + showDialog?>( context: context, builder: (BuildContext ctx) { + var totalApps = existingUpdateIdsAllOrSelected + .length + + newInstallIdsAllOrSelected + .length + + trackOnlyUpdateIdsAllOrSelected + .length; return GeneratedFormModal( - title: tr('categorize'), - items: const [], + title: tr('changeX', args: [ + plural('apps', totalApps) + ]), + items: formItems + .map((e) => [e]) + .toList(), initValid: true, - message: tr( - 'selectedCategorizeWarning'), ); - }) != - null; - } - if (cont) { - await showDialog?>( - context: context, - builder: (BuildContext ctx) { - return GeneratedFormModal( - title: tr('categorize'), - items: const [], - initValid: true, - singleNullReturnButton: - tr('continue'), - additionalWidgets: [ - CategoryEditorSelector( - preselected: !showPrompt - ? preselected ?? {} - : {}, - showLabelWhenNotEmpty: false, - onSelected: (categories) { - appsProvider.saveApps( - selectedApps.map((e) { - e.categories = categories; - return e; - }).toList()); - }, - ) - ], - ); + }).then((values) { + if (values != null) { + if (values.isEmpty) { + values = + getDefaultValuesFromFormItems( + [formItems]); + } + bool shouldInstallUpdates = + values['updates'] == true; + bool shouldInstallNew = + values['installs'] == true; + bool shouldMarkTrackOnlies = + values['trackonlies'] == true; + (() async { + if (shouldInstallNew || + shouldInstallUpdates) { + await settingsProvider + .getInstallPermission(); + } + })() + .then((_) { + List toInstall = []; + if (shouldInstallUpdates) { + toInstall.addAll( + existingUpdateIdsAllOrSelected); + } + if (shouldInstallNew) { + toInstall.addAll( + newInstallIdsAllOrSelected); + } + if (shouldMarkTrackOnlies) { + toInstall.addAll( + trackOnlyUpdateIdsAllOrSelected); + } + appsProvider + .downloadAndInstallLatestApps( + toInstall, + globalNavigatorKey + .currentContext) + .catchError((e) { + showError(e, context); + }); + }); + } }); - } - } catch (err) { - showError(err, context); - } - }, - tooltip: tr('categorize'), - icon: const Icon(Icons.category_outlined), - ), - IconButton( - visualDensity: VisualDensity.compact, - onPressed: selectedApps.isEmpty - ? null - : () { - showDialog( - context: context, - builder: (BuildContext ctx) { - return AlertDialog( - scrollable: true, - content: Padding( - padding: - const EdgeInsets.only(top: 6), - child: Row( - mainAxisAlignment: - MainAxisAlignment - .spaceAround, - children: [ - IconButton( - onPressed: appsProvider - .areDownloadsRunning() - ? null - : () { - showDialog( - context: - context, - builder: - (BuildContext - ctx) { - return AlertDialog( - title: Text(tr( - 'markXSelectedAppsAsUpdated', - args: [ - selectedApps.length.toString() - ])), - content: - Text( - tr('onlyWorksWithNonEVDApps'), - style: const TextStyle( - fontWeight: - FontWeight.bold, - fontStyle: FontStyle.italic), - ), - actions: [ - TextButton( - onPressed: - () { - Navigator.of(context).pop(); - }, - child: - Text(tr('no'))), - TextButton( - onPressed: - () { - HapticFeedback.selectionClick(); - appsProvider.saveApps(selectedApps.map((a) { - if (a.installedVersion != null) { - a.installedVersion = a.latestVersion; - } - return a; - }).toList()); - - Navigator.of(context).pop(); - }, - child: - Text(tr('yes'))) - ], - ); - }).whenComplete(() { - Navigator.of( - context) - .pop(); - }); - }, - tooltip: tr( - 'markSelectedAppsUpdated'), - icon: const Icon( - Icons.done)), - IconButton( - onPressed: () { - var pinStatus = - selectedApps - .where((element) => - element - .pinned) - .isEmpty; - appsProvider.saveApps( - selectedApps.map((e) { - e.pinned = pinStatus; - return e; - }).toList()); - Navigator.of(context) - .pop(); - }, - tooltip: selectedApps - .where((element) => - element.pinned) - .isEmpty - ? tr('pinToTop') - : tr('unpinFromTop'), - icon: Icon(selectedApps - .where((element) => - element.pinned) - .isEmpty - ? Icons - .bookmark_outline_rounded - : Icons - .bookmark_remove_outlined), - ), - IconButton( - onPressed: () { - String urls = ''; - for (var a - in selectedApps) { - urls += '${a.url}\n'; - } - urls = urls.substring( - 0, urls.length - 1); - Share.share(urls, - subject: tr( - 'selectedAppURLsFromObtainium')); - Navigator.of(context) - .pop(); - }, - tooltip: tr( - 'shareSelectedAppURLs'), - icon: - const Icon(Icons.share), - ), - IconButton( - onPressed: () { - showDialog( - context: context, - builder: (BuildContext - ctx) { - return GeneratedFormModal( - title: tr( - 'resetInstallStatusForSelectedAppsQuestion'), - items: const [], - initValid: true, - message: tr( - 'installStatusOfXWillBeResetExplanation', - args: [ - plural( - 'app', - selectedApps - .length) - ]), - ); - }).then((values) { - if (values != null) { + }, + tooltip: selectedApps.isEmpty + ? tr('installUpdateApps') + : tr('installUpdateSelectedApps'), + icon: const Icon( + Icons.file_download_outlined, + )), + IconButton( + visualDensity: VisualDensity.compact, + onPressed: selectedApps.isEmpty + ? null + : () async { + try { + Set? preselected; + var showPrompt = false; + for (var element in selectedApps) { + var currentCats = + element.categories.toSet(); + if (preselected == null) { + preselected = currentCats; + } else { + if (!settingsProvider.setEqual( + currentCats, preselected)) { + showPrompt = true; + break; + } + } + } + var cont = true; + if (showPrompt) { + cont = await showDialog< + Map?>( + context: context, + builder: + (BuildContext ctx) { + return GeneratedFormModal( + title: tr('categorize'), + items: const [], + initValid: true, + message: tr( + 'selectedCategorizeWarning'), + ); + }) != + null; + } + if (cont) { + // ignore: use_build_context_synchronously + await showDialog< + Map?>( + context: context, + builder: (BuildContext ctx) { + return GeneratedFormModal( + title: tr('categorize'), + items: const [], + initValid: true, + singleNullReturnButton: + tr('continue'), + additionalWidgets: [ + CategoryEditorSelector( + preselected: !showPrompt + ? preselected ?? {} + : {}, + showLabelWhenNotEmpty: + false, + onSelected: + (categories) { appsProvider.saveApps( selectedApps .map((e) { - e.installedVersion = - null; + e.categories = + categories; return e; }).toList()); - } - }).whenComplete(() { - Navigator.of(context) - .pop(); - }); - }, - tooltip: tr( - 'resetInstallStatus'), - icon: const Icon(Icons - .restore_page_outlined), - ), - ]), - ), - ); - }); - }, - tooltip: tr('more'), - icon: const Icon(Icons.more_horiz), - ), - ], - ))), - const VerticalDivider(), - IconButton( - visualDensity: VisualDensity.compact, - onPressed: () { - setState(() { - if (currentFilterIsUpdatesOnly) { - filter = AppsFilter(); - } else { - filter = updatesOnlyFilter; - } - }); - }, - tooltip: currentFilterIsUpdatesOnly - ? tr('removeOutdatedFilter') - : tr('showOutdatedOnly'), - icon: Icon( - currentFilterIsUpdatesOnly - ? Icons.update_disabled_rounded - : Icons.update_rounded, - color: Theme.of(context).colorScheme.primary, - ), - ), - appsProvider.apps.isEmpty - ? const SizedBox() - : TextButton.icon( - style: - const ButtonStyle(visualDensity: VisualDensity.compact), - label: Text( - filter.isIdenticalTo(neutralFilter, settingsProvider) - ? tr('filter') - : tr('filterActive'), - style: TextStyle( - fontWeight: filter.isIdenticalTo( - neutralFilter, settingsProvider) - ? FontWeight.normal - : FontWeight.bold), - ), + }, + ) + ], + ); + }); + } + } catch (err) { + showError(err, context); + } + }, + tooltip: tr('categorize'), + icon: const Icon(Icons.category_outlined), + ), + IconButton( + visualDensity: VisualDensity.compact, + onPressed: selectedApps.isEmpty + ? null + : () { + showDialog( + context: context, + builder: (BuildContext ctx) { + return AlertDialog( + scrollable: true, + content: Padding( + padding: + const EdgeInsets.only( + top: 6), + child: Row( + mainAxisAlignment: + MainAxisAlignment + .spaceAround, + children: [ + IconButton( + onPressed: appsProvider + .areDownloadsRunning() + ? null + : () { + showDialog( + context: + context, + builder: + (BuildContext + ctx) { + return AlertDialog( + title: + Text(tr('markXSelectedAppsAsUpdated', args: [ + selectedApps.length.toString() + ])), + content: + Text( + tr('onlyWorksWithNonEVDApps'), + style: const TextStyle(fontWeight: FontWeight.bold, fontStyle: FontStyle.italic), + ), + actions: [ + TextButton( + onPressed: () { + Navigator.of(context).pop(); + }, + child: Text(tr('no'))), + TextButton( + onPressed: () { + HapticFeedback.selectionClick(); + appsProvider.saveApps(selectedApps.map((a) { + if (a.installedVersion != null) { + a.installedVersion = a.latestVersion; + } + return a; + }).toList()); + + Navigator.of(context).pop(); + }, + child: Text(tr('yes'))) + ], + ); + }).whenComplete(() { + Navigator.of( + context) + .pop(); + }); + }, + tooltip: tr( + 'markSelectedAppsUpdated'), + icon: const Icon( + Icons.done)), + IconButton( + onPressed: () { + var pinStatus = selectedApps + .where((element) => + element + .pinned) + .isEmpty; + appsProvider + .saveApps( + selectedApps + .map( + (e) { + e.pinned = + pinStatus; + return e; + }).toList()); + Navigator.of( + context) + .pop(); + }, + tooltip: selectedApps + .where((element) => + element + .pinned) + .isEmpty + ? tr('pinToTop') + : tr( + 'unpinFromTop'), + icon: Icon(selectedApps + .where((element) => + element + .pinned) + .isEmpty + ? Icons + .bookmark_outline_rounded + : Icons + .bookmark_remove_outlined), + ), + IconButton( + onPressed: () { + String urls = ''; + for (var a + in selectedApps) { + urls += + '${a.url}\n'; + } + urls = + urls.substring( + 0, + urls.length - + 1); + Share.share(urls, + subject: tr( + 'selectedAppURLsFromObtainium')); + Navigator.of( + context) + .pop(); + }, + tooltip: tr( + 'shareSelectedAppURLs'), + icon: const Icon( + Icons.share), + ), + IconButton( + onPressed: () { + showDialog( + context: + context, + builder: + (BuildContext + ctx) { + return GeneratedFormModal( + title: tr( + 'resetInstallStatusForSelectedAppsQuestion'), + items: const [], + initValid: + true, + message: tr( + 'installStatusOfXWillBeResetExplanation', + args: [ + plural( + 'app', + selectedApps.length) + ]), + ); + }).then((values) { + if (values != + null) { + appsProvider.saveApps( + selectedApps + .map( + (e) { + e.installedVersion = + null; + return e; + }).toList()); + } + }).whenComplete(() { + Navigator.of( + context) + .pop(); + }); + }, + tooltip: tr( + 'resetInstallStatus'), + icon: const Icon(Icons + .restore_page_outlined), + ), + ]), + ), + ); + }); + }, + tooltip: tr('more'), + icon: const Icon(Icons.more_horiz), + ), + ], + ))), + const VerticalDivider(), + IconButton( + visualDensity: VisualDensity.compact, onPressed: () { - showDialog?>( - context: context, - builder: (BuildContext ctx) { - var vals = filter.toFormValuesMap(); - return GeneratedFormModal( - initValid: true, - title: tr('filterApps'), - items: [ - [ - GeneratedFormTextField('appName', - label: tr('appName'), - required: false, - defaultValue: vals['appName']), - GeneratedFormTextField('author', - label: tr('author'), - required: false, - defaultValue: vals['author']) - ], - [ - GeneratedFormSwitch('upToDateApps', - label: tr('upToDateApps'), - defaultValue: vals['upToDateApps']) - ], - [ - GeneratedFormSwitch('nonInstalledApps', - label: tr('nonInstalledApps'), - defaultValue: vals['nonInstalledApps']) - ] - ], - additionalWidgets: [ - const SizedBox( - height: 16, - ), - CategoryEditorSelector( - preselected: filter.categoryFilter, - onSelected: (categories) { - filter.categoryFilter = categories.toSet(); - }, - ) - ], - ); - }).then((values) { - if (values != null) { - setState(() { - filter.setFormValuesFromMap(values); - }); + setState(() { + if (currentFilterIsUpdatesOnly) { + filter = AppsFilter(); + } else { + filter = updatesOnlyFilter; } }); }, - icon: const Icon(Icons.filter_list_rounded)) - ], - ), - ], + tooltip: currentFilterIsUpdatesOnly + ? tr('removeOutdatedFilter') + : tr('showOutdatedOnly'), + icon: Icon( + currentFilterIsUpdatesOnly + ? Icons.update_disabled_rounded + : Icons.update_rounded, + color: Theme.of(context).colorScheme.primary, + ), + ), + TextButton.icon( + style: const ButtonStyle( + visualDensity: VisualDensity.compact), + label: Text( + filter.isIdenticalTo(neutralFilter, settingsProvider) + ? tr('filter') + : tr('filterActive'), + style: TextStyle( + fontWeight: filter.isIdenticalTo( + neutralFilter, settingsProvider) + ? FontWeight.normal + : FontWeight.bold), + ), + onPressed: () { + showDialog?>( + context: context, + builder: (BuildContext ctx) { + var vals = filter.toFormValuesMap(); + return GeneratedFormModal( + initValid: true, + title: tr('filterApps'), + items: [ + [ + GeneratedFormTextField('appName', + label: tr('appName'), + required: false, + defaultValue: vals['appName']), + GeneratedFormTextField('author', + label: tr('author'), + required: false, + defaultValue: vals['author']) + ], + [ + GeneratedFormSwitch('upToDateApps', + label: tr('upToDateApps'), + defaultValue: vals['upToDateApps']) + ], + [ + GeneratedFormSwitch('nonInstalledApps', + label: tr('nonInstalledApps'), + defaultValue: vals['nonInstalledApps']) + ] + ], + additionalWidgets: [ + const SizedBox( + height: 16, + ), + CategoryEditorSelector( + preselected: filter.categoryFilter, + onSelected: (categories) { + filter.categoryFilter = + categories.toSet(); + }, + ) + ], + ); + }).then((values) { + if (values != null) { + setState(() { + filter.setFormValuesFromMap(values); + }); + } + }); + }, + icon: const Icon(Icons.filter_list_rounded)) + ], + ), + ], ); } } diff --git a/lib/pages/settings.dart b/lib/pages/settings.dart index 9698f95..e43aca4 100644 --- a/lib/pages/settings.dart +++ b/lib/pages/settings.dart @@ -4,10 +4,8 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:obtainium/components/custom_app_bar.dart'; import 'package:obtainium/components/generated_form.dart'; -import 'package:obtainium/components/generated_form_modal.dart'; import 'package:obtainium/custom_errors.dart'; import 'package:obtainium/main.dart'; -import 'package:obtainium/providers/apps_provider.dart'; import 'package:obtainium/providers/logs_provider.dart'; import 'package:obtainium/providers/settings_provider.dart'; import 'package:obtainium/providers/source_provider.dart'; diff --git a/lib/providers/apps_provider.dart b/lib/providers/apps_provider.dart index 92be206..a8380c6 100644 --- a/lib/providers/apps_provider.dart +++ b/lib/providers/apps_provider.dart @@ -262,6 +262,7 @@ class AppsProvider with ChangeNotifier { List archs = (await DeviceInfoPlugin().androidInfo).supportedAbis; if (app.apkUrls.length > 1 && context != null) { + // ignore: use_build_context_synchronously apkUrl = await showDialog( context: context, builder: (BuildContext ctx) { @@ -281,6 +282,7 @@ class AppsProvider with ChangeNotifier { if (apkUrl != null && getHost(apkUrl) != getHost(app.url) && context != null) { + // ignore: use_build_context_synchronously if (await showDialog( context: context, builder: (BuildContext ctx) { diff --git a/lib/providers/source_provider.dart b/lib/providers/source_provider.dart index d03f36b..0599c4e 100644 --- a/lib/providers/source_provider.dart +++ b/lib/providers/source_provider.dart @@ -225,7 +225,19 @@ class AppSource { label: tr('trackOnly'), ) ], - [GeneratedFormSwitch('noVersionDetection', label: tr('noVersionDetection'))] + [ + GeneratedFormSwitch('noVersionDetection', label: tr('noVersionDetection')) + ], + [ + GeneratedFormTextField('apkFilterRegEx', + label: tr('filterAPKsByRegEx'), + required: false, + additionalValidators: [ + (value) { + return regExValidator(value); + } + ]) + ] ]; // Previous 2 variables combined into one at runtime for convenient usage @@ -269,6 +281,18 @@ abstract class MassAppUrlSource { Future> getUrlsWithDescriptions(List args); } +regExValidator(String? value) { + if (value == null || value.isEmpty) { + return null; + } + try { + RegExp(value); + } catch (e) { + return tr('invalidRegEx'); + } + return null; +} + class SourceProvider { // Add more source classes here so they are available via the service List sources = [ @@ -344,20 +368,32 @@ class SourceProvider { } Future getApp( - AppSource source, String url, Map additionalSettings, - {App? currentApp, - bool trackOnlyOverride = false, - noVersionDetectionOverride = false}) async { + AppSource source, + String url, + Map additionalSettings, { + App? currentApp, + bool trackOnlyOverride = false, + noVersionDetectionOverride = false, + // String? apkFilterOverride + }) async { if (trackOnlyOverride || source.enforceTrackOnly) { additionalSettings['trackOnly'] = true; } if (noVersionDetectionOverride) { additionalSettings['noVersionDetection'] = true; } + // if (apkFilterOverride != null) { + // additionalSettings['apkFilterRegEx'] = apkFilterOverride; + // } var trackOnly = additionalSettings['trackOnly'] == true; String standardUrl = source.standardizeURL(preStandardizeUrl(url)); APKDetails apk = await source.getLatestAPKDetails(standardUrl, additionalSettings); + if (additionalSettings['apkFilterRegEx'] != null) { + var reg = RegExp(additionalSettings['apkFilterRegEx']); + apk.apkUrls = + apk.apkUrls.where((element) => reg.hasMatch(element)).toList(); + } if (apk.apkUrls.isEmpty && !trackOnly) { throw NoAPKError(); } diff --git a/pubspec.lock b/pubspec.lock index 3b629d8..4bd6b84 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,182 +5,208 @@ packages: dependency: "direct main" description: name: android_alarm_manager_plus - url: "https://pub.dartlang.org" + sha256: "71e796198588e0038dd125bf8c91683b3237b938ffad037413245c689b87ae28" + url: "https://pub.dev" source: hosted version: "2.1.0" animations: dependency: "direct main" description: name: animations - url: "https://pub.dartlang.org" + sha256: fe8a6bdca435f718bb1dc8a11661b2c22504c6da40ef934cee8327ed77934164 + url: "https://pub.dev" source: hosted version: "2.0.7" archive: dependency: transitive description: name: archive - url: "https://pub.dartlang.org" + sha256: d6347d54a2d8028e0437e3c099f66fdb8ae02c4720c1e7534c9f24c10351f85d + url: "https://pub.dev" source: hosted - version: "3.3.5" + version: "3.3.6" args: dependency: transitive description: name: args - url: "https://pub.dartlang.org" + sha256: "139d809800a412ebb26a3892da228b2d0ba36f0ef5d9a82166e5e52ec8d61611" + url: "https://pub.dev" source: hosted version: "2.3.2" async: dependency: transitive description: name: async - url: "https://pub.dartlang.org" + sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 + url: "https://pub.dev" source: hosted - version: "2.9.0" + version: "2.10.0" boolean_selector: dependency: transitive description: name: boolean_selector - url: "https://pub.dartlang.org" + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" characters: dependency: transitive description: name: characters - url: "https://pub.dartlang.org" + sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c + url: "https://pub.dev" source: hosted version: "1.2.1" checked_yaml: dependency: transitive description: name: checked_yaml - url: "https://pub.dartlang.org" + sha256: "3d1505d91afa809d177efd4eed5bb0eb65805097a1463abdd2add076effae311" + url: "https://pub.dev" source: hosted version: "2.0.2" cli_util: dependency: transitive description: name: cli_util - url: "https://pub.dartlang.org" + sha256: "66f86e916d285c1a93d3b79587d94bd71984a66aac4ff74e524cfa7877f1395c" + url: "https://pub.dev" source: hosted version: "0.3.5" clock: dependency: transitive description: name: clock - url: "https://pub.dartlang.org" + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" source: hosted version: "1.1.1" collection: dependency: transitive description: name: collection - url: "https://pub.dartlang.org" + sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 + url: "https://pub.dev" source: hosted - version: "1.16.0" + version: "1.17.0" convert: dependency: transitive description: name: convert - url: "https://pub.dartlang.org" + sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + url: "https://pub.dev" source: hosted version: "3.1.1" cross_file: dependency: transitive description: name: cross_file - url: "https://pub.dartlang.org" + sha256: f71079978789bc2fe78d79227f1f8cfe195b31bbd8db2399b0d15a4b96fb843b + url: "https://pub.dev" source: hosted version: "0.3.3+2" crypto: dependency: transitive description: name: crypto - url: "https://pub.dartlang.org" + sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67 + url: "https://pub.dev" source: hosted version: "3.0.2" csslib: dependency: transitive description: name: csslib - url: "https://pub.dartlang.org" + sha256: b36c7f7e24c0bdf1bf9a3da461c837d1de64b9f8beb190c9011d8c72a3dfd745 + url: "https://pub.dev" source: hosted version: "0.17.2" cupertino_icons: dependency: "direct main" description: name: cupertino_icons - url: "https://pub.dartlang.org" + sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be + url: "https://pub.dev" source: hosted version: "1.0.5" dbus: dependency: transitive description: name: dbus - url: "https://pub.dartlang.org" + sha256: "6f07cba3f7b3448d42d015bfd3d53fe12e5b36da2423f23838efc1d5fb31a263" + url: "https://pub.dev" source: hosted version: "0.7.8" device_info_plus: dependency: "direct main" description: name: device_info_plus - url: "https://pub.dartlang.org" + sha256: "7ff671ed0a6356fa8f2e1ae7d3558d3fb7b6a41e24455e4f8df75b811fb8e4ab" + url: "https://pub.dev" source: hosted version: "8.0.0" device_info_plus_platform_interface: dependency: transitive description: name: device_info_plus_platform_interface - url: "https://pub.dartlang.org" + sha256: d3b01d5868b50ae571cd1dc6e502fc94d956b665756180f7b16ead09e836fd64 + url: "https://pub.dev" source: hosted version: "7.0.0" dynamic_color: dependency: "direct main" description: name: dynamic_color - url: "https://pub.dartlang.org" + sha256: "37a15576f5a0bfd5555b613cf20ea3bd379607cf88d457374a16032f4e942174" + url: "https://pub.dev" source: hosted version: "1.5.4" easy_localization: dependency: "direct main" description: name: easy_localization - url: "https://pub.dartlang.org" + sha256: "6a2e99fa0bfe5765bf4c6ca9b137d5de2c75593007178c5e4cd2ae985f870080" + url: "https://pub.dev" source: hosted version: "3.0.1" easy_logger: dependency: transitive description: name: easy_logger - url: "https://pub.dartlang.org" + sha256: c764a6e024846f33405a2342caf91c62e357c24b02c04dbc712ef232bf30ffb7 + url: "https://pub.dev" source: hosted version: "0.0.2" fake_async: dependency: transitive description: name: fake_async - url: "https://pub.dartlang.org" + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" source: hosted version: "1.3.1" ffi: dependency: transitive description: name: ffi - url: "https://pub.dartlang.org" + sha256: a38574032c5f1dd06c4aee541789906c12ccaab8ba01446e800d9c5b79c4a978 + url: "https://pub.dev" source: hosted version: "2.0.1" file: dependency: transitive description: name: file - url: "https://pub.dartlang.org" + sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" + url: "https://pub.dev" source: hosted version: "6.1.4" file_picker: dependency: "direct main" description: name: file_picker - url: "https://pub.dartlang.org" + sha256: d090ae03df98b0247b82e5928f44d1b959867049d18d73635e2e0bc3f49542b9 + url: "https://pub.dev" source: hosted version: "5.2.5" flutter: @@ -192,42 +218,48 @@ packages: dependency: "direct main" description: name: flutter_fgbg - url: "https://pub.dartlang.org" + sha256: d37511eef6afb7e2e3f2278ec6498bb12c650ed517c81bcd09452d910e8b9174 + url: "https://pub.dev" source: hosted version: "0.2.2" flutter_launcher_icons: dependency: "direct dev" description: name: flutter_launcher_icons - url: "https://pub.dartlang.org" + sha256: ce0e501cfc258907842238e4ca605e74b7fd1cdf04b3b43e86c43f3e40a1592c + url: "https://pub.dev" source: hosted version: "0.11.0" flutter_lints: dependency: "direct dev" description: name: flutter_lints - url: "https://pub.dartlang.org" + sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c + url: "https://pub.dev" source: hosted version: "2.0.1" flutter_local_notifications: dependency: "direct main" description: name: flutter_local_notifications - url: "https://pub.dartlang.org" + sha256: "293995f94e120c8afce768981bd1fa9c5d6de67c547568e3b42ae2defdcbb4a0" + url: "https://pub.dev" source: hosted version: "13.0.0" flutter_local_notifications_linux: dependency: transitive description: name: flutter_local_notifications_linux - url: "https://pub.dartlang.org" + sha256: "8f6c1611e0c4a88a382691a97bb3c3feb24cc0c0b54152b8b5fb7ffb837f7fbf" + url: "https://pub.dev" source: hosted version: "3.0.0" flutter_local_notifications_platform_interface: dependency: transitive description: name: flutter_local_notifications_platform_interface - url: "https://pub.dartlang.org" + sha256: "5ec1feac5f7f7d9266759488bc5f76416152baba9aa1b26fe572246caa00d1ab" + url: "https://pub.dev" source: hosted version: "6.0.0" flutter_localizations: @@ -239,7 +271,8 @@ packages: dependency: transitive description: name: flutter_plugin_android_lifecycle - url: "https://pub.dartlang.org" + sha256: "60fc7b78455b94e6de2333d2f95196d32cf5c22f4b0b0520a628804cb463503b" + url: "https://pub.dev" source: hosted version: "2.0.7" flutter_test: @@ -256,322 +289,360 @@ packages: dependency: "direct main" description: name: fluttertoast - url: "https://pub.dartlang.org" + sha256: "7cc92eabe01e3f1babe1571c5560b135dfc762a34e41e9056881e2196b178ec1" + url: "https://pub.dev" source: hosted version: "8.1.2" html: dependency: "direct main" description: name: html - url: "https://pub.dartlang.org" + sha256: d9793e10dbe0e6c364f4c59bf3e01fb33a9b2a674bc7a1081693dba0614b6269 + url: "https://pub.dev" source: hosted version: "0.15.1" http: dependency: "direct main" description: name: http - url: "https://pub.dartlang.org" + sha256: "6aa2946395183537c8b880962d935877325d6a09a2867c3970c05c0fed6ac482" + url: "https://pub.dev" source: hosted version: "0.13.5" http_parser: dependency: transitive description: name: http_parser - url: "https://pub.dartlang.org" + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" source: hosted version: "4.0.2" image: dependency: transitive description: name: image - url: "https://pub.dartlang.org" + sha256: "8e9d133755c3e84c73288363e6343157c383a0c6c56fc51afcc5d4d7180306d6" + url: "https://pub.dev" source: hosted version: "3.3.0" install_plugin_v2: dependency: "direct main" description: name: install_plugin_v2 - url: "https://pub.dartlang.org" + sha256: d6b014637e7a53839e9c5a254f9fd9bb8866392c6db1f16184ce17818cc2d979 + url: "https://pub.dev" source: hosted version: "1.0.0" installed_apps: dependency: "direct main" description: name: installed_apps - url: "https://pub.dartlang.org" + sha256: "145af8eb6e4e7c830e9888d6de0573ae5c139e8e0742a3e67316e1db21ab6fe0" + url: "https://pub.dev" source: hosted version: "1.3.1" intl: dependency: transitive description: name: intl - url: "https://pub.dartlang.org" + sha256: "910f85bce16fb5c6f614e117efa303e85a1731bb0081edf3604a2ae6e9a3cc91" + url: "https://pub.dev" source: hosted version: "0.17.0" js: dependency: transitive description: name: js - url: "https://pub.dartlang.org" + sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" + url: "https://pub.dev" source: hosted - version: "0.6.4" + version: "0.6.5" json_annotation: dependency: transitive description: name: json_annotation - url: "https://pub.dartlang.org" + sha256: c33da08e136c3df0190bd5bbe51ae1df4a7d96e7954d1d7249fea2968a72d317 + url: "https://pub.dev" source: hosted version: "4.8.0" lints: dependency: transitive description: name: lints - url: "https://pub.dartlang.org" + sha256: "5e4a9cd06d447758280a8ac2405101e0e2094d2a1dbdd3756aec3fe7775ba593" + url: "https://pub.dev" source: hosted version: "2.0.1" matcher: dependency: transitive description: name: matcher - url: "https://pub.dartlang.org" + sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72" + url: "https://pub.dev" source: hosted - version: "0.12.12" + version: "0.12.13" material_color_utilities: dependency: transitive description: name: material_color_utilities - url: "https://pub.dartlang.org" + sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + url: "https://pub.dev" source: hosted - version: "0.1.5" + version: "0.2.0" meta: dependency: transitive description: name: meta - url: "https://pub.dartlang.org" + sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" + url: "https://pub.dev" source: hosted version: "1.8.0" mime: dependency: transitive description: name: mime - url: "https://pub.dartlang.org" + sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e + url: "https://pub.dev" source: hosted version: "1.0.4" nested: dependency: transitive description: name: nested - url: "https://pub.dartlang.org" + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" source: hosted version: "1.0.0" package_archive_info: dependency: "direct main" description: name: package_archive_info - url: "https://pub.dartlang.org" + sha256: "8f671a29b79d15f192e5e2b0dab9d0bad66b9ee93fb58d4e0afdb62f91a259be" + url: "https://pub.dev" source: hosted version: "0.1.0" package_info: dependency: transitive description: name: package_info - url: "https://pub.dartlang.org" + sha256: "6c07d9d82c69e16afeeeeb6866fe43985a20b3b50df243091bfc4a4ad2b03b75" + url: "https://pub.dev" source: hosted version: "2.0.2" path: dependency: transitive description: name: path - url: "https://pub.dartlang.org" + sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b + url: "https://pub.dev" source: hosted version: "1.8.2" path_provider: dependency: "direct main" description: name: path_provider - url: "https://pub.dartlang.org" + sha256: dcea5feb97d8abf90cab9e9030b497fb7c3cbf26b7a1fe9e3ef7dcb0a1ddec95 + url: "https://pub.dev" source: hosted - version: "2.0.11" + version: "2.0.12" path_provider_android: dependency: transitive description: name: path_provider_android - url: "https://pub.dartlang.org" + sha256: a776c088d671b27f6e3aa8881d64b87b3e80201c64e8869b811325de7a76c15e + url: "https://pub.dev" source: hosted version: "2.0.22" - path_provider_ios: + path_provider_foundation: dependency: transitive description: - name: path_provider_ios - url: "https://pub.dartlang.org" + name: path_provider_foundation + sha256: "62a68e7e1c6c459f9289859e2fae58290c981ce21d1697faf54910fe1faa4c74" + url: "https://pub.dev" source: hosted - version: "2.0.11" + version: "2.1.1" path_provider_linux: dependency: transitive description: name: path_provider_linux - url: "https://pub.dartlang.org" + sha256: ab0987bf95bc591da42dffb38c77398fc43309f0b9b894dcc5d6f40c4b26c379 + url: "https://pub.dev" source: hosted version: "2.1.7" - path_provider_macos: - dependency: transitive - description: - name: path_provider_macos - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.7" path_provider_platform_interface: dependency: transitive description: name: path_provider_platform_interface - url: "https://pub.dartlang.org" + sha256: f0abc8ebd7253741f05488b4813d936b4d07c6bae3e86148a09e342ee4b08e76 + url: "https://pub.dev" source: hosted version: "2.0.5" path_provider_windows: dependency: transitive description: name: path_provider_windows - url: "https://pub.dartlang.org" + sha256: bcabbe399d4042b8ee687e17548d5d3f527255253b4a639f5f8d2094a9c2b45c + url: "https://pub.dev" source: hosted version: "2.1.3" permission_handler: dependency: "direct main" description: name: permission_handler - url: "https://pub.dartlang.org" + sha256: "33c6a1253d1f95fd06fa74b65b7ba907ae9811f9d5c1d3150e51417d04b8d6a8" + url: "https://pub.dev" source: hosted version: "10.2.0" permission_handler_android: dependency: transitive description: name: permission_handler_android - url: "https://pub.dartlang.org" + sha256: "8028362b40c4a45298f1cbfccd227c8dd6caf0e27088a69f2ba2ab15464159e2" + url: "https://pub.dev" source: hosted version: "10.2.0" permission_handler_apple: dependency: transitive description: name: permission_handler_apple - url: "https://pub.dartlang.org" + sha256: "9c370ef6a18b1c4b2f7f35944d644a56aa23576f23abee654cf73968de93f163" + url: "https://pub.dev" source: hosted version: "9.0.7" permission_handler_platform_interface: dependency: transitive description: name: permission_handler_platform_interface - url: "https://pub.dartlang.org" + sha256: "68abbc472002b5e6dfce47fe9898c6b7d8328d58b5d2524f75e277c07a97eb84" + url: "https://pub.dev" source: hosted version: "3.9.0" permission_handler_windows: dependency: transitive description: name: permission_handler_windows - url: "https://pub.dartlang.org" + sha256: f67cab14b4328574938ecea2db3475dad7af7ead6afab6338772c5f88963e38b + url: "https://pub.dev" source: hosted version: "0.1.2" petitparser: dependency: transitive description: name: petitparser - url: "https://pub.dartlang.org" + sha256: "49392a45ced973e8d94a85fdb21293fbb40ba805fc49f2965101ae748a3683b4" + url: "https://pub.dev" source: hosted version: "5.1.0" platform: dependency: transitive description: name: platform - url: "https://pub.dartlang.org" + sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76" + url: "https://pub.dev" source: hosted version: "3.1.0" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface - url: "https://pub.dartlang.org" + sha256: dbf0f707c78beedc9200146ad3cb0ab4d5da13c246336987be6940f026500d3a + url: "https://pub.dev" source: hosted version: "2.1.3" pointycastle: dependency: transitive description: name: pointycastle - url: "https://pub.dartlang.org" + sha256: db7306cf0249f838d1a24af52b5a5887c5bf7f31d8bb4e827d071dc0939ad346 + url: "https://pub.dev" source: hosted version: "3.6.2" process: dependency: transitive description: name: process - url: "https://pub.dartlang.org" + sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09" + url: "https://pub.dev" source: hosted version: "4.2.4" provider: dependency: "direct main" description: name: provider - url: "https://pub.dartlang.org" + sha256: cdbe7530b12ecd9eb455bdaa2fcb8d4dad22e80b8afb4798b41479d5ce26847f + url: "https://pub.dev" source: hosted version: "6.0.5" share_plus: dependency: "direct main" description: name: share_plus - url: "https://pub.dartlang.org" + sha256: e387077716f80609bb979cd199331033326033ecd1c8f200a90c5f57b1c9f55e + url: "https://pub.dev" source: hosted version: "6.3.0" share_plus_platform_interface: dependency: transitive description: name: share_plus_platform_interface - url: "https://pub.dartlang.org" + sha256: "82ddd4ab9260c295e6e39612d4ff00390b9a7a21f1bb1da771e2f232d80ab8a1" + url: "https://pub.dev" source: hosted version: "3.2.0" shared_preferences: dependency: "direct main" description: name: shared_preferences - url: "https://pub.dartlang.org" + sha256: "5949029e70abe87f75cfe59d17bf5c397619c4b74a099b10116baeb34786fad9" + url: "https://pub.dev" source: hosted version: "2.0.17" shared_preferences_android: dependency: transitive description: name: shared_preferences_android - url: "https://pub.dartlang.org" + sha256: "955e9736a12ba776bdd261cf030232b30eadfcd9c79b32a3250dd4a494e8c8f7" + url: "https://pub.dev" source: hosted version: "2.0.15" shared_preferences_foundation: dependency: transitive description: name: shared_preferences_foundation - url: "https://pub.dartlang.org" + sha256: "1ffa239043ab8baf881ec3094a3c767af9d10399b2839020b9e4d44c0bb23951" + url: "https://pub.dev" source: hosted version: "2.1.2" shared_preferences_linux: dependency: transitive description: name: shared_preferences_linux - url: "https://pub.dartlang.org" + sha256: f8ea038aa6da37090093974ebdcf4397010605fd2ff65c37a66f9d28394cb874 + url: "https://pub.dev" source: hosted version: "2.1.3" shared_preferences_platform_interface: dependency: transitive description: name: shared_preferences_platform_interface - url: "https://pub.dartlang.org" + sha256: da9431745ede5ece47bc26d5d73a9d3c6936ef6945c101a5aca46f62e52c1cf3 + url: "https://pub.dev" source: hosted version: "2.1.0" shared_preferences_web: dependency: transitive description: name: shared_preferences_web - url: "https://pub.dartlang.org" + sha256: a4b5bc37fe1b368bbc81f953197d55e12f49d0296e7e412dfe2d2d77d6929958 + url: "https://pub.dev" source: hosted version: "2.0.4" shared_preferences_windows: dependency: transitive description: name: shared_preferences_windows - url: "https://pub.dartlang.org" + sha256: "5eaf05ae77658d3521d0e993ede1af962d4b326cd2153d312df716dc250f00c9" + url: "https://pub.dev" source: hosted version: "2.1.3" sky_engine: @@ -583,205 +654,234 @@ packages: dependency: transitive description: name: source_span - url: "https://pub.dartlang.org" + sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + url: "https://pub.dev" source: hosted - version: "1.9.0" + version: "1.9.1" sqflite: dependency: "direct main" description: name: sqflite - url: "https://pub.dartlang.org" + sha256: "78324387dc81df14f78df06019175a86a2ee0437624166c382e145d0a7fd9a4f" + url: "https://pub.dev" source: hosted - version: "2.2.3" + version: "2.2.4+1" sqflite_common: dependency: transitive description: name: sqflite_common - url: "https://pub.dartlang.org" + sha256: bfd6973aaeeb93475bc0d875ac9aefddf7965ef22ce09790eb963992ffc5183f + url: "https://pub.dev" source: hosted - version: "2.4.1" + version: "2.4.2+2" stack_trace: dependency: transitive description: name: stack_trace - url: "https://pub.dartlang.org" + sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.11.0" stream_channel: dependency: transitive description: name: stream_channel - url: "https://pub.dartlang.org" + sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" string_scanner: dependency: transitive description: name: string_scanner - url: "https://pub.dartlang.org" + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.2.0" synchronized: dependency: transitive description: name: synchronized - url: "https://pub.dartlang.org" + sha256: "33b31b6beb98100bf9add464a36a8dd03eb10c7a8cf15aeec535e9b054aaf04b" + url: "https://pub.dev" source: hosted version: "3.0.1" term_glyph: dependency: transitive description: name: term_glyph - url: "https://pub.dartlang.org" + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" source: hosted version: "1.2.1" test_api: dependency: transitive description: name: test_api - url: "https://pub.dartlang.org" + sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206 + url: "https://pub.dev" source: hosted - version: "0.4.12" + version: "0.4.16" timezone: dependency: transitive description: name: timezone - url: "https://pub.dartlang.org" + sha256: "24c8fcdd49a805d95777a39064862133ff816ebfffe0ceff110fb5960e557964" + url: "https://pub.dev" source: hosted version: "0.9.1" typed_data: dependency: transitive description: name: typed_data - url: "https://pub.dartlang.org" + sha256: "26f87ade979c47a150c9eaab93ccd2bebe70a27dc0b4b29517f2904f04eb11a5" + url: "https://pub.dev" source: hosted version: "1.3.1" url_launcher: dependency: "direct main" description: name: url_launcher - url: "https://pub.dartlang.org" + sha256: "698fa0b4392effdc73e9e184403b627362eb5fbf904483ac9defbb1c2191d809" + url: "https://pub.dev" source: hosted version: "6.1.8" url_launcher_android: dependency: transitive description: name: url_launcher_android - url: "https://pub.dartlang.org" + sha256: "3e2f6dfd2c7d9cd123296cab8ef66cfc2c1a13f5845f42c7a0f365690a8a7dd1" + url: "https://pub.dev" source: hosted version: "6.0.23" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - url: "https://pub.dartlang.org" + sha256: bb328b24d3bccc20bdf1024a0990ac4f869d57663660de9c936fb8c043edefe3 + url: "https://pub.dev" source: hosted version: "6.0.18" url_launcher_linux: dependency: transitive description: name: url_launcher_linux - url: "https://pub.dartlang.org" + sha256: "318c42cba924e18180c029be69caf0a1a710191b9ec49bb42b5998fdcccee3cc" + url: "https://pub.dev" source: hosted version: "3.0.2" url_launcher_macos: dependency: transitive description: name: url_launcher_macos - url: "https://pub.dartlang.org" + sha256: "41988b55570df53b3dd2a7fc90c76756a963de6a8c5f8e113330cb35992e2094" + url: "https://pub.dev" source: hosted version: "3.0.2" url_launcher_platform_interface: dependency: transitive description: name: url_launcher_platform_interface - url: "https://pub.dartlang.org" + sha256: "4eae912628763eb48fc214522e58e942fd16ce195407dbf45638239523c759a6" + url: "https://pub.dev" source: hosted version: "2.1.1" url_launcher_web: dependency: transitive description: name: url_launcher_web - url: "https://pub.dartlang.org" + sha256: "44d79408ce9f07052095ef1f9a693c258d6373dc3944249374e30eff7219ccb0" + url: "https://pub.dev" source: hosted version: "2.0.14" url_launcher_windows: dependency: transitive description: name: url_launcher_windows - url: "https://pub.dartlang.org" + sha256: b6217370f8eb1fd85c8890c539f5a639a01ab209a36db82c921ebeacefc7a615 + url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.0.3" uuid: dependency: transitive description: name: uuid - url: "https://pub.dartlang.org" + sha256: "648e103079f7c64a36dc7d39369cabb358d377078a051d6ae2ad3aa539519313" + url: "https://pub.dev" source: hosted version: "3.0.7" vector_math: dependency: transitive description: name: vector_math - url: "https://pub.dartlang.org" + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.4" webview_flutter: dependency: "direct main" description: name: webview_flutter - url: "https://pub.dartlang.org" + sha256: f7ec234830f86d0ef2bd664e8460b0038b8c1a83ff076035cad74ac70273753c + url: "https://pub.dev" source: hosted version: "4.0.2" webview_flutter_android: dependency: transitive description: name: webview_flutter_android - url: "https://pub.dartlang.org" + sha256: "9d97fa2bae0f1900553c48a2ef0aaa3864367fd7bb625d683c460754b691312c" + url: "https://pub.dev" source: hosted version: "3.2.1" webview_flutter_platform_interface: dependency: transitive description: name: webview_flutter_platform_interface - url: "https://pub.dartlang.org" + sha256: "8b2262dda5d26eabc600a7282a8c16a9473a0c765526afb0ffc33eef912f7968" + url: "https://pub.dev" source: hosted version: "2.0.1" webview_flutter_wkwebview: dependency: transitive description: name: webview_flutter_wkwebview - url: "https://pub.dartlang.org" + sha256: "523aff9168af9bb2170e4809e0499d7dee065c3919799fd3341d3e616c137960" + url: "https://pub.dev" source: hosted version: "3.0.2" win32: dependency: transitive description: name: win32 - url: "https://pub.dartlang.org" + sha256: c9ebe7ee4ab0c2194e65d3a07d8c54c5d00bb001b76081c4a04cdb8448b59e46 + url: "https://pub.dev" source: hosted version: "3.1.3" xdg_directories: dependency: transitive description: name: xdg_directories - url: "https://pub.dartlang.org" + sha256: bd512f03919aac5f1313eb8249f223bacf4927031bf60b02601f81f687689e86 + url: "https://pub.dev" source: hosted version: "0.2.0+3" xml: dependency: transitive description: name: xml - url: "https://pub.dartlang.org" + sha256: "979ee37d622dec6365e2efa4d906c37470995871fe9ae080d967e192d88286b5" + url: "https://pub.dev" source: hosted - version: "6.1.0" + version: "6.2.2" yaml: dependency: transitive description: name: yaml - url: "https://pub.dartlang.org" + sha256: "23812a9b125b48d4007117254bca50abb6c712352927eece9e155207b1db2370" + url: "https://pub.dev" source: hosted version: "3.1.1" sdks: - dart: ">=2.18.2 <3.0.0" + dart: ">=2.18.2 <4.0.0" flutter: ">=3.3.0"