Added Signal.org, fixed bugs, UX tweaks, readme update

This commit is contained in:
Imran Remtulla
2022-08-27 17:47:08 -04:00
parent 5bdab1b1e4
commit 7e5affe1b8
5 changed files with 49 additions and 10 deletions

View File

@@ -1,4 +1,4 @@
# ![](./android/app/src/main/res/drawable/ic_notification.png) Obtainium
# ![Obtainium Icon](./android/app/src/main/res/drawable/ic_notification.png) Obtainium
Get Android App Updates Directly From the Source.
@@ -13,6 +13,7 @@ Motivation: [Side Of Burritos - You should use this instead of F-Droid | How to
## Limitations
- App installs are assumed to have succeeded; failures and cancelled installs cannot be detected.
- Auto (unattended) updates are unsupported due to a lack of any capable Flutter plugin.
- For GitHub, data is gathered using Web scraping and can easily break due to changes in website design. More reliable methods are either insufficient (GitHub RSS) or subject to rate limits (GitHub API). This may also apply to new sources added in the future.
## Screenshots

View File

@@ -46,14 +46,14 @@ class _AppPageState extends State<AppPage> {
appsProvider
.checkAppObjectForUpdate(
app!.app)) &&
app?.downloadProgress == null
!appsProvider.areDownloadsRunning()
? () {
HapticFeedback.heavyImpact();
appsProvider
.downloadAndInstallLatestApp(
[app!.app.id],
context).then((res) {
if (res) {
if (res && mounted) {
Navigator.of(context).pop();
}
});

View File

@@ -22,9 +22,7 @@ class _AppsPageState extends State<AppsPage> {
floatingActionButton: existingUpdateAppIds.isEmpty
? null
: ElevatedButton.icon(
onPressed: appsProvider.apps.values
.where((element) => element.downloadProgress != null)
.isNotEmpty
onPressed: appsProvider.areDownloadsRunning()
? null
: () {
HapticFeedback.heavyImpact();
@@ -60,7 +58,7 @@ class _AppsPageState extends State<AppsPage> {
e.app.installedVersion ?? 'Not Installed'),
trailing: e.downloadProgress != null
? Text(
'Downloading - ${e.downloadProgress!.toInt()}%')
'Downloading - ${e.downloadProgress?.toInt()}%')
: (e.app.installedVersion != null &&
e.app.installedVersion !=
e.app.latestVersion

View File

@@ -80,6 +80,10 @@ class AppsProvider with ChangeNotifier {
return ApkFile(appId, downloadFile);
}
bool areDownloadsRunning() => apps.values
.where((element) => element.downloadProgress != null)
.isNotEmpty;
// Given an AppId, uses stored info about the app to download an APK (with user input if needed) and install it
// Installs can only be done in the foreground, so a notification is sent to get the user's attention if needed
// Returns upon successful download, regardless of installation result
@@ -112,6 +116,7 @@ class AppsProvider with ChangeNotifier {
await notificationsProvider.notify(completeInstallationNotification,
cancelExisting: true);
await FGBGEvents.stream.first == FGBGType.foreground;
await notificationsProvider.cancel(completeInstallationNotification.id);
// We need to wait for the App to come to the foreground to install it
// Can't try to call install plugin in a background isolate (may not have worked anyways) because of:
// https://github.com/flutter/flutter/issues/13937

View File

@@ -165,7 +165,7 @@ class GitLab implements AppSource {
var parsedHtml = parse(res.body);
var entry = parsedHtml.querySelector('entry');
var entryContent =
parse(parseFragment(entry!.querySelector('content')!.innerHtml).text);
parse(parseFragment(entry?.querySelector('content')!.innerHtml).text);
var apkUrlList = getLinksFromParsedHTML(
entryContent,
RegExp(
@@ -176,7 +176,7 @@ class GitLab implements AppSource {
throw 'No APK found';
}
var entryId = entry.querySelector('id')?.innerHtml;
var entryId = entry?.querySelector('id')?.innerHtml;
var version =
entryId == null ? null : Uri.parse(entryId).pathSegments.last;
if (version == null) {
@@ -195,6 +195,39 @@ class GitLab implements AppSource {
}
}
class Signal implements AppSource {
@override
String sourceId = 'signal';
@override
String standardizeURL(String url) {
return 'https://signal.org';
}
@override
Future<APKDetails> getLatestAPKDetails(String standardUrl) async {
Response res =
await get(Uri.parse('https://updates.signal.org/android/latest.json'));
if (res.statusCode == 200) {
var json = jsonDecode(res.body);
String? apkUrl = json['url'];
if (apkUrl == null) {
throw 'No APK found';
}
String? version = json['versionName'];
if (version == null) {
throw 'Could not determine latest release version';
}
return APKDetails(version, [apkUrl]);
} else {
throw 'Unable to fetch release info';
}
}
@override
AppNames getAppNames(String standardUrl) => AppNames('signal', 'signal');
}
class SourceProvider {
// Add more source classes here so they are available via the service
AppSource getSource(String url) {
@@ -202,6 +235,8 @@ class SourceProvider {
return GitHub();
} else if (url.toLowerCase().contains('://gitlab.com')) {
return GitLab();
} else if (url.toLowerCase().contains('://signal.org')) {
return Signal();
}
throw 'URL does not match a known source';
}
@@ -228,5 +263,5 @@ class SourceProvider {
apk.apkUrls);
}
List<String> getSourceHosts() => ['github.com', 'gitlab.com'];
List<String> getSourceHosts() => ['github.com', 'gitlab.com', 'signal.org'];
}