mirror of
https://github.com/ImranR98/Obtainium.git
synced 2025-07-14 21:56:44 +02:00
Compare commits
13 Commits
v0.13.21-b
...
v0.13.22-b
Author | SHA1 | Date | |
---|---|---|---|
e36e6bbaca | |||
ac3a13ed73 | |||
202f7df5cb | |||
1b902b1a18 | |||
1765d399c8 | |||
5dd79707f1 | |||
14755134bf | |||
cccde7e135 | |||
3dafd643c0 | |||
76f8cd4102 | |||
a8bfb03f58 | |||
10ead4f3e0 | |||
af5a6857ba |
@ -240,6 +240,10 @@
|
|||||||
"disablePageTransitions": "Ugasite animaciju prijelaza stranice",
|
"disablePageTransitions": "Ugasite animaciju prijelaza stranice",
|
||||||
"reversePageTransitions": "Reverzne animacije prijelaza stranice",
|
"reversePageTransitions": "Reverzne animacije prijelaza stranice",
|
||||||
"minStarCount": "Minimum Star Count",
|
"minStarCount": "Minimum Star Count",
|
||||||
|
"addInfoBelow": "Add this info below.",
|
||||||
|
"addInfoInSettings": "Add this info in the Settings.",
|
||||||
|
"githubSourceNote": "GitHub rate limiting can be avoided using an API key.",
|
||||||
|
"gitlabSourceNote": "GitLab APK extraction may not work without an API key.",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "Želite li ukloniti aplikaciju?",
|
"one": "Želite li ukloniti aplikaciju?",
|
||||||
"other": "Želite li ukloniti aplikacije?"
|
"other": "Želite li ukloniti aplikacije?"
|
||||||
|
@ -233,13 +233,17 @@
|
|||||||
"about": "Über",
|
"about": "Über",
|
||||||
"requiresCredentialsInSettings": "Benötigt zusätzliche Anmeldedaten (in den Einstellungen)",
|
"requiresCredentialsInSettings": "Benötigt zusätzliche Anmeldedaten (in den Einstellungen)",
|
||||||
"checkOnStart": "Überprüfe einmalig beim Start",
|
"checkOnStart": "Überprüfe einmalig beim Start",
|
||||||
"tryInferAppIdFromCode": "Try inferring App ID from source code",
|
"tryInferAppIdFromCode": "Versuche, die App-ID aus dem Quellcode zu ermitteln",
|
||||||
"removeOnExternalUninstall": "Automatically remove externally uninstalled Apps",
|
"removeOnExternalUninstall": "Automatisches Entfernen von extern deinstallierten Apps",
|
||||||
"pickHighestVersionCode": "Auto-select highest version code APK",
|
"pickHighestVersionCode": "Automatische Auswahl des APK mit höchstem Versionscode",
|
||||||
"checkUpdateOnDetailPage": "Check for updates on opening an App detail page",
|
"checkUpdateOnDetailPage": "Nach Updates suchen, wenn eine App-Detailseite geöffnet wird",
|
||||||
"disablePageTransitions": "Disable page transition animations",
|
"disablePageTransitions": "Animationen für Seitenübergänge deaktivieren",
|
||||||
"reversePageTransitions": "Reverse page transition animations",
|
"reversePageTransitions": "Umgekehrte Animationen für Seitenübergänge",
|
||||||
"minStarCount": "Minimum Star Count",
|
"minStarCount": "Minimale Anzahl von Sternen",
|
||||||
|
"addInfoBelow": "Add this info below.",
|
||||||
|
"addInfoInSettings": "Add this info in the Settings.",
|
||||||
|
"githubSourceNote": "GitHub rate limiting can be avoided using an API key.",
|
||||||
|
"gitlabSourceNote": "GitLab APK extraction may not work without an API key.",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "App entfernen?",
|
"one": "App entfernen?",
|
||||||
"other": "Apps entfernen?"
|
"other": "Apps entfernen?"
|
||||||
|
@ -240,6 +240,10 @@
|
|||||||
"disablePageTransitions": "Disable page transition animations",
|
"disablePageTransitions": "Disable page transition animations",
|
||||||
"reversePageTransitions": "Reverse page transition animations",
|
"reversePageTransitions": "Reverse page transition animations",
|
||||||
"minStarCount": "Minimum Star Count",
|
"minStarCount": "Minimum Star Count",
|
||||||
|
"addInfoBelow": "Add this info below.",
|
||||||
|
"addInfoInSettings": "Add this info in the Settings.",
|
||||||
|
"githubSourceNote": "GitHub rate limiting can be avoided using an API key.",
|
||||||
|
"gitlabSourceNote": "GitLab APK extraction may not work without an API key.",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "Remove App?",
|
"one": "Remove App?",
|
||||||
"other": "Remove Apps?"
|
"other": "Remove Apps?"
|
||||||
|
@ -240,6 +240,10 @@
|
|||||||
"disablePageTransitions": "Disable page transition animations",
|
"disablePageTransitions": "Disable page transition animations",
|
||||||
"reversePageTransitions": "Reverse page transition animations",
|
"reversePageTransitions": "Reverse page transition animations",
|
||||||
"minStarCount": "Minimum Star Count",
|
"minStarCount": "Minimum Star Count",
|
||||||
|
"addInfoBelow": "Add this info below.",
|
||||||
|
"addInfoInSettings": "Add this info in the Settings.",
|
||||||
|
"githubSourceNote": "GitHub rate limiting can be avoided using an API key.",
|
||||||
|
"gitlabSourceNote": "GitLab APK extraction may not work without an API key.",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "¿Eliminar Aplicación?",
|
"one": "¿Eliminar Aplicación?",
|
||||||
"other": "¿Eliminar Aplicaciones?"
|
"other": "¿Eliminar Aplicaciones?"
|
||||||
|
@ -240,6 +240,10 @@
|
|||||||
"disablePageTransitions": "Disable page transition animations",
|
"disablePageTransitions": "Disable page transition animations",
|
||||||
"reversePageTransitions": "Reverse page transition animations",
|
"reversePageTransitions": "Reverse page transition animations",
|
||||||
"minStarCount": "Minimum Star Count",
|
"minStarCount": "Minimum Star Count",
|
||||||
|
"addInfoBelow": "Add this info below.",
|
||||||
|
"addInfoInSettings": "Add this info in the Settings.",
|
||||||
|
"githubSourceNote": "GitHub rate limiting can be avoided using an API key.",
|
||||||
|
"gitlabSourceNote": "GitLab APK extraction may not work without an API key.",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "برنامه حذف شود؟",
|
"one": "برنامه حذف شود؟",
|
||||||
"other": "برنامه ها حذف شوند؟"
|
"other": "برنامه ها حذف شوند؟"
|
||||||
|
@ -240,6 +240,10 @@
|
|||||||
"disablePageTransitions": "Disable page transition animations",
|
"disablePageTransitions": "Disable page transition animations",
|
||||||
"reversePageTransitions": "Reverse page transition animations",
|
"reversePageTransitions": "Reverse page transition animations",
|
||||||
"minStarCount": "Minimum Star Count",
|
"minStarCount": "Minimum Star Count",
|
||||||
|
"addInfoBelow": "Add this info below.",
|
||||||
|
"addInfoInSettings": "Add this info in the Settings.",
|
||||||
|
"githubSourceNote": "GitHub rate limiting can be avoided using an API key.",
|
||||||
|
"gitlabSourceNote": "GitLab APK extraction may not work without an API key.",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "Supprimer l'application ?",
|
"one": "Supprimer l'application ?",
|
||||||
"other": "Supprimer les applications ?"
|
"other": "Supprimer les applications ?"
|
||||||
|
@ -239,6 +239,10 @@
|
|||||||
"disablePageTransitions": "Lap áttűnési animációk tiltása",
|
"disablePageTransitions": "Lap áttűnési animációk tiltása",
|
||||||
"reversePageTransitions": "Fordított lap áttűnési animációk",
|
"reversePageTransitions": "Fordított lap áttűnési animációk",
|
||||||
"minStarCount": "Minimális csillag szám",
|
"minStarCount": "Minimális csillag szám",
|
||||||
|
"addInfoBelow": "Add this info below.",
|
||||||
|
"addInfoInSettings": "Add this info in the Settings.",
|
||||||
|
"githubSourceNote": "GitHub rate limiting can be avoided using an API key.",
|
||||||
|
"gitlabSourceNote": "GitLab APK extraction may not work without an API key.",
|
||||||
"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?"
|
||||||
|
@ -240,6 +240,10 @@
|
|||||||
"disablePageTransitions": "Disable page transition animations",
|
"disablePageTransitions": "Disable page transition animations",
|
||||||
"reversePageTransitions": "Reverse page transition animations",
|
"reversePageTransitions": "Reverse page transition animations",
|
||||||
"minStarCount": "Minimum Star Count",
|
"minStarCount": "Minimum Star Count",
|
||||||
|
"addInfoBelow": "Add this info below.",
|
||||||
|
"addInfoInSettings": "Add this info in the Settings.",
|
||||||
|
"githubSourceNote": "GitHub rate limiting can be avoided using an API key.",
|
||||||
|
"gitlabSourceNote": "GitLab APK extraction may not work without an API key.",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "Rimuovere l'app?",
|
"one": "Rimuovere l'app?",
|
||||||
"other": "Rimuovere le app?"
|
"other": "Rimuovere le app?"
|
||||||
|
@ -240,6 +240,10 @@
|
|||||||
"disablePageTransitions": "ページ遷移アニメーションを無効化する",
|
"disablePageTransitions": "ページ遷移アニメーションを無効化する",
|
||||||
"reversePageTransitions": "ページ遷移アニメーションを反転する",
|
"reversePageTransitions": "ページ遷移アニメーションを反転する",
|
||||||
"minStarCount": "Minimum Star Count",
|
"minStarCount": "Minimum Star Count",
|
||||||
|
"addInfoBelow": "Add this info below.",
|
||||||
|
"addInfoInSettings": "Add this info in the Settings.",
|
||||||
|
"githubSourceNote": "GitHub rate limiting can be avoided using an API key.",
|
||||||
|
"gitlabSourceNote": "GitLab APK extraction may not work without an API key.",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "アプリを削除しますか?",
|
"one": "アプリを削除しますか?",
|
||||||
"other": "アプリを削除しますか?"
|
"other": "アプリを削除しますか?"
|
||||||
|
@ -243,7 +243,11 @@
|
|||||||
"checkUpdateOnDetailPage": "Sprawdzaj aktualizacje podczas otwierania strony szczegółów aplikacji",
|
"checkUpdateOnDetailPage": "Sprawdzaj aktualizacje podczas otwierania strony szczegółów aplikacji",
|
||||||
"disablePageTransitions": "Wyłącz animacje przejścia między stronami",
|
"disablePageTransitions": "Wyłącz animacje przejścia między stronami",
|
||||||
"reversePageTransitions": "Odwróć animacje przejścia pomiędzy stronami",
|
"reversePageTransitions": "Odwróć animacje przejścia pomiędzy stronami",
|
||||||
"minStarCount": "Minimum Star Count",
|
"minStarCount": "Minimalna ilość gwiazdek",
|
||||||
|
"addInfoBelow": "Add this info below.",
|
||||||
|
"addInfoInSettings": "Add this info in the Settings.",
|
||||||
|
"githubSourceNote": "GitHub rate limiting can be avoided using an API key.",
|
||||||
|
"gitlabSourceNote": "GitLab APK extraction may not work without an API key.",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "Usunąć aplikację?",
|
"one": "Usunąć aplikację?",
|
||||||
"other": "Usunąć aplikacje?"
|
"other": "Usunąć aplikacje?"
|
||||||
|
@ -240,6 +240,10 @@
|
|||||||
"disablePageTransitions": "Отключить анимацию перехода между страницами",
|
"disablePageTransitions": "Отключить анимацию перехода между страницами",
|
||||||
"reversePageTransitions": "Реверс анимации перехода между страницами",
|
"reversePageTransitions": "Реверс анимации перехода между страницами",
|
||||||
"minStarCount": "Минимальное количество звёзд",
|
"minStarCount": "Минимальное количество звёзд",
|
||||||
|
"addInfoBelow": "Add this info below.",
|
||||||
|
"addInfoInSettings": "Add this info in the Settings.",
|
||||||
|
"githubSourceNote": "GitHub rate limiting can be avoided using an API key.",
|
||||||
|
"gitlabSourceNote": "GitLab APK extraction may not work without an API key.",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "Удалить приложение?",
|
"one": "Удалить приложение?",
|
||||||
"other": "Удалить приложения?"
|
"other": "Удалить приложения?"
|
||||||
|
@ -240,6 +240,10 @@
|
|||||||
"disablePageTransitions": "禁用页面过渡动画效果",
|
"disablePageTransitions": "禁用页面过渡动画效果",
|
||||||
"reversePageTransitions": "反转页面过渡动画效果",
|
"reversePageTransitions": "反转页面过渡动画效果",
|
||||||
"minStarCount": "最小星标数",
|
"minStarCount": "最小星标数",
|
||||||
|
"addInfoBelow": "Add this info below.",
|
||||||
|
"addInfoInSettings": "Add this info in the Settings.",
|
||||||
|
"githubSourceNote": "GitHub rate limiting can be avoided using an API key.",
|
||||||
|
"gitlabSourceNote": "GitLab APK extraction may not work without an API key.",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "是否删除应用?",
|
"one": "是否删除应用?",
|
||||||
"other": "是否删除应用?"
|
"other": "是否删除应用?"
|
||||||
|
@ -9,8 +9,6 @@ class Codeberg extends AppSource {
|
|||||||
Codeberg() {
|
Codeberg() {
|
||||||
host = 'codeberg.org';
|
host = 'codeberg.org';
|
||||||
|
|
||||||
additionalSourceSpecificSettingFormItems = [];
|
|
||||||
|
|
||||||
additionalSourceAppSpecificSettingFormItems = [
|
additionalSourceAppSpecificSettingFormItems = [
|
||||||
[
|
[
|
||||||
GeneratedFormSwitch('includePrereleases',
|
GeneratedFormSwitch('includePrereleases',
|
||||||
|
@ -16,7 +16,7 @@ class GitHub extends AppSource {
|
|||||||
host = 'github.com';
|
host = 'github.com';
|
||||||
appIdInferIsOptional = true;
|
appIdInferIsOptional = true;
|
||||||
|
|
||||||
additionalSourceSpecificSettingFormItems = [
|
sourceConfigSettingFormItems = [
|
||||||
GeneratedFormTextField('github-creds',
|
GeneratedFormTextField('github-creds',
|
||||||
label: tr('githubPATLabel'),
|
label: tr('githubPATLabel'),
|
||||||
password: true,
|
password: true,
|
||||||
@ -107,7 +107,7 @@ class GitHub extends AppSource {
|
|||||||
for (var path in possibleBuildGradleLocations) {
|
for (var path in possibleBuildGradleLocations) {
|
||||||
try {
|
try {
|
||||||
var res = await sourceRequest(
|
var res = await sourceRequest(
|
||||||
'${await convertStandardUrlToAPIUrl(standardUrl)}/contents/$path');
|
'${await convertStandardUrlToAPIUrl(standardUrl, additionalSettings)}/contents/$path');
|
||||||
if (res.statusCode == 200) {
|
if (res.statusCode == 200) {
|
||||||
try {
|
try {
|
||||||
var body = jsonDecode(res.body);
|
var body = jsonDecode(res.body);
|
||||||
@ -155,19 +155,30 @@ class GitHub extends AppSource {
|
|||||||
return url.substring(0, match.end);
|
return url.substring(0, match.end);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String> getCredentialPrefixIfAny() async {
|
Future<String> getCredentialPrefixIfAny(
|
||||||
|
Map<String, dynamic> additionalSettings) async {
|
||||||
SettingsProvider settingsProvider = SettingsProvider();
|
SettingsProvider settingsProvider = SettingsProvider();
|
||||||
await settingsProvider.initializeSettings();
|
await settingsProvider.initializeSettings();
|
||||||
String? creds = settingsProvider
|
var sourceConfig =
|
||||||
.getSettingString(additionalSourceSpecificSettingFormItems[0].key);
|
await getSourceConfigValues(additionalSettings, settingsProvider);
|
||||||
|
String? creds = sourceConfig['github-creds'];
|
||||||
return creds != null && creds.isNotEmpty ? '$creds@' : '';
|
return creds != null && creds.isNotEmpty ? '$creds@' : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String> getAPIHost() async =>
|
@override
|
||||||
'https://${await getCredentialPrefixIfAny()}api.$host';
|
Future<String?> getSourceNote() async {
|
||||||
|
if (!hostChanged && (await getCredentialPrefixIfAny({})).isEmpty) {
|
||||||
|
return '${tr('githubSourceNote')} ${hostChanged ? tr('addInfoBelow') : tr('addInfoInSettings')}';
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
Future<String> convertStandardUrlToAPIUrl(String standardUrl) async =>
|
Future<String> getAPIHost(Map<String, dynamic> additionalSettings) async =>
|
||||||
'${await getAPIHost()}/repos${standardUrl.substring('https://$host'.length)}';
|
'https://${await getCredentialPrefixIfAny(additionalSettings)}api.$host';
|
||||||
|
|
||||||
|
Future<String> convertStandardUrlToAPIUrl(
|
||||||
|
String standardUrl, Map<String, dynamic> additionalSettings) async =>
|
||||||
|
'${await getAPIHost(additionalSettings)}/repos${standardUrl.substring('https://$host'.length)}';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String? changeLogPageFromStandardUrl(String standardUrl) =>
|
String? changeLogPageFromStandardUrl(String standardUrl) =>
|
||||||
@ -311,7 +322,7 @@ class GitHub extends AppSource {
|
|||||||
) async {
|
) async {
|
||||||
return await getLatestAPKDetailsCommon2(standardUrl, additionalSettings,
|
return await getLatestAPKDetailsCommon2(standardUrl, additionalSettings,
|
||||||
(bool useTagUrl) async {
|
(bool useTagUrl) async {
|
||||||
return '${await convertStandardUrlToAPIUrl(standardUrl)}/${useTagUrl ? 'tags' : 'releases'}?per_page=100';
|
return '${await convertStandardUrlToAPIUrl(standardUrl, additionalSettings)}/${useTagUrl ? 'tags' : 'releases'}?per_page=100';
|
||||||
}, (Response res) {
|
}, (Response res) {
|
||||||
rateLimitErrorCheck(res);
|
rateLimitErrorCheck(res);
|
||||||
});
|
});
|
||||||
@ -360,7 +371,7 @@ class GitHub extends AppSource {
|
|||||||
{Map<String, dynamic> querySettings = const {}}) async {
|
{Map<String, dynamic> querySettings = const {}}) async {
|
||||||
return searchCommon(
|
return searchCommon(
|
||||||
query,
|
query,
|
||||||
'${await getAPIHost()}/search/repositories?q=${Uri.encodeQueryComponent(query)}&per_page=100',
|
'${await getAPIHost({})}/search/repositories?q=${Uri.encodeQueryComponent(query)}&per_page=100',
|
||||||
'items', onHttpErrorCode: (Response res) {
|
'items', onHttpErrorCode: (Response res) {
|
||||||
rateLimitErrorCheck(res);
|
rateLimitErrorCheck(res);
|
||||||
}, querySettings: querySettings);
|
}, querySettings: querySettings);
|
||||||
|
@ -16,7 +16,7 @@ class GitLab extends AppSource {
|
|||||||
host = 'gitlab.com';
|
host = 'gitlab.com';
|
||||||
canSearch = true;
|
canSearch = true;
|
||||||
|
|
||||||
additionalSourceSpecificSettingFormItems = [
|
sourceConfigSettingFormItems = [
|
||||||
GeneratedFormTextField('gitlab-creds',
|
GeneratedFormTextField('gitlab-creds',
|
||||||
label: tr('gitlabPATLabel'),
|
label: tr('gitlabPATLabel'),
|
||||||
password: true,
|
password: true,
|
||||||
@ -60,18 +60,27 @@ class GitLab extends AppSource {
|
|||||||
return url.substring(0, match.end);
|
return url.substring(0, match.end);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String?> getPATIfAny() async {
|
Future<String?> getPATIfAny(Map<String, dynamic> additionalSettings) async {
|
||||||
SettingsProvider settingsProvider = SettingsProvider();
|
SettingsProvider settingsProvider = SettingsProvider();
|
||||||
await settingsProvider.initializeSettings();
|
await settingsProvider.initializeSettings();
|
||||||
String? creds = settingsProvider
|
var sourceConfig =
|
||||||
.getSettingString(additionalSourceSpecificSettingFormItems[0].key);
|
await getSourceConfigValues(additionalSettings, settingsProvider);
|
||||||
|
String? creds = sourceConfig['gitlab-creds'];
|
||||||
return creds != null && creds.isNotEmpty ? creds : null;
|
return creds != null && creds.isNotEmpty ? creds : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<String?> getSourceNote() async {
|
||||||
|
if ((await getPATIfAny({})) == null) {
|
||||||
|
return '${tr('gitlabSourceNote')} ${hostChanged ? tr('addInfoBelow') : tr('addInfoInSettings')}';
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Map<String, List<String>>> search(String query,
|
Future<Map<String, List<String>>> search(String query,
|
||||||
{Map<String, dynamic> querySettings = const {}}) async {
|
{Map<String, dynamic> querySettings = const {}}) async {
|
||||||
String? PAT = await getPATIfAny();
|
String? PAT = await getPATIfAny({});
|
||||||
if (PAT == null) {
|
if (PAT == null) {
|
||||||
throw CredsNeededError(name);
|
throw CredsNeededError(name);
|
||||||
}
|
}
|
||||||
@ -103,7 +112,7 @@ class GitLab extends AppSource {
|
|||||||
) async {
|
) async {
|
||||||
bool fallbackToOlderReleases =
|
bool fallbackToOlderReleases =
|
||||||
additionalSettings['fallbackToOlderReleases'] == true;
|
additionalSettings['fallbackToOlderReleases'] == true;
|
||||||
String? PAT = await getPATIfAny();
|
String? PAT = await getPATIfAny(hostChanged ? additionalSettings : {});
|
||||||
Iterable<APKDetails> apkDetailsList = [];
|
Iterable<APKDetails> apkDetailsList = [];
|
||||||
if (PAT != null) {
|
if (PAT != null) {
|
||||||
var names = GitHub().getAppNames(standardUrl);
|
var names = GitHub().getAppNames(standardUrl);
|
||||||
|
@ -3,6 +3,7 @@ import 'dart:math';
|
|||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:http/http.dart';
|
||||||
import 'package:obtainium/custom_errors.dart';
|
import 'package:obtainium/custom_errors.dart';
|
||||||
import 'package:obtainium/pages/home.dart';
|
import 'package:obtainium/pages/home.dart';
|
||||||
import 'package:obtainium/providers/apps_provider.dart';
|
import 'package:obtainium/providers/apps_provider.dart';
|
||||||
@ -21,7 +22,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.13.21';
|
const String currentVersion = '0.13.22';
|
||||||
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
|
||||||
|
|
||||||
@ -101,10 +102,15 @@ Future<void> bgUpdateCheck(int taskId, Map<String, dynamic>? params) async {
|
|||||||
await appsProvider.checkUpdates(
|
await appsProvider.checkUpdates(
|
||||||
ignoreAppsCheckedAfter: ignoreAfter, throwErrorsForRetry: true);
|
ignoreAppsCheckedAfter: ignoreAfter, throwErrorsForRetry: true);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e is RateLimitError || e is SocketException) {
|
if (e is RateLimitError || e is ClientException) {
|
||||||
var remainingMinutes = e is RateLimitError ? e.remainingMinutes : 15;
|
var remainingMinutes = e is RateLimitError ? e.remainingMinutes : 15;
|
||||||
logs.add(plural('bgUpdateGotErrorRetryInMinutes', remainingMinutes,
|
logs.add(
|
||||||
args: [e.toString(), remainingMinutes.toString()]));
|
plural('bgUpdateGotErrorRetryInMinutes', remainingMinutes, args: [
|
||||||
|
e is ClientException
|
||||||
|
? '${(e).message}, ${e.uri?.path}'
|
||||||
|
: e.toString(),
|
||||||
|
remainingMinutes.toString()
|
||||||
|
]));
|
||||||
AndroidAlarmManager.oneShot(Duration(minutes: remainingMinutes),
|
AndroidAlarmManager.oneShot(Duration(minutes: remainingMinutes),
|
||||||
Random().nextInt(pow(2, 31) as int), bgUpdateCheck, params: {
|
Random().nextInt(pow(2, 31) as int), bgUpdateCheck, params: {
|
||||||
'ignoreAfterMicroseconds': nextIgnoreAfter.microsecondsSinceEpoch
|
'ignoreAfterMicroseconds': nextIgnoreAfter.microsecondsSinceEpoch
|
||||||
|
@ -16,7 +16,7 @@ class GitHubStars implements MassAppUrlSource {
|
|||||||
Future<Map<String, List<String>>> getOnePageOfUserStarredUrlsWithDescriptions(
|
Future<Map<String, List<String>>> getOnePageOfUserStarredUrlsWithDescriptions(
|
||||||
String username, int page) async {
|
String username, int page) async {
|
||||||
Response res = await get(Uri.parse(
|
Response res = await get(Uri.parse(
|
||||||
'https://${await GitHub().getCredentialPrefixIfAny()}api.github.com/users/$username/starred?per_page=100&page=$page'));
|
'https://${await GitHub().getCredentialPrefixIfAny({})}api.github.com/users/$username/starred?per_page=100&page=$page'));
|
||||||
if (res.statusCode == 200) {
|
if (res.statusCode == 200) {
|
||||||
Map<String, List<String>> urlsWithDescriptions = {};
|
Map<String, List<String>> urlsWithDescriptions = {};
|
||||||
for (var e in (jsonDecode(res.body) as List<dynamic>)) {
|
for (var e in (jsonDecode(res.body) as List<dynamic>)) {
|
||||||
|
@ -41,6 +41,7 @@ class _AddAppPageState extends State<AddAppPage> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
AppsProvider appsProvider = context.read<AppsProvider>();
|
AppsProvider appsProvider = context.read<AppsProvider>();
|
||||||
|
SettingsProvider settingsProvider = context.watch<SettingsProvider>();
|
||||||
|
|
||||||
bool doingSomething = gettingAppInfo || searching;
|
bool doingSomething = gettingAppInfo || searching;
|
||||||
|
|
||||||
@ -85,8 +86,7 @@ class _AddAppPageState extends State<AddAppPage> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> getTrackOnlyConfirmationIfNeeded(
|
Future<bool> getTrackOnlyConfirmationIfNeeded(bool userPickedTrackOnly,
|
||||||
bool userPickedTrackOnly, SettingsProvider settingsProvider,
|
|
||||||
{bool ignoreHideSetting = false}) async {
|
{bool ignoreHideSetting = false}) async {
|
||||||
var useTrackOnly = userPickedTrackOnly || pickedSource!.enforceTrackOnly;
|
var useTrackOnly = userPickedTrackOnly || pickedSource!.enforceTrackOnly;
|
||||||
if (useTrackOnly &&
|
if (useTrackOnly &&
|
||||||
@ -138,11 +138,9 @@ class _AddAppPageState extends State<AddAppPage> {
|
|||||||
gettingAppInfo = true;
|
gettingAppInfo = true;
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
var settingsProvider = context.read<SettingsProvider>();
|
|
||||||
var userPickedTrackOnly = additionalSettings['trackOnly'] == true;
|
var userPickedTrackOnly = additionalSettings['trackOnly'] == true;
|
||||||
App? app;
|
App? app;
|
||||||
if ((await getTrackOnlyConfirmationIfNeeded(
|
if ((await getTrackOnlyConfirmationIfNeeded(userPickedTrackOnly)) &&
|
||||||
userPickedTrackOnly, settingsProvider)) &&
|
|
||||||
(await getReleaseDateAsVersionConfirmationIfNeeded(
|
(await getReleaseDateAsVersionConfirmationIfNeeded(
|
||||||
userPickedTrackOnly))) {
|
userPickedTrackOnly))) {
|
||||||
var trackOnly = pickedSource!.enforceTrackOnly || userPickedTrackOnly;
|
var trackOnly = pickedSource!.enforceTrackOnly || userPickedTrackOnly;
|
||||||
@ -410,7 +408,13 @@ class _AddAppPageState extends State<AddAppPage> {
|
|||||||
),
|
),
|
||||||
GeneratedForm(
|
GeneratedForm(
|
||||||
key: Key(pickedSource.runtimeType.toString()),
|
key: Key(pickedSource.runtimeType.toString()),
|
||||||
items: pickedSource!.combinedAppSpecificSettingFormItems,
|
items: [
|
||||||
|
...pickedSource!.combinedAppSpecificSettingFormItems,
|
||||||
|
...(pickedSourceOverride != null
|
||||||
|
? pickedSource!.sourceConfigSettingFormItems
|
||||||
|
.map((e) => [e])
|
||||||
|
: [])
|
||||||
|
],
|
||||||
onValueChanges: (values, valid, isBuilding) {
|
onValueChanges: (values, valid, isBuilding) {
|
||||||
if (!isBuilding) {
|
if (!isBuilding) {
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -504,6 +508,18 @@ class _AddAppPageState extends State<AddAppPage> {
|
|||||||
HTML().runtimeType.toString()))
|
HTML().runtimeType.toString()))
|
||||||
getHTMLSourceOverrideDropdown(),
|
getHTMLSourceOverrideDropdown(),
|
||||||
if (shouldShowSearchBar()) getSearchBarRow(),
|
if (shouldShowSearchBar()) getSearchBarRow(),
|
||||||
|
if (pickedSource != null)
|
||||||
|
FutureBuilder(
|
||||||
|
builder: (ctx, val) {
|
||||||
|
return val.data != null && val.data!.isNotEmpty
|
||||||
|
? Text(
|
||||||
|
val.data!,
|
||||||
|
style:
|
||||||
|
Theme.of(context).textTheme.bodySmall,
|
||||||
|
)
|
||||||
|
: const SizedBox();
|
||||||
|
},
|
||||||
|
future: pickedSource?.getSourceNote()),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 16,
|
height: 16,
|
||||||
),
|
),
|
||||||
|
@ -431,8 +431,7 @@ class _AppPageState extends State<AppPage> {
|
|||||||
? getResetInstallStatusButton()
|
? getResetInstallStatusButton()
|
||||||
: getInstallOrUpdateButton()),
|
: getInstallOrUpdateButton()),
|
||||||
const SizedBox(width: 16.0),
|
const SizedBox(width: 16.0),
|
||||||
Expanded(
|
IconButton(
|
||||||
child: TextButton(
|
|
||||||
onPressed: app?.downloadProgress != null
|
onPressed: app?.downloadProgress != null
|
||||||
? null
|
? null
|
||||||
: () {
|
: () {
|
||||||
@ -445,13 +444,9 @@ class _AppPageState extends State<AppPage> {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
style: TextButton.styleFrom(
|
tooltip: tr('remove'),
|
||||||
foregroundColor:
|
icon: const Icon(Icons.delete_outline),
|
||||||
Theme.of(context).colorScheme.error,
|
),
|
||||||
surfaceTintColor:
|
|
||||||
Theme.of(context).colorScheme.error),
|
|
||||||
child: Text(tr('remove')),
|
|
||||||
)),
|
|
||||||
])),
|
])),
|
||||||
if (app?.downloadProgress != null)
|
if (app?.downloadProgress != null)
|
||||||
Padding(
|
Padding(
|
||||||
|
@ -543,7 +543,6 @@ class AppsPageState extends State<AppsPage> {
|
|||||||
: FontWeight.normal)),
|
: FontWeight.normal)),
|
||||||
trailing: listedApps[index].downloadProgress != null
|
trailing: listedApps[index].downloadProgress != null
|
||||||
? SizedBox(
|
? SizedBox(
|
||||||
width: 90,
|
|
||||||
child: Text(
|
child: Text(
|
||||||
listedApps[index].downloadProgress! >= 0
|
listedApps[index].downloadProgress! >= 0
|
||||||
? tr('percentProgress', args: [
|
? tr('percentProgress', args: [
|
||||||
|
@ -166,9 +166,9 @@ class _SettingsPageState extends State<SettingsPage> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
var sourceSpecificFields = sourceProvider.sources.map((e) {
|
var sourceSpecificFields = sourceProvider.sources.map((e) {
|
||||||
if (e.additionalSourceSpecificSettingFormItems.isNotEmpty) {
|
if (e.sourceConfigSettingFormItems.isNotEmpty) {
|
||||||
return GeneratedForm(
|
return GeneratedForm(
|
||||||
items: e.additionalSourceSpecificSettingFormItems.map((e) {
|
items: e.sourceConfigSettingFormItems.map((e) {
|
||||||
e.defaultValue = settingsProvider.getSettingString(e.key);
|
e.defaultValue = settingsProvider.getSettingString(e.key);
|
||||||
return [e];
|
return [e];
|
||||||
}).toList(),
|
}).toList(),
|
||||||
|
@ -154,6 +154,7 @@ class AppsProvider with ChangeNotifier {
|
|||||||
useExisting: useExisting, headers: headers);
|
useExisting: useExisting, headers: headers);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (retries > 0 && e is ClientException) {
|
if (retries > 0 && e is ClientException) {
|
||||||
|
await Future.delayed(const Duration(seconds: 5));
|
||||||
return await downloadFileWithRetry(url, fileNameNoExt, onProgress,
|
return await downloadFileWithRetry(url, fileNameNoExt, onProgress,
|
||||||
useExisting: useExisting, headers: headers, retries: (retries - 1));
|
useExisting: useExisting, headers: headers, retries: (retries - 1));
|
||||||
} else {
|
} else {
|
||||||
|
@ -28,6 +28,7 @@ import 'package:obtainium/app_sources/vlc.dart';
|
|||||||
import 'package:obtainium/components/generated_form.dart';
|
import 'package:obtainium/components/generated_form.dart';
|
||||||
import 'package:obtainium/custom_errors.dart';
|
import 'package:obtainium/custom_errors.dart';
|
||||||
import 'package:obtainium/mass_app_sources/githubstars.dart';
|
import 'package:obtainium/mass_app_sources/githubstars.dart';
|
||||||
|
import 'package:obtainium/providers/settings_provider.dart';
|
||||||
|
|
||||||
class AppNames {
|
class AppNames {
|
||||||
late String author;
|
late String author;
|
||||||
@ -424,12 +425,31 @@ abstract class AppSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Some Sources may have additional settings at the Source level (not specific to Apps) - these use SettingsProvider
|
// Some Sources may have additional settings at the Source level (not specific to Apps) - these use SettingsProvider
|
||||||
List<GeneratedFormItem> additionalSourceSpecificSettingFormItems = [];
|
// If the source has been overridden, we expect the user to define one-time values as additional settings - don't use the stored values
|
||||||
|
List<GeneratedFormItem> sourceConfigSettingFormItems = [];
|
||||||
|
Future<Map<String, String>> getSourceConfigValues(
|
||||||
|
Map<String, dynamic> additionalSettings,
|
||||||
|
SettingsProvider settingsProvider) async {
|
||||||
|
Map<String, String> results = {};
|
||||||
|
sourceConfigSettingFormItems.forEach((e) {
|
||||||
|
var val = hostChanged
|
||||||
|
? additionalSettings[e.key]
|
||||||
|
: settingsProvider.getSettingString(e.key);
|
||||||
|
if (val != null) {
|
||||||
|
results[e.key] = val;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
String? changeLogPageFromStandardUrl(String standardUrl) {
|
String? changeLogPageFromStandardUrl(String standardUrl) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<String?> getSourceNote() async {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
Future<String> apkUrlPrefetchModifier(
|
Future<String> apkUrlPrefetchModifier(
|
||||||
String apkUrl, String standardUrl) async {
|
String apkUrl, String standardUrl) async {
|
||||||
return apkUrl;
|
return apkUrl;
|
||||||
|
20
pubspec.lock
20
pubspec.lock
@ -695,18 +695,18 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: sqflite
|
name: sqflite
|
||||||
sha256: b4d6710e1200e96845747e37338ea8a819a12b51689a3bcf31eff0003b37a0b9
|
sha256: "591f1602816e9c31377d5f008c2d9ef7b8aca8941c3f89cc5fd9d84da0c38a9a"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.8+4"
|
version: "2.3.0"
|
||||||
sqflite_common:
|
sqflite_common:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: sqflite_common
|
name: sqflite_common
|
||||||
sha256: "8f7603f3f8f126740bc55c4ca2d1027aab4b74a1267a3e31ce51fe40e3b65b8f"
|
sha256: "1b92f368f44b0dee2425bb861cfa17b6f6cf3961f762ff6f941d20b33355660a"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.5+1"
|
version: "2.5.0"
|
||||||
stack_trace:
|
stack_trace:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -863,10 +863,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: webview_flutter_android
|
name: webview_flutter_android
|
||||||
sha256: "8587d0b4991bd0f223f4b4957101c2c7449f905601571315f4967072498dd3fb"
|
sha256: d936a09fbfd08cb78f7329e0bbacf6158fbdfe24ffc908b22444c07d295eb193
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.9.1"
|
version: "3.9.2"
|
||||||
webview_flutter_platform_interface:
|
webview_flutter_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -879,18 +879,18 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: webview_flutter_wkwebview
|
name: webview_flutter_wkwebview
|
||||||
sha256: "3e36a8f564809cb7c257ff4278502b185e2191349df0ddee98837f91805c74b8"
|
sha256: "5fa098f28b606f699e8ca52d9e4e11edbbfef65189f5f77ae92703ba5408fd25"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.7.1"
|
version: "3.7.2"
|
||||||
win32:
|
win32:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: win32
|
name: win32
|
||||||
sha256: dfdf0136e0aa7a1b474ea133e67cb0154a0acd2599c4f3ada3b49d38d38793ee
|
sha256: f2add6fa510d3ae152903412227bda57d0d5a8da61d2c39c1fb022c9429a41c0
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.0.5"
|
version: "5.0.6"
|
||||||
win32_registry:
|
win32_registry:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -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.13.21+185 # When changing this, update the tag in main() accordingly
|
version: 0.13.22+186 # 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