mirror of
https://github.com/ImranR98/Obtainium.git
synced 2025-11-10 18:13:29 +01:00
UI improvements
This commit is contained in:
@@ -7,7 +7,6 @@ import 'package:obtainium/main.dart';
|
|||||||
import 'package:obtainium/pages/apps.dart';
|
import 'package:obtainium/pages/apps.dart';
|
||||||
import 'package:obtainium/pages/settings.dart';
|
import 'package:obtainium/pages/settings.dart';
|
||||||
import 'package:obtainium/providers/apps_provider.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/settings_provider.dart';
|
||||||
import 'package:obtainium/providers/source_provider.dart';
|
import 'package:obtainium/providers/source_provider.dart';
|
||||||
import 'package:url_launcher/url_launcher_string.dart';
|
import 'package:url_launcher/url_launcher_string.dart';
|
||||||
@@ -165,42 +164,11 @@ class _AppPageState extends State<AppPage> {
|
|||||||
onTap: app?.app == null || updating
|
onTap: app?.app == null || updating
|
||||||
? null
|
? null
|
||||||
: () async {
|
: () async {
|
||||||
var fileUrl = await appsProvider.confirmAppFileUrl(
|
try {
|
||||||
app!.app, context, true);
|
await appsProvider
|
||||||
if (fileUrl != null) {
|
.downloadAppAssets([app!.app.id], context);
|
||||||
NotificationsProvider notificationsProvider =
|
} catch (e) {
|
||||||
(globalNavigatorKey.currentContext ?? context)
|
showError(e, 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));
|
|
||||||
} catch (e) {
|
|
||||||
showError(
|
|
||||||
e, globalNavigatorKey.currentContext ?? context);
|
|
||||||
} finally {
|
|
||||||
notificationsProvider
|
|
||||||
.cancel(DownloadNotification(fileUrl.key, 0).id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: Text(
|
child: Text(
|
||||||
|
|||||||
@@ -854,69 +854,78 @@ class AppsPageState extends State<AppsPage> {
|
|||||||
scrollable: true,
|
scrollable: true,
|
||||||
content: Padding(
|
content: Padding(
|
||||||
padding: const EdgeInsets.only(top: 6),
|
padding: const EdgeInsets.only(top: 6),
|
||||||
child: Row(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
children: [
|
children: [
|
||||||
IconButton(
|
TextButton(
|
||||||
|
onPressed: pinSelectedApps,
|
||||||
|
child: Text(selectedApps
|
||||||
|
.where((element) => element.pinned)
|
||||||
|
.isEmpty
|
||||||
|
? tr('pinToTop')
|
||||||
|
: tr('unpinFromTop'))),
|
||||||
|
const Divider(),
|
||||||
|
TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
String urls = '';
|
||||||
|
for (var a in selectedApps) {
|
||||||
|
urls += '${a.url}\n';
|
||||||
|
}
|
||||||
|
urls = urls.substring(0, urls.length - 1);
|
||||||
|
Share.share(urls,
|
||||||
|
subject: 'Obtainium - ${tr('appsString')}');
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
child: Text(tr('shareSelectedAppURLs'))),
|
||||||
|
const Divider(),
|
||||||
|
TextButton(
|
||||||
|
onPressed: selectedAppIds.isEmpty
|
||||||
|
? null
|
||||||
|
: () {
|
||||||
|
String urls =
|
||||||
|
'<p>${tr('customLinkMessage')}:</p>\n\n<ul>\n';
|
||||||
|
for (var a in selectedApps) {
|
||||||
|
urls +=
|
||||||
|
' <li><a href="obtainium://app/${Uri.encodeComponent(jsonEncode({
|
||||||
|
'id': a.id,
|
||||||
|
'url': a.url,
|
||||||
|
'author': a.author,
|
||||||
|
'name': a.name,
|
||||||
|
'preferredApkIndex':
|
||||||
|
a.preferredApkIndex,
|
||||||
|
'additionalSettings':
|
||||||
|
jsonEncode(a.additionalSettings)
|
||||||
|
}))}">${a.name}</a></li>\n';
|
||||||
|
}
|
||||||
|
urls +=
|
||||||
|
'</ul>\n\n<p><a href="$obtainiumUrl">${tr('about')}</a></p>';
|
||||||
|
Share.share(urls,
|
||||||
|
subject:
|
||||||
|
'Obtainium - ${tr('appsString')}');
|
||||||
|
},
|
||||||
|
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()
|
onPressed: appsProvider.areDownloadsRunning()
|
||||||
? null
|
? null
|
||||||
: showMassMarkDialog,
|
: showMassMarkDialog,
|
||||||
tooltip: tr('markSelectedAppsUpdated'),
|
child: Text(tr('markSelectedAppsUpdated'))),
|
||||||
icon: const Icon(Icons.done)),
|
|
||||||
IconButton(
|
|
||||||
onPressed: pinSelectedApps,
|
|
||||||
tooltip: 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(
|
|
||||||
onPressed: () {
|
|
||||||
String urls = '';
|
|
||||||
for (var a in selectedApps) {
|
|
||||||
urls += '${a.url}\n';
|
|
||||||
}
|
|
||||||
urls = urls.substring(0, urls.length - 1);
|
|
||||||
Share.share(urls,
|
|
||||||
subject: 'Obtainium - ${tr('appsString')}');
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
},
|
|
||||||
tooltip: tr('shareSelectedAppURLs'),
|
|
||||||
icon: const Icon(Icons.share_rounded),
|
|
||||||
),
|
|
||||||
IconButton(
|
|
||||||
onPressed: selectedAppIds.isEmpty
|
|
||||||
? null
|
|
||||||
: () {
|
|
||||||
String urls =
|
|
||||||
'<p>${tr('customLinkMessage')}:</p>\n\n<ul>\n';
|
|
||||||
for (var a in selectedApps) {
|
|
||||||
urls +=
|
|
||||||
' <li><a href="obtainium://app/${Uri.encodeComponent(jsonEncode({
|
|
||||||
'id': a.id,
|
|
||||||
'url': a.url,
|
|
||||||
'author': a.author,
|
|
||||||
'name': a.name,
|
|
||||||
'preferredApkIndex':
|
|
||||||
a.preferredApkIndex,
|
|
||||||
'additionalSettings':
|
|
||||||
jsonEncode(a.additionalSettings)
|
|
||||||
}))}">${a.name}</a></li>\n';
|
|
||||||
}
|
|
||||||
urls +=
|
|
||||||
'</ul>\n\n<p><a href="$obtainiumUrl">${tr('about')}</a></p>';
|
|
||||||
Share.share(urls,
|
|
||||||
subject: 'Obtainium - ${tr('appsString')}');
|
|
||||||
},
|
|
||||||
tooltip: tr('shareAppConfigLinks'),
|
|
||||||
icon: const Icon(Icons.ios_share),
|
|
||||||
),
|
|
||||||
]),
|
]),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -916,6 +916,73 @@ class AppsProvider with ChangeNotifier {
|
|||||||
return installedIds;
|
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 {
|
Future<Directory> getAppsDir() async {
|
||||||
Directory appsDir =
|
Directory appsDir =
|
||||||
Directory('${(await getExternalStorageDirectory())!.path}/app_data');
|
Directory('${(await getExternalStorageDirectory())!.path}/app_data');
|
||||||
|
|||||||
Reference in New Issue
Block a user