diff --git a/assets/translations/de.json b/assets/translations/de.json index be299b2..12f8410 100644 --- a/assets/translations/de.json +++ b/assets/translations/de.json @@ -213,10 +213,13 @@ "removeFromObtainium": "Aus Obtainium entfernen", "uninstallFromDevice": "Vom Gerät deinstallieren", "onlyWorksWithNonVersionDetectApps": "Funktioniert nur bei Apps mit deaktivierter Versionserkennung.", - "useReleaseDateAsVersion": "Veröffentlichungsdatum als Version\n verwenden", + "releaseDateAsVersion": "Veröffentlichungsdatum als Version verwenden", "releaseDateAsVersionExplanation": "Diese Option sollte nur für Apps verwendet werden, bei denen die Versionserkennung nicht korrekt funktioniert, aber ein Veröffentlichungsdatum verfügbar ist.", "changes": "Änderungen", "releaseDate": "Veröffentlichungsdatum", + "importFromURLsInFile": "Import from URLs in File (like OPML)", + "versionDetection": "Version Detection", + "standardVersionDetection": "Standard version detection", "removeAppQuestion": { "one": "App entfernen?", "other": "App entfernen?" diff --git a/assets/translations/en.json b/assets/translations/en.json index c6c91bd..a48c185 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -213,10 +213,13 @@ "removeFromObtainium": "Remove from Obtainium", "uninstallFromDevice": "Uninstall from Device", "onlyWorksWithNonVersionDetectApps": "Only works for Apps with version detection disabled.", - "useReleaseDateAsVersion": "Use Release Date as Version", + "releaseDateAsVersion": "Use Release Date as Version", "releaseDateAsVersionExplanation": "This option should only be used for Apps where version detection does not work correctly, but a release date is available.", "changes": "Changes", "releaseDate": "Release Date", + "importFromURLsInFile": "Import from URLs in File (like OPML)", + "versionDetection": "Version Detection", + "standardVersionDetection": "Standard version detection", "removeAppQuestion": { "one": "Remove App?", "other": "Remove Apps?" diff --git a/assets/translations/fa.json b/assets/translations/fa.json index 999162b..1371e88 100644 --- a/assets/translations/fa.json +++ b/assets/translations/fa.json @@ -213,10 +213,13 @@ "removeFromObtainium": "از Obtainium حذف کنید", "uninstallFromDevice": "حذف نصب از دستگاه", "onlyWorksWithNonVersionDetectApps": "فقط برای برنامه‌هایی کار می‌کند که تشخیص نسخه غیرفعال است.", - "useReleaseDateAsVersion": "Use Release Date as Version", + "releaseDateAsVersion": "Use Release Date as Version", "releaseDateAsVersionExplanation": "This option should only be used for Apps where version detection does not work correctly, but a release date is available.", "changes": "Changes", "releaseDate": "Release Date", + "importFromURLsInFile": "Import from URLs in File (like OPML)", + "versionDetection": "Version Detection", + "standardVersionDetection": "Standard version detection", "removeAppQuestion": { "one": "برنامه حذف شود؟", "other": "برنامه ها حذف شوند؟" diff --git a/assets/translations/hu.json b/assets/translations/hu.json index c5745bf..6427f71 100644 --- a/assets/translations/hu.json +++ b/assets/translations/hu.json @@ -212,10 +212,13 @@ "removeFromObtainium": "Eltávolítás az Obtainiumból", "uninstallFromDevice": "Eltávolítás a készülékről", "onlyWorksWithNonVersionDetectApps": "Csak azoknál az alkalmazásoknál működik, amelyeknél a verzióérzékelés le van tiltva.", - "useReleaseDateAsVersion": "Használja a Kiadás dátumát, mint verziót", + "releaseDateAsVersion": "Használja a Kiadás dátumát, mint verziót", "releaseDateAsVersionExplanation": "Ezt a beállítást csak olyan alkalmazásoknál szabad használni, ahol a verzió érzékelése nem működik megfelelően, de elérhető a kiadás dátuma.", "changes": "Változtatások", "releaseDate": "Kiadás dátuma", + "importFromURLsInFile": "Import from URLs in File (like OPML)", + "versionDetection": "Version Detection", + "standardVersionDetection": "Standard version detection", "removeAppQuestion": { "one": "Eltávolítja az alkalmazást?", "other": "Eltávolítja az alkalmazást?" diff --git a/assets/translations/it.json b/assets/translations/it.json index 7cc3307..120096e 100644 --- a/assets/translations/it.json +++ b/assets/translations/it.json @@ -213,10 +213,13 @@ "removeFromObtainium": "Rimuovi da Obtainium", "uninstallFromDevice": "Disinstalla dal dispositivo", "onlyWorksWithNonVersionDetectApps": "Funziona solo per le App con il rilevamento della versione disattivato.", - "useReleaseDateAsVersion": "Usa data di rilascio come versione", + "releaseDateAsVersion": "Usa data di rilascio come versione", "releaseDateAsVersionExplanation": "Questa opzione dovrebbe essere usata solo per le App in cui il rilevamento della versione non funziona correttamente, ma è disponibile una data di rilascio.", "changes": "Novità", "releaseDate": "Data di rilascio", + "importFromURLsInFile": "Import from URLs in File (like OPML)", + "versionDetection": "Version Detection", + "standardVersionDetection": "Standard version detection", "removeAppQuestion": { "one": "Rimuovere l'App?", "other": "Rimuovere le App?" diff --git a/assets/translations/ja.json b/assets/translations/ja.json index 3eb133d..276abc1 100644 --- a/assets/translations/ja.json +++ b/assets/translations/ja.json @@ -213,10 +213,13 @@ "removeFromObtainium": "Obtainiumから削除する", "uninstallFromDevice": "デバイスからアンインストールする", "onlyWorksWithNonVersionDetectApps": "バージョン検出を無効にしているアプリにのみ動作します。", - "useReleaseDateAsVersion": "リリース日をバージョンとして使用する", + "releaseDateAsVersion": "リリース日をバージョンとして使用する", "releaseDateAsVersionExplanation": "このオプションは、バージョン検出が正しく機能しないアプリで、リリース日が利用可能な場合にのみ使用する必要があります。", "changes": "変更点", "releaseDate": "リリース日", + "importFromURLsInFile": "Import from URLs in File (like OPML)", + "versionDetection": "Version Detection", + "standardVersionDetection": "Standard version detection", "removeAppQuestion": { "one": "アプリを削除しますか?", "other": "アプリを削除しますか?" diff --git a/assets/translations/zh.json b/assets/translations/zh.json index 001a3ef..4f892ae 100644 --- a/assets/translations/zh.json +++ b/assets/translations/zh.json @@ -213,10 +213,13 @@ "filterAPKsByRegEx": "Filter APKs by Regular Expression", "removeFromObtainium": "Remove from Obtainium", "uninstallFromDevice": "Uninstall from Device", - "useReleaseDateAsVersion": "Use Release Date as Version", + "releaseDateAsVersion": "Use Release Date as Version", "releaseDateAsVersionExplanation": "This option should only be used for Apps where version detection does not work correctly, but a release date is available.", "changes": "Changes", "releaseDate": "Release Date", + "importFromURLsInFile": "Import from URLs in File (like OPML)", + "versionDetection": "Version Detection", + "standardVersionDetection": "Standard version detection", "removeAppQuestion": { "one": "删除应用?", "other": "删除应用?" diff --git a/lib/main.dart b/lib/main.dart index 8d398da..9a265f9 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -21,7 +21,7 @@ import 'package:easy_localization/src/easy_localization_controller.dart'; // ignore: implementation_imports import 'package:easy_localization/src/localization.dart'; -const String currentVersion = '0.11.2'; +const String currentVersion = '0.11.3'; const String currentReleaseTag = 'v$currentVersion-beta'; // KEEP THIS IN SYNC WITH GITHUB RELEASES diff --git a/lib/pages/add_app.dart b/lib/pages/add_app.dart index 0208c9e..f68ae3c 100644 --- a/lib/pages/add_app.dart +++ b/lib/pages/add_app.dart @@ -71,10 +71,6 @@ class _AddAppPageState extends State { var settingsProvider = context.read(); () async { var userPickedTrackOnly = additionalSettings['trackOnly'] == true; - var userPickedNoVersionDetection = - additionalSettings['noVersionDetection'] == true; - var userPickedReleaseDateAsVersion = - additionalSettings['releaseDateAsVersion'] == true; var cont = true; if ((userPickedTrackOnly || pickedSource!.enforceTrackOnly) && // ignore: use_build_context_synchronously @@ -95,13 +91,13 @@ class _AddAppPageState extends State { null) { cont = false; } - if (userPickedReleaseDateAsVersion && // ignore: use_build_context_synchronously + if (additionalSettings['versionDetection'] == 'releaseDateAsVersion' && // ignore: use_build_context_synchronously await showDialog( context: context, builder: (BuildContext ctx) { return GeneratedFormModal( - title: tr('useReleaseDateAsVersion'), + title: tr('releaseDateAsVersion'), items: const [], message: tr('releaseDateAsVersionExplanation'), ); @@ -109,8 +105,7 @@ class _AddAppPageState extends State { null) { cont = false; } - if (!userPickedReleaseDateAsVersion && - userPickedNoVersionDetection && + if (additionalSettings['versionDetection'] == 'noVersionDetection' && // ignore: use_build_context_synchronously await showDialog( context: context, @@ -129,9 +124,7 @@ class _AddAppPageState extends State { var trackOnly = pickedSource!.enforceTrackOnly || userPickedTrackOnly; App app = await sourceProvider.getApp( pickedSource!, userInput, additionalSettings, - trackOnlyOverride: trackOnly, - noVersionDetectionOverride: userPickedNoVersionDetection, - releaseDateAsVersionOverride: userPickedReleaseDateAsVersion); + trackOnlyOverride: trackOnly); if (!trackOnly) { await settingsProvider.getInstallPermission(); } diff --git a/lib/pages/app.dart b/lib/pages/app.dart index 0cf9405..4a73b72 100644 --- a/lib/pages/app.dart +++ b/lib/pages/app.dart @@ -42,8 +42,6 @@ class _AppPageState extends State { getUpdate(app.app.id); } var trackOnly = app?.app.additionalSettings['trackOnly'] == true; - var noVersionDetection = - app?.app.additionalSettings['noVersionDetection'] == true; var infoColumn = Column( mainAxisAlignment: MainAxisAlignment.center, @@ -207,7 +205,8 @@ class _AppPageState extends State { child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ - if (noVersionDetection && + if (app?.app.additionalSettings['versionDetection'] != + 'standardVersionDetection' && !trackOnly && app?.app.installedVersion != null && app?.app.installedVersion != app?.app.latestVersion) @@ -295,13 +294,11 @@ class _AppPageState extends State { context); } if (app.app.additionalSettings[ - 'releaseDateAsVersion'] == - true) { - app.app.additionalSettings[ - 'noVersionDetection'] = true; + 'versionDetection'] == + 'releaseDateAsVersion') { if (originalSettings[ - 'releaseDateAsVersion'] != - true) { + 'versionDetection'] != + 'releaseDateAsVersion') { if (app.app.releaseDate != null) { bool isUpdated = app.app.installedVersion == @@ -318,10 +315,8 @@ class _AppPageState extends State { } } } else if (originalSettings[ - 'releaseDateAsVersion'] == - true) { - app.app.additionalSettings[ - 'noVersionDetection'] = false; + 'versionDetection'] == + 'releaseDateAsVersion') { app.app.installedVersion = app .installedInfo ?.versionName ?? diff --git a/lib/pages/apps.dart b/lib/pages/apps.dart index e733439..8d4f51d 100644 --- a/lib/pages/apps.dart +++ b/lib/pages/apps.dart @@ -704,7 +704,7 @@ class AppsPageState extends State { onPressed: () { HapticFeedback.selectionClick(); appsProvider.saveApps(selectedApps.map((a) { - if (a.installedVersion != null && a.additionalSettings['noVersionDetection'] == true) { + if (a.installedVersion != null && a.additionalSettings['versionDetection'] != 'standardVersionDetection') { a.installedVersion = a.latestVersion; } return a; diff --git a/lib/pages/import_export.dart b/lib/pages/import_export.dart index df29739..71ec42c 100644 --- a/lib/pages/import_export.dart +++ b/lib/pages/import_export.dart @@ -41,6 +41,66 @@ class _ImportExportPageState extends State { ), ); + urlListImport({String? initValue, bool overrideInitValid = false}) { + showDialog?>( + context: context, + builder: (BuildContext ctx) { + return GeneratedFormModal( + initValid: overrideInitValid, + title: tr('importFromURLList'), + items: [ + [ + GeneratedFormTextField('appURLList', + defaultValue: initValue ?? '', + label: tr('appURLList'), + max: 7, + additionalValidators: [ + (dynamic value) { + if (value != null && value.isNotEmpty) { + var lines = value.trim().split('\n'); + for (int i = 0; i < lines.length; i++) { + try { + sourceProvider.getSource(lines[i]); + } catch (e) { + return '${tr('line')} ${i + 1}: $e'; + } + } + } + return null; + } + ]) + ] + ], + ); + }).then((values) { + if (values != null) { + var urls = (values['appURLList'] as String).split('\n'); + setState(() { + importInProgress = true; + }); + appsProvider.addAppsByURL(urls).then((errors) { + if (errors.isEmpty) { + showError(tr('importedX', args: [plural('apps', urls.length)]), + context); + } else { + showDialog( + context: context, + builder: (BuildContext ctx) { + return ImportErrorDialog( + urlsLength: urls.length, errors: errors); + }); + } + }).catchError((e) { + showError(e, context); + }).whenComplete(() { + setState(() { + importInProgress = false; + }); + }); + } + }); + } + return Scaffold( backgroundColor: Theme.of(context).colorScheme.surface, body: CustomScrollView(slivers: [ @@ -150,88 +210,60 @@ class _ImportExportPageState extends State { ], ) else - const Divider( - height: 32, - ), - TextButton( - onPressed: importInProgress - ? null - : () { - showDialog?>( - context: context, - builder: (BuildContext ctx) { - return GeneratedFormModal( - title: tr('importFromURLList'), - items: [ - [ - GeneratedFormTextField( - 'appURLList', - label: tr('appURLList'), - max: 7, - additionalValidators: [ - (dynamic value) { - if (value != null && - value.isNotEmpty) { - var lines = value - .trim() - .split('\n'); - for (int i = 0; - i < lines.length; - i++) { - try { - sourceProvider - .getSource( - lines[i]); - } catch (e) { - return '${tr('line')} ${i + 1}: $e'; - } - } - } - return null; - } - ]) - ] - ], - ); - }).then((values) { - if (values != null) { - var urls = - (values['appURLList'] as String) - .split('\n'); - setState(() { - importInProgress = true; - }); - appsProvider - .addAppsByURL(urls) - .then((errors) { - if (errors.isEmpty) { - showError( - tr('importedX', args: [ - plural('apps', urls.length) - ]), - context); - } else { - showDialog( - context: context, - builder: (BuildContext ctx) { - return ImportErrorDialog( - urlsLength: urls.length, - errors: errors); - }); - } - }).catchError((e) { - showError(e, context); - }).whenComplete(() { - setState(() { - importInProgress = false; + Column( + children: [ + const Divider( + height: 32, + ), + TextButton( + onPressed: importInProgress + ? null + : () { + urlListImport(); + }, + child: Text( + tr('importFromURLList'), + )), + const SizedBox(height: 8), + TextButton( + onPressed: importInProgress + ? null + : () { + FilePicker.platform + .pickFiles() + .then((result) { + if (result != null) { + urlListImport( + overrideInitValid: true, + initValue: + RegExp('https?://[^"]+') + .allMatches(File(result + .files + .single + .path!) + .readAsStringSync()) + .map((e) => + e.input.substring( + e.start, e.end)) + .toSet() + .toList() + .where((url) { + try { + sourceProvider + .getSource(url); + return true; + } catch (e) { + return false; + } + }).join('\n')); + } }); - }); - } - }); - }, - child: Text( - tr('importFromURLList'), - )), + }, + child: Text( + tr('importFromURLsInFile'), + )), + ], + ), ...sourceProvider.sources .where((element) => element.canSearch) .map((source) => Column( @@ -280,6 +312,7 @@ class _ImportExportPageState extends State { if (urlsWithDescriptions .isNotEmpty) { var selectedUrls = + // ignore: use_build_context_synchronously await showDialog< List< String>?>( @@ -314,6 +347,7 @@ class _ImportExportPageState extends State { ]), context); } else { + // ignore: use_build_context_synchronously showDialog( context: context, builder: @@ -391,6 +425,7 @@ class _ImportExportPageState extends State { e.toString()) .toList()); var selectedUrls = + // ignore: use_build_context_synchronously await showDialog< List?>( context: context, @@ -418,6 +453,7 @@ class _ImportExportPageState extends State { ]), context); } else { + // ignore: use_build_context_synchronously showDialog( context: context, builder: diff --git a/lib/pages/settings.dart b/lib/pages/settings.dart index e2ba218..3caf161 100644 --- a/lib/pages/settings.dart +++ b/lib/pages/settings.dart @@ -87,6 +87,7 @@ class _SettingsPageState extends State { }); var sortDropdown = DropdownButtonFormField( + isExpanded: true, decoration: InputDecoration(labelText: tr('appSortBy')), value: settingsProvider.sortColumn, items: [ @@ -114,6 +115,7 @@ class _SettingsPageState extends State { }); var orderDropdown = DropdownButtonFormField( + isExpanded: true, decoration: InputDecoration(labelText: tr('appSortOrder')), value: settingsProvider.sortOrder, items: [ diff --git a/lib/providers/apps_provider.dart b/lib/providers/apps_provider.dart index f24cc98..b436358 100644 --- a/lib/providers/apps_provider.dart +++ b/lib/providers/apps_provider.dart @@ -467,8 +467,8 @@ class AppsProvider with ChangeNotifier { App? getCorrectedInstallStatusAppIfPossible(App app, AppInfo? installedInfo) { var modded = false; var trackOnly = app.additionalSettings['trackOnly'] == true; - var noVersionDetection = - app.additionalSettings['noVersionDetection'] == true; + var noVersionDetection = app.additionalSettings['versionDetection'] != + 'standardVersionDetection'; if (installedInfo == null && app.installedVersion != null && !trackOnly) { app.installedVersion = null; modded = true; diff --git a/lib/providers/source_provider.dart b/lib/providers/source_provider.dart index 2076600..8cead1e 100644 --- a/lib/providers/source_provider.dart +++ b/lib/providers/source_provider.dart @@ -100,6 +100,20 @@ class App { additionalSettings['noVersionDetection'] = json['noVersionDetection'] == 'true' || json['trackOnly'] == true; } + // Convert bool style version detection options to dropdown style + if (additionalSettings['noVersionDetection'] == true) { + additionalSettings['versionDetection'] = 'noVersionDetection'; + } + if (additionalSettings['releaseDateAsVersion'] == true) { + additionalSettings['versionDetection'] = 'releaseDateAsVersion'; + additionalSettings.remove('releaseDateAsVersion'); + } + if (additionalSettings['noVersionDetection'] != null) { + additionalSettings.remove('noVersionDetection'); + } + if (additionalSettings['releaseDateAsVersion'] != null) { + additionalSettings.remove('releaseDateAsVersion'); + } // Ensure additionalSettings are correctly typed for (var item in formItems) { if (additionalSettings[item.key] != null) { @@ -234,11 +248,16 @@ class AppSource { ) ], [ - GeneratedFormSwitch('releaseDateAsVersion', - label: tr('useReleaseDateAsVersion')) - ], - [ - GeneratedFormSwitch('noVersionDetection', label: tr('noVersionDetection')) + GeneratedFormDropdown( + 'versionDetection', + [ + MapEntry( + 'standardVersionDetection', tr('standardVersionDetection')), + MapEntry('releaseDateAsVersion', tr('releaseDateAsVersion')), + MapEntry('noVersionDetection', tr('noVersionDetection')) + ], + label: tr('versionDetection'), + defaultValue: 'standardVersionDetection') ], [ GeneratedFormTextField('apkFilterRegEx', @@ -373,26 +392,15 @@ class SourceProvider { Future getApp( AppSource source, String url, Map additionalSettings, - {App? currentApp, - bool trackOnlyOverride = false, - bool noVersionDetectionOverride = false, - bool releaseDateAsVersionOverride = false}) async { + {App? currentApp, bool trackOnlyOverride = false}) async { if (trackOnlyOverride || source.enforceTrackOnly) { additionalSettings['trackOnly'] = true; } - if (releaseDateAsVersionOverride) { - additionalSettings['releaseDateAsVersion'] = true; - noVersionDetectionOverride = - true; // Rel. date as version means no ver. det. - } - if (noVersionDetectionOverride) { - additionalSettings['noVersionDetection'] = true; - } var trackOnly = additionalSettings['trackOnly'] == true; String standardUrl = source.standardizeURL(preStandardizeUrl(url)); APKDetails apk = await source.getLatestAPKDetails(standardUrl, additionalSettings); - if (additionalSettings['releaseDateAsVersion'] == true && + if (additionalSettings['versionDetection'] == 'releaseDateAsVersion' && apk.releaseDate != null) { apk.version = apk.releaseDate!.microsecondsSinceEpoch.toString(); } diff --git a/pubspec.lock b/pubspec.lock index 863f011..64df9f3 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -234,10 +234,10 @@ packages: dependency: "direct dev" description: name: flutter_launcher_icons - sha256: ce0e501cfc258907842238e4ca605e74b7fd1cdf04b3b43e86c43f3e40a1592c + sha256: "02dcaf49d405f652b7160e882bacfc02cb497041bb2eab2a49b1c393cf9aac12" url: "https://pub.dev" source: hosted - version: "0.11.0" + version: "0.12.0" flutter_lints: dependency: "direct dev" description: @@ -329,10 +329,10 @@ packages: dependency: transitive description: name: image - sha256: "8e9d133755c3e84c73288363e6343157c383a0c6c56fc51afcc5d4d7180306d6" + sha256: "483a389d6ccb292b570c31b3a193779b1b0178e7eb571986d9a49904b6861227" url: "https://pub.dev" source: hosted - version: "3.3.0" + version: "4.0.15" install_plugin_v2: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 946f921..7848390 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -17,7 +17,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. -version: 0.11.2+121 # When changing this, update the tag in main() accordingly +version: 0.11.3+122 # When changing this, update the tag in main() accordingly environment: sdk: '>=2.18.2 <3.0.0' @@ -64,7 +64,7 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - flutter_launcher_icons: ^0.11.0 + flutter_launcher_icons: ^0.12.0 # The "flutter_lints" package below contains a set of recommended lints to # encourage good coding practices. The lint set provided by the package is