Compare commits

...

17 Commits

Author SHA1 Message Date
abc69e7a0e Merge pull request #849 from ImranR98/dev
Bugfix in HTML Source (#848)
2023-09-03 15:37:43 -04:00
503914dbce Bugfix in HTML Source (#848) 2023-09-03 15:37:26 -04:00
69680f8680 Merge pull request #844 from gidano/main
Update hu.json
2023-09-03 00:15:41 -04:00
1a616aacb7 Merge pull request #847 from ImranR98/dev
Add Aptoide as a Source (#843)
2023-09-03 00:15:01 -04:00
52d19f267e Upgrade packages, increment version 2023-09-03 00:14:23 -04:00
75a8dc9ee4 Add Aptoide as a Source (#843) 2023-09-02 21:28:30 -04:00
8c63920ef6 Update hu.json 2023-09-02 15:41:10 +02:00
dda5619cdc Update issue templates 2023-09-01 11:25:53 -04:00
9cc25fd931 Update issue templates 2023-09-01 11:18:42 -04:00
f5a9eb4295 Update issue templates 2023-09-01 11:13:04 -04:00
ebe256e482 Update issue templates 2023-09-01 11:05:49 -04:00
e215585a64 Merge pull request #840 from ImranR98/dev
Bugfix: BG update fail leads to infinite retries (#838), Group update notifications into one (#829), Temporarily exclude Obtainium from BG updates (#836)
2023-08-30 22:36:31 -04:00
8b01fc03ec Increment version 2023-08-30 22:35:11 -04:00
9af2c8370d Bugfix: BG update fail leads to infinite retries (#838) 2023-08-30 22:34:12 -04:00
01f9003b8d Group update notifications into one (#829) 2023-08-30 22:07:30 -04:00
73a3c7eb71 Temporarily exclude Obtainium from BG updates (#836) 2023-08-30 21:41:26 -04:00
370ec1432e Fix BG update OS requirement 2023-08-30 21:40:05 -04:00
11 changed files with 279 additions and 93 deletions

32
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@ -0,0 +1,32 @@
---
name: Bug report
about: Something isn't working right.
title: ''
labels: bug, To Check
assignees: ''
---
**Prerequisites**
Please ensure your request is not part of an existing issue.
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Tap on '....'
3. Scroll down to '....'
4. See error
**Screenshots and Logs**
If applicable, add screenshots, logs, and any other artifacts (like some/all files under `/Android/data/dev.imranr.obtainium/`) that you think may help troubleshoot the issue.
**Please complete the following information:**
- Device: [e.g. Pixel 7]
- OS: [e.g. GrapheneOS]
- Obtainium Version [e.g. 0.14.6-beta]
**Additional context**
Add any other context about the problem here.

View File

@ -0,0 +1,29 @@
---
name: Feature request
about: Suggest a new Source, setting, or other feature.
title: ''
labels: enhancement, To Check
assignees: ''
---
**Prerequisites**
Please ensure your request is not part of an existing issue.
**Describe the feature**
A clear and concise description of what you want to happen.
For new Sources, it's preferable (not required) if you suggest how the following details can be extracted from the Source in a reliable way (like an API or through web scraping):
- The App version (or any release-specific identifier - a "pseudo-version") for the latest release
- One or more APK URL(s) for the latest release
- Above details for previous releases (optional)
Note that the Web scraper cannot deal with JavaScript-enabled content.
**Describe alternatives you've considered (if applicable)**
A clear and concise description of any alternative solutions or features you've considered.
Note that app-specific Sources are less likely to be added. In those cases, see if the HTML Source will work for you (if not, see if a generally-applicable enhancement to the HTML Source would work, and suggest that instead).
**Additional context**
Add any other context or screenshots about the feature request here.

View File

@ -16,6 +16,7 @@ Currently supported App sources:
- [Signal](https://signal.org/) - [Signal](https://signal.org/)
- [SourceForge](https://sourceforge.net/) - [SourceForge](https://sourceforge.net/)
- [SourceHut](https://git.sr.ht/) - [SourceHut](https://git.sr.ht/)
- [Aptoide](https://aptoide.com/)
- [APKMirror](https://apkmirror.com/) (Track-Only) - [APKMirror](https://apkmirror.com/) (Track-Only)
- [APKPure](https://apkpure.com/) - [APKPure](https://apkpure.com/)
- [Huawei AppGallery](https://appgallery.huawei.com/) - [Huawei AppGallery](https://appgallery.huawei.com/)

View File

@ -87,7 +87,7 @@
"author": "Szerző", "author": "Szerző",
"upToDateApps": "Naprakész appok", "upToDateApps": "Naprakész appok",
"nonInstalledApps": "Nem telepített appok", "nonInstalledApps": "Nem telepített appok",
"importExport": "Importálás/Exportálás", "importExport": "Import/Export",
"settings": "Beállítások", "settings": "Beállítások",
"exportedTo": "Exportálva ide {}", "exportedTo": "Exportálva ide {}",
"obtainiumExport": "Obtainium Adat Exportálás", "obtainiumExport": "Obtainium Adat Exportálás",
@ -137,7 +137,7 @@
"share": "Megosztás", "share": "Megosztás",
"appNotFound": "App nem található", "appNotFound": "App nem található",
"obtainiumExportHyphenatedLowercase": "obtainium-export", "obtainiumExportHyphenatedLowercase": "obtainium-export",
"pickAnAPK": "Válasszon egy APK-ot", "pickAnAPK": "Válasszon egy APK-t",
"appHasMoreThanOnePackage": "A(z) {} egynél több csomaggal rendelkezik:", "appHasMoreThanOnePackage": "A(z) {} egynél több csomaggal rendelkezik:",
"deviceSupportsXArch": "Eszköze támogatja a {} CPU architektúrát.", "deviceSupportsXArch": "Eszköze támogatja a {} CPU architektúrát.",
"deviceSupportsFollowingArchs": "Az eszköze a következő CPU architektúrákat támogatja:", "deviceSupportsFollowingArchs": "Az eszköze a következő CPU architektúrákat támogatja:",
@ -204,7 +204,7 @@
"copiedToClipboard": "Másolva a vágólapra", "copiedToClipboard": "Másolva a vágólapra",
"storagePermissionDenied": "Tárhely engedély megtagadva", "storagePermissionDenied": "Tárhely engedély megtagadva",
"selectedCategorizeWarning": "Ez felváltja a kiválasztott alkalmazások meglévő kategória-beállításait.", "selectedCategorizeWarning": "Ez felváltja a kiválasztott alkalmazások meglévő kategória-beállításait.",
"filterAPKsByRegEx": "Az APK-ok szűrése reguláris kifejezéssel", "filterAPKsByRegEx": "Az APK-k szűrése reguláris kifejezéssel",
"removeFromObtainium": "Eltávolítás az Obtainiumból", "removeFromObtainium": "Eltávolítás az Obtainiumból",
"uninstallFromDevice": "Eltávolítás a készülékről", "uninstallFromDevice": "Eltávolítás a készülékről",
"onlyWorksWithNonVersionDetectApps": "Csak azoknál az alkalmazásoknál működik, amelyeknél a verzióérzékelés le van tiltva.", "onlyWorksWithNonVersionDetectApps": "Csak azoknál az alkalmazásoknál működik, amelyeknél a verzióérzékelés le van tiltva.",
@ -239,15 +239,15 @@
"gitlabSourceNote": "Előfordulhat, hogy a GitLab APK kibontása nem működik API-kulcs nélkül.", "gitlabSourceNote": "Előfordulhat, hogy a GitLab APK kibontása nem működik API-kulcs nélkül.",
"sortByFileNamesNotLinks": "Fájlnevek szerinti elrendezés teljes linkek helyett", "sortByFileNamesNotLinks": "Fájlnevek szerinti elrendezés teljes linkek helyett",
"filterReleaseNotesByRegEx": "Kiadási megjegyzések szűrése reguláris kifejezéssel", "filterReleaseNotesByRegEx": "Kiadási megjegyzések szűrése reguláris kifejezéssel",
"customLinkFilterRegex": "Custom APK Link Filter by Regular Expression (Default '.apk$')", "customLinkFilterRegex": "Egyéni APK hivatkozásszűrő reguláris kifejezéssel (Alapérték '.apk$')",
"appsPossiblyUpdated": "App Updates Attempted", "appsPossiblyUpdated": "App frissítési kísérlet",
"appsPossiblyUpdatedNotifDescription": "Notifies the user that updates to one or more Apps were potentially applied in the background", "appsPossiblyUpdatedNotifDescription": "Értesíti a felhasználót, hogy egy vagy több alkalmazás frissítése lehetséges a háttérben",
"xWasPossiblyUpdatedToY": "{} may have been updated to {}.", "xWasPossiblyUpdatedToY": "{} frissítve lehet erre {}.",
"backgroundUpdateReqsExplanation": "Background updates may not be possible for all apps.", "backgroundUpdateReqsExplanation": "Előfordulhat, hogy nem minden appnál lehetséges a háttérbeli frissítés.",
"backgroundUpdateLimitsExplanation": "The success of a background install can only be determined when Obtainium is opened.", "backgroundUpdateLimitsExplanation": "A háttérben történő telepítés sikeressége csak az Obtainium megnyitásakor állapítható meg.",
"verifyLatestTag": "Verify the 'latest' tag", "verifyLatestTag": "Ellenőrizze a „legújabb” címkét",
"exemptFromBackgroundUpdates": "Exempt from background updates (if enabled)", "exemptFromBackgroundUpdates": "Mentes a háttérben történő frissítések alól (ha engedélyezett)",
"bgUpdatesOnWiFiOnly": "Disable background updates when not on WiFi", "bgUpdatesOnWiFiOnly": "Tiltsa le a háttérben frissítéseket, ha nincs Wi-Fi-n",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Eltávolítja az alkalmazást?", "one": "Eltávolítja az alkalmazást?",
"other": "Eltávolítja az alkalmazást?" "other": "Eltávolítja az alkalmazást?"
@ -297,7 +297,7 @@
"other": "{} és {} további alkalmazás frissítve." "other": "{} és {} további alkalmazás frissítve."
}, },
"xAndNMoreUpdatesPossiblyInstalled": { "xAndNMoreUpdatesPossiblyInstalled": {
"one": "{} and 1 more app may have been updated.", "one": "{} és 1 további alkalmazás is frissült.",
"other": "{} and {} more apps may have been updated." "other": "{} és {} további alkalmazás is frissült."
} }
} }

View File

@ -0,0 +1,104 @@
import 'dart:convert';
import 'package:easy_localization/easy_localization.dart';
import 'package:html/parser.dart';
import 'package:http/http.dart';
import 'package:obtainium/custom_errors.dart';
import 'package:obtainium/providers/source_provider.dart';
class Aptoide extends AppSource {
Aptoide() {
host = 'aptoide.com';
name = tr('Aptoide');
allowSubDomains = true;
}
@override
String sourceSpecificStandardizeURL(String url) {
RegExp standardUrlRegEx = RegExp('^https?://([^\\.]+\\.){2,}$host');
RegExpMatch? match = standardUrlRegEx.firstMatch(url.toLowerCase());
if (match == null) {
throw InvalidURLError(name);
}
return url.substring(0, match.end);
}
@override
Future<String?> tryInferringAppId(String standardUrl,
{Map<String, dynamic> additionalSettings = const {}}) async {
return (await getLatestAPKDetails(standardUrl, additionalSettings)).version;
}
@override
Future<APKDetails> getLatestAPKDetails(
String standardUrl,
Map<String, dynamic> additionalSettings,
) async {
var res = await sourceRequest(standardUrl);
if (res.statusCode != 200) {
throw getObtainiumHttpError(res);
}
var idMatch = RegExp('"app":{"id":[0-9]+').firstMatch(res.body);
String? id;
if (idMatch != null) {
id = res.body.substring(idMatch.start + 12, idMatch.end);
} else {
throw NoReleasesError();
}
var res2 =
await sourceRequest('https://ws2.aptoide.com/api/7/getApp/app_id/$id');
if (res2.statusCode != 200) {
throw getObtainiumHttpError(res);
}
var appDetails = jsonDecode(res2.body)?['nodes']?['meta']?['data'];
String appName = appDetails?['name'] ?? tr('app');
String author = appDetails?['developer']?['name'] ?? name;
String? dateStr = appDetails?['updated'];
String? version = appDetails?['file']?['vername'];
String? apkUrl = appDetails?['file']?['path'];
if (version == null) {
throw NoVersionError();
}
if (apkUrl == null) {
throw NoAPKError();
}
DateTime? relDate;
if (dateStr != null) {
relDate = DateTime.parse(dateStr);
}
return APKDetails(
version, getApkUrlsFromUrls([apkUrl]), AppNames(author, appName),
releaseDate: relDate);
}
@override
Future<Map<String, List<String>>> search(String query,
{Map<String, dynamic> querySettings = const {}}) async {
Response res = await sourceRequest(
'https://search.$host/?q=${Uri.encodeQueryComponent(query)}');
if (res.statusCode == 200) {
Map<String, List<String>> urlsWithDescriptions = {};
parse(res.body).querySelectorAll('.package-header').forEach((e) {
String? url = e.attributes['href'];
if (url != null) {
try {
standardizeUrl(url);
} catch (e) {
url = null;
}
}
if (url != null) {
urlsWithDescriptions[url] = [
e.querySelector('.package-name')?.text.trim() ?? '',
e.querySelector('.package-summary')?.text.trim() ??
tr('noDescription')
];
}
});
return urlsWithDescriptions;
} else {
throw getObtainiumHttpError(res);
}
}
}

View File

@ -18,7 +18,7 @@ String ensureAbsoluteUrl(String ambiguousUrl, Uri referenceAbsoluteUrl) {
.toList(); .toList();
if (ambiguousUrl.startsWith('/') || currPathSegments.isEmpty) { if (ambiguousUrl.startsWith('/') || currPathSegments.isEmpty) {
return '${referenceAbsoluteUrl.origin}/$ambiguousUrl'; return '${referenceAbsoluteUrl.origin}/$ambiguousUrl';
} else if (ambiguousUrl.split('/').length == 1) { } else if (ambiguousUrl.split('/').where((e) => e.isNotEmpty).length == 1) {
return '${referenceAbsoluteUrl.origin}/${currPathSegments.join('/')}/$ambiguousUrl'; return '${referenceAbsoluteUrl.origin}/${currPathSegments.join('/')}/$ambiguousUrl';
} else { } else {
return '${referenceAbsoluteUrl.origin}/${currPathSegments.sublist(0, currPathSegments.length - 1).join('/')}/$ambiguousUrl'; return '${referenceAbsoluteUrl.origin}/${currPathSegments.sublist(0, currPathSegments.length - 1).join('/')}/$ambiguousUrl';

View File

@ -19,7 +19,7 @@ import 'package:easy_localization/src/easy_localization_controller.dart';
// ignore: implementation_imports // ignore: implementation_imports
import 'package:easy_localization/src/localization.dart'; import 'package:easy_localization/src/localization.dart';
const String currentVersion = '0.14.5'; const String currentVersion = '0.14.8';
const String currentReleaseTag = const String currentReleaseTag =
'v$currentVersion-beta'; // KEEP THIS IN SYNC WITH GITHUB RELEASES 'v$currentVersion-beta'; // KEEP THIS IN SYNC WITH GITHUB RELEASES

View File

@ -4,6 +4,7 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'dart:math';
import 'package:android_alarm_manager_plus/android_alarm_manager_plus.dart'; import 'package:android_alarm_manager_plus/android_alarm_manager_plus.dart';
import 'package:android_intent_plus/flag.dart'; import 'package:android_intent_plus/flag.dart';
@ -116,16 +117,19 @@ moveStrToEnd(List<String> arr, String str, {String? strB}) {
return arr; return arr;
} }
moveStrToEndMapEntryWithCount( List<MapEntry<String, int>> moveStrToEndMapEntryWithCount(
List<MapEntry<String, int>> arr, MapEntry<String, int> str, List<MapEntry<String, int>> arr, MapEntry<String, int> str,
{MapEntry<String, int>? strB}) { {MapEntry<String, int>? strB}) {
MapEntry<String, int>? temp; MapEntry<String, int>? temp;
arr.removeWhere((element) { arr.removeWhere((element) {
bool res = element.key == str.key || element.key == strB?.key; bool resA = element.key == str.key;
if (res) { bool resB = element.key == strB?.key;
temp = element; if (resA) {
temp = str;
} else if (resB) {
temp = strB;
} }
return res; return resA || resB;
}); });
if (temp != null) { if (temp != null) {
arr = [...arr, temp!]; arr = [...arr, temp!];
@ -364,6 +368,9 @@ class AppsProvider with ChangeNotifier {
Future<bool> canInstallSilently( Future<bool> canInstallSilently(
App app, SettingsProvider settingsProvider) async { App app, SettingsProvider settingsProvider) async {
if (app.id == obtainiumId) {
return false;
}
if (!settingsProvider.enableBackgroundUpdates) { if (!settingsProvider.enableBackgroundUpdates) {
return false; return false;
} }
@ -393,7 +400,7 @@ class AppsProvider with ChangeNotifier {
(await getInstalledInfo(app.id))?.applicationInfo?.targetSdkVersion; (await getInstalledInfo(app.id))?.applicationInfo?.targetSdkVersion;
// The OS must also be new enough and the APK should target a new enough API // The OS must also be new enough and the APK should target a new enough API
return osInfo.version.sdkInt >= 30 && return osInfo.version.sdkInt >= 31 &&
targetSDK != null && targetSDK != null &&
targetSDK >= // https://developer.android.com/reference/android/content/pm/PackageInstaller.SessionParams#setRequireUserAction(int) targetSDK >= // https://developer.android.com/reference/android/content/pm/PackageInstaller.SessionParams#setRequireUserAction(int)
(osInfo.version.sdkInt - 3); (osInfo.version.sdkInt - 3);
@ -1331,67 +1338,75 @@ Future<void> bgUpdateCheck(int taskId, Map<String, dynamic>? params) async {
(netResult != ConnectivityResult.ethernet); (netResult != ConnectivityResult.ethernet);
} }
// Loop through all updates and check each // Loop through all updates and check each
for (int i = 0; i < toCheck.length; i++) { List<App> toNotify = [];
var appId = toCheck[i].key; try {
var retryCount = toCheck[i].value; for (int i = 0; i < toCheck.length; i++) {
AppInMemory? app = appsProvider.apps[appId]; var appId = toCheck[i].key;
if (app?.app.installedVersion != null) { var attemptCount = toCheck[i].value + 1;
try { AppInMemory? app = appsProvider.apps[appId];
notificationsProvider.notify( if (app?.app.installedVersion != null) {
notif = CheckingUpdatesNotification(app?.name ?? appId), try {
cancelExisting: true); notificationsProvider.notify(
App? newApp = await appsProvider.checkUpdate(appId); notif = CheckingUpdatesNotification(app?.name ?? appId),
if (newApp != null) { cancelExisting: true);
if (networkRestricted || App? newApp = await appsProvider.checkUpdate(appId);
!(await appsProvider.canInstallSilently( if (newApp != null) {
app!.app, settingsProvider))) { if (networkRestricted ||
notificationsProvider.notify( !(await appsProvider.canInstallSilently(
UpdateNotification([newApp], id: newApp.id.hashCode - 1)); app!.app, settingsProvider))) {
toNotify.add(newApp);
} else {
toInstall.add(MapEntry(appId, 0));
}
}
if (i == (toCheck.length - 1)) {
didCompleteChecking = true;
}
} catch (e) {
// If you got an error, move the offender to the back of the line (increment their fail count) and schedule another task to continue checking shortly
logs.add(
'BG update task $taskId: Got error on checking for $appId \'${e.toString()}\'.');
if (attemptCount < maxAttempts) {
var remainingSeconds = e is RateLimitError
? (i == 0 ? (e.remainingMinutes * 60) : (5 * 60))
: e is ClientException
? (15 * 60)
: pow(attemptCount, 2).toInt();
logs.add(
'BG update task $taskId: Will continue in $remainingSeconds seconds (with $appId moved to the end of the line).');
var remainingToCheck = moveStrToEndMapEntryWithCount(
toCheck.sublist(i), MapEntry(appId, attemptCount));
AndroidAlarmManager.oneShot(Duration(seconds: remainingSeconds),
taskId + 1, bgUpdateCheck,
params: {
'toCheck': remainingToCheck
.map(
(entry) => {'key': entry.key, 'value': entry.value})
.toList(),
'toInstall': toInstall
.map(
(entry) => {'key': entry.key, 'value': entry.value})
.toList(),
});
break;
} else { } else {
toInstall.add(MapEntry(appId, 0)); // If the offender has reached its fail limit, notify the user and remove it from the list (task can continue)
toCheck.removeAt(i);
i--;
notificationsProvider
.notify(ErrorCheckingUpdatesNotification(e.toString()));
}
} finally {
if (notif != null) {
notificationsProvider.cancel(notif.id);
} }
} }
if (i == (toCheck.length - 1)) {
didCompleteChecking = true;
}
} catch (e) {
// If you got an error, move the offender to the back of the line (increment their fail count) and schedule another task to continue checking shortly
logs.add(
'BG update task $taskId: Got error on checking for $appId \'${e.toString()}\'.');
if (retryCount < maxAttempts) {
var remainingSeconds = e is RateLimitError
? (i == 0 ? (e.remainingMinutes * 60) : (5 * 60))
: e is ClientException
? (15 * 60)
: (retryCount ^ 2);
logs.add(
'BG update task $taskId: Will continue in $remainingSeconds seconds (with $appId moved to the end of the line).');
var remainingToCheck = moveStrToEndMapEntryWithCount(
toCheck.sublist(i), MapEntry(appId, retryCount + 1));
AndroidAlarmManager.oneShot(
Duration(seconds: remainingSeconds), taskId + 1, bgUpdateCheck,
params: {
'toCheck': remainingToCheck
.map((entry) => {'key': entry.key, 'value': entry.value})
.toList(),
'toInstall': toInstall
.map((entry) => {'key': entry.key, 'value': entry.value})
.toList(),
});
break;
} else {
// If the offender has reached its fail limit, notify the user and remove it from the list (task can continue)
toCheck.removeAt(i);
i--;
notificationsProvider
.notify(ErrorCheckingUpdatesNotification(e.toString()));
}
} finally {
if (notif != null) {
notificationsProvider.cancel(notif.id);
}
} }
} }
} finally {
if (toNotify.isNotEmpty) {
notificationsProvider.notify(UpdateNotification(toNotify));
}
} }
// If you're done checking and found some silently installable updates, schedule another task which will run in install mode // If you're done checking and found some silently installable updates, schedule another task which will run in install mode
if (didCompleteChecking && toInstall.isNotEmpty) { if (didCompleteChecking && toInstall.isNotEmpty) {

View File

@ -9,6 +9,7 @@ import 'package:html/dom.dart';
import 'package:http/http.dart'; import 'package:http/http.dart';
import 'package:obtainium/app_sources/apkmirror.dart'; import 'package:obtainium/app_sources/apkmirror.dart';
import 'package:obtainium/app_sources/apkpure.dart'; import 'package:obtainium/app_sources/apkpure.dart';
import 'package:obtainium/app_sources/aptoide.dart';
import 'package:obtainium/app_sources/codeberg.dart'; import 'package:obtainium/app_sources/codeberg.dart';
import 'package:obtainium/app_sources/fdroid.dart'; import 'package:obtainium/app_sources/fdroid.dart';
import 'package:obtainium/app_sources/fdroidrepo.dart'; import 'package:obtainium/app_sources/fdroidrepo.dart';
@ -325,6 +326,7 @@ abstract class AppSource {
bool enforceTrackOnly = false; bool enforceTrackOnly = false;
bool changeLogIfAnyIsMarkDown = true; bool changeLogIfAnyIsMarkDown = true;
bool appIdInferIsOptional = false; bool appIdInferIsOptional = false;
bool allowSubDomains = false;
AppSource() { AppSource() {
name = runtimeType.toString(); name = runtimeType.toString();
@ -522,13 +524,14 @@ class SourceProvider {
Jenkins(), Jenkins(),
SourceForge(), SourceForge(),
SourceHut(), SourceHut(),
Aptoide(),
APKMirror(), APKMirror(),
APKPure(), APKPure(),
HuaweiAppGallery(), HuaweiAppGallery(),
// APKCombo(), // Can't get past their scraping blocking yet (get 403 Forbidden) // APKCombo(), // Can't get past their scraping blocking yet (get 403 Forbidden)
Mullvad(), Mullvad(),
Signal(), Signal(),
VLC(), // As of 2023-08-26 this site randomly messes up the 'latest' version (one minute it's 3.5.4, next minute back to 3.5.3) VLC(),
// WhatsApp(), // As of 2023-03-20 this is unusable as the version on the webpage is months out of date // WhatsApp(), // As of 2023-03-20 this is unusable as the version on the webpage is months out of date
TelegramApp(), TelegramApp(),
SteamMobile(), SteamMobile(),
@ -554,7 +557,9 @@ class SourceProvider {
} }
AppSource? source; AppSource? source;
for (var s in sources.where((element) => element.host != null)) { for (var s in sources.where((element) => element.host != null)) {
if (RegExp('://${s.host}(/|\\z)?').hasMatch(url)) { if (RegExp(
'://${s.allowSubDomains ? '([^\\.]+\\.)*' : ''}${s.host}(/|\\z)?')
.hasMatch(url)) {
source = s; source = s;
break; break;
} }

View File

@ -46,10 +46,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: archive name: archive
sha256: "0c8368c9b3f0abbc193b9d6133649a614204b528982bebc7026372d61677ce3a" sha256: "49b1fad315e57ab0bbc15bcbb874e83116a1d78f77ebd500a4af6c9407d6b28e"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.3.7" version: "3.3.8"
args: args:
dependency: transitive dependency: transitive
description: description:
@ -206,10 +206,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: easy_localization name: easy_localization
sha256: "30ebf25448ffe169e0bd9bc4b5da94faa8398967a2ad2ca09f438be8b6953645" sha256: de63e3b422adfc97f256cbb3f8cf12739b6a4993d390f3cadb3f51837afaefe5
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.2" version: "3.0.3"
easy_logger: easy_logger:
dependency: transitive dependency: transitive
description: description:
@ -783,18 +783,18 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: url_launcher name: url_launcher
sha256: "38d8e783681bc342e92dc9799cbe4421d08c4d210a67ee9d61d0f7310491a465" sha256: "47e208a6711459d813ba18af120d9663c20bdf6985d6ad39fe165d2538378d27"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.1.13" version: "6.1.14"
url_launcher_android: url_launcher_android:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_android name: url_launcher_android
sha256: ef7e34951ffa963fb7a65928deeb38d40fb3c5975baf93c1d631341ff7f2650a sha256: b04af59516ab45762b2ca6da40fa830d72d0f6045cd97744450b73493fa76330
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.0.39" version: "6.1.0"
url_launcher_ios: url_launcher_ios:
dependency: transitive dependency: transitive
description: description:
@ -823,10 +823,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_platform_interface name: url_launcher_platform_interface
sha256: "4d0dae953f80dc06fa24c58d0f8381302139c22c2dad301417787ad96f5f73bd" sha256: "95465b39f83bfe95fcb9d174829d6476216f2d548b79c38ab2506e0458787618"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.4" version: "2.1.5"
url_launcher_web: url_launcher_web:
dependency: transitive dependency: transitive
description: description:
@ -879,10 +879,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: webview_flutter_android name: webview_flutter_android
sha256: "8545719bbf06f5c4b850f0d5f86da1fe837b1953c56b9af579a26be73627c98d" sha256: "0d8f5ac96a155e672129bf94c7abf625de01241d44d269dbaff083f1b4deb1aa"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.9.4" version: "3.9.5"
webview_flutter_platform_interface: webview_flutter_platform_interface:
dependency: transitive dependency: transitive
description: description:

View File

@ -17,7 +17,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts # In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix. # of the product and file versions while build-number is used as the build suffix.
version: 0.14.5+197 # When changing this, update the tag in main() accordingly version: 0.14.8+200 # When changing this, update the tag in main() accordingly
environment: environment:
sdk: '>=2.18.2 <3.0.0' sdk: '>=2.18.2 <3.0.0'