Added external APK support (GitLab only for now)

This commit is contained in:
Imran Remtulla
2022-09-03 16:12:25 -04:00
parent d643d5a474
commit c30c692d87
2 changed files with 65 additions and 7 deletions

View File

@@ -108,6 +108,7 @@ class AppsProvider with ChangeNotifier {
if (apps[id] == null) {
throw 'App not found';
}
// If the App has more than one APK, the user should pick one
String? apkUrl = apps[id]!.app.apkUrls[apps[id]!.app.preferredApkIndex];
if (apps[id]!.app.apkUrls.length > 1) {
apkUrl = await showDialog(
@@ -116,6 +117,19 @@ class AppsProvider with ChangeNotifier {
return APKPicker(app: apps[id]!.app, initVal: apkUrl);
});
}
// If the picked APK comes from an origin different from the source, get user confirmation
if (apkUrl != null &&
!apkUrl.toLowerCase().startsWith(apps[id]!.app.url.toLowerCase())) {
if (await showDialog(
context: context,
builder: (BuildContext ctx) {
return APKOriginWarningDialog(
sourceUrl: apps[id]!.app.url, apkUrl: apkUrl!);
}) !=
true) {
apkUrl = null;
}
}
if (apkUrl != null) {
int urlInd = apps[id]!.app.apkUrls.indexOf(apkUrl);
if (urlInd != apps[id]!.app.preferredApkIndex) {
@@ -331,7 +345,7 @@ class _APKPickerState extends State<APKPicker> {
child: const Text('Cancel')),
TextButton(
onPressed: () {
HapticFeedback.mediumImpact();
HapticFeedback.heavyImpact();
Navigator.of(context).pop(apkUrl);
},
child: const Text('Continue'))
@@ -339,3 +353,40 @@ class _APKPickerState extends State<APKPicker> {
);
}
}
class APKOriginWarningDialog extends StatefulWidget {
const APKOriginWarningDialog(
{super.key, required this.sourceUrl, required this.apkUrl});
final String sourceUrl;
final String apkUrl;
@override
State<APKOriginWarningDialog> createState() => _APKOriginWarningDialogState();
}
class _APKOriginWarningDialogState extends State<APKOriginWarningDialog> {
@override
Widget build(BuildContext context) {
return AlertDialog(
scrollable: true,
title: const Text('Warning'),
content: Text(
'The App source is \'${Uri.parse(widget.sourceUrl).host}\' but the release package comes from \'${Uri.parse(widget.apkUrl).host}\'. Continue?'),
actions: [
TextButton(
onPressed: () {
HapticFeedback.lightImpact();
Navigator.of(context).pop(null);
},
child: const Text('Cancel')),
TextButton(
onPressed: () {
HapticFeedback.heavyImpact();
Navigator.of(context).pop(true);
},
child: const Text('Continue'))
],
);
}
}

View File

@@ -170,12 +170,19 @@ class GitLab implements AppSource {
var entry = parsedHtml.querySelector('entry');
var entryContent =
parse(parseFragment(entry?.querySelector('content')!.innerHtml).text);
var apkUrlList = getLinksFromParsedHTML(
entryContent,
RegExp(
'^${escapeRegEx(standardUri.path)}/uploads/[^/]+/[^/]+\\.apk\$',
caseSensitive: false),
standardUri.origin);
var apkUrlList = [
...getLinksFromParsedHTML(
entryContent,
RegExp(
'^${escapeRegEx(standardUri.path)}/uploads/[^/]+/[^/]+\\.apk\$',
caseSensitive: false),
standardUri.origin),
// GitLab releases may contain links to externally hosted APKs
...getLinksFromParsedHTML(entryContent,
RegExp('/[^/]+\\.apk\$', caseSensitive: false), '')
.where((element) => Uri.parse(element).host != '')
.toList()
];
if (apkUrlList.isEmpty) {
throw 'No APK found';
}