mirror of
https://github.com/ImranR98/Obtainium.git
synced 2025-08-17 20:28:10 +02:00
Added Signal.org, fixed bugs, UX tweaks, readme update
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
#  Obtainium
|
||||
#  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
|
||||
|
||||
|
@@ -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();
|
||||
}
|
||||
});
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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'];
|
||||
}
|
||||
|
Reference in New Issue
Block a user