Compare commits

...

45 Commits

Author SHA1 Message Date
Imran
b3de2e5d6b Merge pull request #1303 from ImranR98/dev
- Better partial APK hash as pseudo-version (related to #1101)
- Support Direct APK Links (#1292)
- Easier to understand version detection settings
- Bugfix in automatic source selection for URL input
- Various UI improvements and wording changes
- Add invert option to apk filter regex 
- Filter out fdroid APKs from default Obtainium entry (for later)
2024-01-19 23:41:27 -05:00
Imran Remtulla
0183070b2b Merge remote-tracking branch 'origin/main' into dev 2024-01-19 23:38:23 -05:00
Imran
089bbc3ee9 Merge pull request #1291 from Bardesss/patch-1
Update nl.json
2024-01-19 23:29:49 -05:00
Imran
b085801c2c Merge pull request #1298 from jont4/main
Translation: Some fixes and updates in pt.json
2024-01-19 23:29:40 -05:00
Imran Remtulla
ad4cae4288 Add F-Droid build to GitHub action 2024-01-19 23:29:22 -05:00
Imran Remtulla
95c285e1f7 Filter out fdroid APKs from default Obtainium entry 2024-01-19 23:25:00 -05:00
Imran Remtulla
c31a1912a5 Add invert option to apk filter regex 2024-01-19 23:22:00 -05:00
Imran Remtulla
99da1f8481 Upgrade packages, increment version 2024-01-19 20:41:07 -05:00
Imran Remtulla
bf6b3a7da0 UI bug 2024-01-19 20:36:40 -05:00
Imran Remtulla
4ab4f58f65 Cleaner 'add app' page 2024-01-19 20:35:44 -05:00
Imran Remtulla
29a76ac8e6 Removed unused divider and commented code on settings page 2024-01-19 19:59:30 -05:00
Imran Remtulla
e2761ce284 UI improvements on app page 2024-01-19 19:57:28 -05:00
Imran Remtulla
dc45334cb9 Support Direct APK Links (#1292) 2024-01-19 18:54:01 -05:00
Imran Remtulla
56052bfd79 Bugfix in version detection toggles 2024-01-19 00:43:02 -05:00
Imran Remtulla
f5067d636a More UI tweaks 2024-01-19 00:21:57 -05:00
Imran Remtulla
b173b1300a Clearer wording 2024-01-19 00:12:43 -05:00
Imran Remtulla
15a34e53bf Bugfix in automatic source selection for URL input 2024-01-19 00:00:47 -05:00
Imran Remtulla
183fb26988 Clearer version detection settings 2024-01-18 23:46:23 -05:00
Imran Remtulla
2da9a8cd59 Remove unnecessary print() 2024-01-18 20:45:34 -05:00
Imran Remtulla
bb07000280 Better partial APK hash as pseudo-version (related to #1101) 2024-01-18 20:45:06 -05:00
jont4
3a46ad2957 Some fixes and updates 2024-01-16 15:48:59 -03:00
Jonathan Soares
6b631d119c Merge branch 'ImranR98:main' into main 2024-01-16 15:24:02 -03:00
Bardesss
051762fcc1 Update nl.json
Added new strings.
2024-01-15 11:38:00 +00:00
Imran
595d5dc283 Merge pull request #1289 from ImranR98/dev
Added badge graphic (#1287)
2024-01-14 15:14:41 -05:00
Imran Remtulla
1d328f07e2 Merge remote-tracking branch 'origin/main' into dev 2024-01-14 15:14:01 -05:00
Imran Remtulla
b1c8ac6f2a Added badge graphic (#1287) 2024-01-14 15:09:16 -05:00
Imran
da619d37f7 Merge pull request #1288 from iDazai/main
Update de.json
2024-01-14 14:56:54 -05:00
iDazai
236c4722e5 Update de.json
added 2 missing strings, translated new strings
2024-01-14 15:36:08 +01:00
Imran Remtulla
92f59116a0 Merge remote-tracking branch 'origin/main' into dev 2024-01-14 01:37:17 -05:00
Imran Remtulla
c28040f0cb Merge remote-tracking branch 'origin/main' into dev 2024-01-14 01:36:43 -05:00
Imran
e8b9654320 Update release.yml 2024-01-14 01:36:35 -05:00
Imran
be1a793a37 Update release.yml 2024-01-14 01:34:32 -05:00
Imran
440720afb6 Update release.yml 2024-01-14 01:31:42 -05:00
Imran
900d3e734e Update release.yml 2024-01-14 01:27:13 -05:00
Imran
0bf096abb5 Temporary GitHub action change 2024-01-14 01:26:17 -05:00
Imran Remtulla
632efb9e22 Merge remote-tracking branch 'origin/main' into dev 2024-01-14 01:24:50 -05:00
Imran
bfc506e450 Merge pull request #1285 from ImranR98/dev
- Improve loading time (parallelize version detection)
- Newest asset upload date as release date for GitHub (#1284)
- Enable 'start on boot' for BG task (#1234)
- Remove the need to hardcode Obtainium's version number
2024-01-14 01:24:25 -05:00
Imran Remtulla
ffe612708c Remove the need to hardcode Obtainium's version number 2024-01-14 01:22:35 -05:00
Imran Remtulla
5d161160aa Increment version 2024-01-14 00:56:25 -05:00
Imran Remtulla
eadf3e5a29 Enable 'start on boot' for BG task (#1234) 2024-01-14 00:22:25 -05:00
Imran Remtulla
6b6b4084a0 Newest asset upload date as release date for GitHub (#1284) 2024-01-14 00:14:44 -05:00
Imran Remtulla
30a4633f72 Improve loading time (parallelize version detection) 2024-01-13 23:26:57 -05:00
Jonathan Soares
5b78de5d61 Merge branch 'ImranR98:main' into main 2024-01-12 05:46:33 -03:00
Jonathan Soares
f2ae078723 Merge branch 'ImranR98:main' into main 2024-01-08 18:20:27 -03:00
jont4
c3dacf2b9b Translation: tiny bug 2024-01-08 18:18:57 -03:00
46 changed files with 918 additions and 569 deletions

View File

@@ -2,6 +2,10 @@ name: Build and Release
on: on:
workflow_dispatch: workflow_dispatch:
inputs:
beta:
type: boolean
description: Is beta?
jobs: jobs:
build: build:
@@ -19,11 +23,23 @@ jobs:
gpg_private_key: ${{ secrets.PGP_KEY_BASE64 }} gpg_private_key: ${{ secrets.PGP_KEY_BASE64 }}
passphrase: ${{ secrets.PGP_PASSPHRASE }} passphrase: ${{ secrets.PGP_PASSPHRASE }}
- name: Extract Version
id: extract_version
run: |
VERSION=$(grep -oP "^version: [^\+]+" pubspec.yaml | tail -c +10)
echo "version=$VERSION" >> $GITHUB_OUTPUT
if [ ${{ inputs.beta }} == true ]; then BETA=true; else BETA=false; fi
echo "beta=$BETA" >> $GITHUB_OUTPUT
TAG="v$VERSION"
if [ $BETA == true ]; then TAG="$TAG"-beta; fi
echo "tag=$TAG" >> $GITHUB_OUTPUT
- name: Build APKs - name: Build APKs
run: | run: |
sed -i 's/signingConfig signingConfigs.release//g' android/app/build.gradle sed -i 's/signingConfig signingConfigs.release//g' android/app/build.gradle
flutter build apk --flavor normal && flutter build apk --split-per-abi --flavor normal flutter build apk --flavor normal && flutter build apk --split-per-abi --flavor normal
for file in build/app/outputs/flutter-apk/app-*normal*.apk*; do mv "$file" "${file//-normal/}"; done for file in build/app/outputs/flutter-apk/app-*normal*.apk*; do mv "$file" "${file//-normal/}"; done
flutter build apk --flavor fdroid -t lib/main_fdroid.dart && flutter build apk --split-per-abi --flavor fdroid -t lib/main_fdroid.dart
rm ./build/app/outputs/flutter-apk/*.sha1 rm ./build/app/outputs/flutter-apk/*.sha1
ls -l ./build/app/outputs/flutter-apk/ ls -l ./build/app/outputs/flutter-apk/
@@ -43,16 +59,6 @@ jobs:
done done
rm apksign.keystore rm apksign.keystore
PGP_KEY_FINGERPRINT="${{ steps.import_pgp_key.outputs.fingerprint }}" PGP_KEY_FINGERPRINT="${{ steps.import_pgp_key.outputs.fingerprint }}"
- name: Extract Version
id: extract_version
run: |
VERSION=$(grep -oP "currentVersion = '\K[^']+" lib/main.dart)
echo "version=$VERSION" >> $GITHUB_OUTPUT
TAG=$(grep -oP "'.*\\\$currentVersion.*'" lib/main.dart | head -c -2 | tail -c +2 | sed "s/\$currentVersion/$VERSION/g")
echo "tag=$TAG" >> $GITHUB_OUTPUT
if [ -n "$(echo $TAG | grep -oP '\-beta$')" ]; then BETA=true; else BETA=false; fi
echo "beta=$BETA" >> $GITHUB_OUTPUT
- name: Create Tag - name: Create Tag
uses: mathieudutour/github-tag-action@v6.1 uses: mathieudutour/github-tag-action@v6.1

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@@ -51,9 +51,8 @@
"percentProgress": "Napredak: {}%", "percentProgress": "Napredak: {}%",
"pleaseWait": "Molimo sačekajte", "pleaseWait": "Molimo sačekajte",
"updateAvailable": "Ažuriranje dostupno", "updateAvailable": "Ažuriranje dostupno",
"estimateInBracketsShort": "(Procjena)",
"notInstalled": "Nije instalirano", "notInstalled": "Nije instalirano",
"estimateInBrackets": "(Procjena)", "pseudoVersion": "pseudo-version",
"selectAll": "Označi sve", "selectAll": "Označi sve",
"deselectX": "Poništi odabir {}", "deselectX": "Poništi odabir {}",
"xWillBeRemovedButRemainInstalled": "{} će biti uklonjen iz Obtainiuma, ali će ostati instaliran na uređaju.", "xWillBeRemovedButRemainInstalled": "{} će biti uklonjen iz Obtainiuma, ali će ostati instaliran na uređaju.",
@@ -213,6 +212,7 @@
"changes": "Promjene", "changes": "Promjene",
"releaseDate": "Datum izdavanja", "releaseDate": "Datum izdavanja",
"importFromURLsInFile": "Uvoz iz URL-ova u datoteci (kao što je OPML)", "importFromURLsInFile": "Uvoz iz URL-ova u datoteci (kao što je OPML)",
"versionDetectionExplanation": "Reconcile version string with version detected from OS",
"versionDetection": "Otkrivanje verzije", "versionDetection": "Otkrivanje verzije",
"standardVersionDetection": "Detekcija standardne verzije", "standardVersionDetection": "Detekcija standardne verzije",
"groupByCategory": "Grupiši po kategoriji", "groupByCategory": "Grupiši po kategoriji",
@@ -291,6 +291,15 @@
"shizukuBinderNotFound": "Shizuku is not running", "shizukuBinderNotFound": "Shizuku is not running",
"useVersionCodeAsOSVersion": "Use app versionCode as OS-detected version", "useVersionCodeAsOSVersion": "Use app versionCode as OS-detected version",
"requestHeader": "Request header", "requestHeader": "Request header",
"useLatestAssetDateAsReleaseDate": "Use latest asset upload as release date",
"defaultPseudoVersioningMethod": "Default Pseudo-Versioning Method",
"partialAPKHash": "Partial APK Hash",
"APKLinkHash": "APK Link Hash",
"directAPKLink": "Direct APK Link",
"pseudoVersionInUse": "A Pseudo-Version is in Use",
"installed": "Installed",
"latest": "Latest",
"invertRegEx": "Invert regular expression",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Želite li ukloniti aplikaciju?", "one": "Želite li ukloniti aplikaciju?",
"other": "Želite li ukloniti aplikacije?" "other": "Želite li ukloniti aplikacije?"

View File

@@ -51,9 +51,8 @@
"percentProgress": "Pokrok: {}%", "percentProgress": "Pokrok: {}%",
"pleaseWait": "Počkejte prosím", "pleaseWait": "Počkejte prosím",
"updateAvailable": "Aktualizace je k dispozici", "updateAvailable": "Aktualizace je k dispozici",
"estimateInBracketsShort": "(approx.)",
"notInstalled": "Není nainstalováno", "notInstalled": "Není nainstalováno",
"estimateInBrackets": "(přibližně)", "pseudoVersion": "pseudo-version",
"selectAll": "Vybrat vše", "selectAll": "Vybrat vše",
"deselectX": "{} deselected", "deselectX": "{} deselected",
"xWillBeRemovedButRemainInstalled": "{} bude odstraněn z Obtainium, ale zůstane nainstalován v zařízení.", "xWillBeRemovedButRemainInstalled": "{} bude odstraněn z Obtainium, ale zůstane nainstalován v zařízení.",
@@ -213,6 +212,7 @@
"changes": "Změny", "changes": "Změny",
"releaseDate": "Datum vydání", "releaseDate": "Datum vydání",
"importFromURLsInFile": "Importovat adresy URL ze souboru (např. OPML)", "importFromURLsInFile": "Importovat adresy URL ze souboru (např. OPML)",
"versionDetectionExplanation": "Reconcile version string with version detected from OS",
"versionDetection": "Detekce verze", "versionDetection": "Detekce verze",
"standardVersionDetection": "Standardní detekce verze", "standardVersionDetection": "Standardní detekce verze",
"groupByCategory": "Seskupit podle kategorie", "groupByCategory": "Seskupit podle kategorie",
@@ -291,6 +291,15 @@
"shizukuBinderNotFound": "Shizuku neběží", "shizukuBinderNotFound": "Shizuku neběží",
"useVersionCodeAsOSVersion": "Use app versionCode as OS-detected version", "useVersionCodeAsOSVersion": "Use app versionCode as OS-detected version",
"requestHeader": "Request header", "requestHeader": "Request header",
"useLatestAssetDateAsReleaseDate": "Use latest asset upload as release date",
"defaultPseudoVersioningMethod": "Default Pseudo-Versioning Method",
"partialAPKHash": "Partial APK Hash",
"APKLinkHash": "APK Link Hash",
"directAPKLink": "Direct APK Link",
"pseudoVersionInUse": "A Pseudo-Version is in Use",
"installed": "Installed",
"latest": "Latest",
"invertRegEx": "Invert regular expression",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Odstranit Apku?", "one": "Odstranit Apku?",
"other": "Odstranit Apky?" "other": "Odstranit Apky?"

View File

@@ -51,9 +51,8 @@
"percentProgress": "Fortschritt: {}%", "percentProgress": "Fortschritt: {}%",
"pleaseWait": "Bitte warten", "pleaseWait": "Bitte warten",
"updateAvailable": "Aktualisierung verfügbar", "updateAvailable": "Aktualisierung verfügbar",
"estimateInBracketsShort": "(ca.)",
"notInstalled": "Nicht installiert", "notInstalled": "Nicht installiert",
"estimateInBrackets": "(Ungefähr)", "pseudoVersion": "pseudo-version",
"selectAll": "Alle auswählen", "selectAll": "Alle auswählen",
"deselectX": "{} abgewählt", "deselectX": "{} abgewählt",
"xWillBeRemovedButRemainInstalled": "{} wird aus Obtainium entfernt, bleibt aber auf dem Gerät installiert.", "xWillBeRemovedButRemainInstalled": "{} wird aus Obtainium entfernt, bleibt aber auf dem Gerät installiert.",
@@ -73,8 +72,8 @@
"unpinFromTop": "„Oben anheften“ aufheben", "unpinFromTop": "„Oben anheften“ aufheben",
"resetInstallStatusForSelectedAppsQuestion": "Installationsstatus für ausgewählte Apps zurücksetzen?", "resetInstallStatusForSelectedAppsQuestion": "Installationsstatus für ausgewählte Apps zurücksetzen?",
"installStatusOfXWillBeResetExplanation": "Der Installationsstatus der ausgewählten Apps wird zurückgesetzt. Dies kann hilfreich sein, wenn die in Obtainium angezeigte App-Version aufgrund fehlgeschlagener Aktualisierungen oder anderer Probleme falsch ist.", "installStatusOfXWillBeResetExplanation": "Der Installationsstatus der ausgewählten Apps wird zurückgesetzt. Dies kann hilfreich sein, wenn die in Obtainium angezeigte App-Version aufgrund fehlgeschlagener Aktualisierungen oder anderer Probleme falsch ist.",
"customLinkMessage": "These links work on devices with Obtainium installed", "customLinkMessage": "Diese Links funktionieren auf Geräten, wo Obtainium installiert ist",
"shareAppConfigLinks": "Share app configuration as HTML link", "shareAppConfigLinks": "Teile die Appkonfiguration als HTML-Link",
"shareSelectedAppURLs": "Ausgewählte App-URLs teilen", "shareSelectedAppURLs": "Ausgewählte App-URLs teilen",
"resetInstallStatus": "Installationsstatus zurücksetzen", "resetInstallStatus": "Installationsstatus zurücksetzen",
"more": "Mehr", "more": "Mehr",
@@ -213,6 +212,7 @@
"changes": "Änderungen", "changes": "Änderungen",
"releaseDate": "Veröffentlichungsdatum", "releaseDate": "Veröffentlichungsdatum",
"importFromURLsInFile": "Importieren von URLs aus Datei (z. B. OPML)", "importFromURLsInFile": "Importieren von URLs aus Datei (z. B. OPML)",
"versionDetectionExplanation": "Reconcile version string with version detected from OS",
"versionDetection": "Versionserkennung", "versionDetection": "Versionserkennung",
"standardVersionDetection": "Standardversionserkennung", "standardVersionDetection": "Standardversionserkennung",
"groupByCategory": "Nach Kategorie gruppieren", "groupByCategory": "Nach Kategorie gruppieren",
@@ -288,9 +288,20 @@
"normal": "Normal", "normal": "Normal",
"shizuku": "Shizuku", "shizuku": "Shizuku",
"root": "Root", "root": "Root",
"shizukuBinderNotFound": "Shizuku läuft nicht", "shizukuBinderNotFound": "Kompatibler Shizukudienst wurde nicht gefunden",
"useVersionCodeAsOSVersion": "Use app versionCode as OS-detected version", "useSystemFont": "Verwende die Systemschriftart",
"requestHeader": "Request header", "systemFontError": "Fehler beim Laden der Systemschriftart: {}",
"useVersionCodeAsOSVersion": "Verwende die Appversion als erkannte Version vom Betriebssystem",
"requestHeader": "Request Header",
"useLatestAssetDateAsReleaseDate": "Den letzten Asset-Upload als Veröffentlichungsdatum verwenden",
"defaultPseudoVersioningMethod": "Default Pseudo-Versioning Method",
"partialAPKHash": "Partial APK Hash",
"APKLinkHash": "APK Link Hash",
"directAPKLink": "Direct APK Link",
"pseudoVersionInUse": "A Pseudo-Version is in Use",
"installed": "Installed",
"latest": "Latest",
"invertRegEx": "Invert regular expression",
"removeAppQuestion": { "removeAppQuestion": {
"one": "App entfernen?", "one": "App entfernen?",
"other": "Apps entfernen?" "other": "Apps entfernen?"

View File

@@ -51,9 +51,8 @@
"percentProgress": "Progress: {}%", "percentProgress": "Progress: {}%",
"pleaseWait": "Please Wait", "pleaseWait": "Please Wait",
"updateAvailable": "Update Available", "updateAvailable": "Update Available",
"estimateInBracketsShort": "(Est.)",
"notInstalled": "Not Installed", "notInstalled": "Not Installed",
"estimateInBrackets": "(Estimate)", "pseudoVersion": "pseudo-version",
"selectAll": "Select All", "selectAll": "Select All",
"deselectX": "Deselect {}", "deselectX": "Deselect {}",
"xWillBeRemovedButRemainInstalled": "{} will be removed from Obtainium but remain installed on device.", "xWillBeRemovedButRemainInstalled": "{} will be removed from Obtainium but remain installed on device.",
@@ -166,8 +165,8 @@
"unknown": "Unknown", "unknown": "Unknown",
"none": "None", "none": "None",
"never": "Never", "never": "Never",
"latestVersionX": "Latest Version: {}", "latestVersionX": "Latest: {}",
"installedVersionX": "Installed Version: {}", "installedVersionX": "Installed: {}",
"lastUpdateCheckX": "Last Update Check: {}", "lastUpdateCheckX": "Last Update Check: {}",
"remove": "Remove", "remove": "Remove",
"yesMarkUpdated": "Yes, Mark as Updated", "yesMarkUpdated": "Yes, Mark as Updated",
@@ -208,11 +207,12 @@
"removeFromObtainium": "Remove from Obtainium", "removeFromObtainium": "Remove from Obtainium",
"uninstallFromDevice": "Uninstall from Device", "uninstallFromDevice": "Uninstall from Device",
"onlyWorksWithNonVersionDetectApps": "Only works for Apps with version detection disabled.", "onlyWorksWithNonVersionDetectApps": "Only works for Apps with version detection disabled.",
"releaseDateAsVersion": "Use Release Date as Version", "releaseDateAsVersion": "Use release date as version string",
"releaseDateAsVersionExplanation": "This option should only be used for Apps where version detection does not work correctly, but a release date is available.", "releaseDateAsVersionExplanation": "This option should only be used for Apps where version detection does not work correctly, but a release date is available.",
"changes": "Changes", "changes": "Changes",
"releaseDate": "Release Date", "releaseDate": "Release Date",
"importFromURLsInFile": "Import from URLs in File (like OPML)", "importFromURLsInFile": "Import from URLs in File (like OPML)",
"versionDetectionExplanation": "Reconcile version string with version detected from OS",
"versionDetection": "Version Detection", "versionDetection": "Version Detection",
"standardVersionDetection": "Standard version detection", "standardVersionDetection": "Standard version detection",
"groupByCategory": "Group by Category", "groupByCategory": "Group by Category",
@@ -254,8 +254,8 @@
"exemptFromBackgroundUpdates": "Exempt from background updates (if enabled)", "exemptFromBackgroundUpdates": "Exempt from background updates (if enabled)",
"bgUpdatesOnWiFiOnly": "Disable background updates when not on WiFi", "bgUpdatesOnWiFiOnly": "Disable background updates when not on WiFi",
"autoSelectHighestVersionCode": "Auto-select highest versionCode APK", "autoSelectHighestVersionCode": "Auto-select highest versionCode APK",
"versionExtractionRegEx": "Version Extraction RegEx", "versionExtractionRegEx": "Version String Extraction RegEx",
"matchGroupToUse": "Match Group to Use for Version Extraction Regex", "matchGroupToUse": "Match Group to Use for Version String Extraction Regex",
"highlightTouchTargets": "Highlight less obvious touch targets", "highlightTouchTargets": "Highlight less obvious touch targets",
"pickExportDir": "Pick Export Directory", "pickExportDir": "Pick Export Directory",
"autoExportOnChanges": "Auto-export on changes", "autoExportOnChanges": "Auto-export on changes",
@@ -269,7 +269,7 @@
"debugMenu": "Debug Menu", "debugMenu": "Debug Menu",
"bgTaskStarted": "Background task started - check logs.", "bgTaskStarted": "Background task started - check logs.",
"runBgCheckNow": "Run Background Update Check Now", "runBgCheckNow": "Run Background Update Check Now",
"versionExtractWholePage": "Apply Version Extraction Regex to Entire Page", "versionExtractWholePage": "Apply version string extraction Regex to entire page",
"installing": "Installing", "installing": "Installing",
"skipUpdateNotifications": "Skip update notifications", "skipUpdateNotifications": "Skip update notifications",
"updatesAvailableNotifChannel": "Updates Available", "updatesAvailableNotifChannel": "Updates Available",
@@ -293,6 +293,15 @@
"systemFontError": "Error loading the system font: {}", "systemFontError": "Error loading the system font: {}",
"useVersionCodeAsOSVersion": "Use app versionCode as OS-detected version", "useVersionCodeAsOSVersion": "Use app versionCode as OS-detected version",
"requestHeader": "Request header", "requestHeader": "Request header",
"useLatestAssetDateAsReleaseDate": "Use latest asset upload as release date",
"defaultPseudoVersioningMethod": "Default Pseudo-Versioning Method",
"partialAPKHash": "Partial APK Hash",
"APKLinkHash": "APK Link Hash",
"directAPKLink": "Direct APK Link",
"pseudoVersionInUse": "A Pseudo-Version is in Use",
"installed": "Installed",
"latest": "Latest",
"invertRegEx": "Invert regular expression",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Remove App?", "one": "Remove App?",
"other": "Remove Apps?" "other": "Remove Apps?"

View File

@@ -51,9 +51,8 @@
"percentProgress": "Progreso: {}%", "percentProgress": "Progreso: {}%",
"pleaseWait": "Por favor, espere", "pleaseWait": "Por favor, espere",
"updateAvailable": "Actualización Disponible", "updateAvailable": "Actualización Disponible",
"estimateInBracketsShort": "(Aprox.)",
"notInstalled": "No Instalado", "notInstalled": "No Instalado",
"estimateInBrackets": "(Aproximado)", "pseudoVersion": "pseudo-version",
"selectAll": "Seleccionar Todo", "selectAll": "Seleccionar Todo",
"deselectX": "Deseleccionar {}", "deselectX": "Deseleccionar {}",
"xWillBeRemovedButRemainInstalled": "{} será eliminada de Obtainium pero continuará instalada en el dispositivo.", "xWillBeRemovedButRemainInstalled": "{} será eliminada de Obtainium pero continuará instalada en el dispositivo.",
@@ -213,6 +212,7 @@
"changes": "Cambios", "changes": "Cambios",
"releaseDate": "Fecha de Publicación", "releaseDate": "Fecha de Publicación",
"importFromURLsInFile": "Importar URLs desde archivo (como OPML)", "importFromURLsInFile": "Importar URLs desde archivo (como OPML)",
"versionDetectionExplanation": "Reconcile version string with version detected from OS",
"versionDetection": "Detección de Versiones", "versionDetection": "Detección de Versiones",
"standardVersionDetection": "Por versión", "standardVersionDetection": "Por versión",
"groupByCategory": "Agrupar por categoría", "groupByCategory": "Agrupar por categoría",
@@ -291,6 +291,15 @@
"shizukuBinderNotFound": "Shizuku no está operativo", "shizukuBinderNotFound": "Shizuku no está operativo",
"useVersionCodeAsOSVersion": "Use app versionCode as OS-detected version", "useVersionCodeAsOSVersion": "Use app versionCode as OS-detected version",
"requestHeader": "Request header", "requestHeader": "Request header",
"useLatestAssetDateAsReleaseDate": "Use latest asset upload as release date",
"defaultPseudoVersioningMethod": "Default Pseudo-Versioning Method",
"partialAPKHash": "Partial APK Hash",
"APKLinkHash": "APK Link Hash",
"directAPKLink": "Direct APK Link",
"pseudoVersionInUse": "A Pseudo-Version is in Use",
"installed": "Installed",
"latest": "Latest",
"invertRegEx": "Invert regular expression",
"removeAppQuestion": { "removeAppQuestion": {
"one": "¿Eliminar Aplicación?", "one": "¿Eliminar Aplicación?",
"other": "¿Eliminar Aplicaciones?" "other": "¿Eliminar Aplicaciones?"

View File

@@ -51,9 +51,8 @@
"percentProgress": "پیش رفتن: {}%", "percentProgress": "پیش رفتن: {}%",
"pleaseWait": "لطفا صبر کنید", "pleaseWait": "لطفا صبر کنید",
"updateAvailable": "بروزرسانی در دسترس", "updateAvailable": "بروزرسانی در دسترس",
"estimateInBracketsShort": "(تخمین)",
"notInstalled": "نصب نشده", "notInstalled": "نصب نشده",
"estimateInBrackets": "(تخمین زدن)", "pseudoVersion": "pseudo-version",
"selectAll": "انتخاب همه", "selectAll": "انتخاب همه",
"deselectX": "لغو انتخاب {}", "deselectX": "لغو انتخاب {}",
"xWillBeRemovedButRemainInstalled": "{} از Obtainium حذف می‌شود اما روی دستگاه نصب می‌ماند.", "xWillBeRemovedButRemainInstalled": "{} از Obtainium حذف می‌شود اما روی دستگاه نصب می‌ماند.",
@@ -213,6 +212,7 @@
"changes": "تغییرات", "changes": "تغییرات",
"releaseDate": "تاریخ انتشار", "releaseDate": "تاریخ انتشار",
"importFromURLsInFile": "درون ریزی از آدرس های اینترنتی موجود در فایل (مانند OPML)", "importFromURLsInFile": "درون ریزی از آدرس های اینترنتی موجود در فایل (مانند OPML)",
"versionDetectionExplanation": "Reconcile version string with version detected from OS",
"versionDetection": "تشخیص نسخه", "versionDetection": "تشخیص نسخه",
"standardVersionDetection": "تشخیص نسخه استاندارد", "standardVersionDetection": "تشخیص نسخه استاندارد",
"groupByCategory": "گروه بر اساس دسته", "groupByCategory": "گروه بر اساس دسته",
@@ -291,6 +291,15 @@
"shizukuBinderNotFound": "Shizuku در حال اجرا نیست", "shizukuBinderNotFound": "Shizuku در حال اجرا نیست",
"useVersionCodeAsOSVersion": "استفاده کد نسخه برنامه به جای نسخه شناسایی شده توسط سیستم عامل استفاده کنید", "useVersionCodeAsOSVersion": "استفاده کد نسخه برنامه به جای نسخه شناسایی شده توسط سیستم عامل استفاده کنید",
"requestHeader": "درخواست سطر بالایی", "requestHeader": "درخواست سطر بالایی",
"useLatestAssetDateAsReleaseDate": "Use latest asset upload as release date",
"defaultPseudoVersioningMethod": "Default Pseudo-Versioning Method",
"partialAPKHash": "Partial APK Hash",
"APKLinkHash": "APK Link Hash",
"directAPKLink": "Direct APK Link",
"pseudoVersionInUse": "A Pseudo-Version is in Use",
"installed": "Installed",
"latest": "Latest",
"invertRegEx": "Invert regular expression",
"removeAppQuestion": { "removeAppQuestion": {
"one": "برنامه حذف شود؟", "one": "برنامه حذف شود؟",
"other": "برنامه ها حذف شوند؟" "other": "برنامه ها حذف شوند؟"

View File

@@ -51,9 +51,8 @@
"percentProgress": "Progrès: {}%", "percentProgress": "Progrès: {}%",
"pleaseWait": "Veuillez patienter", "pleaseWait": "Veuillez patienter",
"updateAvailable": "Mise à jour disponible", "updateAvailable": "Mise à jour disponible",
"estimateInBracketsShort": "(Est.)",
"notInstalled": "Pas installé", "notInstalled": "Pas installé",
"estimateInBrackets": "(Estimation)", "pseudoVersion": "pseudo-version",
"selectAll": "Tout sélectionner", "selectAll": "Tout sélectionner",
"deselectX": "Déselectionner {}", "deselectX": "Déselectionner {}",
"xWillBeRemovedButRemainInstalled": "{} sera supprimé d'Obtainium mais restera installé sur l'appareil.", "xWillBeRemovedButRemainInstalled": "{} sera supprimé d'Obtainium mais restera installé sur l'appareil.",
@@ -213,6 +212,7 @@
"changes": "Changements", "changes": "Changements",
"releaseDate": "Date de sortie", "releaseDate": "Date de sortie",
"importFromURLsInFile": "Importer à partir d'URL dans un fichier (comme OPML)", "importFromURLsInFile": "Importer à partir d'URL dans un fichier (comme OPML)",
"versionDetectionExplanation": "Reconcile version string with version detected from OS",
"versionDetection": "Détection des versions", "versionDetection": "Détection des versions",
"standardVersionDetection": "Détection de version standard", "standardVersionDetection": "Détection de version standard",
"groupByCategory": "Group by Category", "groupByCategory": "Group by Category",
@@ -291,6 +291,15 @@
"shizukuBinderNotFound": "Shizuku is not running", "shizukuBinderNotFound": "Shizuku is not running",
"useVersionCodeAsOSVersion": "Use app versionCode as OS-detected version", "useVersionCodeAsOSVersion": "Use app versionCode as OS-detected version",
"requestHeader": "Request header", "requestHeader": "Request header",
"useLatestAssetDateAsReleaseDate": "Use latest asset upload as release date",
"defaultPseudoVersioningMethod": "Default Pseudo-Versioning Method",
"partialAPKHash": "Partial APK Hash",
"APKLinkHash": "APK Link Hash",
"directAPKLink": "Direct APK Link",
"pseudoVersionInUse": "A Pseudo-Version is in Use",
"installed": "Installed",
"latest": "Latest",
"invertRegEx": "Invert regular expression",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Supprimer l'application ?", "one": "Supprimer l'application ?",
"other": "Supprimer les applications ?" "other": "Supprimer les applications ?"

View File

@@ -51,9 +51,8 @@
"percentProgress": "Folyamat: {}%", "percentProgress": "Folyamat: {}%",
"pleaseWait": "Kis türelmet", "pleaseWait": "Kis türelmet",
"updateAvailable": "Frissítés érhető el", "updateAvailable": "Frissítés érhető el",
"estimateInBracketsShort": "(Becsült)",
"notInstalled": "Nem telepített", "notInstalled": "Nem telepített",
"estimateInBrackets": "(Becslés)", "pseudoVersion": "pseudo-version",
"selectAll": "Mindet kiválaszt", "selectAll": "Mindet kiválaszt",
"deselectX": "Törölje {} kijelölését", "deselectX": "Törölje {} kijelölését",
"xWillBeRemovedButRemainInstalled": "A(z) {} el lesz távolítva az Obtainiumból, de továbbra is telepítve marad az eszközön.", "xWillBeRemovedButRemainInstalled": "A(z) {} el lesz távolítva az Obtainiumból, de továbbra is telepítve marad az eszközön.",
@@ -213,6 +212,7 @@
"changes": "Változtatások", "changes": "Változtatások",
"releaseDate": "Kiadás dátuma", "releaseDate": "Kiadás dátuma",
"importFromURLsInFile": "Importálás fájlban található URL-ből (mint pl. OPML)", "importFromURLsInFile": "Importálás fájlban található URL-ből (mint pl. OPML)",
"versionDetectionExplanation": "Reconcile version string with version detected from OS",
"versionDetection": "Verzió érzékelés", "versionDetection": "Verzió érzékelés",
"standardVersionDetection": "Alapért. verzió érzékelés", "standardVersionDetection": "Alapért. verzió érzékelés",
"groupByCategory": "Csoportosítás Kategória alapján", "groupByCategory": "Csoportosítás Kategória alapján",
@@ -291,6 +291,15 @@
"shizukuBinderNotFound": "A Shizuku nem fut", "shizukuBinderNotFound": "A Shizuku nem fut",
"useVersionCodeAsOSVersion": "Az app versionCode használata a rendszer által észlelt verzióként", "useVersionCodeAsOSVersion": "Az app versionCode használata a rendszer által észlelt verzióként",
"requestHeader": "Kérelem fejléc", "requestHeader": "Kérelem fejléc",
"useLatestAssetDateAsReleaseDate": "Use latest asset upload as release date",
"defaultPseudoVersioningMethod": "Default Pseudo-Versioning Method",
"partialAPKHash": "Partial APK Hash",
"APKLinkHash": "APK Link Hash",
"directAPKLink": "Direct APK Link",
"pseudoVersionInUse": "A Pseudo-Version is in Use",
"installed": "Installed",
"latest": "Latest",
"invertRegEx": "Invert regular expression",
"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?"

View File

@@ -51,9 +51,8 @@
"percentProgress": "Avanzamento: {}%", "percentProgress": "Avanzamento: {}%",
"pleaseWait": "In attesa", "pleaseWait": "In attesa",
"updateAvailable": "Aggiornamento disponibile", "updateAvailable": "Aggiornamento disponibile",
"estimateInBracketsShort": "(stim.)",
"notInstalled": "Non installato", "notInstalled": "Non installato",
"estimateInBrackets": "(stimato)", "pseudoVersion": "pseudo-version",
"selectAll": "Seleziona tutto", "selectAll": "Seleziona tutto",
"deselectX": "Deseleziona {}", "deselectX": "Deseleziona {}",
"xWillBeRemovedButRemainInstalled": "Verà effettuata la rimozione di {}, ma non la disinstallazione.", "xWillBeRemovedButRemainInstalled": "Verà effettuata la rimozione di {}, ma non la disinstallazione.",
@@ -213,6 +212,7 @@
"changes": "Novità", "changes": "Novità",
"releaseDate": "Data di rilascio", "releaseDate": "Data di rilascio",
"importFromURLsInFile": "Importa da URL in file (come OPML)", "importFromURLsInFile": "Importa da URL in file (come OPML)",
"versionDetectionExplanation": "Reconcile version string with version detected from OS",
"versionDetection": "Rilevamento di versione", "versionDetection": "Rilevamento di versione",
"standardVersionDetection": "Rilevamento di versione standard", "standardVersionDetection": "Rilevamento di versione standard",
"groupByCategory": "Raggruppa per categoria", "groupByCategory": "Raggruppa per categoria",
@@ -291,6 +291,15 @@
"shizukuBinderNotFound": "Shizuku non è in esecuzione", "shizukuBinderNotFound": "Shizuku non è in esecuzione",
"useVersionCodeAsOSVersion": "Use app versionCode as OS-detected version", "useVersionCodeAsOSVersion": "Use app versionCode as OS-detected version",
"requestHeader": "Request header", "requestHeader": "Request header",
"useLatestAssetDateAsReleaseDate": "Use latest asset upload as release date",
"defaultPseudoVersioningMethod": "Default Pseudo-Versioning Method",
"partialAPKHash": "Partial APK Hash",
"APKLinkHash": "APK Link Hash",
"directAPKLink": "Direct APK Link",
"pseudoVersionInUse": "A Pseudo-Version is in Use",
"installed": "Installed",
"latest": "Latest",
"invertRegEx": "Invert regular expression",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Rimuovere l'app?", "one": "Rimuovere l'app?",
"other": "Rimuovere le app?" "other": "Rimuovere le app?"

View File

@@ -51,9 +51,8 @@
"percentProgress": "ダウンロード中: {}%", "percentProgress": "ダウンロード中: {}%",
"pleaseWait": "しばらくお待ちください", "pleaseWait": "しばらくお待ちください",
"updateAvailable": "アップデートが利用可能", "updateAvailable": "アップデートが利用可能",
"estimateInBracketsShort": "(推定)",
"notInstalled": "未インストール", "notInstalled": "未インストール",
"estimateInBrackets": "(推定)", "pseudoVersion": "pseudo-version",
"selectAll": "すべて選択", "selectAll": "すべて選択",
"deselectX": "{}件の選択を解除", "deselectX": "{}件の選択を解除",
"xWillBeRemovedButRemainInstalled": "{} はObtainiumから削除されますが、デバイスにはインストールされたままです。", "xWillBeRemovedButRemainInstalled": "{} はObtainiumから削除されますが、デバイスにはインストールされたままです。",
@@ -213,6 +212,7 @@
"changes": "変更点", "changes": "変更点",
"releaseDate": "リリース日", "releaseDate": "リリース日",
"importFromURLsInFile": "ファイルOPMLなど内のURLからインポート", "importFromURLsInFile": "ファイルOPMLなど内のURLからインポート",
"versionDetectionExplanation": "Reconcile version string with version detected from OS",
"versionDetection": "バージョン検出", "versionDetection": "バージョン検出",
"standardVersionDetection": "標準のバージョン検出", "standardVersionDetection": "標準のバージョン検出",
"groupByCategory": "カテゴリ別にグループ化する", "groupByCategory": "カテゴリ別にグループ化する",
@@ -293,6 +293,15 @@
"systemFontError": "システムフォントの読み込みエラー: {}", "systemFontError": "システムフォントの読み込みエラー: {}",
"useVersionCodeAsOSVersion": "Use app versionCode as OS-detected version", "useVersionCodeAsOSVersion": "Use app versionCode as OS-detected version",
"requestHeader": "Request header", "requestHeader": "Request header",
"useLatestAssetDateAsReleaseDate": "Use latest asset upload as release date",
"defaultPseudoVersioningMethod": "Default Pseudo-Versioning Method",
"partialAPKHash": "Partial APK Hash",
"APKLinkHash": "APK Link Hash",
"directAPKLink": "Direct APK Link",
"pseudoVersionInUse": "A Pseudo-Version is in Use",
"installed": "Installed",
"latest": "Latest",
"invertRegEx": "Invert regular expression",
"removeAppQuestion": { "removeAppQuestion": {
"one": "アプリを削除しますか?", "one": "アプリを削除しますか?",
"other": "アプリを削除しますか?" "other": "アプリを削除しますか?"

View File

@@ -51,9 +51,8 @@
"percentProgress": "Vooruitgang: {}%", "percentProgress": "Vooruitgang: {}%",
"pleaseWait": "Even geduld", "pleaseWait": "Even geduld",
"updateAvailable": "Update beschikbaar", "updateAvailable": "Update beschikbaar",
"estimateInBracketsShort": "(Ong.)",
"notInstalled": "Niet geinstalleerd", "notInstalled": "Niet geinstalleerd",
"estimateInBrackets": "(Ongeveer)", "pseudoVersion": "pseudo-version",
"selectAll": "Selecteer alles", "selectAll": "Selecteer alles",
"deselectX": "Deselecteer {}", "deselectX": "Deselecteer {}",
"xWillBeRemovedButRemainInstalled": "{} zal worden verwijderd uit Obtainium, maar blijft geïnstalleerd op het apparaat.", "xWillBeRemovedButRemainInstalled": "{} zal worden verwijderd uit Obtainium, maar blijft geïnstalleerd op het apparaat.",
@@ -73,8 +72,8 @@
"unpinFromTop": "Losmaken van de bovenkant", "unpinFromTop": "Losmaken van de bovenkant",
"resetInstallStatusForSelectedAppsQuestion": "Installatiestatus resetten voor geselecteerde apps?", "resetInstallStatusForSelectedAppsQuestion": "Installatiestatus resetten voor geselecteerde apps?",
"installStatusOfXWillBeResetExplanation": "De installatiestatus van alle geselecteerde apps zal worden gereset.\n\nDit kan helpen wanneer de versie van de app die in Obtainium wordt weergegeven onjuist is vanwege mislukte updates of andere problemen.", "installStatusOfXWillBeResetExplanation": "De installatiestatus van alle geselecteerde apps zal worden gereset.\n\nDit kan helpen wanneer de versie van de app die in Obtainium wordt weergegeven onjuist is vanwege mislukte updates of andere problemen.",
"customLinkMessage": "These links work on devices with Obtainium installed", "customLinkMessage": "Deze links werken op apparaten waarop Obtainium is geïnstalleerd",
"shareAppConfigLinks": "Share app configuration as HTML link", "shareAppConfigLinks": "App-configuratie delen als HTML-link",
"shareSelectedAppURLs": "Deel geselecteerde app URL's", "shareSelectedAppURLs": "Deel geselecteerde app URL's",
"resetInstallStatus": "Reset installatiestatus", "resetInstallStatus": "Reset installatiestatus",
"more": "Meer", "more": "Meer",
@@ -213,12 +212,13 @@
"changes": "Veranderingen", "changes": "Veranderingen",
"releaseDate": "Releasedatum", "releaseDate": "Releasedatum",
"importFromURLsInFile": "Importeren vanaf URL's in een bestand (zoals OPML)", "importFromURLsInFile": "Importeren vanaf URL's in een bestand (zoals OPML)",
"versionDetectionExplanation": "Reconcile version string with version detected from OS",
"versionDetection": "Versieherkenning", "versionDetection": "Versieherkenning",
"standardVersionDetection": "Standaard versieherkenning", "standardVersionDetection": "Standaard versieherkenning",
"groupByCategory": "Groepeer op categorie", "groupByCategory": "Groepeer op categorie",
"autoApkFilterByArch": "Poging om APK's te filteren op CPU-architectuur indien mogelijk", "autoApkFilterByArch": "Poging om APK's te filteren op CPU-architectuur indien mogelijk",
"overrideSource": "Bron overschrijven", "overrideSource": "Bron overschrijven",
"dontShowAgain": "Don't show this again", "dontShowAgain": "Laat dit niet meer zien",
"dontShowTrackOnlyWarnings": "Geen waarschuwingen voor 'Track-Only' weergeven", "dontShowTrackOnlyWarnings": "Geen waarschuwingen voor 'Track-Only' weergeven",
"dontShowAPKOriginWarnings": "APK-herkomstwaarschuwingen niet weergeven", "dontShowAPKOriginWarnings": "APK-herkomstwaarschuwingen niet weergeven",
"moveNonInstalledAppsToBottom": "Verplaats niet-geïnstalleerde apps naar de onderkant van de apps-weergave", "moveNonInstalledAppsToBottom": "Verplaats niet-geïnstalleerde apps naar de onderkant van de apps-weergave",
@@ -237,7 +237,7 @@
"addInfoInSettings": "Voeg deze informatie toe in de instellingen.", "addInfoInSettings": "Voeg deze informatie toe in de instellingen.",
"githubSourceNote": "Beperkingen van GitHub kunnen worden vermeden door het gebruik van een API-sleutel.", "githubSourceNote": "Beperkingen van GitHub kunnen worden vermeden door het gebruik van een API-sleutel.",
"gitlabSourceNote": "GitLab APK-extractie werkt mogelijk niet zonder een API-sleutel.", "gitlabSourceNote": "GitLab APK-extractie werkt mogelijk niet zonder een API-sleutel.",
"sortByLastLinkSegment": "Sort by only the last segment of the link", "sortByLastLinkSegment": "Sorteren op alleen het laatste segment van de link",
"filterReleaseNotesByRegEx": "Filter release-opmerkingen met een reguliere expressie.", "filterReleaseNotesByRegEx": "Filter release-opmerkingen met een reguliere expressie.",
"customLinkFilterRegex": "Aangepaste APK-linkfilter met een reguliere expressie (Standaard '.apk$').", "customLinkFilterRegex": "Aangepaste APK-linkfilter met een reguliere expressie (Standaard '.apk$').",
"appsPossiblyUpdated": "Poging tot app-updates", "appsPossiblyUpdated": "Poging tot app-updates",
@@ -247,10 +247,10 @@
"backgroundUpdateReqsExplanation": "Achtergrondupdates zijn mogelijk niet voor alle apps mogelijk.", "backgroundUpdateReqsExplanation": "Achtergrondupdates zijn mogelijk niet voor alle apps mogelijk.",
"backgroundUpdateLimitsExplanation": "Het succes van een installatie in de achtergrond kan alleen worden bepaald wanneer Obtainium is geopend.", "backgroundUpdateLimitsExplanation": "Het succes van een installatie in de achtergrond kan alleen worden bepaald wanneer Obtainium is geopend.",
"verifyLatestTag": "Verifieer de 'Laatste'-tag", "verifyLatestTag": "Verifieer de 'Laatste'-tag",
"intermediateLinkRegex": "Filter for an 'Intermediate' Link to Visit", "intermediateLinkRegex": "Filter voor een 'Intermediaire' link om te bezoeken",
"filterByLinkText": "Filter links by link text", "filterByLinkText": "Links filteren op linktekst",
"intermediateLinkNotFound": "Tussenliggende link niet gevonden", "intermediateLinkNotFound": "Tussenliggende link niet gevonden",
"intermediateLink": "Intermediate link", "intermediateLink": "Intermediaire link",
"exemptFromBackgroundUpdates": "Vrijgesteld van achtergrondupdates (indien ingeschakeld)", "exemptFromBackgroundUpdates": "Vrijgesteld van achtergrondupdates (indien ingeschakeld)",
"bgUpdatesOnWiFiOnly": "Achtergrondupdates uitschakelen wanneer niet verbonden met WiFi", "bgUpdatesOnWiFiOnly": "Achtergrondupdates uitschakelen wanneer niet verbonden met WiFi",
"autoSelectHighestVersionCode": "Automatisch de APK met de hoogste versiecode selecteren", "autoSelectHighestVersionCode": "Automatisch de APK met de hoogste versiecode selecteren",
@@ -259,13 +259,13 @@
"highlightTouchTargets": "Markeer minder voor de hand liggende aanraakdoelen.", "highlightTouchTargets": "Markeer minder voor de hand liggende aanraakdoelen.",
"pickExportDir": "Kies de exportmap", "pickExportDir": "Kies de exportmap",
"autoExportOnChanges": "Automatisch exporteren bij wijzigingen", "autoExportOnChanges": "Automatisch exporteren bij wijzigingen",
"includeSettings": "Include settings", "includeSettings": "Instellingen opnemen",
"filterVersionsByRegEx": "Filter versies met een reguliere expressie", "filterVersionsByRegEx": "Filter versies met een reguliere expressie",
"trySelectingSuggestedVersionCode": "Probeer de voorgestelde versiecode APK te selecteren", "trySelectingSuggestedVersionCode": "Probeer de voorgestelde versiecode APK te selecteren",
"dontSortReleasesList": "Volgorde van releases behouden vanuit de API", "dontSortReleasesList": "Volgorde van releases behouden vanuit de API",
"reverseSort": "Sortering omkeren", "reverseSort": "Sortering omkeren",
"takeFirstLink": "Take first link", "takeFirstLink": "Neem de eerste link",
"skipSort": "Skip sorting", "skipSort": "Sorteren overslaan",
"debugMenu": "Debug menu", "debugMenu": "Debug menu",
"bgTaskStarted": "Achtergrondtaak gestart - controleer de logs.", "bgTaskStarted": "Achtergrondtaak gestart - controleer de logs.",
"runBgCheckNow": "Voer nu een achtergrondupdatecontrole uit", "runBgCheckNow": "Voer nu een achtergrondupdatecontrole uit",
@@ -281,16 +281,25 @@
"completeAppInstallationNotifChannel": "Voltooien van de app-installatie", "completeAppInstallationNotifChannel": "Voltooien van de app-installatie",
"checkingForUpdatesNotifChannel": "Controleren op updates", "checkingForUpdatesNotifChannel": "Controleren op updates",
"onlyCheckInstalledOrTrackOnlyApps": "Alleen geïnstalleerde en Track-Only apps controleren op updates", "onlyCheckInstalledOrTrackOnlyApps": "Alleen geïnstalleerde en Track-Only apps controleren op updates",
"supportFixedAPKURL": "Support fixed APK URLs", "supportFixedAPKURL": "Ondersteuning vaste APK URL's",
"selectX": "Select {}", "selectX": "Selecteer {}",
"parallelDownloads": "Allow parallel downloads", "parallelDownloads": "Parallelle downloads toestaan",
"installMethod": "Installation method", "installMethod": "Installatiemethode",
"normal": "Normal", "normal": "Normaal",
"shizuku": "Shizuku", "shizuku": "Shizuku",
"root": "Root", "root": "Root",
"shizukuBinderNotFound": "Shizuku is not running", "shizukuBinderNotFound": "Shizuku draait niet",
"useVersionCodeAsOSVersion": "Use app versionCode as OS-detected version", "useVersionCodeAsOSVersion": "Gebruik app versieCode als door OS gedetecteerde versie",
"requestHeader": "Request header", "requestHeader": "Request header",
"useLatestAssetDateAsReleaseDate": "Gebruik laatste upload als releasedatum",
"defaultPseudoVersioningMethod": "Default Pseudo-Versioning Method",
"partialAPKHash": "Partial APK Hash",
"APKLinkHash": "APK Link Hash",
"directAPKLink": "Direct APK Link",
"pseudoVersionInUse": "A Pseudo-Version is in Use",
"installed": "Installed",
"latest": "Latest",
"invertRegEx": "Invert regular expression",
"removeAppQuestion": { "removeAppQuestion": {
"one": "App verwijderen?", "one": "App verwijderen?",
"other": "Apps verwijderen?" "other": "Apps verwijderen?"
@@ -343,4 +352,4 @@
"one": "{} en nog 1 app zijn mogelijk bijgewerkt.", "one": "{} en nog 1 app zijn mogelijk bijgewerkt.",
"other": "{} en {} meer apps zijn mogelijk bijgwerkt." "other": "{} en {} meer apps zijn mogelijk bijgwerkt."
} }
} }

View File

@@ -51,9 +51,8 @@
"percentProgress": "Postęp: {}%", "percentProgress": "Postęp: {}%",
"pleaseWait": "Proszę czekać", "pleaseWait": "Proszę czekać",
"updateAvailable": "Dostępna aktualizacja", "updateAvailable": "Dostępna aktualizacja",
"estimateInBracketsShort": "(Szac.)",
"notInstalled": "Nie zainstalowano", "notInstalled": "Nie zainstalowano",
"estimateInBrackets": "(Szacunkowo)", "pseudoVersion": "pseudo-version",
"selectAll": "Zaznacz wszystkie", "selectAll": "Zaznacz wszystkie",
"deselectX": "Odznacz {}", "deselectX": "Odznacz {}",
"xWillBeRemovedButRemainInstalled": "{} zostanie usunięty z Obtainium, ale pozostanie zainstalowany na urządzeniu.", "xWillBeRemovedButRemainInstalled": "{} zostanie usunięty z Obtainium, ale pozostanie zainstalowany na urządzeniu.",
@@ -213,6 +212,7 @@
"changes": "Zmiany", "changes": "Zmiany",
"releaseDate": "Data wydania", "releaseDate": "Data wydania",
"importFromURLsInFile": "Importuj z adresów URL w pliku (typu OPML)", "importFromURLsInFile": "Importuj z adresów URL w pliku (typu OPML)",
"versionDetectionExplanation": "Reconcile version string with version detected from OS",
"versionDetection": "Wykrywanie wersji", "versionDetection": "Wykrywanie wersji",
"standardVersionDetection": "Standardowe wykrywanie wersji", "standardVersionDetection": "Standardowe wykrywanie wersji",
"groupByCategory": "Grupuj według kategorii", "groupByCategory": "Grupuj według kategorii",
@@ -291,6 +291,15 @@
"shizukuBinderNotFound": "Shizuku is not running", "shizukuBinderNotFound": "Shizuku is not running",
"useVersionCodeAsOSVersion": "Use app versionCode as OS-detected version", "useVersionCodeAsOSVersion": "Use app versionCode as OS-detected version",
"requestHeader": "Request header", "requestHeader": "Request header",
"useLatestAssetDateAsReleaseDate": "Use latest asset upload as release date",
"defaultPseudoVersioningMethod": "Default Pseudo-Versioning Method",
"partialAPKHash": "Partial APK Hash",
"APKLinkHash": "APK Link Hash",
"directAPKLink": "Direct APK Link",
"pseudoVersionInUse": "A Pseudo-Version is in Use",
"installed": "Installed",
"latest": "Latest",
"invertRegEx": "Invert regular expression",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Usunąć aplikację?", "one": "Usunąć aplikację?",
"few": "Usunąć aplikacje?", "few": "Usunąć aplikacje?",

View File

@@ -54,6 +54,7 @@
"estimateInBracketsShort": "(Aprox.)", "estimateInBracketsShort": "(Aprox.)",
"notInstalled": "Não instalado", "notInstalled": "Não instalado",
"estimateInBrackets": "(Aproximado)", "estimateInBrackets": "(Aproximado)",
"pseudoVersion": "pseudo-version",
"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.",
@@ -213,7 +214,7 @@
"changes": "Mudanças", "changes": "Mudanças",
"releaseDate": "Data de lançamento", "releaseDate": "Data de lançamento",
"importFromURLsInFile": "Importar de URLs em arquivo (como OPML)", "importFromURLsInFile": "Importar de URLs em arquivo (como OPML)",
"versionDetection": "Detecção de Versão", "versionDetection": "Detecção de versão",
"standardVersionDetection": "Detecção de versão padrão", "standardVersionDetection": "Detecção de versão padrão",
"groupByCategory": "Agroupar por categoria", "groupByCategory": "Agroupar por categoria",
"autoApkFilterByArch": "Tente filtrar APKs por arquitetura de CPU, se possível", "autoApkFilterByArch": "Tente filtrar APKs por arquitetura de CPU, se possível",
@@ -222,81 +223,91 @@
"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 aplicativos não instalados para o fundo da lista de aplicativos",
"gitlabPATLabel": "Token de Acceso Pessoal do Gitlab\n(Ativa Pesquisa e Melhor Descoberta de APKs)", "gitlabPATLabel": "Token de Acesso Pessoal do Gitlab\n(Ativa pesquisa e melhora a descoberta de APKs)",
"about": "Sobre", "about": "Sobre",
"requiresCredentialsInSettings": "{}: Isso requer credenciais adicionais (em Configurações)", "requiresCredentialsInSettings": "{}: Isso requer credenciais adicionais (em Configurações)",
"checkOnStart": "Checar por atualizações ao iniciar ", "checkOnStart": "Verificar se há atualizações ao iniciar",
"tryInferAppIdFromCode": "Tente inferir o ID do aplicativo pelo código-fonte", "tryInferAppIdFromCode": "Tente inferir o ID do aplicativo pelo código-fonte",
"removeOnExternalUninstall": "Remover automaticamente aplicativos desinstalados externamente", "removeOnExternalUninstall": "Remover automaticamente aplicativos desinstalados externamente",
"pickHighestVersionCode": "Auto-selecionar o maior numero 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 um aplicativo",
"disablePageTransitions": "Desativar animações de transição de pagina", "disablePageTransitions": "Desativar animações de transição de página",
"reversePageTransitions": "Reverter animações de transição de pagina", "reversePageTransitions": "Reverter animações de transição de página",
"minStarCount": "Contagem Minima de Estrelas", "minStarCount": "Contagem nima de estrelas",
"addInfoBelow": "Adicionar essa informação abaixo.", "addInfoBelow": "Adicionar essa informação abaixo.",
"addInfoInSettings": "Adicionar essa informação nas configurações.", "addInfoInSettings": "Adicionar essa informação nas configurações.",
"githubSourceNote": "A limitação de taxa do GitHub pode ser evitada usando uma chave de API.", "githubSourceNote": "A limitação de taxa do GitHub pode ser evitada usando uma chave de API.",
"gitlabSourceNote": "A extração de APK do GitLab pode não funcionar sem uma chave de API.", "gitlabSourceNote": "A extração de endereço de download do APK no GitLab provavelmente não funcione sem que seja fornecido uma chave de API.",
"sortByLastLinkSegment": "Sort by only the last segment of the link", "sortByLastLinkSegment": "Ordenar apenas usando o último segmento do link",
"filterReleaseNotesByRegEx": "Filtrar Notas de Lançamento por Expressão Regular", "filterReleaseNotesByRegEx": "Filtrar notas de versão usando Regex",
"customLinkFilterRegex": "Filtro de Link Personalizado por 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": "Tentativas de atualização de aplicativos",
"appsPossiblyUpdatedNotifDescription": "Notifica o usuário de que atualizações de um ou mais aplicativos foram potencialmente aplicadas em segundo-plano", "appsPossiblyUpdatedNotifDescription": "Notifica o usuário de que atualizações de um ou mais aplicativos 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": "Atualizações em segundo-plano podem não ser possíveis para todos os aplicativos.",
"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 'ultima' etiqueta", "verifyLatestTag": "Verifique a 'última' etiqueta",
"intermediateLinkRegex": "Filter for an 'Intermediate' Link to Visit", "intermediateLinkRegex": "Filter for an 'Intermediate' Link to Visit",
"filterByLinkText": "Filter links by link text", "filterByLinkText": "Filtrar links pelo texto do link",
"intermediateLinkNotFound": "Link intermediário não encontrado", "intermediateLinkNotFound": "Link intermediário não encontrado",
"intermediateLink": "Intermediate link", "intermediateLink": "Link intermediário",
"exemptFromBackgroundUpdates": "Isento de atualizações em segundo-plano (se ativadas)", "exemptFromBackgroundUpdates": "Isento de atualizações em segundo-plano (se ativadas)",
"bgUpdatesOnWiFiOnly": "Desative atualizações em segundo-plano quando não estiver em WiFi", "bgUpdatesOnWiFiOnly": "Desative as atualizações em segundo-plano quando não estiver conectado no Wi-Fi",
"autoSelectHighestVersionCode": "Auto-selecionar o maior codigo de versão", "autoSelectHighestVersionCode": "Auto-selecionar a versão mais recente",
"versionExtractionRegEx": "RegEx para Extração de Versão", "versionExtractionRegEx": "Regex de extração de versão",
"matchGroupToUse": "Grupo de Seleção para Usar", "matchGroupToUse": "Grupo correspondente a ser usado no Regex de extração de versão",
"highlightTouchTargets": "Destaque areas de toque menos óbvias", "highlightTouchTargets": "Realçar áreas sensíveis ao toque que são menos óbvias",
"pickExportDir": "Escolher Diretorio de Exportação", "pickExportDir": "Escolher diretório para a exportação",
"autoExportOnChanges": "Auto-exportar em mudanças", "autoExportOnChanges": "Auto-exportar em mudanças",
"includeSettings": "Include settings", "includeSettings": "Incluir configurações",
"filterVersionsByRegEx": "Filtrar Versões por Expressão Regular", "filterVersionsByRegEx": "Filtrar versões por expressão regular",
"trySelectingSuggestedVersionCode": "Tente selecionar a versão sugerida", "trySelectingSuggestedVersionCode": "Tente selecionar a versão sugerida",
"dontSortReleasesList": "Reter a ordem de lançamento da API", "dontSortReleasesList": "Reter a ordem de lançamento da API",
"reverseSort": "Ordenação reversa", "reverseSort": "Ordenação reversa",
"takeFirstLink": "Take first link", "takeFirstLink": "Obter primeiro link",
"skipSort": "Skip sorting", "skipSort": "Ignorar ordenação",
"debugMenu": "Menu Debug", "debugMenu": "Menu debug",
"bgTaskStarted": "Tarefa em segundo-plano iniciada - verifique os logs.", "bgTaskStarted": "Tarefa em segundo-plano iniciada - verifique os logs.",
"runBgCheckNow": "Execute a verificação de atualização em segundo-plano agora", "runBgCheckNow": "Execute agora em segundo-plano a verificação de atualizações",
"versionExtractWholePage": "Aplicar Regex de Extração de Versão à Página Inteira", "versionExtractWholePage": "Aplicar regex de extração de versão à página inteira",
"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": "Aplicativos atualizados",
"appsPossiblyUpdatedNotifChannel": "Tentativas de atualização de aplicativos", "appsPossiblyUpdatedNotifChannel": "Tentativas de atualização de aplicativos",
"errorCheckingUpdatesNotifChannel": "Erro ao Procurar por Atualizações", "errorCheckingUpdatesNotifChannel": "Erro ao Procurar por Atualizações",
"appsRemovedNotifChannel": "Aplicativos Removidos", "appsRemovedNotifChannel": "Aplicativos removidos",
"downloadingXNotifChannel": "Baixando {}", "downloadingXNotifChannel": "Baixando {}",
"completeAppInstallationNotifChannel": "Instalação completa do aplicativo", "completeAppInstallationNotifChannel": "Instalação completa do aplicativo",
"checkingForUpdatesNotifChannel": "Checando por Atualizações", "checkingForUpdatesNotifChannel": "Checando por Atualizações",
"onlyCheckInstalledOrTrackOnlyApps": "Apenas checar apps instalados e 'Apenas Seguir' por updates", "onlyCheckInstalledOrTrackOnlyApps": "Apenas checar aplicativos instalados e 'Apenas Seguir' por updates",
"supportFixedAPKURL": "Suporte APK com URLs fixas", "supportFixedAPKURL": "Suporte a APK com URLs fixas",
"selectX": "Selecionar {}", "selectX": "Selecionar {}",
"parallelDownloads": "Permitir downloads paralelos", "parallelDownloads": "Permitir downloads paralelos",
"installMethod": "Método de instalação", "installMethod": "Método de instalação",
"normal": "Normal", "normal": "Normal",
"shizuku": "Shizuku", "shizuku": "Shizuku",
"root": "Root", "root": "Root",
"shizukuBinderNotFound": "Shizuku não está rodando", "shizukuBinderNotFound": "O Shizuku não está rodando",
"useVersionCodeAsOSVersion": "Use app versionCode as OS-detected version", "useVersionCodeAsOSVersion": "Use app versionCode as OS-detected version",
"requestHeader": "Request header", "useSystemFont": "Usar fonte padrão do sistema",
"systemFontError": "Erro ao carregar a fonte do sistema: {}",
"requestHeader": "Requisitar cabeçalho",
"defaultPseudoVersioningMethod": "Default Pseudo-Versioning Method",
"partialAPKHash": "Partial APK Hash",
"APKLinkHash": "APK Link Hash",
"directAPKLink": "Direct APK Link",
"pseudoVersionInUse": "A Pseudo-Version is in Use",
"installed": "Installed",
"latest": "Latest",
"invertRegEx": "Invert regular expression",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Remover aplicativo?", "one": "Remover aplicativo?",
"other": "Remover aplicativos?" "other": "Remover aplicativos?"
}, },
"tooManyRequestsTryAgainInMinutes": { "tooManyRequestsTryAgainInMinutes": {
"one": "Muitas solicitações (taxa limitada) - tente novamente em {} minuto", "one": "Muitas solicitações (taxa de solicitações limitada) - tente novamente em {} minuto",
"other": "Muitas solicitações (taxa limitada) - tente novamente em {} minutos" "other": "Muitas solicitações (taxa limitada) - tente novamente em {} minutos"
}, },
"bgUpdateGotErrorRetryInMinutes": { "bgUpdateGotErrorRetryInMinutes": {
@@ -328,19 +339,19 @@
"other": "{} Dias" "other": "{} Dias"
}, },
"clearedNLogsBeforeXAfterY": { "clearedNLogsBeforeXAfterY": {
"one": "Limpo {n} log (antes = {antes}, depois = {depois})", "one": "Foi limpo {n} log (antes = {antes}, depois = {depois})",
"other": "Limpados {n} logs (antes = {antes}, depois = {depois})" "other": "Foram limpos {n} logs (antes = {antes}, depois = {depois})"
}, },
"xAndNMoreUpdatesAvailable": { "xAndNMoreUpdatesAvailable": {
"one": "{} e 1 outro app tem atualizações.", "one": "{} e 1 outro aplicativo possui atualizações.",
"other": "{} e {} outros apps tem atualizações." "other": "{} e {} outros aplicativo possuem atualizações."
}, },
"xAndNMoreUpdatesInstalled": { "xAndNMoreUpdatesInstalled": {
"one": "{} e 1 outro app foi atualizado.", "one": "{} e um outro aplicativo foi atualizado.",
"other": "{} e {} outros apps foram atualizados." "other": "{} e {} outros aplicativos foram atualizados."
}, },
"xAndNMoreUpdatesPossiblyInstalled": { "xAndNMoreUpdatesPossiblyInstalled": {
"one": "{} e 1 outro app pode ter sido atualizado.", "one": "{} e 1 outro aplicativo pode ter sido atualizado.",
"other": "{} e {} outros apps podem ter sido atualizados." "other": "{} e {} outros aplicativos podem ter sido atualizados."
} }
} }

View File

@@ -51,9 +51,8 @@
"percentProgress": "Прогресс: {}%", "percentProgress": "Прогресс: {}%",
"pleaseWait": "Пожалуйста, подождите", "pleaseWait": "Пожалуйста, подождите",
"updateAvailable": "Доступно обновление", "updateAvailable": "Доступно обновление",
"estimateInBracketsShort": "(Оценка)",
"notInstalled": "Не установлено", "notInstalled": "Не установлено",
"estimateInBrackets": "(Оценка)", "pseudoVersion": "pseudo-version",
"selectAll": "Выбрать всё", "selectAll": "Выбрать всё",
"deselectX": "Отменить выбор {}", "deselectX": "Отменить выбор {}",
"xWillBeRemovedButRemainInstalled": "{} будет удалено из Obtainium, но останется на устройстве", "xWillBeRemovedButRemainInstalled": "{} будет удалено из Obtainium, но останется на устройстве",
@@ -213,6 +212,7 @@
"changes": "Изменения", "changes": "Изменения",
"releaseDate": "Дата выпуска", "releaseDate": "Дата выпуска",
"importFromURLsInFile": "Импорт из файла URL-адресов (например: OPML)", "importFromURLsInFile": "Импорт из файла URL-адресов (например: OPML)",
"versionDetectionExplanation": "Reconcile version string with version detected from OS",
"versionDetection": "Определение версии", "versionDetection": "Определение версии",
"standardVersionDetection": "Стандартное", "standardVersionDetection": "Стандартное",
"groupByCategory": "Группировать по категориям", "groupByCategory": "Группировать по категориям",
@@ -293,6 +293,15 @@
"systemFontError": "Ошибка загрузки системного шрифта: {}", "systemFontError": "Ошибка загрузки системного шрифта: {}",
"useVersionCodeAsOSVersion": "Use app versionCode as OS-detected version", "useVersionCodeAsOSVersion": "Use app versionCode as OS-detected version",
"requestHeader": "Request header", "requestHeader": "Request header",
"useLatestAssetDateAsReleaseDate": "Use latest asset upload as release date",
"defaultPseudoVersioningMethod": "Default Pseudo-Versioning Method",
"partialAPKHash": "Partial APK Hash",
"APKLinkHash": "APK Link Hash",
"directAPKLink": "Direct APK Link",
"pseudoVersionInUse": "A Pseudo-Version is in Use",
"installed": "Installed",
"latest": "Latest",
"invertRegEx": "Invert regular expression",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Удалить приложение?", "one": "Удалить приложение?",
"other": "Удалить приложения?" "other": "Удалить приложения?"

View File

@@ -51,9 +51,8 @@
"percentProgress": "Progress: {}%", "percentProgress": "Progress: {}%",
"pleaseWait": "Vänta", "pleaseWait": "Vänta",
"updateAvailable": "Uppdatering Tillgänglig", "updateAvailable": "Uppdatering Tillgänglig",
"estimateInBracketsShort": "(Est.)",
"notInstalled": "Inte Installerad", "notInstalled": "Inte Installerad",
"estimateInBrackets": "(Uppskattning)", "pseudoVersion": "pseudo-version",
"selectAll": "Välj Alla", "selectAll": "Välj Alla",
"deselectX": "Avmarkera {}", "deselectX": "Avmarkera {}",
"xWillBeRemovedButRemainInstalled": "{} kommer tas bort från Obtainium men kommer vara fortsatt installerad på enheten.", "xWillBeRemovedButRemainInstalled": "{} kommer tas bort från Obtainium men kommer vara fortsatt installerad på enheten.",
@@ -213,6 +212,7 @@
"changes": "Ändringar", "changes": "Ändringar",
"releaseDate": "Releasedatum", "releaseDate": "Releasedatum",
"importFromURLsInFile": "Importera från URL:er i fil (som OPML)", "importFromURLsInFile": "Importera från URL:er i fil (som OPML)",
"versionDetectionExplanation": "Reconcile version string with version detected from OS",
"versionDetection": "Versionsdetektering", "versionDetection": "Versionsdetektering",
"standardVersionDetection": "Standardversionsdetektering", "standardVersionDetection": "Standardversionsdetektering",
"groupByCategory": "Gruppera via Kategori", "groupByCategory": "Gruppera via Kategori",
@@ -277,6 +277,15 @@
"shizukuBinderNotFound": "Shizuku is not running", "shizukuBinderNotFound": "Shizuku is not running",
"useVersionCodeAsOSVersion": "Use app versionCode as OS-detected version", "useVersionCodeAsOSVersion": "Use app versionCode as OS-detected version",
"requestHeader": "Request header", "requestHeader": "Request header",
"useLatestAssetDateAsReleaseDate": "Use latest asset upload as release date",
"defaultPseudoVersioningMethod": "Default Pseudo-Versioning Method",
"partialAPKHash": "Partial APK Hash",
"APKLinkHash": "APK Link Hash",
"directAPKLink": "Direct APK Link",
"pseudoVersionInUse": "A Pseudo-Version is in Use",
"installed": "Installed",
"latest": "Latest",
"invertRegEx": "Invert regular expression",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Ta Bort App?", "one": "Ta Bort App?",
"other": "Ta Bort Appar?" "other": "Ta Bort Appar?"

View File

@@ -51,9 +51,8 @@
"percentProgress": "İlerleme: {}%", "percentProgress": "İlerleme: {}%",
"pleaseWait": "Lütfen Bekleyin", "pleaseWait": "Lütfen Bekleyin",
"updateAvailable": "Güncelleme Var", "updateAvailable": "Güncelleme Var",
"estimateInBracketsShort": "(Est.)",
"notInstalled": "Yüklenmedi", "notInstalled": "Yüklenmedi",
"estimateInBrackets": "(Tahmini)", "pseudoVersion": "pseudo-version",
"selectAll": "Hepsini Seç", "selectAll": "Hepsini Seç",
"deselectX": "{}'yi Seçimden Kaldır", "deselectX": "{}'yi Seçimden Kaldır",
"xWillBeRemovedButRemainInstalled": "{} Obtainium'dan kaldırılacak ancak cihazınızda yüklü kalacaktır.", "xWillBeRemovedButRemainInstalled": "{} Obtainium'dan kaldırılacak ancak cihazınızda yüklü kalacaktır.",
@@ -213,6 +212,7 @@
"changes": "Değişiklikler", "changes": "Değişiklikler",
"releaseDate": "Yayın Tarihi", "releaseDate": "Yayın Tarihi",
"importFromURLsInFile": "Dosyadaki URL'lerden İçe Aktar", "importFromURLsInFile": "Dosyadaki URL'lerden İçe Aktar",
"versionDetectionExplanation": "Reconcile version string with version detected from OS",
"versionDetection": "Sürüm Tespiti", "versionDetection": "Sürüm Tespiti",
"standardVersionDetection": "Standart sürüm tespiti", "standardVersionDetection": "Standart sürüm tespiti",
"groupByCategory": "Kategoriye Göre Grupla", "groupByCategory": "Kategoriye Göre Grupla",
@@ -291,6 +291,15 @@
"shizukuBinderNotFound": "Shizuku is not running", "shizukuBinderNotFound": "Shizuku is not running",
"useVersionCodeAsOSVersion": "Use app versionCode as OS-detected version", "useVersionCodeAsOSVersion": "Use app versionCode as OS-detected version",
"requestHeader": "Request header", "requestHeader": "Request header",
"useLatestAssetDateAsReleaseDate": "Use latest asset upload as release date",
"defaultPseudoVersioningMethod": "Default Pseudo-Versioning Method",
"partialAPKHash": "Partial APK Hash",
"APKLinkHash": "APK Link Hash",
"directAPKLink": "Direct APK Link",
"pseudoVersionInUse": "A Pseudo-Version is in Use",
"installed": "Installed",
"latest": "Latest",
"invertRegEx": "Invert regular expression",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Uygulamayı Kaldır?", "one": "Uygulamayı Kaldır?",
"other": "Uygulamaları Kaldır?" "other": "Uygulamaları Kaldır?"

View File

@@ -51,9 +51,8 @@
"percentProgress": "Đang tải {}%", "percentProgress": "Đang tải {}%",
"pleaseWait": "Vui lòng chờ", "pleaseWait": "Vui lòng chờ",
"updateAvailable": "Có sẵn bản cập nhật", "updateAvailable": "Có sẵn bản cập nhật",
"estimateInBracketsShort": "(Ước lượng.)",
"notInstalled": "Chưa cài đặt", "notInstalled": "Chưa cài đặt",
"estimateInBrackets": "(Ước lượng)", "pseudoVersion": "pseudo-version",
"selectAll": "Chọn tất cả", "selectAll": "Chọn tất cả",
"deselectX": "Bỏ chọn {}", "deselectX": "Bỏ chọn {}",
"xWillBeRemovedButRemainInstalled": "{} sẽ bị xóa khỏi Obtainium nhưng vẫn còn cài đặt trên thiết bị.", "xWillBeRemovedButRemainInstalled": "{} sẽ bị xóa khỏi Obtainium nhưng vẫn còn cài đặt trên thiết bị.",
@@ -213,6 +212,7 @@
"changes": "Thay đổi", "changes": "Thay đổi",
"releaseDate": "Ngày phát hành", "releaseDate": "Ngày phát hành",
"importFromURLsInFile": "Nhập từ URL trong Tệp (như OPML)", "importFromURLsInFile": "Nhập từ URL trong Tệp (như OPML)",
"versionDetectionExplanation": "Reconcile version string with version detected from OS",
"versionDetection": "Phát hiện phiên bản", "versionDetection": "Phát hiện phiên bản",
"standardVersionDetection": "Phát hiện phiên bản tiêu chuẩn", "standardVersionDetection": "Phát hiện phiên bản tiêu chuẩn",
"groupByCategory": "Nhóm theo thể loại", "groupByCategory": "Nhóm theo thể loại",
@@ -289,6 +289,15 @@
"shizuku": "Shizuku", "shizuku": "Shizuku",
"root": "Root", "root": "Root",
"shizukuBinderNotFound": "Shizuku chưa khởi động", "shizukuBinderNotFound": "Shizuku chưa khởi động",
"useLatestAssetDateAsReleaseDate": "Use latest asset upload as release date",
"defaultPseudoVersioningMethod": "Default Pseudo-Versioning Method",
"partialAPKHash": "Partial APK Hash",
"APKLinkHash": "APK Link Hash",
"directAPKLink": "Direct APK Link",
"pseudoVersionInUse": "A Pseudo-Version is in Use",
"installed": "Installed",
"latest": "Latest",
"invertRegEx": "Invert regular expression",
"removeAppQuestion":{ "removeAppQuestion":{
"one": "Gỡ ứng dụng?", "one": "Gỡ ứng dụng?",
"other": "Gỡ ứng dụng?" "other": "Gỡ ứng dụng?"

View File

@@ -51,9 +51,8 @@
"percentProgress": "进度:{}%", "percentProgress": "进度:{}%",
"pleaseWait": "请稍候", "pleaseWait": "请稍候",
"updateAvailable": "更新可用", "updateAvailable": "更新可用",
"estimateInBracketsShort": "(推测)",
"notInstalled": "未安装", "notInstalled": "未安装",
"estimateInBrackets": "(推测)", "pseudoVersion": "pseudo-version",
"selectAll": "全选", "selectAll": "全选",
"deselectX": "取消选择 {}", "deselectX": "取消选择 {}",
"xWillBeRemovedButRemainInstalled": "“{}”将从 Obtainium 中删除,但仍安装在您的设备中。", "xWillBeRemovedButRemainInstalled": "“{}”将从 Obtainium 中删除,但仍安装在您的设备中。",
@@ -213,6 +212,7 @@
"changes": "更新日志", "changes": "更新日志",
"releaseDate": "发行日期", "releaseDate": "发行日期",
"importFromURLsInFile": "从文件中的 URL 导入(如 OPML", "importFromURLsInFile": "从文件中的 URL 导入(如 OPML",
"versionDetectionExplanation": "Reconcile version string with version detected from OS",
"versionDetection": "版本检测", "versionDetection": "版本检测",
"standardVersionDetection": "常规版本检测", "standardVersionDetection": "常规版本检测",
"groupByCategory": "按类别分组显示", "groupByCategory": "按类别分组显示",
@@ -293,6 +293,15 @@
"systemFontError": "加载系统字体出错:{}", "systemFontError": "加载系统字体出错:{}",
"useVersionCodeAsOSVersion": "Use app versionCode as OS-detected version", "useVersionCodeAsOSVersion": "Use app versionCode as OS-detected version",
"requestHeader": "Request header", "requestHeader": "Request header",
"useLatestAssetDateAsReleaseDate": "Use latest asset upload as release date",
"defaultPseudoVersioningMethod": "Default Pseudo-Versioning Method",
"partialAPKHash": "Partial APK Hash",
"APKLinkHash": "APK Link Hash",
"directAPKLink": "Direct APK Link",
"pseudoVersionInUse": "A Pseudo-Version is in Use",
"installed": "Installed",
"latest": "Latest",
"invertRegEx": "Invert regular expression",
"removeAppQuestion": { "removeAppQuestion": {
"one": "是否删除应用?", "one": "是否删除应用?",
"other": "是否删除应用?" "other": "是否删除应用?"

View File

@@ -6,6 +6,7 @@ import 'package:obtainium/providers/source_provider.dart';
class APKCombo extends AppSource { class APKCombo extends AppSource {
APKCombo() { APKCombo() {
hosts = ['apkcombo.com']; hosts = ['apkcombo.com'];
showReleaseDateAsVersionToggle = true;
} }
@override @override

View File

@@ -11,6 +11,7 @@ class APKMirror extends AppSource {
APKMirror() { APKMirror() {
hosts = ['apkmirror.com']; hosts = ['apkmirror.com'];
enforceTrackOnly = true; enforceTrackOnly = true;
showReleaseDateAsVersionToggle = true;
additionalSourceAppSpecificSettingFormItems = [ additionalSourceAppSpecificSettingFormItems = [
[ [

View File

@@ -23,6 +23,7 @@ class APKPure extends AppSource {
hosts = ['apkpure.net', 'apkpure.com']; hosts = ['apkpure.net', 'apkpure.com'];
allowSubDomains = true; allowSubDomains = true;
naiveStandardVersionDetection = true; naiveStandardVersionDetection = true;
showReleaseDateAsVersionToggle = true;
} }
@override @override

View File

@@ -10,6 +10,7 @@ class Aptoide extends AppSource {
name = 'Aptoide'; name = 'Aptoide';
allowSubDomains = true; allowSubDomains = true;
naiveStandardVersionDetection = true; naiveStandardVersionDetection = true;
showReleaseDateAsVersionToggle = true;
} }
@override @override

View File

@@ -0,0 +1,44 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:obtainium/app_sources/html.dart';
import 'package:obtainium/providers/source_provider.dart';
class DirectAPKLink extends AppSource {
HTML html = HTML();
DirectAPKLink() {
neverAutoSelect = true;
name = tr('directAPKLink');
additionalSourceAppSpecificSettingFormItems = html
.additionalSourceAppSpecificSettingFormItems
.where((element) => element
.where((element) => element.key == 'requestHeader')
.isNotEmpty)
.toList();
excludeCommonSettingKeys = [
'versionExtractionRegEx',
'matchGroupToUse',
'versionDetection',
'useVersionCodeAsOSVersion',
'apkFilterRegEx',
'autoApkFilterByArch'
];
}
@override
Future<APKDetails> getLatestAPKDetails(
String standardUrl,
Map<String, dynamic> additionalSettings,
) async {
var additionalSettingsNew =
getDefaultValuesFromFormItems(html.combinedAppSpecificSettingFormItems);
for (var s in additionalSettings.keys) {
if (additionalSettingsNew.containsKey(s)) {
additionalSettingsNew[s] = additionalSettings[s];
}
}
additionalSettingsNew['defaultPseudoVersioningMethod'] = 'partialAPKHash';
additionalSettingsNew['directAPKLink'] = true;
additionalSettings['versionDetection'] = false;
return html.getLatestAPKDetails(standardUrl, additionalSettingsNew);
}
}

View File

@@ -10,6 +10,7 @@ class FDroidRepo extends AppSource {
canSearch = true; canSearch = true;
excludeFromMassSearch = true; excludeFromMassSearch = true;
neverAutoSelect = true; neverAutoSelect = true;
showReleaseDateAsVersionToggle = true;
additionalSourceAppSpecificSettingFormItems = [ additionalSourceAppSpecificSettingFormItems = [
[ [

View File

@@ -16,6 +16,7 @@ class GitHub extends AppSource {
GitHub() { GitHub() {
hosts = ['github.com']; hosts = ['github.com'];
appIdInferIsOptional = true; appIdInferIsOptional = true;
showReleaseDateAsVersionToggle = true;
sourceConfigSettingFormItems = [ sourceConfigSettingFormItems = [
GeneratedFormTextField('github-creds', GeneratedFormTextField('github-creds',
@@ -76,6 +77,10 @@ class GitHub extends AppSource {
[ [
GeneratedFormSwitch('dontSortReleasesList', GeneratedFormSwitch('dontSortReleasesList',
label: tr('dontSortReleasesList')) label: tr('dontSortReleasesList'))
],
[
GeneratedFormSwitch('useLatestAssetDateAsReleaseDate',
label: tr('useLatestAssetDateAsReleaseDate'), defaultValue: false)
] ]
]; ];
@@ -237,6 +242,8 @@ class GitHub extends AppSource {
bool verifyLatestTag = additionalSettings['verifyLatestTag'] == true; bool verifyLatestTag = additionalSettings['verifyLatestTag'] == true;
bool dontSortReleasesList = bool dontSortReleasesList =
additionalSettings['dontSortReleasesList'] == true; additionalSettings['dontSortReleasesList'] == true;
bool useLatestAssetDateAsReleaseDate =
additionalSettings['useLatestAssetDateAsReleaseDate'] == true;
dynamic latestRelease; dynamic latestRelease;
if (verifyLatestTag) { if (verifyLatestTag) {
var temp = requestUrl.split('?'); var temp = requestUrl.split('?');
@@ -277,10 +284,31 @@ class GitHub extends AppSource {
.toList() ?? .toList() ??
[]; [];
DateTime? getReleaseDateFromRelease(dynamic rel) => DateTime? getPublishDateFromRelease(dynamic rel) =>
rel?['published_at'] != null rel?['published_at'] != null
? DateTime.parse(rel['published_at']) ? DateTime.parse(rel['published_at'])
: null; : null;
DateTime? getNewestAssetDateFromRelease(dynamic rel) {
var t = (rel['assets'] as List<dynamic>?)
?.map((e) {
return e?['updated_at'] != null
? DateTime.parse(e['updated_at'])
: null;
})
.where((e) => e != null)
.toList();
t?.sort((a, b) => b!.compareTo(a!));
if (t?.isNotEmpty == true) {
return t!.first;
}
return null;
}
DateTime? getReleaseDateFromRelease(dynamic rel, bool useAssetDate) =>
!useAssetDate
? getPublishDateFromRelease(rel)
: getNewestAssetDateFromRelease(rel);
if (dontSortReleasesList) { if (dontSortReleasesList) {
releases = releases.reversed.toList(); releases = releases.reversed.toList();
} else { } else {
@@ -305,8 +333,12 @@ class GitHub extends AppSource {
(nameA as String).substring(matchA!.start, matchA.end), (nameA as String).substring(matchA!.start, matchA.end),
(nameB as String).substring(matchB!.start, matchB.end)); (nameB as String).substring(matchB!.start, matchB.end));
} else { } else {
return (getReleaseDateFromRelease(a) ?? DateTime(1)) return (getReleaseDateFromRelease(
.compareTo(getReleaseDateFromRelease(b) ?? DateTime(0)); a, useLatestAssetDateAsReleaseDate) ??
DateTime(1))
.compareTo(getReleaseDateFromRelease(
b, useLatestAssetDateAsReleaseDate) ??
DateTime(0));
} }
} }
}); });
@@ -350,11 +382,8 @@ class GitHub extends AppSource {
continue; continue;
} }
var apkUrls = getReleaseAPKUrls(releases[i]); var apkUrls = getReleaseAPKUrls(releases[i]);
if (additionalSettings['apkFilterRegEx'] != null) { apkUrls = filterApks(apkUrls, additionalSettings['apkFilterRegEx'],
var reg = RegExp(additionalSettings['apkFilterRegEx']); additionalSettings['invertAPKFilter']);
apkUrls =
apkUrls.where((element) => reg.hasMatch(element.key)).toList();
}
if (apkUrls.isEmpty && additionalSettings['trackOnly'] != true) { if (apkUrls.isEmpty && additionalSettings['trackOnly'] != true) {
continue; continue;
} }
@@ -366,7 +395,8 @@ class GitHub extends AppSource {
throw NoReleasesError(); throw NoReleasesError();
} }
String? version = targetRelease['tag_name'] ?? targetRelease['name']; String? version = targetRelease['tag_name'] ?? targetRelease['name'];
DateTime? releaseDate = getReleaseDateFromRelease(targetRelease); DateTime? releaseDate = getReleaseDateFromRelease(
targetRelease, useLatestAssetDateAsReleaseDate);
if (version == null) { if (version == null) {
throw NoVersionError(); throw NoVersionError();
} }

View File

@@ -15,6 +15,7 @@ class GitLab extends AppSource {
GitLab() { GitLab() {
hosts = ['gitlab.com']; hosts = ['gitlab.com'];
canSearch = true; canSearch = true;
showReleaseDateAsVersionToggle = true;
sourceConfigSettingFormItems = [ sourceConfigSettingFormItems = [
GeneratedFormTextField('gitlab-creds', GeneratedFormTextField('gitlab-creds',

View File

@@ -108,11 +108,7 @@ class HTML extends AppSource {
[ [
GeneratedFormSwitch('versionExtractWholePage', GeneratedFormSwitch('versionExtractWholePage',
label: tr('versionExtractWholePage')) label: tr('versionExtractWholePage'))
], ]
[
GeneratedFormSwitch('supportFixedAPKURL',
defaultValue: true, label: tr('supportFixedAPKURL')),
],
]; ];
var commonFormItems = [ var commonFormItems = [
[GeneratedFormSwitch('filterByLinkText', label: tr('filterByLinkText'))], [GeneratedFormSwitch('filterByLinkText', label: tr('filterByLinkText'))],
@@ -172,10 +168,18 @@ class HTML extends AppSource {
'User-Agent: Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Mobile Safari/537.36' 'User-Agent: Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Mobile Safari/537.36'
} }
]) ])
],
[
GeneratedFormDropdown(
'defaultPseudoVersioningMethod',
[
MapEntry('partialAPKHash', tr('partialAPKHash')),
MapEntry('APKLinkHash', tr('APKLinkHash'))
],
label: tr('defaultPseudoVersioningMethod'),
defaultValue: 'partialAPKHash')
] ]
]; ];
overrideVersionDetectionFormDefault('noVersionDetection',
disableStandard: false, disableRelDate: true);
} }
@override @override
@@ -288,17 +292,21 @@ class HTML extends AppSource {
currentUrl = intLinks.last.key; currentUrl = intLinks.last.key;
} }
} }
var uri = Uri.parse(currentUrl); var uri = Uri.parse(currentUrl);
Response res = await sourceRequest(currentUrl, additionalSettings); List<MapEntry<String, String>> links = [];
var links = await grabLinksCommon(res, additionalSettings); String versionExtractionWholePageString = currentUrl;
if (additionalSettings['directAPKLink'] != true) {
if ((additionalSettings['apkFilterRegEx'] as String?)?.isNotEmpty == true) { Response res = await sourceRequest(currentUrl, additionalSettings);
var reg = RegExp(additionalSettings['apkFilterRegEx']); versionExtractionWholePageString =
links = links.where((element) => reg.hasMatch(element.key)).toList(); res.body.split('\r\n').join('\n').split('\n').join('\\n');
} links = await grabLinksCommon(res, additionalSettings);
if (links.isEmpty) { links = filterApks(links, additionalSettings['apkFilterRegEx'],
throw NoReleasesError(); additionalSettings['invertAPKFilter']);
if (links.isEmpty) {
throw NoReleasesError();
}
} else {
links = [MapEntry(currentUrl, currentUrl)];
} }
var rel = links.last.key; var rel = links.last.key;
String? version; String? version;
@@ -306,11 +314,12 @@ class HTML extends AppSource {
additionalSettings['versionExtractionRegEx'] as String?, additionalSettings['versionExtractionRegEx'] as String?,
additionalSettings['matchGroupToUse'] as String?, additionalSettings['matchGroupToUse'] as String?,
additionalSettings['versionExtractWholePage'] == true additionalSettings['versionExtractWholePage'] == true
? res.body.split('\r\n').join('\n').split('\n').join('\\n') ? versionExtractionWholePageString
: rel); : rel);
version ??= additionalSettings['supportFixedAPKURL'] != true version ??=
? rel.hashCode.toString() additionalSettings['defaultPseudoVersioningMethod'] == 'APKLinkHash'
: (await checkDownloadHash(rel)).toString(); ? rel.hashCode.toString()
: (await checkPartialDownloadHashDynamc(rel)).toString();
return APKDetails(version, [rel].map((e) => MapEntry(e, e)).toList(), return APKDetails(version, [rel].map((e) => MapEntry(e, e)).toList(),
AppNames(uri.host, tr('app'))); AppNames(uri.host, tr('app')));
} }

View File

@@ -7,8 +7,8 @@ class HuaweiAppGallery extends AppSource {
HuaweiAppGallery() { HuaweiAppGallery() {
name = 'Huawei AppGallery'; name = 'Huawei AppGallery';
hosts = ['appgallery.huawei.com']; hosts = ['appgallery.huawei.com'];
overrideVersionDetectionFormDefault('releaseDateAsVersion', versionDetectionDisallowed = true;
disableStandard: true); showReleaseDateAsVersionToggle = true;
} }
@override @override

View File

@@ -6,9 +6,9 @@ import 'package:obtainium/providers/source_provider.dart';
class Jenkins extends AppSource { class Jenkins extends AppSource {
Jenkins() { Jenkins() {
overrideVersionDetectionFormDefault('releaseDateAsVersion', versionDetectionDisallowed = true;
disableStandard: true);
neverAutoSelect = true; neverAutoSelect = true;
showReleaseDateAsVersionToggle = true;
} }
String trimJobUrl(String url) { String trimJobUrl(String url) {

View File

@@ -6,6 +6,7 @@ import 'package:obtainium/providers/source_provider.dart';
class NeutronCode extends AppSource { class NeutronCode extends AppSource {
NeutronCode() { NeutronCode() {
hosts = ['neutroncode.com']; hosts = ['neutroncode.com'];
showReleaseDateAsVersionToggle = true;
} }
@override @override

View File

@@ -9,6 +9,7 @@ import 'package:easy_localization/easy_localization.dart';
class SourceHut extends AppSource { class SourceHut extends AppSource {
SourceHut() { SourceHut() {
hosts = ['git.sr.ht']; hosts = ['git.sr.ht'];
showReleaseDateAsVersionToggle = true;
additionalSourceAppSpecificSettingFormItems = [ additionalSourceAppSpecificSettingFormItems = [
[ [

View File

@@ -9,6 +9,7 @@ class Uptodown extends AppSource {
hosts = ['uptodown.com']; hosts = ['uptodown.com'];
allowSubDomains = true; allowSubDomains = true;
naiveStandardVersionDetection = true; naiveStandardVersionDetection = true;
showReleaseDateAsVersionToggle = true;
} }
@override @override

View File

@@ -6,8 +6,7 @@ import 'package:obtainium/providers/source_provider.dart';
class WhatsApp extends AppSource { class WhatsApp extends AppSource {
WhatsApp() { WhatsApp() {
hosts = ['whatsapp.com']; hosts = ['whatsapp.com'];
overrideVersionDetectionFormDefault('noVersionDetection', versionDetectionDisallowed = true;
disableStandard: true, disableRelDate: true);
} }
@override @override

View File

@@ -96,11 +96,14 @@ class GeneratedFormDropdown extends GeneratedFormItem {
} }
class GeneratedFormSwitch extends GeneratedFormItem { class GeneratedFormSwitch extends GeneratedFormItem {
bool disabled = false;
GeneratedFormSwitch( GeneratedFormSwitch(
super.key, { super.key, {
super.label, super.label,
super.belowWidgets, super.belowWidgets,
bool super.defaultValue = false, bool super.defaultValue = false,
bool disabled = false,
List<String? Function(bool value)> super.additionalValidators = const [], List<String? Function(bool value)> super.additionalValidators = const [],
}); });
@@ -115,6 +118,7 @@ class GeneratedFormSwitch extends GeneratedFormItem {
label: label, label: label,
belowWidgets: belowWidgets, belowWidgets: belowWidgets,
defaultValue: defaultValue, defaultValue: defaultValue,
disabled: false,
additionalValidators: List.from(additionalValidators)); additionalValidators: List.from(additionalValidators));
} }
} }
@@ -368,15 +372,51 @@ class _GeneratedFormState extends State<GeneratedForm> {
), ),
Switch( Switch(
value: values[fieldKey], value: values[fieldKey],
onChanged: (value) { onChanged:
setState(() { (widget.items[r][e] as GeneratedFormSwitch).disabled
values[fieldKey] = value; ? null
someValueChanged(); : (value) {
}); setState(() {
}) values[fieldKey] = value;
someValueChanged();
});
})
], ],
); );
} else if (widget.items[r][e] is GeneratedFormTagInput) { } else if (widget.items[r][e] is GeneratedFormTagInput) {
onAddPressed() {
showDialog<Map<String, dynamic>?>(
context: context,
builder: (BuildContext ctx) {
return GeneratedFormModal(
title: widget.items[r][e].label,
items: [
[GeneratedFormTextField('label', label: tr('label'))]
]);
}).then((value) {
String? label = value?['label'];
if (label != null) {
setState(() {
var temp =
values[fieldKey] as Map<String, MapEntry<int, bool>>?;
temp ??= {};
if (temp[label] == null) {
var singleSelect =
(widget.items[r][e] as GeneratedFormTagInput)
.singleSelect;
var someSelected = temp.entries
.where((element) => element.value.value)
.isNotEmpty;
temp[label] = MapEntry(generateRandomLightColor().value,
!(someSelected && singleSelect));
values[fieldKey] = temp;
someValueChanged();
}
});
}
});
}
formInputs[r][e] = formInputs[r][e] =
Column(crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Column(crossAxisAlignment: CrossAxisAlignment.stretch, children: [
if ((values[fieldKey] as Map<String, MapEntry<int, bool>>?) if ((values[fieldKey] as Map<String, MapEntry<int, bool>>?)
@@ -402,14 +442,14 @@ class _GeneratedFormState extends State<GeneratedForm> {
(widget.items[r][e] as GeneratedFormTagInput).alignment, (widget.items[r][e] as GeneratedFormTagInput).alignment,
crossAxisAlignment: WrapCrossAlignment.center, crossAxisAlignment: WrapCrossAlignment.center,
children: [ children: [
(values[fieldKey] as Map<String, MapEntry<int, bool>>?) // (values[fieldKey] as Map<String, MapEntry<int, bool>>?)
?.isEmpty == // ?.isEmpty ==
true // true
? Text( // ? Text(
(widget.items[r][e] as GeneratedFormTagInput) // (widget.items[r][e] as GeneratedFormTagInput)
.emptyMessage, // .emptyMessage,
) // )
: const SizedBox.shrink(), // : const SizedBox.shrink(),
...(values[fieldKey] as Map<String, MapEntry<int, bool>>?) ...(values[fieldKey] as Map<String, MapEntry<int, bool>>?)
?.entries ?.entries
.map((e2) { .map((e2) {
@@ -533,49 +573,26 @@ class _GeneratedFormState extends State<GeneratedForm> {
tooltip: tr('remove'), tooltip: tr('remove'),
)) ))
: const SizedBox.shrink(), : const SizedBox.shrink(),
Padding( (values[fieldKey] as Map<String, MapEntry<int, bool>>?)
padding: const EdgeInsets.symmetric(horizontal: 4), ?.isEmpty ==
child: IconButton( true
onPressed: () { ? Padding(
showDialog<Map<String, dynamic>?>( padding: const EdgeInsets.symmetric(horizontal: 4),
context: context, child: TextButton.icon(
builder: (BuildContext ctx) { onPressed: onAddPressed,
return GeneratedFormModal( icon: const Icon(Icons.add),
title: widget.items[r][e].label, label: Text(
items: [ (widget.items[r][e] as GeneratedFormTagInput)
[ .label),
GeneratedFormTextField('label', ))
label: tr('label')) : Padding(
] padding: const EdgeInsets.symmetric(horizontal: 4),
]); child: IconButton(
}).then((value) { onPressed: onAddPressed,
String? label = value?['label']; icon: const Icon(Icons.add),
if (label != null) { visualDensity: VisualDensity.compact,
setState(() { tooltip: tr('add'),
var temp = values[fieldKey] )),
as Map<String, MapEntry<int, bool>>?;
temp ??= {};
if (temp[label] == null) {
var singleSelect = (widget.items[r][e]
as GeneratedFormTagInput)
.singleSelect;
var someSelected = temp.entries
.where((element) => element.value.value)
.isNotEmpty;
temp[label] = MapEntry(
generateRandomLightColor().value,
!(someSelected && singleSelect));
values[fieldKey] = temp;
someValueChanged();
}
});
}
});
},
icon: const Icon(Icons.add),
visualDensity: VisualDensity.compact,
tooltip: tr('add'),
)),
], ],
) )
]); ]);

View File

@@ -7,6 +7,7 @@ import 'package:obtainium/providers/apps_provider.dart';
import 'package:obtainium/providers/logs_provider.dart'; import 'package:obtainium/providers/logs_provider.dart';
import 'package:obtainium/providers/notifications_provider.dart'; import 'package:obtainium/providers/notifications_provider.dart';
import 'package:obtainium/providers/settings_provider.dart'; import 'package:obtainium/providers/settings_provider.dart';
import 'package:obtainium/providers/source_provider.dart';
import 'package:permission_handler/permission_handler.dart'; import 'package:permission_handler/permission_handler.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:dynamic_color/dynamic_color.dart'; import 'package:dynamic_color/dynamic_color.dart';
@@ -18,10 +19,6 @@ 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.15.10';
const String currentReleaseTag =
'v$currentVersion-beta'; // KEEP THIS IN SYNC WITH GITHUB RELEASES
List<MapEntry<Locale, String>> supportedLocales = const [ List<MapEntry<Locale, String>> supportedLocales = const [
MapEntry(Locale('en'), 'English'), MapEntry(Locale('en'), 'English'),
MapEntry(Locale('zh'), '简体中文'), MapEntry(Locale('zh'), '简体中文'),
@@ -143,6 +140,7 @@ class _ObtainiumState extends State<Obtainium> {
BackgroundFetchConfig( BackgroundFetchConfig(
minimumFetchInterval: 15, minimumFetchInterval: 15,
stopOnTerminate: false, stopOnTerminate: false,
startOnBoot: true,
enableHeadless: true, enableHeadless: true,
requiresBatteryNotLow: false, requiresBatteryNotLow: false,
requiresCharging: false, requiresCharging: false,
@@ -173,7 +171,31 @@ class _ObtainiumState extends State<Obtainium> {
// If this is the first run, ask for notification permissions and add Obtainium to the Apps list // If this is the first run, ask for notification permissions and add Obtainium to the Apps list
Permission.notification.request(); Permission.notification.request();
if (!fdroid) { if (!fdroid) {
appsProvider.saveApps([obtainiumApp], onlyIfExists: false); getInstalledInfo(obtainiumId).then((value) {
if (value?.versionName != null) {
appsProvider.saveApps([
App(
obtainiumId,
obtainiumUrl,
'ImranR98',
'Obtainium',
value!.versionName,
value.versionName!,
[],
0,
{
'includePrereleases': true,
'versionDetection': true,
'apkFilterRegEx': 'fdroid',
'invertAPKFilter': true
},
null,
false)
], onlyIfExists: false);
}
}).catchError((err) {
print(err);
});
} }
} }
if (!supportedLocales if (!supportedLocales

View File

@@ -135,8 +135,7 @@ class AddAppPageState extends State<AddAppPage> {
getReleaseDateAsVersionConfirmationIfNeeded( getReleaseDateAsVersionConfirmationIfNeeded(
bool userPickedTrackOnly) async { bool userPickedTrackOnly) async {
return (!(additionalSettings['versionDetection'] == return (!(additionalSettings['releaseDateAsVersion'] == true &&
'releaseDateAsVersion' &&
// ignore: use_build_context_synchronously // ignore: use_build_context_synchronously
await showDialog( await showDialog(
context: context, context: context,
@@ -192,8 +191,7 @@ class AddAppPageState extends State<AddAppPage> {
throw ObtainiumError(tr('appAlreadyAdded')); throw ObtainiumError(tr('appAlreadyAdded'));
} }
if (app.additionalSettings['trackOnly'] == true || if (app.additionalSettings['trackOnly'] == true ||
app.additionalSettings['versionDetection'] != app.additionalSettings['versionDetection'] != true) {
'standardVersionDetection') {
app.installedVersion = app.latestVersion; app.installedVersion = app.latestVersion;
} }
app.categories = pickedCategories; app.categories = pickedCategories;
@@ -498,36 +496,61 @@ class AddAppPageState extends State<AddAppPage> {
], ],
); );
Widget getSourcesListWidget() => Column( Widget getSourcesListWidget() => Padding(
crossAxisAlignment: CrossAxisAlignment.center, padding: const EdgeInsets.all(16),
mainAxisAlignment: MainAxisAlignment.center, child: Row(
children: [ children: [
Text( GestureDetector(
tr('supportedSources'), onTap: () {
style: const TextStyle(fontWeight: FontWeight.bold), showDialog(
), context: context,
const SizedBox( builder: (context) {
height: 16, return GeneratedFormModal(
), singleNullReturnButton: tr('ok'),
...sourceProvider.sources.map((e) => GestureDetector( title: tr('supportedSources'),
onTap: e.hosts.isNotEmpty items: const [],
? () { additionalWidgets: [
launchUrlString('https://${e.hosts[0]}', ...sourceProvider.sources.map(
mode: LaunchMode.externalApplication); (e) => Padding(
} padding:
: null, const EdgeInsets.symmetric(vertical: 4),
child: GestureDetector(
onTap: e.hosts.isNotEmpty
? () {
launchUrlString(
'https://${e.hosts[0]}',
mode: LaunchMode
.externalApplication);
}
: null,
child: Text(
'${e.name}${e.enforceTrackOnly ? ' ${tr('trackOnlyInBrackets')}' : ''}${e.canSearch ? ' ${tr('searchableInBrackets')}' : ''}',
style: TextStyle(
decoration: e.hosts.isNotEmpty
? TextDecoration.underline
: TextDecoration.none),
))),
)
],
);
},
);
},
child: Text( child: Text(
'${e.name}${e.enforceTrackOnly ? ' ${tr('trackOnlyInBrackets')}' : ''}${e.canSearch ? ' ${tr('searchableInBrackets')}' : ''}', tr('supportedSources'),
style: TextStyle( style: const TextStyle(
decoration: e.hosts.isNotEmpty fontWeight: FontWeight.bold,
? TextDecoration.underline decoration: TextDecoration.underline,
: TextDecoration.none,
fontStyle: FontStyle.italic), fontStyle: FontStyle.italic),
))) ))
]); ],
),
);
return Scaffold( return Scaffold(
backgroundColor: Theme.of(context).colorScheme.surface, backgroundColor: Theme.of(context).colorScheme.surface,
bottomNavigationBar:
pickedSource == null ? getSourcesListWidget() : null,
body: CustomScrollView(shrinkWrap: true, slivers: <Widget>[ body: CustomScrollView(shrinkWrap: true, slivers: <Widget>[
CustomAppBar(title: tr('addApp')), CustomAppBar(title: tr('addApp')),
SliverToBoxAdapter( SliverToBoxAdapter(
@@ -559,18 +582,7 @@ class AddAppPageState extends State<AddAppPage> {
: const SizedBox(); : const SizedBox();
}, },
future: pickedSource?.getSourceNote()), future: pickedSource?.getSourceNote()),
SizedBox(
height: pickedSource != null ? 16 : 96,
),
if (pickedSource != null) getAdditionalOptsCol(), if (pickedSource != null) getAdditionalOptsCol(),
if (pickedSource == null)
const Divider(
height: 48,
),
if (pickedSource == null) getSourcesListWidget(),
SizedBox(
height: pickedSource != null ? 8 : 2,
),
])), ])),
) )
])); ]));

View File

@@ -1,7 +1,6 @@
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:obtainium/components/generated_form.dart';
import 'package:obtainium/components/generated_form_modal.dart'; import 'package:obtainium/components/generated_form_modal.dart';
import 'package:obtainium/custom_errors.dart'; import 'package:obtainium/custom_errors.dart';
import 'package:obtainium/main.dart'; import 'package:obtainium/main.dart';
@@ -29,8 +28,18 @@ class _AppPageState extends State<AppPage> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
var appsProvider = context.watch<AppsProvider>(); var appsProvider = context.watch<AppsProvider>();
var settingsProvider = context.watch<SettingsProvider>(); var settingsProvider = context.watch<SettingsProvider>();
getUpdate(String id) { getUpdate(String id, {bool resetVersion = false}) {
appsProvider.checkUpdate(id).catchError((e) { appsProvider.checkUpdate(id).then((e) {
if (resetVersion) {
appsProvider.apps[id]?.app.additionalSettings['versionDetection'] =
true;
if (appsProvider.apps[id]?.app.installedVersion != null) {
appsProvider.apps[id]?.app.installedVersion =
appsProvider.apps[id]?.app.latestVersion;
}
appsProvider.saveApps([appsProvider.apps[id]!.app]);
}
}).catchError((e) {
showError(e, context); showError(e, context);
return null; return null;
}); });
@@ -54,122 +63,113 @@ class _AppPageState extends State<AppPage> {
var trackOnly = app?.app.additionalSettings['trackOnly'] == true; var trackOnly = app?.app.additionalSettings['trackOnly'] == true;
bool isVersionDetectionStandard = bool isVersionDetectionStandard =
app?.app.additionalSettings['versionDetection'] == app?.app.additionalSettings['versionDetection'] == true;
'standardVersionDetection';
bool installedVersionIsEstimate = trackOnly || bool installedVersionIsEstimate = trackOnly ||
(app?.app.installedVersion != null && (app?.app.installedVersion != null &&
app?.app.additionalSettings['versionDetection'] == app?.app.additionalSettings['versionDetection'] != true);
'noVersionDetection');
getInfoColumn() => Column( getInfoColumn() {
mainAxisAlignment: MainAxisAlignment.center, String versionLines = '';
crossAxisAlignment: CrossAxisAlignment.stretch, bool installed = app?.app.installedVersion != null;
children: [ bool upToDate = app?.app.installedVersion == app?.app.latestVersion;
GestureDetector( if (installed) {
onTap: () { versionLines = '${app?.app.installedVersion} ${tr('installed')}';
if (app?.app.url != null) { if (upToDate) {
launchUrlString(app?.app.url ?? '', versionLines += '/${tr('latest')}';
mode: LaunchMode.externalApplication); }
} } else {
}, versionLines = tr('notInstalled');
onLongPress: () { }
Clipboard.setData(ClipboardData(text: app?.app.url ?? '')); if (!upToDate) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar( versionLines += '\n${app?.app.latestVersion} ${tr('latest')}';
content: Text(tr('copiedToClipboard')), }
)); String infoLines = tr('lastUpdateCheckX', args: [
}, app?.app.lastUpdateCheck == null
child: Text( ? tr('never')
app?.app.url ?? '', : '${app?.app.lastUpdateCheck?.toLocal()}'
textAlign: TextAlign.center, ]);
style: const TextStyle( if (trackOnly) {
decoration: TextDecoration.underline, infoLines = '${tr('xIsTrackOnly', args: [tr('app')])}\n$infoLines';
fontStyle: FontStyle.italic, }
fontSize: 12), if (installedVersionIsEstimate) {
)), infoLines = '${tr('pseudoVersionInUse')}\n$infoLines';
const SizedBox( }
height: 32, return Column(
), mainAxisAlignment: MainAxisAlignment.center,
Column( crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 24),
child: Column(
children: [ children: [
Text( const SizedBox(
'${tr('latestVersionX', args: [ height: 8,
app?.app.latestVersion ?? tr('unknown') ),
])}\n${tr('installedVersionX', args: [ Text(versionLines,
app?.app.installedVersion ?? tr('none') textAlign: TextAlign.start,
])}${installedVersionIsEstimate ? '\n${tr('estimateInBrackets')}' : ''}', style: Theme.of(context)
textAlign: TextAlign.end, .textTheme
style: Theme.of(context).textTheme.bodyLarge!, .bodyLarge!
.copyWith(fontWeight: FontWeight.bold)),
app?.app.releaseDate == null
? const SizedBox.shrink()
: Text(
app!.app.releaseDate.toString(),
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.labelSmall,
),
const SizedBox(
height: 8,
), ),
], ],
), ),
if (app?.app.installedVersion != null && ),
!isVersionDetectionStandard) Text(
Column( infoLines,
children: [ textAlign: TextAlign.center,
const SizedBox( style: const TextStyle(fontStyle: FontStyle.italic, fontSize: 12),
height: 16, ),
), const SizedBox(
Text( height: 48,
'${trackOnly ? '${tr('xIsTrackOnly', args: [ ),
tr('app') CategoryEditorSelector(
])}\n' : ''}${tr('noVersionDetection')}', alignment: WrapAlignment.center,
style: Theme.of(context).textTheme.labelSmall, preselected: app?.app.categories != null
? app!.app.categories.toSet()
: {},
onSelected: (categories) {
if (app != null) {
app.app.categories = categories;
appsProvider.saveApps([app.app]);
}
}),
if (app?.app.additionalSettings['about'] is String &&
app?.app.additionalSettings['about'].isNotEmpty)
Column(
children: [
const SizedBox(
height: 48,
),
GestureDetector(
onLongPress: () {
Clipboard.setData(ClipboardData(
text: app?.app.additionalSettings['about'] ?? ''));
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(tr('copiedToClipboard')),
));
},
child: Text(
app?.app.additionalSettings['about'],
textAlign: TextAlign.center, textAlign: TextAlign.center,
) style: const TextStyle(fontStyle: FontStyle.italic),
],
),
const SizedBox(
height: 32,
),
Text(
tr('lastUpdateCheckX', args: [
app?.app.lastUpdateCheck == null
? tr('never')
: '\n${app?.app.lastUpdateCheck?.toLocal()}'
]),
textAlign: TextAlign.center,
style: const TextStyle(fontStyle: FontStyle.italic, fontSize: 12),
),
const SizedBox(
height: 48,
),
CategoryEditorSelector(
alignment: WrapAlignment.center,
preselected: app?.app.categories != null
? app!.app.categories.toSet()
: {},
onSelected: (categories) {
if (app != null) {
app.app.categories = categories;
appsProvider.saveApps([app.app]);
}
}),
if (app?.app.additionalSettings['about'] is String &&
app?.app.additionalSettings['about'].isNotEmpty)
Column(
children: [
const SizedBox(
height: 48,
), ),
GestureDetector( )
onLongPress: () { ],
Clipboard.setData(ClipboardData( ),
text: app?.app.additionalSettings['about'] ?? '')); ],
ScaffoldMessenger.of(context).showSnackBar(SnackBar( );
content: Text(tr('copiedToClipboard')), }
));
},
child: Text(
app?.app.additionalSettings['about'],
textAlign: TextAlign.center,
style: const TextStyle(fontStyle: FontStyle.italic),
),
)
],
),
],
);
getFullInfoColumn() => Column( getFullInfoColumn() => Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
@@ -196,11 +196,26 @@ class _AppPageState extends State<AppPage> {
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: Theme.of(context).textTheme.displayLarge, style: Theme.of(context).textTheme.displayLarge,
), ),
Text( GestureDetector(
tr('byX', args: [app?.app.author ?? tr('unknown')]), onTap: () {
textAlign: TextAlign.center, if (app?.app.url != null) {
style: Theme.of(context).textTheme.headlineMedium, launchUrlString(app?.app.url ?? '',
), mode: LaunchMode.externalApplication);
}
},
onLongPress: () {
Clipboard.setData(ClipboardData(text: app?.app.url ?? ''));
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(tr('copiedToClipboard')),
));
},
child: Text(
tr('byX', args: [app?.app.author ?? tr('unknown')]),
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.headlineMedium!.copyWith(
decoration: TextDecoration.underline,
fontStyle: FontStyle.italic),
)),
const SizedBox( const SizedBox(
height: 8, height: 8,
), ),
@@ -209,16 +224,6 @@ class _AppPageState extends State<AppPage> {
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: Theme.of(context).textTheme.labelSmall, style: Theme.of(context).textTheme.labelSmall,
), ),
app?.app.releaseDate == null
? const SizedBox.shrink()
: Text(
app!.app.releaseDate.toString(),
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.labelSmall,
),
const SizedBox(
height: 32,
),
getInfoColumn(), getInfoColumn(),
const SizedBox(height: 150) const SizedBox(height: 150)
], ],
@@ -287,25 +292,6 @@ class _AppPageState extends State<AppPage> {
return row; return row;
}).toList(); }).toList();
items = items.map((row) {
row = row.map((e) {
if (e.key == 'versionDetection' && e is GeneratedFormDropdown) {
e.disabledOptKeys ??= [];
if (app?.app.installedVersion != null &&
app?.app.additionalSettings['versionDetection'] !=
'releaseDateAsVersion' &&
!appsProvider.isVersionDetectionPossible(app)) {
e.disabledOptKeys!.add('standardVersionDetection');
}
if (app?.app.releaseDate == null) {
e.disabledOptKeys!.add('releaseDateAsVersion');
}
}
return e;
}).toList();
return row;
}).toList();
return GeneratedFormModal( return GeneratedFormModal(
title: tr('additionalOptions'), items: items); title: tr('additionalOptions'), items: items);
}); });
@@ -320,26 +306,34 @@ class _AppPageState extends State<AppPage> {
// ignore: use_build_context_synchronously // ignore: use_build_context_synchronously
showMessage(tr('appsFromSourceAreTrackOnly'), context); showMessage(tr('appsFromSourceAreTrackOnly'), context);
} }
if (app.app.additionalSettings['versionDetection'] == var versionDetectionEnabled =
'releaseDateAsVersion') { app.app.additionalSettings['versionDetection'] == true &&
if (originalSettings['versionDetection'] != 'releaseDateAsVersion') { originalSettings['versionDetection'] != true;
if (app.app.releaseDate != null) { var releaseDateVersionEnabled =
bool isUpdated = app.app.additionalSettings['releaseDateAsVersion'] == true &&
app.app.installedVersion == app.app.latestVersion; originalSettings['releaseDateAsVersion'] != true;
app.app.latestVersion = var releaseDateVersionDisabled =
app.app.releaseDate!.microsecondsSinceEpoch.toString(); app.app.additionalSettings['releaseDateAsVersion'] != true &&
if (isUpdated) { originalSettings['releaseDateAsVersion'] == true;
app.app.installedVersion = app.app.latestVersion; if (releaseDateVersionEnabled) {
} if (app.app.releaseDate != null) {
bool isUpdated = app.app.installedVersion == app.app.latestVersion;
app.app.latestVersion =
app.app.releaseDate!.microsecondsSinceEpoch.toString();
if (isUpdated) {
app.app.installedVersion = app.app.latestVersion;
} }
} }
} else if (originalSettings['versionDetection'] == } else if (releaseDateVersionDisabled) {
'releaseDateAsVersion') {
app.app.installedVersion = app.app.installedVersion =
app.installedInfo?.versionName ?? app.app.installedVersion; app.installedInfo?.versionName ?? app.app.installedVersion;
} }
if (versionDetectionEnabled) {
app.app.additionalSettings['versionDetection'] = true;
app.app.additionalSettings['releaseDateAsVersion'] = false;
}
appsProvider.saveApps([app.app]).then((value) { appsProvider.saveApps([app.app]).then((value) {
getUpdate(app.app.id); getUpdate(app.app.id, resetVersion: versionDetectionEnabled);
}); });
} }
} }

View File

@@ -421,7 +421,7 @@ class AppsPageState extends State<AppsPage> {
} }
getVersionText(int appIndex) { getVersionText(int appIndex) {
return '${listedApps[appIndex].app.installedVersion ?? tr('notInstalled')}${listedApps[appIndex].app.additionalSettings['trackOnly'] == true ? ' ${tr('estimateInBrackets')}' : ''}'; return '${listedApps[appIndex].app.installedVersion ?? tr('notInstalled')}${listedApps[appIndex].app.additionalSettings['trackOnly'] == true ? ' ${tr('pseudoVersion')}' : ''}';
} }
getChangesButtonString(int appIndex, bool hasChangeLogFn) { getChangesButtonString(int appIndex, bool hasChangeLogFn) {
@@ -904,7 +904,7 @@ class AppsPageState extends State<AppsPage> {
}))}">${a.name}</a></li>\n'; }))}">${a.name}</a></li>\n';
} }
urls += urls +=
'</ul>\n\n<p><a href="${obtainiumApp.url}">${tr('about')}</a></p>'; '</ul>\n\n<p><a href="$obtainiumUrl">${tr('about')}</a></p>';
Share.share(urls, Share.share(urls,
subject: subject:
'${tr('obtainium')} - ${tr('appsString')}'); '${tr('obtainium')} - ${tr('appsString')}');

View File

@@ -416,13 +416,17 @@ class _SettingsPageState extends State<SettingsPage> {
value: settingsProvider.useSystemFont, value: settingsProvider.useSystemFont,
onChanged: (useSystemFont) { onChanged: (useSystemFont) {
if (useSystemFont) { if (useSystemFont) {
NativeFeatures.loadSystemFont().then((fontLoadRes) { NativeFeatures.loadSystemFont()
.then((fontLoadRes) {
if (fontLoadRes == 'ok') { if (fontLoadRes == 'ok') {
settingsProvider.useSystemFont = true; settingsProvider.useSystemFont =
true;
} else { } else {
showError(ObtainiumError( showError(
tr('systemFontError', args: [fontLoadRes]) ObtainiumError(tr(
), context); 'systemFontError',
args: [fontLoadRes])),
context);
} }
}); });
} else { } else {
@@ -628,38 +632,9 @@ class _SettingsPageState extends State<SettingsPage> {
label: Text(tr('appLogs'))), label: Text(tr('appLogs'))),
], ],
), ),
const Divider( const SizedBox(
height: 32, height: 16,
), )
// Padding(
// padding: const EdgeInsets.fromLTRB(16, 0, 16, 16),
// child: Column(children: [
// Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// Flexible(child: Text(tr('debugMenu'))),
// Switch(
// value: settingsProvider.showDebugOpts,
// onChanged: (value) {
// settingsProvider.showDebugOpts = value;
// })
// ],
// ),
// if (settingsProvider.showDebugOpts)
// Column(
// crossAxisAlignment: CrossAxisAlignment.stretch,
// children: [
// height16,
// TextButton(
// onPressed: () {
// bgUpdateCheck('taskId', null);
// showMessage(tr('bgTaskStarted'), context);
// },
// child: Text(tr('runBgCheckNow')))
// ],
// ),
// ]),
// ),
], ],
), ),
) )

View File

@@ -167,8 +167,24 @@ String hashListOfLists(List<List<int>> data) {
return hash.hashCode.toString(); return hash.hashCode.toString();
} }
Future<String> checkDownloadHash(String url, Future<String> checkPartialDownloadHashDynamc(String url,
{int bytesToGrab = 1024, Map<String, String>? headers}) async { {int startingSize = 1024,
int lowerLimit = 128,
Map<String, String>? headers}) async {
for (int i = startingSize; i >= lowerLimit; i -= 256) {
List<String> ab = await Future.wait([
checkPartialDownloadHash(url, i, headers: headers),
checkPartialDownloadHash(url, i, headers: headers)
]);
if (ab[0] == ab[1]) {
return ab[0];
}
}
throw NoVersionError();
}
Future<String> checkPartialDownloadHash(String url, int bytesToGrab,
{Map<String, String>? headers}) async {
var req = Request('GET', Uri.parse(url)); var req = Request('GET', Uri.parse(url));
if (headers != null) { if (headers != null) {
req.headers.addAll(headers); req.headers.addAll(headers);
@@ -234,6 +250,20 @@ Future<File> downloadFile(
return downloadedFile; return downloadedFile;
} }
Future<PackageInfo?> getInstalledInfo(String? packageName,
{bool printErr = true}) async {
if (packageName != null) {
try {
return await pm.getPackageInfo(packageName: packageName);
} catch (e) {
if (printErr) {
print(e); // OK
}
}
}
return null;
}
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 = {};
@@ -404,7 +434,7 @@ class AppsProvider with ChangeNotifier {
.isNotEmpty; .isNotEmpty;
Future<bool> canInstallSilently(App app) async { Future<bool> canInstallSilently(App app) async {
if (app.id == obtainiumApp.id) { if (app.id == obtainiumId) {
return false; return false;
} }
if (!settingsProvider.enableBackgroundUpdates) { if (!settingsProvider.enableBackgroundUpdates) {
@@ -428,7 +458,7 @@ class AppsProvider with ChangeNotifier {
} catch (e) { } catch (e) {
// Probably not installed - ignore // Probably not installed - ignore
} }
if (installerPackageName != obtainiumApp.id) { if (installerPackageName != obtainiumId) {
// If we did not install the app (or it isn't installed), silent install is not possible // If we did not install the app (or it isn't installed), silent install is not possible
return false; return false;
} }
@@ -639,6 +669,7 @@ class AppsProvider with ChangeNotifier {
MapEntry<String, String>? apkUrl; MapEntry<String, String>? apkUrl;
var trackOnly = apps[id]!.app.additionalSettings['trackOnly'] == true; var trackOnly = apps[id]!.app.additionalSettings['trackOnly'] == true;
if (!trackOnly) { if (!trackOnly) {
// ignore: use_build_context_synchronously
apkUrl = await confirmApkUrl(apps[id]!.app, context); apkUrl = await confirmApkUrl(apps[id]!.app, context);
} }
if (apkUrl != null) { if (apkUrl != null) {
@@ -673,7 +704,7 @@ class AppsProvider with ChangeNotifier {
// Move Obtainium to the end of the line (let all other apps update first) // Move Obtainium to the end of the line (let all other apps update first)
appsToInstall = appsToInstall =
moveStrToEnd(appsToInstall, obtainiumApp.id, strB: obtainiumTempId); moveStrToEnd(appsToInstall, obtainiumId, strB: obtainiumTempId);
Future<void> updateFn(String id, {bool skipInstalls = false}) async { Future<void> updateFn(String id, {bool skipInstalls = false}) async {
try { try {
@@ -775,20 +806,6 @@ class AppsProvider with ChangeNotifier {
return appsDir; return appsDir;
} }
Future<PackageInfo?> getInstalledInfo(String? packageName,
{bool printErr = true}) async {
if (packageName != null) {
try {
return await pm.getPackageInfo(packageName: packageName);
} catch (e) {
if (printErr) {
print(e); // OK
}
}
}
return null;
}
bool isVersionDetectionPossible(AppInMemory? app) { bool isVersionDetectionPossible(AppInMemory? app) {
if (app?.app == null) { if (app?.app == null) {
return false; return false;
@@ -803,8 +820,7 @@ class AppsProvider with ChangeNotifier {
? app.installedInfo?.versionCode.toString() ? app.installedInfo?.versionCode.toString()
: app.installedInfo?.versionName; : app.installedInfo?.versionName;
return app.app.additionalSettings['trackOnly'] != true && return app.app.additionalSettings['trackOnly'] != true &&
app.app.additionalSettings['versionDetection'] != app.app.additionalSettings['releaseDateAsVersion'] != true &&
'releaseDateAsVersion' &&
realInstalledVersion != null && realInstalledVersion != null &&
app.app.installedVersion != null && app.app.installedVersion != null &&
(reconcileVersionDifferences( (reconcileVersionDifferences(
@@ -820,8 +836,7 @@ class AppsProvider with ChangeNotifier {
var modded = false; var modded = false;
var trackOnly = app.additionalSettings['trackOnly'] == true; var trackOnly = app.additionalSettings['trackOnly'] == true;
var versionDetectionIsStandard = var versionDetectionIsStandard =
app.additionalSettings['versionDetection'] == app.additionalSettings['versionDetection'] == true;
'standardVersionDetection';
var naiveStandardVersionDetection = var naiveStandardVersionDetection =
app.additionalSettings['naiveStandardVersionDetection'] == true || app.additionalSettings['naiveStandardVersionDetection'] == true ||
SourceProvider() SourceProvider()
@@ -875,7 +890,7 @@ class AppsProvider with ChangeNotifier {
versionDetectionIsStandard && versionDetectionIsStandard &&
!isVersionDetectionPossible( !isVersionDetectionPossible(
AppInMemory(app, null, installedInfo, null))) { AppInMemory(app, null, installedInfo, null))) {
app.additionalSettings['versionDetection'] = 'noVersionDetection'; app.additionalSettings['versionDetection'] = false;
logs.add('Could not reconcile version formats for: ${app.id}'); logs.add('Could not reconcile version formats for: ${app.id}');
modded = true; modded = true;
} }
@@ -917,6 +932,17 @@ class AppsProvider with ChangeNotifier {
: false; : false;
} }
Future<void> updateInstallStatusInMemory(AppInMemory app) async {
apps[app.app.id]?.installedInfo = await getInstalledInfo(app.app.id);
apps[app.app.id]?.icon =
await apps[app.app.id]?.installedInfo?.applicationInfo?.getAppIcon();
apps[app.app.id]?.app.name = await (apps[app.app.id]
?.installedInfo
?.applicationInfo
?.getAppLabel()) ??
app.name;
}
Future<void> loadApps({String? singleId}) async { Future<void> loadApps({String? singleId}) async {
while (loadingApps) { while (loadingApps) {
await Future.delayed(const Duration(microseconds: 1)); await Future.delayed(const Duration(microseconds: 1));
@@ -965,19 +991,11 @@ class AppsProvider with ChangeNotifier {
NotificationsProvider().notify( NotificationsProvider().notify(
AppsRemovedNotification(errors.map((e) => [e[1], e[2]]).toList())); AppsRemovedNotification(errors.map((e) => [e[1], e[2]]).toList()));
} }
// Get install status and other OS info for each App (slow)
for (var app in apps.values) { await Future.wait(apps.values.map((app) {
// Get install status and other OS info for each App (slow) return updateInstallStatusInMemory(app);
apps[app.app.id]?.installedInfo = await getInstalledInfo(app.app.id); }));
apps[app.app.id]?.icon = notifyListeners();
await apps[app.app.id]?.installedInfo?.applicationInfo?.getAppIcon();
apps[app.app.id]?.app.name = await (apps[app.app.id]
?.installedInfo
?.applicationInfo
?.getAppLabel()) ??
app.name;
notifyListeners();
}
// Reconcile version differences // Reconcile version differences
List<App> modifiedApps = []; List<App> modifiedApps = [];
for (var app in apps.values) { for (var app in apps.values) {
@@ -1000,7 +1018,6 @@ class AppsProvider with ChangeNotifier {
} }
} }
} }
loadingApps = false; loadingApps = false;
notifyListeners(); notifyListeners();
} }
@@ -1676,8 +1693,7 @@ Future<void> bgUpdateCheck(String taskId, Map<String, dynamic>? params) async {
} }
if (toInstall.isNotEmpty) { if (toInstall.isNotEmpty) {
logs.add('BG install task: Started (${toInstall.length}).'); logs.add('BG install task: Started (${toInstall.length}).');
var tempObtArr = var tempObtArr = toInstall.where((element) => element.key == obtainiumId);
toInstall.where((element) => element.key == obtainiumApp.id);
if (tempObtArr.isNotEmpty) { if (tempObtArr.isNotEmpty) {
// Move obtainium to the end of the list as it must always install last // Move obtainium to the end of the list as it must always install last
var obt = tempObtArr.first; var obt = tempObtArr.first;

View File

@@ -15,22 +15,8 @@ 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;
String obtainiumTempId = 'imranr98_obtainium_${GitHub().hosts[0]}'; String obtainiumTempId = 'imranr98_obtainium_${GitHub().hosts[0]}';
String obtainiumId = 'dev.imranr.obtainium';
App obtainiumApp = App( String obtainiumUrl = 'https://github.com/ImranR98/Obtainium';
'dev.imranr.obtainium',
'https://github.com/ImranR98/Obtainium',
'ImranR98',
'Obtainium',
currentReleaseTag,
currentReleaseTag,
[],
0,
{
'includePrereleases': true,
'versionDetection': 'standardVersionDetection'
},
null,
false);
enum InstallMethodSettings { normal, shizuku, root } enum InstallMethodSettings { normal, shizuku, root }

View File

@@ -11,6 +11,7 @@ import 'package:obtainium/app_sources/apkmirror.dart';
import 'package:obtainium/app_sources/apkpure.dart'; import 'package:obtainium/app_sources/apkpure.dart';
import 'package:obtainium/app_sources/aptoide.dart'; import 'package:obtainium/app_sources/aptoide.dart';
import 'package:obtainium/app_sources/codeberg.dart'; import 'package:obtainium/app_sources/codeberg.dart';
import 'package:obtainium/app_sources/directAPKLink.dart';
import 'package:obtainium/app_sources/fdroid.dart'; import 'package:obtainium/app_sources/fdroid.dart';
import 'package:obtainium/app_sources/fdroidrepo.dart'; import 'package:obtainium/app_sources/fdroidrepo.dart';
import 'package:obtainium/app_sources/github.dart'; import 'package:obtainium/app_sources/github.dart';
@@ -103,6 +104,21 @@ appJSONCompatibilityModifiers(Map<String, dynamic> json) {
additionalSettings.remove('releaseDateAsVersion'); additionalSettings.remove('releaseDateAsVersion');
} }
} }
// Convert dropdown style version detection options back into bool style
if (additionalSettings['versionDetection'] == 'standardVersionDetection') {
additionalSettings['versionDetection'] = true;
} else if (additionalSettings['versionDetection'] == 'noVersionDetection') {
additionalSettings['versionDetection'] = false;
} else if (additionalSettings['versionDetection'] == 'releaseDateAsVersion') {
additionalSettings['versionDetection'] = false;
additionalSettings['releaseDateAsVersion'] = true;
}
// Convert bool style pseudo version method to dropdown style
if (originalAdditionalSettings['supportFixedAPKURL'] == true) {
additionalSettings['defaultPseudoVersioningMethod'] = 'partialAPKHash';
} else if (originalAdditionalSettings['supportFixedAPKURL'] == false) {
additionalSettings['defaultPseudoVersioningMethod'] = 'APKLinkHash';
}
// Ensure additionalSettings are correctly typed // Ensure additionalSettings are correctly typed
for (var item in formItems) { for (var item in formItems) {
if (additionalSettings[item.key] != null) { if (additionalSettings[item.key] != null) {
@@ -380,28 +396,24 @@ abstract class AppSource {
bool allowSubDomains = false; bool allowSubDomains = false;
bool naiveStandardVersionDetection = false; bool naiveStandardVersionDetection = false;
bool neverAutoSelect = false; bool neverAutoSelect = false;
bool showReleaseDateAsVersionToggle = false;
bool versionDetectionDisallowed = false;
List<String> excludeCommonSettingKeys = [];
AppSource() { AppSource() {
name = runtimeType.toString(); name = runtimeType.toString();
} }
overrideVersionDetectionFormDefault(String vd, overrideAdditionalAppSpecificSourceAgnosticSettingSwitch(String key,
{bool disableStandard = false, bool disableRelDate = false}) { {bool disabled = true, bool defaultValue = true}) {
additionalAppSpecificSourceAgnosticSettingFormItems = additionalAppSpecificSourceAgnosticSettingFormItemsNeverUseDirectly =
additionalAppSpecificSourceAgnosticSettingFormItems.map((e) { additionalAppSpecificSourceAgnosticSettingFormItemsNeverUseDirectly
.map((e) {
return e.map((e2) { return e.map((e2) {
if (e2.key == 'versionDetection') { if (e2.key == key) {
var item = e2 as GeneratedFormDropdown; var item = e2 as GeneratedFormSwitch;
item.defaultValue = vd; item.disabled = disabled;
item.disabledOptKeys = []; item.defaultValue = defaultValue;
if (disableStandard) {
item.disabledOptKeys?.add('standardVersionDetection');
}
if (disableRelDate) {
item.disabledOptKeys?.add('releaseDateAsVersion');
}
item.disabledOptKeys =
item.disabledOptKeys?.where((element) => element != vd).toList();
} }
return e2; return e2;
}).toList(); }).toList();
@@ -457,7 +469,7 @@ abstract class AppSource {
// Some additional data may be needed for Apps regardless of Source // Some additional data may be needed for Apps regardless of Source
List<List<GeneratedFormItem>> List<List<GeneratedFormItem>>
additionalAppSpecificSourceAgnosticSettingFormItems = [ additionalAppSpecificSourceAgnosticSettingFormItemsNeverUseDirectly = [
[ [
GeneratedFormSwitch( GeneratedFormSwitch(
'trackOnly', 'trackOnly',
@@ -475,16 +487,8 @@ abstract class AppSource {
label: tr('matchGroupToUse'), required: false, hint: '\$0') label: tr('matchGroupToUse'), required: false, hint: '\$0')
], ],
[ [
GeneratedFormDropdown( GeneratedFormSwitch('versionDetection',
'versionDetection', label: tr('versionDetectionExplanation'), defaultValue: true)
[
MapEntry(
'standardVersionDetection', tr('standardVersionDetection')),
MapEntry('releaseDateAsVersion', tr('releaseDateAsVersion')),
MapEntry('noVersionDetection', tr('noVersionDetection'))
],
label: tr('versionDetection'),
defaultValue: 'standardVersionDetection')
], ],
[ [
GeneratedFormSwitch('useVersionCodeAsOSVersion', GeneratedFormSwitch('useVersionCodeAsOSVersion',
@@ -500,6 +504,11 @@ abstract class AppSource {
} }
]) ])
], ],
[
GeneratedFormSwitch('invertAPKFilter',
label: '${tr('invertRegEx')} (${tr('filterAPKsByRegEx')})',
defaultValue: false)
],
[ [
GeneratedFormSwitch('autoApkFilterByArch', GeneratedFormSwitch('autoApkFilterByArch',
label: tr('autoApkFilterByArch'), defaultValue: true) label: tr('autoApkFilterByArch'), defaultValue: true)
@@ -518,9 +527,48 @@ 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
List<List<GeneratedFormItem>> get combinedAppSpecificSettingFormItems { List<List<GeneratedFormItem>> get combinedAppSpecificSettingFormItems {
if (showReleaseDateAsVersionToggle == true) {
if (additionalAppSpecificSourceAgnosticSettingFormItemsNeverUseDirectly
.indexWhere((List<GeneratedFormItem> e) =>
e.indexWhere((GeneratedFormItem i) =>
i.key == 'releaseDateAsVersion') >=
0) <
0) {
additionalAppSpecificSourceAgnosticSettingFormItemsNeverUseDirectly.insert(
additionalAppSpecificSourceAgnosticSettingFormItemsNeverUseDirectly
.indexWhere((List<GeneratedFormItem> e) =>
e.indexWhere((GeneratedFormItem i) =>
i.key == 'versionDetection') >=
0) +
1,
[
GeneratedFormSwitch('releaseDateAsVersion',
label:
'${tr('releaseDateAsVersion')} (${tr('pseudoVersion')})',
defaultValue: false)
]);
}
}
additionalAppSpecificSourceAgnosticSettingFormItemsNeverUseDirectly =
additionalAppSpecificSourceAgnosticSettingFormItemsNeverUseDirectly
.map((e) => e
.where((ee) => !excludeCommonSettingKeys.contains(ee.key))
.toList())
.where((e) => e.isNotEmpty)
.toList();
if (versionDetectionDisallowed) {
overrideAdditionalAppSpecificSourceAgnosticSettingSwitch(
'versionDetection',
disabled: true,
defaultValue: false);
overrideAdditionalAppSpecificSourceAgnosticSettingSwitch(
'useVersionCodeAsOSVersion',
disabled: true,
defaultValue: false);
}
return [ return [
...additionalSourceAppSpecificSettingFormItems, ...additionalSourceAppSpecificSettingFormItems,
...additionalAppSpecificSourceAgnosticSettingFormItems ...additionalAppSpecificSourceAgnosticSettingFormItemsNeverUseDirectly
]; ];
} }
@@ -665,6 +713,20 @@ String? extractVersion(String? versionExtractionRegEx, String? matchGroupString,
} }
} }
List<MapEntry<String, String>> filterApks(
List<MapEntry<String, String>> apkUrls,
String? apkFilterRegEx,
bool? invert) {
if (apkFilterRegEx?.isNotEmpty == true) {
var reg = RegExp(apkFilterRegEx!);
apkUrls = apkUrls.where((element) {
var hasMatch = reg.hasMatch(element.key);
return invert == true ? !hasMatch : hasMatch;
}).toList();
}
return apkUrls;
}
class SourceProvider { class SourceProvider {
// Add more source classes here so they are available via the service // Add more source classes here so they are available via the service
List<AppSource> get sources => [ List<AppSource> get sources => [
@@ -687,6 +749,7 @@ class SourceProvider {
WhatsApp(), WhatsApp(),
TelegramApp(), TelegramApp(),
NeutronCode(), NeutronCode(),
DirectAPKLink(),
HTML() // This should ALWAYS be the last option as they are tried in order HTML() // This should ALWAYS be the last option as they are tried in order
]; ];
@@ -708,11 +771,15 @@ class SourceProvider {
} }
AppSource? source; AppSource? source;
for (var s in sources.where((element) => element.hosts.isNotEmpty)) { for (var s in sources.where((element) => element.hosts.isNotEmpty)) {
if (RegExp( try {
'://${s.allowSubDomains ? '([^\\.]+\\.)*' : '(www\\.)?'}(${getSourceRegex(s.hosts)})(/|\\z)?') if (RegExp(
.hasMatch(url)) { '^${s.allowSubDomains ? '([^\\.]+\\.)*' : '(www\\.)?'}(${getSourceRegex(s.hosts)})\$')
source = s; .hasMatch(Uri.parse(url).host)) {
break; source = s;
break;
}
} catch (e) {
// Ignore
} }
} }
if (source == null) { if (source == null) {
@@ -773,15 +840,12 @@ class SourceProvider {
} }
} }
if (additionalSettings['versionDetection'] == 'releaseDateAsVersion' && if (additionalSettings['releaseDateAsVersion'] == true &&
apk.releaseDate != null) { apk.releaseDate != null) {
apk.version = apk.releaseDate!.microsecondsSinceEpoch.toString(); apk.version = apk.releaseDate!.microsecondsSinceEpoch.toString();
} }
if (additionalSettings['apkFilterRegEx'] != null) { apk.apkUrls = filterApks(apk.apkUrls, additionalSettings['apkFilterRegEx'],
var reg = RegExp(additionalSettings['apkFilterRegEx']); additionalSettings['invertAPKFilter']);
apk.apkUrls =
apk.apkUrls.where((element) => reg.hasMatch(element.key)).toList();
}
if (apk.apkUrls.isEmpty && !trackOnly) { if (apk.apkUrls.isEmpty && !trackOnly) {
throw NoAPKError(); throw NoAPKError();
} }

View File

@@ -307,10 +307,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: flutter_local_notifications name: flutter_local_notifications
sha256: "892ada16046d641263f30c72e7432397088810a84f34479f6677494802a2b535" sha256: "66cc2fe16bf4bca71d795939763ad3f1830ad85772dc3b1561613c501859826d"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "16.3.0" version: "16.3.1+1"
flutter_local_notifications_linux: flutter_local_notifications_linux:
dependency: transitive dependency: transitive
description: description:
@@ -394,10 +394,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: http name: http
sha256: d4872660c46d929f6b8a9ef4e7a7eff7e49bbf0c4ec3f385ee32df5119175139 sha256: a2bbf9d017fcced29139daa8ed2bba4ece450ab222871df93ca9eec6f80c34ba
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.2" version: "1.2.0"
http_parser: http_parser:
dependency: transitive dependency: transitive
description: description:
@@ -450,10 +450,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: markdown name: markdown
sha256: acf35edccc0463a9d7384e437c015a3535772e09714cf60e07eeef3a15870dcd sha256: "1b134d9f8ff2da15cb298efe6cd8b7d2a78958c1b00384ebcbdf13fe340a6c90"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "7.1.1" version: "7.2.1"
matcher: matcher:
dependency: transitive dependency: transitive
description: description:
@@ -562,50 +562,50 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: permission_handler name: permission_handler
sha256: "860c6b871c94c78e202dc69546d4d8fd84bd59faeb36f8fb9888668a53ff4f78" sha256: "45ff3fbcb99040fde55c528d5e3e6ca29171298a85436274d49c6201002087d6"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "11.1.0" version: "11.2.0"
permission_handler_android: permission_handler_android:
dependency: transitive dependency: transitive
description: description:
name: permission_handler_android name: permission_handler_android
sha256: "2f1bec180ee2f5665c22faada971a8f024761f632e93ddc23310487df52dcfa6" sha256: "758284a0976772f9c744d6384fc5dc4834aa61e3f7aa40492927f244767374eb"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "12.0.1" version: "12.0.3"
permission_handler_apple: permission_handler_apple:
dependency: transitive dependency: transitive
description: description:
name: permission_handler_apple name: permission_handler_apple
sha256: "1a816084338ada8d574b1cb48390e6e8b19305d5120fe3a37c98825bacc78306" sha256: c6bf440f80acd2a873d3d91a699e4cc770f86e7e6b576dda98759e8b92b39830
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "9.2.0" version: "9.3.0"
permission_handler_html: permission_handler_html:
dependency: transitive dependency: transitive
description: description:
name: permission_handler_html name: permission_handler_html
sha256: "11b762a8c123dced6461933a88ea1edbbe036078c3f9f41b08886e678e7864df" sha256: "54bf176b90f6eddd4ece307e2c06cf977fb3973719c35a93b85cc7093eb6070d"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.1.0+2" version: "0.1.1"
permission_handler_platform_interface: permission_handler_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: permission_handler_platform_interface name: permission_handler_platform_interface
sha256: d87349312f7eaf6ce0adaf668daf700ac5b06af84338bd8b8574dfbd93ffe1a1 sha256: "5c43148f2bfb6d14c5a8162c0a712afe891f2d847f35fcff29c406b37da43c3c"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.0.2" version: "4.1.0"
permission_handler_windows: permission_handler_windows:
dependency: transitive dependency: transitive
description: description:
name: permission_handler_windows name: permission_handler_windows
sha256: "1e8640c1e39121128da6b816d236e714d2cf17fac5a105dd6acdd3403a628004" sha256: "1a790728016f79a41216d88672dbc5df30e686e811ad4e698bfc51f76ad91f1e"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.2.0" version: "0.2.1"
petitparser: petitparser:
dependency: transitive dependency: transitive
description: description:
@@ -634,10 +634,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: pointycastle name: pointycastle
sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c" sha256: "43ac87de6e10afabc85c445745a7b799e04de84cebaa4fd7bf55a5e1e9604d29"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.7.3" version: "3.7.4"
provider: provider:
dependency: "direct main" dependency: "direct main"
description: description:
@@ -943,10 +943,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: webview_flutter_wkwebview name: webview_flutter_wkwebview
sha256: "4d062ad505390ecef1c4bfb6001cd857a51e00912cc9dfb66edb1886a9ebd80c" sha256: b99ca8d8bae9c6b43d568218691aa537fb0aeae1d7d34eadf112a6aa36d26506
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.10.2" version: "3.11.0"
win32: win32:
dependency: transitive dependency: transitive
description: description:
@@ -988,5 +988,5 @@ packages:
source: hosted source: hosted
version: "3.1.2" version: "3.1.2"
sdks: sdks:
dart: ">=3.2.0 <4.0.0" dart: ">=3.2.3 <4.0.0"
flutter: ">=3.16.0" flutter: ">=3.16.6"

View File

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