From 00988ed04d9da708416b3d905a94feac663f7bd8 Mon Sep 17 00:00:00 2001 From: Imran Remtulla Date: Sun, 7 Apr 2024 01:41:35 -0400 Subject: [PATCH] Improve release asset download UI --- lib/pages/add_app.dart | 3 +- lib/pages/app.dart | 51 ++++++------------------ lib/providers/apps_provider.dart | 68 ++++++++++++++++++++------------ 3 files changed, 55 insertions(+), 67 deletions(-) diff --git a/lib/pages/add_app.dart b/lib/pages/add_app.dart index e280519..5dc17b0 100644 --- a/lib/pages/add_app.dart +++ b/lib/pages/add_app.dart @@ -155,7 +155,8 @@ class AddAppPageState extends State { // Only download the APK here if you need to for the package ID if (isTempId(app) && app.additionalSettings['trackOnly'] != true) { // ignore: use_build_context_synchronously - var apkUrl = await appsProvider.confirmApkUrl(app, context); + var apkUrl = + await appsProvider.confirmAppFileUrl(app, context, false); if (apkUrl == null) { throw ObtainiumError(tr('cancelled')); } diff --git a/lib/pages/app.dart b/lib/pages/app.dart index 3b76d21..745542a 100644 --- a/lib/pages/app.dart +++ b/lib/pages/app.dart @@ -1,8 +1,6 @@ -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'; @@ -167,46 +165,19 @@ class _AppPageState extends State { 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; + var fileUrl = await appsProvider.confirmAppFileUrl( + app!.app, context, true); + if (fileUrl != null) { NotificationsProvider notificationsProvider = (globalNavigatorKey.currentContext ?? context) .read(); try { showMessage( - '${tr('downloadingX', args: [fileName])}...', + '${tr('downloadingX', args: [fileUrl.key])}...', globalNavigatorKey.currentContext ?? context); await downloadFile( - downloadUrl, - fileName + fileUrl.value, + fileUrl.key .split('.') .reversed .toList() @@ -214,21 +185,21 @@ class _AppPageState extends State { .reversed .join('.'), (double? progress) { notificationsProvider.notify(DownloadNotification( - fileName, progress?.ceil() ?? 0)); + fileUrl.key, progress?.ceil() ?? 0)); }, '/storage/emulated/0/Download', headers: await source?.getRequestHeaders( app.app.additionalSettings, - forAPKDownload: fileName.endsWith('.apk') + forAPKDownload: fileUrl.key.endsWith('.apk') ? true : false)); - notificationsProvider.notify( - DownloadedNotification(fileName, downloadUrl)); + notificationsProvider.notify(DownloadedNotification( + fileUrl.key, fileUrl.value)); } catch (e) { showError( e, globalNavigatorKey.currentContext ?? context); } finally { notificationsProvider - .cancel(DownloadNotification(fileName, 0).id); + .cancel(DownloadNotification(fileUrl.key, 0).id); } } }, diff --git a/lib/providers/apps_provider.dart b/lib/providers/apps_provider.dart index 743db8b..d926726 100644 --- a/lib/providers/apps_provider.dart +++ b/lib/providers/apps_provider.dart @@ -705,23 +705,28 @@ class AppsProvider with ChangeNotifier { await intent.launch(); } - Future?> confirmApkUrl( - App app, BuildContext? context) async { + Future?> confirmAppFileUrl( + App app, BuildContext? context, bool pickAnyAsset) async { + var urlsToSelectFrom = app.apkUrls; + if (pickAnyAsset) { + urlsToSelectFrom = [...urlsToSelectFrom, ...app.otherAssetUrls]; + } // If the App has more than one APK, the user should pick one (if context provided) - MapEntry? apkUrl = - app.apkUrls[app.preferredApkIndex >= 0 ? app.preferredApkIndex : 0]; + MapEntry? appFileUrl = urlsToSelectFrom[ + app.preferredApkIndex >= 0 ? app.preferredApkIndex : 0]; // get device supported architecture List archs = (await DeviceInfoPlugin().androidInfo).supportedAbis; - if (app.apkUrls.length > 1 && context != null) { + if (urlsToSelectFrom.length > 1 && context != null) { // ignore: use_build_context_synchronously - apkUrl = await showDialog( + appFileUrl = await showDialog( context: context, builder: (BuildContext ctx) { - return APKPicker( + return AppFilePicker( app: app, - initVal: apkUrl, + initVal: appFileUrl, archs: archs, + pickAnyAsset: pickAnyAsset, ); }); } @@ -731,8 +736,8 @@ class AppsProvider with ChangeNotifier { } // If the picked APK comes from an origin different from the source, get user confirmation (if context provided) - if (apkUrl != null && - getHost(apkUrl.value) != getHost(app.url) && + if (appFileUrl != null && + getHost(appFileUrl.value) != getHost(app.url) && context != null) { // ignore: use_build_context_synchronously if (!(settingsProvider.hideAPKOriginWarning) && @@ -741,13 +746,13 @@ class AppsProvider with ChangeNotifier { context: context, builder: (BuildContext ctx) { return APKOriginWarningDialog( - sourceUrl: app.url, apkUrl: apkUrl!.value); + sourceUrl: app.url, apkUrl: appFileUrl!.value); }) != true) { - apkUrl = null; + appFileUrl = null; } } - return apkUrl; + return appFileUrl; } // Given a list of AppIds, uses stored info about the apps to download APKs and install them @@ -774,7 +779,7 @@ class AppsProvider with ChangeNotifier { var trackOnly = apps[id]!.app.additionalSettings['trackOnly'] == true; if (!trackOnly) { // ignore: use_build_context_synchronously - apkUrl = await confirmApkUrl(apps[id]!.app, context); + apkUrl = await confirmAppFileUrl(apps[id]!.app, context, false); } if (apkUrl != null) { int urlInd = apps[id]! @@ -1482,38 +1487,49 @@ class AppsProvider with ChangeNotifier { } } -class APKPicker extends StatefulWidget { - const APKPicker({super.key, required this.app, this.initVal, this.archs}); +class AppFilePicker extends StatefulWidget { + const AppFilePicker( + {super.key, + required this.app, + this.initVal, + this.archs, + this.pickAnyAsset = false}); final App app; final MapEntry? initVal; final List? archs; + final bool pickAnyAsset; @override - State createState() => _APKPickerState(); + State createState() => _AppFilePickerState(); } -class _APKPickerState extends State { - MapEntry? apkUrl; +class _AppFilePickerState extends State { + MapEntry? fileUrl; @override Widget build(BuildContext context) { - apkUrl ??= widget.initVal; + fileUrl ??= widget.initVal; + var urlsToSelectFrom = widget.app.apkUrls; + if (widget.pickAnyAsset) { + urlsToSelectFrom = [...urlsToSelectFrom, ...widget.app.otherAssetUrls]; + } return AlertDialog( scrollable: true, - title: Text(tr('pickAnAPK')), + title: Text(widget.pickAnyAsset + ? tr('selectX', args: [tr('releaseAsset').toLowerCase()]) + : tr('pickAnAPK')), content: Column(children: [ Text(tr('appHasMoreThanOnePackage', args: [widget.app.finalName])), const SizedBox(height: 16), - ...widget.app.apkUrls.map( + ...urlsToSelectFrom.map( (u) => RadioListTile( title: Text(u.key), value: u.value, - groupValue: apkUrl!.value, + groupValue: fileUrl!.value, onChanged: (String? val) { setState(() { - apkUrl = - widget.app.apkUrls.where((e) => e.value == val).first; + fileUrl = urlsToSelectFrom.where((e) => e.value == val).first; }); }), ), @@ -1540,7 +1556,7 @@ class _APKPickerState extends State { TextButton( onPressed: () { HapticFeedback.selectionClick(); - Navigator.of(context).pop(apkUrl); + Navigator.of(context).pop(fileUrl); }, child: Text(tr('continue'))) ],