diff --git a/assets/translations/bs.json b/assets/translations/bs.json index a3e935a..62b5b32 100644 --- a/assets/translations/bs.json +++ b/assets/translations/bs.json @@ -183,6 +183,9 @@ "disableVersionDetection": "Onemogući detekciju verzije", "noVersionDetectionExplanation": "Ova opcija bi se trebala koristiti samo za aplikacije gdje detekcija verzije ne radi ispravno.", "downloadingX": "Preuzimanje {}", + "downloadX": "Download {}", + "downloadedX": "Downloaded {}", + "releaseAsset": "Release Asset", "downloadNotifDescription": "Obavještava korisnika o napretku u preuzimanju aplikacije", "noAPKFound": "APK nije pronađen", "noVersionDetection": "Nema detekcije verzije", diff --git a/assets/translations/cs.json b/assets/translations/cs.json index 33fa372..52d23b4 100644 --- a/assets/translations/cs.json +++ b/assets/translations/cs.json @@ -183,6 +183,9 @@ "disableVersionDetection": "Deaktivovat detekci verze", "noVersionDetectionExplanation": "Tato možnost by měla být použita pouze u aplikace, kde detekce verzí nefunguje správně.", "downloadingX": "Stáhnout {}", + "downloadX": "Stáhnout {}", + "downloadedX": "Staženo {}", + "releaseAsset": "Vydání aktiva", "downloadNotifDescription": "Informuje uživatele o průběhu stahování aplikace", "noAPKFound": "Žádná APK nebyla nalezena", "noVersionDetection": "Žádná detekce verze", diff --git a/assets/translations/de.json b/assets/translations/de.json index 4d711bf..58f6873 100644 --- a/assets/translations/de.json +++ b/assets/translations/de.json @@ -183,6 +183,9 @@ "disableVersionDetection": "Versionsermittlung deaktivieren", "noVersionDetectionExplanation": "Diese Option sollte nur für Apps verwendet werden, bei denen die Versionserkennung nicht korrekt funktioniert.", "downloadingX": "Lade {} herunter", + "downloadX": "Herunterladen {}", + "downloadedX": "Heruntergeladen {}", + "releaseAsset": "Asset freigeben", "downloadNotifDescription": "Benachrichtigt den Nutzer über den Fortschritt beim Herunterladen einer App", "noAPKFound": "Keine APK gefunden", "noVersionDetection": "Keine Versionserkennung", diff --git a/assets/translations/en.json b/assets/translations/en.json index 23b389e..7b52dc7 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -183,6 +183,9 @@ "disableVersionDetection": "Disable Version Detection", "noVersionDetectionExplanation": "This option should only be used for Apps where version detection does not work correctly.", "downloadingX": "Downloading {}", + "downloadX": "Download {}", + "downloadedX": "Downloaded {}", + "releaseAsset": "Release Asset", "downloadNotifDescription": "Notifies the user of the progress in downloading an App", "noAPKFound": "No APK found", "noVersionDetection": "No version detection", diff --git a/assets/translations/es.json b/assets/translations/es.json index 873a1d4..e0020fb 100644 --- a/assets/translations/es.json +++ b/assets/translations/es.json @@ -183,6 +183,9 @@ "disableVersionDetection": "Desactivar la detección de versiones", "noVersionDetectionExplanation": "Esta opción solo se debe usar en aplicaciones en las que la deteción de versiones pueda que no funcionar correctamente.", "downloadingX": "Descargando {}", + "downloadX": "Descargar {}", + "downloadedX": "Descargado {}", + "releaseAsset": "Liberar activos", "downloadNotifDescription": "Notifica al usuario del progreso de descarga de una aplicación", "noAPKFound": "No se encontró el paquete de instalación APK", "noVersionDetection": "Sin detección de versiones", diff --git a/assets/translations/fa.json b/assets/translations/fa.json index 10731d6..3b785eb 100644 --- a/assets/translations/fa.json +++ b/assets/translations/fa.json @@ -183,6 +183,9 @@ "disableVersionDetection": "غیرفعال کردن تشخیص نسخه", "noVersionDetectionExplanation": "این گزینه فقط باید برای برنامه هایی استفاده شود که تشخیص نسخه به درستی کار نمی کند.", "downloadingX": "در حال دانلود {}", + "downloadX": "Download {}", + "downloadedX": "Downloaded {}", + "releaseAsset": "Release Asset", "downloadNotifDescription": "کاربر را از پیشرفت دانلود یک برنامه مطلع می کند", "noAPKFound": "APK پیدا نشد فایل", "noVersionDetection": "بدون تشخیص نسخه", diff --git a/assets/translations/fr.json b/assets/translations/fr.json index 61be34e..9e60af6 100644 --- a/assets/translations/fr.json +++ b/assets/translations/fr.json @@ -183,6 +183,9 @@ "disableVersionDetection": "Désactiver la détection de version", "noVersionDetectionExplanation": "Cette option ne doit être utilisée que pour les applications où la détection de version ne fonctionne pas correctement.", "downloadingX": "Téléchargement {}", + "downloadX": "Télécharger {}", + "downloadedX": "Téléchargé {}", + "releaseAsset": "Actif libéré", "downloadNotifDescription": "Avertit l'utilisateur de la progression du téléchargement d'une application", "noAPKFound": "Aucun APK trouvé", "noVersionDetection": "Pas de détection de version", diff --git a/assets/translations/hu.json b/assets/translations/hu.json index 5e9c669..a5dc4bc 100644 --- a/assets/translations/hu.json +++ b/assets/translations/hu.json @@ -183,6 +183,9 @@ "disableVersionDetection": "Verzió érzékelés letiltása", "noVersionDetectionExplanation": "Ezt a beállítást csak olyan alkalmazásoknál szabad használni, ahol a verzióérzékelés nem működik megfelelően.", "downloadingX": "{} letöltés", + "downloadX": "Letöltés {}", + "downloadedX": "Letöltés {}", + "releaseAsset": "Release Asset", "downloadNotifDescription": "Értesíti a felhasználót az app letöltésének előrehaladásáról", "noAPKFound": "Nem található APK", "noVersionDetection": "Nincs verzió érzékelés", diff --git a/assets/translations/it.json b/assets/translations/it.json index e6aa2a4..e0b6af0 100644 --- a/assets/translations/it.json +++ b/assets/translations/it.json @@ -183,6 +183,9 @@ "disableVersionDetection": "Disattiva il rilevamento della versione", "noVersionDetectionExplanation": "Questa opzione dovrebbe essere usata solo per le app la cui versione non viene rilevata correttamente.", "downloadingX": "Scaricamento di {} in corso", + "downloadX": "Scarica {}", + "downloadedX": "Scaricato {}", + "releaseAsset": "Rilascio Asset", "downloadNotifDescription": "Notifica all'utente lo stato di avanzamento del download di un'app", "noAPKFound": "Nessun APK trovato", "noVersionDetection": "Disattiva rilevamento di versione", diff --git a/assets/translations/ja.json b/assets/translations/ja.json index 171167e..dba7734 100644 --- a/assets/translations/ja.json +++ b/assets/translations/ja.json @@ -183,6 +183,9 @@ "disableVersionDetection": "バージョン検出を無効にする", "noVersionDetectionExplanation": "このオプションは、バージョン検出が正しく機能しないアプリにのみ使用する必要があります。", "downloadingX": "{} をダウンロード中", + "downloadX": "ダウンロード", + "downloadedX": "ダウンロード", + "releaseAsset": "リリース資産", "downloadNotifDescription": "アプリのダウンロード状況を通知する", "noAPKFound": "APKが見つかりません", "noVersionDetection": "バージョン検出を行わない", diff --git a/assets/translations/nl.json b/assets/translations/nl.json index 845676d..417ec3b 100644 --- a/assets/translations/nl.json +++ b/assets/translations/nl.json @@ -183,6 +183,9 @@ "disableVersionDetection": "Versieherkenning uitschakelen", "noVersionDetectionExplanation": "Deze optie moet alleen worden gebruikt voor apps waar versieherkenning niet correct werkt.", "downloadingX": "Downloaden {}", + "downloadX": "Downloaden", + "downloadedX": "Gedownload {}", + "releaseAsset": "Release Activa", "downloadNotifDescription": "Stelt de gebruiker op de hoogte van de voortgang bij het downloaden van een app", "noAPKFound": "Geen APK gevonden", "noVersionDetection": "Geen versieherkenning", diff --git a/assets/translations/pl.json b/assets/translations/pl.json index c017f93..3886a0c 100644 --- a/assets/translations/pl.json +++ b/assets/translations/pl.json @@ -183,6 +183,9 @@ "disableVersionDetection": "Wyłącz wykrywanie wersji", "noVersionDetectionExplanation": "Opcja ta powinna być używana tylko w przypadku aplikacji, w których wykrywanie wersji nie działa poprawnie.", "downloadingX": "Pobieranie {}", + "downloadX": "Pobierz {}", + "downloadedX": "Pobrano {}", + "releaseAsset": "Release Asset", "downloadNotifDescription": "Informuje o postępach w pobieraniu aplikacji", "noAPKFound": "Nie znaleziono pakietu APK", "noVersionDetection": "Bez wykrywania wersji", diff --git a/assets/translations/pt.json b/assets/translations/pt.json index c2281d9..a8b170f 100644 --- a/assets/translations/pt.json +++ b/assets/translations/pt.json @@ -183,6 +183,9 @@ "disableVersionDetection": "Desativar detecção de versão", "noVersionDetectionExplanation": "Essa opção deve apenas ser usada por aplicativos onde a detecção de versão não funciona corretamente.", "downloadingX": "Baixando {}", + "downloadX": "Descarregar {}", + "downloadedX": "Descarregado {}", + "releaseAsset": "Libertação de activos", "downloadNotifDescription": "Notifica o usuário o progresso do download de um aplicativo", "noAPKFound": "APK não encontrado", "noVersionDetection": "Sem detecção de versão", diff --git a/assets/translations/ru.json b/assets/translations/ru.json index c5233d5..0fcad3b 100644 --- a/assets/translations/ru.json +++ b/assets/translations/ru.json @@ -183,6 +183,9 @@ "disableVersionDetection": "Отключить обнаружение версии", "noVersionDetectionExplanation": "Эта настройка должна использоваться только для приложений, где обнаружение версии не работает корректно", "downloadingX": "Загрузка {}", + "downloadX": "Скачать {}", + "downloadedX": "Загружено {}", + "releaseAsset": "Освобождение актива", "downloadNotifDescription": "Уведомляет пользователя о прогрессе загрузки приложения", "noAPKFound": "APK не найден", "noVersionDetection": "Обнаружение версий отключено", diff --git a/assets/translations/sv.json b/assets/translations/sv.json index 5713536..f77c5d3 100644 --- a/assets/translations/sv.json +++ b/assets/translations/sv.json @@ -183,6 +183,9 @@ "disableVersionDetection": "Inaktivera versionsdetektering", "noVersionDetectionExplanation": "Det här alternativet bör endast användas för appar där versionsidentifiering inte fungerar korrekt.", "downloadingX": "Laddar ner {}", + "downloadX": "Ladda ner {}", + "downloadedX": "Nedladdad {}", + "releaseAsset": "Frigör tillgång", "downloadNotifDescription": "Meddelar användaren om framstegen med att ladda ner en app", "noAPKFound": "Ingen APK funnen", "noVersionDetection": "Ingen versiondetektering", diff --git a/assets/translations/tr.json b/assets/translations/tr.json index 176663a..db1df8e 100644 --- a/assets/translations/tr.json +++ b/assets/translations/tr.json @@ -183,6 +183,9 @@ "disableVersionDetection": "Sürüm Algılama Devre Dışı", "noVersionDetectionExplanation": "Bu seçenek, sürüm algılamanın doğru çalışmadığı uygulamalar için kullanılmalıdır.", "downloadingX": "{} İndiriliyor", + "downloadX": "İndir {}", + "downloadedX": "İndirildi {}", + "releaseAsset": "Varlık Serbest Bırakma", "downloadNotifDescription": "Bir uygulamanın indirme sürecinde ilerlemeyi bildiren bir bildirim", "noAPKFound": "APK bulunamadı", "noVersionDetection": "Sürüm Algılanamıyor", diff --git a/assets/translations/uk.json b/assets/translations/uk.json index 327d5fa..b2de35c 100644 --- a/assets/translations/uk.json +++ b/assets/translations/uk.json @@ -183,6 +183,9 @@ "disableVersionDetection": "Вимкнути визначення версії", "noVersionDetectionExplanation": "Цю опцію слід використовувати лише для застосунків, де визначення версії працює неправильно.", "downloadingX": "Завантаження {}", + "downloadX": "Завантажити {}", + "downloadedX": "Завантажено {}", + "releaseAsset": "Звільнити актив", "downloadNotifDescription": "Повідомляє користувача про прогрес завантаження застосунку", "noAPKFound": "APK не знайдено", "noVersionDetection": "Визначення версії відключено", diff --git a/assets/translations/vi.json b/assets/translations/vi.json index bd82a12..4259cf0 100644 --- a/assets/translations/vi.json +++ b/assets/translations/vi.json @@ -183,6 +183,9 @@ "disableVersionDetection": "Tắt tính năng phát hiện phiên bản", "noVersionDetectionExplanation": "Chỉ nên sử dụng tùy chọn này cho Ứng dụng mà tính năng phát hiện phiên bản không hoạt động chính xác.", "downloadingX": "Đang tải xuống {}", + "downloadX": "Download {}", + "downloadedX": "Downloaded {}", + "releaseAsset": "Release Asset", "downloadNotifDescription": "Thông báo cho người dùng về tiến trình tải xuống Ứng dụng", "noAPKFound": "Không tìm thấy APK", "noVersionDetection": "Không phát hiện phiên bản", diff --git a/assets/translations/zh.json b/assets/translations/zh.json index ed1482c..8ee9682 100644 --- a/assets/translations/zh.json +++ b/assets/translations/zh.json @@ -183,6 +183,9 @@ "disableVersionDetection": "禁用版本检测", "noVersionDetectionExplanation": "此选项应该仅用于无法进行版本检测的应用。", "downloadingX": "正在下载“{}”", + "downloadX": "下载 {}", + "downloadedX": "下载 {}", + "releaseAsset": "释放资产", "downloadNotifDescription": "提示应用的下载进度", "noAPKFound": "未找到 APK 文件", "noVersionDetection": "禁用版本检测", diff --git a/lib/app_sources/github.dart b/lib/app_sources/github.dart index f6e2615..c7aa120 100644 --- a/lib/app_sources/github.dart +++ b/lib/app_sources/github.dart @@ -271,17 +271,14 @@ class GitHub extends AppSource { } } - List> getReleaseAPKUrls(dynamic release) => - (release['assets'] as List?) - ?.map((e) { - return (e['name'] != null) && - ((e['url'] ?? e['browser_download_url']) != null) - ? MapEntry(e['name'] as String, - (e['url'] ?? e['browser_download_url']) as String) - : const MapEntry('', ''); - }) - .where((element) => element.key.toLowerCase().endsWith('.apk')) - .toList() ?? + List> getReleaseAssetUrls(dynamic release) => + (release['assets'] as List?)?.map((e) { + return (e['name'] != null) && + ((e['url'] ?? e['browser_download_url']) != null) + ? MapEntry(e['name'] as String, + (e['url'] ?? e['browser_download_url']) as String) + : const MapEntry('', ''); + }).toList() ?? []; DateTime? getPublishDateFromRelease(dynamic rel) => @@ -383,7 +380,11 @@ class GitHub extends AppSource { .hasMatch(((releases[i]['body'] as String?) ?? '').trim())) { continue; } - var apkUrls = getReleaseAPKUrls(releases[i]); + var allAssetUrls = getReleaseAssetUrls(releases[i]); + List> apkUrls = allAssetUrls + .where((element) => element.key.toLowerCase().endsWith('.apk')) + .toList(); + apkUrls = filterApks(apkUrls, additionalSettings['apkFilterRegEx'], additionalSettings['invertAPKFilter']); if (apkUrls.isEmpty && additionalSettings['trackOnly'] != true) { @@ -391,12 +392,25 @@ class GitHub extends AppSource { } targetRelease = releases[i]; targetRelease['apkUrls'] = apkUrls; + targetRelease['version'] = + targetRelease['tag_name'] ?? targetRelease['name']; + if (targetRelease['tarball_url'] != null) { + allAssetUrls.add(MapEntry( + (targetRelease['version'] ?? 'source') + '.tar.gz', + targetRelease['tarball_url'])); + } + if (targetRelease['zipball_url'] != null) { + allAssetUrls.add(MapEntry( + (targetRelease['version'] ?? 'source') + '.zip', + targetRelease['zipball_url'])); + } + targetRelease['allAssetUrls'] = allAssetUrls; break; } if (targetRelease == null) { throw NoReleasesError(); } - String? version = targetRelease['tag_name'] ?? targetRelease['name']; + String? version = targetRelease['version']; DateTime? releaseDate = getReleaseDateFromRelease( targetRelease, useLatestAssetDateAsReleaseDate); if (version == null) { @@ -408,7 +422,9 @@ class GitHub extends AppSource { targetRelease['apkUrls'] as List>, getAppNames(standardUrl), releaseDate: releaseDate, - changeLog: changeLog.isEmpty ? null : changeLog); + changeLog: changeLog.isEmpty ? null : changeLog, + allAssetUrls: + targetRelease['allAssetUrls'] as List>); } else { if (onHttpErrorCode != null) { onHttpErrorCode(res); diff --git a/lib/pages/app.dart b/lib/pages/app.dart index 6970cb3..3b76d21 100644 --- a/lib/pages/app.dart +++ b/lib/pages/app.dart @@ -1,12 +1,15 @@ +import 'package:animations/animations.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.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/pages/apps.dart'; import 'package:obtainium/pages/settings.dart'; import 'package:obtainium/providers/apps_provider.dart'; +import 'package:obtainium/providers/notifications_provider.dart'; import 'package:obtainium/providers/settings_provider.dart'; import 'package:obtainium/providers/source_provider.dart'; import 'package:url_launcher/url_launcher_string.dart'; @@ -158,6 +161,87 @@ class _AppPageState extends State { textAlign: TextAlign.center, style: const TextStyle(fontStyle: FontStyle.italic, fontSize: 12), ), + if (app?.app.apkUrls.isNotEmpty == true || + app?.app.otherAssetUrls.isNotEmpty == true) + GestureDetector( + onTap: app?.app == null || updating + ? null + : () async { + var allAssetUrls = [ + ...app!.app.apkUrls, + ...app.app.otherAssetUrls + ].map((e) => MapEntry(e.value, e.key)).toList(); + var values = await showModal( + context: globalNavigatorKey.currentContext ?? context, + builder: (BuildContext ctx) { + return GeneratedFormModal( + title: + tr('downloadX', args: [tr('releaseAsset')]), + initValid: true, + items: [ + [ + GeneratedFormDropdown( + 'assetToDownload', allAssetUrls, + defaultValue: allAssetUrls[0].key, + label: tr('selectX', args: [ + tr('releaseAsset').toLowerCase() + ])) + ] + ]); + }, + ); + + if (values != null) { + var downloadUrl = values['assetToDownload'] as String; + var fileName = allAssetUrls + .where((e) => e.key == downloadUrl) + .first + .value; + NotificationsProvider notificationsProvider = + (globalNavigatorKey.currentContext ?? context) + .read(); + try { + showMessage( + '${tr('downloadingX', args: [fileName])}...', + globalNavigatorKey.currentContext ?? context); + await downloadFile( + downloadUrl, + fileName + .split('.') + .reversed + .toList() + .sublist(1) + .reversed + .join('.'), (double? progress) { + notificationsProvider.notify(DownloadNotification( + fileName, progress?.ceil() ?? 0)); + }, '/storage/emulated/0/Download', + headers: await source?.getRequestHeaders( + app.app.additionalSettings, + forAPKDownload: fileName.endsWith('.apk') + ? true + : false)); + notificationsProvider.notify( + DownloadedNotification(fileName, downloadUrl)); + } catch (e) { + showError( + e, globalNavigatorKey.currentContext ?? context); + } finally { + notificationsProvider + .cancel(DownloadNotification(fileName, 0).id); + } + } + }, + child: Text( + tr('downloadX', args: [tr('releaseAsset').toLowerCase()]), + textAlign: TextAlign.center, + style: Theme.of(context).textTheme.labelSmall!.copyWith( + decoration: + changeLogFn != null ? TextDecoration.underline : null, + fontStyle: changeLogFn != null ? FontStyle.italic : null, + ), + ), + ), const SizedBox( height: 48, ), diff --git a/lib/providers/notifications_provider.dart b/lib/providers/notifications_provider.dart index 851fb18..898126b 100644 --- a/lib/providers/notifications_provider.dart +++ b/lib/providers/notifications_provider.dart @@ -120,6 +120,18 @@ class DownloadNotification extends ObtainiumNotification { progPercent: progPercent); } +class DownloadedNotification extends ObtainiumNotification { + DownloadedNotification(String fileName, String downloadUrl) + : super( + downloadUrl.hashCode, + tr('downloadedX', args: [fileName]), + '', + 'FILE_DOWNLOADED', + tr('downloadedXNotifChannel', args: [tr('app')]), + tr('downloadedX', args: [tr('app')]), + Importance.defaultImportance); +} + final completeInstallationNotification = ObtainiumNotification( 1, tr('completeAppInstallation'), diff --git a/lib/providers/source_provider.dart b/lib/providers/source_provider.dart index 7761f61..d69b33e 100644 --- a/lib/providers/source_provider.dart +++ b/lib/providers/source_provider.dart @@ -47,9 +47,10 @@ class APKDetails { late AppNames names; late DateTime? releaseDate; late String? changeLog; + late List> allAssetUrls; APKDetails(this.version, this.apkUrls, this.names, - {this.releaseDate, this.changeLog}); + {this.releaseDate, this.changeLog, this.allAssetUrls = const []}); } stringMapListTo2DList(List> mapList) => @@ -223,6 +224,7 @@ class App { String? installedVersion; late String latestVersion; List> apkUrls = []; + List> otherAssetUrls = []; late int preferredApkIndex; late Map additionalSettings; late DateTime? lastUpdateCheck; @@ -248,7 +250,8 @@ class App { this.releaseDate, this.changeLog, this.overrideSource, - this.allowIdChange = false}); + this.allowIdChange = false, + this.otherAssetUrls = const []}); @override String toString() { @@ -280,41 +283,44 @@ class App { changeLog: changeLog, releaseDate: releaseDate, overrideSource: overrideSource, - allowIdChange: allowIdChange); + allowIdChange: allowIdChange, + otherAssetUrls: otherAssetUrls); factory App.fromJson(Map json) { json = appJSONCompatibilityModifiers(json); return App( - json['id'] as String, - json['url'] as String, - json['author'] as String, - json['name'] as String, - json['installedVersion'] == null - ? null - : json['installedVersion'] as String, - (json['latestVersion'] ?? tr('unknown')) as String, - assumed2DlistToStringMapList(jsonDecode( - (json['apkUrls'] ?? '[["placeholder", "placeholder"]]'))), - (json['preferredApkIndex'] ?? -1) as int, - jsonDecode(json['additionalSettings']) as Map, - json['lastUpdateCheck'] == null - ? null - : DateTime.fromMicrosecondsSinceEpoch(json['lastUpdateCheck']), - json['pinned'] ?? false, - categories: json['categories'] != null - ? (json['categories'] as List) - .map((e) => e.toString()) - .toList() - : json['category'] != null - ? [json['category'] as String] - : [], - releaseDate: json['releaseDate'] == null - ? null - : DateTime.fromMicrosecondsSinceEpoch(json['releaseDate']), - changeLog: - json['changeLog'] == null ? null : json['changeLog'] as String, - overrideSource: json['overrideSource'], - allowIdChange: json['allowIdChange'] ?? false); + json['id'] as String, + json['url'] as String, + json['author'] as String, + json['name'] as String, + json['installedVersion'] == null + ? null + : json['installedVersion'] as String, + (json['latestVersion'] ?? tr('unknown')) as String, + assumed2DlistToStringMapList( + jsonDecode((json['apkUrls'] ?? '[["placeholder", "placeholder"]]'))), + (json['preferredApkIndex'] ?? -1) as int, + jsonDecode(json['additionalSettings']) as Map, + json['lastUpdateCheck'] == null + ? null + : DateTime.fromMicrosecondsSinceEpoch(json['lastUpdateCheck']), + json['pinned'] ?? false, + categories: json['categories'] != null + ? (json['categories'] as List) + .map((e) => e.toString()) + .toList() + : json['category'] != null + ? [json['category'] as String] + : [], + releaseDate: json['releaseDate'] == null + ? null + : DateTime.fromMicrosecondsSinceEpoch(json['releaseDate']), + changeLog: json['changeLog'] == null ? null : json['changeLog'] as String, + overrideSource: json['overrideSource'], + allowIdChange: json['allowIdChange'] ?? false, + otherAssetUrls: assumed2DlistToStringMapList( + jsonDecode((json['otherAssetUrls'] ?? '[]'))), + ); } Map toJson() => { @@ -325,6 +331,7 @@ class App { 'installedVersion': installedVersion, 'latestVersion': latestVersion, 'apkUrls': jsonEncode(stringMapListTo2DList(apkUrls)), + 'otherAssetUrls': jsonEncode(stringMapListTo2DList(otherAssetUrls)), 'preferredApkIndex': preferredApkIndex, 'additionalSettings': jsonEncode(additionalSettings), 'lastUpdateCheck': lastUpdateCheck?.microsecondsSinceEpoch, @@ -892,8 +899,10 @@ class SourceProvider { allowIdChange: currentApp?.allowIdChange ?? trackOnly || (source.appIdInferIsOptional && - inferAppIdIfOptional) // Optional ID inferring may be incorrect - allow correction on first install - ); + inferAppIdIfOptional), // Optional ID inferring may be incorrect - allow correction on first install + otherAssetUrls: apk.allAssetUrls + .where((a) => apk.apkUrls.indexWhere((p) => a.key == p.key) < 0) + .toList()); return source.endOfGetAppChanges(finalApp); }