From 69904265c99c061e00ea6d61f6fba8aa37c77a81 Mon Sep 17 00:00:00 2001 From: Imran Remtulla Date: Fri, 1 Aug 2025 11:56:53 -0400 Subject: [PATCH 01/10] Don't init the foreground service unless it is needed (#2437) --- lib/main.dart | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index eaec345..dc96456 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -185,7 +185,6 @@ class _ObtainiumState extends State { initPlatformState(); WidgetsBinding.instance.addPostFrameCallback((_) { requestNonOptionalPermissions(); - initForegroundService(); }); } @@ -201,28 +200,32 @@ class _ObtainiumState extends State { } void initForegroundService() { - FlutterForegroundTask.init( - androidNotificationOptions: AndroidNotificationOptions( - channelId: 'bg_update', - channelName: tr('foregroundService'), - channelDescription: tr('foregroundService'), - onlyAlertOnce: true, - ), - iosNotificationOptions: const IOSNotificationOptions( - showNotification: false, - playSound: false, - ), - foregroundTaskOptions: ForegroundTaskOptions( - eventAction: ForegroundTaskEventAction.repeat(900000), - autoRunOnBoot: true, - autoRunOnMyPackageReplaced: true, - allowWakeLock: true, - allowWifiLock: true, - ), - ); + // ignore: invalid_use_of_visible_for_testing_member + if (!FlutterForegroundTask.isInitialized) { + FlutterForegroundTask.init( + androidNotificationOptions: AndroidNotificationOptions( + channelId: 'bg_update', + channelName: tr('foregroundService'), + channelDescription: tr('foregroundService'), + onlyAlertOnce: true, + ), + iosNotificationOptions: const IOSNotificationOptions( + showNotification: false, + playSound: false, + ), + foregroundTaskOptions: ForegroundTaskOptions( + eventAction: ForegroundTaskEventAction.repeat(900000), + autoRunOnBoot: true, + autoRunOnMyPackageReplaced: true, + allowWakeLock: true, + allowWifiLock: true, + ), + ); + } } Future startForegroundService(bool restart) async { + initForegroundService(); if (await FlutterForegroundTask.isRunningService) { if (restart) { return FlutterForegroundTask.restartService(); From 6495987248dac30edcd7dbfd29b59f6bc48cbceb Mon Sep 17 00:00:00 2001 From: Imran Remtulla Date: Fri, 1 Aug 2025 11:57:50 -0400 Subject: [PATCH 02/10] Restore Oxford comma but only for English (#2245) --- assets/translations/bs.json | 2 +- assets/translations/en-EO.json | 2 +- assets/translations/en.json | 2 +- assets/translations/fa.json | 2 +- lib/custom_errors.dart | 3 ++- 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/assets/translations/bs.json b/assets/translations/bs.json index 726756e..846b3d3 100644 --- a/assets/translations/bs.json +++ b/assets/translations/bs.json @@ -327,7 +327,7 @@ "smartname": "Name (Smart)", "sortMethod": "Sort Method", "welcome": "Welcome", - "documentationLinksNote": "The Obtainium GitHub page linked below contains links to videos, articles, discussions and other resources that will help you understand how to use the app.", + "documentationLinksNote": "The Obtainium GitHub page linked below contains links to videos, articles, discussions, and other resources that will help you understand how to use the app.", "batteryOptimizationNote": "Note that background downloads may work more reliably if you disable OS battery optimizations for Obtainium.", "fileDeletionError": "Failed to delete file (try deleting it manually then try again): \"{}\"", "foregroundService": "Obtainium foreground service", diff --git a/assets/translations/en-EO.json b/assets/translations/en-EO.json index 3244535..a3ba189 100644 --- a/assets/translations/en-EO.json +++ b/assets/translations/en-EO.json @@ -327,7 +327,7 @@ "smartname": "Name (Smart)", "sortMethod": "Sort Method", "welcome": "Welcome", - "documentationLinksNote": "The Obtainium GitHub page linked below contains links to videos, articles, discussions and other resources that will help you understand how to use the app.", + "documentationLinksNote": "The Obtainium GitHub page linked below contains links to videos, articles, discussions, and other resources that will help you understand how to use the app.", "batteryOptimizationNote": "Note that background downloads may work more reliably if you disable OS battery optimizations for Obtainium.", "fileDeletionError": "Failed to delete file (try deleting it manually then try again): \"{}\"", "foregroundService": "Obtainium foreground service", diff --git a/assets/translations/en.json b/assets/translations/en.json index ba76647..bacf774 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -327,7 +327,7 @@ "smartname": "Name (smart)", "sortMethod": "Sort method", "welcome": "Welcome", - "documentationLinksNote": "The Obtainium GitHub page linked below contains links to videos, articles, discussions and other resources that will help you understand how to use the app.", + "documentationLinksNote": "The Obtainium GitHub page linked below contains links to videos, articles, discussions, and other resources that will help you understand how to use the app.", "batteryOptimizationNote": "Note that background downloads may work more reliably if you switch to the \"foreground service\" in the Obtainium settings and/or disable battery optimization for Obtainium in your OS settings.", "fileDeletionError": "Failed to delete file (try deleting it manually then try again): \"{}\"", "foregroundService": "Obtainium foreground service", diff --git a/assets/translations/fa.json b/assets/translations/fa.json index c7670cb..10de606 100644 --- a/assets/translations/fa.json +++ b/assets/translations/fa.json @@ -327,7 +327,7 @@ "smartname": "Name (Smart)", "sortMethod": "Sort Method", "welcome": "Welcome", - "documentationLinksNote": "The Obtainium GitHub page linked below contains links to videos, articles, discussions and other resources that will help you understand how to use the app.", + "documentationLinksNote": "The Obtainium GitHub page linked below contains links to videos, articles, discussions, and other resources that will help you understand how to use the app.", "batteryOptimizationNote": "Note that background downloads may work more reliably if you disable OS battery optimizations for Obtainium.", "fileDeletionError": "Failed to delete file (try deleting it manually then try again): \"{}\"", "foregroundService": "Obtainium foreground service", diff --git a/lib/custom_errors.dart b/lib/custom_errors.dart index cbb811d..4f06df5 100644 --- a/lib/custom_errors.dart +++ b/lib/custom_errors.dart @@ -158,6 +158,7 @@ void showError(dynamic e, BuildContext context) { } String list2FriendlyString(List list) { + var isEnglish = tr('and') == 'and'; // Quick hack, find better way; return list.length == 2 ? '${list[0]} ${tr('and')} ${list[1]}' : list @@ -169,7 +170,7 @@ String list2FriendlyString(List list) { (e.key == list.length - 1 ? '' : e.key == list.length - 2 - ? ' and ' + ? '${isEnglish ? ',' : ''} and ' : ', '), ) .join(''); From 93380f4229247c17e00355e8fd398f5fd587db17 Mon Sep 17 00:00:00 2001 From: Imran Remtulla Date: Fri, 1 Aug 2025 12:09:03 -0400 Subject: [PATCH 03/10] Minor bug in F-Droid variant (#2373) --- lib/providers/apps_provider.dart | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/providers/apps_provider.dart b/lib/providers/apps_provider.dart index 5a967cc..933a920 100644 --- a/lib/providers/apps_provider.dart +++ b/lib/providers/apps_provider.dart @@ -1121,6 +1121,7 @@ class AppsProvider with ChangeNotifier { obtainiumId, strB: obtainiumTempId, ); + appsToInstall = moveStrToEnd(appsToInstall, '$obtainiumId.fdroid'); Future installFn( String id, @@ -2511,7 +2512,10 @@ Future bgUpdateCheck(String taskId, Map? params) async { } } if (toInstall.isNotEmpty) { - var tempObtArr = toInstall.where((element) => element.key == obtainiumId); + var tempObtArr = toInstall.where( + (element) => + element.key == obtainiumId || element.key == '$obtainiumId.fdroid', + ); if (tempObtArr.isNotEmpty) { // Move obtainium to the end of the list as it must always install last var obt = tempObtArr.first; From f71e97f6e293b1af05adf551909266fe326633d5 Mon Sep 17 00:00:00 2001 From: Imran Remtulla Date: Fri, 1 Aug 2025 14:06:00 -0400 Subject: [PATCH 04/10] Minor wording changes (#2402, #2406) --- assets/translations/en.json | 4 ++-- assets/translations/nl.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/assets/translations/en.json b/assets/translations/en.json index bacf774..ea77e47 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -25,7 +25,7 @@ "standard": "Standard", "custom": "Custom", "useMaterialYou": "Use Material You", - "githubStarredRepos": "GitHub starred repos", + "githubStarredRepos": "GitHub starred repositories", "uname": "Username", "wrongArgNum": "Wrong number of arguments provided", "xIsTrackOnly": "{} is track-only", @@ -313,7 +313,7 @@ "badDownload": "The APK could not be parsed (incompatible or partial download)", "beforeNewInstallsShareToAppVerifier": "Share new apps with AppVerifier (if available)", "appVerifierInstructionToast": "Share to AppVerifier, then return here when ready.", - "wiki": "Help/Wiki", + "wiki": "Help/wiki", "crowdsourcedConfigsLabel": "Crowdsourced app configurations (use at your own risk)", "crowdsourcedConfigsShort": "Crowdsourced app configurations", "allowInsecure": "Allow insecure HTTP requests", diff --git a/assets/translations/nl.json b/assets/translations/nl.json index 8d017ae..bf5d675 100644 --- a/assets/translations/nl.json +++ b/assets/translations/nl.json @@ -313,7 +313,7 @@ "badDownload": "De APK kon niet worden verwerkt (incompatibele of gedeeltelijke download)", "beforeNewInstallsShareToAppVerifier": "Nieuwe Apps delen met AppVerifier (indien beschikbaar)", "appVerifierInstructionToast": "Deel het met AppVerifier en keer daarna hier terug.", - "wiki": "Help/Wiki", + "wiki": "Help/wiki", "crowdsourcedConfigsLabel": "Crowdsourced App-configuraties (gebruik op eigen risico)", "crowdsourcedConfigsShort": "App-configuraties door menigte", "allowInsecure": "Onveilige HTTP-verzoeken toestaan", From 75430573f3f88209d49f41bff6b741d3d4bee1ef Mon Sep 17 00:00:00 2001 From: Imran Remtulla Date: Fri, 1 Aug 2025 14:52:54 -0400 Subject: [PATCH 05/10] Add "de/select all" button to multi-select menus (#2401) --- lib/pages/import_export.dart | 37 +++++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/lib/pages/import_export.dart b/lib/pages/import_export.dart index ebb0f1b..d8e34dd 100644 --- a/lib/pages/import_export.dart +++ b/lib/pages/import_export.dart @@ -396,9 +396,7 @@ class _ImportExportPageState extends State { Expanded( child: TextButton( style: outlineButtonStyle, - onPressed: - appsProvider.apps.isEmpty || - importInProgress + onPressed: importInProgress ? null : () { runObtainiumExport(pickOnly: true); @@ -710,6 +708,12 @@ class _SelectionModalState extends State { } } + void selectAll({bool deselect = false}) { + for (var e in entrySelections.keys) { + entrySelections[e] = !deselect; + } + } + @override Widget build(BuildContext context) { Map>, bool> filteredEntrySelections = {}; @@ -731,6 +735,32 @@ class _SelectionModalState extends State { } }); } + getSelectAllButton() { + if (widget.onlyOneSelectionAllowed) { + return SizedBox.shrink(); + } + var noneSelected = entrySelections.values.where((v) => v == true).isEmpty; + return noneSelected + ? TextButton( + style: const ButtonStyle(visualDensity: VisualDensity.compact), + onPressed: () { + setState(() { + selectAll(); + }); + }, + child: Text(tr('selectAll')), + ) + : TextButton( + style: const ButtonStyle(visualDensity: VisualDensity.compact), + onPressed: () { + setState(() { + selectAll(deselect: true); + }); + }, + child: Text(tr('deselectX', args: [''])), + ); + } + return AlertDialog( scrollable: true, title: Text(widget.title ?? tr('pick')), @@ -900,6 +930,7 @@ class _SelectionModalState extends State { ], ), actions: [ + getSelectAllButton(), TextButton( onPressed: () { Navigator.of(context).pop(); From 8204a16e90ca61e525bdc611c2c7d2999f0c5cb8 Mon Sep 17 00:00:00 2001 From: Imran Remtulla Date: Fri, 1 Aug 2025 15:52:39 -0400 Subject: [PATCH 06/10] Allow excluding secret values from export file (#2430) --- assets/translations/ar.json | 2 ++ assets/translations/bs.json | 2 ++ assets/translations/ca.json | 2 ++ assets/translations/cs.json | 2 ++ assets/translations/da.json | 2 ++ assets/translations/de.json | 2 ++ assets/translations/en-EO.json | 2 ++ assets/translations/en.json | 2 ++ assets/translations/es.json | 2 ++ assets/translations/fa.json | 2 ++ assets/translations/fr.json | 2 ++ assets/translations/hu.json | 2 ++ assets/translations/id.json | 2 ++ assets/translations/it.json | 2 ++ assets/translations/ja.json | 2 ++ assets/translations/ko.json | 2 ++ assets/translations/ml.json | 2 ++ assets/translations/nl.json | 2 ++ assets/translations/pl.json | 2 ++ assets/translations/pt-BR.json | 2 ++ assets/translations/pt.json | 2 ++ assets/translations/ru.json | 2 ++ assets/translations/sv.json | 2 ++ assets/translations/tr.json | 2 ++ assets/translations/uk.json | 2 ++ assets/translations/vi.json | 2 ++ assets/translations/zh-Hant-TW.json | 2 ++ assets/translations/zh.json | 2 ++ lib/pages/apps.dart | 2 +- lib/pages/import_export.dart | 20 ++++++++++++-------- lib/providers/apps_provider.dart | 15 +++++++++------ lib/providers/settings_provider.dart | 15 +++++++++++---- 32 files changed, 89 insertions(+), 19 deletions(-) diff --git a/assets/translations/ar.json b/assets/translations/ar.json index 4f54f3b..ed6defc 100644 --- a/assets/translations/ar.json +++ b/assets/translations/ar.json @@ -167,6 +167,7 @@ "versionCorrectionDisabled": "تعطيل تصحيح الإصدار (يبدو أن الملحق لا يعمل)", "unknown": "غير معروف", "none": "لا شيء", + "all": "الكل", "never": "أبدًا", "latestVersionX": "الأحدث: {}", "installedVersionX": "المثبت: {}", @@ -333,6 +334,7 @@ "foregroundService": "الحصول على خدمة الحصول على خدمة المقدمة", "foregroundServiceExplanation": "استخدام خدمة مقدمة للتحقق من التحديثات (أكثر موثوقية وتستهلك طاقة أكبر)", "fgServiceNotice": "هذا الإشعار مطلوب للتحقق من التحديث في الخلفية (يمكن إخفاؤه في إعدادات نظام التشغيل)", + "excludeSecrets": "استبعاد الأسرار", "removeAppQuestion": { "one": "إزالة التطبيق؟", "other": "إزالة التطبيقات؟" diff --git a/assets/translations/bs.json b/assets/translations/bs.json index 846b3d3..74b7a2a 100644 --- a/assets/translations/bs.json +++ b/assets/translations/bs.json @@ -167,6 +167,7 @@ "versionCorrectionDisabled": "Ispravka verzije je onemogućena (izgleda da plugin ne radi)", "unknown": "Nepoznato", "none": "Ništa", + "all": "All", "never": "Nikad", "latestVersionX": "Najnovija verzija: {}", "installedVersionX": "Instalirana verzija: {}", @@ -333,6 +334,7 @@ "foregroundService": "Obtainium foreground service", "foregroundServiceExplanation": "Use a foreground service for update checking (more reliable, consumes more power)", "fgServiceNotice": "This notification is required for background update checking (it can be hidden in the OS settings)", + "excludeSecrets": "Exclude secrets", "removeAppQuestion": { "one": "Želite li ukloniti aplikaciju?", "other": "Želite li ukloniti aplikacije?" diff --git a/assets/translations/ca.json b/assets/translations/ca.json index e441a1e..c28564e 100644 --- a/assets/translations/ca.json +++ b/assets/translations/ca.json @@ -167,6 +167,7 @@ "versionCorrectionDisabled": "Correcció de versions desactivada (el plugin sembla que no funciona)", "unknown": "Desconegut", "none": "Cap", + "all": "All", "never": "Mai", "latestVersionX": "Última versió: {}", "installedVersionX": "Versió instal·lada: {}", @@ -333,6 +334,7 @@ "foregroundService": "Servei d'Obtainium en primer pla", "foregroundServiceExplanation": "Usa el servei d'Obtainium en primer pla per comprovar les actualitzacions (és més fiable però consumeix més bateria)", "fgServiceNotice": "Aquesta notificació és necessària per comprovar les actualitzacions en segon pla (la pots ocultar als paràmetres del Sistema Operatiu)", + "excludeSecrets": "Exclude secrets", "removeAppQuestion": { "one": "¿Suprimeixo l'aplicació?", "other": "¿Suprimeixo les aplicacions?" diff --git a/assets/translations/cs.json b/assets/translations/cs.json index d828e15..abf4284 100644 --- a/assets/translations/cs.json +++ b/assets/translations/cs.json @@ -167,6 +167,7 @@ "versionCorrectionDisabled": "Oprava verze zakázána (zásuvný modul zřejmě nefunguje)", "unknown": "Neznám", "none": "Žádný", + "all": "Všechny", "never": "Nikdy", "latestVersionX": "Nejnovější verze: {}", "installedVersionX": "Nainstalovaná verze: {}", @@ -333,6 +334,7 @@ "foregroundService": "Služba Obtainium na popředí", "foregroundServiceExplanation": "Použití služby v popředí pro kontrolu aktualizací (spolehlivější, spotřebovává více energie).", "fgServiceNotice": "Toto oznámení je nutné pro kontrolu aktualizací na pozadí (lze jej skrýt v nastavení operačního systému).", + "excludeSecrets": "Vyloučit tajemství", "removeAppQuestion": { "one": "Odstranit Apku?", "other": "Odstranit Apky?" diff --git a/assets/translations/da.json b/assets/translations/da.json index 616ac27..3513048 100644 --- a/assets/translations/da.json +++ b/assets/translations/da.json @@ -167,6 +167,7 @@ "versionCorrectionDisabled": "Versionskorrektion deaktiveret (plugin ser ikke ud til at virke)", "unknown": "Ukendt", "none": "Ingen", + "all": "Alle", "never": "Aldrig", "latestVersionX": "Seneste: {}", "installedVersionX": "Installeret: {}", @@ -333,6 +334,7 @@ "foregroundService": "Obtainium forgrundstjeneste", "foregroundServiceExplanation": "Brug en forgrundstjeneste til opdateringskontrol (mere pålidelig, bruger mere strøm)", "fgServiceNotice": "Denne meddelelse er nødvendig for baggrundsopdateringskontrol (den kan skjules i OS-indstillingerne).", + "excludeSecrets": "Udeluk hemmeligheder", "removeAppQuestion": { "one": "Fjern app?", "other": "Fjern apps?" diff --git a/assets/translations/de.json b/assets/translations/de.json index 99261d2..bc6bbbe 100644 --- a/assets/translations/de.json +++ b/assets/translations/de.json @@ -167,6 +167,7 @@ "versionCorrectionDisabled": "Versionskorrektur deaktiviert (Plugin scheint nicht zu funktionieren)", "unknown": "Unbekannt", "none": "Keine", + "all": "Alle", "never": "Nie", "latestVersionX": "Neueste Version: {}", "installedVersionX": "Installierte Version: {}", @@ -333,6 +334,7 @@ "foregroundService": "Obtainium-Vordergrunddienst", "foregroundServiceExplanation": "Aktualisierungsprüfung im Vordergrund durchführen (zuverlässiger, verbraucht mehr Strom)", "fgServiceNotice": "Diese Benachrichtigung ist für die Prüfung von Updates im Hintergrund erforderlich (sie kann in den Betriebssystemeinstellungen ausgeblendet werden)", + "excludeSecrets": "Geheimnisse ausschließen", "removeAppQuestion": { "one": "App entfernen?", "other": "Apps entfernen?" diff --git a/assets/translations/en-EO.json b/assets/translations/en-EO.json index a3ba189..f1fae9b 100644 --- a/assets/translations/en-EO.json +++ b/assets/translations/en-EO.json @@ -167,6 +167,7 @@ "versionCorrectionDisabled": "Versiokorekto malaktivigita (ŝajnas, ke la kromaĵo ne funkcias)", "unknown": "Nekonata", "none": "Nenio", + "all": "All", "never": "Neniam", "latestVersionX": "Lasta versio: {}", "installedVersionX": "Instalita versio: {}", @@ -333,6 +334,7 @@ "foregroundService": "Obtainium foreground service", "foregroundServiceExplanation": "Use a foreground service for update checking (more reliable, consumes more power)", "fgServiceNotice": "This notification is required for background update checking (it can be hidden in the OS settings)", + "excludeSecrets": "Exclude secrets", "removeAppQuestion": { "one": "Forigi la aplikaĵon?", "other": "Forigi la aplikaĵojn?" diff --git a/assets/translations/en.json b/assets/translations/en.json index ea77e47..07967db 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -167,6 +167,7 @@ "versionCorrectionDisabled": "Version correction disabled (plugin doesn't seem to work)", "unknown": "Unknown", "none": "None", + "all": "All", "never": "Never", "latestVersionX": "Latest: {}", "installedVersionX": "Installed: {}", @@ -333,6 +334,7 @@ "foregroundService": "Obtainium foreground service", "foregroundServiceExplanation": "Use a foreground service for update checking (more reliable, consumes more power)", "fgServiceNotice": "This notification is required for background update checking (it can be hidden in the OS settings)", + "excludeSecrets": "Exclude secrets", "removeAppQuestion": { "one": "Remove app?", "other": "Remove apps?" diff --git a/assets/translations/es.json b/assets/translations/es.json index b39e110..40d2046 100644 --- a/assets/translations/es.json +++ b/assets/translations/es.json @@ -167,6 +167,7 @@ "versionCorrectionDisabled": "Corrección de versiones desactivada (el plugin parece no funcionar)", "unknown": "Desconocido", "none": "Ninguno", + "all": "Todos", "never": "Nunca", "latestVersionX": "Última versión: {}", "installedVersionX": "Versión instalada: {}", @@ -333,6 +334,7 @@ "foregroundService": "Obtainium servicio en primer plano", "foregroundServiceExplanation": "Utilizar un servicio en primer plano para comprobar las actualizaciones (más fiable, consume más energía).", "fgServiceNotice": "Esta notificación es necesaria para la comprobación de actualizaciones en segundo plano (puede ocultarse en la configuración del sistema operativo).", + "excludeSecrets": "Excluir secretos", "removeAppQuestion": { "one": "¿Eliminar aplicación?", "other": "¿Eliminar aplicaciones?" diff --git a/assets/translations/fa.json b/assets/translations/fa.json index 10de606..48a4c69 100644 --- a/assets/translations/fa.json +++ b/assets/translations/fa.json @@ -167,6 +167,7 @@ "versionCorrectionDisabled": "تصحیح نسخه غیرفعال شد (به نظر می رسد افزونه کار نمی کند)", "unknown": "ناشناخته", "none": "هیچ", + "all": "All", "never": "هرگز", "latestVersionX": "آخرین نسخه: {}", "installedVersionX": "نسخه نصب شده: {}", @@ -333,6 +334,7 @@ "foregroundService": "Obtainium foreground service", "foregroundServiceExplanation": "Use a foreground service for update checking (more reliable, consumes more power)", "fgServiceNotice": "This notification is required for background update checking (it can be hidden in the OS settings)", + "excludeSecrets": "Exclude secrets", "removeAppQuestion": { "one": "برنامه حذف شود؟", "other": "برنامه ها حذف شوند؟" diff --git a/assets/translations/fr.json b/assets/translations/fr.json index f65d20e..43c5dde 100644 --- a/assets/translations/fr.json +++ b/assets/translations/fr.json @@ -167,6 +167,7 @@ "versionCorrectionDisabled": "Correction de version désactivée (le plugin ne semble pas fonctionner)", "unknown": "Inconnu", "none": "Aucun", + "all": "Tous", "never": "Jamais", "latestVersionX": "Dernière version : {}", "installedVersionX": "Version installée : {}", @@ -333,6 +334,7 @@ "foregroundService": "Service d'avant-plan Obtainium", "foregroundServiceExplanation": "Utiliser un service de premier plan pour la vérification des mises à jour (plus fiable, consomme plus d'énergie)", "fgServiceNotice": "Cette notification est nécessaire pour la vérification des mises à jour en arrière-plan (elle peut être masquée dans les paramètres du système d'exploitation).", + "excludeSecrets": "Exclure les secrets", "removeAppQuestion": { "one": "Supprimer l'application ?", "other": "Supprimer les applications ?" diff --git a/assets/translations/hu.json b/assets/translations/hu.json index d40c1df..bd0aaa7 100644 --- a/assets/translations/hu.json +++ b/assets/translations/hu.json @@ -167,6 +167,7 @@ "versionCorrectionDisabled": "Verziókorrekció letiltva (úgy tűnik, hogy a bővítmény nem működik)", "unknown": "Ismeretlen", "none": "Semmi", + "all": "Minden", "never": "Soha", "latestVersionX": "Legújabb verzió: {}", "installedVersionX": "Telepített verzió: {}", @@ -333,6 +334,7 @@ "foregroundService": "Obtainium előtér-szolgáltatás", "foregroundServiceExplanation": "Előtér-szolgáltatás használata a frissítések ellenőrzéséhez (megbízhatóbb, de több energiát fogyaszt)", "fgServiceNotice": "Ez az értesítés a háttérben történő frissítésellenőrzéshez szükséges (a rendszer beállításaiban elrejthető).", + "excludeSecrets": "Titkok kizárása", "removeAppQuestion": { "one": "Eltávolítja az alkalmazást?", "other": "Eltávolítja az alkalmazásokat?" diff --git a/assets/translations/id.json b/assets/translations/id.json index efc3783..4258754 100644 --- a/assets/translations/id.json +++ b/assets/translations/id.json @@ -167,6 +167,7 @@ "versionCorrectionDisabled": "Koreksi versi dinonaktifkan (sepertinya plugin tidak berfungsi)", "unknown": "Tidak diketahui", "none": "Tidak ada", + "all": "Semua", "never": "Tidak pernah", "latestVersionX": "Terbaru: {}", "installedVersionX": "Terpasang: {}", @@ -333,6 +334,7 @@ "foregroundService": "Layanan latar depan Obtainium", "foregroundServiceExplanation": "Gunakan layanan latar depan untuk pemeriksaan pembaruan (lebih dapat diandalkan, menghabiskan lebih banyak daya)", "fgServiceNotice": "Pemberitahuan ini diperlukan untuk pemeriksaan pembaruan latar belakang (dapat disembunyikan dalam pengaturan OS)", + "excludeSecrets": "Mengecualikan rahasia", "removeAppQuestion": { "one": "Hapus aplikasi?", "other": "Hapus aplikasi?" diff --git a/assets/translations/it.json b/assets/translations/it.json index d5262c7..d060e66 100644 --- a/assets/translations/it.json +++ b/assets/translations/it.json @@ -167,6 +167,7 @@ "versionCorrectionDisabled": "Correzione della versione disattivata (il plugin sembra non funzionare)", "unknown": "Sconosciuto", "none": "Nessuno", + "all": "Tutti", "never": "Mai", "latestVersionX": "Ultima versione: {}", "installedVersionX": "Versione installata: {}", @@ -333,6 +334,7 @@ "foregroundService": "Servizio Obtainium in primo piano", "foregroundServiceExplanation": "Utilizzare un servizio in primo piano per il controllo degli aggiornamenti (più affidabile, consuma più energia)", "fgServiceNotice": "Questa notifica è necessaria per il controllo degli aggiornamenti in background (può essere nascosta nelle impostazioni del sistema operativo).", + "excludeSecrets": "Escludere i segreti", "removeAppQuestion": { "one": "Rimuovere l'app?", "other": "Rimuovere le app?" diff --git a/assets/translations/ja.json b/assets/translations/ja.json index ed83c5e..4ffc54e 100644 --- a/assets/translations/ja.json +++ b/assets/translations/ja.json @@ -167,6 +167,7 @@ "versionCorrectionDisabled": "バージョン補正無効 (プラグインが動作していません)", "unknown": "不明", "none": "なし", + "all": "すべて", "never": "しない", "latestVersionX": "最新のバージョン: {}", "installedVersionX": "インストールされたバージョン: {}", @@ -333,6 +334,7 @@ "foregroundService": "Obtainium フォアグラウンドサービス", "foregroundServiceExplanation": "アップデート確認にフォアグラウンドサービスを使用する(より信頼性が高いが、より電力を消費する)", "fgServiceNotice": "この通知は、バックグラウンドでアップデートを確認するために必要です(OSの設定で非表示にできます)。", + "excludeSecrets": "秘密を除く", "removeAppQuestion": { "one": "アプリを削除しますか?", "other": "アプリを削除しますか?" diff --git a/assets/translations/ko.json b/assets/translations/ko.json index 801627f..678df6c 100644 --- a/assets/translations/ko.json +++ b/assets/translations/ko.json @@ -167,6 +167,7 @@ "versionCorrectionDisabled": "버전 수정 비활성화됨 (플러그인이 작동하지 않는 것 같습니다)", "unknown": "알 수 없음", "none": "없음", + "all": "모두", "never": "절대", "latestVersionX": "최신: {}", "installedVersionX": "설치됨: {}", @@ -333,6 +334,7 @@ "foregroundService": "오베티움 포그라운드 서비스", "foregroundServiceExplanation": "업데이트 확인을 위해 포그라운드 서비스 사용(안정성 향상, 전력 소비량 증가)", "fgServiceNotice": "이 알림은 백그라운드 업데이트 확인에 필요합니다(OS 설정에서 숨길 수 있음).", + "excludeSecrets": "비밀 제외", "removeAppQuestion": { "one": "앱을 제거하시겠습니까?", "other": "앱을 제거하시겠습니까?" diff --git a/assets/translations/ml.json b/assets/translations/ml.json index 843cc87..0f81d1c 100644 --- a/assets/translations/ml.json +++ b/assets/translations/ml.json @@ -167,6 +167,7 @@ "versionCorrectionDisabled": "പതിപ്പ് തിരുത്തൽ പ്രവർത്തനരഹിതമാക്കി (പ്ലഗിൻ പ്രവർത്തിക്കുന്നതായി തോന്നുന്നില്ല)", "unknown": "അജ്ഞാതം", "none": "ഒന്നുമില്ല", + "all": "All", "never": "ഒരിക്കലുമില്ല", "latestVersionX": "ഏറ്റവും പുതിയത്: {}", "installedVersionX": "ഇൻസ്റ്റാൾ ചെയ്തത്: {}", @@ -333,6 +334,7 @@ "foregroundService": "Obtainium foreground service", "foregroundServiceExplanation": "Use a foreground service for update checking (more reliable, consumes more power)", "fgServiceNotice": "This notification is required for background update checking (it can be hidden in the OS settings)", + "excludeSecrets": "Exclude secrets", "removeAppQuestion": { "one": "ആപ്പ് നീക്കം ചെയ്യണോ?", "other": "ആപ്പുകൾ നീക്കം ചെയ്യണോ?" diff --git a/assets/translations/nl.json b/assets/translations/nl.json index bf5d675..a9846fd 100644 --- a/assets/translations/nl.json +++ b/assets/translations/nl.json @@ -167,6 +167,7 @@ "versionCorrectionDisabled": "Versiecorrectie uitgeschakeld (de plug-in lijkt niet te werken)", "unknown": "Onbekend", "none": "Geen", + "all": "Alle", "never": "Nooit", "latestVersionX": "Laatste versie: {}", "installedVersionX": "Geïnstalleerde versie: {}", @@ -333,6 +334,7 @@ "foregroundService": "Obtainium foreground service", "foregroundServiceExplanation": "Gebruik een voorgronddienst voor het controleren van updates (betrouwbaarder, verbruikt meer stroom)", "fgServiceNotice": "Deze melding is nodig voor het controleren van updates op de achtergrond (kan worden verborgen in de OS-instellingen)", + "excludeSecrets": "Geheimen uitsluiten", "removeAppQuestion": { "one": "App verwijderen?", "other": "Apps verwijderen?" diff --git a/assets/translations/pl.json b/assets/translations/pl.json index fd87b83..0c84a29 100644 --- a/assets/translations/pl.json +++ b/assets/translations/pl.json @@ -167,6 +167,7 @@ "versionCorrectionDisabled": "Korekta wersji wyłączona (wtyczka wydaje się nie działać)", "unknown": "Nieznane", "none": "Brak", + "all": "Wszystkie", "never": "Nigdy", "latestVersionX": "Najnowsza wersja: {}", "installedVersionX": "Zainstalowana wersja: {}", @@ -333,6 +334,7 @@ "foregroundService": "Usługa nowej generacji Obtainium", "foregroundServiceExplanation": "Używanie usługi pierwszoplanowej do sprawdzania aktualizacji (bardziej niezawodne, zużywa więcej energii)", "fgServiceNotice": "To powiadomienie jest wymagane do sprawdzania aktualizacji w tle (można je ukryć w ustawieniach systemu operacyjnego).", + "excludeSecrets": "Wyklucz sekrety", "removeAppQuestion": { "one": "Usunąć aplikację?", "few": "Usunąć aplikacje?", diff --git a/assets/translations/pt-BR.json b/assets/translations/pt-BR.json index 2d3406a..d9c89ef 100644 --- a/assets/translations/pt-BR.json +++ b/assets/translations/pt-BR.json @@ -167,6 +167,7 @@ "versionCorrectionDisabled": "Correção de versão desativada (o plugin parece não funcionar)", "unknown": "Desconhecido", "none": "Nenhum", + "all": "Todos", "never": "Nunca", "latestVersionX": "Mais recente: {}", "installedVersionX": "Instalado: {}", @@ -333,6 +334,7 @@ "foregroundService": "Serviço de primeiro plano do Obtainium", "foregroundServiceExplanation": "Usar um serviço em primeiro plano para verificação de atualizações (mais confiável, consome mais energia)", "fgServiceNotice": "Essa notificação é necessária para a verificação de atualizações em segundo plano (ela pode ser ocultada nas configurações do sistema operacional)", + "excludeSecrets": "Excluir segredos", "removeAppQuestion": { "one": "Remover app?", "other": "Remover apps?" diff --git a/assets/translations/pt.json b/assets/translations/pt.json index c388a15..7c21d09 100644 --- a/assets/translations/pt.json +++ b/assets/translations/pt.json @@ -167,6 +167,7 @@ "versionCorrectionDisabled": "Correção de versão desativada (plugin parece não funcionar)", "unknown": "Desconhecido", "none": "Nenhum", + "all": "Todos", "never": "Nunca", "latestVersionX": "Última versão: {}", "installedVersionX": "Versão instalada: {}", @@ -333,6 +334,7 @@ "foregroundService": "Serviço de primeiro plano Obtainium", "foregroundServiceExplanation": "Utilizar um serviço em primeiro plano para verificação de actualizações (mais fiável, consome mais energia)", "fgServiceNotice": "Esta notificação é necessária para a verificação de actualizações em segundo plano (pode ser ocultada nas definições do SO)", + "excludeSecrets": "Excluir segredos", "removeAppQuestion": { "one": "Remover aplicativo?", "other": "Remover aplicativos?" diff --git a/assets/translations/ru.json b/assets/translations/ru.json index e4e5b10..bcb4bf9 100644 --- a/assets/translations/ru.json +++ b/assets/translations/ru.json @@ -167,6 +167,7 @@ "versionCorrectionDisabled": "Коррекция версий отключена (плагин, кажется, не работает)", "unknown": "Неизвестно", "none": "Отсутствует", + "all": "Все", "never": "Никогда", "latestVersionX": "Последняя версия: {}", "installedVersionX": "Установленная версия: {}", @@ -333,6 +334,7 @@ "foregroundService": "Приоритетная служба Obtainium", "foregroundServiceExplanation": "Использовать приоритетную службу для проверки обновлений (надёжнее, энергозатратнее)", "fgServiceNotice": "Это уведомление необходимо для фоновой проверки обновлений (оно может быть скрыто в настройках ОС)", + "excludeSecrets": "Исключить секреты", "removeAppQuestion": { "one": "Удалить приложение?", "other": "Удалить приложения?" diff --git a/assets/translations/sv.json b/assets/translations/sv.json index 9aedddd..44def8d 100644 --- a/assets/translations/sv.json +++ b/assets/translations/sv.json @@ -167,6 +167,7 @@ "versionCorrectionDisabled": "Versionskorrigering inaktiverat (plugin verkar inte fungera)", "unknown": "Okänd", "none": "Ingen", + "all": "Alla", "never": "Aldrig", "latestVersionX": "Senaste Version: {}", "installedVersionX": "Installerad Version: {}", @@ -333,6 +334,7 @@ "foregroundService": "Obtainium förgrundstjänst", "foregroundServiceExplanation": "Använd en förgrundstjänst för uppdateringskontroll (mer tillförlitlig, förbrukar mer ström)", "fgServiceNotice": "Detta meddelande krävs för bakgrundsuppdateringskontroll (det kan döljas i OS-inställningarna)", + "excludeSecrets": "Utesluta hemligheter", "removeAppQuestion": { "one": "Ta Bort App?", "other": "Ta Bort Appar?" diff --git a/assets/translations/tr.json b/assets/translations/tr.json index f4a53b8..ddda952 100644 --- a/assets/translations/tr.json +++ b/assets/translations/tr.json @@ -167,6 +167,7 @@ "versionCorrectionDisabled": "Sürüm düzeltme devre dışı bırakıldı (eklenti çalışmıyor gibi görünüyor)", "unknown": "Bilinmiyor", "none": "Hiçbiri", + "all": "Tümü", "never": "Asla", "latestVersionX": "En Son Sürüm: {}", "installedVersionX": "Yüklenen Sürüm: {}", @@ -333,6 +334,7 @@ "foregroundService": "Obtainium ön plan hizmeti", "foregroundServiceExplanation": "Güncelleme denetimi için bir ön plan hizmeti kullanın (daha güvenilir, daha fazla güç tüketir)", "fgServiceNotice": "Bu bildirim arka planda güncelleme kontrolü için gereklidir (işletim sistemi ayarlarından gizlenebilir)", + "excludeSecrets": "Sırları hariç tut", "removeAppQuestion": { "one": "Uygulamayı Kaldır?", "other": "Uygulamaları Kaldır?" diff --git a/assets/translations/uk.json b/assets/translations/uk.json index f1695f6..f2053a2 100644 --- a/assets/translations/uk.json +++ b/assets/translations/uk.json @@ -167,6 +167,7 @@ "versionCorrectionDisabled": "Виправлення версії вимкнено (здається, плагін не працює)", "unknown": "Невідомо", "none": "Нічого", + "all": "Усе.", "never": "Ніколи", "latestVersionX": "Остання версія: {}", "installedVersionX": "Встановлено: {}", @@ -333,6 +334,7 @@ "foregroundService": "Обслуговування переднього плану Obtainium", "foregroundServiceExplanation": "Використовуйте службу переднього плану для перевірки оновлень (надійніша, споживає більше енергії)", "fgServiceNotice": "Це сповіщення необхідне для фонової перевірки оновлень (його можна приховати в налаштуваннях ОС)", + "excludeSecrets": "Виключити секрети", "removeAppQuestion": { "one": "Видалити застосунок?", "other": "Видалити застосунки?" diff --git a/assets/translations/vi.json b/assets/translations/vi.json index 2f92c3d..6b1a275 100644 --- a/assets/translations/vi.json +++ b/assets/translations/vi.json @@ -167,6 +167,7 @@ "versionCorrectionDisabled": "Tính năng sửa phiên bản bị vô hiệu hóa (plugin dường như không hoạt động)", "unknown": "Không xác định", "none": "Không", + "all": "Tất cả", "never": "Không bao giờ", "latestVersionX": "Phiên bản mới nhất: {}", "installedVersionX": "Phiên bản đã cài đặt: {}", @@ -333,6 +334,7 @@ "foregroundService": "Dịch vụ nền Obtainium", "foregroundServiceExplanation": "Sử dụng dịch vụ nền trước để kiểm tra cập nhật (đáng tin cậy hơn, tiêu tốn nhiều pin hơn)", "fgServiceNotice": "Thông báo này là bắt buộc để kiểm tra cập nhật nền (có thể ẩn trong cài đặt hệ điều hành).", + "excludeSecrets": "Loại trừ thông tin bí mật", "removeAppQuestion": { "one": "Gỡ ứng dụng?", "other": "Gỡ ứng dụng?" diff --git a/assets/translations/zh-Hant-TW.json b/assets/translations/zh-Hant-TW.json index 4146d2b..b926867 100644 --- a/assets/translations/zh-Hant-TW.json +++ b/assets/translations/zh-Hant-TW.json @@ -167,6 +167,7 @@ "versionCorrectionDisabled": "版本校正已停用(外掛程式似乎無法正常工作)", "unknown": "未知", "none": "無", + "all": "All", "never": "從不", "latestVersionX": "最新版本:{}", "installedVersionX": "已安裝版本:{}", @@ -333,6 +334,7 @@ "foregroundService": "Obtainium foreground service", "foregroundServiceExplanation": "Use a foreground service for update checking (more reliable, consumes more power)", "fgServiceNotice": "This notification is required for background update checking (it can be hidden in the OS settings)", + "excludeSecrets": "Exclude secrets", "removeAppQuestion": { "one": "移除應用程式?", "other": "移除應用程式?" diff --git a/assets/translations/zh.json b/assets/translations/zh.json index 01d9d32..120d879 100644 --- a/assets/translations/zh.json +++ b/assets/translations/zh.json @@ -167,6 +167,7 @@ "versionCorrectionDisabled": "禁用版本号更正(插件似乎未起作用)", "unknown": "未知", "none": "无", + "all": "全部", "never": "从未", "latestVersionX": "最新版本:{}", "installedVersionX": "当前版本:{}", @@ -333,6 +334,7 @@ "foregroundService": "Obtainium 前台服务", "foregroundServiceExplanation": "使用前台服务检查更新(更稳定,但也更耗电)", "fgServiceNotice": "后台检查更新时需要此通知(可在操作系统设置中隐藏)", + "excludeSecrets": "排除机密", "removeAppQuestion": { "one": "是否删除应用?", "other": "是否删除应用?" diff --git a/lib/pages/apps.dart b/lib/pages/apps.dart index 6ef7e11..73dce64 100644 --- a/lib/pages/apps.dart +++ b/lib/pages/apps.dart @@ -1037,7 +1037,7 @@ class AppsPageState extends State { var exportJSON = encoder.convert( appsProvider.generateExportJSON( appIds: selectedApps.map((e) => e.id).toList(), - overrideExportSettings: false, + overrideExportSettings: 0, ), ); String fn = diff --git a/lib/pages/import_export.dart b/lib/pages/import_export.dart index d8e34dd..ba0c663 100644 --- a/lib/pages/import_export.dart +++ b/lib/pages/import_export.dart @@ -412,9 +412,7 @@ class _ImportExportPageState extends State { child: TextButton( style: outlineButtonStyle, onPressed: - appsProvider.apps.isEmpty || - importInProgress || - snapshot.data == null + importInProgress || snapshot.data == null ? null : runObtainiumExport, child: Text( @@ -457,11 +455,17 @@ class _ImportExportPageState extends State { ), ], [ - GeneratedFormSwitch( + GeneratedFormDropdown( 'exportSettings', + [ + MapEntry('0', tr('none')), + MapEntry('1', tr('excludeSecrets')), + MapEntry('2', tr('all')), + ], label: tr('includeSettings'), - defaultValue: - settingsProvider.exportSettings, + defaultValue: settingsProvider + .exportSettings + .toString(), ), ], ], @@ -475,7 +479,7 @@ class _ImportExportPageState extends State { } if (value['exportSettings'] != null) { settingsProvider.exportSettings = - value['exportSettings'] == true; + int.parse(value['exportSettings']); } } }, @@ -497,7 +501,7 @@ class _ImportExportPageState extends State { else Column( children: [ - const Divider(height: 32), + SizedBox(height: 32), Row( children: [ Expanded( diff --git a/lib/providers/apps_provider.dart b/lib/providers/apps_provider.dart index 933a920..8cd78e2 100644 --- a/lib/providers/apps_provider.dart +++ b/lib/providers/apps_provider.dart @@ -1965,7 +1965,7 @@ class AppsProvider with ChangeNotifier { Map generateExportJSON({ List? appIds, - bool? overrideExportSettings, + int? overrideExportSettings, }) { Map finalExport = {}; finalExport['apps'] = apps.values @@ -1978,15 +1978,18 @@ class AppsProvider with ChangeNotifier { }) .map((e) => e.app.toJson()) .toList(); - bool shouldExportSettings = settingsProvider.exportSettings; + int shouldExportSettings = settingsProvider.exportSettings; if (overrideExportSettings != null) { shouldExportSettings = overrideExportSettings; } - if (shouldExportSettings) { + if (shouldExportSettings > 0) { + var settingsValueKeys = settingsProvider.prefs?.getKeys(); + if (shouldExportSettings < 2) { + settingsValueKeys?.removeWhere((k) => k.endsWith('-creds')); + } finalExport['settings'] = Map.fromEntries( - (settingsProvider.prefs - ?.getKeys() - .map((key) => MapEntry(key, settingsProvider.prefs?.get(key))) + (settingsValueKeys + ?.map((key) => MapEntry(key, settingsProvider.prefs?.get(key))) .toList()) ?? [], ); diff --git a/lib/providers/settings_provider.dart b/lib/providers/settings_provider.dart index 48e75f9..121ad1e 100644 --- a/lib/providers/settings_provider.dart +++ b/lib/providers/settings_provider.dart @@ -453,12 +453,19 @@ class SettingsProvider with ChangeNotifier { notifyListeners(); } - bool get exportSettings { - return prefs?.getBool('exportSettings') ?? false; + int get exportSettings { + try { + return prefs?.getInt('exportSettings') ?? + 1; // 0 for no, 1 for yes but no secrets, 2 for everything + } catch (e) { + var val = prefs?.getBool('exportSettings') == true ? 1 : 0; + prefs?.setInt('exportSettings', val); + return val; + } } - set exportSettings(bool val) { - prefs?.setBool('exportSettings', val); + set exportSettings(int val) { + prefs?.setInt('exportSettings', val > 2 || val < 0 ? 1 : val); notifyListeners(); } From 8f9978aadda268e6a9d2c32a181e999809a13eac Mon Sep 17 00:00:00 2001 From: Imran Remtulla Date: Fri, 1 Aug 2025 16:46:17 -0400 Subject: [PATCH 07/10] Fix occasional RangeError after importing apps (#2438) --- lib/pages/home.dart | 9 --------- lib/providers/apps_provider.dart | 14 +++++++++++--- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/lib/pages/home.dart b/lib/pages/home.dart index 670527a..1bb5802 100644 --- a/lib/pages/home.dart +++ b/lib/pages/home.dart @@ -14,7 +14,6 @@ import 'package:obtainium/pages/import_export.dart'; import 'package:obtainium/pages/settings.dart'; import 'package:obtainium/providers/apps_provider.dart'; import 'package:obtainium/providers/settings_provider.dart'; -import 'package:obtainium/providers/source_provider.dart'; import 'package:provider/provider.dart'; import 'package:url_launcher/url_launcher_string.dart'; @@ -201,14 +200,6 @@ class _HomePageState extends State { ), context, ); - await appsProvider - .checkUpdates(specificIds: result.key.map((e) => e.id).toList()) - .catchError((e) { - if (e is Map && e['errors'] is MultiAppMultiError) { - showError(e['errors'].toString(), context); - } - return []; - }); } } else { throw ObtainiumError(tr('unknown')); diff --git a/lib/providers/apps_provider.dart b/lib/providers/apps_provider.dart index 8cd78e2..61801a5 100644 --- a/lib/providers/apps_provider.dart +++ b/lib/providers/apps_provider.dart @@ -1025,13 +1025,19 @@ class AppsProvider with ChangeNotifier { ); } getHost(String url) { + if (url == 'placeholder') { + return null; + } var temp = Uri.parse(url).host.split('.'); return temp.sublist(temp.length - 2).join('.'); } // If the picked APK comes from an origin different from the source, get user confirmation (if context provided) if (appFileUrl != null && - getHost(appFileUrl.value) != getHost(app.url) && + ![ + getHost(app.url), + 'placeholder', + ].contains(getHost(appFileUrl.value)) && context != null) { if (!(settingsProvider.hideAPKOriginWarning) && await showDialog( @@ -1077,7 +1083,8 @@ class AppsProvider with ChangeNotifier { MapEntry? apkUrl; var trackOnly = apps[id]!.app.additionalSettings['trackOnly'] == true; var refreshBeforeDownload = - apps[id]!.app.additionalSettings['refreshBeforeDownload'] == true; + apps[id]!.app.additionalSettings['refreshBeforeDownload'] == true || + apps[id]!.app.apkUrls.first.value == 'placeholder'; if (refreshBeforeDownload) { await checkUpdate(apps[id]!.app.id); } @@ -1301,7 +1308,8 @@ class AppsProvider with ChangeNotifier { } MapEntry? fileUrl; var refreshBeforeDownload = - apps[id]!.app.additionalSettings['refreshBeforeDownload'] == true; + apps[id]!.app.additionalSettings['refreshBeforeDownload'] == true || + apps[id]!.app.apkUrls.first.value == 'placeholder'; if (refreshBeforeDownload) { await checkUpdate(apps[id]!.app.id); } From 89d853a9486e4eeda4193c8e944caa5be7e33182 Mon Sep 17 00:00:00 2001 From: Imran Remtulla Date: Fri, 1 Aug 2025 17:50:16 -0400 Subject: [PATCH 08/10] Added farsroid.com as a source (#2435) --- README.md | 1 + lib/app_sources/farsroid.dart | 76 ++++++++++++++++++++++++++++++ lib/app_sources/html.dart | 25 ++++++---- lib/providers/source_provider.dart | 12 +++-- 4 files changed, 102 insertions(+), 12 deletions(-) create mode 100644 lib/app_sources/farsroid.dart diff --git a/README.md b/README.md index 229979b..2832b4d 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,7 @@ Currently supported App sources: - [CoolApk](https://coolapk.com/) - [vivo App Store (CN)](https://h5.appstore.vivo.com.cn/) - [RuStore](https://rustore.ru/) + - [Farsroid](https://www.farsroid.com) - Jenkins Jobs - [APKMirror](https://apkmirror.com/) (Track-Only) - Other - App-Specific: diff --git a/lib/app_sources/farsroid.dart b/lib/app_sources/farsroid.dart new file mode 100644 index 0000000..82754d0 --- /dev/null +++ b/lib/app_sources/farsroid.dart @@ -0,0 +1,76 @@ +import 'dart:convert'; + +import 'package:html/parser.dart'; +import 'package:obtainium/app_sources/html.dart'; +import 'package:obtainium/custom_errors.dart'; +import 'package:obtainium/providers/source_provider.dart'; + +class Farsroid extends AppSource { + Farsroid() { + hosts = ['farsroid.com']; + name = 'Farsroid'; + } + + @override + String sourceSpecificStandardizeURL(String url, {bool forSelection = false}) { + RegExp standardUrlRegEx = RegExp( + '^https?://([^\\.]+\\.)${getSourceRegex(hosts)}/[^/]+', + caseSensitive: false, + ); + RegExpMatch? match = standardUrlRegEx.firstMatch(url); + if (match == null) { + throw InvalidURLError(name); + } + return match.group(0)!; + } + + @override + Future getLatestAPKDetails( + String standardUrl, + Map additionalSettings, + ) async { + String appName = Uri.parse(standardUrl).pathSegments.last; + + var res = await sourceRequest(standardUrl, additionalSettings); + if (res.statusCode != 200) { + throw getObtainiumHttpError(res); + } + var html = parse(res.body); + var dlinks = html.querySelectorAll('.download-links'); + if (dlinks.isEmpty) { + throw NoReleasesError(); + } + var postId = dlinks.first.attributes['data-post-id'] ?? ''; + var version = dlinks.first.attributes['data-post-version'] ?? ''; + + if (postId.isEmpty || version.isEmpty) { + throw NoVersionError(); + } + + var res2 = await sourceRequest( + Uri.encodeFull( + 'https://${hosts[0]}/api/download-box/?post_id=$postId&post_version=$version', + ), + additionalSettings, + ); + var html2 = jsonDecode(res2.body)?['data']?['content'] as String? ?? ''; + if (html2.isEmpty) { + throw NoAPKError(); + } + var apkLinks = + (await grabLinksCommon(html2, res2.request!.url, additionalSettings)) + .map((l) => MapEntry(Uri.parse(l.key).pathSegments.last, l.key)) + .where( + (l) => l.key.toLowerCase().startsWith( + '$appName-$version'.toLowerCase(), + ), + ) + .toList(); + + if (apkLinks.isEmpty) { + throw NoAPKError(); + } + + return APKDetails(version, apkLinks, AppNames(name, appName)); + } +} diff --git a/lib/app_sources/html.dart b/lib/app_sources/html.dart index 437cb6f..08c070e 100644 --- a/lib/app_sources/html.dart +++ b/lib/app_sources/html.dart @@ -113,14 +113,23 @@ List> getLinksInLines(String lines) => // Given an HTTP response, grab some links according to the common additional settings // (those that apply to intermediate and final steps) -Future>> grabLinksCommon( +Future>> grabLinksCommonFromRes( Response res, Map additionalSettings, ) async { if (res.statusCode != 200) { throw getObtainiumHttpError(res); } - var html = parse(res.body); + return grabLinksCommon(res.body, res.request!.url, additionalSettings); +} + +// Note keys are URLs, values are filenames (opposite to the AppSource apkUrls) +Future>> grabLinksCommon( + String rawBody, + Uri reqUrl, + Map additionalSettings, +) async { + var html = parse(rawBody); List> allLinks = html .querySelectorAll('a') .map( @@ -132,21 +141,21 @@ Future>> grabLinksCommon( ), ) .where((element) => element.key.isNotEmpty) - .map((e) => MapEntry(ensureAbsoluteUrl(e.key, res.request!.url), e.value)) + .map((e) => MapEntry(ensureAbsoluteUrl(e.key, reqUrl), e.value)) .toList(); if (allLinks.isEmpty) { - allLinks = getLinksInLines(res.body); + allLinks = getLinksInLines(rawBody); } if (allLinks.isEmpty) { // Getting desperate try { - var jsonStrings = collectAllStringsFromJSONObject(jsonDecode(res.body)); + var jsonStrings = collectAllStringsFromJSONObject(jsonDecode(rawBody)); allLinks = getLinksInLines(jsonStrings.join('\n')); if (allLinks.isEmpty) { allLinks = getLinksInLines( jsonStrings .map((l) { - return ensureAbsoluteUrl(l, res.request!.url); + return ensureAbsoluteUrl(l, reqUrl); }) .join('\n'), ); @@ -368,7 +377,7 @@ class HTML extends AppSource { .where((l) => l['customLinkFilterRegex'].isNotEmpty == true) .toList(); for (int i = 0; i < (additionalSettings['intermediateLink'].length); i++) { - var intLinks = await grabLinksCommon( + var intLinks = await grabLinksCommonFromRes( await sourceRequest(currentUrl, additionalSettings), additionalSettings['intermediateLink'][i], ); @@ -392,7 +401,7 @@ class HTML extends AppSource { .join('\n') .split('\n') .join('\\n'); - links = await grabLinksCommon(res, additionalSettings); + links = await grabLinksCommonFromRes(res, additionalSettings); links = filterApks( links, additionalSettings['apkFilterRegEx'], diff --git a/lib/providers/source_provider.dart b/lib/providers/source_provider.dart index f14d988..d9c1b69 100644 --- a/lib/providers/source_provider.dart +++ b/lib/providers/source_provider.dart @@ -16,6 +16,7 @@ import 'package:obtainium/app_sources/aptoide.dart'; import 'package:obtainium/app_sources/codeberg.dart'; import 'package:obtainium/app_sources/coolapk.dart'; import 'package:obtainium/app_sources/directAPKLink.dart'; +import 'package:obtainium/app_sources/farsroid.dart'; import 'package:obtainium/app_sources/fdroid.dart'; import 'package:obtainium/app_sources/fdroidrepo.dart'; import 'package:obtainium/app_sources/github.dart'; @@ -63,11 +64,13 @@ class APKDetails { }); } -List> stringMapListTo2DList(List> mapList) => - mapList.map((e) => [e.key, e.value]).toList(); +List> stringMapListTo2DList( + List> mapList, +) => mapList.map((e) => [e.key, e.value]).toList(); -List> assumed2DlistToStringMapList(List arr) => - arr.map((e) => MapEntry(e[0] as String, e[1] as String)).toList(); +List> assumed2DlistToStringMapList( + List arr, +) => arr.map((e) => MapEntry(e[0] as String, e[1] as String)).toList(); // App JSON schema has changed multiple times over the many versions of Obtainium // This function takes an App JSON and modifies it if needed to conform to the latest (current) version @@ -1074,6 +1077,7 @@ class SourceProvider { Jenkins(), APKMirror(), RuStore(), + Farsroid(), TelegramApp(), NeutronCode(), DirectAPKLink(), From 3e73156f78be5e59e6589c6ec1958e268b253571 Mon Sep 17 00:00:00 2001 From: Imran Remtulla Date: Fri, 1 Aug 2025 17:59:15 -0400 Subject: [PATCH 09/10] Minor language-specific case tweaks (#2396) --- lib/custom_errors.dart | 5 +++-- lib/pages/app.dart | 5 ++++- lib/pages/apps.dart | 5 ++++- lib/pages/import_export.dart | 2 +- lib/providers/apps_provider.dart | 2 +- lib/providers/source_provider.dart | 3 +++ 6 files changed, 16 insertions(+), 6 deletions(-) diff --git a/lib/custom_errors.dart b/lib/custom_errors.dart index 4f06df5..83d200a 100644 --- a/lib/custom_errors.dart +++ b/lib/custom_errors.dart @@ -5,6 +5,7 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:obtainium/providers/logs_provider.dart'; +import 'package:obtainium/providers/source_provider.dart'; import 'package:provider/provider.dart'; class ObtainiumError { @@ -158,7 +159,7 @@ void showError(dynamic e, BuildContext context) { } String list2FriendlyString(List list) { - var isEnglish = tr('and') == 'and'; // Quick hack, find better way; + var isUsingEnglish = isEnglish(); return list.length == 2 ? '${list[0]} ${tr('and')} ${list[1]}' : list @@ -170,7 +171,7 @@ String list2FriendlyString(List list) { (e.key == list.length - 1 ? '' : e.key == list.length - 2 - ? '${isEnglish ? ',' : ''} and ' + ? '${isUsingEnglish ? ',' : ''} and ' : ', '), ) .join(''); diff --git a/lib/pages/app.dart b/lib/pages/app.dart index 1aee32c..f67884e 100644 --- a/lib/pages/app.dart +++ b/lib/pages/app.dart @@ -232,7 +232,10 @@ class _AppPageState extends State { : const EdgeInsetsDirectional.fromSTEB(0, 6, 0, 6), margin: const EdgeInsetsDirectional.fromSTEB(0, 6, 0, 0), child: Text( - tr('downloadX', args: [tr('releaseAsset').toLowerCase()]), + tr( + 'downloadX', + args: [lowerCaseIfEnglish(tr('releaseAsset'))], + ), textAlign: TextAlign.center, style: Theme.of(context).textTheme.labelSmall!.copyWith( decoration: TextDecoration.underline, diff --git a/lib/pages/apps.dart b/lib/pages/apps.dart index 73dce64..3cbf7e6 100644 --- a/lib/pages/apps.dart +++ b/lib/pages/apps.dart @@ -1072,7 +1072,10 @@ class AppsPageState extends State { Navigator.of(context).pop(); }, child: Text( - tr('downloadX', args: [tr('releaseAsset').toLowerCase()]), + tr( + 'downloadX', + args: [lowerCaseIfEnglish(tr('releaseAsset'))], + ), ), ), const Divider(), diff --git a/lib/pages/import_export.dart b/lib/pages/import_export.dart index ba0c663..1b6d6da 100644 --- a/lib/pages/import_export.dart +++ b/lib/pages/import_export.dart @@ -545,7 +545,7 @@ class _ImportExportPageState extends State { child: Text( tr( 'searchX', - args: [tr('source').toLowerCase()], + args: [lowerCaseIfEnglish(tr('source'))], ), ), ), diff --git a/lib/providers/apps_provider.dart b/lib/providers/apps_provider.dart index 61801a5..c10d401 100644 --- a/lib/providers/apps_provider.dart +++ b/lib/providers/apps_provider.dart @@ -2164,7 +2164,7 @@ class _AppFilePickerState extends State { scrollable: true, title: Text( widget.pickAnyAsset - ? tr('selectX', args: [tr('releaseAsset').toLowerCase()]) + ? tr('selectX', args: [lowerCaseIfEnglish(tr('releaseAsset'))]) : tr('pickAnAPK'), ), content: Column( diff --git a/lib/providers/source_provider.dart b/lib/providers/source_provider.dart index d9c1b69..54dcab9 100644 --- a/lib/providers/source_provider.dart +++ b/lib/providers/source_provider.dart @@ -1052,6 +1052,9 @@ List> filterApks( return apkUrls; } +bool isEnglish() => tr('and') == 'and'; // Quick hack, find a better way +String lowerCaseIfEnglish(String str) => isEnglish() ? str.toLowerCase() : str; + bool isVersionPseudo(App app) => app.additionalSettings['trackOnly'] == true || (app.installedVersion != null && From 0f726889c8918cf6fa7d6dd16a0fa7b5fa2b1626 Mon Sep 17 00:00:00 2001 From: Imran Remtulla Date: Fri, 1 Aug 2025 18:09:23 -0400 Subject: [PATCH 10/10] Increment version, upgrade Flutter + packages --- .flutter | 2 +- pubspec.lock | 20 ++++++++++---------- pubspec.yaml | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.flutter b/.flutter index d7b523b..edada7c 160000 --- a/.flutter +++ b/.flutter @@ -1 +1 @@ -Subproject commit d7b523b356d15fb81e7d340bbe52b47f93937323 +Subproject commit edada7c56edf4a183c1735310e123c7f923584f1 diff --git a/pubspec.lock b/pubspec.lock index e5ee5c2..065f369 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -96,10 +96,10 @@ packages: dependency: "direct main" description: name: background_fetch - sha256: "442e82f508708be89fd0cc7e1dc3b27bc7c6c8c39a47967ccb7ed1c57b9108b5" + sha256: e767745c31f71660063985c982497995d0a71755d3f1b0c8e8c96988d64d3003 url: "https://pub.dev" source: hosted - version: "1.3.8" + version: "1.4.0" battery_plus: dependency: "direct main" description: @@ -288,10 +288,10 @@ packages: dependency: "direct main" description: name: file_picker - sha256: ef9908739bdd9c476353d6adff72e88fd00c625f5b959ae23f7567bd5137db0a + sha256: "13ba4e627ef24503a465d1d61b32596ce10eb6b8903678d362a528f9939b4aa8" url: "https://pub.dev" source: hosted - version: "10.2.0" + version: "10.2.1" fixnum: dependency: transitive description: @@ -349,10 +349,10 @@ packages: dependency: transitive description: name: flutter_charset_detector_darwin - sha256: "65d91133ea8ef06a440941b1126702b4735a8bd487430b41760e706a0b6b26d4" + sha256: "8cf51c3e16c2fb4ec4e309f16f6046a0ddf1ff57d1b6b696410d077a9ffbfb15" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.2.1" flutter_charset_detector_platform_interface: dependency: transitive description: @@ -955,10 +955,10 @@ packages: dependency: transitive description: name: sqflite_common - sha256: "84731e8bfd8303a3389903e01fb2141b6e59b5973cacbb0929021df08dddbe8b" + sha256: "6ef422a4525ecc601db6c0a2233ff448c731307906e92cabc9ba292afaae16a6" url: "https://pub.dev" source: hosted - version: "2.5.5" + version: "2.5.6" sqflite_darwin: dependency: transitive description: @@ -1163,10 +1163,10 @@ packages: dependency: transitive description: name: webview_flutter_platform_interface - sha256: f0dc2dc3a2b1e3a6abdd6801b9355ebfeb3b8f6cde6b9dc7c9235909c4a1f147 + sha256: "63d26ee3aca7256a83ccb576a50272edd7cfc80573a4305caa98985feb493ee0" url: "https://pub.dev" source: hosted - version: "2.13.1" + version: "2.14.0" webview_flutter_wkwebview: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index ba3afdf..08cd2ed 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -16,7 +16,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: 1.2.1+2317 +version: 1.2.2+2318 environment: sdk: ^3.8.1