Compare commits

...

74 Commits

Author SHA1 Message Date
Imran
3e23fffaea Merge pull request #1725 from ImranR98/dev
- Attempt bugfix for error when on VPN (#1120)
- Translation fixes (#1699)
- GitHub search bugfix (#1705)
- Fix missing trailing slash for path-less URLs (#1715)
- Rename Codeberg to Forgejo (#1722)
- Rename "Version String Extraction" to "Trim Version String" for non-HTML Sources (#1723)
2024-07-14 20:56:22 -04:00
Imran Remtulla
624b9fb6dc Update packages, increment version 2024-07-14 20:50:48 -04:00
Imran Remtulla
fbd6189721 GitHub search bugfix (#1705) 2024-07-14 20:42:20 -04:00
Imran Remtulla
6a44fe227c Fix missing trailing slash for path-less URLs (#1715) 2024-07-14 20:27:42 -04:00
Imran Remtulla
d1cb2688c6 Rename "Version String Extraction" to "Trim Version String" for non-HTML Sources (#1723)
Rename Codeberg to Forgejo (#1722)
2024-07-14 20:20:41 -04:00
Imran
b43b2f9740 Merge pull request #1720 from Erudaro/main
Update bs.json
2024-07-14 02:08:43 -04:00
Imran
6288a9cb8d Merge pull request #1710 from DwainZwerg/for-eXense-auth-Update-ru.json-see-#1703](https/github.com/ImranR98/Obtainium/issues/1703)
for eXense-auth: Update ru.json (issue#1703)
2024-07-14 02:08:31 -04:00
Erudaro
18c6f75054 Update bs.json 2024-07-13 23:56:33 +00:00
DwainZwerg
1f8d187b84 Update ru.json
see [#1703](https://github.com/ImranR98/Obtainium/issues/1703)
2024-07-07 12:13:07 +02:00
Imran Remtulla
77618ad1ff Merge remote-tracking branch 'origin/main' into dev 2024-06-30 13:02:43 -04:00
Imran
75efd335e9 Update release.yml 2024-06-30 12:56:28 -04:00
Imran
c4438de200 Update release.yml 2024-06-30 12:55:38 -04:00
Imran Remtulla
e3c9a227d3 Translation fixes 2024-06-29 17:04:34 -04:00
Imran Remtulla
548f859349 Merge remote-tracking branch 'origin/main' into dev 2024-06-29 16:49:16 -04:00
Imran Remtulla
db413badec Attempt bugfix for error when on VPN (#1120) 2024-06-29 16:48:59 -04:00
Imran
dfac3af3f5 Merge pull request #1698 from ImranR98/dev
Bugfix for files with vague 'content-disposition' header (#1697)
2024-06-29 03:03:36 -04:00
Imran Remtulla
5eceaeecde Increment version, run dart fix 2024-06-29 03:02:56 -04:00
Imran Remtulla
62c23004f7 Bugfix for files with vague 'content-disposition' header (#1697) 2024-06-29 03:01:48 -04:00
Imran
cd153e7d11 Merge pull request #1696 from ImranR98/dev
- Bugfix: Pull to refresh not working with few apps (#1680)
- Add third-party F-Droid repo search to main search menu (#1681)
- Added autocomplete for F-Droid repos (#1681)
- Bugfix: Missing request headers for direct APK link apps (#1688)
- Release asset download confirmation even for single choice (#1694)
- Add a less obvious touch target to highlights (#1694)
2024-06-28 23:03:14 -04:00
Imran Remtulla
3b494511d7 Merge remote-tracking branch 'origin/main' into dev 2024-06-28 22:54:15 -04:00
Imran
6c806a44d4 Merge pull request #1676 from abc0922001/patch-1
add Traditional Chinese translation
2024-06-28 22:54:01 -04:00
Imran
c5bac43bfd Merge pull request #1673 from AntoninDelFabbro/patch-1
(following d8c805a + #1670) Undone a mistake
2024-06-28 22:53:52 -04:00
Imran
1636281d6d Merge pull request #1674 from catsnote/main
Improved Danish Translation
2024-06-28 22:53:46 -04:00
Imran
0f4feb2da6 Merge pull request #1682 from CertainBot/patch-4
Update es.json
2024-06-28 22:53:23 -04:00
Imran Remtulla
c32f34c116 Update packages, increment version 2024-06-28 22:52:24 -04:00
Imran Remtulla
d391c5cfc2 Bugfix: Missing request headers for direct APK link apps (#1688) 2024-06-28 22:50:43 -04:00
Imran Remtulla
bb45a157b3 Add a less obvious touch target to highlights (#1694) 2024-06-28 22:29:34 -04:00
Imran Remtulla
c90a571f89 Release asset download confirmation even for single choice (#1694) 2024-06-28 22:12:45 -04:00
Imran Remtulla
1278407c90 Slight spacing change 2024-06-28 22:04:21 -04:00
Imran Remtulla
dff1b4cf39 Bugfixes for F-Droid repo search (#1681) 2024-06-28 21:55:13 -04:00
Imran Remtulla
105e70a814 F-Droid repo search bugfix (#1681) 2024-06-28 21:28:02 -04:00
Imran Remtulla
2938cea419 Added autocomplete for F-Droid repos (#1681) 2024-06-28 21:03:53 -04:00
Imran Remtulla
9b6b7780d8 Fix F-Droid repo search bugs (#1681) 2024-06-28 20:11:43 -04:00
Imran Remtulla
f53a4f3827 Add third-party F-Droid repo search to main search menu (#1681) 2024-06-28 19:10:45 -04:00
Imran Remtulla
9b0d672553 Bugfix: Pull to refresh not working with few apps (#1680) 2024-06-28 18:51:02 -04:00
CertainBot
9d14145ac2 Update es.json
- English: corrected a few typos and wrong translations
- Español: corregidas faltas y errores de traducción
2024-06-19 19:31:58 +00:00
abc0922001
9948797b25 Create zh-TW.json
add Traditional Chinese translation
2024-06-17 13:08:26 +08:00
cat
a80d9e3623 Improved assets/translations/da.json 2024-06-16 20:22:03 +02:00
Antonin Del Fabbro
37ecb057f9 Undone a mistake 2024-06-15 22:19:42 +02:00
Imran
06cbe74c6c Merge pull request #1672 from ImranR98/dev
- Add release date extraction for track-only GitLab and Codeberg apps (#1664)
- Add a scrollbar to the apps page
2024-06-15 02:00:30 -04:00
Imran Remtulla
f5769b85fe Add release date extraction for track-only GitLab and Codeberg apps (#1664) 2024-06-15 01:58:07 -04:00
Imran Remtulla
875868af47 Added DA to the language menu 2024-06-15 01:21:31 -04:00
Imran Remtulla
24ea15d600 Merge remote-tracking branch 'origin/main' into dev 2024-06-15 01:20:23 -04:00
Imran
87cdc3dcef Merge pull request #1657 from Grooty12/main
Add da.json
2024-06-15 01:20:01 -04:00
Imran
c2f976d7f4 Merge pull request #1670 from AntoninDelFabbro/patch-1
Reworked french translation
2024-06-15 01:19:50 -04:00
Imran Remtulla
ebc46bfd3f Update Flutter submodule 2024-06-15 01:19:33 -04:00
Imran Remtulla
e674f7e89d Merge remote-tracking branch 'origin/main' into dev 2024-06-15 01:19:13 -04:00
Imran Remtulla
86d29b163c Update packages, increment version 2024-06-15 01:19:06 -04:00
Imran Remtulla
a849919799 Add a scrollbar to the apps page 2024-06-15 01:18:50 -04:00
Antonin Del Fabbro
d8c805a6b3 Reworked french translation 2024-06-12 23:07:57 +02:00
Antonin Del Fabbro
8acbd3ef78 "Material You" shouldn't be translated 2024-06-12 20:43:50 +02:00
Rasmus Rosendahl-Kaa
b81088d767 Add danish translation 2024-06-05 14:33:22 +02:00
Imran
7071e34a74 Merge pull request #1643 from ImranR98/dev
- Bugfix: Include GitLab token in APK request (#1622)
- Bugfix: Don't trim trailing slashes when parsing links (#1625)
- Improve contrast of placeholder icon in dark mode (#1637) 
- Improve app loading times
- Revert a previous change to background downloads
- Add a "clear logs" button
2024-05-24 16:27:18 -04:00
Imran Remtulla
6a73ade359 Add a "clear logs" button 2024-05-23 21:18:13 -04:00
Imran Remtulla
6c5e5043a4 Improve icon loading after last commit 2024-05-23 21:02:50 -04:00
Imran Remtulla
5edaf1306d Update packages + Flutter, increment version 2024-05-23 20:17:44 -04:00
Imran Remtulla
5bf7fdb94e Revert a previous change related to BG downloads (did not work as intended) 2024-05-23 20:15:25 -04:00
Imran Remtulla
7808bc5ccb Improve loading time/stability (at the cost of icon flickering) 2024-05-23 20:02:43 -04:00
Imran Remtulla
06a079e452 Attempt to improve load times again + link parsing bugfix (#1625) 2024-05-23 19:35:52 -04:00
Imran Remtulla
de509737e6 Include GitLab token in APK request (#1622) 2024-05-22 19:51:35 -04:00
Imran Remtulla
08a3ba8d13 Merge remote-tracking branch 'origin/main' into dev 2024-05-22 19:37:30 -04:00
Imran
2b27902d5f Merge pull request #1633 from teaminh/main
Update vi.json
2024-05-22 19:37:16 -04:00
Imran Remtulla
62185127c2 Merge remote-tracking branch 'origin/main' into dev 2024-05-22 19:36:53 -04:00
Imran Remtulla
9c46e3f88c Attempt to improve app load time
Slight icon opacity tweak (#1637)
2024-05-22 19:35:51 -04:00
teaminh
daa4de921d Update vi.json 2024-05-19 12:20:28 +07:00
teaminh
bc977e2a5a Update vi.json 2024-05-19 12:09:36 +07:00
Imran
1e3815ca20 Merge pull request #1631 from ImranR98/dev
- Don't use partial downloads for BG tasks (more reliable)
- More accurate error reports for Huawei AppGallery fails
- Various bugfixes
- Update Flutter
2024-05-17 22:35:12 -04:00
Imran Remtulla
0e2fa96b9f More accurate error reports for Huawei AppGallery fails 2024-05-17 16:17:51 -04:00
Imran Remtulla
389aebe54e Various bugfixes 2024-05-17 15:56:41 -04:00
Imran Remtulla
fbfeaf2a91 Update Flutter, packages, increment version 2024-05-16 22:31:21 -04:00
Imran Remtulla
485812d076 Merge remote-tracking branch 'origin/main' into dev 2024-05-16 22:21:58 -04:00
Imran Remtulla
68e98ec719 Don't use partial downloads for BG tasks (more reliable) 2024-05-16 22:21:52 -04:00
Imran
cbe41de734 Merge pull request #1620 from mxhdee/main
Update fa.json
2024-05-16 22:11:23 -04:00
Mxhdee
abb8641105 Update fa.json 2024-05-13 18:46:01 -04:00
45 changed files with 1657 additions and 484 deletions

View File

@@ -6,7 +6,10 @@ on:
beta: beta:
type: boolean type: boolean
description: Is beta? description: Is beta?
draft:
type: boolean
description: Is draft?
jobs: jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -35,13 +38,7 @@ jobs:
- name: Check submodule - name: Check submodule
id: check_submodule id: check_submodule
run: | run: |
SUBMODULE_COMMIT_LONG="$(git submodule status | head -1 | tail -c +2 | awk '{print $1}')" git checkout ${{ inputs.checkout }}
FLUTTER_COMMIT_SHORT="$(flutter --version | head -2 | tail -1 | awk '{print $4}')"
echo "SUBMODULE_COMMIT_LONG=$SUBMODULE_COMMIT_LONG, FLUTTER_COMMIT_SHORT=$FLUTTER_COMMIT_SHORT"
if ! [[ "$SUBMODULE_COMMIT_LONG" =~ ^$FLUTTER_COMMIT_SHORT ]]; then
echo "Your submodule has not been updated!"
exit 1
fi
- name: Extract Version - name: Extract Version
id: extract_version id: extract_version
@@ -92,5 +89,6 @@ jobs:
token: ${{ secrets.GH_ACCESS_TOKEN }} token: ${{ secrets.GH_ACCESS_TOKEN }}
tag: "${{ steps.extract_version.outputs.tag }}" tag: "${{ steps.extract_version.outputs.tag }}"
prerelease: "${{ steps.extract_version.outputs.beta }}" prerelease: "${{ steps.extract_version.outputs.beta }}"
draft: "${{ inputs.draft }}"
artifacts: ./build/app/outputs/flutter-apk/*-release*.apk* artifacts: ./build/app/outputs/flutter-apk/*-release*.apk*
generateReleaseNotes: true generateReleaseNotes: true

View File

@@ -16,7 +16,7 @@ Currently supported App sources:
- Open Source - General: - Open Source - General:
- [GitHub](https://github.com/) - [GitHub](https://github.com/)
- [GitLab](https://gitlab.com/) - [GitLab](https://gitlab.com/)
- [Codeberg](https://codeberg.org/) - [Forgejo](https://forgejo.org/) ([Codeberg](https://codeberg.org/))
- [F-Droid](https://f-droid.org/) - [F-Droid](https://f-droid.org/)
- Third Party F-Droid Repos - Third Party F-Droid Repos
- [IzzyOnDroid](https://android.izzysoft.de/) - [IzzyOnDroid](https://android.izzysoft.de/)

View File

@@ -24,7 +24,7 @@
"colour": "Boja", "colour": "Boja",
"standard": "Standard", "standard": "Standard",
"custom": "Custom", "custom": "Custom",
"useMaterialYou": "Use Material You", "useMaterialYou": "Koristi Material You temu",
"githubStarredRepos": "GitHub repo-i sa zvjezdicom", "githubStarredRepos": "GitHub repo-i sa zvjezdicom",
"uname": "Korisničko ime", "uname": "Korisničko ime",
"wrongArgNum": "Naveden je pogrešan broj argumenata", "wrongArgNum": "Naveden je pogrešan broj argumenata",
@@ -113,7 +113,7 @@
"dark": "Tamna", "dark": "Tamna",
"light": "Svijetla", "light": "Svijetla",
"followSystem": "Pratite sistem", "followSystem": "Pratite sistem",
"followSystemThemeExplanation": "Following system theme is possible only by using third-party applications", "followSystemThemeExplanation": "Praćenje sistemske teme je moguće jedino koristeći aplikacije treće strane",
"useBlackTheme": "Koristite čisto crnu tamnu temu", "useBlackTheme": "Koristite čisto crnu tamnu temu",
"appSortBy": "Aplikacije sortirane po", "appSortBy": "Aplikacije sortirane po",
"authorName": "Autor/Ime", "authorName": "Autor/Ime",
@@ -147,10 +147,10 @@
"noNewUpdates": "Nema novih ažuriranja.", "noNewUpdates": "Nema novih ažuriranja.",
"xHasAnUpdate": "{} ima ažuriranje.", "xHasAnUpdate": "{} ima ažuriranje.",
"appsUpdated": "Aplikacije su ažurirane", "appsUpdated": "Aplikacije su ažurirane",
"appsNotUpdated": "Failed to update applications", "appsNotUpdated": "Neuspješno ažuriranje aplikacija",
"appsUpdatedNotifDescription": "Obavještava korisnika da su u pozadini primijenjena ažuriranja na jednu ili više aplikacija", "appsUpdatedNotifDescription": "Obavještava korisnika da su u pozadini primijenjena ažuriranja na jednu ili više aplikacija",
"xWasUpdatedToY": "{} je ažuriran na {}.", "xWasUpdatedToY": "{} je ažuriran na {}.",
"xWasNotUpdatedToY": "Failed to update {} to {}.", "xWasNotUpdatedToY": "Neuspješno ažuriranje {} na {}.",
"errorCheckingUpdates": "Greška pri provjeri ažuriranja", "errorCheckingUpdates": "Greška pri provjeri ažuriranja",
"errorCheckingUpdatesNotifDescription": "Obavijest koja se prikazuje kada provjera sigurnosnog ažuriranja ne uspije", "errorCheckingUpdatesNotifDescription": "Obavijest koja se prikazuje kada provjera sigurnosnog ažuriranja ne uspije",
"appsRemoved": "Aplikacije su uklonjene", "appsRemoved": "Aplikacije su uklonjene",
@@ -191,7 +191,7 @@
"downloadingX": "Preuzimanje {}", "downloadingX": "Preuzimanje {}",
"downloadX": "Download {}", "downloadX": "Download {}",
"downloadedX": "Downloaded {}", "downloadedX": "Downloaded {}",
"releaseAsset": "Release Asset", "releaseAsset": "Fajlovi verzije",
"downloadNotifDescription": "Obavještava korisnika o napretku u preuzimanju aplikacije", "downloadNotifDescription": "Obavještava korisnika o napretku u preuzimanju aplikacije",
"noAPKFound": "APK nije pronađen", "noAPKFound": "APK nije pronađen",
"noVersionDetection": "Nema detekcije verzije", "noVersionDetection": "Nema detekcije verzije",
@@ -253,12 +253,14 @@
"verifyLatestTag": "Provjerite 'posljednu' ('latest') oznaku", "verifyLatestTag": "Provjerite 'posljednu' ('latest') oznaku",
"intermediateLinkRegex": "Filter za 'srednju' vezu za posjetu", "intermediateLinkRegex": "Filter za 'srednju' vezu za posjetu",
"filterByLinkText": "Filtriraj linkove prema tekstu linka", "filterByLinkText": "Filtriraj linkove prema tekstu linka",
"intermediateLinkNotFound": "Intermediate link nije nađen", "intermediateLinkNotFound": "Intermediate veza nije nađena",
"intermediateLink": "srednja karika", "intermediateLink": "Intermediate veza",
"exemptFromBackgroundUpdates": "Izuzmi iz ažuriranja u pozadini (ako su uključeni)", "exemptFromBackgroundUpdates": "Izuzmi iz ažuriranja u pozadini (ako su uključeni)",
"bgUpdatesOnWiFiOnly": "Isključite ažuriranje u pozadini kada niste na WiFi-ju", "bgUpdatesOnWiFiOnly": "Isključite ažuriranje u pozadini kada niste na WiFi-ju",
"autoSelectHighestVersionCode": "Automatski izaberite najveću (verziju) versionCode APK-a", "autoSelectHighestVersionCode": "Automatski izaberite najveću (verziju) versionCode APK-a",
"versionExtractionRegEx": "RegEx ekstrakcija verzije", "versionExtractionRegEx": "RegEx ekstrakcija verzije",
"trimVersionString": "Trim Version String With RegEx",
"matchGroupToUseForX": "Match Group to Use for \"{}\"",
"matchGroupToUse": "Podjesite grupu za upotebu", "matchGroupToUse": "Podjesite grupu za upotebu",
"highlightTouchTargets": "Istaknite manje vidljive touch mete", "highlightTouchTargets": "Istaknite manje vidljive touch mete",
"pickExportDir": "Izaberite datoteku za izvoz", "pickExportDir": "Izaberite datoteku za izvoz",
@@ -288,11 +290,11 @@
"supportFixedAPKURL": "Podržite fiksne APK URL-ove", "supportFixedAPKURL": "Podržite fiksne APK URL-ove",
"selectX": "Izaberite {}", "selectX": "Izaberite {}",
"parallelDownloads": "Dozvoli paralelna preuzimanja", "parallelDownloads": "Dozvoli paralelna preuzimanja",
"useShizuku": "Use Shizuku or Sui to install", "useShizuku": "Koristi Shizuku ili Sui za instaliranje",
"shizukuBinderNotFound": "Shizuku is not running", "shizukuBinderNotFound": "Shizuku nije pokrenut",
"shizukuOld": "Old Shizuku version (<11) - update it", "shizukuOld": "Stara Shizuku verzija (<11) - ažurirajte je",
"shizukuOldAndroidWithADB": "Shizuku running on Android < 8.1 with ADB - update Android or use Sui instead", "shizukuOldAndroidWithADB": "Shizuku pokrenut na Android-u < 8.1 pomoću ADB-a - ažurirajte Android ili koristite Sui",
"shizukuPretendToBeGooglePlay": "Set Google Play as the installation source (if Shizuku is used)", "shizukuPretendToBeGooglePlay": "Postavi Google Play kao izvor instalacije (samo ako je Shizuku u upotrebi)",
"useSystemFont": "Koristite sistemski font", "useSystemFont": "Koristite sistemski font",
"useVersionCodeAsOSVersion": "Koristite kod verzije aplikacije kao verziju koju je otkrio OS", "useVersionCodeAsOSVersion": "Koristite kod verzije aplikacije kao verziju koju je otkrio OS",
"requestHeader": "Zaglavlje zahtjeva", "requestHeader": "Zaglavlje zahtjeva",
@@ -305,13 +307,13 @@
"installed": "Instalirano", "installed": "Instalirano",
"latest": "Najnoviji", "latest": "Najnoviji",
"invertRegEx": "Obrni regularni izraz", "invertRegEx": "Obrni regularni izraz",
"note": "Note", "note": "Zabelješke",
"selfHostedNote": "The \"{}\" dropdown can be used to reach self-hosted/custom instances of any source.", "selfHostedNote": "\"{}\" padajući meni se može koristiti da dosegnete vlastite/prilagođene instance bilo kojeg izvora.",
"badDownload": "The APK could not be parsed (incompatible or partial download)", "badDownload": "APK ne može biti raščlanjen (nekomaptibilno ili delimično preuzimanje)",
"beforeNewInstallsShareToAppVerifier": "Share new Apps with AppVerifier (if available)", "beforeNewInstallsShareToAppVerifier": "Dijeli nove aplikacije sa AppVerifier-om (ako je dostupno)",
"appVerifierInstructionToast": "Share to AppVerifier, then return here when ready.", "appVerifierInstructionToast": "Dijeli sa AppVerifier-om, zatim se vratite kada ste spremni.",
"wiki": "Help/Wiki", "wiki": "Pomoć/Wiki",
"crowdsourcedConfigsLabel": "Crowdsourced App Configurations (use at your own risk)", "crowdsourcedConfigsLabel": "Konfiguracije aplikacije obezbeđene pomoću velikog broja ljudi (crowdsourcing) (koristite na svoju odgovornost)",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Želite li ukloniti aplikaciju?", "one": "Želite li ukloniti aplikaciju?",
"other": "Želite li ukloniti aplikacije?" "other": "Želite li ukloniti aplikacije?"
@@ -370,6 +372,6 @@
}, },
"apk": { "apk": {
"one": "{} APK", "one": "{} APK",
"other": "{} APKs" "other": "{} APK-a"
} }
} }

View File

@@ -259,6 +259,8 @@
"bgUpdatesOnWiFiOnly": "Deaktivovat aktualizace na pozadí, pokud není k dispozici Wi-Fi", "bgUpdatesOnWiFiOnly": "Deaktivovat aktualizace na pozadí, pokud není k dispozici Wi-Fi",
"autoSelectHighestVersionCode": "Automaticky vybrat nejvyšší verzi APK", "autoSelectHighestVersionCode": "Automaticky vybrat nejvyšší verzi APK",
"versionExtractionRegEx": "Extrakce verze pomocí RegEx", "versionExtractionRegEx": "Extrakce verze pomocí RegEx",
"trimVersionString": "Oříznutí řetězce verze pomocí příkazu RegEx",
"matchGroupToUseForX": "Skupina shody, která se použije pro \"{}\"",
"matchGroupToUse": "Odpovídá použité skupině", "matchGroupToUse": "Odpovídá použité skupině",
"highlightTouchTargets": "Zvýraznit méně zjevné cíle dotyku", "highlightTouchTargets": "Zvýraznit méně zjevné cíle dotyku",
"pickExportDir": "Vybrat adresář pro export", "pickExportDir": "Vybrat adresář pro export",

377
assets/translations/da.json Normal file
View File

@@ -0,0 +1,377 @@
{
"invalidURLForSource": "Ikke et gyldigt {} App-URL",
"noReleaseFound": "Kunne ikke finde en passende udgivelse",
"noVersionFound": "Kunne ikke afgøre udgivelsesversion",
"urlMatchesNoSource": "URL'en matcher ikke en kendt kilde",
"cantInstallOlderVersion": "Kan ikke installere en ældre version af en app",
"appIdMismatch": "Hentet pakke-ID matcher ikke eksisterende app-ID",
"functionNotImplemented": "Denne klasse har ikke implementeret denne funktion",
"placeholder": "Pladsholder",
"someErrors": "Nogle fejl opstod",
"unexpectedError": "Uventet fejl",
"ok": "Okay",
"and": "og",
"githubPATLabel": "GitHub Personlig Adgangstoken (øger hastighedsgrænse)",
"includePrereleases": "Inkluder forudgivelser",
"fallbackToOlderReleases": "Fallback til ældre udgivelser",
"filterReleaseTitlesByRegEx": "Filtrer udgivelsestitler efter regulært udtryk",
"invalidRegEx": "Ugyldigt regulært udtryk",
"noDescription": "Ingen beskrivelse",
"cancel": "Annuller",
"continue": "Fortsæt",
"requiredInBrackets": "(Påkrævet)",
"dropdownNoOptsError": "FEJL: RULLEMENU SKAL HAVE MINDST ÉT TILVALG",
"colour": "Farve",
"standard": "Standard",
"custom": "Brugerdefineret",
"useMaterialYou": "Brug Material You",
"githubStarredRepos": "Stjernemarkeret GitHub-repos",
"uname": "Brugernavn",
"wrongArgNum": "Forkert antal argumenter angivet",
"xIsTrackOnly": "{} kan kun følges",
"source": "Kilde",
"app": "App",
"appsFromSourceAreTrackOnly": "Apps fra denne kilde er 'Følg Kun'.",
"youPickedTrackOnly": "Du har valgt 'Følg Kun'-indstillingen.",
"trackOnlyAppDescription": "Appen tjekkes for opdateringer, men Obtainium kan ikke hente eller installere den.",
"cancelled": "Annulleret",
"appAlreadyAdded": "Appen er allerede tilføjet",
"alreadyUpToDateQuestion": "Appen er allerede opdateret?",
"addApp": "Tilføj app",
"appSourceURL": "URL til app-kilde",
"error": "Fejl",
"add": "Tilføj",
"searchSomeSourcesLabel": "Søg (kun visse kilder)",
"search": "Søg",
"additionalOptsFor": "Yderligere indstillinger for {}",
"supportedSources": "Understøttede kilder",
"trackOnlyInBrackets": "(Følg Kun)",
"searchableInBrackets": "(Kan Søges)",
"appsString": "Apps",
"noApps": "Ingen apps",
"noAppsForFilter": "Ingen apps til filter",
"byX": "Af {}",
"percentProgress": "Fremskridt: {}%",
"pleaseWait": "Vent venligst",
"updateAvailable": "Opdatering tilgængelig",
"notInstalled": "Ikke installeret",
"pseudoVersion": "pseudo-version",
"selectAll": "Vælg alle",
"deselectX": "Fravælg {}",
"xWillBeRemovedButRemainInstalled": "{} fjernes fra Obtainium, men forbliver installeret på enheden.",
"removeSelectedAppsQuestion": "Fjern valgte apps?",
"removeSelectedApps": "Fjern valgte apps",
"updateX": "Opdater {}",
"installX": "Installer {}",
"markXTrackOnlyAsUpdated": "Markér {}\n(Følg Kun)\nsom opdateret",
"changeX": "Skift {}",
"installUpdateApps": "Installer/Opdater apps",
"installUpdateSelectedApps": "Installer/Opdater valgte apps",
"markXSelectedAppsAsUpdated": "Markér {} valgte apps som opdateret?",
"no": "Nej",
"yes": "Ja",
"markSelectedAppsUpdated": "Markér valgte apps som opdateret",
"pinToTop": "Fastgør til toppen",
"unpinFromTop": "Frigør fra toppen",
"resetInstallStatusForSelectedAppsQuestion": "Nulstil installationsstatus for valgte apps?",
"installStatusOfXWillBeResetExplanation": "Installationsstatus for alle valgte apps nulstilles.\n\nDette kan hjælpe, når den app-version, der vises i Obtainium, er forkert grundet mislykkede opdateringer eller andre problemer.",
"customLinkMessage": "Disse links virker på enheder med Obtainium installeret",
"shareAppConfigLinks": "Del app-konfiguration som HTML-link",
"shareSelectedAppURLs": "Del valgte app-URL'er",
"resetInstallStatus": "Nulstil installationsstatus",
"more": "Mere",
"removeOutdatedFilter": "Fjern forældet app-filter",
"showOutdatedOnly": "Vis kun forældet apps",
"filter": "Filtrer",
"filterApps": "Filtrer Apps",
"appName": "Appnavn",
"author": "Udvikler",
"upToDateApps": "Opdaterede apps",
"nonInstalledApps": "Ikke-installerede apps",
"importExport": "Import/Eksport",
"settings": "Indstillinger",
"exportedTo": "Eksportér til {}",
"obtainiumExport": "Obtainium-eksport",
"invalidInput": "Ugyldigt input",
"importedX": "Importerede {}",
"obtainiumImport": "Obtainium-import",
"importFromURLList": "Importér fra URL-liste",
"searchQuery": "Søgning",
"appURLList": "Liste over app-URL'er",
"line": "Linje",
"searchX": "Søg {}",
"noResults": "Ingen resultater fundet",
"importX": "Importér {}",
"importedAppsIdDisclaimer": "Importerede apps vises muligvis forkert som \"Ikke installeret\".\nFor at løse dette, geninstaller dem via Obtainium.\nDette bør ikke påvirke app-data.\n\nPåvirker kun URL- og tredjepartsimportmetoder.",
"importErrors": "Importfejl",
"importedXOfYApps": "{} af {} app importeret.",
"followingURLsHadErrors": "Følgende URL'er havde fejl:",
"selectURL": "Vælg URL",
"selectURLs": "Vælg URL'er",
"pick": "Vælg",
"theme": "Tema",
"dark": "Mørk",
"light": "Lys",
"followSystem": "Følg system",
"followSystemThemeExplanation": "Det er kun muligt at følge systemtemaet ved brug af tredjepartsapplikationer",
"useBlackTheme": "Brug rent sort, mørkt tema",
"appSortBy": "Sortér apps efter:",
"authorName": "Udvikler/Navn",
"nameAuthor": "Navn/Udvikler",
"asAdded": "Som tilføjet",
"appSortOrder": "Sorteringsrækkefølge for apps",
"ascending": "Stigende",
"descending": "Faldende",
"bgUpdateCheckInterval": "Kontrolinterval for baggrundsopdatering",
"neverManualOnly": "Aldrig - Kun manuelt",
"appearance": "Udseende",
"showWebInAppView": "Vis kildewebsiden i appvisning",
"pinUpdates": "Fastgør opdateringer til toppen af appvisning",
"updates": "Opdateringer",
"sourceSpecific": "Kildespecifik",
"appSource": "App-kilde",
"noLogs": "Ingen logs",
"appLogs": "App-logs",
"close": "Luk",
"share": "Del",
"appNotFound": "App ikke fundet",
"obtainiumExportHyphenatedLowercase": "obtainium-eksport",
"pickAnAPK": "Vælg en APK",
"appHasMoreThanOnePackage": "{} har mere end én pakke:",
"deviceSupportsXArch": "Din enhed understøtter {} CPU-arkitekturen.",
"deviceSupportsFollowingArchs": "Din enhed understøtter følgende CPU-arkitekturer:",
"warning": "Advarsel",
"sourceIsXButPackageFromYPrompt": "App-kilden er '{}', men udgivelsespakken kommer fra '{}'. Fortsæt?",
"updatesAvailable": "Opdateringer tilgængelige",
"updatesAvailableNotifDescription": "Underretter brugeren om, at opdateringer er tilgængelige for en eller flere apps, der spores af Obtainium",
"noNewUpdates": "Ingen nye opdateringer.",
"xHasAnUpdate": "{} har en opdatering.",
"appsUpdated": "Apps opdateret",
"appsNotUpdated": "Kunne ikke opdatere applikationerne",
"appsUpdatedNotifDescription": "Underretter brugeren om, at opdateringer til en eller flere apps blev udført i baggrunden",
"xWasUpdatedToY": "{} blev opdateret til {}.",
"xWasNotUpdatedToY": "Kunne ikke opdatere {} til {}.",
"errorCheckingUpdates": "Fejl ved tjek for opdateringer",
"errorCheckingUpdatesNotifDescription": "En meddelelse, der vises, når opdateringstjek i baggrunden mislykkes",
"appsRemoved": "Apps fjernet",
"appsRemovedNotifDescription": "Underretter brugeren om, at en eller flere apps blev fjernet grundet fejl under indlæsning af dem",
"xWasRemovedDueToErrorY": "{} blev fjernet grundet denne fejl: {}",
"completeAppInstallation": "Færdiggør app-installation",
"obtainiumMustBeOpenToInstallApps": "Obtainium skal være åben for at installere apps",
"completeAppInstallationNotifDescription": "Beder brugeren om at vende tilbage til Obtainium for at afslutte installationen af en app",
"checkingForUpdates": "Tjekker for opdateringer",
"checkingForUpdatesNotifDescription": "Kortvarig meddelelse, der vises ved tjek for opdateringer",
"pleaseAllowInstallPerm": "Tillad venligst Obtainium at installere apps",
"trackOnly": "Følg Kun",
"errorWithHttpStatusCode": "Fejl {}",
"versionCorrectionDisabled": "Versionskorrigering deaktiveret (plugin ser ikke ud til at virke)",
"unknown": "Ukendt",
"none": "Ingen",
"never": "Aldrig",
"latestVersionX": "Seneste: {}",
"installedVersionX": "Installeret: {}",
"lastUpdateCheckX": "Sidste opdateringstjek: {}",
"remove": "Fjern",
"yesMarkUpdated": "Ja, markér som opdateret",
"fdroid": "F-Droid Officiel",
"appIdOrName": "App-ID eller navn",
"appId": "App-ID",
"appWithIdOrNameNotFound": "Ingen app med det ID eller navn blev fundet",
"reposHaveMultipleApps": "Repos kan indeholde flere apps",
"fdroidThirdPartyRepo": "F-Droid Tredjeparts-repo",
"steamMobile": "Steam Mobil",
"steamChat": "Steam Chat",
"install": "Installer",
"markInstalled": "Markér som installeret",
"update": "Opdater",
"markUpdated": "Markér som opdateret",
"additionalOptions": "Yderligere indstillinger",
"disableVersionDetection": "Deaktivér versionsregistrering",
"noVersionDetectionExplanation": "Denne indstilling bør kun bruges til apps, hvor versionsregistrering ikke virker korrekt.",
"downloadingX": "Henter {}",
"downloadX": "Hent {}",
"downloadedX": "Hentede {}",
"releaseAsset": "Udgivelsesressource",
"downloadNotifDescription": "Underretter brugeren om fremskridt i hentning af en app",
"noAPKFound": "Ingen APK fundet",
"noVersionDetection": "Ingen versionsregistrering",
"categorize": "Kategoriser",
"categories": "Kategorier",
"category": "Kategori",
"noCategory": "Ingen kategori",
"noCategories": "Ingen kategorier",
"deleteCategoriesQuestion": "Slet kategorier?",
"categoryDeleteWarning": "Alle apps i slettede kategorier indstilles til ukategoriseret.",
"addCategory": "Tilføj kategori",
"label": "Etiket",
"language": "Sprog",
"copiedToClipboard": "Kopieret til udklipsholder",
"storagePermissionDenied": "Lagringstilladelse nægtet",
"selectedCategorizeWarning": "Dette erstatter alle eksisterende kategoriindstillinger for de valgte apps.",
"filterAPKsByRegEx": "Filtrer APK'er efter regulært udtryk",
"removeFromObtainium": "Fjern fra Obtainium",
"uninstallFromDevice": "Afinstaller fra enhed",
"onlyWorksWithNonVersionDetectApps": "Virker kun for apps med versionsregistrering deaktiveret.",
"releaseDateAsVersion": "Brug udgivelsesdato som versionsstreng",
"releaseDateAsVersionExplanation": "Denne indstilling bør kun bruges til apps, hvor versionsregistrering ikke virker korrekt, men hvor en udgivelsesdato er tilgængelig.",
"changes": "Ændringer",
"releaseDate": "Udgivelsesdato",
"importFromURLsInFile": "Importér fra URL'er i fil (som OPML)",
"versionDetectionExplanation": "Afstem versionsstreng med versionen registreret fra OS",
"versionDetection": "Versionsregistrering",
"standardVersionDetection": "Standard versionsregistrering",
"groupByCategory": "Gruppér efter kategori",
"autoApkFilterByArch": "Forsøg at filtrere APK'er efter CPU-arkitektur, hvis muligt",
"overrideSource": "Tilsidesæt kilde",
"dontShowAgain": "Vis ikke denne igen",
"dontShowTrackOnlyWarnings": "Vis ikke 'Følg Kun'-advarsler",
"dontShowAPKOriginWarnings": "Vis ikke advarsler om APK-oprindelse",
"moveNonInstalledAppsToBottom": "Flyt ikke-installerede apps til bunden af appvisning",
"gitlabPATLabel": "GitLab Personlig Adgangstoken",
"about": "Om",
"requiresCredentialsInSettings": "{} kræver yderligere legitimation (i Indstillinger)",
"checkOnStart": "Tjek for opdateringer ved opstart",
"tryInferAppIdFromCode": "Forsøg at udlede app-ID fra kildekode",
"removeOnExternalUninstall": "Fjern automatisk eksternt afinstallerede apps",
"pickHighestVersionCode": "Auto-vælg højeste versionKode af APK",
"checkUpdateOnDetailPage": "Tjek for opdateringer ved åbning af appens detaljeside",
"disablePageTransitions": "Deaktivér sideovergangsanimationer",
"reversePageTransitions": "Omvendte sideovergangsanimationer",
"minStarCount": "Minimum antal stjerner",
"addInfoBelow": "Tilføj denne info nedenfor.",
"addInfoInSettings": "Tilføj denne info i indstillingerne.",
"githubSourceNote": "GitHubs hastighedsbegrænsning kan undgås med en API-nøgle.",
"sortByLastLinkSegment": "Sortér kun efter det sidste segment af linket",
"filterReleaseNotesByRegEx": "Filtrer udgivelsesnoter efter regulært udtryk",
"customLinkFilterRegex": "Brugerdefineret APK-linkfilter efter regulært udtryk (standard '.apk$')",
"appsPossiblyUpdated": "App-opdateringer forsøgt",
"appsPossiblyUpdatedNotifDescription": "Underretter brugeren om, at opdateringer til en eller flere apps potentielt blev udført i baggrunden",
"xWasPossiblyUpdatedToY": "{} er muligvis blevet opdateret til {}.",
"enableBackgroundUpdates": "Aktivér baggrundsopdateringer",
"backgroundUpdateReqsExplanation": "Baggrundsopdateringer er muligvis ikke mulige for alle apps.",
"backgroundUpdateLimitsExplanation": "Om en baggrundsinstallation er vellykket, kan kun afgøres, når Obtainium åbnes.",
"verifyLatestTag": "Verificer 'seneste'-tagget",
"intermediateLinkRegex": "Filtrer efter et 'mellemliggende' link at besøge",
"filterByLinkText": "Filtrer links efter linktekst",
"intermediateLinkNotFound": "Mellemliggende link ikke fundet",
"intermediateLink": "Mellemliggende link",
"exemptFromBackgroundUpdates": "Undtag fra baggrundsopdateringer (hvis aktiveret)",
"bgUpdatesOnWiFiOnly": "Deaktivér baggrundsopdateringer, når du ikke er på WiFi",
"autoSelectHighestVersionCode": "Auto-vælg højeste versionKode af APK",
"versionExtractionRegEx": "RegEx for versionsstrengsudtrækning",
"trimVersionString": "Trim versionsstrengen med RegEx",
"matchGroupToUseForX": "Matchgruppe til brug for \"{}\"",
"matchGroupToUse": "Match gruppe til brug til RegEx for versionsstrengsudtrækning",
"highlightTouchTargets": "Fremhæv mindre åbenlyse berøringsmål",
"pickExportDir": "Vælg eksportmappe",
"autoExportOnChanges": "Auto-eksport ved ændringer",
"includeSettings": "Inkluder indstillinger",
"filterVersionsByRegEx": "Filtrer versioner efter regulært udtryk",
"trySelectingSuggestedVersionCode": "Forsøg at vælge den foreslåede versionKode af APK",
"dontSortReleasesList": "Behold udgivelsesordre fra API",
"reverseSort": "Omvendt sortering",
"takeFirstLink": "Tag første link",
"skipSort": "Spring sortering over",
"debugMenu": "Fejlfindingsmenu",
"bgTaskStarted": "Baggrundsopgave startet - tjek logfiler.",
"runBgCheckNow": "Kør baggrundsopdateringstjek nu",
"versionExtractWholePage": "Anvend RegEx for versionsstrengsudtrækning for hele siden",
"installing": "Installerer",
"skipUpdateNotifications": "Spring opdateringsmeddelelser over",
"updatesAvailableNotifChannel": "Opdateringer tilgængelige",
"appsUpdatedNotifChannel": "Apps opdateret",
"appsPossiblyUpdatedNotifChannel": "App-opdateringer forsøgt",
"errorCheckingUpdatesNotifChannel": "Fejl ved opdateringstjek",
"appsRemovedNotifChannel": "Apps fjernet",
"downloadingXNotifChannel": "Henter {}",
"completeAppInstallationNotifChannel": "Færdiggør app-installation",
"checkingForUpdatesNotifChannel": "Tjekker for opdateringer",
"onlyCheckInstalledOrTrackOnlyApps": "Tjek kun installeret og 'Følg Kun'-apps for opdateringer",
"supportFixedAPKURL": "Understøt fikserede APK-URL'er",
"selectX": "Vælg {}",
"parallelDownloads": "Tillad samtidige overførsler",
"useShizuku": "Brug Shizuku eller Sui til at installere",
"shizukuBinderNotFound": "Shizuku-tjeneste kører ikke",
"shizukuOld": "Forældet Shizuku-version (<11). Opdater den",
"shizukuOldAndroidWithADB": "Shizuku kører på Android <8.1 med ADB. Opdater Android eller brug Sui i stedet",
"shizukuPretendToBeGooglePlay": "Indstil Google Play som installationskilde (hvis Shizuku bruges)",
"useSystemFont": "Brug systemskrifttype",
"useVersionCodeAsOSVersion": "Brug app versionKode som OS-registreret version",
"requestHeader": "Anmod overskrift",
"useLatestAssetDateAsReleaseDate": "Brug seneste ressourceupload som udgivelsesdato",
"defaultPseudoVersioningMethod": "Standard pseudo-versioneringsmetode",
"partialAPKHash": "Delvis APK-hash",
"APKLinkHash": "Hash for APK-link",
"directAPKLink": "Direkte APK-link",
"pseudoVersionInUse": "En pseudo-version er i brug",
"installed": "Installeret",
"latest": "Seneste",
"invertRegEx": "Inverter regulært udtryk",
"note": "Bemærk",
"selfHostedNote": "Rullemenuen \"{}\" kan bruges til at nå selvhostede/brugerdefinerede instanser af enhver kilde.",
"badDownload": "APK'en kunne ikke analyseres (inkompatibel eller delvis hentning)",
"beforeNewInstallsShareToAppVerifier": "Del nye apps med AppVerifier (hvis tilgængelig)",
"appVerifierInstructionToast": "Del til AppVerifier, og vend tilbage hertil, når du er klar.",
"wiki": "Hjælp/Wiki",
"crowdsourcedConfigsLabel": "Crowdsourcede app-konfigurationer (brug på egen risiko)",
"removeAppQuestion": {
"one": "Fjern app?",
"other": "Fjern apps?"
},
"tooManyRequestsTryAgainInMinutes": {
"one": "For mange anmodninger (begrænset hastighed). Prøv igen om {} minut",
"other": "For mange anmodninger (begrænset hastighed). Prøv igen om {} minutter"
},
"bgUpdateGotErrorRetryInMinutes": {
"one": "Baggrundsopdateringstjek stødte på en {}. Planlægger et nyt tjek om {} minut",
"other": "Baggrundsopdateringstjek stødte på en {}. Planlægger et nyt tjek om {} minutter"
},
"bgCheckFoundUpdatesWillNotifyIfNeeded": {
"one": "Baggrundsopdateringstjek fandt {} opdatering. Underretter brugeren, hvis nødvendigt",
"other": "Baggrundsopdateringstjek fandt {} opdateringer. Underretter brugeren, hvis nødvendigt"
},
"apps": {
"one": "{} App",
"other": "{} Apps"
},
"url": {
"one": "{} URL",
"other": "{} URL'er"
},
"minute": {
"one": "{} Minut",
"other": "{} Minutter"
},
"hour": {
"one": "{} Time",
"other": "{} Timer"
},
"day": {
"one": "{} Dag",
"other": "{} Dage"
},
"clearedNLogsBeforeXAfterY": {
"one": "Ryddet {n} log (før = {before}, efter = {after})",
"other": "Ryddet {n} logs (før = {before}, efter = {after})"
},
"xAndNMoreUpdatesAvailable": {
"one": "{} og 1 anden app har opdateringer.",
"other": "{} og {} andre apps har opdateringer."
},
"xAndNMoreUpdatesInstalled": {
"one": "{} og 1 anden app blev opdateret.",
"other": "{} og {} andre apps blev opdateret."
},
"xAndNMoreUpdatesFailed": {
"one": "Kunne ikke opdatere {} og 1 anden app.",
"other": "Kunne ikke opdatere {} og {} andre apps."
},
"xAndNMoreUpdatesPossiblyInstalled": {
"one": "{} og 1 anden app blev muligvis opdateret.",
"other": "{} og {} andre apps blev muligvis opdateret."
},
"apk": {
"one": "{} APK",
"other": "{} APK'er"
}
}

View File

@@ -259,6 +259,8 @@
"bgUpdatesOnWiFiOnly": "Hintergrundaktualisierungen deaktivieren, wenn kein WLAN vorhanden ist", "bgUpdatesOnWiFiOnly": "Hintergrundaktualisierungen deaktivieren, wenn kein WLAN vorhanden ist",
"autoSelectHighestVersionCode": "Automatisch höchste APK-Version auswählen", "autoSelectHighestVersionCode": "Automatisch höchste APK-Version auswählen",
"versionExtractionRegEx": "Versions-Extraktion per RegEx", "versionExtractionRegEx": "Versions-Extraktion per RegEx",
"trimVersionString": "Trim Version String mit RegEx",
"matchGroupToUseForX": "Zu verwendende Abgleichsgruppe für \"{}\"",
"matchGroupToUse": "zu verwendende Gruppe abgleichen", "matchGroupToUse": "zu verwendende Gruppe abgleichen",
"highlightTouchTargets": "Weniger offensichtliche Touch-Ziele hervorheben", "highlightTouchTargets": "Weniger offensichtliche Touch-Ziele hervorheben",
"pickExportDir": "Export-Verzeichnis wählen", "pickExportDir": "Export-Verzeichnis wählen",
@@ -329,12 +331,12 @@
"other": "Die Hintergrundaktualisierungsprüfung fand {} Aktualisierungen benachrichtigt den Benutzer, falls erforderlich" "other": "Die Hintergrundaktualisierungsprüfung fand {} Aktualisierungen benachrichtigt den Benutzer, falls erforderlich"
}, },
"apps": { "apps": {
"eine": "{} App", "one": "{} App",
"andere": "{} Apps" "other": "{} Apps"
}, },
"url": { "url": {
"eine": "{} URL", "one": "{} URL",
"andere": "{} URLs" "other": "{} URLs"
}, },
"minute": { "minute": {
"one": "{} Minute", "one": "{} Minute",

View File

@@ -259,6 +259,8 @@
"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 String Extraction RegEx", "versionExtractionRegEx": "Version String Extraction RegEx",
"trimVersionString": "Trim Version String With RegEx",
"matchGroupToUseForX": "Match Group to Use for \"{}\"",
"matchGroupToUse": "Match Group to Use for Version String 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",

View File

@@ -21,15 +21,15 @@
"continue": "Continuar", "continue": "Continuar",
"requiredInBrackets": "(Requerido)", "requiredInBrackets": "(Requerido)",
"dropdownNoOptsError": "ERROR: EL DESPLEGABLE DEBE TENER AL MENOS UNA OPCIÓN", "dropdownNoOptsError": "ERROR: EL DESPLEGABLE DEBE TENER AL MENOS UNA OPCIÓN",
"colour": "Color", "colour": "color",
"standard": "Estándar", "standard": "Estándar",
"custom": "A medida", "custom": "A medida",
"useMaterialYou": "Use 'Material You'", "useMaterialYou": "Aplicar 'Material You'",
"githubStarredRepos": "Repositorios favoritos en GitHub", "githubStarredRepos": "repositorios favoritos en GitHub",
"uname": "Nombre de usuario", "uname": "Nombre de usuario",
"wrongArgNum": "Número de argumentos provistos inválido", "wrongArgNum": "Número de argumentos provistos inválido",
"xIsTrackOnly": "{} es de 'sólo seguimiento'", "xIsTrackOnly": "{} es de 'sólo seguimiento'",
"source": "Origen", "source": "origen",
"app": "Aplicación", "app": "Aplicación",
"appsFromSourceAreTrackOnly": "Las aplicaciones de este origen son solo para seguimiento.", "appsFromSourceAreTrackOnly": "Las aplicaciones de este origen son solo para seguimiento.",
"youPickedTrackOnly": "Debe seleccionar la opción de 'solo para seguimiento'.", "youPickedTrackOnly": "Debe seleccionar la opción de 'solo para seguimiento'.",
@@ -122,14 +122,14 @@
"appSortOrder": "Orden de Clasificación", "appSortOrder": "Orden de Clasificación",
"ascending": "Ascendente", "ascending": "Ascendente",
"descending": "Descendente", "descending": "Descendente",
"bgUpdateCheckInterval": "Comprobación actualizaciones en segundo plano", "bgUpdateCheckInterval": "Comprobar actualizaciones en segundo plano",
"neverManualOnly": "Nunca, solo manual", "neverManualOnly": "Nunca, solo manual",
"appearance": "Apariencia", "appearance": "Apariencia",
"showWebInAppView": "Mostrar vista de la web de origen", "showWebInAppView": "Mostrar vista de la web de origen",
"pinUpdates": "Anclar actualizaciones al principio", "pinUpdates": "Anclar actualizaciones al principio",
"updates": "Actualizaciones", "updates": "Actualizaciones",
"sourceSpecific": "Fuente específica", "sourceSpecific": "Fuente específica",
"appSource": "Obtainium en GitHub", "appSource": "Filtrar por fuente",
"noLogs": "Ningún registro", "noLogs": "Ningún registro",
"appLogs": "Registros", "appLogs": "Registros",
"close": "Cerrar", "close": "Cerrar",
@@ -220,11 +220,11 @@
"versionDetectionExplanation": "Conciliar la cadena de versión con la versión detectada desde el sistema operativo", "versionDetectionExplanation": "Conciliar la cadena de versión con la versión detectada desde el sistema operativo",
"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ías",
"autoApkFilterByArch": "Filtrar APK por arquitectura del procesador (si es posible)", "autoApkFilterByArch": "Filtrar APK por arquitectura del procesador (si es posible)",
"overrideSource": "Forzar desde la fuente", "overrideSource": "Forzar desde la fuente",
"dontShowAgain": "No mostrar de nuevo", "dontShowAgain": "No mostrar de nuevo",
"dontShowTrackOnlyWarnings": "No mostrar avisos sobre apps 'solo para seguimiento", "dontShowTrackOnlyWarnings": "No mostrar avisos sobre apps 'solo para seguimiento'",
"dontShowAPKOriginWarnings": "No mostrar avisos sobre las fuentes de las APKs", "dontShowAPKOriginWarnings": "No mostrar avisos sobre las fuentes de las APKs",
"moveNonInstalledAppsToBottom": "Mover apps no instaladas al final", "moveNonInstalledAppsToBottom": "Mover apps no instaladas al final",
"gitlabPATLabel": "Token de acceso personal a GitLab", "gitlabPATLabel": "Token de acceso personal a GitLab",
@@ -259,6 +259,8 @@
"bgUpdatesOnWiFiOnly": "Deshabilitar las actualizaciones en segundo plano sin WiFi", "bgUpdatesOnWiFiOnly": "Deshabilitar las actualizaciones en segundo plano sin WiFi",
"autoSelectHighestVersionCode": "Auto selección del paquete APK con versión más reciente", "autoSelectHighestVersionCode": "Auto selección del paquete APK con versión más reciente",
"versionExtractionRegEx": "Versión de extracción regex", "versionExtractionRegEx": "Versión de extracción regex",
"trimVersionString": "Recortar cadena de versión con RegEx",
"matchGroupToUseForX": "Grupo de coincidencia a utilizar para \"{}\"",
"matchGroupToUse": "Grupo a usar para versión de extracción regex", "matchGroupToUse": "Grupo a usar para versión de extracción regex",
"highlightTouchTargets": "Resaltar objetivos menos obvios", "highlightTouchTargets": "Resaltar objetivos menos obvios",
"pickExportDir": "Directorio para exportar", "pickExportDir": "Directorio para exportar",
@@ -288,7 +290,7 @@
"supportFixedAPKURL": "Soporte para URLs fijas de APK", "supportFixedAPKURL": "Soporte para URLs fijas de APK",
"selectX": "Elija {}", "selectX": "Elija {}",
"parallelDownloads": "Permitir descargas paralelas", "parallelDownloads": "Permitir descargas paralelas",
"useShizuku": "Use Shizuku o Sui para instalar", "useShizuku": "Usar Shizuku o Sui para instalar",
"shizukuBinderNotFound": "Shizuku no funciona", "shizukuBinderNotFound": "Shizuku no funciona",
"shizukuOld": "Versión antigua de Shizuku (<11) - actualícela", "shizukuOld": "Versión antigua de Shizuku (<11) - actualícela",
"shizukuOldAndroidWithADB": "Shizuku corriendo en Android < 8.1 con ADB - actualiza Android o usa Sui en su lugar", "shizukuOldAndroidWithADB": "Shizuku corriendo en Android < 8.1 con ADB - actualiza Android o usa Sui en su lugar",
@@ -308,7 +310,7 @@
"note": "Nota", "note": "Nota",
"selfHostedNote": "El desplegable «{}» puede usarse para acceder a instancias autoalojadas/personalizadas de cualquier fuente.", "selfHostedNote": "El desplegable «{}» puede usarse para acceder a instancias autoalojadas/personalizadas de cualquier fuente.",
"badDownload": "No se ha podido analizar el APK (incompatible o descarga parcial)", "badDownload": "No se ha podido analizar el APK (incompatible o descarga parcial)",
"beforeNewInstallsShareToAppVerifier": "Compartir nuevas aplicaciones con AppVerifier (si está disponible)", "beforeNewInstallsShareToAppVerifier": "Compartir aplicaciones nuevas con AppVerifier (si está disponible)",
"appVerifierInstructionToast": "Comparta con AppVerifier y vuelva aquí cuando esté listo.", "appVerifierInstructionToast": "Comparta con AppVerifier y vuelva aquí cuando esté listo.",
"wiki": "Ayuda/Wiki", "wiki": "Ayuda/Wiki",
"crowdsourcedConfigsLabel": "Crowdsourced App Configurations (uso bajo su propia responsabilidad)", "crowdsourcedConfigsLabel": "Crowdsourced App Configurations (uso bajo su propia responsabilidad)",
@@ -333,8 +335,8 @@
"other": "{} Aplicaciones" "other": "{} Aplicaciones"
}, },
"url": { "url": {
"uno": "{} URL", "one": "{} URL",
"otro": "{} URL" "other": "{} URL"
}, },
"minute": { "minute": {
"one": "{} minuto", "one": "{} minuto",

View File

@@ -113,7 +113,7 @@
"dark": "تاریک", "dark": "تاریک",
"light": "روشن", "light": "روشن",
"followSystem": "هماهنگ با سیستم", "followSystem": "هماهنگ با سیستم",
"followSystemThemeExplanation": "Following system theme is possible only by using third-party applications", "followSystemThemeExplanation": "دنبال کردن تم سیستم فقط با استفاده از برنامه های شخص ثالث امکان پذیر است",
"useBlackTheme": "استفاده از تم تیره سیاه خالص", "useBlackTheme": "استفاده از تم تیره سیاه خالص",
"appSortBy": "مرتب سازی برنامه بر اساس", "appSortBy": "مرتب سازی برنامه بر اساس",
"authorName": "سازنده/اسم", "authorName": "سازنده/اسم",
@@ -147,10 +147,10 @@
"noNewUpdates": "به روز رسانی جدیدی وجود ندارد.", "noNewUpdates": "به روز رسانی جدیدی وجود ندارد.",
"xHasAnUpdate": "{} یک به روز رسانی دارد.", "xHasAnUpdate": "{} یک به روز رسانی دارد.",
"appsUpdated": "برنامه ها به روز شدند", "appsUpdated": "برنامه ها به روز شدند",
"appsNotUpdated": "Failed to update applications", "appsNotUpdated": "به روز رسانی برنامه ها ناموفق بود",
"appsUpdatedNotifDescription": "به کاربر اطلاع می دهد که به روز رسانی یک یا چند برنامه در پس زمینه اعمال شده است", "appsUpdatedNotifDescription": "به کاربر اطلاع می دهد که به روز رسانی یک یا چند برنامه در پس زمینه اعمال شده است",
"xWasUpdatedToY": "{} به {} به روز شد.", "xWasUpdatedToY": "{} به {} به روز شد.",
"xWasNotUpdatedToY": "Failed to update {} to {}.", "xWasNotUpdatedToY": "به روز رسانی {} به {} انجام نشد.",
"errorCheckingUpdates": "خطا در بررسی به‌روزرسانی‌ها", "errorCheckingUpdates": "خطا در بررسی به‌روزرسانی‌ها",
"errorCheckingUpdatesNotifDescription": "اعلانی که وقتی بررسی به‌روزرسانی پس‌زمینه ناموفق است نشان می‌دهد", "errorCheckingUpdatesNotifDescription": "اعلانی که وقتی بررسی به‌روزرسانی پس‌زمینه ناموفق است نشان می‌دهد",
"appsRemoved": "برنامه ها حذف شدند", "appsRemoved": "برنامه ها حذف شدند",
@@ -189,9 +189,9 @@
"disableVersionDetection": "غیرفعال کردن تشخیص نسخه", "disableVersionDetection": "غیرفعال کردن تشخیص نسخه",
"noVersionDetectionExplanation": "این گزینه فقط باید برای برنامه هایی استفاده شود که تشخیص نسخه به درستی کار نمی کند.", "noVersionDetectionExplanation": "این گزینه فقط باید برای برنامه هایی استفاده شود که تشخیص نسخه به درستی کار نمی کند.",
"downloadingX": "در حال دانلود {}", "downloadingX": "در حال دانلود {}",
"downloadX": "Download {}", "downloadX": "دانلود {}",
"downloadedX": "Downloaded {}", "downloadedX": "دانلود شده {}",
"releaseAsset": "Release Asset", "releaseAsset": "انتشار دارایی",
"downloadNotifDescription": "کاربر را از پیشرفت دانلود یک برنامه مطلع می کند", "downloadNotifDescription": "کاربر را از پیشرفت دانلود یک برنامه مطلع می کند",
"noAPKFound": "APK پیدا نشد فایل", "noAPKFound": "APK پیدا نشد فایل",
"noVersionDetection": "بدون تشخیص نسخه", "noVersionDetection": "بدون تشخیص نسخه",
@@ -259,6 +259,8 @@
"bgUpdatesOnWiFiOnly": "به‌روزرسانی‌های پس‌زمینه را در صورت عدم اتصال به WiFi غیرفعال کنید", "bgUpdatesOnWiFiOnly": "به‌روزرسانی‌های پس‌زمینه را در صورت عدم اتصال به WiFi غیرفعال کنید",
"autoSelectHighestVersionCode": "انتخاب خودکار بالاترین نسخه کد APK", "autoSelectHighestVersionCode": "انتخاب خودکار بالاترین نسخه کد APK",
"versionExtractionRegEx": "نسخه استخراج RegEx", "versionExtractionRegEx": "نسخه استخراج RegEx",
"trimVersionString": "Trim Version String With RegEx",
"matchGroupToUseForX": "Match Group to Use for \"{}\"",
"matchGroupToUse": "گروه مورد استفاده را مطابقت دهید", "matchGroupToUse": "گروه مورد استفاده را مطابقت دهید",
"highlightTouchTargets": "اهداف لمسی کمتر واضح را برجسته کنید", "highlightTouchTargets": "اهداف لمسی کمتر واضح را برجسته کنید",
"pickExportDir": "فهرست برون ریزی را انتخاب کنید", "pickExportDir": "فهرست برون ریزی را انتخاب کنید",
@@ -305,13 +307,13 @@
"installed": "نصب شده است", "installed": "نصب شده است",
"latest": "آخرین", "latest": "آخرین",
"invertRegEx": "معکوس کردن عبارت منظم", "invertRegEx": "معکوس کردن عبارت منظم",
"note": "Note", "note": "یادداشت",
"selfHostedNote": "The \"{}\" dropdown can be used to reach self-hosted/custom instances of any source.", "selfHostedNote": "از منوی کرکره ای \"{}\" می توان برای دسترسی به نمونه های خود میزبانی/سفارشی از هر منبعی استفاده کرد.",
"badDownload": "The APK could not be parsed (incompatible or partial download)", "badDownload": "APK قابل تجزیه نیست (دانلود ناسازگار یا جزئی)",
"beforeNewInstallsShareToAppVerifier": "Share new Apps with AppVerifier (if available)", "beforeNewInstallsShareToAppVerifier": "اشتراک‌گذاری برنامه‌های جدید با AppVerifier (در صورت وجود)",
"appVerifierInstructionToast": "Share to AppVerifier, then return here when ready.", "appVerifierInstructionToast": "در AppVerifier به اشتراک بگذارید، سپس پس از آماده شدن به اینجا برگردید.",
"wiki": "Help/Wiki", "wiki": "راهنما/ویکی",
"crowdsourcedConfigsLabel": "Crowdsourced App Configurations (use at your own risk)", "crowdsourcedConfigsLabel": "تنظیمات برنامه Crowdsourced (با مسئولیت خود استفاده کنید)",
"removeAppQuestion": { "removeAppQuestion": {
"one": "برنامه حذف شود؟", "one": "برنامه حذف شود؟",
"other": "برنامه ها حذف شوند؟" "other": "برنامه ها حذف شوند؟"
@@ -361,8 +363,8 @@
"other": "{} و {} برنامه دیگر به روز شدند." "other": "{} و {} برنامه دیگر به روز شدند."
}, },
"xAndNMoreUpdatesFailed": { "xAndNMoreUpdatesFailed": {
"one": "Failed to update {} and 1 more app.", "one": "{} و 1 برنامه دیگر به روز نشد.",
"other": "Failed to update {} and {} more apps." "other": "{} و {} برنامه دیگر به روز نشد."
}, },
"xAndNMoreUpdatesPossiblyInstalled": { "xAndNMoreUpdatesPossiblyInstalled": {
"one": "{} و 1 برنامه دیگر ممکن است به روز شده باشند.", "one": "{} و 1 برنامه دیگر ممکن است به روز شده باشند.",

View File

@@ -11,7 +11,7 @@
"unexpectedError": "Erreur inattendue", "unexpectedError": "Erreur inattendue",
"ok": "D'accord", "ok": "D'accord",
"and": "et", "and": "et",
"githubPATLabel": "Jeton d'Accès Personnel GitHub (Augmente la limite de débit)", "githubPATLabel": "Jeton d'Accès Personnel GitHub (augmente la limite de débit)",
"includePrereleases": "Inclure les avant-premières", "includePrereleases": "Inclure les avant-premières",
"fallbackToOlderReleases": "Retour aux anciennes versions", "fallbackToOlderReleases": "Retour aux anciennes versions",
"filterReleaseTitlesByRegEx": "Filtrer les titres de version par expression régulière", "filterReleaseTitlesByRegEx": "Filtrer les titres de version par expression régulière",
@@ -24,7 +24,7 @@
"colour": "Couleur", "colour": "Couleur",
"standard": "Standard", "standard": "Standard",
"custom": "Sur mesure", "custom": "Sur mesure",
"useMaterialYou": "Utiliser le matériel que vous", "useMaterialYou": "Utiliser Material You",
"githubStarredRepos": "Dépôts étoilés GitHub", "githubStarredRepos": "Dépôts étoilés GitHub",
"uname": "Nom d'utilisateur", "uname": "Nom d'utilisateur",
"wrongArgNum": "Mauvais nombre d'arguments fournis", "wrongArgNum": "Mauvais nombre d'arguments fournis",
@@ -46,12 +46,12 @@
"additionalOptsFor": "Options supplémentaires pour {}", "additionalOptsFor": "Options supplémentaires pour {}",
"supportedSources": "Sources prises en charge ", "supportedSources": "Sources prises en charge ",
"trackOnlyInBrackets": "(Suivi uniquement)", "trackOnlyInBrackets": "(Suivi uniquement)",
"searchableInBrackets": "(Intérrogeable)", "searchableInBrackets": "(Interrogeable)",
"appsString": "Applications", "appsString": "Applications",
"noApps": "Aucune application", "noApps": "Aucune application",
"noAppsForFilter": "Aucune application pour le filtre", "noAppsForFilter": "Aucune application pour le filtre",
"byX": "Par {}", "byX": "Par {}",
"percentProgress": "Progrès: {}%", "percentProgress": "Progrès: {}%",
"pleaseWait": "Veuillez patienter", "pleaseWait": "Veuillez patienter",
"updateAvailable": "Mise à jour disponible", "updateAvailable": "Mise à jour disponible",
"notInstalled": "Non installé", "notInstalled": "Non installé",
@@ -67,18 +67,18 @@
"changeX": "Changer {}", "changeX": "Changer {}",
"installUpdateApps": "Installer/Mettre à jour les applications", "installUpdateApps": "Installer/Mettre à jour les applications",
"installUpdateSelectedApps": "Installer/Mettre à jour les applications sélectionnées", "installUpdateSelectedApps": "Installer/Mettre à jour les applications sélectionnées",
"markXSelectedAppsAsUpdated": "Marquer {} les applications sélectionnées comme étant à jour ?", "markXSelectedAppsAsUpdated": "Marquer {} les applications sélectionnées comme étant à jour?",
"no": "Non", "no": "Non",
"yes": "Oui", "yes": "Oui",
"markSelectedAppsUpdated": "Marquer les applications sélectionnées comme étant à jour", "markSelectedAppsUpdated": "Marquer les applications sélectionnées comme étant à jour",
"pinToTop": "Épingler en haut", "pinToTop": "Épingler en haut",
"unpinFromTop": "Désépingler du haut", "unpinFromTop": "Désépingler du haut",
"resetInstallStatusForSelectedAppsQuestion": "Réinitialiser le statu d'installation des applications sélectionnées ?", "resetInstallStatusForSelectedAppsQuestion": "Réinitialiser le statut d'installation des applications sélectionnées?",
"installStatusOfXWillBeResetExplanation": "Le statu d'installation de toutes les applications sélectionnées sera réinitialisé.\n\nCela peut aider lorsque la version de l'application affichée dans Obtainium est incorrecte en raison d'échecs de mises à jour ou d'autres problèmes.", "installStatusOfXWillBeResetExplanation": "Le statut d'installation de toutes les applications sélectionnées sera réinitialisé.\n\nCela peut aider lorsque la version de l'application affichée dans Obtainium est incorrecte en raison d'échecs de mises à jour ou d'autres problèmes.",
"customLinkMessage": "Ces liens fonctionnent sur les appareils sur lesquels Obtainium est installé", "customLinkMessage": "Ces liens fonctionnent sur les appareils sur lesquels Obtainium est installé",
"shareAppConfigLinks": "Partager la configuration de l'application sous forme de lien HTML", "shareAppConfigLinks": "Partager la configuration de l'application sous forme de lien HTML",
"shareSelectedAppURLs": "Partager les URL d'application sélectionnées", "shareSelectedAppURLs": "Partager les URL d'applications sélectionnées",
"resetInstallStatus": "Réinitialiser le statu d'installation", "resetInstallStatus": "Réinitialiser le statut d'installation",
"more": "Plus", "more": "Plus",
"removeOutdatedFilter": "Supprimer le filtre d'application obsolète", "removeOutdatedFilter": "Supprimer le filtre d'application obsolète",
"showOutdatedOnly": "Afficher uniquement les applications obsolètes", "showOutdatedOnly": "Afficher uniquement les applications obsolètes",
@@ -98,7 +98,7 @@
"importFromURLList": "Importer à partir de la liste d'URL", "importFromURLList": "Importer à partir de la liste d'URL",
"searchQuery": "Requête", "searchQuery": "Requête",
"appURLList": "Liste d'URL d'application", "appURLList": "Liste d'URL d'application",
"line": "Queue", "line": "File d'attente",
"searchX": "Rechercher {}", "searchX": "Rechercher {}",
"noResults": "Aucun résultat trouvé", "noResults": "Aucun résultat trouvé",
"importX": "Importer {}", "importX": "Importer {}",
@@ -107,14 +107,14 @@
"importedXOfYApps": "{} sur {} applications importées.", "importedXOfYApps": "{} sur {} applications importées.",
"followingURLsHadErrors": "Les URL suivantes comportaient des erreurs :", "followingURLsHadErrors": "Les URL suivantes comportaient des erreurs :",
"selectURL": "Sélectionnez l'URL", "selectURL": "Sélectionnez l'URL",
"selectURLs": "Sélectionnez les URLs", "selectURLs": "Sélectionnez les URL",
"pick": "Prendre", "pick": "Prendre",
"theme": "Thème", "theme": "Thème",
"dark": "Sombre", "dark": "Sombre",
"light": "Clair", "light": "Clair",
"followSystem": "Suivre le système", "followSystem": "Suivre le système",
"followSystemThemeExplanation": "Il n'est possible de suivre le thème du système qu'en utilisant des applications tierces.", "followSystemThemeExplanation": "Il n'est possible de suivre le thème du système qu'en utilisant des applications tierces.",
"useBlackTheme": "Utilisez le thème noir pur", "useBlackTheme": "Utiliser le thème noir pur",
"appSortBy": "Applications triées par", "appSortBy": "Applications triées par",
"authorName": "Auteur/Nom", "authorName": "Auteur/Nom",
"nameAuthor": "Nom/Auteur", "nameAuthor": "Nom/Auteur",
@@ -123,10 +123,10 @@
"ascending": "Ascendant", "ascending": "Ascendant",
"descending": "Descendant", "descending": "Descendant",
"bgUpdateCheckInterval": "Intervalle de vérification des mises à jour en arrière-plan", "bgUpdateCheckInterval": "Intervalle de vérification des mises à jour en arrière-plan",
"neverManualOnly": "Jamais - Manuel uniquement", "neverManualOnly": "Jamais Manuel uniquement",
"appearance": "Apparence", "appearance": "Apparence",
"showWebInAppView": "Afficher la page Web source dans la vue de l'application", "showWebInAppView": "Afficher la page Web source dans la vue de l'application",
"pinUpdates": "Épingler les mises à jour dans la vue Top des applications", "pinUpdates": "Épingler les mises à jour en tête de la vue Applications",
"updates": "Mises à jour", "updates": "Mises à jour",
"sourceSpecific": "Spécifique à la source", "sourceSpecific": "Spécifique à la source",
"appSource": "Source de l'application", "appSource": "Source de l'application",
@@ -135,13 +135,13 @@
"close": "Fermer", "close": "Fermer",
"share": "Partager", "share": "Partager",
"appNotFound": "Application introuvable", "appNotFound": "Application introuvable",
"obtainiumExportHyphenatedLowercase": "exportation d'Obtainium", "obtainiumExportHyphenatedLowercase": "Exportation-Obtainium",
"pickAnAPK": "Choisissez un APK", "pickAnAPK": "Choisissez un APK",
"appHasMoreThanOnePackage": "{} a plus d'un paquet :", "appHasMoreThanOnePackage": "{} a plus d'un paquet :",
"deviceSupportsXArch": "Votre appareil prend en charge l'architecture CPU {}.", "deviceSupportsXArch": "Votre appareil prend en charge l'architecture CPU {}.",
"deviceSupportsFollowingArchs": "Votre appareil prend en charge les architectures CPU suivantes :", "deviceSupportsFollowingArchs": "Votre appareil prend en charge les architectures CPU suivantes :",
"warning": "Avertissement", "warning": "Avertissement",
"sourceIsXButPackageFromYPrompt": "La source de l'application est '{}' mais la version du paquet provient de '{}'. Continuer?", "sourceIsXButPackageFromYPrompt": "La source de l'application est '{}' mais la version du paquet provient de '{}'. Continuer?",
"updatesAvailable": "Mises à jour disponibles", "updatesAvailable": "Mises à jour disponibles",
"updatesAvailableNotifDescription": "Avertit l'utilisateur que des mises à jour sont disponibles pour une ou plusieurs applications suivies par Obtainium", "updatesAvailableNotifDescription": "Avertit l'utilisateur que des mises à jour sont disponibles pour une ou plusieurs applications suivies par Obtainium",
"noNewUpdates": "Aucune nouvelle mise à jour.", "noNewUpdates": "Aucune nouvelle mise à jour.",
@@ -168,7 +168,7 @@
"unknown": "Inconnu", "unknown": "Inconnu",
"none": "Aucun", "none": "Aucun",
"never": "Jamais", "never": "Jamais",
"latestVersionX": "Dernière version: {}", "latestVersionX": "Dernière version: {}",
"installedVersionX": "Version installée : {}", "installedVersionX": "Version installée : {}",
"lastUpdateCheckX": "Vérification de la dernière mise à jour : {}", "lastUpdateCheckX": "Vérification de la dernière mise à jour : {}",
"remove": "Retirer", "remove": "Retirer",
@@ -179,15 +179,15 @@
"appWithIdOrNameNotFound": "Aucune application n'a été trouvée avec cet identifiant ou ce nom", "appWithIdOrNameNotFound": "Aucune application n'a été trouvée avec cet identifiant ou ce nom",
"reposHaveMultipleApps": "Les dépôts peuvent contenir plusieurs applications", "reposHaveMultipleApps": "Les dépôts peuvent contenir plusieurs applications",
"fdroidThirdPartyRepo": "Dépôt tiers F-Droid", "fdroidThirdPartyRepo": "Dépôt tiers F-Droid",
"steamMobile": "Vapeur Mobile", "steamMobile": "Application mobile Steam",
"steamChat": "Chat sur Steam", "steamChat": "Steam Chat",
"install": "Installer", "install": "Installer",
"markInstalled": "Marquer installée", "markInstalled": "Marquer comme installée",
"update": "Mettre à jour", "update": "Mettre à jour",
"markUpdated": "Marquer à jour", "markUpdated": "Marquer comme étant à jour",
"additionalOptions": "Options additionnelles", "additionalOptions": "Options additionnelles",
"disableVersionDetection": "Désactiver la détection de version", "disableVersionDetection": "Désactiver la détection de version",
"noVersionDetectionExplanation": "Cette option ne doit être utilisée que pour les applications où la détection de version ne fonctionne pas correctement.", "noVersionDetectionExplanation": "Cette option être utilisée uniquement pour les applications où la détection de version ne fonctionne pas correctement.",
"downloadingX": "Téléchargement {}", "downloadingX": "Téléchargement {}",
"downloadX": "Télécharger {}", "downloadX": "Télécharger {}",
"downloadedX": "Téléchargé {}", "downloadedX": "Téléchargé {}",
@@ -199,9 +199,9 @@
"categories": "Catégories", "categories": "Catégories",
"category": "Catégorie", "category": "Catégorie",
"noCategory": "Aucune catégorie", "noCategory": "Aucune catégorie",
"noCategories": "Aucune catégorie", "noCategories": "Aucune catégories",
"deleteCategoriesQuestion": "Supprimer les catégories ?", "deleteCategoriesQuestion": "Supprimer les catégories?",
"categoryDeleteWarning": "Toutes les applications dans les catégories supprimées seront définies sur non catégorisées.", "categoryDeleteWarning": "Toutes les applications dans les catégories supprimées ne seront plus catégorisées.",
"addCategory": "Ajouter une catégorie", "addCategory": "Ajouter une catégorie",
"label": "Étiquette", "label": "Étiquette",
"language": "Langue", "language": "Langue",
@@ -221,18 +221,18 @@
"versionDetection": "Détection des versions", "versionDetection": "Détection des versions",
"standardVersionDetection": "Détection de version standard", "standardVersionDetection": "Détection de version standard",
"groupByCategory": "Regrouper par catégorie", "groupByCategory": "Regrouper par catégorie",
"autoApkFilterByArch": "Si possible, essayez de filtrer les APK par architecture CPU", "autoApkFilterByArch": "Si possible, essayer de filtrer les APK par architecture CPU",
"overrideSource": "Remplacer la source", "overrideSource": "Remplacer la source",
"dontShowAgain": "Ne plus montrer", "dontShowAgain": "Ne plus montrer",
"dontShowTrackOnlyWarnings": "Ne pas afficher l'avertissement 'Track-Only'", "dontShowTrackOnlyWarnings": "Ne pas afficher l'avertissement 'Suivi uniquement'",
"dontShowAPKOriginWarnings": "Ne pas afficher les avertissements sur l'origine de l'APK", "dontShowAPKOriginWarnings": "Ne pas afficher les avertissements sur l'origine de l'APK",
"moveNonInstalledAppsToBottom": "Déplacer les applications non installées vers le bas de la vue Applications", "moveNonInstalledAppsToBottom": "Déplacer les applications non installées vers le bas de la vue Applications",
"gitlabPATLabel": "Jeton d'accès personnel GitLab", "gitlabPATLabel": "Jeton d'accès personnel GitLab",
"about": "À propos de", "about": "À propos de",
"requiresCredentialsInSettings": "{}: Cela nécessite des identifiants supplémentaires (dans Paramètres)", "requiresCredentialsInSettings": "{}: Cela nécessite des identifiants supplémentaires (dans Paramètres)",
"checkOnStart": "Vérifier les mises à jour au démarrage", "checkOnStart": "Vérifier les mises à jour au démarrage",
"tryInferAppIdFromCode": "Essayez de déduire l'ID de l'application à partir du code source", "tryInferAppIdFromCode": "Essayer de déduire l'ID de l'application à partir du code source",
"removeOnExternalUninstall": "Supprimer automatiquement les applications désinstallées en externe", "removeOnExternalUninstall": "Supprimer automatiquement les applications désinstallées depuis l'extérieur",
"pickHighestVersionCode": "Sélectionner automatiquement le code de version de l'APK la plus élevée", "pickHighestVersionCode": "Sélectionner automatiquement le code de version de l'APK la plus élevée",
"checkUpdateOnDetailPage": "Vérifier les mises à jour lors de l'ouverture de la page détaillée d'une application", "checkUpdateOnDetailPage": "Vérifier les mises à jour lors de l'ouverture de la page détaillée d'une application",
"disablePageTransitions": "Désactiver les animations de transition de page", "disablePageTransitions": "Désactiver les animations de transition de page",
@@ -246,32 +246,34 @@
"customLinkFilterRegex": "Filtre du lien APK personnalisé par expression régulière (par défaut '.apk$')", "customLinkFilterRegex": "Filtre du lien APK personnalisé par expression régulière (par défaut '.apk$')",
"appsPossiblyUpdated": "Tentative de mise à jour de l'application", "appsPossiblyUpdated": "Tentative de mise à jour de l'application",
"appsPossiblyUpdatedNotifDescription": "Avertit l'utilisateur que des mises à jour d'une ou plusieurs applications ont été potentiellement appliquées en arrière-plan", "appsPossiblyUpdatedNotifDescription": "Avertit l'utilisateur que des mises à jour d'une ou plusieurs applications ont été potentiellement appliquées en arrière-plan",
"xWasPossiblyUpdatedToY": "{} a peut-être été mis à jour vers {}.", "xWasPossiblyUpdatedToY": "{} pourrait avoir été mis à jour vers {}.",
"enableBackgroundUpdates": "Activer les mises à jour en arrière-plan", "enableBackgroundUpdates": "Activer les mises à jour en arrière-plan",
"backgroundUpdateReqsExplanation": "Les mises à jour en arrière-plan peuvent ne pas être possibles pour toutes les applications.", "backgroundUpdateReqsExplanation": "Les mises à jour en arrière-plan peuvent ne pas être possibles pour toutes les applications.",
"backgroundUpdateLimitsExplanation": "Le succès d'une installation en arrière-plan ne peut être déterminé qu'à l'ouverture d'Obtainium.", "backgroundUpdateLimitsExplanation": "Le succès d'une installation en arrière-plan ne peut être déterminé qu'à l'ouverture d'Obtainium.",
"verifyLatestTag": "Vérifiez la balise 'Latest'", "verifyLatestTag": "Vérifier la balise 'latest'",
"intermediateLinkRegex": " Filtrer un lien \" intermédiaire \" à visiter ", "intermediateLinkRegex": " Filtrer un lien \" intermédiaire \" à visiter ",
"filterByLinkText": "Filtrer les liens par le texte du lien", "filterByLinkText": "Filtrer les liens par le texte du lien",
"intermediateLinkNotFound": "Lien intermédiaire introuvable", "intermediateLinkNotFound": "Lien intermédiaire introuvable",
"intermediateLink": "Lien intermédiaire", "intermediateLink": "Lien intermédiaire",
"exemptFromBackgroundUpdates": "Exempté des mises à jour en arrière-plan (si activé)", "exemptFromBackgroundUpdates": "Exempté des mises à jour en arrière-plan (si activé)",
"bgUpdatesOnWiFiOnly": "Désactiver les mises à jour en arrière-plan lorsque vous n'êtes pas connecté au WiFi", "bgUpdatesOnWiFiOnly": "Désactiver les mises à jour en arrière-plan lorsque vous n'êtes pas connecté au WiFi",
"autoSelectHighestVersionCode": "Sélection automatique du code de version de l'APK la plus élevée", "autoSelectHighestVersionCode": "Sélection automatique du code de version le plus élevé de l'APK",
"versionExtractionRegEx": "Expression régulière d'extraction de version", "versionExtractionRegEx": "Expression régulière d'extraction de version",
"trimVersionString": "Découper une chaîne de version avec RegEx",
"matchGroupToUseForX": "Groupe de correspondance à utiliser pour \"{}\"",
"matchGroupToUse": "Groupe de correspondance pour l'expression régulière d'extraction de version", "matchGroupToUse": "Groupe de correspondance pour l'expression régulière d'extraction de version",
"highlightTouchTargets": "Mettre en évidence les cibles tactiles moins évidentes", "highlightTouchTargets": "Mettre en évidence les cibles tactiles moins évidentes",
"pickExportDir": "Choisir le répertoire d'exportation", "pickExportDir": "Choisir le répertoire d'exportation",
"autoExportOnChanges": "Exporter automatiquement après modification", "autoExportOnChanges": "Exporter automatiquement après modification",
"includeSettings": "Inclure les paramètres", "includeSettings": "Inclure les paramètres",
"filterVersionsByRegEx": "Filtrer les versions par expression régulière", "filterVersionsByRegEx": "Filtrer les versions par expression régulière",
"trySelectingSuggestedVersionCode": "Essayez de sélectionner le code de la version APK suggérée", "trySelectingSuggestedVersionCode": "Essayer de sélectionner le code de la version suggérée de l'APK",
"dontSortReleasesList": "Conserver l'ordre des version de l'API", "dontSortReleasesList": "Conserver l'ordre des versions de l'API",
"reverseSort": "Tri inversé", "reverseSort": "Tri inversé",
"takeFirstLink": "Prendre le premier lien", "takeFirstLink": "Prendre le premier lien",
"skipSort": "Sauter le tri", "skipSort": "Éviter le tri",
"debugMenu": "Menu de débogage", "debugMenu": "Menu de débogage",
"bgTaskStarted": "Tâche en arrière-plan démarrée - vérifier les journaux.", "bgTaskStarted": "Tâche en arrière-plan démarrée vérifier les journaux.",
"runBgCheckNow": "Exécuter maintenant la vérification de la mise à jour en arrière-plan", "runBgCheckNow": "Exécuter maintenant la vérification de la mise à jour en arrière-plan",
"versionExtractWholePage": "Appliquer l'expression régulière d'extraction de version sur l'ensemble de la page", "versionExtractWholePage": "Appliquer l'expression régulière d'extraction de version sur l'ensemble de la page",
"installing": "Installation", "installing": "Installation",
@@ -284,14 +286,14 @@
"downloadingXNotifChannel": "Téléchargement {}", "downloadingXNotifChannel": "Téléchargement {}",
"completeAppInstallationNotifChannel": "Installation complète de l'application", "completeAppInstallationNotifChannel": "Installation complète de l'application",
"checkingForUpdatesNotifChannel": "Vérification des mises à jour", "checkingForUpdatesNotifChannel": "Vérification des mises à jour",
"onlyCheckInstalledOrTrackOnlyApps": "Vérifiez uniquement les mises à jour des applications installées et 'Track-Only'", "onlyCheckInstalledOrTrackOnlyApps": "Vérifier uniquement les mises à jour des applications installées et 'Suivi uniquement'",
"supportFixedAPKURL": "Prise en charge des URL APK fixes", "supportFixedAPKURL": "Prise en charge des URL APK fixes",
"selectX": "Sélectionner {}", "selectX": "Sélectionner {}",
"parallelDownloads": "Autoriser les téléchargements parallèles", "parallelDownloads": "Autoriser le téléchargement en parallèle",
"useShizuku": "Utiliser Shizuku ou Sui pour l'installation", "useShizuku": "Utiliser Shizuku ou Sui pour l'installation",
"shizukuBinderNotFound": "Service Shizuku compatible non trouvé", "shizukuBinderNotFound": "Service Shizuku compatible non trouvé",
"shizukuOld": "Ancienne version de Shizuku (<11) - la mettre à jour", "shizukuOld": "Ancienne version de Shizuku (<11) la mettre à jour",
"shizukuOldAndroidWithADB": "Shizuku fonctionne sur Android < 8.1 avec ADB - mettre à jour Android ou utiliser Sui à la place", "shizukuOldAndroidWithADB": "Shizuku fonctionne sur Android < 8.1 avec ADB mettez à jour Android ou utilisez Sui à la place",
"shizukuPretendToBeGooglePlay": "Définir Google Play comme source d'installation (si Shizuku est utilisé)", "shizukuPretendToBeGooglePlay": "Définir Google Play comme source d'installation (si Shizuku est utilisé)",
"useSystemFont": "Utiliser la police du système", "useSystemFont": "Utiliser la police du système",
"useVersionCodeAsOSVersion": "Utiliser le code de version de l'application comme version détectée par le système d'exploitation", "useVersionCodeAsOSVersion": "Utiliser le code de version de l'application comme version détectée par le système d'exploitation",
@@ -311,22 +313,22 @@
"beforeNewInstallsShareToAppVerifier": "Partager les nouvelles applications avec AppVerifier (si disponible)", "beforeNewInstallsShareToAppVerifier": "Partager les nouvelles applications avec AppVerifier (si disponible)",
"appVerifierInstructionToast": "Partagez avec AppVerifier, puis revenez ici lorsque vous êtes prêt.", "appVerifierInstructionToast": "Partagez avec AppVerifier, puis revenez ici lorsque vous êtes prêt.",
"wiki": "Aide/Wiki", "wiki": "Aide/Wiki",
"crowdsourcedConfigsLabel": "Configurations d'applications par la foule (utilisation à vos risques et périls)", "crowdsourcedConfigsLabel": "Configurations d'applications participative (utilisation à vos risques et périls)",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Supprimer l'application ?", "one": "Supprimer l'application?",
"other": "Supprimer les applications ?" "other": "Supprimer les applications?"
}, },
"tooManyRequestsTryAgainInMinutes": { "tooManyRequestsTryAgainInMinutes": {
"one": "Trop de demandes (taux limité) - réessayez dans {} minute", "one": "Trop de demandes (taux limité) réessayez dans {} minute",
"other": "Trop de demandes (taux limité) - réessayez dans {} minutes" "other": "Trop de demandes (taux limité) réessayez dans {} minutes"
}, },
"bgUpdateGotErrorRetryInMinutes": { "bgUpdateGotErrorRetryInMinutes": {
"one": "La vérification de la mise à jour en arrière-plan a rencontré un {}, une nouvelle tentative de vérification sera planifié dans {} minute", "one": "La vérification de la mise à jour en arrière-plan a rencontré un {}, une nouvelle tentative de vérification sera planifié dans {} minute",
"other": "La vérification de la mise à jour en arrière-plan a rencontré un {}, une nouvelle tentative de vérification sera planifié dans {} minute" "other": "La vérification de la mise à jour en arrière-plan a rencontré un {}, une nouvelle tentative de vérification sera planifié dans {} minutes"
}, },
"bgCheckFoundUpdatesWillNotifyIfNeeded": { "bgCheckFoundUpdatesWillNotifyIfNeeded": {
"one": "La vérification des mises à jour en arrière-plan a trouvée {} mise à jour - l'utilisateur sera notifié si nécessaire", "one": "La vérification des mises à jour en arrière-plan a trouvée {} mise à jour l'utilisateur sera notifié si nécessaire",
"other": "La vérification des mises à jour en arrière-plan a trouvé {} mises à jour - l'utilisateur sera notifié si nécessaire" "other": "La vérification des mises à jour en arrière-plan a trouvée {} mises à jour  l'utilisateur sera notifié si nécessaire"
}, },
"apps": { "apps": {
"one": "{} Application", "one": "{} Application",
@@ -365,8 +367,8 @@
"other": "Échec de la mise à jour de {} et {} autres applications." "other": "Échec de la mise à jour de {} et {} autres applications."
}, },
"xAndNMoreUpdatesPossiblyInstalled": { "xAndNMoreUpdatesPossiblyInstalled": {
"une": "{} et 1 application supplémentaire ont peut-être été mises à jour.", "une": "{} et 1 application supplémentaire pourraient avoir été mises à jour.",
"other": "{} et {} autres applications peuvent avoir été mises à jour." "other": "{} et {} autres applications pourraient avoir été mises à jour."
}, },
"apk": { "apk": {
"one": "{} APK", "one": "{} APK",

View File

@@ -259,6 +259,8 @@
"bgUpdatesOnWiFiOnly": "Tiltsa le a háttérben frissítéseket, ha nincs Wi-Fi-n", "bgUpdatesOnWiFiOnly": "Tiltsa le a háttérben frissítéseket, ha nincs Wi-Fi-n",
"autoSelectHighestVersionCode": "A legmagasabb verziószámú APK auto. kiválasztása", "autoSelectHighestVersionCode": "A legmagasabb verziószámú APK auto. kiválasztása",
"versionExtractionRegEx": "Verzió kibontása reguláris kifejezéssel", "versionExtractionRegEx": "Verzió kibontása reguláris kifejezéssel",
"trimVersionString": "Trim Version String RegEx-szel",
"matchGroupToUseForX": "A \"{}\" csoporthoz használandó csoport egyeztetése",
"matchGroupToUse": "Párosítsa a csoportot a használathoz", "matchGroupToUse": "Párosítsa a csoportot a használathoz",
"highlightTouchTargets": "Emelje ki a kevésbé nyilvánvaló érintési célokat", "highlightTouchTargets": "Emelje ki a kevésbé nyilvánvaló érintési célokat",
"pickExportDir": "Válassza az Exportálási könyvtárat", "pickExportDir": "Válassza az Exportálási könyvtárat",

View File

@@ -259,6 +259,8 @@
"bgUpdatesOnWiFiOnly": "Disattiva aggiornamenti in secondo piano quando non si usa il WiFi", "bgUpdatesOnWiFiOnly": "Disattiva aggiornamenti in secondo piano quando non si usa il WiFi",
"autoSelectHighestVersionCode": "Auto-seleziona APK con versionCode più alto", "autoSelectHighestVersionCode": "Auto-seleziona APK con versionCode più alto",
"versionExtractionRegEx": "RegEx di estrazione versione", "versionExtractionRegEx": "RegEx di estrazione versione",
"trimVersionString": "Tagliare la stringa della versione con RegEx",
"matchGroupToUseForX": "Gruppo di corrispondenza da utilizzare per \"{}\"",
"matchGroupToUse": "Gruppo da usare", "matchGroupToUse": "Gruppo da usare",
"highlightTouchTargets": "Evidenzia elementi toccabili meno ovvi", "highlightTouchTargets": "Evidenzia elementi toccabili meno ovvi",
"pickExportDir": "Scegli cartella esp.", "pickExportDir": "Scegli cartella esp.",

View File

@@ -259,6 +259,8 @@
"bgUpdatesOnWiFiOnly": "WiFiを使用していない場合、バックグラウンドアップデートを無効にする", "bgUpdatesOnWiFiOnly": "WiFiを使用していない場合、バックグラウンドアップデートを無効にする",
"autoSelectHighestVersionCode": "最も高いバージョンコードのAPKを自動で選択する", "autoSelectHighestVersionCode": "最も高いバージョンコードのAPKを自動で選択する",
"versionExtractionRegEx": "バージョン抽出の正規表現", "versionExtractionRegEx": "バージョン抽出の正規表現",
"trimVersionString": "RegExでバージョン文字列をトリムする",
"matchGroupToUseForX": "\"{}\"に使用するマッチグループ",
"matchGroupToUse": "使用するマッチしたグループ", "matchGroupToUse": "使用するマッチしたグループ",
"highlightTouchTargets": "目立たないタップ可能な対象をハイライトする", "highlightTouchTargets": "目立たないタップ可能な対象をハイライトする",
"pickExportDir": "エクスポートディレクトリを選択", "pickExportDir": "エクスポートディレクトリを選択",

View File

@@ -259,6 +259,8 @@
"bgUpdatesOnWiFiOnly": "Achtergrond-updates uitschakelen wanneer niet verbonden met WiFi", "bgUpdatesOnWiFiOnly": "Achtergrond-updates uitschakelen wanneer niet verbonden met WiFi",
"autoSelectHighestVersionCode": "De APK met de hoogste versiecode automatisch selecteren", "autoSelectHighestVersionCode": "De APK met de hoogste versiecode automatisch selecteren",
"versionExtractionRegEx": "Reguliere expressie voor versie-extractie", "versionExtractionRegEx": "Reguliere expressie voor versie-extractie",
"trimVersionString": "Versie string trimmen met RegEx",
"matchGroupToUseForX": "Overeenkomende groep te gebruiken voor \"{}\"",
"matchGroupToUse": "Overeenkomende groep om te gebruiken voor de reguliere expressie voor versie-extractie", "matchGroupToUse": "Overeenkomende groep om te gebruiken voor de reguliere expressie voor versie-extractie",
"highlightTouchTargets": "Minder voor de hand liggende aanraakdoelen markeren.", "highlightTouchTargets": "Minder voor de hand liggende aanraakdoelen markeren.",
"pickExportDir": "Kies de exportmap", "pickExportDir": "Kies de exportmap",

View File

@@ -259,6 +259,8 @@
"bgUpdatesOnWiFiOnly": "Wyłącz aktualizacje w tle, gdy nie ma połączenia z Wi-Fi", "bgUpdatesOnWiFiOnly": "Wyłącz aktualizacje w tle, gdy nie ma połączenia z Wi-Fi",
"autoSelectHighestVersionCode": "Automatycznie wybierz najwyższy kod wersji APK", "autoSelectHighestVersionCode": "Automatycznie wybierz najwyższy kod wersji APK",
"versionExtractionRegEx": "Wyrażenie regularne wyodrębniające wersję", "versionExtractionRegEx": "Wyrażenie regularne wyodrębniające wersję",
"trimVersionString": "Przycinanie łańcucha wersji za pomocą RegEx",
"matchGroupToUseForX": "Dopasuj grupę do użycia dla \"{}\"",
"matchGroupToUse": "Dopasuj grupę do użycia dla wyrażenia regularnego wyodrębniania wersji", "matchGroupToUse": "Dopasuj grupę do użycia dla wyrażenia regularnego wyodrębniania wersji",
"highlightTouchTargets": "Wyróżnij mniej oczywiste elementy dotykowe", "highlightTouchTargets": "Wyróżnij mniej oczywiste elementy dotykowe",
"pickExportDir": "Wybierz katalog eksportu", "pickExportDir": "Wybierz katalog eksportu",

View File

@@ -259,6 +259,8 @@
"bgUpdatesOnWiFiOnly": "Desative as atualizações em segundo-plano quando não estiver conectado no Wi-Fi", "bgUpdatesOnWiFiOnly": "Desative as atualizações em segundo-plano quando não estiver conectado no Wi-Fi",
"autoSelectHighestVersionCode": "Auto-selecionar a versão mais recente", "autoSelectHighestVersionCode": "Auto-selecionar a versão mais recente",
"versionExtractionRegEx": "Regex de extração de versão", "versionExtractionRegEx": "Regex de extração de versão",
"trimVersionString": "Cortar a cadeia de caracteres da versão com RegEx",
"matchGroupToUseForX": "Grupo de correspondência a utilizar para \"{}\"",
"matchGroupToUse": "Grupo correspondente a ser usado no Regex de extração de versão", "matchGroupToUse": "Grupo correspondente a ser usado no Regex de extração de versão",
"highlightTouchTargets": "Realçar áreas sensíveis ao toque que são menos óbvias", "highlightTouchTargets": "Realçar áreas sensíveis ao toque que são menos óbvias",
"pickExportDir": "Escolher diretório para exportação", "pickExportDir": "Escolher diretório para exportação",

View File

@@ -129,7 +129,7 @@
"pinUpdates": "Отображать обновления приложений сверху списка", "pinUpdates": "Отображать обновления приложений сверху списка",
"updates": "Обновления", "updates": "Обновления",
"sourceSpecific": "Настройки источников", "sourceSpecific": "Настройки источников",
"appSource": "Исходный код", "appSource": "Источник",
"noLogs": "Нет журналов", "noLogs": "Нет журналов",
"appLogs": "Логи", "appLogs": "Логи",
"close": "Закрыть", "close": "Закрыть",
@@ -259,6 +259,8 @@
"bgUpdatesOnWiFiOnly": "Отключить фоновые обновления, если нет соединения с Wi-Fi", "bgUpdatesOnWiFiOnly": "Отключить фоновые обновления, если нет соединения с Wi-Fi",
"autoSelectHighestVersionCode": "Автоматически выбирать APK с актуальной версией кода", "autoSelectHighestVersionCode": "Автоматически выбирать APK с актуальной версией кода",
"versionExtractionRegEx": "Регулярное выражение для извлечения версии", "versionExtractionRegEx": "Регулярное выражение для извлечения версии",
"trimVersionString": "Обрезка строки версии с помощью RegEx",
"matchGroupToUseForX": "Группа соответствия, которую следует использовать для \"{}\"",
"matchGroupToUse": "Выберите группу для использования", "matchGroupToUse": "Выберите группу для использования",
"highlightTouchTargets": "Выделить менее очевидные элементы управления касанием", "highlightTouchTargets": "Выделить менее очевидные элементы управления касанием",
"pickExportDir": "Выбрать каталог для экспорта", "pickExportDir": "Выбрать каталог для экспорта",

View File

@@ -259,6 +259,8 @@
"bgUpdatesOnWiFiOnly": "Inaktivera Bakgrundsuppdateringar utan WiFi", "bgUpdatesOnWiFiOnly": "Inaktivera Bakgrundsuppdateringar utan WiFi",
"autoSelectHighestVersionCode": "Välj automatiskt högsta versionskod APK", "autoSelectHighestVersionCode": "Välj automatiskt högsta versionskod APK",
"versionExtractionRegEx": "Version Extraction RegEx", "versionExtractionRegEx": "Version Extraction RegEx",
"trimVersionString": "Trimma versionssträng med RegEx",
"matchGroupToUseForX": "Matchningsgrupp att använda för \"{}\"",
"matchGroupToUse": "Match Group to Use", "matchGroupToUse": "Match Group to Use",
"highlightTouchTargets": "Markera mindre uppenbara beröringsobjekt", "highlightTouchTargets": "Markera mindre uppenbara beröringsobjekt",
"pickExportDir": "Välj Exportsökväg", "pickExportDir": "Välj Exportsökväg",

View File

@@ -259,6 +259,8 @@
"bgUpdatesOnWiFiOnly": "WiFi olmadığında arka plan güncellemelerini devre dışı bırak", "bgUpdatesOnWiFiOnly": "WiFi olmadığında arka plan güncellemelerini devre dışı bırak",
"autoSelectHighestVersionCode": "Otomatik olarak en yüksek sürüm kodunu seç", "autoSelectHighestVersionCode": "Otomatik olarak en yüksek sürüm kodunu seç",
"versionExtractionRegEx": "Sürüm Çıkarma Düzenli İfade", "versionExtractionRegEx": "Sürüm Çıkarma Düzenli İfade",
"trimVersionString": "RegEx ile Sürüm Dizesini Kırpma",
"matchGroupToUseForX": "\"{}\" için Kullanılacak Grubu Eşleştirin",
"matchGroupToUse": "Sürüm Çıkarma Regex için Kullanılacak Eşleşme Grubu", "matchGroupToUse": "Sürüm Çıkarma Regex için Kullanılacak Eşleşme Grubu",
"highlightTouchTargets": "Daha az belirgin dokunma hedeflerini vurgula", "highlightTouchTargets": "Daha az belirgin dokunma hedeflerini vurgula",
"pickExportDir": "Dışa Aktarılacak Klasörü Seç", "pickExportDir": "Dışa Aktarılacak Klasörü Seç",

View File

@@ -259,6 +259,8 @@
"bgUpdatesOnWiFiOnly": "Вимкнути фонові оновлення поза Wi-Fi", "bgUpdatesOnWiFiOnly": "Вимкнути фонові оновлення поза Wi-Fi",
"autoSelectHighestVersionCode": "Автоматичний вибір APK з найвищим кодом версії", "autoSelectHighestVersionCode": "Автоматичний вибір APK з найвищим кодом версії",
"versionExtractionRegEx": "Регулярний вираз для вилучення рядка версії", "versionExtractionRegEx": "Регулярний вираз для вилучення рядка версії",
"trimVersionString": "Обрізати рядок версії за допомогою RegEx",
"matchGroupToUseForX": "Група збігів для \"{}\"",
"matchGroupToUse": "Група співпадінь для використання в регулярному виразі вилучення версії", "matchGroupToUse": "Група співпадінь для використання в регулярному виразі вилучення версії",
"highlightTouchTargets": "Підсвічувати менш очевидні області дотику", "highlightTouchTargets": "Підсвічувати менш очевидні області дотику",
"pickExportDir": "Вибрати каталог експорту", "pickExportDir": "Вибрати каталог експорту",

View File

@@ -22,9 +22,9 @@
"requiredInBrackets": "(Yêu cầu)", "requiredInBrackets": "(Yêu cầu)",
"dropdownNoOptsError": "LỖI: TẢI XUỐNG PHẢI CÓ ÍT NHẤT MỘT LỰA CHỌN", "dropdownNoOptsError": "LỖI: TẢI XUỐNG PHẢI CÓ ÍT NHẤT MỘT LỰA CHỌN",
"colour": "Màu sắc", "colour": "Màu sắc",
"standard": "Standard", "standard": "Mặc định",
"custom": "Custom", "custom": "Tùy chỉnh",
"useMaterialYou": "Use Material You", "useMaterialYou": "Sử dụng Material You",
"githubStarredRepos": "Kho lưu trữ có gắn dấu sao GitHub", "githubStarredRepos": "Kho lưu trữ có gắn dấu sao GitHub",
"uname": "Tên người dùng", "uname": "Tên người dùng",
"wrongArgNum": "Số lượng đối số được cung cấp sai", "wrongArgNum": "Số lượng đối số được cung cấp sai",
@@ -147,10 +147,10 @@
"noNewUpdates": "Không có bản cập nhật mới.", "noNewUpdates": "Không có bản cập nhật mới.",
"xHasAnUpdate": "{} có bản cập nhật.", "xHasAnUpdate": "{} có bản cập nhật.",
"appsUpdated": "Ứng dụng đã cập nhật ", "appsUpdated": "Ứng dụng đã cập nhật ",
"appsNotUpdated": "Failed to update applications", "appsNotUpdated": "Ứng dụng đã cập nhật không thành công",
"appsUpdatedNotifDescription": "Thông báo cho người dùng rằng các bản cập nhật cho một hoặc nhiều Ứng dụng đã được áp dụng trong nền", "appsUpdatedNotifDescription": "Thông báo cho người dùng rằng các bản cập nhật cho một hoặc nhiều Ứng dụng đã được áp dụng trong nền",
"xWasUpdatedToY": "{} đã được cập nhật thành {}.", "xWasUpdatedToY": "{} đã được cập nhật thành {}.",
"xWasNotUpdatedToY": "Failed to update {} to {}.", "xWasNotUpdatedToY": "{} đã cập nhật thành {} không thành công.",
"errorCheckingUpdates": "Lỗi kiểm tra bản cập nhật", "errorCheckingUpdates": "Lỗi kiểm tra bản cập nhật",
"errorCheckingUpdatesNotifDescription": "Thông báo hiển thị khi kiểm tra cập nhật nền không thành công", "errorCheckingUpdatesNotifDescription": "Thông báo hiển thị khi kiểm tra cập nhật nền không thành công",
"appsRemoved": "Ứng dụng đã loại bỏ", "appsRemoved": "Ứng dụng đã loại bỏ",
@@ -189,8 +189,8 @@
"disableVersionDetection": "Tắt tính năng phát hiện phiên bản", "disableVersionDetection": "Tắt tính năng phát hiện phiên bản",
"noVersionDetectionExplanation": "Chỉ nên sử dụng tùy chọn này cho Ứng dụng mà tính năng phát hiện phiên bản không hoạt động chính xác.", "noVersionDetectionExplanation": "Chỉ nên sử dụng tùy chọn này cho Ứng dụng mà tính năng phát hiện phiên bản không hoạt động chính xác.",
"downloadingX": "Đang tải xuống {}", "downloadingX": "Đang tải xuống {}",
"downloadX": "Download {}", "downloadX": "Tải xuống {}",
"downloadedX": "Downloaded {}", "downloadedX": "Đã tải xuống {}",
"releaseAsset": "Release Asset", "releaseAsset": "Release Asset",
"downloadNotifDescription": "Thông báo cho người dùng về tiến trình tải xuống Ứng dụng", "downloadNotifDescription": "Thông báo cho người dùng về tiến trình tải xuống Ứng dụng",
"noAPKFound": "Không tìm thấy APK", "noAPKFound": "Không tìm thấy APK",
@@ -259,6 +259,8 @@
"bgUpdatesOnWiFiOnly": "Tắt cập nhật nền khi không có WiFi", "bgUpdatesOnWiFiOnly": "Tắt cập nhật nền khi không có WiFi",
"autoSelectHighestVersionCode": "Tự động chọn APK mã phiên bản cao nhất", "autoSelectHighestVersionCode": "Tự động chọn APK mã phiên bản cao nhất",
"versionExtractionRegEx": "Trích xuất phiên bản RegEx", "versionExtractionRegEx": "Trích xuất phiên bản RegEx",
"trimVersionString": "Trim Version String With RegEx",
"matchGroupToUseForX": "Match Group to Use for \"{}\"",
"matchGroupToUse": "Nhóm đối sánh để sử dụng cho Regex trích xuất phiên bản", "matchGroupToUse": "Nhóm đối sánh để sử dụng cho Regex trích xuất phiên bản",
"highlightTouchTargets": "Đánh dấu các mục tiêu cảm ứng ít rõ ràng hơn", "highlightTouchTargets": "Đánh dấu các mục tiêu cảm ứng ít rõ ràng hơn",
"pickExportDir": "Chọn thư mục xuất", "pickExportDir": "Chọn thư mục xuất",
@@ -288,10 +290,10 @@
"supportFixedAPKURL": "Hỗ trợ URL APK cố định", "supportFixedAPKURL": "Hỗ trợ URL APK cố định",
"selectX": "Lựa chọn {}", "selectX": "Lựa chọn {}",
"parallelDownloads": "Cho phép tải đa luồng", "parallelDownloads": "Cho phép tải đa luồng",
"useShizuku": "Use Shizuku or Sui to install", "useShizuku": "Sử dụng Shizuku hoặc Sui để cài đặt",
"shizukuBinderNotFound": "Shizuku chưa khởi động", "shizukuBinderNotFound": "Shizuku chưa khởi động",
"shizukuOld": "Old Shizuku version (<11) - update it", "shizukuOld": "Phiên bản Shizuku lỗi thời (<11) - hãy cập nhật nó",
"shizukuOldAndroidWithADB": "Shizuku running on Android < 8.1 with ADB - update Android or use Sui instead", "shizukuOldAndroidWithADB": "Shizuku chạy trên Android < 8.1 với ADB - hãy cập nhật Android hoặc thay bằng Sui",
"shizukuPretendToBeGooglePlay": "Set Google Play as the installation source (if Shizuku is used)", "shizukuPretendToBeGooglePlay": "Set Google Play as the installation source (if Shizuku is used)",
"useSystemFont": "Sử dụng phông chữ hệ thống", "useSystemFont": "Sử dụng phông chữ hệ thống",
"useVersionCodeAsOSVersion": "Sử dụng Mã phiên bản ứng dụng làm phiên bản do hệ điều hành phát hiện", "useVersionCodeAsOSVersion": "Sử dụng Mã phiên bản ứng dụng làm phiên bản do hệ điều hành phát hiện",
@@ -310,7 +312,7 @@
"badDownload": "Không thể phân tích cú pháp APK (tải xuống một phần hoặc không tương thích)", "badDownload": "Không thể phân tích cú pháp APK (tải xuống một phần hoặc không tương thích)",
"beforeNewInstallsShareToAppVerifier": "Chia sẻ ứng dụng mới với AppVerifier (nếu có)", "beforeNewInstallsShareToAppVerifier": "Chia sẻ ứng dụng mới với AppVerifier (nếu có)",
"appVerifierInstructionToast": "Chia sẻ lên AppVerifier, sau đó quay lại đây khi sẵn sàng.", "appVerifierInstructionToast": "Chia sẻ lên AppVerifier, sau đó quay lại đây khi sẵn sàng.",
"wiki": "Help/Wiki", "wiki": "Trợ giúp/Wiki",
"crowdsourcedConfigsLabel": "Crowdsourced App Configurations (use at your own risk)", "crowdsourcedConfigsLabel": "Crowdsourced App Configurations (use at your own risk)",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Gỡ ứng dụng?", "one": "Gỡ ứng dụng?",
@@ -361,8 +363,8 @@
"other": "{} và {} ứng dụng khác đã được cập nhật." "other": "{} và {} ứng dụng khác đã được cập nhật."
}, },
"xAndNMoreUpdatesFailed": { "xAndNMoreUpdatesFailed": {
"one": "Failed to update {} and 1 more app.", "one": "{} và 1 ứng dụng khác đã cập nhật không thành công.",
"other": "Failed to update {} and {} more apps." "other": "{} và {} ứng dụng khác đã cập nhật không thảnh công."
}, },
"xAndNMoreUpdatesPossiblyInstalled": { "xAndNMoreUpdatesPossiblyInstalled": {
"one": "{} và 1 ứng dụng khác có thể đã được cập nhật.", "one": "{} và 1 ứng dụng khác có thể đã được cập nhật.",

View File

@@ -0,0 +1,377 @@
{
"invalidURLForSource": "不是有效的 {} 應用程式 URL",
"noReleaseFound": "找不到合適的版本",
"noVersionFound": "無法確定版本",
"urlMatchesNoSource": "URL 不符合已知來源",
"cantInstallOlderVersion": "無法安裝舊版本的應用程式",
"appIdMismatch": "下載的套件 ID 與現有的應用程式 ID 不匹配",
"functionNotImplemented": "此類別尚未實作此功能",
"placeholder": "佔位",
"someErrors": "發生了一些錯誤",
"unexpectedError": "意外錯誤",
"ok": "確定",
"and": "和",
"githubPATLabel": "GitHub 個人存取權杖(增加速率限制)",
"includePrereleases": "包含預發佈版本",
"fallbackToOlderReleases": "回退到舊版本",
"filterReleaseTitlesByRegEx": "用正則表達式過濾版本標題",
"invalidRegEx": "無效的正則表達式",
"noDescription": "無描述",
"cancel": "取消",
"continue": "繼續",
"requiredInBrackets": "(必填)",
"dropdownNoOptsError": "錯誤:下拉選單必須至少有一個選項",
"colour": "顏色",
"standard": "標準",
"custom": "自訂",
"useMaterialYou": "使用 Material You",
"githubStarredRepos": "GitHub Starred Repos",
"uname": "使用者名稱",
"wrongArgNum": "提供的參數數量錯誤",
"xIsTrackOnly": "{} 是僅追蹤",
"source": "來源",
"app": "應用程式",
"appsFromSourceAreTrackOnly": "來自此來源的應用程式是「僅追蹤」。",
"youPickedTrackOnly": "您已選擇「僅追蹤」選項。",
"trackOnlyAppDescription": "該應用程式將被追蹤更新,但 Obtainium 將無法下載或安裝它。",
"cancelled": "已取消",
"appAlreadyAdded": "應用程式已添加",
"alreadyUpToDateQuestion": "應用程式已經是最新的?",
"addApp": "添加應用程式",
"appSourceURL": "應用程式來源 URL",
"error": "錯誤",
"add": "添加",
"searchSomeSourcesLabel": "搜尋(僅限部分來源)",
"search": "搜尋",
"additionalOptsFor": "{} 的其他選項",
"supportedSources": "支持的來源",
"trackOnlyInBrackets": "(僅追蹤)",
"searchableInBrackets": "(可搜尋)",
"appsString": "應用程式",
"noApps": "無應用程式",
"noAppsForFilter": "無符合過濾條件的應用程式",
"byX": "由 {}",
"percentProgress": "進度:{}%",
"pleaseWait": "請稍候",
"updateAvailable": "有可用的更新",
"notInstalled": "未安裝",
"pseudoVersion": "偽版本",
"selectAll": "全選",
"deselectX": "取消選取 {}",
"xWillBeRemovedButRemainInstalled": "{} 將從 Obtainium 中移除,但仍然安裝在設備上。",
"removeSelectedAppsQuestion": "移除選取的應用程式?",
"removeSelectedApps": "移除選取的應用程式",
"updateX": "更新 {}",
"installX": "安裝 {}",
"markXTrackOnlyAsUpdated": "標記 {}\n僅追蹤\n為已更新",
"changeX": "更改 {}",
"installUpdateApps": "安裝/更新應用程式",
"installUpdateSelectedApps": "安裝/更新選取的應用程式",
"markXSelectedAppsAsUpdated": "標記 {} 個選取的應用程式為已更新?",
"no": "否",
"yes": "是",
"markSelectedAppsUpdated": "標記選取的應用程式為已更新",
"pinToTop": "釘選到頂部",
"unpinFromTop": "取消釘選",
"resetInstallStatusForSelectedAppsQuestion": "重設選取應用程式的安裝狀態?",
"installStatusOfXWillBeResetExplanation": "任何選取應用程式的安裝狀態將被重設。\n\n這可以在由於更新失敗或其他問題導致 Obtainium 顯示的應用程式版本不正確時有所幫助。",
"customLinkMessage": "這些連結適用於已安裝 Obtainium 的設備",
"shareAppConfigLinks": "分享應用程式配置為 HTML 連結",
"shareSelectedAppURLs": "分享選取的應用程式 URL",
"resetInstallStatus": "重設安裝狀態",
"more": "更多",
"removeOutdatedFilter": "移除過時應用程式過濾",
"showOutdatedOnly": "僅顯示過時的應用程式",
"filter": "過濾",
"filterApps": "過濾應用程式",
"appName": "應用程式名稱",
"author": "作者",
"upToDateApps": "最新的應用程式",
"nonInstalledApps": "未安裝的應用程式",
"importExport": "匯入/匯出",
"settings": "設定",
"exportedTo": "匯出到 {}",
"obtainiumExport": "Obtainium 匯出",
"invalidInput": "無效的輸入",
"importedX": "已匯入 {}",
"obtainiumImport": "Obtainium 匯入",
"importFromURLList": "從 URL 列表匯入",
"searchQuery": "搜尋查詢",
"appURLList": "應用程式 URL 清單",
"line": "行",
"searchX": "搜尋 {}",
"noResults": "未找到結果",
"importX": "匯入 {}",
"importedAppsIdDisclaimer": "匯入的應用程式可能會錯誤地顯示為「未安裝」。\n要修正此問題請通過 Obtainium 重新安裝它們。\n這不應該影響應用程式數據。\n\n僅影響 URL 和第三方匯入方法。",
"importErrors": "匯入錯誤",
"importedXOfYApps": "已匯入 {} 個中的 {} 個應用程式。",
"followingURLsHadErrors": "以下 URL 有錯誤:",
"selectURL": "選擇 URL",
"selectURLs": "選擇多個 URL",
"pick": "選取",
"theme": "主題",
"dark": "深色",
"light": "淺色",
"followSystem": "跟隨系統",
"followSystemThemeExplanation": "僅使用第三方應用程式時才可跟隨系統主題",
"useBlackTheme": "使用純黑色深色主題",
"appSortBy": "應用程式排序依據",
"authorName": "作者/名稱",
"nameAuthor": "名稱/作者",
"asAdded": "添加順序",
"appSortOrder": "應用程式排序順序",
"ascending": "升序",
"descending": "降序",
"bgUpdateCheckInterval": "背景更新檢查間隔",
"neverManualOnly": "從不 - 僅手動",
"appearance": "外觀",
"showWebInAppView": "在應用程式檢視中顯示來源網頁",
"pinUpdates": "將更新釘選至應用程式檢視的頂端",
"updates": "更新",
"sourceSpecific": "特定來源",
"appSource": "應用程式來源",
"noLogs": "無日誌",
"appLogs": "應用程式日誌",
"close": "關閉",
"share": "分享",
"appNotFound": "未找到應用程式",
"obtainiumExportHyphenatedLowercase": "obtainium-export",
"pickAnAPK": "選擇一個 APK",
"appHasMoreThanOnePackage": "{} 有多個套件:",
"deviceSupportsXArch": "您的設備支持 {} CPU 架構。",
"deviceSupportsFollowingArchs": "您的設備支持以下 CPU 架構:",
"warning": "警告",
"sourceIsXButPackageFromYPrompt": "應用程式來源是 「{}」,但發佈套件來自 「{}」。要繼續嗎?",
"updatesAvailable": "有可用的更新",
"updatesAvailableNotifDescription": "通知使用者有一個或多個由 Obtainium 追蹤的應用程式有更新",
"noNewUpdates": "沒有新更新。",
"xHasAnUpdate": "{} 有一個更新。",
"appsUpdated": "應用程式已更新",
"appsNotUpdated": "未能更新應用程式",
"appsUpdatedNotifDescription": "通知使用者一個或多個應用程式的更新已在背景中應用",
"xWasUpdatedToY": "{} 已更新到 {}。",
"xWasNotUpdatedToY": "未能將 {} 更新到 {}。",
"errorCheckingUpdates": "檢查更新時出錯",
"errorCheckingUpdatesNotifDescription": "背景檢查更新失敗時顯示的通知",
"appsRemoved": "應用程式已移除",
"appsRemovedNotifDescription": "通知使用者由於載入時出錯,一個或多個應用程式已被移除",
"xWasRemovedDueToErrorY": "{} 已因以下錯誤被移除:{}",
"completeAppInstallation": "完成應用程式安裝",
"obtainiumMustBeOpenToInstallApps": "Obtainium 必須開啟才能安裝應用程式",
"completeAppInstallationNotifDescription": "請使用者返回 Obtainium 以完成應用程式安裝",
"checkingForUpdates": "正在檢查更新",
"checkingForUpdatesNotifDescription": "檢查更新時顯示的暫時性通知",
"pleaseAllowInstallPerm": "請允許 Obtainium 安裝應用程式",
"trackOnly": "僅追蹤",
"errorWithHttpStatusCode": "錯誤 {}",
"versionCorrectionDisabled": "版本校正已禁用(外掛程式似乎無法正常工作)",
"unknown": "未知",
"none": "無",
"never": "從不",
"latestVersionX": "最新版本:{}",
"installedVersionX": "已安裝版本:{}",
"lastUpdateCheckX": "上次檢查更新時間:{}",
"remove": "移除",
"yesMarkUpdated": "是,標記為已更新",
"fdroid": "F-Droid 官方",
"appIdOrName": "應用程式 ID 或名稱",
"appId": "應用程式 ID",
"appWithIdOrNameNotFound": "找不到具有該 ID 或名稱的應用程式",
"reposHaveMultipleApps": "倉庫可能包含多個應用程式",
"fdroidThirdPartyRepo": "F-Droid 第三方倉庫",
"steamMobile": "Steam 行動版",
"steamChat": "Steam 聊天",
"install": "安裝",
"markInstalled": "標記為已安裝",
"update": "更新",
"markUpdated": "標記為已更新",
"additionalOptions": "額外選項",
"disableVersionDetection": "禁用版本檢測",
"noVersionDetectionExplanation": "此選項僅應用於版本檢測無法正確工作的應用程式。",
"downloadingX": "正在下載 {}",
"downloadX": "下載 {}",
"downloadedX": "已下載 {}",
"releaseAsset": "發佈資源",
"downloadNotifDescription": "通知使用者應用程式下載進度",
"noAPKFound": "未找到 APK",
"noVersionDetection": "無版本檢測",
"categorize": "分類",
"categories": "類別",
"category": "類別",
"noCategory": "無類別",
"noCategories": "無類別",
"deleteCategoriesQuestion": "刪除類別?",
"categoryDeleteWarning": "所有在已刪除類別中的應用程式將被設置為未分類。",
"addCategory": "新增類別",
"label": "標籤",
"language": "語言",
"copiedToClipboard": "已複製到剪貼簿",
"storagePermissionDenied": "存取權限被拒絕",
"selectedCategorizeWarning": "這將替換選取應用程式的任何現有類別設置。",
"filterAPKsByRegEx": "用正則表達式過濾 APK",
"removeFromObtainium": "從 Obtainium 移除",
"uninstallFromDevice": "從設備解除安裝",
"onlyWorksWithNonVersionDetectApps": "僅適用於禁用版本檢測的應用程式。",
"releaseDateAsVersion": "使用發佈日期作為版本字串",
"releaseDateAsVersionExplanation": "此選項僅應用於版本檢測無法正確工作但有發佈日期的應用程式。",
"changes": "變更",
"releaseDate": "發佈日期",
"importFromURLsInFile": "從文件中的 URL 匯入(如 OPML",
"versionDetectionExplanation": "將版本字串與作業系統檢測到的版本對比",
"versionDetection": "版本檢測",
"standardVersionDetection": "標準版本檢測",
"groupByCategory": "按類別分組",
"autoApkFilterByArch": "如果可能,嘗試按 CPU 架構過濾 APK",
"overrideSource": "覆蓋來源",
"dontShowAgain": "不要再顯示",
"dontShowTrackOnlyWarnings": "不要顯示「僅追蹤」警告",
"dontShowAPKOriginWarnings": "不要顯示 APK 來源警告",
"moveNonInstalledAppsToBottom": "將未安裝的應用程式移到應用程式視圖的底部",
"gitlabPATLabel": "GitLab 個人存取權杖",
"about": "關於",
"requiresCredentialsInSettings": "{} 需要額外的憑證(在設定中)",
"checkOnStart": "啟動時檢查更新",
"tryInferAppIdFromCode": "嘗試從原始碼推斷應用程式 ID",
"removeOnExternalUninstall": "自動移除外部解除安裝的應用程式",
"pickHighestVersionCode": "自動選取最高版本號的 APK",
"checkUpdateOnDetailPage": "在打開應用程式詳細頁面時檢查更新",
"disablePageTransitions": "禁用頁面過渡動畫",
"reversePageTransitions": "反轉頁面過渡動畫",
"minStarCount": "最少星數",
"addInfoBelow": "在下方添加此資訊。",
"addInfoInSettings": "在設定中增加此資訊。",
"githubSourceNote": "使用 API 金鑰可以避免 GitHub 的速率限制。",
"sortByLastLinkSegment": "僅按連結的最後一段排序",
"filterReleaseNotesByRegEx": "用正則表達式過濾發佈說明",
"customLinkFilterRegex": "自定 APK 連結過濾正則表達式(預設為 '.apk$'",
"appsPossiblyUpdated": "嘗試更新應用程式",
"appsPossiblyUpdatedNotifDescription": "通知使用者一個或多個應用程式的更新可能已在背景中應用",
"xWasPossiblyUpdatedToY": "{} 可能已更新到 {}。",
"enableBackgroundUpdates": "啟用背景更新",
"backgroundUpdateReqsExplanation": "並非所有應用程式都能進行背景更新。",
"backgroundUpdateLimitsExplanation": "背景安裝的成功與否只能在打開 Obtainium 時確定。",
"verifyLatestTag": "驗證「最新」標籤",
"intermediateLinkRegex": "過濾要訪問的「中間」連結",
"filterByLinkText": "按連結文本過濾連結",
"intermediateLinkNotFound": "未找到中間連結",
"intermediateLink": "中間連結",
"exemptFromBackgroundUpdates": "免除背景更新(若已啟用)",
"bgUpdatesOnWiFiOnly": "禁用非 WiFi 的背景更新",
"autoSelectHighestVersionCode": "自動選擇最高 versionCode 的 APK",
"versionExtractionRegEx": "版本字串提取正則表達式",
"trimVersionString": "Trim Version String With RegEx",
"matchGroupToUseForX": "Match Group to Use for \"{}\"",
"matchGroupToUse": "要用於版本字串提取的匹配組",
"highlightTouchTargets": "突出顯示不明顯的觸控目標",
"pickExportDir": "選擇匯出目錄",
"autoExportOnChanges": "更改時自動匯出",
"includeSettings": "包含設定",
"filterVersionsByRegEx": "用正則表達式過濾版本",
"trySelectingSuggestedVersionCode": "嘗試選擇建議的 versionCode APK",
"dontSortReleasesList": "保留 API 的發佈順序",
"reverseSort": "反向排序",
"takeFirstLink": "使用第一個連結",
"skipSort": "跳過排序",
"debugMenu": "除錯選單",
"bgTaskStarted": "背景任務已啟動 - 檢查日誌。",
"runBgCheckNow": "立即執行背景更新檢查",
"versionExtractWholePage": "將版本字串提取正則表達式應用於整個頁面",
"installing": "正在安裝",
"skipUpdateNotifications": "跳過更新通知",
"updatesAvailableNotifChannel": "有可用的更新",
"appsUpdatedNotifChannel": "應用程式已更新",
"appsPossiblyUpdatedNotifChannel": "嘗試更新應用程式",
"errorCheckingUpdatesNotifChannel": "檢查更新錯誤",
"appsRemovedNotifChannel": "應用程式已移除",
"downloadingXNotifChannel": "正在下載 {}",
"completeAppInstallationNotifChannel": "完成應用程式安裝",
"checkingForUpdatesNotifChannel": "正在檢查更新",
"onlyCheckInstalledOrTrackOnlyApps": "僅檢查已安裝和僅追蹤的應用程式更新",
"supportFixedAPKURL": "支援固定的 APK 網址",
"selectX": "選擇 {}",
"parallelDownloads": "允許平行下載",
"useShizuku": "使用 Shizuku 或 Sui 來安裝",
"shizukuBinderNotFound": "Shizuku 服務未運行",
"shizukuOld": "舊版 Shizuku (<11) - 請更新",
"shizukuOldAndroidWithADB": "Shizuku 在 Android 8.1 以下版本使用 ADB 運行 - 請更新 Android 或改用 Sui",
"shizukuPretendToBeGooglePlay": "設置 Google Play 為安裝來源(如果使用 Shizuku",
"useSystemFont": "使用系統字體",
"useVersionCodeAsOSVersion": "使用應用程式 versionCode 作為操作系統檢測的版本",
"requestHeader": "請求標頭",
"useLatestAssetDateAsReleaseDate": "使用最新資源上傳日期作為發佈日期",
"defaultPseudoVersioningMethod": "預設偽版本管理方法",
"partialAPKHash": "部分 APK Hash",
"APKLinkHash": "APK 連結 Hash",
"directAPKLink": "直接 APK 連結",
"pseudoVersionInUse": "正在使用偽版本",
"installed": "已安裝",
"latest": "最新",
"invertRegEx": "反轉正則表達式",
"note": "備註",
"selfHostedNote": "可使用「{}」下拉選單來訪問任何來源的自託管/自定義實例。",
"badDownload": "無法解析 APK不兼容或下載不完整",
"beforeNewInstallsShareToAppVerifier": "將新應用程式分享到 AppVerifier如果可用",
"appVerifierInstructionToast": "分享至 AppVerifier然後準備好時返回此處。",
"wiki": "幫助/維基",
"crowdsourcedConfigsLabel": "群眾外包的應用程式配置(使用風險自負)",
"removeAppQuestion": {
"one": "移除應用程式?",
"other": "移除應用程式?"
},
"tooManyRequestsTryAgainInMinutes": {
"one": "請求過多(速率限制)- {} 分鐘後重試",
"other": "請求過多(速率限制)- {} 分鐘後重試"
},
"bgUpdateGotErrorRetryInMinutes": {
"one": "背景更新檢查遇到 {},將在 {} 分鐘後重新檢查",
"other": "背景更新檢查遇到 {},將在 {} 分鐘後重新檢查"
},
"bgCheckFoundUpdatesWillNotifyIfNeeded": {
"one": "背景更新檢查發現 {} 個更新 - 如果需要將通知使用者",
"other": "背景更新檢查發現 {} 個更新 - 如果需要將通知使用者"
},
"apps": {
"one": "{} 個應用程式",
"other": "{} 個應用程式"
},
"url": {
"one": "{} 個 URL",
"other": "{} 個 URL"
},
"minute": {
"one": "{} 分鐘",
"other": "{} 分鐘"
},
"hour": {
"one": "{} 小時",
"other": "{} 小時"
},
"day": {
"one": "{} 天",
"other": "{} 天"
},
"clearedNLogsBeforeXAfterY": {
"one": "清除 {n} 個日誌(之前 = {before},之後 = {after}",
"other": "清除 {n} 個日誌(之前 = {before},之後 = {after}"
},
"xAndNMoreUpdatesAvailable": {
"one": "{} 和另外 1 個應用程式有更新。",
"other": "{} 和另外 {} 個應用程式有更新。"
},
"xAndNMoreUpdatesInstalled": {
"one": "{} 和另外 1 個應用程式已更新。",
"other": "{} 和另外 {} 個應用程式已更新。"
},
"xAndNMoreUpdatesFailed": {
"one": "更新 {} 和另外 1 個應用程式失敗。",
"other": "更新 {} 和另外 {} 個應用程式失敗。"
},
"xAndNMoreUpdatesPossiblyInstalled": {
"one": "{} 和另外 1 個應用程式可能已更新。",
"other": "{} 和另外 {} 個應用程式可能已更新。"
},
"apk": {
"one": "{} 個 APK",
"other": "{} 個 APK"
}
}

View File

@@ -259,6 +259,8 @@
"bgUpdatesOnWiFiOnly": "未连接 Wi-Fi 时禁用后台更新", "bgUpdatesOnWiFiOnly": "未连接 Wi-Fi 时禁用后台更新",
"autoSelectHighestVersionCode": "自动选择内部版本号最高的 APK 文件", "autoSelectHighestVersionCode": "自动选择内部版本号最高的 APK 文件",
"versionExtractionRegEx": "提取版本号的正则表达式", "versionExtractionRegEx": "提取版本号的正则表达式",
"trimVersionString": "使用 RegEx 修剪版本字符串",
"matchGroupToUseForX": "用于\"{}\"的匹配组",
"matchGroupToUse": "从上述匹配结果中引用的捕获组", "matchGroupToUse": "从上述匹配结果中引用的捕获组",
"highlightTouchTargets": "突出展示不明显的可交互区域", "highlightTouchTargets": "突出展示不明显的可交互区域",
"pickExportDir": "选择导出文件夹", "pickExportDir": "选择导出文件夹",

View File

@@ -9,7 +9,7 @@
<ul> <ul>
<li>GitHub</li> <li>GitHub</li>
<li>GitLab</li> <li>GitLab</li>
<li>Codeberg</li> <li>Forgejo (Codeberg)</li>
<li>F-Droid</li> <li>F-Droid</li>
<li>Third Party F-Droid Repos</li> <li>Third Party F-Droid Repos</li>
<li>IzzyOnDroid</li> <li>IzzyOnDroid</li>

View File

@@ -9,7 +9,7 @@
<ul> <ul>
<li>GitHub</li> <li>GitHub</li>
<li>GitLab</li> <li>GitLab</li>
<li>Codeberg</li> <li>Forgejo (Codeberg)</li>
<li>F-Droid</li> <li>F-Droid</li>
<li>Third Party F-Droid Repos</li> <li>Third Party F-Droid Repos</li>
<li>IzzyOnDroid</li> <li>IzzyOnDroid</li>

View File

@@ -5,6 +5,7 @@ import 'package:obtainium/providers/source_provider.dart';
class Codeberg extends AppSource { class Codeberg extends AppSource {
GitHub gh = GitHub(); GitHub gh = GitHub();
Codeberg() { Codeberg() {
name = 'Forgejo (Codeberg)';
hosts = ['codeberg.org']; hosts = ['codeberg.org'];
additionalSourceAppSpecificSettingFormItems = additionalSourceAppSpecificSettingFormItems =

View File

@@ -24,6 +24,14 @@ class DirectAPKLink extends AppSource {
]; ];
} }
@override
Future<Map<String, String>?> getRequestHeaders(
Map<String, dynamic> additionalSettings,
{bool forAPKDownload = false}) {
return html.getRequestHeaders(additionalSettings,
forAPKDownload: forAPKDownload);
}
@override @override
Future<APKDetails> getLatestAPKDetails( Future<APKDetails> getLatestAPKDetails(
String standardUrl, String standardUrl,

View File

@@ -9,7 +9,7 @@ class FDroidRepo extends AppSource {
FDroidRepo() { FDroidRepo() {
name = tr('fdroidThirdPartyRepo'); name = tr('fdroidThirdPartyRepo');
canSearch = true; canSearch = true;
excludeFromMassSearch = true; includeAdditionalOptsInMainSearch = true;
neverAutoSelect = true; neverAutoSelect = true;
showReleaseDateAsVersionToggle = true; showReleaseDateAsVersionToggle = true;
@@ -86,6 +86,27 @@ class FDroidRepo extends AppSource {
} }
} }
@override
void runOnAddAppInputChange(String userInput) {
additionalSourceAppSpecificSettingFormItems =
additionalSourceAppSpecificSettingFormItems.map((row) {
row = row.map((item) {
if (item.key == 'appIdOrName') {
try {
var appId = Uri.parse(userInput).queryParameters['appId'];
if (appId != null && item is GeneratedFormTextField) {
item.required = false;
}
} catch (e) {
//
}
}
return item;
}).toList();
return row;
}).toList();
}
@override @override
App endOfGetAppChanges(App app) { App endOfGetAppChanges(App app) {
var uri = Uri.parse(app.url); var uri = Uri.parse(app.url);
@@ -142,6 +163,7 @@ class FDroidRepo extends AppSource {
if (appIdOrName == null) { if (appIdOrName == null) {
throw NoReleasesError(); throw NoReleasesError();
} }
additionalSettings['appIdOrName'] = appIdOrName;
var res = var res =
await sourceRequestWithURLVariants(standardUrl, additionalSettings); await sourceRequestWithURLVariants(standardUrl, additionalSettings);
if (res.statusCode == 200) { if (res.statusCode == 200) {

View File

@@ -171,7 +171,7 @@ class GitHub extends AppSource {
{bool forAPKDownload = false}) async { {bool forAPKDownload = false}) async {
var token = await getTokenIfAny(additionalSettings); var token = await getTokenIfAny(additionalSettings);
var headers = <String, String>{}; var headers = <String, String>{};
if (token != null) { if (token != null && token.isNotEmpty) {
headers[HttpHeaders.authorizationHeader] = 'Token $token'; headers[HttpHeaders.authorizationHeader] = 'Token $token';
} }
if (forAPKDownload == true) { if (forAPKDownload == true) {
@@ -285,7 +285,9 @@ class GitHub extends AppSource {
DateTime? getPublishDateFromRelease(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; : rel?['commit']?['created'] != null
? DateTime.parse(rel['commit']['created'])
: null;
DateTime? getNewestAssetDateFromRelease(dynamic rel) { DateTime? getNewestAssetDateFromRelease(dynamic rel) {
var t = (rel['assets'] as List<dynamic>?) var t = (rel['assets'] as List<dynamic>?)
?.map((e) { ?.map((e) {

View File

@@ -111,6 +111,14 @@ class GitLab extends AppSource {
} }
} }
@override
Future<String> apkUrlPrefetchModifier(String apkUrl, String standardUrl,
Map<String, dynamic> additionalSettings) async {
String? PAT = await getPATIfAny(hostChanged ? additionalSettings : {});
String optionalAuth = (PAT != null) ? 'private_token=$PAT' : '';
return '$apkUrl?$optionalAuth';
}
@override @override
Future<APKDetails> getLatestAPKDetails( Future<APKDetails> getLatestAPKDetails(
String standardUrl, String standardUrl,
@@ -153,7 +161,8 @@ class GitLab extends AppSource {
.toList(); .toList();
var apkUrlsSet = apkUrlsFromAssets.toSet(); var apkUrlsSet = apkUrlsFromAssets.toSet();
apkUrlsSet.addAll(uploadedAPKsFromDescription); apkUrlsSet.addAll(uploadedAPKsFromDescription);
var releaseDateString = e['released_at'] ?? e['created_at']; var releaseDateString =
e['released_at'] ?? e['created_at'] ?? e['commit']?['created_at'];
DateTime? releaseDate = DateTime? releaseDate =
releaseDateString != null ? DateTime.parse(releaseDateString) : null; releaseDateString != null ? DateTime.parse(releaseDateString) : null;
return APKDetails( return APKDetails(

View File

@@ -93,6 +93,21 @@ bool _isNumeric(String s) {
} }
class HTML extends AppSource { class HTML extends AppSource {
@override
List<List<GeneratedFormItem>> get combinedAppSpecificSettingFormItems {
return super.combinedAppSpecificSettingFormItems.map((r) {
return r.map((e) {
if (e.key == 'versionExtractionRegEx') {
e.label = tr('versionExtractionRegEx');
}
if (e.key == 'matchGroupToUse') {
e.label = tr('matchGroupToUse');
}
return e;
}).toList();
}).toList();
}
var finalStepFormitems = [ var finalStepFormitems = [
[ [
GeneratedFormTextField('customLinkFilterRegex', GeneratedFormTextField('customLinkFilterRegex',
@@ -332,10 +347,13 @@ class HTML extends AppSource {
additionalSettings['versionExtractWholePage'] == true additionalSettings['versionExtractWholePage'] == true
? versionExtractionWholePageString ? versionExtractionWholePageString
: relDecoded); : relDecoded);
version ??= version ??= additionalSettings['defaultPseudoVersioningMethod'] ==
additionalSettings['defaultPseudoVersioningMethod'] == 'APKLinkHash' 'APKLinkHash'
? rel.hashCode.toString() ? rel.hashCode.toString()
: (await checkPartialDownloadHashDynamic(rel)).toString(); : (await checkPartialDownloadHashDynamic(rel,
headers: await getRequestHeaders(additionalSettings,
forAPKDownload: true)))
.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

@@ -73,21 +73,23 @@ class HuaweiAppGallery extends AppSource {
throw NoReleasesError(); throw NoReleasesError();
} }
String appId = appIdFromRedirectDlUrl(res.headers['location']!); String appId = appIdFromRedirectDlUrl(res.headers['location']!);
if (appId.isEmpty) {
throw NoReleasesError();
}
var relDateStr = var relDateStr =
res.headers['location']?.split('?')[0].split('.').reversed.toList()[1]; res.headers['location']?.split('?')[0].split('.').reversed.toList()[1];
var relDateStrAdj = relDateStr?.split(''); if (relDateStr == null || relDateStr.length != 10) {
var tempLen = relDateStrAdj?.length ?? 0;
var i = 2;
while (i < tempLen) {
relDateStrAdj?.insert((i + i ~/ 2 - 1), '-');
i += 2;
}
var relDate = relDateStrAdj == null
? null
: DateFormat('yy-MM-dd-HH-mm', 'en_US').parse(relDateStrAdj.join(''));
if (relDateStr == null) {
throw NoVersionError(); throw NoVersionError();
} }
var relDateStrAdj = relDateStr.split('');
var tempLen = relDateStrAdj.length;
var i = 2;
while (i < tempLen) {
relDateStrAdj.insert((i + i ~/ 2 - 1), '-');
i += 2;
}
var relDate =
DateFormat('yy-MM-dd-HH-mm', 'en_US').parse(relDateStrAdj.join(''));
return APKDetails( return APKDetails(
relDateStr, [MapEntry('$appId.apk', dlUrl)], AppNames(name, appId), relDateStr, [MapEntry('$appId.apk', dlUrl)], AppNames(name, appId),
releaseDate: relDate); releaseDate: relDate);

View File

@@ -5,6 +5,7 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:obtainium/components/generated_form_modal.dart'; import 'package:obtainium/components/generated_form_modal.dart';
import 'package:obtainium/providers/source_provider.dart'; import 'package:obtainium/providers/source_provider.dart';
import 'package:flutter_typeahead/flutter_typeahead.dart';
abstract class GeneratedFormItem { abstract class GeneratedFormItem {
late String key; late String key;
@@ -28,6 +29,7 @@ class GeneratedFormTextField extends GeneratedFormItem {
late String? hint; late String? hint;
late bool password; late bool password;
late TextInputType? textInputType; late TextInputType? textInputType;
late List<String>? autoCompleteOptions;
GeneratedFormTextField(super.key, GeneratedFormTextField(super.key,
{super.label, {super.label,
@@ -39,7 +41,8 @@ class GeneratedFormTextField extends GeneratedFormItem {
this.max = 1, this.max = 1,
this.hint, this.hint,
this.password = false, this.password = false,
this.textInputType}); this.textInputType,
this.autoCompleteOptions});
@override @override
String ensureType(val) { String ensureType(val) {
@@ -274,38 +277,62 @@ class _GeneratedFormState extends State<GeneratedForm> {
var formItem = e.value; var formItem = e.value;
if (formItem is GeneratedFormTextField) { if (formItem is GeneratedFormTextField) {
final formFieldKey = GlobalKey<FormFieldState>(); final formFieldKey = GlobalKey<FormFieldState>();
return TextFormField( var ctrl = TextEditingController(text: values[formItem.key]);
keyboardType: formItem.textInputType, return TypeAheadField<String>(
obscureText: formItem.password, controller: ctrl,
autocorrect: !formItem.password, builder: (context, controller, focusNode) {
enableSuggestions: !formItem.password, return TextFormField(
key: formFieldKey, controller: ctrl,
initialValue: values[formItem.key], focusNode: focusNode,
autovalidateMode: AutovalidateMode.onUserInteraction, keyboardType: formItem.textInputType,
onChanged: (value) { obscureText: formItem.password,
autocorrect: !formItem.password,
enableSuggestions: !formItem.password,
key: formFieldKey,
autovalidateMode: AutovalidateMode.onUserInteraction,
onChanged: (value) {
setState(() {
values[formItem.key] = value;
someValueChanged();
});
},
decoration: InputDecoration(
helperText:
formItem.label + (formItem.required ? ' *' : ''),
hintText: formItem.hint),
minLines: formItem.max <= 1 ? null : formItem.max,
maxLines: formItem.max <= 1 ? 1 : formItem.max,
validator: (value) {
if (formItem.required &&
(value == null || value.trim().isEmpty)) {
return '${formItem.label} ${tr('requiredInBrackets')}';
}
for (var validator in formItem.additionalValidators) {
String? result = validator(value);
if (result != null) {
return result;
}
}
return null;
},
);
},
itemBuilder: (context, value) {
return ListTile(title: Text(value));
},
onSelected: (value) {
ctrl.text = value;
setState(() { setState(() {
values[formItem.key] = value; values[formItem.key] = value;
someValueChanged(); someValueChanged();
}); });
}, },
decoration: InputDecoration( suggestionsCallback: (search) {
helperText: formItem.label + (formItem.required ? ' *' : ''), return formItem.autoCompleteOptions
hintText: formItem.hint), ?.where((t) => t.toLowerCase().contains(search.toLowerCase()))
minLines: formItem.max <= 1 ? null : formItem.max, .toList();
maxLines: formItem.max <= 1 ? 1 : formItem.max,
validator: (value) {
if (formItem.required &&
(value == null || value.trim().isEmpty)) {
return '${formItem.label} ${tr('requiredInBrackets')}';
}
for (var validator in formItem.additionalValidators) {
String? result = validator(value);
if (result != null) {
return result;
}
}
return null;
}, },
hideOnEmpty: true,
); );
} else if (formItem is GeneratedFormDropdown) { } else if (formItem is GeneratedFormDropdown) {
if (formItem.opts!.isEmpty) { if (formItem.opts!.isEmpty) {

View File

@@ -40,6 +40,7 @@ List<MapEntry<Locale, String>> supportedLocales = const [
MapEntry(Locale('vi'), 'Tiếng Việt'), MapEntry(Locale('vi'), 'Tiếng Việt'),
MapEntry(Locale('tr'), 'Türkçe'), MapEntry(Locale('tr'), 'Türkçe'),
MapEntry(Locale('uk'), 'Українська'), MapEntry(Locale('uk'), 'Українська'),
MapEntry(Locale('da'), 'Dansk'),
]; ];
const fallbackLocale = Locale('en'); const fallbackLocale = Locale('en');
const localeDir = 'assets/translations'; const localeDir = 'assets/translations';
@@ -212,20 +213,23 @@ class _ObtainiumState extends State<Obtainium> {
// Decide on a colour/brightness scheme based on OS and user settings // Decide on a colour/brightness scheme based on OS and user settings
ColorScheme lightColorScheme; ColorScheme lightColorScheme;
ColorScheme darkColorScheme; ColorScheme darkColorScheme;
if (lightDynamic != null && darkDynamic != null && settingsProvider.useMaterialYou) { if (lightDynamic != null &&
darkDynamic != null &&
settingsProvider.useMaterialYou) {
lightColorScheme = lightDynamic.harmonized(); lightColorScheme = lightDynamic.harmonized();
darkColorScheme = darkDynamic.harmonized(); darkColorScheme = darkDynamic.harmonized();
} else { } else {
lightColorScheme = ColorScheme.fromSeed(seedColor: settingsProvider.themeColor); lightColorScheme =
ColorScheme.fromSeed(seedColor: settingsProvider.themeColor);
darkColorScheme = ColorScheme.fromSeed( darkColorScheme = ColorScheme.fromSeed(
seedColor: settingsProvider.themeColor, brightness: Brightness.dark); seedColor: settingsProvider.themeColor,
brightness: Brightness.dark);
} }
// set the background and surface colors to pure black in the amoled theme // set the background and surface colors to pure black in the amoled theme
if (settingsProvider.useBlackTheme) { if (settingsProvider.useBlackTheme) {
darkColorScheme = darkColorScheme darkColorScheme =
.copyWith(background: Colors.black, surface: Colors.black) darkColorScheme.copyWith(surface: Colors.black).harmonized();
.harmonized();
} }
if (settingsProvider.useSystemFont) NativeFeatures.loadSystemFont(); if (settingsProvider.useSystemFont) NativeFeatures.loadSystemFont();

View File

@@ -51,10 +51,13 @@ class AddAppPageState extends State<AddAppPage> {
} }
changeUserInput(String input, bool valid, bool isBuilding, changeUserInput(String input, bool valid, bool isBuilding,
{bool updateUrlInput = false}) { {bool updateUrlInput = false, String? overrideSource}) {
userInput = input; userInput = input;
if (!isBuilding) { if (!isBuilding) {
setState(() { setState(() {
if (overrideSource != null) {
pickedSourceOverride = overrideSource;
}
if (updateUrlInput) { if (updateUrlInput) {
urlInputKey++; urlInputKey++;
} }
@@ -68,6 +71,7 @@ class AddAppPageState extends State<AddAppPage> {
if (pickedSource.runtimeType != source.runtimeType || if (pickedSource.runtimeType != source.runtimeType ||
(prevHost != null && prevHost != source?.hosts[0])) { (prevHost != null && prevHost != source?.hosts[0])) {
pickedSource = source; pickedSource = source;
pickedSource?.runOnAddAppInputChange(userInput);
additionalSettings = source != null additionalSettings = source != null
? getDefaultValuesFromFormItems( ? getDefaultValuesFromFormItems(
source.combinedAppSpecificSettingFormItems) source.combinedAppSpecificSettingFormItems)
@@ -259,9 +263,7 @@ class AddAppPageState extends State<AddAppPage> {
searching = true; searching = true;
}); });
var sourceStrings = <String, List<String>>{}; var sourceStrings = <String, List<String>>{};
sourceProvider.sources sourceProvider.sources.where((e) => e.canSearch).forEach((s) {
.where((e) => e.canSearch && !e.excludeFromMassSearch)
.forEach((s) {
sourceStrings[s.name] = [s.name]; sourceStrings[s.name] = [s.name];
}); });
try { try {
@@ -282,32 +284,78 @@ class AddAppPageState extends State<AddAppPage> {
settingsProvider.searchDeselected = sourceStrings.keys settingsProvider.searchDeselected = sourceStrings.keys
.where((s) => !searchSources.contains(s)) .where((s) => !searchSources.contains(s))
.toList(); .toList();
var results = await Future.wait(sourceProvider.sources List<MapEntry<String, Map<String, List<String>>>?> results =
.where((e) => searchSources.contains(e.name)) (await Future.wait(sourceProvider.sources
.map((e) async { .where((e) => searchSources.contains(e.name))
.map((e) async {
try { try {
return await e.search(searchQuery); Map<String, dynamic>? querySettings = {};
if (e.includeAdditionalOptsInMainSearch) {
querySettings = await showDialog<Map<String, dynamic>?>(
context: context,
builder: (BuildContext ctx) {
return GeneratedFormModal(
title: tr('searchX', args: [e.name]),
items: [
...e.searchQuerySettingFormItems.map((e) => [e]),
[
GeneratedFormTextField('url',
label: e.hosts.isNotEmpty
? tr('overrideSource')
: plural('url', 1).substring(2),
autoCompleteOptions: [
...(e.hosts.isNotEmpty ? [e.hosts[0]] : []),
...appsProvider.apps.values
.where((a) =>
sourceProvider
.getSource(a.app.url,
overrideSource:
a.app.overrideSource)
.runtimeType ==
e.runtimeType)
.map((a) {
var uri = Uri.parse(a.app.url);
return '${uri.origin}${uri.path}';
})
],
defaultValue:
e.hosts.isNotEmpty ? e.hosts[0] : '',
required: true)
],
],
);
});
if (querySettings == null) {
return null;
}
}
return MapEntry(e.runtimeType.toString(),
await e.search(searchQuery, querySettings: querySettings));
} catch (err) { } catch (err) {
if (err is! CredsNeededError) { if (err is! CredsNeededError) {
rethrow; rethrow;
} else { } else {
err.unexpected = true; err.unexpected = true;
showError(err, context); showError(err, context);
return <String, List<String>>{}; return null;
} }
} }
})); })))
.where((a) => a != null)
.toList();
// Interleave results instead of simple reduce // Interleave results instead of simple reduce
Map<String, List<String>> res = {}; Map<String, MapEntry<String, List<String>>> res = {};
var si = 0; var si = 0;
var done = false; var done = false;
while (!done) { while (!done) {
done = true; done = true;
for (var r in results) { for (var r in results) {
if (r.length > si) { var sourceName = r!.key;
if (r.value.length > si) {
done = false; done = false;
res.addEntries([r.entries.elementAt(si)]); var singleRes = r.value.entries.elementAt(si);
res[singleRes.key] = MapEntry(sourceName, singleRes.value);
} }
} }
si++; si++;
@@ -322,13 +370,15 @@ class AddAppPageState extends State<AddAppPage> {
context: context, context: context,
builder: (BuildContext ctx) { builder: (BuildContext ctx) {
return SelectionModal( return SelectionModal(
entries: res, entries: res.map((k, v) => MapEntry(k, v.value)),
selectedByDefault: false, selectedByDefault: false,
onlyOneSelectionAllowed: true, onlyOneSelectionAllowed: true,
); );
}); });
if (selectedUrls != null && selectedUrls.isNotEmpty) { if (selectedUrls != null && selectedUrls.isNotEmpty) {
changeUserInput(selectedUrls[0], true, false, updateUrlInput: true); var sourceName = res[selectedUrls[0]]?.key;
changeUserInput(selectedUrls[0], true, false,
updateUrlInput: true, overrideSource: sourceName);
} }
} }
} catch (e) { } catch (e) {
@@ -349,7 +399,7 @@ class AddAppPageState extends State<AddAppPage> {
[ [
GeneratedFormDropdown( GeneratedFormDropdown(
'overrideSource', 'overrideSource',
defaultValue: '', defaultValue: pickedSourceOverride ?? '',
[ [
MapEntry('', tr('none')), MapEntry('', tr('none')),
...sourceProvider.sources.map( ...sourceProvider.sources.map(

View File

@@ -161,25 +161,46 @@ class _AppPageState extends State<AppPage> {
if (app?.app.apkUrls.isNotEmpty == true || if (app?.app.apkUrls.isNotEmpty == true ||
app?.app.otherAssetUrls.isNotEmpty == true) app?.app.otherAssetUrls.isNotEmpty == true)
GestureDetector( GestureDetector(
onTap: app?.app == null || updating onTap: app?.app == null || updating
? null ? null
: () async { : () async {
try { try {
await appsProvider await appsProvider
.downloadAppAssets([app!.app.id], context); .downloadAppAssets([app!.app.id], context);
} catch (e) { } catch (e) {
showError(e, context); showError(e, context);
} }
}, },
child: Text( child: Row(
tr('downloadX', args: [tr('releaseAsset').toLowerCase()]), mainAxisAlignment: MainAxisAlignment.center,
textAlign: TextAlign.center, children: [
style: Theme.of(context).textTheme.labelSmall!.copyWith( Container(
decoration: TextDecoration.underline, decoration: BoxDecoration(
fontStyle: FontStyle.italic, borderRadius: BorderRadius.circular(12),
), color: settingsProvider.highlightTouchTargets
), ? (Theme.of(context).brightness ==
), Brightness.light
? Theme.of(context).primaryColor
: Theme.of(context).primaryColorLight)
.withAlpha(20)
: null),
padding: settingsProvider.highlightTouchTargets
? const EdgeInsetsDirectional.fromSTEB(12, 6, 12, 6)
: const EdgeInsetsDirectional.fromSTEB(0, 6, 0, 6),
margin:
const EdgeInsetsDirectional.fromSTEB(0, 6, 0, 0),
child: Text(
tr('downloadX',
args: [tr('releaseAsset').toLowerCase()]),
textAlign: TextAlign.center,
style:
Theme.of(context).textTheme.labelSmall!.copyWith(
decoration: TextDecoration.underline,
fontStyle: FontStyle.italic,
),
))
],
)),
const SizedBox( const SizedBox(
height: 48, height: 48,
), ),
@@ -226,18 +247,26 @@ class _AppPageState extends State<AppPage> {
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: [
const SizedBox(height: 20), const SizedBox(height: 20),
app?.icon != null FutureBuilder(
? Row(mainAxisAlignment: MainAxisAlignment.center, children: [ future: appsProvider.updateAppIcon(app?.app.id),
GestureDetector( builder: (ctx, val) {
child: Image.memory( return app?.icon != null
app!.icon!, ? Row(
height: 150, mainAxisAlignment: MainAxisAlignment.center,
gaplessPlayback: true, children: [
), GestureDetector(
onTap: () => pm.openApp(app.app.id), onTap: app == null
) ? null
]) : () => pm.openApp(app.app.id),
: Container(), child: Image.memory(
app!.icon!,
height: 150,
gaplessPlayback: true,
),
)
])
: Container();
}),
const SizedBox( const SizedBox(
height: 25, height: 25,
), ),
@@ -286,7 +315,7 @@ class _AppPageState extends State<AppPage> {
? WebViewWidget( ? WebViewWidget(
controller: WebViewController() controller: WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted) ..setJavaScriptMode(JavaScriptMode.unrestricted)
..setBackgroundColor(Theme.of(context).colorScheme.background) ..setBackgroundColor(Theme.of(context).colorScheme.surface)
..setJavaScriptMode(JavaScriptMode.unrestricted) ..setJavaScriptMode(JavaScriptMode.unrestricted)
..setNavigationDelegate( ..setNavigationDelegate(
NavigationDelegate( NavigationDelegate(

View File

@@ -143,11 +143,14 @@ class AppsPageState extends State<AppsPage> {
final GlobalKey<RefreshIndicatorState> _refreshIndicatorKey = final GlobalKey<RefreshIndicatorState> _refreshIndicatorKey =
GlobalKey<RefreshIndicatorState>(); GlobalKey<RefreshIndicatorState>();
late final ScrollController scrollController = ScrollController();
var sourceProvider = SourceProvider();
@override @override
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>();
var sourceProvider = SourceProvider();
var listedApps = appsProvider.getAppValues().toList(); var listedApps = appsProvider.getAppValues().toList();
refresh() { refresh() {
@@ -354,7 +357,11 @@ class AppsPageState extends State<AppsPage> {
SliverFillRemaining( SliverFillRemaining(
child: Center( child: Center(
child: Text( child: Text(
appsProvider.apps.isEmpty ? tr('noApps') : tr('noAppsForFilter'), appsProvider.apps.isEmpty
? appsProvider.loadingApps
? tr('pleaseWait')
: tr('noApps')
: tr('noAppsForFilter'),
style: Theme.of(context).textTheme.headlineMedium, style: Theme.of(context).textTheme.headlineMedium,
textAlign: TextAlign.center, textAlign: TextAlign.center,
))), ))),
@@ -402,29 +409,36 @@ class AppsPageState extends State<AppsPage> {
} }
getAppIcon(int appIndex) { getAppIcon(int appIndex) {
return listedApps[appIndex].icon != null return FutureBuilder(
? Image.memory( future: appsProvider.updateAppIcon(listedApps[appIndex].app.id),
listedApps[appIndex].icon!, builder: (ctx, val) {
gaplessPlayback: true, return listedApps[appIndex].icon != null
) ? Image.memory(
: Row( listedApps[appIndex].icon!,
mainAxisSize: MainAxisSize.min, gaplessPlayback: true,
mainAxisAlignment: MainAxisAlignment.center, )
children: [ : Row(
Transform( mainAxisSize: MainAxisSize.min,
alignment: Alignment.center, mainAxisAlignment: MainAxisAlignment.center,
transform: Matrix4.rotationZ(0.31), children: [
child: Padding( Transform(
padding: const EdgeInsets.all(15), alignment: Alignment.center,
child: Image( transform: Matrix4.rotationZ(0.31),
image: const AssetImage( child: Padding(
'assets/graphics/icon_small.png'), padding: const EdgeInsets.all(15),
color: Colors.white.withOpacity(0.3), child: Image(
colorBlendMode: BlendMode.modulate, image: const AssetImage(
gaplessPlayback: true, 'assets/graphics/icon_small.png'),
), color: Theme.of(context).brightness ==
)), Brightness.dark
]); ? Colors.white.withOpacity(0.4)
: Colors.white.withOpacity(0.3),
colorBlendMode: BlendMode.modulate,
gaplessPlayback: true,
),
)),
]);
});
} }
getVersionText(int appIndex) { getVersionText(int appIndex) {
@@ -452,7 +466,7 @@ class AppsPageState extends State<AppsPage> {
hasUpdate ? getUpdateButton(index) : const SizedBox.shrink(), hasUpdate ? getUpdateButton(index) : const SizedBox.shrink(),
hasUpdate hasUpdate
? const SizedBox( ? const SizedBox(
width: 10, width: 5,
) )
: const SizedBox.shrink(), : const SizedBox.shrink(),
GestureDetector( GestureDetector(
@@ -503,7 +517,7 @@ class AppsPageState extends State<AppsPage> {
); );
var transparent = var transparent =
Theme.of(context).colorScheme.background.withAlpha(0).value; Theme.of(context).colorScheme.surface.withAlpha(0).value;
List<double> stops = [ List<double> stops = [
...listedApps[index].app.categories.asMap().entries.map( ...listedApps[index].app.categories.asMap().entries.map(
(e) => ((e.key / (listedApps[index].app.categories.length - 1)))), (e) => ((e.key / (listedApps[index].app.categories.length - 1)))),
@@ -1087,11 +1101,17 @@ class AppsPageState extends State<AppsPage> {
body: RefreshIndicator( body: RefreshIndicator(
key: _refreshIndicatorKey, key: _refreshIndicatorKey,
onRefresh: refresh, onRefresh: refresh,
child: CustomScrollView(slivers: <Widget>[ child: Scrollbar(
CustomAppBar(title: tr('appsString')), interactive: true,
...getLoadingWidgets(), controller: scrollController,
getDisplayedList() child: CustomScrollView(
])), physics: const AlwaysScrollableScrollPhysics(),
controller: scrollController,
slivers: <Widget>[
CustomAppBar(title: tr('appsString')),
...getLoadingWidgets(),
getDisplayedList()
]))),
persistentFooterButtons: appsProvider.apps.isEmpty persistentFooterButtons: appsProvider.apps.isEmpty
? null ? null
: [ : [

View File

@@ -103,7 +103,7 @@ class _HomePageState extends State<HomePage> {
}) != }) !=
null) { null) {
// ignore: use_build_context_synchronously // ignore: use_build_context_synchronously
var appsProvider = await context.read<AppsProvider>(); var appsProvider = context.read<AppsProvider>();
var result = await appsProvider.import(action == 'app' var result = await appsProvider.import(action == 'app'
? '{ "apps": [$dataStr] }' ? '{ "apps": [$dataStr] }'
: '{ "apps": $dataStr }'); : '{ "apps": $dataStr }');

View File

@@ -33,7 +33,7 @@ class _ImportExportPageState extends State<ImportExportPage> {
var settingsProvider = context.watch<SettingsProvider>(); var settingsProvider = context.watch<SettingsProvider>();
var outlineButtonStyle = ButtonStyle( var outlineButtonStyle = ButtonStyle(
shape: MaterialStateProperty.all( shape: WidgetStateProperty.all(
StadiumBorder( StadiumBorder(
side: BorderSide( side: BorderSide(
width: 1, width: 1,

View File

@@ -5,6 +5,7 @@ import 'package:flex_color_picker/flex_color_picker.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:obtainium/components/custom_app_bar.dart'; import 'package:obtainium/components/custom_app_bar.dart';
import 'package:obtainium/components/generated_form.dart'; import 'package:obtainium/components/generated_form.dart';
import 'package:obtainium/components/generated_form_modal.dart';
import 'package:obtainium/custom_errors.dart'; import 'package:obtainium/custom_errors.dart';
import 'package:obtainium/main.dart'; import 'package:obtainium/main.dart';
import 'package:obtainium/providers/apps_provider.dart'; import 'package:obtainium/providers/apps_provider.dart';
@@ -945,6 +946,25 @@ class _LogsDialogState extends State<LogsDialog> {
], ],
), ),
actions: [ actions: [
TextButton(
onPressed: () async {
var cont = (await showDialog<Map<String, dynamic>?>(
context: context,
builder: (BuildContext ctx) {
return GeneratedFormModal(
title: tr('appLogs'),
items: const [],
initValid: true,
message: tr('removeFromObtainium'),
);
})) !=
null;
if (cont) {
logsProvider.clear();
Navigator.of(context).pop();
}
},
child: Text(tr('remove'))),
TextButton( TextButton(
onPressed: () { onPressed: () {
Navigator.of(context).pop(); Navigator.of(context).pop();

View File

@@ -220,7 +220,9 @@ Future<File> downloadFile(String url, String fileName, bool fileNameHasExt,
if (ext.endsWith('"') || ext.endsWith("other")) { if (ext.endsWith('"') || ext.endsWith("other")) {
ext = ext.substring(0, ext.length - 1); ext = ext.substring(0, ext.length - 1);
} }
if (url.toLowerCase().endsWith('.apk') && ext != 'apk') { if (((Uri.tryParse(url)?.path ?? url).toLowerCase().endsWith('.apk') ||
ext == 'attachment') &&
ext != 'apk') {
ext = 'apk'; ext = 'apk';
} }
fileName = fileName.split('/').last; // Ensure the fileName is a file name fileName = fileName.split('/').last; // Ensure the fileName is a file name
@@ -329,6 +331,10 @@ Future<Map<String, String>> getHeaders(String url,
return returnHeaders; return returnHeaders;
} }
Future<List<PackageInfo>> getAllInstalledInfo() async {
return await pm.getInstalledPackages() ?? [];
}
Future<PackageInfo?> getInstalledInfo(String? packageName, Future<PackageInfo?> getInstalledInfo(String? packageName,
{bool printErr = true}) async { {bool printErr = true}) async {
if (packageName != null) { if (packageName != null) {
@@ -364,7 +370,9 @@ class AppsProvider with ChangeNotifier {
foregroundStream = FGBGEvents.stream.asBroadcastStream(); foregroundStream = FGBGEvents.stream.asBroadcastStream();
foregroundSubscription = foregroundStream?.listen((event) async { foregroundSubscription = foregroundStream?.listen((event) async {
isForeground = event == FGBGType.foreground; isForeground = event == FGBGType.foreground;
if (isForeground) loadApps(); if (isForeground) {
await loadApps();
}
}); });
() async { () async {
await settingsProvider.initializeSettings(); await settingsProvider.initializeSettings();
@@ -421,7 +429,8 @@ class AppsProvider with ChangeNotifier {
} }
Future<Object> downloadApp(App app, BuildContext? context, Future<Object> downloadApp(App app, BuildContext? context,
{NotificationsProvider? notificationsProvider}) async { {NotificationsProvider? notificationsProvider,
bool useExisting = true}) async {
var notifId = DownloadNotification(app.finalName, 0).id; var notifId = DownloadNotification(app.finalName, 0).id;
if (apps[app.id] != null) { if (apps[app.id] != null) {
apps[app.id]!.downloadProgress = 0; apps[app.id]!.downloadProgress = 0;
@@ -453,7 +462,7 @@ class AppsProvider with ChangeNotifier {
notificationsProvider?.notify(notif); notificationsProvider?.notify(notif);
} }
prevProg = prog; prevProg = prog;
}, APKDir.path); }, APKDir.path, useExisting: useExisting);
// Set to 90 for remaining steps, will make null in 'finally' // Set to 90 for remaining steps, will make null in 'finally'
if (apps[app.id] != null) { if (apps[app.id] != null) {
apps[app.id]!.downloadProgress = -1; apps[app.id]!.downloadProgress = -1;
@@ -710,7 +719,8 @@ class AppsProvider with ChangeNotifier {
} }
Future<MapEntry<String, String>?> confirmAppFileUrl( Future<MapEntry<String, String>?> confirmAppFileUrl(
App app, BuildContext? context, bool pickAnyAsset) async { App app, BuildContext? context, bool pickAnyAsset,
{bool evenIfSingleChoice = false}) async {
var urlsToSelectFrom = app.apkUrls; var urlsToSelectFrom = app.apkUrls;
if (pickAnyAsset) { if (pickAnyAsset) {
urlsToSelectFrom = [...urlsToSelectFrom, ...app.otherAssetUrls]; urlsToSelectFrom = [...urlsToSelectFrom, ...app.otherAssetUrls];
@@ -721,7 +731,8 @@ class AppsProvider with ChangeNotifier {
// get device supported architecture // get device supported architecture
List<String> archs = (await DeviceInfoPlugin().androidInfo).supportedAbis; List<String> archs = (await DeviceInfoPlugin().androidInfo).supportedAbis;
if (urlsToSelectFrom.length > 1 && context != null) { if ((urlsToSelectFrom.length > 1 || evenIfSingleChoice) &&
context != null) {
appFileUrl = await showDialog( appFileUrl = await showDialog(
// ignore: use_build_context_synchronously // ignore: use_build_context_synchronously
context: context, context: context,
@@ -766,7 +777,8 @@ class AppsProvider with ChangeNotifier {
Future<List<String>> downloadAndInstallLatestApps( Future<List<String>> downloadAndInstallLatestApps(
List<String> appIds, BuildContext? context, List<String> appIds, BuildContext? context,
{NotificationsProvider? notificationsProvider, {NotificationsProvider? notificationsProvider,
bool forceParallelDownloads = false}) async { bool forceParallelDownloads = false,
bool useExisting = true}) async {
notificationsProvider = notificationsProvider =
notificationsProvider ?? context?.read<NotificationsProvider>(); notificationsProvider ?? context?.read<NotificationsProvider>();
List<String> appsToInstall = []; List<String> appsToInstall = [];
@@ -818,21 +830,82 @@ class AppsProvider with ChangeNotifier {
appsToInstall = appsToInstall =
moveStrToEnd(appsToInstall, obtainiumId, strB: obtainiumTempId); moveStrToEnd(appsToInstall, obtainiumId, strB: obtainiumTempId);
Future<String> updateFn(String id, {bool skipInstalls = false}) async { Future<void> installFn(String id, bool willBeSilent,
DownloadedApk? downloadedFile, DownloadedXApkDir? downloadedDir) async {
apps[id]?.downloadProgress = -1;
notifyListeners();
try {
bool sayInstalled = true;
var contextIfNewInstall =
apps[id]?.installedInfo == null ? context : null;
bool needBGWorkaround =
willBeSilent && context == null && !settingsProvider.useShizuku;
if (downloadedFile != null) {
if (needBGWorkaround) {
// ignore: use_build_context_synchronously
installApk(downloadedFile, contextIfNewInstall,
needsBGWorkaround: true);
} else {
// ignore: use_build_context_synchronously
sayInstalled = await installApk(downloadedFile, contextIfNewInstall,
shizukuPretendToBeGooglePlay: apps[id]!
.app
.additionalSettings['shizukuPretendToBeGooglePlay'] ==
true);
}
} else {
if (needBGWorkaround) {
// ignore: use_build_context_synchronously
installXApkDir(downloadedDir!, contextIfNewInstall,
needsBGWorkaround: true);
} else {
// ignore: use_build_context_synchronously
sayInstalled = await installXApkDir(
downloadedDir!, contextIfNewInstall,
shizukuPretendToBeGooglePlay: apps[id]!
.app
.additionalSettings['shizukuPretendToBeGooglePlay'] ==
true);
}
}
if (willBeSilent && context == null) {
if (!settingsProvider.useShizuku) {
notificationsProvider?.notify(SilentUpdateAttemptNotification(
[apps[id]!.app],
id: id.hashCode));
} else {
notificationsProvider?.notify(SilentUpdateNotification(
[apps[id]!.app], sayInstalled,
id: id.hashCode));
}
}
if (sayInstalled) {
installedIds.add(id);
}
} finally {
apps[id]?.downloadProgress = null;
notifyListeners();
}
}
Future<Map<Object?, Object?>> downloadFn(String id,
{bool skipInstalls = false}) async {
bool willBeSilent = false;
DownloadedApk? downloadedFile;
DownloadedXApkDir? downloadedDir;
try { try {
var downloadedArtifact = var downloadedArtifact =
// ignore: use_build_context_synchronously // ignore: use_build_context_synchronously
await downloadApp(apps[id]!.app, context, await downloadApp(apps[id]!.app, context,
notificationsProvider: notificationsProvider); notificationsProvider: notificationsProvider,
DownloadedApk? downloadedFile; useExisting: useExisting);
DownloadedXApkDir? downloadedDir;
if (downloadedArtifact is DownloadedApk) { if (downloadedArtifact is DownloadedApk) {
downloadedFile = downloadedArtifact; downloadedFile = downloadedArtifact;
} else { } else {
downloadedDir = downloadedArtifact as DownloadedXApkDir; downloadedDir = downloadedArtifact as DownloadedXApkDir;
} }
id = downloadedFile?.appId ?? downloadedDir!.appId; id = downloadedFile?.appId ?? downloadedDir!.appId;
bool willBeSilent = await canInstallSilently(apps[id]!.app); willBeSilent = await canInstallSilently(apps[id]!.app);
if (!settingsProvider.useShizuku) { if (!settingsProvider.useShizuku) {
if (!(await settingsProvider.getInstallPermission(enforce: false))) { if (!(await settingsProvider.getInstallPermission(enforce: false))) {
throw ObtainiumError(tr('cancelled')); throw ObtainiumError(tr('cancelled'));
@@ -853,80 +926,33 @@ class AppsProvider with ChangeNotifier {
// ignore: use_build_context_synchronously // ignore: use_build_context_synchronously
await waitForUserToReturnToForeground(context); await waitForUserToReturnToForeground(context);
} }
apps[id]?.downloadProgress = -1;
notifyListeners();
try {
if (!skipInstalls) {
bool sayInstalled = true;
var contextIfNewInstall =
apps[id]?.installedInfo == null ? context : null;
bool needBGWorkaround =
willBeSilent && context == null && !settingsProvider.useShizuku;
if (downloadedFile != null) {
if (needBGWorkaround) {
// ignore: use_build_context_synchronously
installApk(downloadedFile, contextIfNewInstall,
needsBGWorkaround: true);
} else {
// ignore: use_build_context_synchronously
sayInstalled = await installApk(
downloadedFile, contextIfNewInstall,
shizukuPretendToBeGooglePlay:
apps[id]!.app.additionalSettings[
'shizukuPretendToBeGooglePlay'] ==
true);
}
} else {
if (needBGWorkaround) {
// ignore: use_build_context_synchronously
installXApkDir(downloadedDir!, contextIfNewInstall,
needsBGWorkaround: true);
} else {
// ignore: use_build_context_synchronously
sayInstalled = await installXApkDir(
downloadedDir!, contextIfNewInstall,
shizukuPretendToBeGooglePlay:
apps[id]!.app.additionalSettings[
'shizukuPretendToBeGooglePlay'] ==
true);
}
}
if (willBeSilent && context == null) {
if (!settingsProvider.useShizuku) {
notificationsProvider?.notify(SilentUpdateAttemptNotification(
[apps[id]!.app],
id: id.hashCode));
} else {
notificationsProvider?.notify(SilentUpdateNotification(
[apps[id]!.app], sayInstalled,
id: id.hashCode));
}
}
if (sayInstalled) {
installedIds.add(id);
}
}
} finally {
apps[id]?.downloadProgress = null;
notifyListeners();
}
} catch (e) { } catch (e) {
errors.add(id, e, appName: apps[id]?.name); errors.add(id, e, appName: apps[id]?.name);
} }
return id; return {
'id': id,
'willBeSilent': willBeSilent,
'downloadedFile': downloadedFile,
'downloadedDir': downloadedDir
};
} }
List<Map<Object?, Object?>> downloadResults = [];
if (forceParallelDownloads || !settingsProvider.parallelDownloads) { if (forceParallelDownloads || !settingsProvider.parallelDownloads) {
for (var id in appsToInstall) { for (var id in appsToInstall) {
await updateFn(id); downloadResults.add(await downloadFn(id));
} }
} else { } else {
List<String> ids = await Future.wait( downloadResults = await Future.wait(
appsToInstall.map((id) => updateFn(id, skipInstalls: true))); appsToInstall.map((id) => downloadFn(id, skipInstalls: true)));
for (var id in ids) { }
if (!errors.appIdNames.containsKey(id)) { for (var res in downloadResults) {
await updateFn(id); if (!errors.appIdNames.containsKey(res['id'])) {
} await installFn(
res['id'] as String,
res['willBeSilent'] as bool,
res['downloadedFile'] as DownloadedApk?,
res['downloadedDir'] as DownloadedXApkDir?);
} }
} }
@@ -951,7 +977,8 @@ class AppsProvider with ChangeNotifier {
if (apps[id]!.app.apkUrls.isNotEmpty || if (apps[id]!.app.apkUrls.isNotEmpty ||
apps[id]!.app.otherAssetUrls.isNotEmpty) { apps[id]!.app.otherAssetUrls.isNotEmpty) {
// ignore: use_build_context_synchronously // ignore: use_build_context_synchronously
fileUrl = await confirmAppFileUrl(apps[id]!.app, context, true); fileUrl = await confirmAppFileUrl(apps[id]!.app, context, true,
evenIfSingleChoice: true);
} }
if (fileUrl != null) { if (fileUrl != null) {
filesToDownload.add(MapEntry(fileUrl, apps[id]!.app)); filesToDownload.add(MapEntry(fileUrl, apps[id]!.app));
@@ -1144,17 +1171,6 @@ 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));
@@ -1163,67 +1179,75 @@ class AppsProvider with ChangeNotifier {
notifyListeners(); notifyListeners();
var sp = SourceProvider(); var sp = SourceProvider();
List<List<String>> errors = []; List<List<String>> errors = [];
List<App?> newApps = (await getAppsDir()) // Parse Apps from JSON var installedAppsData = await getAllInstalledInfo();
List<String> removedAppIds = [];
await Future.wait((await getAppsDir()) // Parse Apps from JSON
.listSync() .listSync()
.where((item) => item.path.toLowerCase().endsWith('.json')) .map((item) async {
.where((item) => App? app;
singleId == null || if (item.path.toLowerCase().endsWith('.json') &&
item.path.split('/').last.toLowerCase() == (singleId == null ||
'${singleId.toLowerCase()}.json') item.path.split('/').last.toLowerCase() ==
.map((e) { '${singleId.toLowerCase()}.json')) {
try { try {
return App.fromJson(jsonDecode(File(e.path).readAsStringSync())); app = App.fromJson(jsonDecode(File(item.path).readAsStringSync()));
} catch (err) { } catch (err) {
if (err is FormatException) { if (err is FormatException) {
logs.add('Corrupt JSON when loading App (will be ignored): $e'); logs.add('Corrupt JSON when loading App (will be ignored): $e');
e.renameSync('${e.path}.corrupt'); item.renameSync('${item.path}.corrupt');
} else { } else {
rethrow; rethrow;
}
} }
} }
}).toList();
for (var app in newApps) {
// Put Apps into memory to list them (fast)
if (app != null) { if (app != null) {
// Save the app to the in-memory list without grabbing any OS info first
apps.update(
app.id,
(value) => AppInMemory(
app!, value.downloadProgress, value.installedInfo, value.icon),
ifAbsent: () => AppInMemory(app!, null, null, null));
notifyListeners();
try { try {
// Try getting the app's source to ensure no invalid apps get loaded
sp.getSource(app.url, overrideSource: app.overrideSource); sp.getSource(app.url, overrideSource: app.overrideSource);
// If the app is installed, grab its OS data and reconcile install statuses
PackageInfo? installedInfo;
try {
installedInfo =
installedAppsData.firstWhere((i) => i.packageName == app!.id);
} catch (e) {
// If the app isn't installed the above throws an error
}
// Reconcile differences between the installed and recorded install info
var moddedApp =
getCorrectedInstallStatusAppIfPossible(app, installedInfo);
if (moddedApp != null) {
app = moddedApp;
// Note the app ID if it was uninstalled externally
if (moddedApp.installedVersion == null) {
removedAppIds.add(moddedApp.id);
}
}
// Update the app in memory with install info and corrections
apps.update( apps.update(
app.id, app.id,
(value) => AppInMemory( (value) => AppInMemory(
app, value.downloadProgress, value.installedInfo, value.icon), app!, value.downloadProgress, installedInfo, value.icon),
ifAbsent: () => AppInMemory(app, null, null, null)); ifAbsent: () => AppInMemory(app!, null, installedInfo, null));
notifyListeners();
} catch (e) { } catch (e) {
errors.add([app.id, app.finalName, e.toString()]); errors.add([app!.id, app.finalName, e.toString()]);
} }
} }
} }));
notifyListeners();
if (errors.isNotEmpty) { if (errors.isNotEmpty) {
removeApps(errors.map((e) => e[0]).toList()); removeApps(errors.map((e) => e[0]).toList());
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) // Delete externally uninstalled Apps if needed
await Future.wait(apps.values.map((app) { if (removedAppIds.isNotEmpty) {
return updateInstallStatusInMemory(app);
}));
notifyListeners();
// Reconcile version differences
List<App> modifiedApps = [];
for (var app in apps.values) {
var moddedApp =
getCorrectedInstallStatusAppIfPossible(app.app, app.installedInfo);
if (moddedApp != null) {
modifiedApps.add(moddedApp);
}
}
if (modifiedApps.isNotEmpty) {
await saveApps(modifiedApps, attemptToCorrectInstallStatus: false);
var removedAppIds = modifiedApps
.where((a) => a.installedVersion == null)
.map((e) => e.id)
.toList();
// After reconciliation, delete externally uninstalled Apps if needed
if (removedAppIds.isNotEmpty) { if (removedAppIds.isNotEmpty) {
if (settingsProvider.removeOnExternalUninstall) { if (settingsProvider.removeOnExternalUninstall) {
await removeApps(removedAppIds); await removeApps(removedAppIds);
@@ -1234,11 +1258,27 @@ class AppsProvider with ChangeNotifier {
notifyListeners(); notifyListeners();
} }
Future<void> updateAppIcon(String? appId) async {
if (apps[appId]?.icon == null) {
var icon =
(await apps[appId]?.installedInfo?.applicationInfo?.getAppIcon());
if (icon != null) {
apps.update(
apps[appId]!.app.id,
(value) => AppInMemory(apps[appId]!.app, value.downloadProgress,
value.installedInfo, icon),
ifAbsent: () => AppInMemory(
apps[appId]!.app, null, apps[appId]?.installedInfo, icon));
notifyListeners();
}
}
}
Future<void> saveApps(List<App> apps, Future<void> saveApps(List<App> apps,
{bool attemptToCorrectInstallStatus = true, {bool attemptToCorrectInstallStatus = true,
bool onlyIfExists = true}) async { bool onlyIfExists = true}) async {
attemptToCorrectInstallStatus = attemptToCorrectInstallStatus; attemptToCorrectInstallStatus = attemptToCorrectInstallStatus;
for (var a in apps) { await Future.wait(apps.map((a) async {
var app = a.deepCopy(); var app = a.deepCopy();
PackageInfo? info = await getInstalledInfo(app.id); PackageInfo? info = await getInstalledInfo(app.id);
var icon = await info?.applicationInfo?.getAppIcon(); var icon = await info?.applicationInfo?.getAppIcon();
@@ -1260,14 +1300,14 @@ class AppsProvider with ChangeNotifier {
rethrow; rethrow;
} }
} }
} }));
notifyListeners(); notifyListeners();
export(isAuto: true); export(isAuto: true);
} }
Future<void> removeApps(List<String> appIds) async { Future<void> removeApps(List<String> appIds) async {
var apkFiles = APKDir.listSync(); var apkFiles = APKDir.listSync();
for (var appId in appIds) { await Future.wait(appIds.map((appId) async {
File file = File('${(await getAppsDir()).path}/$appId.json'); File file = File('${(await getAppsDir()).path}/$appId.json');
if (file.existsSync()) { if (file.existsSync()) {
file.deleteSync(recursive: true); file.deleteSync(recursive: true);
@@ -1281,7 +1321,7 @@ class AppsProvider with ChangeNotifier {
if (apps.containsKey(appId)) { if (apps.containsKey(appId)) {
apps.remove(appId); apps.remove(appId);
} }
} }));
if (appIds.isNotEmpty) { if (appIds.isNotEmpty) {
notifyListeners(); notifyListeners();
export(isAuto: true); export(isAuto: true);
@@ -1540,6 +1580,8 @@ class AppsProvider with ChangeNotifier {
settingsMap.forEach((key, value) { settingsMap.forEach((key, value) {
if (value is int) { if (value is int) {
settingsProvider.prefs?.setInt(key, value); settingsProvider.prefs?.setInt(key, value);
} else if (value is double) {
settingsProvider.prefs?.setDouble(key, value);
} else if (value is bool) { } else if (value is bool) {
settingsProvider.prefs?.setBool(key, value); settingsProvider.prefs?.setBool(key, value);
} else if (value is List) { } else if (value is List) {
@@ -1613,7 +1655,9 @@ class _AppFilePickerState extends State<AppFilePicker> {
? tr('selectX', args: [tr('releaseAsset').toLowerCase()]) ? tr('selectX', args: [tr('releaseAsset').toLowerCase()])
: tr('pickAnAPK')), : tr('pickAnAPK')),
content: Column(children: [ content: Column(children: [
Text(tr('appHasMoreThanOnePackage', args: [widget.app.finalName])), urlsToSelectFrom.length > 1
? Text(tr('appHasMoreThanOnePackage', args: [widget.app.finalName]))
: const SizedBox.shrink(),
const SizedBox(height: 16), const SizedBox(height: 16),
...urlsToSelectFrom.map( ...urlsToSelectFrom.map(
(u) => RadioListTile<String>( (u) => RadioListTile<String>(
@@ -1726,7 +1770,9 @@ Future<void> bgUpdateCheck(String taskId, Map<String, dynamic>? params) async {
int maxRetryWaitSeconds = 5; int maxRetryWaitSeconds = 5;
var netResult = await (Connectivity().checkConnectivity()); var netResult = await (Connectivity().checkConnectivity());
if (netResult.contains(ConnectivityResult.none)) { if (netResult.contains(ConnectivityResult.none) ||
netResult.isEmpty ||
(netResult.contains(ConnectivityResult.vpn) && netResult.length == 1)) {
logs.add('BG update task: No network.'); logs.add('BG update task: No network.');
return; return;
} }

View File

@@ -354,11 +354,17 @@ preStandardizeUrl(String url) {
url.toLowerCase().indexOf('https://') != 0) { url.toLowerCase().indexOf('https://') != 0) {
url = 'https://$url'; url = 'https://$url';
} }
var uri = Uri.tryParse(url);
var trailingSlash = ((uri?.path.endsWith('/') ?? false) ||
((uri?.path.isEmpty ?? false) && url.endsWith('/'))) &&
(uri?.queryParameters.isEmpty ?? false);
url = url url = url
.split('/') .split('/')
.where((e) => e.isNotEmpty) .where((e) => e.isNotEmpty)
.join('/') .join('/')
.replaceFirst(':/', '://'); .replaceFirst(':/', '://') +
(trailingSlash ? '/' : '');
return url; return url;
} }
@@ -461,6 +467,10 @@ abstract class AppSource {
} }
} }
void runOnAddAppInputChange(String inputUrl) {
//
}
String sourceSpecificStandardizeURL(String url) { String sourceSpecificStandardizeURL(String url) {
throw NotImplementedError(); throw NotImplementedError();
} }
@@ -485,13 +495,15 @@ abstract class AppSource {
], ],
[ [
GeneratedFormTextField('versionExtractionRegEx', GeneratedFormTextField('versionExtractionRegEx',
label: tr('versionExtractionRegEx'), label: tr('trimVersionString'),
required: false, required: false,
additionalValidators: [(value) => regExValidator(value)]), additionalValidators: [(value) => regExValidator(value)]),
], ],
[ [
GeneratedFormTextField('matchGroupToUse', GeneratedFormTextField('matchGroupToUse',
label: tr('matchGroupToUse'), required: false, hint: '\$0') label: tr('matchGroupToUseForX', args: [tr('trimVersionString')]),
required: false,
hint: '\$0')
], ],
[ [
GeneratedFormSwitch('versionDetection', GeneratedFormSwitch('versionDetection',
@@ -523,8 +535,7 @@ abstract class AppSource {
[GeneratedFormTextField('appName', label: tr('appName'), required: false)], [GeneratedFormTextField('appName', label: tr('appName'), required: false)],
[ [
GeneratedFormSwitch('shizukuPretendToBeGooglePlay', GeneratedFormSwitch('shizukuPretendToBeGooglePlay',
label: tr('shizukuPretendToBeGooglePlay'), label: tr('shizukuPretendToBeGooglePlay'), defaultValue: false)
defaultValue: false)
], ],
[ [
GeneratedFormSwitch('exemptFromBackgroundUpdates', GeneratedFormSwitch('exemptFromBackgroundUpdates',
@@ -616,7 +627,7 @@ abstract class AppSource {
} }
bool canSearch = false; bool canSearch = false;
bool excludeFromMassSearch = false; bool includeAdditionalOptsInMainSearch = false;
List<GeneratedFormItem> searchQuerySettingFormItems = []; List<GeneratedFormItem> searchQuerySettingFormItems = [];
Future<Map<String, List<String>>> search(String query, Future<Map<String, List<String>>> search(String query,
{Map<String, dynamic> querySettings = const {}}) { {Map<String, dynamic> querySettings = const {}}) {

View File

@@ -47,18 +47,42 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: app_links name: app_links
sha256: "1c2b9e9c56d80d17610bcbd111b37187875c5d0ded8654caa1bda14ea753d001" sha256: ae5f9a1b7d40d26178f605414be81ed4260350b4fae8259fe5ca4f89fe70c4af
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.0.1" version: "6.1.4"
app_links_linux:
dependency: transitive
description:
name: app_links_linux
sha256: f5f7173a78609f3dfd4c2ff2c95bd559ab43c80a87dc6a095921d96c05688c81
url: "https://pub.dev"
source: hosted
version: "1.0.3"
app_links_platform_interface:
dependency: transitive
description:
name: app_links_platform_interface
sha256: "05f5379577c513b534a29ddea68176a4d4802c46180ee8e2e966257158772a3f"
url: "https://pub.dev"
source: hosted
version: "2.0.2"
app_links_web:
dependency: transitive
description:
name: app_links_web
sha256: "74586ed5f3c4786341e82a0fa43c39ec3f13108a550f74e80d8bf68aa11349d1"
url: "https://pub.dev"
source: hosted
version: "1.0.3"
archive: archive:
dependency: transitive dependency: transitive
description: description:
name: archive name: archive
sha256: ecf4273855368121b1caed0d10d4513c7241dfc813f7d3c8933b36622ae9b265 sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.5.1" version: "3.6.1"
args: args:
dependency: transitive dependency: transitive
description: description:
@@ -79,10 +103,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: background_fetch name: background_fetch
sha256: "2fe367c9be0e256dadb75b8b637b0b58a2a2d2317b7c8420bb1ae8b41e23fde3" sha256: b5c298c911bc2ce41152668bc72eb0488f0665d75bc6d1e69e7d8367763eddcd
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.3.4" version: "1.3.5"
boolean_selector: boolean_selector:
dependency: transitive dependency: transitive
description: description:
@@ -263,10 +287,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: file_picker name: file_picker
sha256: "29c90806ac5f5fb896547720b73b17ee9aed9bba540dc5d91fe29f8c5745b10a" sha256: "824f5b9f389bfc4dddac3dea76cd70c51092d9dff0b2ece7ef4f53db8547d258"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "8.0.3" version: "8.0.6"
fixnum: fixnum:
dependency: transitive dependency: transitive
description: description:
@@ -279,18 +303,18 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: flex_color_picker name: flex_color_picker
sha256: "5c846437069fb7afdd7ade6bf37e628a71d2ab0787095ddcb1253bf9345d5f3a" sha256: "809af4ec82ede3b140ed0219b97d548de99e47aa4b99b14a10f705a2dbbcba5e"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.4.1" version: "3.5.1"
flex_seed_scheme: flex_seed_scheme:
dependency: transitive dependency: transitive
description: description:
name: flex_seed_scheme name: flex_seed_scheme
sha256: "4cee2f1d07259f77e8b36f4ec5f35499d19e74e17c7dce5b819554914082bc01" sha256: cb5b7ec4ba525d9846d8992858a1c6cfc88f9466d96b8850e2a061aa5f682539
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.5.0" version: "3.1.1"
flutter: flutter:
dependency: "direct main" dependency: "direct main"
description: flutter description: flutter
@@ -312,6 +336,54 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.3.0" version: "0.3.0"
flutter_keyboard_visibility:
dependency: transitive
description:
name: flutter_keyboard_visibility
sha256: "98664be7be0e3ffca00de50f7f6a287ab62c763fc8c762e0a21584584a3ff4f8"
url: "https://pub.dev"
source: hosted
version: "6.0.0"
flutter_keyboard_visibility_linux:
dependency: transitive
description:
name: flutter_keyboard_visibility_linux
sha256: "6fba7cd9bb033b6ddd8c2beb4c99ad02d728f1e6e6d9b9446667398b2ac39f08"
url: "https://pub.dev"
source: hosted
version: "1.0.0"
flutter_keyboard_visibility_macos:
dependency: transitive
description:
name: flutter_keyboard_visibility_macos
sha256: c5c49b16fff453dfdafdc16f26bdd8fb8d55812a1d50b0ce25fc8d9f2e53d086
url: "https://pub.dev"
source: hosted
version: "1.0.0"
flutter_keyboard_visibility_platform_interface:
dependency: transitive
description:
name: flutter_keyboard_visibility_platform_interface
sha256: e43a89845873f7be10cb3884345ceb9aebf00a659f479d1c8f4293fcb37022a4
url: "https://pub.dev"
source: hosted
version: "2.0.0"
flutter_keyboard_visibility_web:
dependency: transitive
description:
name: flutter_keyboard_visibility_web
sha256: d3771a2e752880c79203f8d80658401d0c998e4183edca05a149f5098ce6e3d1
url: "https://pub.dev"
source: hosted
version: "2.0.0"
flutter_keyboard_visibility_windows:
dependency: transitive
description:
name: flutter_keyboard_visibility_windows
sha256: fc4b0f0b6be9b93ae527f3d527fb56ee2d918cd88bbca438c478af7bcfd0ef73
url: "https://pub.dev"
source: hosted
version: "1.0.0"
flutter_launcher_icons: flutter_launcher_icons:
dependency: "direct dev" dependency: "direct dev"
description: description:
@@ -332,26 +404,26 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: flutter_local_notifications name: flutter_local_notifications
sha256: "40e6fbd2da7dcc7ed78432c5cdab1559674b4af035fddbfb2f9a8f9c2112fcef" sha256: dd6676d8c2926537eccdf9f72128bbb2a9d0814689527b17f92c248ff192eaf3
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "17.1.2" version: "17.2.1+2"
flutter_local_notifications_linux: flutter_local_notifications_linux:
dependency: transitive dependency: transitive
description: description:
name: flutter_local_notifications_linux name: flutter_local_notifications_linux
sha256: "33f741ef47b5f63cc7f78fe75eeeac7e19f171ff3c3df054d84c1e38bedb6a03" sha256: c49bd06165cad9beeb79090b18cd1eb0296f4bf4b23b84426e37dd7c027fc3af
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.0.0+1" version: "4.0.1"
flutter_local_notifications_platform_interface: flutter_local_notifications_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: flutter_local_notifications_platform_interface name: flutter_local_notifications_platform_interface
sha256: "340abf67df238f7f0ef58f4a26d2a83e1ab74c77ab03cd2b2d5018ac64db30b7" sha256: "85f8d07fe708c1bdcf45037f2c0109753b26ae077e9d9e899d55971711a4ea66"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "7.1.0" version: "7.2.0"
flutter_localizations: flutter_localizations:
dependency: transitive dependency: transitive
description: flutter description: flutter
@@ -361,23 +433,31 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: flutter_markdown name: flutter_markdown
sha256: "9921f9deda326f8a885e202b1e35237eadfc1345239a0f6f0f1ff287e047547f" sha256: "2e8a801b1ded5ea001a4529c97b1f213dcb11c6b20668e081cafb23468593514"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.7.1" version: "0.7.3"
flutter_plugin_android_lifecycle: flutter_plugin_android_lifecycle:
dependency: transitive dependency: transitive
description: description:
name: flutter_plugin_android_lifecycle name: flutter_plugin_android_lifecycle
sha256: "8cf40eebf5dec866a6d1956ad7b4f7016e6c0cc69847ab946833b7d43743809f" sha256: c6b0b4c05c458e1c01ad9bcc14041dd7b1f6783d487be4386f793f47a8a4d03e
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.19" version: "2.0.20"
flutter_test: flutter_test:
dependency: "direct dev" dependency: "direct dev"
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" version: "0.0.0"
flutter_typeahead:
dependency: "direct main"
description:
name: flutter_typeahead
sha256: d64712c65db240b1057559b952398ebb6e498077baeebf9b0731dade62438a6d
url: "https://pub.dev"
source: hosted
version: "5.2.0"
flutter_web_plugins: flutter_web_plugins:
dependency: transitive dependency: transitive
description: flutter description: flutter
@@ -387,10 +467,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: fluttertoast name: fluttertoast
sha256: "81b68579e23fcbcada2db3d50302813d2371664afe6165bc78148050ab94bf66" sha256: "7eae679e596a44fdf761853a706f74979f8dd3cd92cf4e23cae161fda091b847"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "8.2.5" version: "8.2.6"
fraction: fraction:
dependency: transitive dependency: transitive
description: description:
@@ -443,18 +523,18 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: image name: image
sha256: "4c68bfd5ae83e700b5204c1e74451e7bf3cf750e6843c6e158289cf56bda018e" sha256: "2237616a36c0d69aef7549ab439b833fb7f9fb9fc861af2cc9ac3eedddd69ca8"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.1.7" version: "4.2.0"
intl: intl:
dependency: transitive dependency: transitive
description: description:
name: intl name: intl
sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d" sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.18.1" version: "0.19.0"
json_annotation: json_annotation:
dependency: transitive dependency: transitive
description: description:
@@ -467,26 +547,26 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: leak_tracker name: leak_tracker
sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "10.0.0" version: "10.0.4"
leak_tracker_flutter_testing: leak_tracker_flutter_testing:
dependency: transitive dependency: transitive
description: description:
name: leak_tracker_flutter_testing name: leak_tracker_flutter_testing
sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.1" version: "3.0.3"
leak_tracker_testing: leak_tracker_testing:
dependency: transitive dependency: transitive
description: description:
name: leak_tracker_testing name: leak_tracker_testing
sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.1" version: "3.0.1"
lints: lints:
dependency: transitive dependency: transitive
description: description:
@@ -496,7 +576,7 @@ packages:
source: hosted source: hosted
version: "4.0.0" version: "4.0.0"
markdown: markdown:
dependency: transitive dependency: "direct main"
description: description:
name: markdown name: markdown
sha256: ef2a1298144e3f985cc736b22e0ccdaf188b5b3970648f2d9dc13efd1d9df051 sha256: ef2a1298144e3f985cc736b22e0ccdaf188b5b3970648f2d9dc13efd1d9df051
@@ -523,10 +603,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: meta name: meta
sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.11.0" version: "1.12.0"
mime: mime:
dependency: transitive dependency: transitive
description: description:
@@ -571,10 +651,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: path_provider_android name: path_provider_android
sha256: a248d8146ee5983446bf03ed5ea8f6533129a12b11f12057ad1b4a67a2b3b41d sha256: "30c5aa827a6ae95ce2853cdc5fe3971daaac00f6f081c419c013f7f57bff2f5e"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.4" version: "2.2.7"
path_provider_foundation: path_provider_foundation:
dependency: transitive dependency: transitive
description: description:
@@ -603,10 +683,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: path_provider_windows name: path_provider_windows
sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170" sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.1" version: "2.3.0"
permission_handler: permission_handler:
dependency: "direct main" dependency: "direct main"
description: description:
@@ -619,18 +699,18 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: permission_handler_android name: permission_handler_android
sha256: "8bb852cd759488893805c3161d0b2b5db55db52f773dbb014420b304055ba2c5" sha256: b29a799ca03be9f999aa6c39f7de5209482d638e6f857f6b93b0875c618b7e54
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "12.0.6" version: "12.0.7"
permission_handler_apple: permission_handler_apple:
dependency: transitive dependency: transitive
description: description:
name: permission_handler_apple name: permission_handler_apple
sha256: e9ad66020b89ff1b63908f247c2c6f931c6e62699b756ef8b3c4569350cd8662 sha256: e6f6d73b12438ef13e648c4ae56bd106ec60d17e90a59c4545db6781229082a0
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "9.4.4" version: "9.4.5"
permission_handler_html: permission_handler_html:
dependency: transitive dependency: transitive
description: description:
@@ -667,10 +747,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: platform name: platform
sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec" sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.1.4" version: "3.1.5"
plugin_platform_interface: plugin_platform_interface:
dependency: transitive dependency: transitive
description: description:
@@ -679,6 +759,38 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.8" version: "2.1.8"
pointer_interceptor:
dependency: transitive
description:
name: pointer_interceptor
sha256: d0a8e660d1204eaec5bd34b34cc92174690e076d2e4f893d9d68c486a13b07c4
url: "https://pub.dev"
source: hosted
version: "0.10.1+1"
pointer_interceptor_ios:
dependency: transitive
description:
name: pointer_interceptor_ios
sha256: a6906772b3205b42c44614fcea28f818b1e5fdad73a4ca742a7bd49818d9c917
url: "https://pub.dev"
source: hosted
version: "0.10.1"
pointer_interceptor_platform_interface:
dependency: transitive
description:
name: pointer_interceptor_platform_interface
sha256: "0597b0560e14354baeb23f8375cd612e8bd4841bf8306ecb71fcd0bb78552506"
url: "https://pub.dev"
source: hosted
version: "0.10.0+1"
pointer_interceptor_web:
dependency: transitive
description:
name: pointer_interceptor_web
sha256: a6237528b46c411d8d55cdfad8fcb3269fc4cbb26060b14bff94879165887d1e
url: "https://pub.dev"
source: hosted
version: "0.10.2"
provider: provider:
dependency: "direct main" dependency: "direct main"
description: description:
@@ -715,10 +827,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: shared_preferences_android name: shared_preferences_android
sha256: "1ee8bf911094a1b592de7ab29add6f826a7331fb854273d55918693d5364a1f2" sha256: "93d0ec9dd902d85f326068e6a899487d1f65ffcd5798721a95330b26c8131577"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.2" version: "2.2.3"
shared_preferences_foundation: shared_preferences_foundation:
dependency: transitive dependency: transitive
description: description:
@@ -857,18 +969,18 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: test_api name: test_api
sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.6.1" version: "0.7.0"
timezone: timezone:
dependency: transitive dependency: transitive
description: description:
name: timezone name: timezone
sha256: a6ccda4a69a442098b602c44e61a1e2b4bf6f5516e875bbf0f427d5df14745d5 sha256: "2236ec079a174ce07434e89fcd3fcda430025eb7692244139a9cf54fdcf1fc7d"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.9.3" version: "0.9.4"
typed_data: typed_data:
dependency: transitive dependency: transitive
description: description:
@@ -881,26 +993,26 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: url_launcher name: url_launcher
sha256: "6ce1e04375be4eed30548f10a315826fd933c1e493206eab82eed01f438c8d2e" sha256: "21b704ce5fa560ea9f3b525b43601c678728ba46725bab9b01187b4831377ed3"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.2.6" version: "6.3.0"
url_launcher_android: url_launcher_android:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_android name: url_launcher_android
sha256: "360a6ed2027f18b73c8d98e159dda67a61b7f2e0f6ec26e86c3ada33b0621775" sha256: ceb2625f0c24ade6ef6778d1de0b2e44f2db71fded235eb52295247feba8c5cf
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.3.1" version: "6.3.3"
url_launcher_ios: url_launcher_ios:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_ios name: url_launcher_ios
sha256: "7068716403343f6ba4969b4173cbf3b84fc768042124bc2c011e5d782b24fe89" sha256: e43b677296fadce447e987a2f519dcf5f6d1e527dc35d01ffab4fff5b8a7063e
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.3.0" version: "6.3.1"
url_launcher_linux: url_launcher_linux:
dependency: transitive dependency: transitive
description: description:
@@ -945,10 +1057,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: uuid name: uuid
sha256: "814e9e88f21a176ae1359149021870e87f7cddaf633ab678a5d2b0bff7fd1ba8" sha256: "83d37c7ad7aaf9aa8e275490669535c8080377cfa7a7004c24dfac53afffaa90"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.4.0" version: "4.4.2"
vector_math: vector_math:
dependency: transitive dependency: transitive
description: description:
@@ -961,10 +1073,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: vm_service name: vm_service
sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "13.0.0" version: "14.2.1"
web: web:
dependency: transitive dependency: transitive
description: description:
@@ -977,18 +1089,18 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: webview_flutter name: webview_flutter
sha256: "25e1b6e839e8cbfbd708abc6f85ed09d1727e24e08e08c6b8590d7c65c9a8932" sha256: "6869c8786d179f929144b4a1f86e09ac0eddfe475984951ea6c634774c16b522"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.7.0" version: "4.8.0"
webview_flutter_android: webview_flutter_android:
dependency: transitive dependency: transitive
description: description:
name: webview_flutter_android name: webview_flutter_android
sha256: dad3313c9ead95517bb1cae5e1c9d20ba83729d5a59e5e83c0a2d66203f27f91 sha256: f42447ca49523f11d8f70abea55ea211b3cafe172dd7a0e7ac007bb35dd356dc
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.16.1" version: "3.16.4"
webview_flutter_platform_interface: webview_flutter_platform_interface:
dependency: transitive dependency: transitive
description: description:
@@ -1001,18 +1113,18 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: webview_flutter_wkwebview name: webview_flutter_wkwebview
sha256: f12f8d8a99784b863e8b85e4a9a5e3cf1839d6803d2c0c3e0533a8f3c5a992a7 sha256: "9c62cc46fa4f2d41e10ab81014c1de470a6c6f26051a2de32111b2ee55287feb"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.13.0" version: "3.14.0"
win32: win32:
dependency: transitive dependency: transitive
description: description:
name: win32 name: win32
sha256: "0eaf06e3446824099858367950a813472af675116bf63f008a4c2a75ae13e9cb" sha256: a79dbe579cb51ecd6d30b17e0cae4e0ea15e2c0e66f69ad4198f22a6789e94f4
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "5.5.0" version: "5.5.1"
win32_registry: win32_registry:
dependency: transitive dependency: transitive
description: description:
@@ -1046,5 +1158,5 @@ packages:
source: hosted source: hosted
version: "3.1.2" version: "3.1.2"
sdks: sdks:
dart: ">=3.3.3 <4.0.0" dart: ">=3.4.0 <4.0.0"
flutter: ">=3.19.0" flutter: ">=3.22.0"

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: 1.1.8+2265 version: 1.1.14+2271
environment: environment:
sdk: '>=3.0.0 <4.0.0' sdk: '>=3.0.0 <4.0.0'
@@ -79,6 +79,8 @@ dependencies:
url: https://github.com/re7gog/shizuku_apk_installer url: https://github.com/re7gog/shizuku_apk_installer
ref: master ref: master
markdown: any
flutter_typeahead: ^5.2.0
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
sdk: flutter sdk: flutter