mirror of
https://github.com/ImranR98/Obtainium.git
synced 2025-07-18 07:36:43 +02:00
Compare commits
4 Commits
v0.11.24-b
...
v0.11.26-b
Author | SHA1 | Date | |
---|---|---|---|
a2edc86bfa | |||
0804e680b2 | |||
49affd1bd4 | |||
202ce4f0d5 |
@ -222,6 +222,7 @@
|
|||||||
"versionDetection": "Versionserkennung",
|
"versionDetection": "Versionserkennung",
|
||||||
"standardVersionDetection": "Standardversionserkennung",
|
"standardVersionDetection": "Standardversionserkennung",
|
||||||
"groupByCategory": "Group by Category",
|
"groupByCategory": "Group by Category",
|
||||||
|
"autoApkFilterByArch": "Attempt to filter APKs by CPU architecture if possible",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "App entfernen?",
|
"one": "App entfernen?",
|
||||||
"other": "App entfernen?"
|
"other": "App entfernen?"
|
||||||
|
@ -222,6 +222,7 @@
|
|||||||
"versionDetection": "Version Detection",
|
"versionDetection": "Version Detection",
|
||||||
"standardVersionDetection": "Standard version detection",
|
"standardVersionDetection": "Standard version detection",
|
||||||
"groupByCategory": "Group by Category",
|
"groupByCategory": "Group by Category",
|
||||||
|
"autoApkFilterByArch": "Attempt to filter APKs by CPU architecture if possible",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "Remove App?",
|
"one": "Remove App?",
|
||||||
"other": "Remove Apps?"
|
"other": "Remove Apps?"
|
||||||
|
@ -222,6 +222,7 @@
|
|||||||
"versionDetection": "تشخیص نسخه",
|
"versionDetection": "تشخیص نسخه",
|
||||||
"standardVersionDetection": "تشخیص نسخه استاندارد",
|
"standardVersionDetection": "تشخیص نسخه استاندارد",
|
||||||
"groupByCategory": "Group by Category",
|
"groupByCategory": "Group by Category",
|
||||||
|
"autoApkFilterByArch": "Attempt to filter APKs by CPU architecture if possible",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "برنامه حذف شود؟",
|
"one": "برنامه حذف شود؟",
|
||||||
"other": "برنامه ها حذف شوند؟"
|
"other": "برنامه ها حذف شوند؟"
|
||||||
|
@ -222,6 +222,7 @@
|
|||||||
"versionDetection": "Détection des versions",
|
"versionDetection": "Détection des versions",
|
||||||
"standardVersionDetection": "Détection de version standard",
|
"standardVersionDetection": "Détection de version standard",
|
||||||
"groupByCategory": "Group by Category",
|
"groupByCategory": "Group by Category",
|
||||||
|
"autoApkFilterByArch": "Attempt to filter APKs by CPU architecture if possible",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "Supprimer l'application ?",
|
"one": "Supprimer l'application ?",
|
||||||
"other": "Supprimer les applications ?"
|
"other": "Supprimer les applications ?"
|
||||||
|
@ -221,6 +221,7 @@
|
|||||||
"versionDetection": "Verzió érzékelés",
|
"versionDetection": "Verzió érzékelés",
|
||||||
"standardVersionDetection": "Alapért. verzió érzékelés",
|
"standardVersionDetection": "Alapért. verzió érzékelés",
|
||||||
"groupByCategory": "Csoportosítás Kategória alapján",
|
"groupByCategory": "Csoportosítás Kategória alapján",
|
||||||
|
"autoApkFilterByArch": "Attempt to filter APKs by CPU architecture if possible",
|
||||||
"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?"
|
||||||
|
@ -222,6 +222,7 @@
|
|||||||
"versionDetection": "Rilevamento di versione",
|
"versionDetection": "Rilevamento di versione",
|
||||||
"standardVersionDetection": "Rilevamento di versione standard",
|
"standardVersionDetection": "Rilevamento di versione standard",
|
||||||
"groupByCategory": "Group by Category",
|
"groupByCategory": "Group by Category",
|
||||||
|
"autoApkFilterByArch": "Attempt to filter APKs by CPU architecture if possible",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "Rimuovere l'App?",
|
"one": "Rimuovere l'App?",
|
||||||
"other": "Rimuovere le App?"
|
"other": "Rimuovere le App?"
|
||||||
|
@ -222,6 +222,7 @@
|
|||||||
"versionDetection": "バージョン検出",
|
"versionDetection": "バージョン検出",
|
||||||
"standardVersionDetection": "標準のバージョン検出",
|
"standardVersionDetection": "標準のバージョン検出",
|
||||||
"groupByCategory": "Group by Category",
|
"groupByCategory": "Group by Category",
|
||||||
|
"autoApkFilterByArch": "Attempt to filter APKs by CPU architecture if possible",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "アプリを削除しますか?",
|
"one": "アプリを削除しますか?",
|
||||||
"other": "アプリを削除しますか?"
|
"other": "アプリを削除しますか?"
|
||||||
|
@ -222,6 +222,7 @@
|
|||||||
"versionDetection": "Version Detection",
|
"versionDetection": "Version Detection",
|
||||||
"standardVersionDetection": "Standard version detection",
|
"standardVersionDetection": "Standard version detection",
|
||||||
"groupByCategory": "Group by Category",
|
"groupByCategory": "Group by Category",
|
||||||
|
"autoApkFilterByArch": "Attempt to filter APKs by CPU architecture if possible",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "删除应用?",
|
"one": "删除应用?",
|
||||||
"other": "删除应用?"
|
"other": "删除应用?"
|
||||||
|
@ -68,7 +68,7 @@ class Codeberg extends AppSource {
|
|||||||
if (res.statusCode == 200) {
|
if (res.statusCode == 200) {
|
||||||
var releases = jsonDecode(res.body) as List<dynamic>;
|
var releases = jsonDecode(res.body) as List<dynamic>;
|
||||||
|
|
||||||
List<String> getReleaseAPKUrls(dynamic release) =>
|
List<MapEntry<String, String>> getReleaseAPKUrls(dynamic release) =>
|
||||||
(release['assets'] as List<dynamic>?)
|
(release['assets'] as List<dynamic>?)
|
||||||
?.map((e) {
|
?.map((e) {
|
||||||
return e['name'] != null && e['browser_download_url'] != null
|
return e['name'] != null && e['browser_download_url'] != null
|
||||||
@ -77,7 +77,6 @@ class Codeberg extends AppSource {
|
|||||||
: const MapEntry('', '');
|
: const MapEntry('', '');
|
||||||
})
|
})
|
||||||
.where((element) => element.key.toLowerCase().endsWith('.apk'))
|
.where((element) => element.key.toLowerCase().endsWith('.apk'))
|
||||||
.map((e) => e.value)
|
|
||||||
.toList() ??
|
.toList() ??
|
||||||
[];
|
[];
|
||||||
|
|
||||||
@ -119,7 +118,9 @@ class Codeberg extends AppSource {
|
|||||||
throw NoVersionError();
|
throw NoVersionError();
|
||||||
}
|
}
|
||||||
var changeLog = targetRelease['body'].toString();
|
var changeLog = targetRelease['body'].toString();
|
||||||
return APKDetails(version, targetRelease['apkUrls'] as List<String>,
|
return APKDetails(
|
||||||
|
version,
|
||||||
|
targetRelease['apkUrls'] as List<MapEntry<String, String>>,
|
||||||
getAppNames(standardUrl),
|
getAppNames(standardUrl),
|
||||||
releaseDate: releaseDate,
|
releaseDate: releaseDate,
|
||||||
changeLog: changeLog.isEmpty ? null : changeLog);
|
changeLog: changeLog.isEmpty ? null : changeLog);
|
||||||
|
@ -50,7 +50,7 @@ class FDroid extends AppSource {
|
|||||||
.where((element) => element['versionName'] == latestVersion)
|
.where((element) => element['versionName'] == latestVersion)
|
||||||
.map((e) => '${apkUrlPrefix}_${e['versionCode']}.apk')
|
.map((e) => '${apkUrlPrefix}_${e['versionCode']}.apk')
|
||||||
.toList();
|
.toList();
|
||||||
return APKDetails(latestVersion, apkUrls,
|
return APKDetails(latestVersion, getApkUrlsFromUrls(apkUrls),
|
||||||
AppNames(name, Uri.parse(standardUrl).pathSegments.last));
|
AppNames(name, Uri.parse(standardUrl).pathSegments.last));
|
||||||
} else {
|
} else {
|
||||||
throw getObtainiumHttpError(res);
|
throw getObtainiumHttpError(res);
|
||||||
|
@ -80,7 +80,8 @@ class FDroidRepo extends AppSource {
|
|||||||
element.querySelector('apkname') != null)
|
element.querySelector('apkname') != null)
|
||||||
.map((e) => '$standardUrl/${e.querySelector('apkname')!.innerHtml}')
|
.map((e) => '$standardUrl/${e.querySelector('apkname')!.innerHtml}')
|
||||||
.toList();
|
.toList();
|
||||||
return APKDetails(latestVersion, apkUrls, AppNames(authorName, appName),
|
return APKDetails(latestVersion, getApkUrlsFromUrls(apkUrls),
|
||||||
|
AppNames(authorName, appName),
|
||||||
releaseDate: releaseDate);
|
releaseDate: releaseDate);
|
||||||
} else {
|
} else {
|
||||||
throw getObtainiumHttpError(res);
|
throw getObtainiumHttpError(res);
|
||||||
|
@ -161,7 +161,9 @@ class GitHub extends AppSource {
|
|||||||
throw NoVersionError();
|
throw NoVersionError();
|
||||||
}
|
}
|
||||||
var changeLog = targetRelease['body'].toString();
|
var changeLog = targetRelease['body'].toString();
|
||||||
return APKDetails(version, targetRelease['apkUrls'] as List<String>,
|
return APKDetails(
|
||||||
|
version,
|
||||||
|
getApkUrlsFromUrls(targetRelease['apkUrls'] as List<String>),
|
||||||
getAppNames(standardUrl),
|
getAppNames(standardUrl),
|
||||||
releaseDate: releaseDate,
|
releaseDate: releaseDate,
|
||||||
changeLog: changeLog.isEmpty ? null : changeLog);
|
changeLog: changeLog.isEmpty ? null : changeLog);
|
||||||
|
@ -60,7 +60,8 @@ class GitLab extends AppSource {
|
|||||||
if (version == null) {
|
if (version == null) {
|
||||||
throw NoVersionError();
|
throw NoVersionError();
|
||||||
}
|
}
|
||||||
return APKDetails(version, apkUrls, GitHub().getAppNames(standardUrl),
|
return APKDetails(version, getApkUrlsFromUrls(apkUrls),
|
||||||
|
GitHub().getAppNames(standardUrl),
|
||||||
releaseDate: releaseDate);
|
releaseDate: releaseDate);
|
||||||
} else {
|
} else {
|
||||||
throw getObtainiumHttpError(res);
|
throw getObtainiumHttpError(res);
|
||||||
|
@ -42,7 +42,8 @@ class HTML extends AppSource {
|
|||||||
? '${uri.origin}/$e'
|
? '${uri.origin}/$e'
|
||||||
: '${uri.origin}/${uri.path}/$e')
|
: '${uri.origin}/${uri.path}/$e')
|
||||||
.toList();
|
.toList();
|
||||||
return APKDetails(version, apkUrls, AppNames(uri.host, tr('app')));
|
return APKDetails(
|
||||||
|
version, getApkUrlsFromUrls(apkUrls), AppNames(uri.host, tr('app')));
|
||||||
} else {
|
} else {
|
||||||
throw getObtainiumHttpError(res);
|
throw getObtainiumHttpError(res);
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,7 @@ class Mullvad extends AppSource {
|
|||||||
}
|
}
|
||||||
return APKDetails(
|
return APKDetails(
|
||||||
versions[0],
|
versions[0],
|
||||||
['https://mullvad.net/download/app/apk/latest'],
|
getApkUrlsFromUrls(['https://mullvad.net/download/app/apk/latest']),
|
||||||
AppNames(name, 'Mullvad-VPN'),
|
AppNames(name, 'Mullvad-VPN'),
|
||||||
changeLog: changeLog);
|
changeLog: changeLog);
|
||||||
} else {
|
} else {
|
||||||
|
@ -98,7 +98,7 @@ class NeutronCode extends AppSource {
|
|||||||
? (customDateParse(dateStringOriginal))
|
? (customDateParse(dateStringOriginal))
|
||||||
: null;
|
: null;
|
||||||
var changeLogElements = http.querySelectorAll('.pd-fdesc p');
|
var changeLogElements = http.querySelectorAll('.pd-fdesc p');
|
||||||
return APKDetails(version, [apkUrl],
|
return APKDetails(version, getApkUrlsFromUrls([apkUrl]),
|
||||||
AppNames(runtimeType.toString(), name ?? standardUrl.split('/').last),
|
AppNames(runtimeType.toString(), name ?? standardUrl.split('/').last),
|
||||||
releaseDate: dateString != null ? DateTime.parse(dateString) : null,
|
releaseDate: dateString != null ? DateTime.parse(dateString) : null,
|
||||||
changeLog: changeLogElements.isNotEmpty
|
changeLog: changeLogElements.isNotEmpty
|
||||||
|
@ -28,7 +28,8 @@ class Signal extends AppSource {
|
|||||||
if (version == null) {
|
if (version == null) {
|
||||||
throw NoVersionError();
|
throw NoVersionError();
|
||||||
}
|
}
|
||||||
return APKDetails(version, apkUrls, AppNames(name, 'Signal'));
|
return APKDetails(
|
||||||
|
version, getApkUrlsFromUrls(apkUrls), AppNames(name, 'Signal'));
|
||||||
} else {
|
} else {
|
||||||
throw getObtainiumHttpError(res);
|
throw getObtainiumHttpError(res);
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@ class SourceForge extends AppSource {
|
|||||||
.toList();
|
.toList();
|
||||||
return APKDetails(
|
return APKDetails(
|
||||||
version,
|
version,
|
||||||
apkUrlList,
|
getApkUrlsFromUrls(apkUrlList),
|
||||||
AppNames(
|
AppNames(
|
||||||
name, standardUrl.substring(standardUrl.lastIndexOf('/') + 1)));
|
name, standardUrl.substring(standardUrl.lastIndexOf('/') + 1)));
|
||||||
} else {
|
} else {
|
||||||
|
@ -53,7 +53,8 @@ class SteamMobile extends AppSource {
|
|||||||
var version = links[0].substring(
|
var version = links[0].substring(
|
||||||
versionMatch.start + apkNamePrefix.length + 2, versionMatch.end - 4);
|
versionMatch.start + apkNamePrefix.length + 2, versionMatch.end - 4);
|
||||||
var apkUrls = [links[0]];
|
var apkUrls = [links[0]];
|
||||||
return APKDetails(version, apkUrls, AppNames(name, apks[apkNamePrefix]!));
|
return APKDetails(version, getApkUrlsFromUrls(apkUrls),
|
||||||
|
AppNames(name, apks[apkNamePrefix]!));
|
||||||
} else {
|
} else {
|
||||||
throw getObtainiumHttpError(res);
|
throw getObtainiumHttpError(res);
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,8 @@ class TelegramApp extends AppSource {
|
|||||||
throw NoVersionError();
|
throw NoVersionError();
|
||||||
}
|
}
|
||||||
String? apkUrl = 'https://telegram.org/dl/android/apk';
|
String? apkUrl = 'https://telegram.org/dl/android/apk';
|
||||||
return APKDetails(version, [apkUrl], AppNames('Telegram', 'Telegram'));
|
return APKDetails(version, getApkUrlsFromUrls([apkUrl]),
|
||||||
|
AppNames('Telegram', 'Telegram'));
|
||||||
} else {
|
} else {
|
||||||
throw getObtainiumHttpError(res);
|
throw getObtainiumHttpError(res);
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,8 @@ class VLC extends AppSource {
|
|||||||
throw getObtainiumHttpError(res2);
|
throw getObtainiumHttpError(res2);
|
||||||
}
|
}
|
||||||
|
|
||||||
return APKDetails(version, apkUrls, AppNames('VideoLAN', 'VLC'));
|
return APKDetails(
|
||||||
|
version, getApkUrlsFromUrls(apkUrls), AppNames('VideoLAN', 'VLC'));
|
||||||
} else {
|
} else {
|
||||||
throw getObtainiumHttpError(res);
|
throw getObtainiumHttpError(res);
|
||||||
}
|
}
|
||||||
|
@ -64,9 +64,9 @@ class WhatsApp extends AppSource {
|
|||||||
vLines[0].substring(versionMatch.start, versionMatch.end);
|
vLines[0].substring(versionMatch.start, versionMatch.end);
|
||||||
return APKDetails(
|
return APKDetails(
|
||||||
version,
|
version,
|
||||||
[
|
getApkUrlsFromUrls([
|
||||||
'https://www.whatsapp.com/android?v=$version&=thisIsaPlaceholder&a=realURLPrefetchedAtDownloadTime'
|
'https://www.whatsapp.com/android?v=$version&=thisIsaPlaceholder&a=realURLPrefetchedAtDownloadTime'
|
||||||
],
|
]),
|
||||||
AppNames('Meta', 'WhatsApp'));
|
AppNames('Meta', 'WhatsApp'));
|
||||||
} else {
|
} else {
|
||||||
throw getObtainiumHttpError(res);
|
throw getObtainiumHttpError(res);
|
||||||
|
@ -267,7 +267,10 @@ class _GeneratedFormState extends State<GeneratedForm> {
|
|||||||
formInputs[r][e] = Row(
|
formInputs[r][e] = Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text(widget.items[r][e].label),
|
Flexible(child: Text(widget.items[r][e].label)),
|
||||||
|
const SizedBox(
|
||||||
|
width: 8,
|
||||||
|
),
|
||||||
Switch(
|
Switch(
|
||||||
value: values[widget.items[r][e].key],
|
value: values[widget.items[r][e].key],
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
|
@ -21,7 +21,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.11.24';
|
const String currentVersion = '0.11.26';
|
||||||
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
|
||||||
|
|
||||||
|
@ -169,7 +169,7 @@ class AppsProvider with ChangeNotifier {
|
|||||||
'${app.id}-${app.latestVersion}-${app.preferredApkIndex}.apk';
|
'${app.id}-${app.latestVersion}-${app.preferredApkIndex}.apk';
|
||||||
String downloadUrl = await SourceProvider()
|
String downloadUrl = await SourceProvider()
|
||||||
.getSource(app.url)
|
.getSource(app.url)
|
||||||
.apkUrlPrefetchModifier(app.apkUrls[app.preferredApkIndex]);
|
.apkUrlPrefetchModifier(app.apkUrls[app.preferredApkIndex].value);
|
||||||
var notif = DownloadNotification(app.name, 100);
|
var notif = DownloadNotification(app.name, 100);
|
||||||
notificationsProvider?.cancel(notif.id);
|
notificationsProvider?.cancel(notif.id);
|
||||||
int? prevProg;
|
int? prevProg;
|
||||||
@ -296,9 +296,10 @@ class AppsProvider with ChangeNotifier {
|
|||||||
await intent.launch();
|
await intent.launch();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String?> confirmApkUrl(App app, BuildContext? context) async {
|
Future<MapEntry<String, String>?> confirmApkUrl(
|
||||||
|
App app, BuildContext? context) async {
|
||||||
// If the App has more than one APK, the user should pick one (if context provided)
|
// If the App has more than one APK, the user should pick one (if context provided)
|
||||||
String? apkUrl = app.apkUrls[app.preferredApkIndex];
|
MapEntry<String, String>? apkUrl = app.apkUrls[app.preferredApkIndex];
|
||||||
// get device supported architecture
|
// get device supported architecture
|
||||||
List<String> archs = (await DeviceInfoPlugin().androidInfo).supportedAbis;
|
List<String> archs = (await DeviceInfoPlugin().androidInfo).supportedAbis;
|
||||||
|
|
||||||
@ -321,14 +322,14 @@ class AppsProvider with ChangeNotifier {
|
|||||||
|
|
||||||
// If the picked APK comes from an origin different from the source, get user confirmation (if context provided)
|
// If the picked APK comes from an origin different from the source, get user confirmation (if context provided)
|
||||||
if (apkUrl != null &&
|
if (apkUrl != null &&
|
||||||
getHost(apkUrl) != getHost(app.url) &&
|
getHost(apkUrl.value) != getHost(app.url) &&
|
||||||
context != null) {
|
context != null) {
|
||||||
// ignore: use_build_context_synchronously
|
// ignore: use_build_context_synchronously
|
||||||
if (await showDialog(
|
if (await showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext ctx) {
|
builder: (BuildContext ctx) {
|
||||||
return APKOriginWarningDialog(
|
return APKOriginWarningDialog(
|
||||||
sourceUrl: app.url, apkUrl: apkUrl!);
|
sourceUrl: app.url, apkUrl: apkUrl!.value);
|
||||||
}) !=
|
}) !=
|
||||||
true) {
|
true) {
|
||||||
apkUrl = null;
|
apkUrl = null;
|
||||||
@ -353,7 +354,7 @@ class AppsProvider with ChangeNotifier {
|
|||||||
if (apps[id] == null) {
|
if (apps[id] == null) {
|
||||||
throw ObtainiumError(tr('appNotFound'));
|
throw ObtainiumError(tr('appNotFound'));
|
||||||
}
|
}
|
||||||
String? apkUrl;
|
MapEntry<String, String>? apkUrl;
|
||||||
var trackOnly = apps[id]!.app.additionalSettings['trackOnly'] == true;
|
var trackOnly = apps[id]!.app.additionalSettings['trackOnly'] == true;
|
||||||
if (!trackOnly) {
|
if (!trackOnly) {
|
||||||
apkUrl = await confirmApkUrl(apps[id]!.app, context);
|
apkUrl = await confirmApkUrl(apps[id]!.app, context);
|
||||||
@ -923,7 +924,7 @@ class APKPicker extends StatefulWidget {
|
|||||||
const APKPicker({super.key, required this.app, this.initVal, this.archs});
|
const APKPicker({super.key, required this.app, this.initVal, this.archs});
|
||||||
|
|
||||||
final App app;
|
final App app;
|
||||||
final String? initVal;
|
final MapEntry<String, String>? initVal;
|
||||||
final List<String>? archs;
|
final List<String>? archs;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -931,7 +932,7 @@ class APKPicker extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _APKPickerState extends State<APKPicker> {
|
class _APKPickerState extends State<APKPicker> {
|
||||||
String? apkUrl;
|
MapEntry<String, String>? apkUrl;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -944,15 +945,13 @@ class _APKPickerState extends State<APKPicker> {
|
|||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
...widget.app.apkUrls.map(
|
...widget.app.apkUrls.map(
|
||||||
(u) => RadioListTile<String>(
|
(u) => RadioListTile<String>(
|
||||||
title: Text(Uri.parse(u)
|
title: Text(u.key),
|
||||||
.pathSegments
|
value: u.value,
|
||||||
.where((element) => element.isNotEmpty)
|
groupValue: apkUrl!.value,
|
||||||
.last),
|
|
||||||
value: u,
|
|
||||||
groupValue: apkUrl,
|
|
||||||
onChanged: (String? val) {
|
onChanged: (String? val) {
|
||||||
setState(() {
|
setState(() {
|
||||||
apkUrl = val;
|
apkUrl =
|
||||||
|
widget.app.apkUrls.where((e) => e.value == val).first;
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:device_info_plus/device_info_plus.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:html/dom.dart';
|
import 'package:html/dom.dart';
|
||||||
import 'package:http/http.dart';
|
import 'package:http/http.dart';
|
||||||
@ -34,7 +35,7 @@ class AppNames {
|
|||||||
|
|
||||||
class APKDetails {
|
class APKDetails {
|
||||||
late String version;
|
late String version;
|
||||||
late List<String> apkUrls;
|
late List<MapEntry<String, String>> apkUrls;
|
||||||
late AppNames names;
|
late AppNames names;
|
||||||
late DateTime? releaseDate;
|
late DateTime? releaseDate;
|
||||||
late String? changeLog;
|
late String? changeLog;
|
||||||
@ -50,7 +51,7 @@ class App {
|
|||||||
late String name;
|
late String name;
|
||||||
String? installedVersion;
|
String? installedVersion;
|
||||||
late String latestVersion;
|
late String latestVersion;
|
||||||
List<String> apkUrls = [];
|
List<MapEntry<String, String>> apkUrls = [];
|
||||||
late int preferredApkIndex;
|
late int preferredApkIndex;
|
||||||
late Map<String, dynamic> additionalSettings;
|
late Map<String, dynamic> additionalSettings;
|
||||||
late DateTime? lastUpdateCheck;
|
late DateTime? lastUpdateCheck;
|
||||||
@ -134,6 +135,23 @@ class App {
|
|||||||
if (preferredApkIndex < 0) {
|
if (preferredApkIndex < 0) {
|
||||||
preferredApkIndex = 0;
|
preferredApkIndex = 0;
|
||||||
}
|
}
|
||||||
|
// apkUrls can either be old list or new named list apkUrls
|
||||||
|
List<MapEntry<String, String>> apkUrls = [];
|
||||||
|
if (json['apkUrls'] != null) {
|
||||||
|
var apkUrlJson = jsonDecode(json['apkUrls']);
|
||||||
|
try {
|
||||||
|
apkUrls = getApkUrlsFromUrls(List<String>.from(apkUrlJson));
|
||||||
|
} catch (e) {
|
||||||
|
apkUrls = List<dynamic>.from(apkUrlJson)
|
||||||
|
.map((e) => MapEntry(e[0] as String, e[1] as String))
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Arch based APK filter option should be disabled if it previously did not exist
|
||||||
|
if (json['additionalSettings'] != null &&
|
||||||
|
jsonDecode(json['additionalSettings'])['autoApkFilterByArch'] == null) {
|
||||||
|
additionalSettings['autoApkFilterByArch'] = false;
|
||||||
|
}
|
||||||
return App(
|
return App(
|
||||||
json['id'] as String,
|
json['id'] as String,
|
||||||
json['url'] as String,
|
json['url'] as String,
|
||||||
@ -143,9 +161,7 @@ class App {
|
|||||||
? null
|
? null
|
||||||
: json['installedVersion'] as String,
|
: json['installedVersion'] as String,
|
||||||
json['latestVersion'] as String,
|
json['latestVersion'] as String,
|
||||||
json['apkUrls'] == null
|
apkUrls,
|
||||||
? []
|
|
||||||
: List<String>.from(jsonDecode(json['apkUrls'])),
|
|
||||||
preferredApkIndex,
|
preferredApkIndex,
|
||||||
additionalSettings,
|
additionalSettings,
|
||||||
json['lastUpdateCheck'] == null
|
json['lastUpdateCheck'] == null
|
||||||
@ -173,7 +189,7 @@ class App {
|
|||||||
'name': name,
|
'name': name,
|
||||||
'installedVersion': installedVersion,
|
'installedVersion': installedVersion,
|
||||||
'latestVersion': latestVersion,
|
'latestVersion': latestVersion,
|
||||||
'apkUrls': jsonEncode(apkUrls),
|
'apkUrls': jsonEncode(apkUrls.map((e) => [e.key, e.value]).toList()),
|
||||||
'preferredApkIndex': preferredApkIndex,
|
'preferredApkIndex': preferredApkIndex,
|
||||||
'additionalSettings': jsonEncode(additionalSettings),
|
'additionalSettings': jsonEncode(additionalSettings),
|
||||||
'lastUpdateCheck': lastUpdateCheck?.microsecondsSinceEpoch,
|
'lastUpdateCheck': lastUpdateCheck?.microsecondsSinceEpoch,
|
||||||
@ -225,6 +241,11 @@ Map<String, dynamic> getDefaultValuesFromFormItems(
|
|||||||
.reduce((value, element) => [...value, ...element]));
|
.reduce((value, element) => [...value, ...element]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getApkUrlsFromUrls(List<String> urls) => urls
|
||||||
|
.map((e) =>
|
||||||
|
MapEntry(e.split('/').where((el) => el.trim().isNotEmpty).last, e))
|
||||||
|
.toList();
|
||||||
|
|
||||||
class AppSource {
|
class AppSource {
|
||||||
String? host;
|
String? host;
|
||||||
late String name;
|
late String name;
|
||||||
@ -279,6 +300,10 @@ class AppSource {
|
|||||||
}
|
}
|
||||||
])
|
])
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
GeneratedFormSwitch('autoApkFilterByArch',
|
||||||
|
label: tr('autoApkFilterByArch'), defaultValue: true)
|
||||||
|
],
|
||||||
[GeneratedFormTextField('appName', label: tr('appName'), required: false)]
|
[GeneratedFormTextField('appName', label: tr('appName'), required: false)]
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -422,11 +447,24 @@ class SourceProvider {
|
|||||||
if (additionalSettings['apkFilterRegEx'] != null) {
|
if (additionalSettings['apkFilterRegEx'] != null) {
|
||||||
var reg = RegExp(additionalSettings['apkFilterRegEx']);
|
var reg = RegExp(additionalSettings['apkFilterRegEx']);
|
||||||
apk.apkUrls =
|
apk.apkUrls =
|
||||||
apk.apkUrls.where((element) => reg.hasMatch(element)).toList();
|
apk.apkUrls.where((element) => reg.hasMatch(element.key)).toList();
|
||||||
}
|
}
|
||||||
if (apk.apkUrls.isEmpty && !trackOnly) {
|
if (apk.apkUrls.isEmpty && !trackOnly) {
|
||||||
throw NoAPKError();
|
throw NoAPKError();
|
||||||
}
|
}
|
||||||
|
if (apk.apkUrls.length > 1 &&
|
||||||
|
additionalSettings['autoApkFilterByArch'] == true) {
|
||||||
|
var abis = (await DeviceInfoPlugin().androidInfo).supportedAbis;
|
||||||
|
for (var abi in abis) {
|
||||||
|
var urls2 = apk.apkUrls
|
||||||
|
.where((element) => RegExp('.*$abi.*').hasMatch(element.key))
|
||||||
|
.toList();
|
||||||
|
if (urls2.isNotEmpty && urls2.length < apk.apkUrls.length) {
|
||||||
|
apk.apkUrls = urls2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
String apkVersion = apk.version.replaceAll('/', '-');
|
String apkVersion = apk.version.replaceAll('/', '-');
|
||||||
var name = currentApp != null ? currentApp.name.trim() : '';
|
var name = currentApp != null ? currentApp.name.trim() : '';
|
||||||
name = name.isNotEmpty
|
name = name.isNotEmpty
|
||||||
|
@ -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.11.24+146 # When changing this, update the tag in main() accordingly
|
version: 0.11.26+148 # 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'
|
||||||
|
Reference in New Issue
Block a user