UI improvements

This commit is contained in:
Imran Remtulla
2024-04-07 02:13:36 -04:00
parent 00988ed04d
commit 1f9921e6ff
3 changed files with 139 additions and 95 deletions

View File

@@ -7,7 +7,6 @@ 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';
@@ -165,42 +164,11 @@ class _AppPageState extends State<AppPage> {
onTap: app?.app == null || updating
? null
: () async {
var fileUrl = await appsProvider.confirmAppFileUrl(
app!.app, context, true);
if (fileUrl != null) {
NotificationsProvider notificationsProvider =
(globalNavigatorKey.currentContext ?? context)
.read<NotificationsProvider>();
try {
showMessage(
'${tr('downloadingX', args: [fileUrl.key])}...',
globalNavigatorKey.currentContext ?? context);
await downloadFile(
fileUrl.value,
fileUrl.key
.split('.')
.reversed
.toList()
.sublist(1)
.reversed
.join('.'), (double? progress) {
notificationsProvider.notify(DownloadNotification(
fileUrl.key, progress?.ceil() ?? 0));
}, '/storage/emulated/0/Download',
headers: await source?.getRequestHeaders(
app.app.additionalSettings,
forAPKDownload: fileUrl.key.endsWith('.apk')
? true
: false));
notificationsProvider.notify(DownloadedNotification(
fileUrl.key, fileUrl.value));
await appsProvider
.downloadAppAssets([app!.app.id], context);
} catch (e) {
showError(
e, globalNavigatorKey.currentContext ?? context);
} finally {
notificationsProvider
.cancel(DownloadNotification(fileUrl.key, 0).id);
}
showError(e, context);
}
},
child: Text(

View File

@@ -854,29 +854,18 @@ class AppsPageState extends State<AppsPage> {
scrollable: true,
content: Padding(
padding: const EdgeInsets.only(top: 6),
child: Row(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
IconButton(
onPressed: appsProvider.areDownloadsRunning()
? null
: showMassMarkDialog,
tooltip: tr('markSelectedAppsUpdated'),
icon: const Icon(Icons.done)),
IconButton(
TextButton(
onPressed: pinSelectedApps,
tooltip: selectedApps
child: Text(selectedApps
.where((element) => element.pinned)
.isEmpty
? tr('pinToTop')
: tr('unpinFromTop'),
icon: Icon(selectedApps
.where((element) => element.pinned)
.isEmpty
? Icons.bookmark_outline_rounded
: Icons.bookmark_remove_outlined),
),
IconButton(
: tr('unpinFromTop'))),
const Divider(),
TextButton(
onPressed: () {
String urls = '';
for (var a in selectedApps) {
@@ -887,10 +876,9 @@ class AppsPageState extends State<AppsPage> {
subject: 'Obtainium - ${tr('appsString')}');
Navigator.of(context).pop();
},
tooltip: tr('shareSelectedAppURLs'),
icon: const Icon(Icons.share_rounded),
),
IconButton(
child: Text(tr('shareSelectedAppURLs'))),
const Divider(),
TextButton(
onPressed: selectedAppIds.isEmpty
? null
: () {
@@ -912,11 +900,32 @@ class AppsPageState extends State<AppsPage> {
urls +=
'</ul>\n\n<p><a href="$obtainiumUrl">${tr('about')}</a></p>';
Share.share(urls,
subject: 'Obtainium - ${tr('appsString')}');
subject:
'Obtainium - ${tr('appsString')}');
},
tooltip: tr('shareAppConfigLinks'),
icon: const Icon(Icons.ios_share),
),
child: Text(tr('shareAppConfigLinks'))),
const Divider(),
TextButton(
onPressed: () {
appsProvider
.downloadAppAssets(
selectedApps.map((e) => e.id).toList(),
globalNavigatorKey.currentContext ??
context)
.catchError((e) => showError(
e,
globalNavigatorKey.currentContext ??
context));
Navigator.of(context).pop();
},
child: Text(tr('downloadX',
args: [tr('releaseAsset').toLowerCase()]))),
const Divider(),
TextButton(
onPressed: appsProvider.areDownloadsRunning()
? null
: showMassMarkDialog,
child: Text(tr('markSelectedAppsUpdated'))),
]),
),
);

View File

@@ -916,6 +916,73 @@ class AppsProvider with ChangeNotifier {
return installedIds;
}
Future<List<String>> downloadAppAssets(
List<String> appIds, BuildContext context,
{bool forceParallelDownloads = false}) async {
NotificationsProvider notificationsProvider =
context.read<NotificationsProvider>();
List<MapEntry<MapEntry<String, String>, App>> filesToDownload = [];
for (var id in appIds) {
if (apps[id] == null) {
throw ObtainiumError(tr('appNotFound'));
}
MapEntry<String, String>? fileUrl;
if (apps[id]!.app.apkUrls.isNotEmpty ||
apps[id]!.app.otherAssetUrls.isNotEmpty) {
// ignore: use_build_context_synchronously
fileUrl = await confirmAppFileUrl(apps[id]!.app, context, true);
}
if (fileUrl != null) {
filesToDownload.add(MapEntry(fileUrl, apps[id]!.app));
}
}
// Prepare to download+install Apps
MultiAppMultiError errors = MultiAppMultiError();
List<String> downloadedIds = [];
Future<void> downloadFn(MapEntry<String, String> fileUrl, App app) async {
try {
await downloadFile(
fileUrl.value,
fileUrl.key
.split('.')
.reversed
.toList()
.sublist(1)
.reversed
.join('.'), (double? progress) {
notificationsProvider
.notify(DownloadNotification(fileUrl.key, progress?.ceil() ?? 0));
}, '/storage/emulated/0/Download',
headers: await SourceProvider()
.getSource(app.url, overrideSource: app.overrideSource)
.getRequestHeaders(app.additionalSettings,
forAPKDownload:
fileUrl.key.endsWith('.apk') ? true : false));
notificationsProvider
.notify(DownloadedNotification(fileUrl.key, fileUrl.value));
} catch (e) {
errors.add(fileUrl.key, e);
} finally {
notificationsProvider.cancel(DownloadNotification(fileUrl.key, 0).id);
}
}
if (forceParallelDownloads || !settingsProvider.parallelDownloads) {
for (var urlWithApp in filesToDownload) {
await downloadFn(urlWithApp.key, urlWithApp.value);
}
} else {
await Future.wait(filesToDownload
.map((urlWithApp) => downloadFn(urlWithApp.key, urlWithApp.value)));
}
if (errors.idsByErrorString.isNotEmpty) {
throw errors;
}
return downloadedIds;
}
Future<Directory> getAppsDir() async {
Directory appsDir =
Directory('${(await getExternalStorageDirectory())!.path}/app_data');