mirror of
https://github.com/ImranR98/Obtainium.git
synced 2025-07-14 21:56:44 +02:00
Compare commits
10 Commits
v0.10.3-be
...
v0.10.5-be
Author | SHA1 | Date | |
---|---|---|---|
4252c2711b | |||
52913b0450 | |||
427b0ed8d2 | |||
a85d6d4f08 | |||
05f712603c | |||
fa2a80e34c | |||
f43e5a2ff1 | |||
b72aa8273e | |||
520f186e4a | |||
e1e97672cf |
@ -2,4 +2,5 @@
|
|||||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<background android:drawable="@color/ic_launcher_background"/>
|
<background android:drawable="@color/ic_launcher_background"/>
|
||||||
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||||
|
<monochrome android:drawable="@drawable/ic_launcher_foreground"/>
|
||||||
</adaptive-icon>
|
</adaptive-icon>
|
||||||
|
@ -211,6 +211,7 @@
|
|||||||
"language": "Sprache",
|
"language": "Sprache",
|
||||||
"storagePermissionDenied": "Storage permission denied",
|
"storagePermissionDenied": "Storage permission denied",
|
||||||
"selectedCategorizeWarning": "This will replace any existing category settings for the selected Apps.",
|
"selectedCategorizeWarning": "This will replace any existing category settings for the selected Apps.",
|
||||||
|
"filterAPKsByRegEx": "Filter APKs by Regular Expression",
|
||||||
"tooManyRequestsTryAgainInMinutes": {
|
"tooManyRequestsTryAgainInMinutes": {
|
||||||
"one": "Zu viele Anfragen (Rate begrenzt) - versuchen Sie es in {} Minute erneut",
|
"one": "Zu viele Anfragen (Rate begrenzt) - versuchen Sie es in {} Minute erneut",
|
||||||
"other": "Zu viele Anfragen (Rate begrenzt) - versuchen Sie es in {} Minuten erneut"
|
"other": "Zu viele Anfragen (Rate begrenzt) - versuchen Sie es in {} Minuten erneut"
|
||||||
|
@ -211,6 +211,7 @@
|
|||||||
"language": "Language",
|
"language": "Language",
|
||||||
"storagePermissionDenied": "Storage permission denied",
|
"storagePermissionDenied": "Storage permission denied",
|
||||||
"selectedCategorizeWarning": "This will replace any existing category settings for the selected Apps.",
|
"selectedCategorizeWarning": "This will replace any existing category settings for the selected Apps.",
|
||||||
|
"filterAPKsByRegEx": "Filter APKs by Regular Expression",
|
||||||
"tooManyRequestsTryAgainInMinutes": {
|
"tooManyRequestsTryAgainInMinutes": {
|
||||||
"one": "Too many requests (rate limited) - try again in {} minute",
|
"one": "Too many requests (rate limited) - try again in {} minute",
|
||||||
"other": "Too many requests (rate limited) - try again in {} minutes"
|
"other": "Too many requests (rate limited) - try again in {} minutes"
|
||||||
|
@ -210,6 +210,7 @@
|
|||||||
"language": "Nyelv",
|
"language": "Nyelv",
|
||||||
"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": "Filter APKs by Regular Expression",
|
||||||
"tooManyRequestsTryAgainInMinutes": {
|
"tooManyRequestsTryAgainInMinutes": {
|
||||||
"one": "Túl sok kérés (korlátozott arány) – próbálja újra {} perc múlva",
|
"one": "Túl sok kérés (korlátozott arány) – próbálja újra {} perc múlva",
|
||||||
"other": "Túl sok kérés (korlátozott arány) – próbálja újra {} perc múlva"
|
"other": "Túl sok kérés (korlátozott arány) – próbálja újra {} perc múlva"
|
||||||
|
@ -211,6 +211,7 @@
|
|||||||
"language": "Lingua",
|
"language": "Lingua",
|
||||||
"storagePermissionDenied": "Storage permission denied",
|
"storagePermissionDenied": "Storage permission denied",
|
||||||
"selectedCategorizeWarning": "This will replace any existing category settings for the selected Apps.",
|
"selectedCategorizeWarning": "This will replace any existing category settings for the selected Apps.",
|
||||||
|
"filterAPKsByRegEx": "Filter APKs by Regular Expression",
|
||||||
"tooManyRequestsTryAgainInMinutes": {
|
"tooManyRequestsTryAgainInMinutes": {
|
||||||
"one": "Troppe richieste (traffico limitato) - riprova tra {} minuto",
|
"one": "Troppe richieste (traffico limitato) - riprova tra {} minuto",
|
||||||
"other": "Troppe richieste (traffico limitato) - riprova tra {} minuti"
|
"other": "Troppe richieste (traffico limitato) - riprova tra {} minuti"
|
||||||
|
@ -211,6 +211,7 @@
|
|||||||
"language": "言語",
|
"language": "言語",
|
||||||
"storagePermissionDenied": "ストレージ権限が拒否されました",
|
"storagePermissionDenied": "ストレージ権限が拒否されました",
|
||||||
"selectedCategorizeWarning": "これにより、選択したアプリの既存のカテゴリ設定がすべて置き換えられます。",
|
"selectedCategorizeWarning": "これにより、選択したアプリの既存のカテゴリ設定がすべて置き換えられます。",
|
||||||
|
"filterAPKsByRegEx": "Filter APKs by Regular Expression",
|
||||||
"tooManyRequestsTryAgainInMinutes": {
|
"tooManyRequestsTryAgainInMinutes": {
|
||||||
"one": "リクエストが多すぎます(レート制限)- {}分後に再試行してください",
|
"one": "リクエストが多すぎます(レート制限)- {}分後に再試行してください",
|
||||||
"other": "リクエストが多すぎます(レート制限)- {}分後に再試行してください"
|
"other": "リクエストが多すぎます(レート制限)- {}分後に再試行してください"
|
||||||
|
@ -211,6 +211,7 @@
|
|||||||
"language": "语言",
|
"language": "语言",
|
||||||
"storagePermissionDenied": "存储权限已被拒绝",
|
"storagePermissionDenied": "存储权限已被拒绝",
|
||||||
"selectedCategorizeWarning": "这将取代所选应用程序的任何现有类别",
|
"selectedCategorizeWarning": "这将取代所选应用程序的任何现有类别",
|
||||||
|
"filterAPKsByRegEx": "Filter APKs by Regular Expression",
|
||||||
"tooManyRequestsTryAgainInMinutes": {
|
"tooManyRequestsTryAgainInMinutes": {
|
||||||
"one": "请求过多 (API 限制) - 在 {} 分钟后重试",
|
"one": "请求过多 (API 限制) - 在 {} 分钟后重试",
|
||||||
"other": "请求过多 (API 限制) - 在 {} 分钟后重试"
|
"other": "请求过多 (API 限制) - 在 {} 分钟后重试"
|
||||||
|
@ -26,15 +26,7 @@ class Codeberg extends AppSource {
|
|||||||
required: false,
|
required: false,
|
||||||
additionalValidators: [
|
additionalValidators: [
|
||||||
(value) {
|
(value) {
|
||||||
if (value == null || value.isEmpty) {
|
return regExValidator(value);
|
||||||
return null;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
RegExp(value);
|
|
||||||
} catch (e) {
|
|
||||||
return tr('invalidRegEx');
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
]
|
]
|
||||||
@ -72,7 +64,7 @@ class Codeberg extends AppSource {
|
|||||||
? additionalSettings['filterReleaseTitlesByRegEx']
|
? additionalSettings['filterReleaseTitlesByRegEx']
|
||||||
: null;
|
: null;
|
||||||
Response res = await get(Uri.parse(
|
Response res = await get(Uri.parse(
|
||||||
'https://$host/api/v1/repos${standardUrl.substring('https://$host'.length)}/releases'));
|
'https://$host/api/v1/repos${standardUrl.substring('https://$host'.length)}/releases?per_page=100'));
|
||||||
if (res.statusCode == 200) {
|
if (res.statusCode == 200) {
|
||||||
var releases = jsonDecode(res.body) as List<dynamic>;
|
var releases = jsonDecode(res.body) as List<dynamic>;
|
||||||
|
|
||||||
|
@ -65,15 +65,7 @@ class GitHub extends AppSource {
|
|||||||
required: false,
|
required: false,
|
||||||
additionalValidators: [
|
additionalValidators: [
|
||||||
(value) {
|
(value) {
|
||||||
if (value == null || value.isEmpty) {
|
return regExValidator(value);
|
||||||
return null;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
RegExp(value);
|
|
||||||
} catch (e) {
|
|
||||||
return tr('invalidRegEx');
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
]
|
]
|
||||||
@ -119,7 +111,7 @@ class GitHub extends AppSource {
|
|||||||
? additionalSettings['filterReleaseTitlesByRegEx']
|
? additionalSettings['filterReleaseTitlesByRegEx']
|
||||||
: null;
|
: null;
|
||||||
Response res = await get(Uri.parse(
|
Response res = await get(Uri.parse(
|
||||||
'https://${await getCredentialPrefixIfAny()}api.$host/repos${standardUrl.substring('https://$host'.length)}/releases'));
|
'https://${await getCredentialPrefixIfAny()}api.$host/repos${standardUrl.substring('https://$host'.length)}/releases?per_page=100'));
|
||||||
if (res.statusCode == 200) {
|
if (res.statusCode == 200) {
|
||||||
var releases = jsonDecode(res.body) as List<dynamic>;
|
var releases = jsonDecode(res.body) as List<dynamic>;
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ class NoReleasesError extends ObtainiumError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class NoAPKError extends ObtainiumError {
|
class NoAPKError extends ObtainiumError {
|
||||||
NoAPKError() : super(tr('noReleaseFound'));
|
NoAPKError() : super(tr('noAPKFound'));
|
||||||
}
|
}
|
||||||
|
|
||||||
class NoVersionError extends ObtainiumError {
|
class NoVersionError extends ObtainiumError {
|
||||||
|
@ -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.10.3';
|
const String currentVersion = '0.10.5';
|
||||||
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
|
||||||
|
|
||||||
|
@ -70,6 +70,7 @@ class _AddAppPageState extends State<AddAppPage> {
|
|||||||
additionalSettings['noVersionDetection'] == true;
|
additionalSettings['noVersionDetection'] == true;
|
||||||
var cont = true;
|
var cont = true;
|
||||||
if ((userPickedTrackOnly || pickedSource!.enforceTrackOnly) &&
|
if ((userPickedTrackOnly || pickedSource!.enforceTrackOnly) &&
|
||||||
|
// ignore: use_build_context_synchronously
|
||||||
await showDialog(
|
await showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext ctx) {
|
builder: (BuildContext ctx) {
|
||||||
@ -88,6 +89,7 @@ class _AddAppPageState extends State<AddAppPage> {
|
|||||||
cont = false;
|
cont = false;
|
||||||
}
|
}
|
||||||
if (userPickedNoVersionDetection &&
|
if (userPickedNoVersionDetection &&
|
||||||
|
// ignore: use_build_context_synchronously
|
||||||
await showDialog(
|
await showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext ctx) {
|
builder: (BuildContext ctx) {
|
||||||
|
@ -317,7 +317,7 @@ class _AppPageState extends State<AppPage> {
|
|||||||
tooltip: tr('more')),
|
tooltip: tr('more')),
|
||||||
const SizedBox(width: 16.0),
|
const SizedBox(width: 16.0),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ElevatedButton(
|
child: TextButton(
|
||||||
onPressed: (app?.app.installedVersion == null ||
|
onPressed: (app?.app.installedVersion == null ||
|
||||||
app?.app.installedVersion !=
|
app?.app.installedVersion !=
|
||||||
app?.app.latestVersion) &&
|
app?.app.latestVersion) &&
|
||||||
@ -356,7 +356,8 @@ class _AppPageState extends State<AppPage> {
|
|||||||
? tr('update')
|
? tr('update')
|
||||||
: tr('markUpdated')))),
|
: tr('markUpdated')))),
|
||||||
const SizedBox(width: 16.0),
|
const SizedBox(width: 16.0),
|
||||||
ElevatedButton(
|
Expanded(
|
||||||
|
child: TextButton(
|
||||||
onPressed: app?.downloadProgress != null
|
onPressed: app?.downloadProgress != null
|
||||||
? null
|
? null
|
||||||
: () {
|
: () {
|
||||||
@ -401,7 +402,7 @@ class _AppPageState extends State<AppPage> {
|
|||||||
surfaceTintColor:
|
surfaceTintColor:
|
||||||
Theme.of(context).colorScheme.error),
|
Theme.of(context).colorScheme.error),
|
||||||
child: Text(tr('remove')),
|
child: Text(tr('remove')),
|
||||||
),
|
)),
|
||||||
])),
|
])),
|
||||||
if (app?.downloadProgress != null)
|
if (app?.downloadProgress != null)
|
||||||
Padding(
|
Padding(
|
||||||
|
1056
lib/pages/apps.dart
1056
lib/pages/apps.dart
File diff suppressed because it is too large
Load Diff
@ -4,10 +4,8 @@ import 'package:easy_localization/easy_localization.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:obtainium/components/custom_app_bar.dart';
|
import 'package:obtainium/components/custom_app_bar.dart';
|
||||||
import 'package:obtainium/components/generated_form.dart';
|
import 'package:obtainium/components/generated_form.dart';
|
||||||
import 'package:obtainium/components/generated_form_modal.dart';
|
|
||||||
import 'package:obtainium/custom_errors.dart';
|
import 'package:obtainium/custom_errors.dart';
|
||||||
import 'package:obtainium/main.dart';
|
import 'package:obtainium/main.dart';
|
||||||
import 'package:obtainium/providers/apps_provider.dart';
|
|
||||||
import 'package:obtainium/providers/logs_provider.dart';
|
import 'package:obtainium/providers/logs_provider.dart';
|
||||||
import 'package:obtainium/providers/settings_provider.dart';
|
import 'package:obtainium/providers/settings_provider.dart';
|
||||||
import 'package:obtainium/providers/source_provider.dart';
|
import 'package:obtainium/providers/source_provider.dart';
|
||||||
|
@ -262,6 +262,7 @@ class AppsProvider with ChangeNotifier {
|
|||||||
List<String> archs = (await DeviceInfoPlugin().androidInfo).supportedAbis;
|
List<String> archs = (await DeviceInfoPlugin().androidInfo).supportedAbis;
|
||||||
|
|
||||||
if (app.apkUrls.length > 1 && context != null) {
|
if (app.apkUrls.length > 1 && context != null) {
|
||||||
|
// ignore: use_build_context_synchronously
|
||||||
apkUrl = await showDialog(
|
apkUrl = await showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext ctx) {
|
builder: (BuildContext ctx) {
|
||||||
@ -281,6 +282,7 @@ class AppsProvider with ChangeNotifier {
|
|||||||
if (apkUrl != null &&
|
if (apkUrl != null &&
|
||||||
getHost(apkUrl) != getHost(app.url) &&
|
getHost(apkUrl) != getHost(app.url) &&
|
||||||
context != null) {
|
context != null) {
|
||||||
|
// ignore: use_build_context_synchronously
|
||||||
if (await showDialog(
|
if (await showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext ctx) {
|
builder: (BuildContext ctx) {
|
||||||
|
@ -225,7 +225,19 @@ class AppSource {
|
|||||||
label: tr('trackOnly'),
|
label: tr('trackOnly'),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
[GeneratedFormSwitch('noVersionDetection', label: tr('noVersionDetection'))]
|
[
|
||||||
|
GeneratedFormSwitch('noVersionDetection', label: tr('noVersionDetection'))
|
||||||
|
],
|
||||||
|
[
|
||||||
|
GeneratedFormTextField('apkFilterRegEx',
|
||||||
|
label: tr('filterAPKsByRegEx'),
|
||||||
|
required: false,
|
||||||
|
additionalValidators: [
|
||||||
|
(value) {
|
||||||
|
return regExValidator(value);
|
||||||
|
}
|
||||||
|
])
|
||||||
|
]
|
||||||
];
|
];
|
||||||
|
|
||||||
// Previous 2 variables combined into one at runtime for convenient usage
|
// Previous 2 variables combined into one at runtime for convenient usage
|
||||||
@ -269,6 +281,18 @@ abstract class MassAppUrlSource {
|
|||||||
Future<Map<String, String>> getUrlsWithDescriptions(List<String> args);
|
Future<Map<String, String>> getUrlsWithDescriptions(List<String> args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
regExValidator(String? value) {
|
||||||
|
if (value == null || value.isEmpty) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
RegExp(value);
|
||||||
|
} catch (e) {
|
||||||
|
return tr('invalidRegEx');
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
class SourceProvider {
|
class SourceProvider {
|
||||||
// Add more source classes here so they are available via the service
|
// Add more source classes here so they are available via the service
|
||||||
List<AppSource> sources = [
|
List<AppSource> sources = [
|
||||||
@ -344,10 +368,13 @@ class SourceProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<App> getApp(
|
Future<App> getApp(
|
||||||
AppSource source, String url, Map<String, dynamic> additionalSettings,
|
AppSource source,
|
||||||
{App? currentApp,
|
String url,
|
||||||
bool trackOnlyOverride = false,
|
Map<String, dynamic> additionalSettings, {
|
||||||
noVersionDetectionOverride = false}) async {
|
App? currentApp,
|
||||||
|
bool trackOnlyOverride = false,
|
||||||
|
noVersionDetectionOverride = false,
|
||||||
|
}) async {
|
||||||
if (trackOnlyOverride || source.enforceTrackOnly) {
|
if (trackOnlyOverride || source.enforceTrackOnly) {
|
||||||
additionalSettings['trackOnly'] = true;
|
additionalSettings['trackOnly'] = true;
|
||||||
}
|
}
|
||||||
@ -358,6 +385,11 @@ class SourceProvider {
|
|||||||
String standardUrl = source.standardizeURL(preStandardizeUrl(url));
|
String standardUrl = source.standardizeURL(preStandardizeUrl(url));
|
||||||
APKDetails apk =
|
APKDetails apk =
|
||||||
await source.getLatestAPKDetails(standardUrl, additionalSettings);
|
await source.getLatestAPKDetails(standardUrl, additionalSettings);
|
||||||
|
if (additionalSettings['apkFilterRegEx'] != null) {
|
||||||
|
var reg = RegExp(additionalSettings['apkFilterRegEx']);
|
||||||
|
apk.apkUrls =
|
||||||
|
apk.apkUrls.where((element) => reg.hasMatch(element)).toList();
|
||||||
|
}
|
||||||
if (apk.apkUrls.isEmpty && !trackOnly) {
|
if (apk.apkUrls.isEmpty && !trackOnly) {
|
||||||
throw NoAPKError();
|
throw NoAPKError();
|
||||||
}
|
}
|
||||||
|
398
pubspec.lock
398
pubspec.lock
File diff suppressed because it is too large
Load Diff
@ -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.10.3+109 # When changing this, update the tag in main() accordingly
|
version: 0.10.5+111 # 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