Compare commits

..

17 Commits

Author SHA1 Message Date
Imran
b665b739f6 Merge pull request #2624 from ImranR98/dev
- Use alternative storage dir if user-accessible one is null (#2392)
- Fix error message for RuStore when no APK found (#2615)
- Allow XAPK downloads from GitHub (#2587)
2025-11-08 16:59:37 -05:00
Imran Remtulla
faaab3f038 Allow XAPK downloads from GitHub (#2587) 2025-11-08 16:42:12 -05:00
Imran Remtulla
3853cca7e5 Upgrade Flutter+packages, increment version 2025-11-08 16:30:57 -05:00
Imran Remtulla
006c39f1d0 Fix error message for RuStore when no APK found (#2615) 2025-11-08 16:29:56 -05:00
Imran Remtulla
44950032f7 Use alternative storage dir if user-accessible one is null (#2392) 2025-11-08 16:17:33 -05:00
Imran
0ba2ec04f1 Merge pull request #2584 from summoner001/main
Translation: Update hu.json
2025-11-08 15:58:23 -05:00
Imran
a909e47201 Merge pull request #2607 from CertainBot/main
Update es.json
2025-11-08 15:58:15 -05:00
CertainBot
9fc4a07889 Update es.json
Few fixes.

Corregidos varios errores.
2025-10-23 04:05:52 +02:00
summoner
fdabd96288 Translation: Update hu.json
Fix autotranslated strings
2025-10-12 11:08:48 +02:00
Imran
d21feaaf74 Merge pull request #2574 from neardaniel-pls/main
Refine Portuguese Translation
2025-10-11 19:27:17 -04:00
Imran
c0c0e2a5c5 Merge pull request #2583 from ImranR98/dev
- Add support for zipped APKs - GitHub/HTML only for now (#983)
- Fix bug: Release asset download box crashing for track-only apps (#2567)
- Fix text alignment in app selection menu (#2577)
2025-10-11 19:26:45 -04:00
Imran Remtulla
60e7bba5d9 Flutter upgrade + increment version 2025-10-11 19:25:55 -04:00
Imran Remtulla
6654406c81 Fix text alignment in app selection menu (#2577) 2025-10-11 18:33:30 -04:00
Imran Remtulla
f5cbbfcace Fix bug: Release asset download box crashing for track-only apps (#2567) 2025-10-11 18:30:54 -04:00
Imran Remtulla
8bdc0f8d12 Add support for zipped APKs - GitHub/HTML only for now (#983) 2025-10-11 18:29:59 -04:00
NearDaniel
a980b00600 Merge branch 'ImranR98:main' into main 2025-09-30 19:02:38 +01:00
Near
7a385843f9 chore(i18n): refine Portuguese translation
This commit updates the Portuguese translation (`pt.json`) to improve consistency and correctness.

The primary change involves replacing most instances of "aplicativo" with "aplicação" to better align with European Portuguese terminology. Other minor grammatical and wording adjustments have also been made throughout the file.
2025-09-29 21:32:03 +01:00
38 changed files with 297 additions and 175 deletions

View File

@@ -337,6 +337,8 @@
"fgServiceNotice": "هذا الإشعار مطلوب للتحقق من التحديث في الخلفية (يمكن إخفاؤه في إعدادات نظام التشغيل)", "fgServiceNotice": "هذا الإشعار مطلوب للتحقق من التحديث في الخلفية (يمكن إخفاؤه في إعدادات نظام التشغيل)",
"excludeSecrets": "استبعاد الأسرار", "excludeSecrets": "استبعاد الأسرار",
"GHReqPrefix": "مثيل \"sky22333/hubproxy\" لطلبات GitHub", "GHReqPrefix": "مثيل \"sky22333/hubproxy\" لطلبات GitHub",
"includeZips": "تضمين ملفات ZIP",
"zippedApkFilterRegEx": "تصفية ملفات APK داخل ZIP",
"removeAppQuestion": { "removeAppQuestion": {
"one": "إزالة التطبيق؟", "one": "إزالة التطبيق؟",
"other": "إزالة التطبيقات؟" "other": "إزالة التطبيقات؟"

View File

@@ -337,6 +337,8 @@
"fgServiceNotice": "This notification is required for background update checking (it can be hidden in the OS settings)", "fgServiceNotice": "This notification is required for background update checking (it can be hidden in the OS settings)",
"excludeSecrets": "Exclude secrets", "excludeSecrets": "Exclude secrets",
"GHReqPrefix": "'sky22333/hubproxy' instance for GitHub requests", "GHReqPrefix": "'sky22333/hubproxy' instance for GitHub requests",
"includeZips": "Include ZIP files",
"zippedApkFilterRegEx": "Filter APKs inside ZIP",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Želite li ukloniti aplikaciju?", "one": "Želite li ukloniti aplikaciju?",
"other": "Želite li ukloniti aplikacije?" "other": "Želite li ukloniti aplikacije?"

View File

@@ -337,6 +337,8 @@
"fgServiceNotice": "Aquesta notificació és necessària per comprovar les actualitzacions en segon pla (la pots ocultar als paràmetres del Sistema Operatiu)", "fgServiceNotice": "Aquesta notificació és necessària per comprovar les actualitzacions en segon pla (la pots ocultar als paràmetres del Sistema Operatiu)",
"excludeSecrets": "Exclude secrets", "excludeSecrets": "Exclude secrets",
"GHReqPrefix": "'sky22333/hubproxy' instance for GitHub requests", "GHReqPrefix": "'sky22333/hubproxy' instance for GitHub requests",
"includeZips": "Include ZIP files",
"zippedApkFilterRegEx": "Filter APKs inside ZIP",
"removeAppQuestion": { "removeAppQuestion": {
"one": "¿Suprimeixo l'aplicació?", "one": "¿Suprimeixo l'aplicació?",
"other": "¿Suprimeixo les aplicacions?" "other": "¿Suprimeixo les aplicacions?"

View File

@@ -337,6 +337,8 @@
"fgServiceNotice": "Toto oznámení je nutné pro kontrolu aktualizací na pozadí (lze jej skrýt v nastavení systému)", "fgServiceNotice": "Toto oznámení je nutné pro kontrolu aktualizací na pozadí (lze jej skrýt v nastavení systému)",
"excludeSecrets": "Vyloučit tajemství", "excludeSecrets": "Vyloučit tajemství",
"GHReqPrefix": "instance 'sky22333/hubproxy' pro požadavky GitHubu", "GHReqPrefix": "instance 'sky22333/hubproxy' pro požadavky GitHubu",
"includeZips": "Zahrnout soubory ZIP",
"zippedApkFilterRegEx": "Filtrování souborů APK uvnitř ZIP",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Odstranit aplikaci?", "one": "Odstranit aplikaci?",
"other": "Odstranit aplikace?" "other": "Odstranit aplikace?"

View File

@@ -337,6 +337,8 @@
"fgServiceNotice": "Denne meddelelse er nødvendig for baggrundsopdateringskontrol (den kan skjules i OS-indstillingerne).", "fgServiceNotice": "Denne meddelelse er nødvendig for baggrundsopdateringskontrol (den kan skjules i OS-indstillingerne).",
"excludeSecrets": "Udeluk hemmeligheder", "excludeSecrets": "Udeluk hemmeligheder",
"GHReqPrefix": "'sky22333/hubproxy'-instans til GitHub-anmodninger", "GHReqPrefix": "'sky22333/hubproxy'-instans til GitHub-anmodninger",
"includeZips": "Inkluder ZIP-filer",
"zippedApkFilterRegEx": "Filtrer APK'er inde i ZIP",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Fjern app?", "one": "Fjern app?",
"other": "Fjern apps?" "other": "Fjern apps?"

View File

@@ -337,6 +337,8 @@
"fgServiceNotice": "Diese Benachrichtigung ist für die Prüfung von Updates im Hintergrund erforderlich (sie kann in den Betriebssystemeinstellungen ausgeblendet werden)", "fgServiceNotice": "Diese Benachrichtigung ist für die Prüfung von Updates im Hintergrund erforderlich (sie kann in den Betriebssystemeinstellungen ausgeblendet werden)",
"excludeSecrets": "Geheimnisse ausschließen", "excludeSecrets": "Geheimnisse ausschließen",
"GHReqPrefix": "sky22333/hubproxy'-Instanz für GitHub-Anfragen", "GHReqPrefix": "sky22333/hubproxy'-Instanz für GitHub-Anfragen",
"includeZips": "ZIP-Dateien einbeziehen",
"zippedApkFilterRegEx": "APKs in ZIP filtern",
"removeAppQuestion": { "removeAppQuestion": {
"one": "App entfernen?", "one": "App entfernen?",
"other": "Apps entfernen?" "other": "Apps entfernen?"

View File

@@ -337,6 +337,8 @@
"fgServiceNotice": "This notification is required for background update checking (it can be hidden in the OS settings)", "fgServiceNotice": "This notification is required for background update checking (it can be hidden in the OS settings)",
"excludeSecrets": "Exclude secrets", "excludeSecrets": "Exclude secrets",
"GHReqPrefix": "'sky22333/hubproxy' instance for GitHub requests", "GHReqPrefix": "'sky22333/hubproxy' instance for GitHub requests",
"includeZips": "Include ZIP files",
"zippedApkFilterRegEx": "Filter APKs inside ZIP",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Forigi la aplikaĵon?", "one": "Forigi la aplikaĵon?",
"other": "Forigi la aplikaĵojn?" "other": "Forigi la aplikaĵojn?"

View File

@@ -337,6 +337,8 @@
"fgServiceNotice": "This notification is required for background update checking (it can be hidden in the OS settings)", "fgServiceNotice": "This notification is required for background update checking (it can be hidden in the OS settings)",
"excludeSecrets": "Exclude secrets", "excludeSecrets": "Exclude secrets",
"GHReqPrefix": "'sky22333/hubproxy' instance for GitHub requests", "GHReqPrefix": "'sky22333/hubproxy' instance for GitHub requests",
"includeZips": "Include ZIP files",
"zippedApkFilterRegEx": "Filter APKs inside ZIP",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Remove app?", "one": "Remove app?",
"other": "Remove apps?" "other": "Remove apps?"

View File

@@ -1,8 +1,8 @@
{ {
"invalidURLForSource": "El URL de la aplicación {} no es válido", "invalidURLForSource": "La URL de la aplicación {} no es válida",
"noReleaseFound": "No se ha encontrado una versión válida", "noReleaseFound": "No se ha encontrado una versión válida",
"noVersionFound": "No se ha podido determinar la versión", "noVersionFound": "No se ha podido determinar la versión",
"urlMatchesNoSource": "El URL no coincide con ninguna fuente conocida", "urlMatchesNoSource": "La URL no coincide con ninguna fuente conocida",
"cantInstallOlderVersion": "No se puede instalar una versión previa de la aplicación", "cantInstallOlderVersion": "No se puede instalar una versión previa de la aplicación",
"appIdMismatch": "El ID del paquete descargado no coincide con el ID de la aplicación instalada", "appIdMismatch": "El ID del paquete descargado no coincide con el ID de la aplicación instalada",
"functionNotImplemented": "Esta clase no ha implementado esta función", "functionNotImplemented": "Esta clase no ha implementado esta función",
@@ -29,7 +29,7 @@
"uname": "Nombre de usuario", "uname": "Nombre de usuario",
"wrongArgNum": "Número de argumentos provistos inválido", "wrongArgNum": "Número de argumentos provistos inválido",
"xIsTrackOnly": "{} es de 'sólo seguimiento'", "xIsTrackOnly": "{} es de 'sólo seguimiento'",
"source": "origen", "source": "fuente",
"app": "Aplicación", "app": "Aplicación",
"appsFromSourceAreTrackOnly": "Las aplicaciones de este origen son solo para seguimiento.", "appsFromSourceAreTrackOnly": "Las aplicaciones de este origen son solo para seguimiento.",
"youPickedTrackOnly": "Debe seleccionar la opción de 'solo para seguimiento'.", "youPickedTrackOnly": "Debe seleccionar la opción de 'solo para seguimiento'.",
@@ -41,7 +41,7 @@
"appSourceURL": "URL origen de la aplicación", "appSourceURL": "URL origen de la aplicación",
"error": "Error", "error": "Error",
"add": "Añadir", "add": "Añadir",
"searchSomeSourcesLabel": "Buscar (solo algunas fuentes)", "searchSomeSourcesLabel": "Buscar (solo en algunas fuentes)",
"search": "Buscar", "search": "Buscar",
"additionalOptsFor": "Opciones adicionales para {}", "additionalOptsFor": "Opciones adicionales para {}",
"supportedSources": "Fuentes admitidas", "supportedSources": "Fuentes admitidas",
@@ -105,7 +105,7 @@
"importedAppsIdDisclaimer": "Las aplicaciones importadas podrían mostrarse incorrectamente como «No instalada».\nPara solucionarlo, reinstálelas a través de Obtainium.\nEsto no debería afectar a los datos de las aplicaciones.\n\nSolo afecta a los URL y a los métodos de importación mediante terceros.", "importedAppsIdDisclaimer": "Las aplicaciones importadas podrían mostrarse incorrectamente como «No instalada».\nPara solucionarlo, reinstálelas a través de Obtainium.\nEsto no debería afectar a los datos de las aplicaciones.\n\nSolo afecta a los URL y a los métodos de importación mediante terceros.",
"importErrors": "Errores de Importación", "importErrors": "Errores de Importación",
"importedXOfYApps": "{} de {} aplicaciones importadas.", "importedXOfYApps": "{} de {} aplicaciones importadas.",
"followingURLsHadErrors": "Los URL siguientes han tenido problemas:", "followingURLsHadErrors": "Las URL siguientes han tenido problemas:",
"selectURL": "Seleccionar URL", "selectURL": "Seleccionar URL",
"selectURLs": "Seleccionar URLs", "selectURLs": "Seleccionar URLs",
"pick": "Escoger", "pick": "Escoger",
@@ -291,7 +291,7 @@
"checkingForUpdatesNotifChannel": "Buscando actualizaciones", "checkingForUpdatesNotifChannel": "Buscando actualizaciones",
"onlyCheckInstalledOrTrackOnlyApps": "Comprobar actualizaciones solo para apps instaladas o en seguimiento", "onlyCheckInstalledOrTrackOnlyApps": "Comprobar actualizaciones solo para apps instaladas o en seguimiento",
"supportFixedAPKURL": "Soporte para URLs fijas de APK", "supportFixedAPKURL": "Soporte para URLs fijas de APK",
"selectX": "Elija {}", "selectX": "Seleccionar {}",
"parallelDownloads": "Permitir descargas paralelas", "parallelDownloads": "Permitir descargas paralelas",
"useShizuku": "Usar Shizuku o Sui para instalar", "useShizuku": "Usar Shizuku o Sui para instalar",
"shizukuBinderNotFound": "Shizuku no funciona", "shizukuBinderNotFound": "Shizuku no funciona",
@@ -337,6 +337,8 @@
"fgServiceNotice": "Esta notificación es necesaria para la comprobación de actualizaciones en segundo plano (puede ocultarse en la configuración del sistema operativo).", "fgServiceNotice": "Esta notificación es necesaria para la comprobación de actualizaciones en segundo plano (puede ocultarse en la configuración del sistema operativo).",
"excludeSecrets": "Excluir secretos", "excludeSecrets": "Excluir secretos",
"GHReqPrefix": "Instancia \"sky22333/hubproxy\" para las solicitudes de GitHub", "GHReqPrefix": "Instancia \"sky22333/hubproxy\" para las solicitudes de GitHub",
"includeZips": "Incluir archivos ZIP",
"zippedApkFilterRegEx": "Filtrar APKs dentro de ZIP",
"removeAppQuestion": { "removeAppQuestion": {
"one": "¿Eliminar aplicación?", "one": "¿Eliminar aplicación?",
"other": "¿Eliminar aplicaciones?" "other": "¿Eliminar aplicaciones?"

View File

@@ -337,6 +337,8 @@
"fgServiceNotice": "This notification is required for background update checking (it can be hidden in the OS settings)", "fgServiceNotice": "This notification is required for background update checking (it can be hidden in the OS settings)",
"excludeSecrets": "Exclude secrets", "excludeSecrets": "Exclude secrets",
"GHReqPrefix": "'sky22333/hubproxy' instance for GitHub requests", "GHReqPrefix": "'sky22333/hubproxy' instance for GitHub requests",
"includeZips": "Include ZIP files",
"zippedApkFilterRegEx": "Filter APKs inside ZIP",
"removeAppQuestion": { "removeAppQuestion": {
"one": "برنامه حذف شود؟", "one": "برنامه حذف شود؟",
"other": "برنامه ها حذف شوند؟" "other": "برنامه ها حذف شوند؟"

View File

@@ -337,6 +337,8 @@
"fgServiceNotice": "Cette notification est nécessaire pour la vérification des mises à jour en arrière-plan (elle peut être masquée dans les paramètres du système d'exploitation).", "fgServiceNotice": "Cette notification est nécessaire pour la vérification des mises à jour en arrière-plan (elle peut être masquée dans les paramètres du système d'exploitation).",
"excludeSecrets": "Exclure les secrets", "excludeSecrets": "Exclure les secrets",
"GHReqPrefix": "instance 'sky22333/hubproxy' pour les requêtes GitHub", "GHReqPrefix": "instance 'sky22333/hubproxy' pour les requêtes GitHub",
"includeZips": "Inclure les fichiers ZIP",
"zippedApkFilterRegEx": "Filtrer les APK à l'intérieur du ZIP",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Supprimer l'application ?", "one": "Supprimer l'application ?",
"other": "Supprimer les applications ?" "other": "Supprimer les applications ?"

View File

@@ -337,6 +337,8 @@
"fgServiceNotice": "Ez az értesítés a háttérben történő frissítésellenőrzéshez szükséges (a rendszer beállításaiban elrejthető).", "fgServiceNotice": "Ez az értesítés a háttérben történő frissítésellenőrzéshez szükséges (a rendszer beállításaiban elrejthető).",
"excludeSecrets": "Érzékeny adatok (például: személyes hozzáférési tokenek) kihagyása", "excludeSecrets": "Érzékeny adatok (például: személyes hozzáférési tokenek) kihagyása",
"GHReqPrefix": "„sky22333/hubproxy” példány a GitHub lekérdezéséhez", "GHReqPrefix": "„sky22333/hubproxy” példány a GitHub lekérdezéséhez",
"includeZips": "ZIP-fájlok belefoglalása",
"zippedApkFilterRegEx": "APK-fájlok szűrése a ZIP-fájlon belül",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Eltávolítja az alkalmazást?", "one": "Eltávolítja az alkalmazást?",
"other": "Eltávolítja az alkalmazásokat?" "other": "Eltávolítja az alkalmazásokat?"

View File

@@ -337,6 +337,8 @@
"fgServiceNotice": "Pemberitahuan ini diperlukan untuk pemeriksaan pembaruan latar belakang (dapat disembunyikan dalam pengaturan OS)", "fgServiceNotice": "Pemberitahuan ini diperlukan untuk pemeriksaan pembaruan latar belakang (dapat disembunyikan dalam pengaturan OS)",
"excludeSecrets": "Mengecualikan rahasia", "excludeSecrets": "Mengecualikan rahasia",
"GHReqPrefix": "Instance 'sky22333/hubproxy' untuk permintaan GitHub", "GHReqPrefix": "Instance 'sky22333/hubproxy' untuk permintaan GitHub",
"includeZips": "Menyertakan file ZIP",
"zippedApkFilterRegEx": "Saring APK di dalam ZIP",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Hapus aplikasi?", "one": "Hapus aplikasi?",
"other": "Hapus aplikasi?" "other": "Hapus aplikasi?"

View File

@@ -337,6 +337,8 @@
"fgServiceNotice": "Questa notifica è necessaria per il controllo degli aggiornamenti in background (può essere nascosta nelle impostazioni del sistema operativo).", "fgServiceNotice": "Questa notifica è necessaria per il controllo degli aggiornamenti in background (può essere nascosta nelle impostazioni del sistema operativo).",
"excludeSecrets": "Escludere i segreti", "excludeSecrets": "Escludere i segreti",
"GHReqPrefix": "istanza 'sky22333/hubproxy' per le richieste a GitHub", "GHReqPrefix": "istanza 'sky22333/hubproxy' per le richieste a GitHub",
"includeZips": "Includere file ZIP",
"zippedApkFilterRegEx": "Filtrare gli APK all'interno dello ZIP",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Rimuovere l'app?", "one": "Rimuovere l'app?",
"other": "Rimuovere le app?" "other": "Rimuovere le app?"

View File

@@ -337,6 +337,8 @@
"fgServiceNotice": "この通知は、バックグラウンドでアップデートを確認するために必要ですOSの設定で非表示にできます。", "fgServiceNotice": "この通知は、バックグラウンドでアップデートを確認するために必要ですOSの設定で非表示にできます。",
"excludeSecrets": "シークレットを除く", "excludeSecrets": "シークレットを除く",
"GHReqPrefix": "GitHub リクエスト用の 'sky22333/hubproxy' インスタンス", "GHReqPrefix": "GitHub リクエスト用の 'sky22333/hubproxy' インスタンス",
"includeZips": "ZIPファイルを含む",
"zippedApkFilterRegEx": "ZIP内のAPKをフィルタリングする",
"removeAppQuestion": { "removeAppQuestion": {
"one": "アプリを削除しますか?", "one": "アプリを削除しますか?",
"other": "アプリを削除しますか?" "other": "アプリを削除しますか?"

View File

@@ -337,6 +337,8 @@
"fgServiceNotice": "이 알림은 백그라운드 업데이트 확인에 필요합니다(OS 설정에서 숨길 수 있음).", "fgServiceNotice": "이 알림은 백그라운드 업데이트 확인에 필요합니다(OS 설정에서 숨길 수 있음).",
"excludeSecrets": "비밀 제외", "excludeSecrets": "비밀 제외",
"GHReqPrefix": "GitHub 요청을 위한 'sky22333/hubproxy' 인스턴스", "GHReqPrefix": "GitHub 요청을 위한 'sky22333/hubproxy' 인스턴스",
"includeZips": "ZIP 파일 포함",
"zippedApkFilterRegEx": "ZIP 내 APK 필터링",
"removeAppQuestion": { "removeAppQuestion": {
"one": "앱을 제거하시겠습니까?", "one": "앱을 제거하시겠습니까?",
"other": "앱을 제거하시겠습니까?" "other": "앱을 제거하시겠습니까?"

View File

@@ -337,6 +337,8 @@
"fgServiceNotice": "This notification is required for background update checking (it can be hidden in the OS settings)", "fgServiceNotice": "This notification is required for background update checking (it can be hidden in the OS settings)",
"excludeSecrets": "Exclude secrets", "excludeSecrets": "Exclude secrets",
"GHReqPrefix": "'sky22333/hubproxy' instance for GitHub requests", "GHReqPrefix": "'sky22333/hubproxy' instance for GitHub requests",
"includeZips": "Include ZIP files",
"zippedApkFilterRegEx": "Filter APKs inside ZIP",
"removeAppQuestion": { "removeAppQuestion": {
"one": "ആപ്പ് നീക്കം ചെയ്യണോ?", "one": "ആപ്പ് നീക്കം ചെയ്യണോ?",
"other": "ആപ്പുകൾ നീക്കം ചെയ്യണോ?" "other": "ആപ്പുകൾ നീക്കം ചെയ്യണോ?"

View File

@@ -337,6 +337,8 @@
"fgServiceNotice": "Deze melding is nodig voor het controleren van updates op de achtergrond (kan worden verborgen in de OS-instellingen)", "fgServiceNotice": "Deze melding is nodig voor het controleren van updates op de achtergrond (kan worden verborgen in de OS-instellingen)",
"excludeSecrets": "Geheimen uitsluiten", "excludeSecrets": "Geheimen uitsluiten",
"GHReqPrefix": "'sky22333/hubproxy' instantie voor GitHub verzoeken", "GHReqPrefix": "'sky22333/hubproxy' instantie voor GitHub verzoeken",
"includeZips": "ZIP-bestanden opnemen",
"zippedApkFilterRegEx": "APK's filteren in ZIP",
"removeAppQuestion": { "removeAppQuestion": {
"one": "App verwijderen?", "one": "App verwijderen?",
"other": "Apps verwijderen?" "other": "Apps verwijderen?"

View File

@@ -337,6 +337,8 @@
"fgServiceNotice": "To powiadomienie jest wymagane do sprawdzania aktualizacji w tle (można je ukryć w ustawieniach systemu operacyjnego).", "fgServiceNotice": "To powiadomienie jest wymagane do sprawdzania aktualizacji w tle (można je ukryć w ustawieniach systemu operacyjnego).",
"excludeSecrets": "Wyklucz sekrety", "excludeSecrets": "Wyklucz sekrety",
"GHReqPrefix": "Instancja \"sky22333/hubproxy\" dla żądań GitHub", "GHReqPrefix": "Instancja \"sky22333/hubproxy\" dla żądań GitHub",
"includeZips": "Dołączanie plików ZIP",
"zippedApkFilterRegEx": "Filtrowanie plików APK wewnątrz ZIP",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Usunąć aplikację?", "one": "Usunąć aplikację?",
"few": "Usunąć aplikacje?", "few": "Usunąć aplikacje?",

View File

@@ -337,6 +337,8 @@
"fgServiceNotice": "Essa notificação é necessária para a verificação de atualizações em segundo plano (ela pode ser ocultada nas configurações do sistema operacional)", "fgServiceNotice": "Essa notificação é necessária para a verificação de atualizações em segundo plano (ela pode ser ocultada nas configurações do sistema operacional)",
"excludeSecrets": "Excluir segredos", "excludeSecrets": "Excluir segredos",
"GHReqPrefix": "Instância \"sky22333/hubproxy\" para solicitações do GitHub", "GHReqPrefix": "Instância \"sky22333/hubproxy\" para solicitações do GitHub",
"includeZips": "Incluir arquivos ZIP",
"zippedApkFilterRegEx": "Filtrar APKs dentro do ZIP",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Remover app?", "one": "Remover app?",
"other": "Remover apps?" "other": "Remover apps?"

View File

@@ -3,8 +3,8 @@
"noReleaseFound": "Não foi possível encontrar uma versão adequada", "noReleaseFound": "Não foi possível encontrar uma versão adequada",
"noVersionFound": "Não foi possível encontrar uma versão", "noVersionFound": "Não foi possível encontrar uma versão",
"urlMatchesNoSource": "A URL não corresponde a uma fonte conhecida", "urlMatchesNoSource": "A URL não corresponde a uma fonte conhecida",
"cantInstallOlderVersion": "Não é permitido instalar uma versão anterior de um aplicativo", "cantInstallOlderVersion": "Não é permitido instalar uma versão anterior de uma aplicação",
"appIdMismatch": "ID do pacote baixado não é igual ao ID do aplicativo instalado", "appIdMismatch": "O ID do pacote descarregado não é igual ao ID da aplicação instalada",
"functionNotImplemented": "Esta classe não implementou essa função", "functionNotImplemented": "Esta classe não implementou essa função",
"placeholder": "Espaço reservado", "placeholder": "Espaço reservado",
"someErrors": "Alguns erros ocorreram", "someErrors": "Alguns erros ocorreram",
@@ -30,15 +30,15 @@
"wrongArgNum": "Número de argumentos errado", "wrongArgNum": "Número de argumentos errado",
"xIsTrackOnly": "{} é 'Apenas monitorar'", "xIsTrackOnly": "{} é 'Apenas monitorar'",
"source": "Fonte", "source": "Fonte",
"app": "Aplicativo", "app": "Aplicação",
"appsFromSourceAreTrackOnly": "Os aplicativos desta fonte são 'Apenas monitorar'.", "appsFromSourceAreTrackOnly": "As aplicações desta fonte são 'Apenas monitorar'.",
"youPickedTrackOnly": "Você selecionou a opção 'Apenas monitorar'.", "youPickedTrackOnly": "Você selecionou a opção 'Apenas monitorar'.",
"trackOnlyAppDescription": "As atualizações desse aplicativo serão monitoradas, mas o Obtainium não poderá baixá-lo ou instalá-lo.", "trackOnlyAppDescription": "As atualizações desta aplicação serão monitorizadas, mas o Obtainium não poderá descarregá-la ou instalá-la.",
"cancelled": "Cancelado", "cancelled": "Cancelado",
"appAlreadyAdded": "Aplicativo já adicionado", "appAlreadyAdded": "Aplicação já adicionada",
"alreadyUpToDateQuestion": "Aplicativo já foi atualizado?", "alreadyUpToDateQuestion": "Aplicação já foi atualizada?",
"addApp": "Adicionar aplicativo", "addApp": "Adicionar aplicação",
"appSourceURL": "URL de origem do aplicativo", "appSourceURL": "URL de origem da aplicação",
"error": "Erro", "error": "Erro",
"add": "Adicionar", "add": "Adicionar",
"searchSomeSourcesLabel": "Procurar (apenas algumas fontes)", "searchSomeSourcesLabel": "Procurar (apenas algumas fontes)",
@@ -47,9 +47,9 @@
"supportedSources": "Fontes compatíveis", "supportedSources": "Fontes compatíveis",
"trackOnlyInBrackets": "(apenas monitorar)", "trackOnlyInBrackets": "(apenas monitorar)",
"searchableInBrackets": "(pesquisável)", "searchableInBrackets": "(pesquisável)",
"appsString": "Aplicativos", "appsString": "Aplicações",
"noApps": "Não há aplicativos", "noApps": "Não há aplicações",
"noAppsForFilter": "Sem aplicativos para filtrar", "noAppsForFilter": "Sem aplicações para filtrar",
"byX": "Por {}", "byX": "Por {}",
"percentProgress": "Progresso: {}%", "percentProgress": "Progresso: {}%",
"pleaseWait": "Por favor, espere", "pleaseWait": "Por favor, espere",
@@ -59,35 +59,35 @@
"selectAll": "Selecionar todos", "selectAll": "Selecionar todos",
"deselectX": "Deselecionar {}", "deselectX": "Deselecionar {}",
"xWillBeRemovedButRemainInstalled": "{} será removido do Obtainium mais permanecerá instalado no dispositivo.", "xWillBeRemovedButRemainInstalled": "{} será removido do Obtainium mais permanecerá instalado no dispositivo.",
"removeSelectedAppsQuestion": "Remover aplicativos selecionados?", "removeSelectedAppsQuestion": "Remover aplicações selecionadas?",
"removeSelectedApps": "Remover aplicativos selecionados", "removeSelectedApps": "Remover aplicações selecionadas",
"updateX": "Atualizar {}", "updateX": "Atualizar {}",
"installX": "Instalar {}", "installX": "Instalar {}",
"markXTrackOnlyAsUpdated": "Marcar {}\n(Apenas monitorar)\ncomo Atualizado", "markXTrackOnlyAsUpdated": "Marcar {}\n(Apenas monitorar)\ncomo Atualizado",
"changeX": "Mudar {}", "changeX": "Mudar {}",
"installUpdateApps": "Instalar/Atualizar aplicativos", "installUpdateApps": "Instalar/Atualizar aplicações",
"installUpdateSelectedApps": "Instalar/Atualizar aplicativos selecionados", "installUpdateSelectedApps": "Instalar/Atualizar aplicações selecionadas",
"markXSelectedAppsAsUpdated": "Marcar {} aplicativos selecionados como atualizados?", "markXSelectedAppsAsUpdated": "Marcar {} aplicações selecionadas como atualizadas?",
"no": "Não", "no": "Não",
"yes": "Sim", "yes": "Sim",
"markSelectedAppsUpdated": "Marcar aplicativos selecionados como Atualizados", "markSelectedAppsUpdated": "Marcar aplicações selecionadas como Atualizadas",
"pinToTop": "Fixar no topo", "pinToTop": "Fixar no topo",
"unpinFromTop": "Desafixar do topo", "unpinFromTop": "Desafixar do topo",
"resetInstallStatusForSelectedAppsQuestion": "Reiniciar status de instalação nos aplicativos selecionados?", "resetInstallStatusForSelectedAppsQuestion": "Reiniciar o estado de instalação das aplicações selecionadas?",
"installStatusOfXWillBeResetExplanation": "O status de instalação de todos os aplicativos selecionados será reiniciado.\n\nIsso pode ajudar quando uma versão de um aplicativo mostrada no Obtainium é incorreta devido a falhas ao atualizar ou outros problemas.", "installStatusOfXWillBeResetExplanation": "O estado de instalação de todas as aplicações selecionadas será reiniciado.\n\nIsto pode ajudar quando uma versão de uma aplicação mostrada no Obtainium está incorreta devido a falhas na atualização ou outros problemas.",
"customLinkMessage": "Esses links funcionam em dispositivos com o Obtainium instalado", "customLinkMessage": "Esses links funcionam em dispositivos com o Obtainium instalado",
"shareAppConfigLinks": "Compartilhar configuração do aplicativo como link HTML", "shareAppConfigLinks": "Partilhar a configuração da aplicação como um link HTML",
"shareSelectedAppURLs": "Compartilhar URLs de aplicativos selecionados", "shareSelectedAppURLs": "Partilhar URLs de aplicações selecionadas",
"resetInstallStatus": "Reiniciar status de instalação", "resetInstallStatus": "Reiniciar status de instalação",
"more": "Mais", "more": "Mais",
"removeOutdatedFilter": "Remover filtro de aplicativos desatualizados", "removeOutdatedFilter": "Remover filtro de aplicações desatualizadas",
"showOutdatedOnly": "Mostrar apenas aplicativos desatualizados", "showOutdatedOnly": "Mostrar apenas aplicações desatualizadas",
"filter": "Filtro", "filter": "Filtro",
"filterApps": "Filtrar aplicativos", "filterApps": "Filtrar aplicações",
"appName": "Nome do aplicativo", "appName": "Nome da aplicação",
"author": "Autor", "author": "Autor",
"upToDateApps": "Aplicativos atualizados", "upToDateApps": "Aplicações atualizadas",
"nonInstalledApps": "Aplicativos não instalados", "nonInstalledApps": "Aplicações não instaladas",
"importExport": "Importar/Exportar", "importExport": "Importar/Exportar",
"settings": "Configurações", "settings": "Configurações",
"exportedTo": "Exportado para {}", "exportedTo": "Exportado para {}",
@@ -97,14 +97,14 @@
"obtainiumImport": "Importar dados do Obtainium", "obtainiumImport": "Importar dados do Obtainium",
"importFromURLList": "Importar de lista de URLs", "importFromURLList": "Importar de lista de URLs",
"searchQuery": "Pesquisa", "searchQuery": "Pesquisa",
"appURLList": "Lista de URLs de aplicativos", "appURLList": "Lista de URLs de aplicações",
"line": "Linha", "line": "Linha",
"searchX": "Pesquisar na/o {}", "searchX": "Pesquisar na/o {}",
"noResults": "Nenhum resultado encontrado", "noResults": "Nenhum resultado encontrado",
"importX": "Importar {}", "importX": "Importar {}",
"importedAppsIdDisclaimer": "Aplicativos Importados podem ser mostrados incorretamente como \"Não Instalado\".\nPara consertar, reinstale-os usando o Obtainium.\nIsso não deve afetar dados do aplicativo.\n\nAfeta apenas métodos de importação de URL e de terceiros.", "importedAppsIdDisclaimer": "Aplicações Importadas podem ser mostradas incorretamente como \"Não Instalado\".\nPara corrigir, reinstale-as usando o Obtainium.\nIsto não deve afetar os dados da aplicação.\n\nAfeta apenas os métodos de importação de URL e de terceiros.",
"importErrors": "Erros de importação", "importErrors": "Erros de importação",
"importedXOfYApps": "{} de {} aplicativos importados.", "importedXOfYApps": "{} de {} aplicações importadas.",
"followingURLsHadErrors": "As seguintes URLs apresentaram erros:", "followingURLsHadErrors": "As seguintes URLs apresentaram erros:",
"selectURL": "Selecionar URL", "selectURL": "Selecionar URL",
"selectURLs": "Selecionar URLs", "selectURLs": "Selecionar URLs",
@@ -115,53 +115,53 @@
"followSystem": "Padrão do sistema", "followSystem": "Padrão do sistema",
"followSystemThemeExplanation": "O tema do sistema seguinte só é possível através da utilização de aplicações de terceiros", "followSystemThemeExplanation": "O tema do sistema seguinte só é possível através da utilização de aplicações de terceiros",
"useBlackTheme": "Usar tema preto AMOLED", "useBlackTheme": "Usar tema preto AMOLED",
"appSortBy": "Classificar aplicativo por", "appSortBy": "Classificar aplicação por",
"authorName": "Autor/Nome", "authorName": "Autor/Nome",
"nameAuthor": "Nome/Autor", "nameAuthor": "Nome/Autor",
"asAdded": "Como adicionado", "asAdded": "Como adicionado",
"appSortOrder": "Ordem de classificação de aplicativos", "appSortOrder": "Ordem de classificação das aplicações",
"ascending": "Ascendente", "ascending": "Ascendente",
"descending": "Descendente", "descending": "Descendente",
"bgUpdateCheckInterval": "Intervalo de verificação de atualizações em segundo-plano", "bgUpdateCheckInterval": "Intervalo de verificação de atualizações em segundo-plano",
"neverManualOnly": "Nunca - apenas manual", "neverManualOnly": "Nunca - apenas manual",
"appearance": "Aparência", "appearance": "Aparência",
"showWebInAppView": "Mostrar página web do aplicativo em informações do aplicativo", "showWebInAppView": "Mostrar a página web da aplicação nas informações da aplicação",
"pinUpdates": "Fixar atualizações no topo da janela de aplicativos", "pinUpdates": "Fixar atualizações no topo da janela das aplicações",
"updates": "Atualizações", "updates": "Atualizações",
"sourceSpecific": "Token de acesso", "sourceSpecific": "Token de acesso",
"appSource": "Fonte do aplicativo", "appSource": "Fonte da aplicação",
"noLogs": "Sem logs", "noLogs": "Sem logs",
"appLogs": "Logs do aplicativo", "appLogs": "Logs da aplicação",
"close": "Fechar", "close": "Fechar",
"share": "Compartilhar", "share": "Compartilhar",
"appNotFound": "Aplicativo não encontrado", "appNotFound": "Aplicação não encontrada",
"obtainiumExportHyphenatedLowercase": "exportação de obtainium", "obtainiumExportHyphenatedLowercase": "exportação de obtainium",
"pickAnAPK": "Selecionar um APK", "pickAnAPK": "Selecionar um APK",
"appHasMoreThanOnePackage": "{} tem mais de um pacote:", "appHasMoreThanOnePackage": "{} tem mais de um pacote:",
"deviceSupportsXArch": "Seu dispositivo suporta a arquitetura de CPU {}.", "deviceSupportsXArch": "Seu dispositivo suporta a arquitetura de CPU {}.",
"deviceSupportsFollowingArchs": "Seu dispositivo suporta as seguintes arquiteturas de CPU:", "deviceSupportsFollowingArchs": "Seu dispositivo suporta as seguintes arquiteturas de CPU:",
"warning": "Aviso", "warning": "Aviso",
"sourceIsXButPackageFromYPrompt": "A fonte do aplicativo é '{}' mas a origem do pacote é '{}'. Continuar?", "sourceIsXButPackageFromYPrompt": "A fonte da aplicação é '{}' mas a origem do pacote é '{}'. Continuar?",
"updatesAvailable": "Atualizações disponíveis", "updatesAvailable": "Atualizações disponíveis",
"updatesAvailableNotifDescription": "Notifica o usuário quando atualizações de um ou mais aplicativos monitorados pelo Obtainium estão disponíveis", "updatesAvailableNotifDescription": "Notifica o utilizador quando as atualizações de uma ou mais aplicações monitorizadas pelo Obtainium estão disponíveis",
"noNewUpdates": "Sem novas atualizações.", "noNewUpdates": "Sem novas atualizações.",
"xHasAnUpdate": "{} tem uma atualização.", "xHasAnUpdate": "{} tem uma atualização.",
"appsUpdated": "Aplicativos atualizados", "appsUpdated": "Aplicações atualizadas",
"appsNotUpdated": "Falha na atualização das aplicações", "appsNotUpdated": "Falha na atualização das aplicações",
"appsUpdatedNotifDescription": "Notifica o usuário quando atualizações foram aplicadas em segundo-plano para um ou mais aplicativos ", "appsUpdatedNotifDescription": "Notifica o utilizador quando as atualizações foram aplicadas em segundo plano para uma ou mais aplicações ",
"xWasUpdatedToY": "{} foi atualizado para {}.", "xWasUpdatedToY": "{} foi atualizado para {}.",
"xWasNotUpdatedToY": "Falha ao atualizar {} para {}.", "xWasNotUpdatedToY": "Falha ao atualizar {} para {}.",
"errorCheckingUpdates": "Erro ao procurar por atualizações", "errorCheckingUpdates": "Erro ao procurar por atualizações",
"errorCheckingUpdatesNotifDescription": "Uma notificação que mostra quando a checagem por atualizações em segundo-plano falha", "errorCheckingUpdatesNotifDescription": "Uma notificação que mostra quando a checagem por atualizações em segundo-plano falha",
"appsRemoved": "Aplicativos removidos", "appsRemoved": "Aplicações removidas",
"appsRemovedNotifDescription": "Notifica o usuário quando um ou mais aplicativos foram removidos devido a erros de carregamento", "appsRemovedNotifDescription": "Notifica o utilizador quando uma ou mais aplicações foram removidas devido a erros de carregamento",
"xWasRemovedDueToErrorY": "{} foi removido devido a este erro: {}", "xWasRemovedDueToErrorY": "{} foi removido devido a este erro: {}",
"completeAppInstallation": "Instalação do aplicativo concluída", "completeAppInstallation": "Instalação da aplicação concluída",
"obtainiumMustBeOpenToInstallApps": "Obtainium deve estar aberto para instalar os aplicativos", "obtainiumMustBeOpenToInstallApps": "O Obtainium deve estar aberto para instalar as aplicações",
"completeAppInstallationNotifDescription": "Pede ao usuário que retorne ao Obtainium para finalizar a instalação de um aplicativo", "completeAppInstallationNotifDescription": "Pede ao usuário que retorne ao Obtainium para finalizar a instalação de uma aplicação",
"checkingForUpdates": "Verificando atualizações", "checkingForUpdates": "Verificando atualizações",
"checkingForUpdatesNotifDescription": "Notificação transiente que aparece quando o Obtainium está verificando se há atualizações", "checkingForUpdatesNotifDescription": "Notificação transiente que aparece quando o Obtainium está verificando se há atualizações",
"pleaseAllowInstallPerm": "Por favor, permita que o Obtainium possa instalar aplicativos", "pleaseAllowInstallPerm": "Por favor, permita que o Obtainium instale aplicações",
"trackOnly": "Apenas monitorar", "trackOnly": "Apenas monitorar",
"errorWithHttpStatusCode": "Erro {}", "errorWithHttpStatusCode": "Erro {}",
"versionCorrectionDisabled": "Correção de versão desativada (plugin parece não funcionar)", "versionCorrectionDisabled": "Correção de versão desativada (plugin parece não funcionar)",
@@ -175,10 +175,10 @@
"remove": "Remover", "remove": "Remover",
"yesMarkUpdated": "Sim, marcar como atualizado", "yesMarkUpdated": "Sim, marcar como atualizado",
"fdroid": "Oficial F-Droid", "fdroid": "Oficial F-Droid",
"appIdOrName": "ID do aplicativo ou nome", "appIdOrName": "ID da aplicação ou nome",
"appId": "ID do aplicativo", "appId": "ID da aplicação",
"appWithIdOrNameNotFound": "Nenhum aplicativo foi encontrado com esse ID ou nome", "appWithIdOrNameNotFound": "Nenhuma aplicação foi encontrada com esse ID ou nome",
"reposHaveMultipleApps": "Repositórios podem conter múltiplos aplicativos", "reposHaveMultipleApps": "Os repositórios podem conter múltiplas aplicações",
"fdroidThirdPartyRepo": "Repositórios de terceiros F-Droid", "fdroidThirdPartyRepo": "Repositórios de terceiros F-Droid",
"install": "Instalar", "install": "Instalar",
"markInstalled": "Marcar instalado", "markInstalled": "Marcar instalado",
@@ -186,12 +186,12 @@
"markUpdated": "Marcar como atualizado", "markUpdated": "Marcar como atualizado",
"additionalOptions": "Opções adicionais", "additionalOptions": "Opções adicionais",
"disableVersionDetection": "Desativar detecção de versão", "disableVersionDetection": "Desativar detecção de versão",
"noVersionDetectionExplanation": "Essa opção deve apenas ser usada por aplicativos onde a detecção de versão não funciona corretamente.", "noVersionDetectionExplanation": "Esta opção deve ser usada apenas por aplicações onde a deteção de versão não funciona corretamente.",
"downloadingX": "Baixando {}", "downloadingX": "Baixando {}",
"downloadX": "Descarregar {}", "downloadX": "Descarregar {}",
"downloadedX": "Descarregado {}", "downloadedX": "Descarregado {}",
"releaseAsset": "Libertação de activos", "releaseAsset": "Libertação de activos",
"downloadNotifDescription": "Notifica o usuário o progresso do download de um aplicativo", "downloadNotifDescription": "Notifica o utilizador sobre o progresso do download de uma aplicação",
"noAPKFound": "APK não encontrado", "noAPKFound": "APK não encontrado",
"noVersionDetection": "Sem detecção de versão", "noVersionDetection": "Sem detecção de versão",
"categorize": "Categorizar", "categorize": "Categorizar",
@@ -200,20 +200,20 @@
"noCategory": "Sem categoria", "noCategory": "Sem categoria",
"noCategories": "Sem categorias", "noCategories": "Sem categorias",
"deleteCategoriesQuestion": "Deletar categorias?", "deleteCategoriesQuestion": "Deletar categorias?",
"categoryDeleteWarning": "Todos os aplicativos em categorias removidas serão descategorizados.", "categoryDeleteWarning": "Todas as aplicações em categorias removidas serão descategorizadas.",
"addCategory": "Adicionar categoria", "addCategory": "Adicionar categoria",
"label": "Etiqueta", "label": "Etiqueta",
"language": "Linguagem", "language": "Linguagem",
"copiedToClipboard": "Copiado para a área de transferência", "copiedToClipboard": "Copiado para a área de transferência",
"storagePermissionDenied": "Permissão de armazenamento negada", "storagePermissionDenied": "Permissão de armazenamento negada",
"selectedCategorizeWarning": "Isso vai substituir qualquer configuração de categoria para os aplicativos selecionados.", "selectedCategorizeWarning": "Isto irá substituir qualquer configuração de categoria para as aplicações selecionadas.",
"filterAPKsByRegEx": "Filtrar APKs usando expressão regular", "filterAPKsByRegEx": "Filtrar APKs usando expressão regular",
"removeFromObtainium": "Remover do Obtainium", "removeFromObtainium": "Remover do Obtainium",
"uninstallFromDevice": "Desinstalar do dispositivo", "uninstallFromDevice": "Desinstalar do dispositivo",
"onlyWorksWithNonVersionDetectApps": "Apenas funciona para aplicativos com detecção de versão desativada.", "onlyWorksWithNonVersionDetectApps": "Apenas funciona para aplicações com a deteção de versão desativada.",
"releaseDateAsVersion": "Usar data de lançamento como versão", "releaseDateAsVersion": "Usar data de lançamento como versão",
"releaseTitleAsVersion": "Utilizar o título da versão como cadeia de versões", "releaseTitleAsVersion": "Utilizar o título da versão como cadeia de versões",
"releaseDateAsVersionExplanation": "Esta opção só deve ser usada para aplicativos onde a detecção de versão não funciona corretamente, mas uma data de lançamento disponível.", "releaseDateAsVersionExplanation": "Esta opção só deve ser usada para aplicações onde a deteção de versão não funciona corretamente, mas existe uma data de lançamento disponível.",
"changes": "Alterações", "changes": "Alterações",
"releaseDate": "Data de lançamento", "releaseDate": "Data de lançamento",
"importFromURLsInFile": "Importar de URLs em arquivo (formato OPML)", "importFromURLsInFile": "Importar de URLs em arquivo (formato OPML)",
@@ -227,15 +227,15 @@
"dontShowAgain": "Não mostrar isso novamente", "dontShowAgain": "Não mostrar isso novamente",
"dontShowTrackOnlyWarnings": "Não mostrar avisos 'Apenas monitorar'", "dontShowTrackOnlyWarnings": "Não mostrar avisos 'Apenas monitorar'",
"dontShowAPKOriginWarnings": "Não mostrar avisos de origem da APK", "dontShowAPKOriginWarnings": "Não mostrar avisos de origem da APK",
"moveNonInstalledAppsToBottom": "Mover aplicativos não instalados para o fundo da lista de aplicativos", "moveNonInstalledAppsToBottom": "Mover aplicações não instaladas para o fundo da lista de aplicações",
"gitlabPATLabel": "Token de acesso pessoal do Gitlab", "gitlabPATLabel": "Token de acesso pessoal do Gitlab",
"about": "Sobre", "about": "Sobre",
"requiresCredentialsInSettings": "{}: Isso requer credenciais adicionais (em Configurações)", "requiresCredentialsInSettings": "{}: Isso requer credenciais adicionais (em Configurações)",
"checkOnStart": "Verificar se há atualizações ao iniciar", "checkOnStart": "Verificar se há atualizações ao iniciar",
"tryInferAppIdFromCode": "Tente inferir o ID do aplicativo pelo código-fonte", "tryInferAppIdFromCode": "Tentar inferir o ID da aplicação a partir do código-fonte",
"removeOnExternalUninstall": "Remover automaticamente aplicativos desinstalados externamente", "removeOnExternalUninstall": "Remover automaticamente aplicações desinstaladas externamente",
"pickHighestVersionCode": "Auto-selecionar o maior número de versão do APK", "pickHighestVersionCode": "Auto-selecionar o maior número de versão do APK",
"checkUpdateOnDetailPage": "Checar por atualizações ao abrir a página de detalhes de um aplicativo", "checkUpdateOnDetailPage": "Checar por atualizações ao abrir a página de detalhes de uma aplicação",
"disablePageTransitions": "Desativar animações de transição de página", "disablePageTransitions": "Desativar animações de transição de página",
"reversePageTransitions": "Animações de transição de página invertidas", "reversePageTransitions": "Animações de transição de página invertidas",
"minStarCount": "Contagem mínima de estrelas", "minStarCount": "Contagem mínima de estrelas",
@@ -245,11 +245,11 @@
"sortByLastLinkSegment": "Ordenar apenas usando o último segmento do link", "sortByLastLinkSegment": "Ordenar apenas usando o último segmento do link",
"filterReleaseNotesByRegEx": "Filtrar notas de versão usando Regex", "filterReleaseNotesByRegEx": "Filtrar notas de versão usando Regex",
"customLinkFilterRegex": "Filtro de link personalizado usando expressão regular (Padrão '.apk$')", "customLinkFilterRegex": "Filtro de link personalizado usando expressão regular (Padrão '.apk$')",
"appsPossiblyUpdated": "Tentativas de atualização de aplicativos", "appsPossiblyUpdated": "Aplicações possivelmente atualizadas",
"appsPossiblyUpdatedNotifDescription": "Notifica o usuário de que atualizações de um ou mais aplicativos foram potencialmente aplicadas em segundo-plano", "appsPossiblyUpdatedNotifDescription": "Notifica o utilizador de que as atualizações de uma ou mais aplicações foram potencialmente aplicadas em segundo plano",
"xWasPossiblyUpdatedToY": "{} pode ter sido atualizado para {}.", "xWasPossiblyUpdatedToY": "{} pode ter sido atualizado para {}.",
"enableBackgroundUpdates": "Ativar atualizações em segundo-plano", "enableBackgroundUpdates": "Ativar atualizações em segundo-plano",
"backgroundUpdateReqsExplanation": "Atualizações em segundo-plano podem não ser possíveis para todos os aplicativos.", "backgroundUpdateReqsExplanation": "As atualizações em segundo plano podem não ser possíveis para todas as aplicações.",
"backgroundUpdateLimitsExplanation": "O sucesso de uma instalação em segundo-plano só pode ser determinado quando o Obtainium é aberto.", "backgroundUpdateLimitsExplanation": "O sucesso de uma instalação em segundo-plano só pode ser determinado quando o Obtainium é aberto.",
"verifyLatestTag": "Verifique a 'última' etiqueta", "verifyLatestTag": "Verifique a 'última' etiqueta",
"intermediateLinkRegex": "Filtrar um link 'intermediário' para visitar", "intermediateLinkRegex": "Filtrar um link 'intermediário' para visitar",
@@ -282,14 +282,14 @@
"installing": "Instalando", "installing": "Instalando",
"skipUpdateNotifications": "Pular notificações de update", "skipUpdateNotifications": "Pular notificações de update",
"updatesAvailableNotifChannel": "Atualizações disponíveis", "updatesAvailableNotifChannel": "Atualizações disponíveis",
"appsUpdatedNotifChannel": "Aplicativos atualizados", "appsUpdatedNotifChannel": "Aplicações atualizadas",
"appsPossiblyUpdatedNotifChannel": "Tentativas de atualização de aplicativos", "appsPossiblyUpdatedNotifChannel": "Aplicações possivelmente atualizadas",
"errorCheckingUpdatesNotifChannel": "Erro ao procurar por atualizações", "errorCheckingUpdatesNotifChannel": "Erro ao procurar por atualizações",
"appsRemovedNotifChannel": "Aplicativos removidos", "appsRemovedNotifChannel": "Aplicações removidas",
"downloadingXNotifChannel": "Baixando {}", "downloadingXNotifChannel": "Baixando {}",
"completeAppInstallationNotifChannel": "Instalação completa do aplicativo", "completeAppInstallationNotifChannel": "Instalação da aplicação concluída",
"checkingForUpdatesNotifChannel": "Checando por atualizações", "checkingForUpdatesNotifChannel": "Checando por atualizações",
"onlyCheckInstalledOrTrackOnlyApps": "Apenas verificar atualizações de aplicativos instalados e 'Apenas monitorar'", "onlyCheckInstalledOrTrackOnlyApps": "Apenas verificar atualizações de aplicações instaladas e 'Apenas monitorizar'",
"supportFixedAPKURL": "Suporte a APK com URLs fixas", "supportFixedAPKURL": "Suporte a APK com URLs fixas",
"selectX": "Selecionar {}", "selectX": "Selecionar {}",
"parallelDownloads": "Permitir downloads paralelos", "parallelDownloads": "Permitir downloads paralelos",
@@ -299,7 +299,7 @@
"shizukuOldAndroidWithADB": "Shizuku a funcionar no Android < 8.1 com ADB - atualizar o Android ou utilizar o Sui", "shizukuOldAndroidWithADB": "Shizuku a funcionar no Android < 8.1 com ADB - atualizar o Android ou utilizar o Sui",
"shizukuPretendToBeGooglePlay": "Definir o Google Play como fonte de instalação (se for utilizado o Shizuku)", "shizukuPretendToBeGooglePlay": "Definir o Google Play como fonte de instalação (se for utilizado o Shizuku)",
"useSystemFont": "Usar fonte padrão do sistema", "useSystemFont": "Usar fonte padrão do sistema",
"useVersionCodeAsOSVersion": "Usar versionCode do aplicativo como versão detectada pelo sistema operacional", "useVersionCodeAsOSVersion": "Usar o versionCode da aplicação como a versão detetada pelo sistema operativo",
"requestHeader": "Requisitar cabeçalho", "requestHeader": "Requisitar cabeçalho",
"useLatestAssetDateAsReleaseDate": "Use o último upload de recursos como data de lançamento", "useLatestAssetDateAsReleaseDate": "Use o último upload de recursos como data de lançamento",
"defaultPseudoVersioningMethod": "Método de pseudo-versionamento padrão", "defaultPseudoVersioningMethod": "Método de pseudo-versionamento padrão",
@@ -337,6 +337,8 @@
"fgServiceNotice": "Esta notificação é necessária para a verificação de actualizações em segundo plano (pode ser ocultada nas definições do SO)", "fgServiceNotice": "Esta notificação é necessária para a verificação de actualizações em segundo plano (pode ser ocultada nas definições do SO)",
"excludeSecrets": "Excluir segredos", "excludeSecrets": "Excluir segredos",
"GHReqPrefix": "Instância 'sky22333/hubproxy' para pedidos de GitHub", "GHReqPrefix": "Instância 'sky22333/hubproxy' para pedidos de GitHub",
"includeZips": "Incluir ficheiros ZIP",
"zippedApkFilterRegEx": "Filtrar APKs dentro do ZIP",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Remover aplicação?", "one": "Remover aplicação?",
"other": "Remover aplicações?" "other": "Remover aplicações?"

View File

@@ -337,6 +337,8 @@
"fgServiceNotice": "Это уведомление необходимо для фоновой проверки обновлений (оно может быть скрыто в настройках ОС)", "fgServiceNotice": "Это уведомление необходимо для фоновой проверки обновлений (оно может быть скрыто в настройках ОС)",
"excludeSecrets": "Исключить секреты", "excludeSecrets": "Исключить секреты",
"GHReqPrefix": "Экземпляр 'sky22333/hubproxy' для запросов на GitHub", "GHReqPrefix": "Экземпляр 'sky22333/hubproxy' для запросов на GitHub",
"includeZips": "Включить ZIP-файлы",
"zippedApkFilterRegEx": "Фильтр APK внутри ZIP",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Удалить приложение?", "one": "Удалить приложение?",
"other": "Удалить приложения?" "other": "Удалить приложения?"

View File

@@ -337,6 +337,8 @@
"fgServiceNotice": "Detta meddelande krävs för bakgrundsuppdateringskontroll (det kan döljas i OS-inställningarna)", "fgServiceNotice": "Detta meddelande krävs för bakgrundsuppdateringskontroll (det kan döljas i OS-inställningarna)",
"excludeSecrets": "Utesluta hemligheter", "excludeSecrets": "Utesluta hemligheter",
"GHReqPrefix": "Instansen \"sky22333/hubproxy\" för GitHub-förfrågningar", "GHReqPrefix": "Instansen \"sky22333/hubproxy\" för GitHub-förfrågningar",
"includeZips": "Inkludera ZIP-filer",
"zippedApkFilterRegEx": "Filtrera APK:er inuti ZIP",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Ta Bort App?", "one": "Ta Bort App?",
"other": "Ta Bort Appar?" "other": "Ta Bort Appar?"

View File

@@ -337,6 +337,8 @@
"fgServiceNotice": "Bu bildirim arka planda güncelleme kontrolü için gereklidir (işletim sistemi ayarlarından gizlenebilir)", "fgServiceNotice": "Bu bildirim arka planda güncelleme kontrolü için gereklidir (işletim sistemi ayarlarından gizlenebilir)",
"excludeSecrets": "Sırları hariç tut", "excludeSecrets": "Sırları hariç tut",
"GHReqPrefix": "GitHub istekleri için 'sky22333/hubproxy' örneği", "GHReqPrefix": "GitHub istekleri için 'sky22333/hubproxy' örneği",
"includeZips": "ZIP dosyalarını dahil edin",
"zippedApkFilterRegEx": "ZIP içindeki APK'ları filtreleme",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Uygulamayı Kaldır?", "one": "Uygulamayı Kaldır?",
"other": "Uygulamaları Kaldır?" "other": "Uygulamaları Kaldır?"

View File

@@ -337,6 +337,8 @@
"fgServiceNotice": "Це сповіщення необхідне для фонової перевірки оновлень (його можна приховати в налаштуваннях ОС)", "fgServiceNotice": "Це сповіщення необхідне для фонової перевірки оновлень (його можна приховати в налаштуваннях ОС)",
"excludeSecrets": "Виключити секрети", "excludeSecrets": "Виключити секрети",
"GHReqPrefix": "екземпляр 'sky22333/hubproxy' для запитів на GitHub", "GHReqPrefix": "екземпляр 'sky22333/hubproxy' для запитів на GitHub",
"includeZips": "Додайте ZIP-файли",
"zippedApkFilterRegEx": "Фільтруйте APK-файли всередині ZIP",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Видалити застосунок?", "one": "Видалити застосунок?",
"other": "Видалити застосунки?" "other": "Видалити застосунки?"

View File

@@ -337,6 +337,8 @@
"fgServiceNotice": "Thông báo này là bắt buộc để kiểm tra cập nhật nền (có thể ẩn trong cài đặt hệ điều hành).", "fgServiceNotice": "Thông báo này là bắt buộc để kiểm tra cập nhật nền (có thể ẩn trong cài đặt hệ điều hành).",
"excludeSecrets": "Loại trừ thông tin bí mật", "excludeSecrets": "Loại trừ thông tin bí mật",
"GHReqPrefix": "Thực thể 'sky22333/hubproxy' cho các yêu cầu GitHub", "GHReqPrefix": "Thực thể 'sky22333/hubproxy' cho các yêu cầu GitHub",
"includeZips": "Ba gồm các tệp ZIP",
"zippedApkFilterRegEx": "Lọc các tệp APK bên trong tệp ZIP",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Gỡ ứng dụng?", "one": "Gỡ ứng dụng?",
"other": "Gỡ ứng dụng?" "other": "Gỡ ứng dụng?"

View File

@@ -337,6 +337,8 @@
"fgServiceNotice": "This notification is required for background update checking (it can be hidden in the OS settings)", "fgServiceNotice": "This notification is required for background update checking (it can be hidden in the OS settings)",
"excludeSecrets": "Exclude secrets", "excludeSecrets": "Exclude secrets",
"GHReqPrefix": "'sky22333/hubproxy' instance for GitHub requests", "GHReqPrefix": "'sky22333/hubproxy' instance for GitHub requests",
"includeZips": "Include ZIP files",
"zippedApkFilterRegEx": "Filter APKs inside ZIP",
"removeAppQuestion": { "removeAppQuestion": {
"one": "移除應用程式?", "one": "移除應用程式?",
"other": "移除應用程式?" "other": "移除應用程式?"

View File

@@ -337,6 +337,8 @@
"fgServiceNotice": "后台检查更新时需要此通知(可在操作系统设置中隐藏)", "fgServiceNotice": "后台检查更新时需要此通知(可在操作系统设置中隐藏)",
"excludeSecrets": "排除机密", "excludeSecrets": "排除机密",
"GHReqPrefix": "用于 GitHub 请求的 \"sky22333/hubproxy \"实例", "GHReqPrefix": "用于 GitHub 请求的 \"sky22333/hubproxy \"实例",
"includeZips": "包含 ZIP 文件",
"zippedApkFilterRegEx": "过滤 ZIP 内的 APK",
"removeAppQuestion": { "removeAppQuestion": {
"one": "是否删除应用?", "one": "是否删除应用?",
"other": "是否删除应用?" "other": "是否删除应用?"

View File

@@ -18,6 +18,7 @@ class GitHub extends AppSource {
appIdInferIsOptional = true; appIdInferIsOptional = true;
showReleaseDateAsVersionToggle = true; showReleaseDateAsVersionToggle = true;
this.hostChanged = hostChanged; this.hostChanged = hostChanged;
allowIncludeZips = true;
sourceConfigSettingFormItems = [ sourceConfigSettingFormItems = [
GeneratedFormTextField( GeneratedFormTextField(
@@ -370,6 +371,7 @@ class GitHub extends AppSource {
additionalSettings['useLatestAssetDateAsReleaseDate'] == true; additionalSettings['useLatestAssetDateAsReleaseDate'] == true;
String sortMethod = String sortMethod =
additionalSettings['sortMethodChoice'] ?? 'smartname-datefallback'; additionalSettings['sortMethodChoice'] ?? 'smartname-datefallback';
bool includeZips = additionalSettings['includeZips'] == true;
dynamic latestRelease; dynamic latestRelease;
if (verifyLatestTag) { if (verifyLatestTag) {
var temp = requestUrl.split('?'); var temp = requestUrl.split('?');
@@ -402,7 +404,8 @@ class GitHub extends AppSource {
findReleaseAssetUrls(dynamic release) => findReleaseAssetUrls(dynamic release) =>
(release['assets'] as List<dynamic>?)?.map((e) { (release['assets'] as List<dynamic>?)?.map((e) {
var url = !e['name'].toString().toLowerCase().endsWith('.apk') var ext = e['name'].toString().toLowerCase().split('.').last;
var url = !(ext == 'apk' || ext == 'xapk' || (includeZips && ext == 'zip'))
? (e['browser_download_url'] ?? e['url']) ? (e['browser_download_url'] ?? e['url'])
: (e['url'] ?? e['browser_download_url']); : (e['url'] ?? e['browser_download_url']);
url = undoGHProxyMod(url, sourceConfigSettingValues); url = undoGHProxyMod(url, sourceConfigSettingValues);
@@ -542,14 +545,13 @@ class GitHub extends AppSource {
List<MapEntry<String, String>> allAssetUrls = allAssetsWithUrls List<MapEntry<String, String>> allAssetUrls = allAssetsWithUrls
.map((e) => e['final_url'] as MapEntry<String, String>) .map((e) => e['final_url'] as MapEntry<String, String>)
.toList(); .toList();
var apkAssetsWithUrls = allAssetsWithUrls var apkAssetsWithUrls = allAssetsWithUrls.where((element) {
.where( var ext = (element['final_url'] as MapEntry<String, String>).key
(element) => (element['final_url'] as MapEntry<String, String>)
.key
.toLowerCase() .toLowerCase()
.endsWith('.apk'), .split('.')
) .last;
.toList(); return ext == 'apk' || ext == 'xapk' || (includeZips && ext == 'zip');
}).toList();
var filteredApkUrls = filterApks( var filteredApkUrls = filterApks(
apkAssetsWithUrls apkAssetsWithUrls

View File

@@ -86,9 +86,13 @@ class RuStore extends AppSource {
postBody: {"appId": appDetails['appId'], "firstInstall": true}, postBody: {"appId": appDetails['appId'], "firstInstall": true},
); );
var downloadDetails = (await decodeJsonBody(res1.bodyBytes))['body']; var downloadDetails = (await decodeJsonBody(res1.bodyBytes))['body'];
try {
if (res1.statusCode != 200 || downloadDetails['downloadUrls'][0]['url'] == null) { if (res1.statusCode != 200 || downloadDetails['downloadUrls'][0]['url'] == null) {
throw NoAPKError(); throw NoAPKError();
} }
} catch (e) {
throw NoAPKError();
}
return APKDetails( return APKDetails(
version, version,

View File

@@ -203,11 +203,11 @@ class AddAppPageState extends State<AddAppPage> {
notificationsProvider: notificationsProvider, notificationsProvider: notificationsProvider,
); );
DownloadedApk? downloadedFile; DownloadedApk? downloadedFile;
DownloadedXApkDir? downloadedDir; DownloadedDir? downloadedDir;
if (downloadedArtifact is DownloadedApk) { if (downloadedArtifact is DownloadedApk) {
downloadedFile = downloadedArtifact; downloadedFile = downloadedArtifact;
} else { } else {
downloadedDir = downloadedArtifact as DownloadedXApkDir; downloadedDir = downloadedArtifact as DownloadedDir;
} }
app.id = downloadedFile?.appId ?? downloadedDir!.appId; app.id = downloadedFile?.appId ?? downloadedDir!.appId;
} }

View File

@@ -1010,6 +1010,7 @@ class AppsPageState extends State<AppsPage> {
selectedApps.where((element) => element.pinned).isEmpty selectedApps.where((element) => element.pinned).isEmpty
? tr('pinToTop') ? tr('pinToTop')
: tr('unpinFromTop'), : tr('unpinFromTop'),
textAlign: TextAlign.center,
), ),
), ),
const Divider(), const Divider(),
@@ -1026,7 +1027,10 @@ class AppsPageState extends State<AppsPage> {
); );
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },
child: Text(tr('shareSelectedAppURLs')), child: Text(
tr('shareSelectedAppURLs'),
textAlign: TextAlign.center,
),
), ),
const Divider(), const Divider(),
TextButton( TextButton(
@@ -1043,7 +1047,10 @@ class AppsPageState extends State<AppsPage> {
subject: 'Obtainium - ${tr('appsString')}', subject: 'Obtainium - ${tr('appsString')}',
); );
}, },
child: Text(tr('shareAppConfigLinks')), child: Text(
tr('shareAppConfigLinks'),
textAlign: TextAlign.center,
),
), ),
const Divider(), const Divider(),
TextButton( TextButton(
@@ -1069,7 +1076,10 @@ class AppsPageState extends State<AppsPage> {
fileNameOverrides: ['$fn.json'], fileNameOverrides: ['$fn.json'],
); );
}, },
child: Text('${tr('share')} - ${tr('obtainiumExport')}'), child: Text(
'${tr('share')} - ${tr('obtainiumExport')}',
textAlign: TextAlign.center,
),
), ),
const Divider(), const Divider(),
TextButton( TextButton(
@@ -1093,6 +1103,7 @@ class AppsPageState extends State<AppsPage> {
'downloadX', 'downloadX',
args: [lowerCaseIfEnglish(tr('releaseAsset'))], args: [lowerCaseIfEnglish(tr('releaseAsset'))],
), ),
textAlign: TextAlign.center,
), ),
), ),
const Divider(), const Divider(),
@@ -1100,7 +1111,10 @@ class AppsPageState extends State<AppsPage> {
onPressed: appsProvider.areDownloadsRunning() onPressed: appsProvider.areDownloadsRunning()
? null ? null
: showMassMarkDialog, : showMassMarkDialog,
child: Text(tr('markSelectedAppsUpdated')), child: Text(
tr('markSelectedAppsUpdated'),
textAlign: TextAlign.center,
),
), ),
], ],
), ),

View File

@@ -62,11 +62,14 @@ class DownloadedApk {
DownloadedApk(this.appId, this.file); DownloadedApk(this.appId, this.file);
} }
class DownloadedXApkDir { enum DownloadedDirType { XAPK, ZIP }
class DownloadedDir {
String appId; String appId;
File file; File file;
Directory extracted; Directory extracted;
DownloadedXApkDir(this.appId, this.file, this.extracted); DownloadedDirType type;
DownloadedDir(this.appId, this.file, this.extracted, this.type);
} }
List<String> generateStandardVersionRegExStrings() { List<String> generateStandardVersionRegExStrings() {
@@ -495,6 +498,10 @@ Future<PackageInfo?> getInstalledInfo(
return null; return null;
} }
Future<Directory> getAppStorageDir() async =>
await getExternalStorageDirectory() ??
await getApplicationDocumentsDirectory();
class AppsProvider with ChangeNotifier { class AppsProvider with ChangeNotifier {
// In memory App state (should always be kept in sync with local storage versions) // In memory App state (should always be kept in sync with local storage versions)
Map<String, AppInMemory> apps = {}; Map<String, AppInMemory> apps = {};
@@ -531,15 +538,11 @@ class AppsProvider with ChangeNotifier {
iconsCacheDir.createSync(); iconsCacheDir.createSync();
} }
} else { } else {
APKDir = Directory( APKDir = Directory('${(await getAppStorageDir()).path}/apks');
'${(await getExternalStorageDirectory())!.path}/apks',
);
if (!APKDir.existsSync()) { if (!APKDir.existsSync()) {
APKDir.createSync(); APKDir.createSync();
} }
iconsCacheDir = Directory( iconsCacheDir = Directory('${(await getAppStorageDir()).path}/icons');
'${(await getExternalStorageDirectory())!.path}/icons',
);
if (!iconsCacheDir.existsSync()) { if (!iconsCacheDir.existsSync()) {
iconsCacheDir.createSync(); iconsCacheDir.createSync();
} }
@@ -664,17 +667,18 @@ class AppsProvider with ChangeNotifier {
} }
PackageInfo? newInfo; PackageInfo? newInfo;
var isAPK = downloadedFile.path.toLowerCase().endsWith('.apk'); var isAPK = downloadedFile.path.toLowerCase().endsWith('.apk');
Directory? xapkDir; var isXAPK = downloadedFile.path.toLowerCase().endsWith('.xapk');
Directory? apkDir;
if (isAPK) { if (isAPK) {
newInfo = await pm.getPackageArchiveInfo( newInfo = await pm.getPackageArchiveInfo(
archiveFilePath: downloadedFile.path, archiveFilePath: downloadedFile.path,
); );
} else { } else {
// Assume XAPK // Assume XAPK or ZIP
String xapkDirPath = '${downloadedFile.path}-dir'; String apkDirPath = '${downloadedFile.path}-dir';
await unzipFile(downloadedFile.path, '${downloadedFile.path}-dir'); await unzipFile(downloadedFile.path, '${downloadedFile.path}-dir');
xapkDir = Directory(xapkDirPath); apkDir = Directory(apkDirPath);
var apks = xapkDir var apks = apkDir
.listSync() .listSync()
.where((e) => e.path.toLowerCase().endsWith('.apk')) .where((e) => e.path.toLowerCase().endsWith('.apk'))
.toList(); .toList();
@@ -691,6 +695,22 @@ class AppsProvider with ChangeNotifier {
apks = [temp!, ...apks]; apks = [temp!, ...apks];
} }
if (app.additionalSettings['zippedApkFilterRegEx']?.isNotEmpty ==
true) {
var reg = RegExp(app.additionalSettings['zippedApkFilterRegEx']);
apks.removeWhere((apk) {
var shouldDelete = !reg.hasMatch(apk.uri.pathSegments.last);
if (shouldDelete) {
apk.delete();
}
return shouldDelete;
});
}
if (apks.isEmpty) {
throw NoAPKError();
}
for (var i = 0; i < apks.length; i++) { for (var i = 0; i < apks.length; i++) {
try { try {
newInfo = await pm.getPackageArchiveInfo( newInfo = await pm.getPackageArchiveInfo(
@@ -728,7 +748,12 @@ class AppsProvider with ChangeNotifier {
if (isAPK) { if (isAPK) {
return DownloadedApk(app.id, downloadedFile); return DownloadedApk(app.id, downloadedFile);
} else { } else {
return DownloadedXApkDir(app.id, downloadedFile, xapkDir!); return DownloadedDir(
app.id,
downloadedFile,
apkDir!,
isXAPK ? DownloadedDirType.XAPK : DownloadedDirType.ZIP,
);
} }
} finally { } finally {
notificationsProvider?.cancel(notifId); notificationsProvider?.cancel(notifId);
@@ -826,15 +851,16 @@ class AppsProvider with ChangeNotifier {
); );
} }
Future<bool> installXApkDir( Future<bool> installApkDir(
DownloadedXApkDir dir, DownloadedDir dir,
BuildContext? firstTimeWithContext, { BuildContext? firstTimeWithContext, {
bool needsBGWorkaround = false, bool needsBGWorkaround = false,
bool shizukuPretendToBeGooglePlay = false, bool shizukuPretendToBeGooglePlay = false,
}) async { }) async {
// We don't know which APKs in an XAPK are supported by the user's device // We don't know which APKs in an XAPK or ZIP are supported by the user's device
// So we try installing all of them and assume success if at least one installed // So we try installing all of them and assume success if at least one installed
// If 0 APKs installed, throw the first install error encountered // If 0 APKs installed, throw the first install error encountered
// Obviously this approach is naive and is undesirable in many cases, needs to be improved
var somethingInstalled = false; var somethingInstalled = false;
try { try {
MultiAppMultiError errors = MultiAppMultiError(); MultiAppMultiError errors = MultiAppMultiError();
@@ -863,7 +889,7 @@ class AppsProvider with ChangeNotifier {
} }
try { try {
await installApk( var wasInstalled = await installApk(
DownloadedApk(dir.appId, APKFiles[0]), DownloadedApk(dir.appId, APKFiles[0]),
firstTimeWithContext, firstTimeWithContext,
needsBGWorkaround: needsBGWorkaround, needsBGWorkaround: needsBGWorkaround,
@@ -872,10 +898,10 @@ class AppsProvider with ChangeNotifier {
1, 1,
).map((a) => DownloadedApk(dir.appId, a)).toList(), ).map((a) => DownloadedApk(dir.appId, a)).toList(),
); );
somethingInstalled = true; somethingInstalled = somethingInstalled || wasInstalled;
dir.file.delete(recursive: true); dir.file.delete(recursive: true);
} catch (e) { } catch (e) {
logs.add('Could not install APKs from XAPK: ${e.toString()}'); logs.add('Could not install APKs from ${dir.type}: ${e.toString()}');
errors.add(dir.appId, e, appName: apps[dir.appId]?.name); errors.add(dir.appId, e, appName: apps[dir.appId]?.name);
} }
if (errors.idsByErrorString.isNotEmpty) { if (errors.idsByErrorString.isNotEmpty) {
@@ -976,7 +1002,7 @@ class AppsProvider with ChangeNotifier {
} }
Future<String> getStorageRootPath() async { Future<String> getStorageRootPath() async {
return '/${(await getExternalStorageDirectory())!.uri.pathSegments.sublist(0, 3).join('/')}'; return '/${(await getAppStorageDir()).uri.pathSegments.sublist(0, 3).join('/')}';
} }
Future<void> moveObbFile(File file, String appId) async { Future<void> moveObbFile(File file, String appId) async {
@@ -1148,7 +1174,7 @@ class AppsProvider with ChangeNotifier {
String id, String id,
bool willBeSilent, bool willBeSilent,
DownloadedApk? downloadedFile, DownloadedApk? downloadedFile,
DownloadedXApkDir? downloadedDir, DownloadedDir? downloadedDir,
) async { ) async {
apps[id]?.downloadProgress = -1; apps[id]?.downloadProgress = -1;
notifyListeners(); notifyListeners();
@@ -1183,14 +1209,14 @@ class AppsProvider with ChangeNotifier {
} else { } else {
if (needBGWorkaround) { if (needBGWorkaround) {
// ignore: use_build_context_synchronously // ignore: use_build_context_synchronously
installXApkDir( installApkDir(
downloadedDir!, downloadedDir!,
contextIfNewInstall, contextIfNewInstall,
needsBGWorkaround: true, needsBGWorkaround: true,
); );
} else { } else {
// ignore: use_build_context_synchronously // ignore: use_build_context_synchronously
sayInstalled = await installXApkDir( sayInstalled = await installApkDir(
downloadedDir!, downloadedDir!,
contextIfNewInstall, contextIfNewInstall,
shizukuPretendToBeGooglePlay: shizukuPretendToBeGooglePlay, shizukuPretendToBeGooglePlay: shizukuPretendToBeGooglePlay,
@@ -1227,7 +1253,7 @@ class AppsProvider with ChangeNotifier {
}) async { }) async {
bool willBeSilent = false; bool willBeSilent = false;
DownloadedApk? downloadedFile; DownloadedApk? downloadedFile;
DownloadedXApkDir? downloadedDir; DownloadedDir? downloadedDir;
try { try {
var downloadedArtifact = var downloadedArtifact =
// ignore: use_build_context_synchronously // ignore: use_build_context_synchronously
@@ -1240,7 +1266,7 @@ class AppsProvider with ChangeNotifier {
if (downloadedArtifact is DownloadedApk) { if (downloadedArtifact is DownloadedApk) {
downloadedFile = downloadedArtifact; downloadedFile = downloadedArtifact;
} else { } else {
downloadedDir = downloadedArtifact as DownloadedXApkDir; downloadedDir = downloadedArtifact as DownloadedDir;
} }
id = downloadedFile?.appId ?? downloadedDir!.appId; id = downloadedFile?.appId ?? downloadedDir!.appId;
willBeSilent = await canInstallSilently(apps[id]!.app); willBeSilent = await canInstallSilently(apps[id]!.app);
@@ -1292,7 +1318,7 @@ class AppsProvider with ChangeNotifier {
res['id'] as String, res['id'] as String,
res['willBeSilent'] as bool, res['willBeSilent'] as bool,
res['downloadedFile'] as DownloadedApk?, res['downloadedFile'] as DownloadedApk?,
res['downloadedDir'] as DownloadedXApkDir?, res['downloadedDir'] as DownloadedDir?,
); );
} catch (e) { } catch (e) {
var id = res['id'] as String; var id = res['id'] as String;
@@ -1323,6 +1349,7 @@ class AppsProvider with ChangeNotifier {
MapEntry<String, String>? fileUrl; MapEntry<String, String>? fileUrl;
var refreshBeforeDownload = var refreshBeforeDownload =
apps[id]!.app.additionalSettings['refreshBeforeDownload'] == true || apps[id]!.app.additionalSettings['refreshBeforeDownload'] == true ||
apps[id]!.app.apkUrls.isNotEmpty &&
apps[id]!.app.apkUrls.first.value == 'placeholder'; apps[id]!.app.apkUrls.first.value == 'placeholder';
if (refreshBeforeDownload) { if (refreshBeforeDownload) {
await checkUpdate(apps[id]!.app.id); await checkUpdate(apps[id]!.app.id);
@@ -1422,7 +1449,7 @@ class AppsProvider with ChangeNotifier {
Future<Directory> getAppsDir() async { Future<Directory> getAppsDir() async {
Directory appsDir = Directory( Directory appsDir = Directory(
'${(await getExternalStorageDirectory())!.path}/app_data', '${(await getAppStorageDir()).path}/app_data',
); );
if (!appsDir.existsSync()) { if (!appsDir.existsSync()) {
appsDir.createSync(); appsDir.createSync();

View File

@@ -9,7 +9,6 @@ import 'package:obtainium/app_sources/github.dart';
import 'package:obtainium/main.dart'; import 'package:obtainium/main.dart';
import 'package:obtainium/providers/apps_provider.dart'; import 'package:obtainium/providers/apps_provider.dart';
import 'package:obtainium/providers/source_provider.dart'; import 'package:obtainium/providers/source_provider.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart'; import 'package:permission_handler/permission_handler.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:shared_storage/shared_storage.dart' as saf; import 'package:shared_storage/shared_storage.dart' as saf;
@@ -35,7 +34,7 @@ class SettingsProvider with ChangeNotifier {
// Not done in constructor as we want to be able to await it // Not done in constructor as we want to be able to await it
Future<void> initializeSettings() async { Future<void> initializeSettings() async {
prefs = await SharedPreferences.getInstance(); prefs = await SharedPreferences.getInstance();
defaultAppDir = (await getExternalStorageDirectory())!.path; defaultAppDir = (await getAppStorageDir()).path;
notifyListeners(); notifyListeners();
} }

View File

@@ -636,6 +636,7 @@ abstract class AppSource {
bool versionDetectionDisallowed = false; bool versionDetectionDisallowed = false;
List<String> excludeCommonSettingKeys = []; List<String> excludeCommonSettingKeys = [];
bool urlsAlwaysHaveExtension = false; bool urlsAlwaysHaveExtension = false;
bool allowIncludeZips = false;
AppSource() { AppSource() {
name = runtimeType.toString(); name = runtimeType.toString();
@@ -834,7 +835,7 @@ abstract class AppSource {
], ],
]; ];
// Previous 2 variables combined into one at runtime for convenient usage // Previous 2 variables combined into one at runtime for convenient usage + additional processing
List<List<GeneratedFormItem>> get combinedAppSpecificSettingFormItems { List<List<GeneratedFormItem>> get combinedAppSpecificSettingFormItems {
if (showReleaseDateAsVersionToggle == true) { if (showReleaseDateAsVersionToggle == true) {
if (additionalAppSpecificSourceAgnosticSettingFormItemsNeverUseDirectly if (additionalAppSpecificSourceAgnosticSettingFormItemsNeverUseDirectly
@@ -878,6 +879,32 @@ abstract class AppSource {
) )
.where((e) => e.isNotEmpty) .where((e) => e.isNotEmpty)
.toList(); .toList();
var moreConditionalItems = [];
if (allowIncludeZips) {
moreConditionalItems.addAll([
[
GeneratedFormSwitch(
'includeZips',
label: tr('includeZips'),
defaultValue: false,
),
],
[
GeneratedFormTextField(
'zippedApkFilterRegEx',
label: tr('zippedApkFilterRegEx'),
required: false,
additionalValidators: [
(value) {
return regExValidator(value);
},
],
),
],
]);
}
if (versionDetectionDisallowed) { if (versionDetectionDisallowed) {
overrideAdditionalAppSpecificSourceAgnosticSettingSwitch( overrideAdditionalAppSpecificSourceAgnosticSettingSwitch(
'versionDetection', 'versionDetection',
@@ -893,6 +920,7 @@ abstract class AppSource {
return [ return [
...additionalSourceAppSpecificSettingFormItems, ...additionalSourceAppSpecificSettingFormItems,
...additionalAppSpecificSourceAgnosticSettingFormItemsNeverUseDirectly, ...additionalAppSpecificSourceAgnosticSettingFormItemsNeverUseDirectly,
...moreConditionalItems,
]; ];
} }

View File

@@ -40,10 +40,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: animations name: animations
sha256: d3d6dcfb218225bbe68e87ccf6378bbb2e32a94900722c5f81611dad089911cb sha256: a8031b276f0a7986ac907195f10ca7cd04ecf2a8a566bd6dbe03018a9b02b427
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.11" version: "2.1.0"
app_links: app_links:
dependency: "direct main" dependency: "direct main"
description: description:
@@ -176,18 +176,18 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: cross_file name: cross_file
sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670" sha256: "942a4791cd385a68ccb3b32c71c427aba508a1bb949b86dff2adbe4049f16239"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.3.4+2" version: "0.3.5"
crypto: crypto:
dependency: "direct main" dependency: "direct main"
description: description:
name: crypto name: crypto
sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.6" version: "3.0.7"
csslib: csslib:
dependency: transitive dependency: transitive
description: description:
@@ -216,10 +216,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: device_info_plus name: device_info_plus
sha256: "49413c8ca514dea7633e8def233b25efdf83ec8522955cc2c0e3ad802927e7c6" sha256: dd0e8e02186b2196c7848c9d394a5fd6e5b57a43a546082c5820b1ec72317e33
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "12.1.0" version: "12.2.0"
device_info_plus_platform_interface: device_info_plus_platform_interface:
dependency: transitive dependency: transitive
description: description:
@@ -304,18 +304,18 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: flex_color_picker name: flex_color_picker
sha256: "8f753a1a026a13ea5cc5eddbae3ceb886f2537569ab2e5208efb1e3bb5af72ff" sha256: f5b0b53d4ae0d59b1e28dfc21d5398e5028cf8e764518e491a52fd050aa23881
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.7.1" version: "3.7.2"
flex_seed_scheme: flex_seed_scheme:
dependency: transitive dependency: transitive
description: description:
name: flex_seed_scheme name: flex_seed_scheme
sha256: b06d8b367b84cbf7ca5c5603c858fa5edae88486c4e4da79ac1044d73b6c62ec sha256: "828291a5a4d4283590541519d8b57821946660ac61d2e07d955f81cfcab22e5d"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.5.1" version: "3.6.1"
flutter: flutter:
dependency: "direct main" dependency: "direct main"
description: flutter description: flutter
@@ -482,10 +482,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: flutter_plugin_android_lifecycle name: flutter_plugin_android_lifecycle
sha256: b0694b7fb1689b0e6cc193b3f1fcac6423c4f93c74fb20b806c6b6f196db0c31 sha256: "306f0596590e077338312f38837f595c04f28d6cdeeac392d3d74df2f0003687"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.30" version: "2.0.32"
flutter_test: flutter_test:
dependency: transitive dependency: transitive
description: flutter description: flutter
@@ -676,18 +676,18 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: path_provider_android name: path_provider_android
sha256: "993381400e94d18469750e5b9dcb8206f15bc09f9da86b9e44a9b0092a0066db" sha256: e122c5ea805bb6773bb12ce667611265980940145be920cd09a4b0ec0285cb16
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.18" version: "2.2.20"
path_provider_foundation: path_provider_foundation:
dependency: transitive dependency: transitive
description: description:
name: path_provider_foundation name: path_provider_foundation
sha256: "16eef174aacb07e09c351502740fa6254c165757638eba1e9116b0a781201bbd" sha256: efaec349ddfc181528345c56f8eda9d6cccd71c177511b132c6a0ddaefaa2738
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.4.2" version: "2.4.3"
path_provider_linux: path_provider_linux:
dependency: transitive dependency: transitive
description: description:
@@ -796,10 +796,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: pointer_interceptor_ios name: pointer_interceptor_ios
sha256: a6906772b3205b42c44614fcea28f818b1e5fdad73a4ca742a7bd49818d9c917 sha256: "03c5fa5896080963ab4917eeffda8d28c90f22863a496fb5ba13bc10943e40e4"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.10.1" version: "0.10.1+1"
pointer_interceptor_platform_interface: pointer_interceptor_platform_interface:
dependency: transitive dependency: transitive
description: description:
@@ -828,10 +828,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: share_plus name: share_plus
sha256: "3424e9d5c22fd7f7590254ba09465febd6f8827c8b19a44350de4ac31d92d3a6" sha256: "14c8860d4de93d3a7e53af51bff479598c4e999605290756bbbe45cf65b37840"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "12.0.0" version: "12.0.1"
share_plus_platform_interface: share_plus_platform_interface:
dependency: transitive dependency: transitive
description: description:
@@ -852,18 +852,18 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: shared_preferences_android name: shared_preferences_android
sha256: bd14436108211b0d4ee5038689a56d4ae3620fd72fd6036e113bf1345bc74d9e sha256: "34266009473bf71d748912da4bf62d439185226c03e01e2d9687bc65bbfcb713"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.4.13" version: "2.4.15"
shared_preferences_foundation: shared_preferences_foundation:
dependency: transitive dependency: transitive
description: description:
name: shared_preferences_foundation name: shared_preferences_foundation
sha256: "6a52cfcdaeac77cad8c97b539ff688ccfc458c007b4db12be584fbe5c0e49e03" sha256: "1c33a907142607c40a7542768ec9badfd16293bac51da3a4482623d15845f88b"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.5.4" version: "2.5.5"
shared_preferences_linux: shared_preferences_linux:
dependency: transitive dependency: transitive
description: description:
@@ -927,14 +927,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.10.1" version: "1.10.1"
sprintf:
dependency: transitive
description:
name: sprintf
sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23"
url: "https://pub.dev"
source: hosted
version: "7.0.0"
sqflite: sqflite:
dependency: "direct main" dependency: "direct main"
description: description:
@@ -1059,18 +1051,18 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_android name: url_launcher_android
sha256: "199bc33e746088546a39cc5f36bac5a278c5e53b40cb3196f99e7345fdcfae6b" sha256: "5c8b6c2d89a78f5a1cca70a73d9d5f86c701b36b42f9c9dac7bad592113c28e9"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.3.22" version: "6.3.24"
url_launcher_ios: url_launcher_ios:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_ios name: url_launcher_ios
sha256: d80b3f567a617cb923546034cc94bfe44eb15f989fe670b37f26abdb9d939cb7 sha256: "6b63f1441e4f653ae799166a72b50b1767321ecc263a57aadf825a7a2a5477d9"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.3.4" version: "6.3.5"
url_launcher_linux: url_launcher_linux:
dependency: transitive dependency: transitive
description: description:
@@ -1083,10 +1075,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_macos name: url_launcher_macos
sha256: c043a77d6600ac9c38300567f33ef12b0ef4f4783a2c1f00231d2b1941fea13f sha256: "8262208506252a3ed4ff5c0dc1e973d2c0e0ef337d0a074d35634da5d44397c9"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.2.3" version: "3.2.4"
url_launcher_platform_interface: url_launcher_platform_interface:
dependency: transitive dependency: transitive
description: description:
@@ -1115,10 +1107,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: uuid name: uuid
sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff sha256: a11b666489b1954e01d992f3d601b1804a33937b5a8fe677bd26b8a9f96f96e8
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.5.1" version: "4.5.2"
vector_math: vector_math:
dependency: transitive dependency: transitive
description: description:
@@ -1155,10 +1147,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: webview_flutter_android name: webview_flutter_android
sha256: "3c4eb4fcc252b40c2b5ce7be20d0481428b70f3ff589b0a8b8aaeb64c6bed701" sha256: e5201c620eb2637dca88a756961fae4a7191bb30b4f2271e08b746405ffdf3fd
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.10.2" version: "4.10.5"
webview_flutter_platform_interface: webview_flutter_platform_interface:
dependency: transitive dependency: transitive
description: description:
@@ -1171,18 +1163,18 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: webview_flutter_wkwebview name: webview_flutter_wkwebview
sha256: fea63576b3b7e02b2df8b78ba92b48ed66caec2bb041e9a0b1cbd586d5d80bfd sha256: "5de608fdea144d4370c21d4c80f0528135529e0180aa129790064c345e457a43"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.23.1" version: "3.23.2"
win32: win32:
dependency: transitive dependency: transitive
description: description:
name: win32 name: win32
sha256: "66814138c3562338d05613a6e368ed8cfb237ad6d64a9e9334be3f309acfca03" sha256: d7cb55e04cd34096cd3a79b3330245f54cb96a370a1c27adb3c84b917de8b08e
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "5.14.0" version: "5.15.0"
win32_registry: win32_registry:
dependency: transitive dependency: transitive
description: description:

View File

@@ -16,7 +16,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: 1.2.6+2322 version: 1.2.8+2324
environment: environment:
sdk: ^3.8.1 sdk: ^3.8.1