mirror of
https://github.com/ImranR98/Obtainium.git
synced 2025-07-31 21:00:15 +02:00
Compare commits
107 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
cd153e7d11 | ||
|
3b494511d7 | ||
|
6c806a44d4 | ||
|
c5bac43bfd | ||
|
1636281d6d | ||
|
0f4feb2da6 | ||
|
c32f34c116 | ||
|
d391c5cfc2 | ||
|
bb45a157b3 | ||
|
c90a571f89 | ||
|
1278407c90 | ||
|
dff1b4cf39 | ||
|
105e70a814 | ||
|
2938cea419 | ||
|
9b6b7780d8 | ||
|
f53a4f3827 | ||
|
9b0d672553 | ||
|
9d14145ac2 | ||
|
9948797b25 | ||
|
a80d9e3623 | ||
|
37ecb057f9 | ||
|
06cbe74c6c | ||
|
f5769b85fe | ||
|
875868af47 | ||
|
24ea15d600 | ||
|
87cdc3dcef | ||
|
c2f976d7f4 | ||
|
ebc46bfd3f | ||
|
e674f7e89d | ||
|
86d29b163c | ||
|
a849919799 | ||
|
d8c805a6b3 | ||
|
8acbd3ef78 | ||
|
b81088d767 | ||
|
7071e34a74 | ||
|
6a73ade359 | ||
|
6c5e5043a4 | ||
|
5edaf1306d | ||
|
5bf7fdb94e | ||
|
7808bc5ccb | ||
|
06a079e452 | ||
|
de509737e6 | ||
|
08a3ba8d13 | ||
|
2b27902d5f | ||
|
62185127c2 | ||
|
9c46e3f88c | ||
|
daa4de921d | ||
|
bc977e2a5a | ||
|
1e3815ca20 | ||
|
0e2fa96b9f | ||
|
389aebe54e | ||
|
fbfeaf2a91 | ||
|
485812d076 | ||
|
68e98ec719 | ||
|
cbe41de734 | ||
|
abb8641105 | ||
|
dbcb4b3c09 | ||
|
b231c756e6 | ||
|
3cb3f7fdd4 | ||
|
9837e8e325 | ||
|
73d4814f18 | ||
|
0a9219c314 | ||
|
56c5a73d9a | ||
|
a30e063246 | ||
|
bd26b6514a | ||
|
3ea8c7e888 | ||
|
5f2ec5ce6f | ||
|
783ce9d555 | ||
|
a719b2475b | ||
|
84df499ea6 | ||
|
0d25b74050 | ||
|
0effbc3841 | ||
|
7478a7af22 | ||
|
0838a6d30b | ||
|
8cee268d13 | ||
|
a3fddc5400 | ||
|
c0a2e372e5 | ||
|
c633963203 | ||
|
299f457938 | ||
|
37e62c922b | ||
|
95722ce47b | ||
|
8b806b3ef1 | ||
|
09221b3526 | ||
|
31b6250082 | ||
|
07372da91b | ||
|
5c36bcfb4b | ||
|
e5012b1fcb | ||
|
6f951175a4 | ||
|
be52ec372f | ||
|
eb7126afc3 | ||
|
26fc63a02a | ||
|
d33ca0948f | ||
|
f76637a2e1 | ||
|
b7de627c7b | ||
|
27fc60d437 | ||
|
ec240f946e | ||
|
ecd80fc371 | ||
|
68fa660e6d | ||
|
70f9e33d17 | ||
|
2e2dffd8e2 | ||
|
0b1d5bf514 | ||
|
2570c8e289 | ||
|
43a8ba4de1 | ||
|
3f2fb1c1ed | ||
|
40d303fb57 | ||
|
2c1687c33d | ||
|
b688e7f160 |
2
.flutter
2
.flutter
Submodule .flutter updated: 54e66469a9...761747bfc5
10
README.md
10
README.md
@@ -29,15 +29,23 @@ Currently supported App sources:
|
||||
- [Huawei AppGallery](https://appgallery.huawei.com/)
|
||||
- Jenkins Jobs
|
||||
- Open Source - App-Specific:
|
||||
- [Mullvad](https://mullvad.net/en/)
|
||||
- [Signal](https://signal.org/)
|
||||
- [VLC](https://videolan.org/)
|
||||
- Other - App-Specific:
|
||||
- [WhatsApp](https://whatsapp.com)
|
||||
- [Telegram App](https://telegram.org)
|
||||
- [Neutron Code](https://neutroncode.com)
|
||||
- Direct APK Link
|
||||
- "HTML" (Fallback): Any other URL that returns an HTML page with links to APK files
|
||||
|
||||
## Finding App Configurations
|
||||
|
||||
You can find crowdsourced app configurations at [apps.obtainium.imranr.dev](https://apps.obtainium.imranr.dev).
|
||||
|
||||
If you can't find the configuration for an app you want, feel free to leave a request on the [discussions page](https://github.com/ImranR98/apps.obtainium.imranr.dev/discussions/new?category=app-requests).
|
||||
|
||||
Or, contribute some configurations to the website by creating a PR at [this repo](https://github.com/ImranR98/apps.obtainium.imranr.dev).
|
||||
|
||||
## Installation
|
||||
|
||||
[<img src="https://github.com/machiav3lli/oandbackupx/blob/034b226cea5c1b30eb4f6a6f313e4dadcbb0ece4/badge_github.png"
|
||||
|
@@ -6,7 +6,8 @@
|
||||
android:name="${applicationName}"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:requestLegacyExternalStorage="true"
|
||||
android:usesCleartextTraffic="true">
|
||||
android:usesCleartextTraffic="true"
|
||||
android:localeConfig="@xml/locales_config">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
@@ -47,7 +48,7 @@
|
||||
android:value="2" />
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="dev.imranr.obtainium"
|
||||
android:authorities="${applicationId}"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
@@ -72,4 +73,4 @@
|
||||
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
||||
android:maxSdkVersion="29" />\
|
||||
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
|
||||
</manifest>
|
||||
</manifest>
|
||||
|
22
android/app/src/main/res/xml/locales_config.xml
Normal file
22
android/app/src/main/res/xml/locales_config.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<locale-config xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<locale android:name="bs"/>
|
||||
<locale android:name="cs"/>
|
||||
<locale android:name="de"/>
|
||||
<locale android:name="en"/>
|
||||
<locale android:name="es"/>
|
||||
<locale android:name="fa"/>
|
||||
<locale android:name="fr"/>
|
||||
<locale android:name="hu"/>
|
||||
<locale android:name="it"/>
|
||||
<locale android:name="ja"/>
|
||||
<locale android:name="nl"/>
|
||||
<locale android:name="pl"/>
|
||||
<locale android:name="pt"/>
|
||||
<locale android:name="ru"/>
|
||||
<locale android:name="sv"/>
|
||||
<locale android:name="tr"/>
|
||||
<locale android:name="uk"/>
|
||||
<locale android:name="vi"/>
|
||||
<locale android:name="zh"/>
|
||||
</locale-config>
|
@@ -113,6 +113,7 @@
|
||||
"dark": "Tamna",
|
||||
"light": "Svijetla",
|
||||
"followSystem": "Pratite sistem",
|
||||
"followSystemThemeExplanation": "Following system theme is possible only by using third-party applications",
|
||||
"useBlackTheme": "Koristite čisto crnu tamnu temu",
|
||||
"appSortBy": "Aplikacije sortirane po",
|
||||
"authorName": "Autor/Ime",
|
||||
@@ -309,6 +310,8 @@
|
||||
"badDownload": "The APK could not be parsed (incompatible or partial download)",
|
||||
"beforeNewInstallsShareToAppVerifier": "Share new Apps with AppVerifier (if available)",
|
||||
"appVerifierInstructionToast": "Share to AppVerifier, then return here when ready.",
|
||||
"wiki": "Help/Wiki",
|
||||
"crowdsourcedConfigsLabel": "Crowdsourced App Configurations (use at your own risk)",
|
||||
"removeAppQuestion": {
|
||||
"one": "Želite li ukloniti aplikaciju?",
|
||||
"other": "Želite li ukloniti aplikacije?"
|
||||
|
@@ -113,6 +113,7 @@
|
||||
"dark": "Tmavé",
|
||||
"light": "Světlé",
|
||||
"followSystem": "Jako systém",
|
||||
"followSystemThemeExplanation": "Sledování motivu systému je možné pouze pomocí aplikací třetích stran.",
|
||||
"useBlackTheme": "Použít čistě černé tmavé téma",
|
||||
"appSortBy": "Seřadit podle",
|
||||
"authorName": "Autor/Jméno",
|
||||
@@ -309,6 +310,8 @@
|
||||
"badDownload": "APK nelze analyzovat (nekompatibilní nebo částečné stažení)",
|
||||
"beforeNewInstallsShareToAppVerifier": "Sdílení nových aplikací s aplikací AppVerifier (pokud je k dispozici)",
|
||||
"appVerifierInstructionToast": "Sdílejte do aplikace AppVerifier a po dokončení se sem vraťte.",
|
||||
"wiki": "Nápověda/Wiki",
|
||||
"crowdsourcedConfigsLabel": "Konfigurace aplikací s využitím crowdsourcingu (použití na vlastní nebezpečí)",
|
||||
"removeAppQuestion": {
|
||||
"one": "Odstranit Apku?",
|
||||
"other": "Odstranit Apky?"
|
||||
|
375
assets/translations/da.json
Normal file
375
assets/translations/da.json
Normal file
@@ -0,0 +1,375 @@
|
||||
{
|
||||
"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",
|
||||
"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": "Note",
|
||||
"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"
|
||||
}
|
||||
}
|
@@ -24,7 +24,7 @@
|
||||
"colour": "Farbe",
|
||||
"standard": "Standard",
|
||||
"custom": "Benutzerdefiniert",
|
||||
"useMaterialYou": "Verwenden Sie Material, das Sie",
|
||||
"useMaterialYou": "Verwende Material You",
|
||||
"githubStarredRepos": "GitHub Starred Repos",
|
||||
"uname": "Benutzername",
|
||||
"wrongArgNum": "Falsche Anzahl von Argumenten (Parametern) übermittelt",
|
||||
@@ -113,6 +113,7 @@
|
||||
"dark": "Dunkel",
|
||||
"light": "Hell",
|
||||
"followSystem": "System folgen",
|
||||
"followSystemThemeExplanation": "Das Folgen des Systemthemes ist unter Android <10 nur mit Hilfe von Drittanbieteranwendungen möglich",
|
||||
"useBlackTheme": "Verwende Pure Black Dark Theme",
|
||||
"appSortBy": "App sortieren nach",
|
||||
"authorName": "Autor/Name",
|
||||
@@ -309,6 +310,8 @@
|
||||
"badDownload": "Die APK konnte nicht geparst werden (inkompatibler oder teilweiser Download)",
|
||||
"beforeNewInstallsShareToAppVerifier": "Neue Apps mit AppVerifier teilen (falls verfügbar)",
|
||||
"appVerifierInstructionToast": "Geben Sie die Daten an AppVerifier weiter und kehren Sie dann hierher zurück, wenn Sie fertig sind.",
|
||||
"wiki": "Hilfe/Wiki",
|
||||
"crowdsourcedConfigsLabel": "Crowdsourced App Configurations (Verwendung auf eigene Gefahr)",
|
||||
"removeAppQuestion": {
|
||||
"one": "App entfernen?",
|
||||
"other": "Apps entfernen?"
|
||||
|
@@ -113,6 +113,7 @@
|
||||
"dark": "Dark",
|
||||
"light": "Light",
|
||||
"followSystem": "Follow System",
|
||||
"followSystemThemeExplanation": "Following system theme is possible only by using third-party applications",
|
||||
"useBlackTheme": "Use pure black dark theme",
|
||||
"appSortBy": "App Sort By",
|
||||
"authorName": "Author/Name",
|
||||
@@ -258,7 +259,7 @@
|
||||
"bgUpdatesOnWiFiOnly": "Disable background updates when not on WiFi",
|
||||
"autoSelectHighestVersionCode": "Auto-select highest versionCode APK",
|
||||
"versionExtractionRegEx": "Version String Extraction RegEx",
|
||||
"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",
|
||||
"pickExportDir": "Pick Export Directory",
|
||||
"autoExportOnChanges": "Auto-export on changes",
|
||||
@@ -309,6 +310,8 @@
|
||||
"badDownload": "The APK could not be parsed (incompatible or partial download)",
|
||||
"beforeNewInstallsShareToAppVerifier": "Share new Apps with AppVerifier (if available)",
|
||||
"appVerifierInstructionToast": "Share to AppVerifier, then return here when ready.",
|
||||
"wiki": "Help/Wiki",
|
||||
"crowdsourcedConfigsLabel": "Crowdsourced App Configurations (use at your own risk)",
|
||||
"removeAppQuestion": {
|
||||
"one": "Remove App?",
|
||||
"other": "Remove Apps?"
|
||||
|
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"invalidURLForSource": "El URL de la aplicación {} no es válido",
|
||||
"noReleaseFound": "No se ha podido encontrar una versión válida",
|
||||
"noReleaseFound": "No se ha encontrado una versión válida",
|
||||
"noVersionFound": "No se ha podido determinar la versión",
|
||||
"urlMatchesNoSource": "El URL no coincide con ninguna fuente conocida",
|
||||
"cantInstallOlderVersion": "No se puede instalar una versión previa de la aplicación",
|
||||
"appIdMismatch": "El id. del paquete descargado no coincide con la ID de la aplicación instalada",
|
||||
"appIdMismatch": "El ID del paquete descargado no coincide con el ID de la aplicación instalada",
|
||||
"functionNotImplemented": "Esta clase no ha implementado esta función",
|
||||
"placeholder": "Espacio reservado",
|
||||
"someErrors": "Han ocurrido algunos errores",
|
||||
@@ -21,18 +21,18 @@
|
||||
"continue": "Continuar",
|
||||
"requiredInBrackets": "(Requerido)",
|
||||
"dropdownNoOptsError": "ERROR: EL DESPLEGABLE DEBE TENER AL MENOS UNA OPCIÓN",
|
||||
"colour": "Color",
|
||||
"colour": "color",
|
||||
"standard": "Estándar",
|
||||
"custom": "A medida",
|
||||
"useMaterialYou": "Utilice el material que",
|
||||
"githubStarredRepos": "Repositorios favoritos en GitHub",
|
||||
"useMaterialYou": "Aplicar 'Material You'",
|
||||
"githubStarredRepos": "repositorios favoritos en GitHub",
|
||||
"uname": "Nombre de usuario",
|
||||
"wrongArgNum": "Número de argumentos provistos inválido",
|
||||
"xIsTrackOnly": "{} es de 'sólo seguimiento'",
|
||||
"source": "Origen",
|
||||
"source": "origen",
|
||||
"app": "Aplicación",
|
||||
"appsFromSourceAreTrackOnly": "Las aplicaciones de este origen son de 'solo seguimiento'.",
|
||||
"youPickedTrackOnly": "Debe seleccionar la opción de 'solo seguimiento'.",
|
||||
"appsFromSourceAreTrackOnly": "Las aplicaciones de este origen son solo para seguimiento.",
|
||||
"youPickedTrackOnly": "Debe seleccionar la opción de 'solo para seguimiento'.",
|
||||
"trackOnlyAppDescription": "Se hará el seguimiento de actualizaciones para la aplicación, pero Obtainium no será capaz de descargar o actualizarla.",
|
||||
"cancelled": "Cancelado",
|
||||
"appAlreadyAdded": "Aplicación añadida anteriormente",
|
||||
@@ -45,14 +45,14 @@
|
||||
"search": "Buscar",
|
||||
"additionalOptsFor": "Opciones adicionales para {}",
|
||||
"supportedSources": "Fuentes admitidas",
|
||||
"trackOnlyInBrackets": "(Solo seguimiento)",
|
||||
"trackOnlyInBrackets": "(Solo para seguimiento)",
|
||||
"searchableInBrackets": "(permite búsqueda)",
|
||||
"appsString": "Aplicaciones",
|
||||
"noApps": "Sin Aplicaciones",
|
||||
"noAppsForFilter": "Sin aplicaciones para filtrar",
|
||||
"byX": "por: {}",
|
||||
"percentProgress": "Progreso: {} %",
|
||||
"pleaseWait": "Espere un momento",
|
||||
"pleaseWait": "Espere...",
|
||||
"updateAvailable": "Actualización disponible",
|
||||
"notInstalled": "No instalado",
|
||||
"pseudoVersion": "pseudoversión",
|
||||
@@ -63,7 +63,7 @@
|
||||
"removeSelectedApps": "Eliminar aplicaciones seleccionadas",
|
||||
"updateX": "Actualizar {}",
|
||||
"installX": "Instalar {}",
|
||||
"markXTrackOnlyAsUpdated": "Marcar {}\n(Solo seguimiento)\ncomo actualizada",
|
||||
"markXTrackOnlyAsUpdated": "Marcar {}\n(solo para seguimiento)\ncomo actualizada",
|
||||
"changeX": "Cambiar {}",
|
||||
"installUpdateApps": "Instalar/actualizar aplicaciones",
|
||||
"installUpdateSelectedApps": "Instalar/actualizar aplicaciones seleccionadas",
|
||||
@@ -100,7 +100,7 @@
|
||||
"appURLList": "Lista de URL de aplicaciones",
|
||||
"line": "Línea",
|
||||
"searchX": "Buscar {}",
|
||||
"noResults": "No se encontró ningún resultado",
|
||||
"noResults": "No se ha encontrado ningún resultado",
|
||||
"importX": "Importar desde {}",
|
||||
"importedAppsIdDisclaimer": "Las aplicaciones importadas podrían mostrarse incorrectamente como «No instalada».\nPara solucionarlo, reinstálelas a través de Obtainium.\nEsto no debería afectar a los datos de las aplicaciones.\n\nSolo afecta a los URL y a los métodos de importación mediante terceros.",
|
||||
"importErrors": "Errores de Importación",
|
||||
@@ -113,6 +113,7 @@
|
||||
"dark": "Oscuro",
|
||||
"light": "Claro",
|
||||
"followSystem": "Seguir al sistema",
|
||||
"followSystemThemeExplanation": "Seguir el tema del sistema sólo es posible utilizando aplicaciones de terceros",
|
||||
"useBlackTheme": "Negro puro en tema oscuro",
|
||||
"appSortBy": "Ordenar aplicaciones por",
|
||||
"authorName": "Autor/nombre",
|
||||
@@ -121,14 +122,14 @@
|
||||
"appSortOrder": "Orden de Clasificación",
|
||||
"ascending": "Ascendente",
|
||||
"descending": "Descendente",
|
||||
"bgUpdateCheckInterval": "Comprobación actualizaciones en segundo plano",
|
||||
"bgUpdateCheckInterval": "Comprobar actualizaciones en segundo plano",
|
||||
"neverManualOnly": "Nunca, solo manual",
|
||||
"appearance": "Apariencia",
|
||||
"showWebInAppView": "Mostrar vista de la web de origen",
|
||||
"pinUpdates": "Anclar actualizaciones al principio",
|
||||
"updates": "Actualizaciones",
|
||||
"sourceSpecific": "Fuente específica",
|
||||
"appSource": "Obtainium en GitHub",
|
||||
"appSource": "Filtrar por fuente",
|
||||
"noLogs": "Ningún registro",
|
||||
"appLogs": "Registros",
|
||||
"close": "Cerrar",
|
||||
@@ -175,9 +176,9 @@
|
||||
"fdroid": "Repositorio oficial F-Droid",
|
||||
"appIdOrName": "ID o Nombre de la Aplicación",
|
||||
"appId": "ID de la Aplicación",
|
||||
"appWithIdOrNameNotFound": "No se han encontrado aplicaciones con esa ID o nombre",
|
||||
"appWithIdOrNameNotFound": "No se han encontrado aplicaciones con ese ID o nombre",
|
||||
"reposHaveMultipleApps": "Los repositorios pueden contener varias aplicaciones",
|
||||
"fdroidThirdPartyRepo": "Repositorio de tercera parte F-Droid",
|
||||
"fdroidThirdPartyRepo": "Repositorio de terceros F-Droid",
|
||||
"steamMobile": "Steam para móviles",
|
||||
"steamChat": "Chat de Steam",
|
||||
"install": "Instalar",
|
||||
@@ -190,9 +191,9 @@
|
||||
"downloadingX": "Descargando {}",
|
||||
"downloadX": "Descargar {}",
|
||||
"downloadedX": "Descargado {}",
|
||||
"releaseAsset": "Liberar activos",
|
||||
"releaseAsset": "Recurso publicado",
|
||||
"downloadNotifDescription": "Notifica al usuario del progreso de descarga de una aplicación",
|
||||
"noAPKFound": "No se encontró el paquete de instalación APK",
|
||||
"noAPKFound": "No se ha encontrado el paquete de instalación APK",
|
||||
"noVersionDetection": "Sin detección de versiones",
|
||||
"categorize": "Catogorizar",
|
||||
"categories": "Categorías",
|
||||
@@ -204,7 +205,7 @@
|
||||
"addCategory": "Añadir categoría",
|
||||
"label": "Nombre",
|
||||
"language": "Idioma",
|
||||
"copiedToClipboard": "Se copió en el portapapeles",
|
||||
"copiedToClipboard": "Copiado en el portapapeles",
|
||||
"storagePermissionDenied": "Permiso de almacenamiento rechazado",
|
||||
"selectedCategorizeWarning": "Esto reemplazará cualquier ajuste de categoría para las aplicaciones seleccionadas.",
|
||||
"filterAPKsByRegEx": "Filtrar por APK",
|
||||
@@ -219,18 +220,18 @@
|
||||
"versionDetectionExplanation": "Conciliar la cadena de versión con la versión detectada desde el sistema operativo",
|
||||
"versionDetection": "Detección de versiones",
|
||||
"standardVersionDetection": "Por versión",
|
||||
"groupByCategory": "Agrupar por categoría",
|
||||
"groupByCategory": "Agrupar por categorías",
|
||||
"autoApkFilterByArch": "Filtrar APK por arquitectura del procesador (si es posible)",
|
||||
"overrideSource": "Anular fuente",
|
||||
"overrideSource": "Forzar desde la fuente",
|
||||
"dontShowAgain": "No mostrar de nuevo",
|
||||
"dontShowTrackOnlyWarnings": "No mostrar avisos sobre apps en 'solo seguimiento'",
|
||||
"dontShowTrackOnlyWarnings": "No mostrar avisos sobre apps 'solo para seguimiento'",
|
||||
"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",
|
||||
"about": "Acerca",
|
||||
"requiresCredentialsInSettings": "{}: Esto requiere credenciales adicionales (en ajustes)",
|
||||
"checkOnStart": "Comprobar actualizaciones al inicio",
|
||||
"tryInferAppIdFromCode": "Intentar deducir la ID de la app por el código fuente",
|
||||
"tryInferAppIdFromCode": "Intentar deducir el ID de la app por el código fuente",
|
||||
"removeOnExternalUninstall": "Auto eliminar apps desinstaladas externamente",
|
||||
"pickHighestVersionCode": "Auto selección de versión superior del paquete APK",
|
||||
"checkUpdateOnDetailPage": "Comprobar actualizaciones al abrir detalles de la app",
|
||||
@@ -285,30 +286,32 @@
|
||||
"checkingForUpdatesNotifChannel": "Buscando actualizaciones",
|
||||
"onlyCheckInstalledOrTrackOnlyApps": "Comprobar actualizaciones solo para apps instaladas o en seguimiento",
|
||||
"supportFixedAPKURL": "Soporte para URLs fijas de APK",
|
||||
"selectX": "Selecciona {}",
|
||||
"selectX": "Elija {}",
|
||||
"parallelDownloads": "Permitir descargas paralelas",
|
||||
"useShizuku": "Utilice Shizuku o Sui para instalar",
|
||||
"useShizuku": "Usar Shizuku o Sui para instalar",
|
||||
"shizukuBinderNotFound": "Shizuku no funciona",
|
||||
"shizukuOld": "Versión antigua de Shizuku (<11) - actualízala",
|
||||
"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",
|
||||
"shizukuPretendToBeGooglePlay": "Establecer Google Play como fuente de instalación (si se utiliza Shizuku)",
|
||||
"useSystemFont": "Usar la fuente de impresión del sistema",
|
||||
"shizukuPretendToBeGooglePlay": "Establecer Google Play como fuente de instalación (si se usa Shizuku)",
|
||||
"useSystemFont": "Usar fuente del sistema",
|
||||
"useVersionCodeAsOSVersion": "Usar la versión de la aplicación como versión detectada por el sistema operativo",
|
||||
"requestHeader": "Encabezado de solicitud",
|
||||
"useLatestAssetDateAsReleaseDate": "Usar la última carga de recursos como fecha de lanzamiento",
|
||||
"useLatestAssetDateAsReleaseDate": "Usar la última carga del recurso como fecha de lanzamiento",
|
||||
"defaultPseudoVersioningMethod": "Método de pseudoversionado predeterminado",
|
||||
"partialAPKHash": "Hash de APK parcial",
|
||||
"APKLinkHash": "Hash de enlace APK",
|
||||
"directAPKLink": "Enlace APK directo",
|
||||
"pseudoVersionInUse": "Se está utilizando una pseudoversión",
|
||||
"pseudoVersionInUse": "Se está usando una pseudoversión",
|
||||
"installed": "Instalado",
|
||||
"latest": "Versión más reciente",
|
||||
"invertRegEx": "Invertir expresión regular",
|
||||
"note": "Nota",
|
||||
"selfHostedNote": "El desplegable «{}» puede utilizarse 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)",
|
||||
"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.",
|
||||
"wiki": "Ayuda/Wiki",
|
||||
"crowdsourcedConfigsLabel": "Crowdsourced App Configurations (uso bajo su propia responsabilidad)",
|
||||
"removeAppQuestion": {
|
||||
"one": "¿Eliminar aplicación?",
|
||||
"other": "¿Eliminar aplicaciones?"
|
||||
|
@@ -113,6 +113,7 @@
|
||||
"dark": "تاریک",
|
||||
"light": "روشن",
|
||||
"followSystem": "هماهنگ با سیستم",
|
||||
"followSystemThemeExplanation": "دنبال کردن تم سیستم فقط با استفاده از برنامه های شخص ثالث امکان پذیر است",
|
||||
"useBlackTheme": "استفاده از تم تیره سیاه خالص",
|
||||
"appSortBy": "مرتب سازی برنامه بر اساس",
|
||||
"authorName": "سازنده/اسم",
|
||||
@@ -146,10 +147,10 @@
|
||||
"noNewUpdates": "به روز رسانی جدیدی وجود ندارد.",
|
||||
"xHasAnUpdate": "{} یک به روز رسانی دارد.",
|
||||
"appsUpdated": "برنامه ها به روز شدند",
|
||||
"appsNotUpdated": "Failed to update applications",
|
||||
"appsNotUpdated": "به روز رسانی برنامه ها ناموفق بود",
|
||||
"appsUpdatedNotifDescription": "به کاربر اطلاع می دهد که به روز رسانی یک یا چند برنامه در پس زمینه اعمال شده است",
|
||||
"xWasUpdatedToY": "{} به {} به روز شد.",
|
||||
"xWasNotUpdatedToY": "Failed to update {} to {}.",
|
||||
"xWasNotUpdatedToY": "به روز رسانی {} به {} انجام نشد.",
|
||||
"errorCheckingUpdates": "خطا در بررسی بهروزرسانیها",
|
||||
"errorCheckingUpdatesNotifDescription": "اعلانی که وقتی بررسی بهروزرسانی پسزمینه ناموفق است نشان میدهد",
|
||||
"appsRemoved": "برنامه ها حذف شدند",
|
||||
@@ -188,9 +189,9 @@
|
||||
"disableVersionDetection": "غیرفعال کردن تشخیص نسخه",
|
||||
"noVersionDetectionExplanation": "این گزینه فقط باید برای برنامه هایی استفاده شود که تشخیص نسخه به درستی کار نمی کند.",
|
||||
"downloadingX": "در حال دانلود {}",
|
||||
"downloadX": "Download {}",
|
||||
"downloadedX": "Downloaded {}",
|
||||
"releaseAsset": "Release Asset",
|
||||
"downloadX": "دانلود {}",
|
||||
"downloadedX": "دانلود شده {}",
|
||||
"releaseAsset": "انتشار دارایی",
|
||||
"downloadNotifDescription": "کاربر را از پیشرفت دانلود یک برنامه مطلع می کند",
|
||||
"noAPKFound": "APK پیدا نشد فایل",
|
||||
"noVersionDetection": "بدون تشخیص نسخه",
|
||||
@@ -304,11 +305,13 @@
|
||||
"installed": "نصب شده است",
|
||||
"latest": "آخرین",
|
||||
"invertRegEx": "معکوس کردن عبارت منظم",
|
||||
"note": "Note",
|
||||
"selfHostedNote": "The \"{}\" dropdown can be used to reach self-hosted/custom instances of any source.",
|
||||
"badDownload": "The APK could not be parsed (incompatible or partial download)",
|
||||
"beforeNewInstallsShareToAppVerifier": "Share new Apps with AppVerifier (if available)",
|
||||
"appVerifierInstructionToast": "Share to AppVerifier, then return here when ready.",
|
||||
"note": "یادداشت",
|
||||
"selfHostedNote": "از منوی کرکره ای \"{}\" می توان برای دسترسی به نمونه های خود میزبانی/سفارشی از هر منبعی استفاده کرد.",
|
||||
"badDownload": "APK قابل تجزیه نیست (دانلود ناسازگار یا جزئی)",
|
||||
"beforeNewInstallsShareToAppVerifier": "اشتراکگذاری برنامههای جدید با AppVerifier (در صورت وجود)",
|
||||
"appVerifierInstructionToast": "در AppVerifier به اشتراک بگذارید، سپس پس از آماده شدن به اینجا برگردید.",
|
||||
"wiki": "راهنما/ویکی",
|
||||
"crowdsourcedConfigsLabel": "تنظیمات برنامه Crowdsourced (با مسئولیت خود استفاده کنید)",
|
||||
"removeAppQuestion": {
|
||||
"one": "برنامه حذف شود؟",
|
||||
"other": "برنامه ها حذف شوند؟"
|
||||
@@ -358,8 +361,8 @@
|
||||
"other": "{} و {} برنامه دیگر به روز شدند."
|
||||
},
|
||||
"xAndNMoreUpdatesFailed": {
|
||||
"one": "Failed to update {} and 1 more app.",
|
||||
"other": "Failed to update {} and {} more apps."
|
||||
"one": "{} و 1 برنامه دیگر به روز نشد.",
|
||||
"other": "{} و {} برنامه دیگر به روز نشد."
|
||||
},
|
||||
"xAndNMoreUpdatesPossiblyInstalled": {
|
||||
"one": "{} و 1 برنامه دیگر ممکن است به روز شده باشند.",
|
||||
|
@@ -11,7 +11,7 @@
|
||||
"unexpectedError": "Erreur inattendue",
|
||||
"ok": "D'accord",
|
||||
"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",
|
||||
"fallbackToOlderReleases": "Retour aux anciennes versions",
|
||||
"filterReleaseTitlesByRegEx": "Filtrer les titres de version par expression régulière",
|
||||
@@ -24,7 +24,7 @@
|
||||
"colour": "Couleur",
|
||||
"standard": "Standard",
|
||||
"custom": "Sur mesure",
|
||||
"useMaterialYou": "Utiliser le matériel que vous",
|
||||
"useMaterialYou": "Utiliser Material You",
|
||||
"githubStarredRepos": "Dépôts étoilés GitHub",
|
||||
"uname": "Nom d'utilisateur",
|
||||
"wrongArgNum": "Mauvais nombre d'arguments fournis",
|
||||
@@ -46,12 +46,12 @@
|
||||
"additionalOptsFor": "Options supplémentaires pour {}",
|
||||
"supportedSources": "Sources prises en charge ",
|
||||
"trackOnlyInBrackets": "(Suivi uniquement)",
|
||||
"searchableInBrackets": "(Intérrogeable)",
|
||||
"searchableInBrackets": "(Interrogeable)",
|
||||
"appsString": "Applications",
|
||||
"noApps": "Aucune application",
|
||||
"noAppsForFilter": "Aucune application pour le filtre",
|
||||
"byX": "Par {}",
|
||||
"percentProgress": "Progrès: {}%",
|
||||
"percentProgress": "Progrès : {}%",
|
||||
"pleaseWait": "Veuillez patienter",
|
||||
"updateAvailable": "Mise à jour disponible",
|
||||
"notInstalled": "Non installé",
|
||||
@@ -67,18 +67,18 @@
|
||||
"changeX": "Changer {}",
|
||||
"installUpdateApps": "Installer/Mettre à jour les applications",
|
||||
"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",
|
||||
"yes": "Oui",
|
||||
"markSelectedAppsUpdated": "Marquer les applications sélectionnées comme étant à jour",
|
||||
"pinToTop": "Épingler en haut",
|
||||
"unpinFromTop": "Désépingler du haut",
|
||||
"resetInstallStatusForSelectedAppsQuestion": "Réinitialiser le statu 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.",
|
||||
"resetInstallStatusForSelectedAppsQuestion": "Réinitialiser le statut d'installation des applications sélectionnées ?",
|
||||
"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é",
|
||||
"shareAppConfigLinks": "Partager la configuration de l'application sous forme de lien HTML",
|
||||
"shareSelectedAppURLs": "Partager les URL d'application sélectionnées",
|
||||
"resetInstallStatus": "Réinitialiser le statu d'installation",
|
||||
"shareSelectedAppURLs": "Partager les URL d'applications sélectionnées",
|
||||
"resetInstallStatus": "Réinitialiser le statut d'installation",
|
||||
"more": "Plus",
|
||||
"removeOutdatedFilter": "Supprimer le filtre d'application obsolète",
|
||||
"showOutdatedOnly": "Afficher uniquement les applications obsolètes",
|
||||
@@ -98,7 +98,7 @@
|
||||
"importFromURLList": "Importer à partir de la liste d'URL",
|
||||
"searchQuery": "Requête",
|
||||
"appURLList": "Liste d'URL d'application",
|
||||
"line": "Queue",
|
||||
"line": "File d'attente",
|
||||
"searchX": "Rechercher {}",
|
||||
"noResults": "Aucun résultat trouvé",
|
||||
"importX": "Importer {}",
|
||||
@@ -107,13 +107,14 @@
|
||||
"importedXOfYApps": "{} sur {} applications importées.",
|
||||
"followingURLsHadErrors": "Les URL suivantes comportaient des erreurs :",
|
||||
"selectURL": "Sélectionnez l'URL",
|
||||
"selectURLs": "Sélectionnez les URLs",
|
||||
"selectURLs": "Sélectionnez les URL",
|
||||
"pick": "Prendre",
|
||||
"theme": "Thème",
|
||||
"dark": "Sombre",
|
||||
"light": "Clair",
|
||||
"followSystem": "Suivre le système",
|
||||
"useBlackTheme": "Utilisez le thème noir pur",
|
||||
"followSystemThemeExplanation": "Il n'est possible de suivre le thème du système qu'en utilisant des applications tierces.",
|
||||
"useBlackTheme": "Utiliser le thème noir pur",
|
||||
"appSortBy": "Applications triées par",
|
||||
"authorName": "Auteur/Nom",
|
||||
"nameAuthor": "Nom/Auteur",
|
||||
@@ -122,10 +123,10 @@
|
||||
"ascending": "Ascendant",
|
||||
"descending": "Descendant",
|
||||
"bgUpdateCheckInterval": "Intervalle de vérification des mises à jour en arrière-plan",
|
||||
"neverManualOnly": "Jamais - Manuel uniquement",
|
||||
"neverManualOnly": "Jamais — Manuel uniquement",
|
||||
"appearance": "Apparence",
|
||||
"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",
|
||||
"sourceSpecific": "Spécifique à la source",
|
||||
"appSource": "Source de l'application",
|
||||
@@ -134,13 +135,13 @@
|
||||
"close": "Fermer",
|
||||
"share": "Partager",
|
||||
"appNotFound": "Application introuvable",
|
||||
"obtainiumExportHyphenatedLowercase": "exportation d'Obtainium",
|
||||
"obtainiumExportHyphenatedLowercase": "Exportation-Obtainium",
|
||||
"pickAnAPK": "Choisissez un APK",
|
||||
"appHasMoreThanOnePackage": "{} a plus d'un paquet :",
|
||||
"deviceSupportsXArch": "Votre appareil prend en charge l'architecture CPU {}.",
|
||||
"deviceSupportsFollowingArchs": "Votre appareil prend en charge les architectures CPU suivantes :",
|
||||
"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",
|
||||
"updatesAvailableNotifDescription": "Avertit l'utilisateur que des mises à jour sont disponibles pour une ou plusieurs applications suivies par Obtainium",
|
||||
"noNewUpdates": "Aucune nouvelle mise à jour.",
|
||||
@@ -167,7 +168,7 @@
|
||||
"unknown": "Inconnu",
|
||||
"none": "Aucun",
|
||||
"never": "Jamais",
|
||||
"latestVersionX": "Dernière version: {}",
|
||||
"latestVersionX": "Dernière version : {}",
|
||||
"installedVersionX": "Version installée : {}",
|
||||
"lastUpdateCheckX": "Vérification de la dernière mise à jour : {}",
|
||||
"remove": "Retirer",
|
||||
@@ -178,15 +179,15 @@
|
||||
"appWithIdOrNameNotFound": "Aucune application n'a été trouvée avec cet identifiant ou ce nom",
|
||||
"reposHaveMultipleApps": "Les dépôts peuvent contenir plusieurs applications",
|
||||
"fdroidThirdPartyRepo": "Dépôt tiers F-Droid",
|
||||
"steamMobile": "Vapeur Mobile",
|
||||
"steamChat": "Chat sur Steam",
|
||||
"steamMobile": "Application mobile Steam",
|
||||
"steamChat": "Steam Chat",
|
||||
"install": "Installer",
|
||||
"markInstalled": "Marquer installée",
|
||||
"markInstalled": "Marquer comme installée",
|
||||
"update": "Mettre à jour",
|
||||
"markUpdated": "Marquer à jour",
|
||||
"markUpdated": "Marquer comme étant à jour",
|
||||
"additionalOptions": "Options additionnelles",
|
||||
"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 {}",
|
||||
"downloadX": "Télécharger {}",
|
||||
"downloadedX": "Téléchargé {}",
|
||||
@@ -198,9 +199,9 @@
|
||||
"categories": "Catégories",
|
||||
"category": "Catégorie",
|
||||
"noCategory": "Aucune catégorie",
|
||||
"noCategories": "Aucune catégorie",
|
||||
"deleteCategoriesQuestion": "Supprimer les catégories ?",
|
||||
"categoryDeleteWarning": "Toutes les applications dans les catégories supprimées seront définies sur non catégorisées.",
|
||||
"noCategories": "Aucune catégories",
|
||||
"deleteCategoriesQuestion": "Supprimer les catégories ?",
|
||||
"categoryDeleteWarning": "Toutes les applications dans les catégories supprimées ne seront plus catégorisées.",
|
||||
"addCategory": "Ajouter une catégorie",
|
||||
"label": "Étiquette",
|
||||
"language": "Langue",
|
||||
@@ -220,18 +221,18 @@
|
||||
"versionDetection": "Détection des versions",
|
||||
"standardVersionDetection": "Détection de version standard",
|
||||
"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",
|
||||
"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",
|
||||
"moveNonInstalledAppsToBottom": "Déplacer les applications non installées vers le bas de la vue Applications",
|
||||
"gitlabPATLabel": "Jeton d'accès personnel GitLab",
|
||||
"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",
|
||||
"tryInferAppIdFromCode": "Essayez de déduire l'ID de l'application à partir du code source",
|
||||
"removeOnExternalUninstall": "Supprimer automatiquement les applications désinstallées en externe",
|
||||
"tryInferAppIdFromCode": "Essayer de déduire l'ID de l'application à partir du code source",
|
||||
"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",
|
||||
"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",
|
||||
@@ -245,18 +246,18 @@
|
||||
"customLinkFilterRegex": "Filtre du lien APK personnalisé par expression régulière (par défaut '.apk$')",
|
||||
"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",
|
||||
"xWasPossiblyUpdatedToY": "{} a peut-être été mis à jour vers {}.",
|
||||
"xWasPossiblyUpdatedToY": "{} pourrait avoir été mis à jour vers {}.",
|
||||
"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.",
|
||||
"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 ",
|
||||
"filterByLinkText": "Filtrer les liens par le texte du lien",
|
||||
"intermediateLinkNotFound": "Lien intermédiaire introuvable",
|
||||
"intermediateLink": "Lien intermédiaire",
|
||||
"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",
|
||||
"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",
|
||||
"matchGroupToUse": "Groupe de correspondance pour l'expression régulière d'extraction de version",
|
||||
"highlightTouchTargets": "Mettre en évidence les cibles tactiles moins évidentes",
|
||||
@@ -264,13 +265,13 @@
|
||||
"autoExportOnChanges": "Exporter automatiquement après modification",
|
||||
"includeSettings": "Inclure les paramètres",
|
||||
"filterVersionsByRegEx": "Filtrer les versions par expression régulière",
|
||||
"trySelectingSuggestedVersionCode": "Essayez de sélectionner le code de la version APK suggérée",
|
||||
"dontSortReleasesList": "Conserver l'ordre des version de l'API",
|
||||
"trySelectingSuggestedVersionCode": "Essayer de sélectionner le code de la version suggérée de l'APK",
|
||||
"dontSortReleasesList": "Conserver l'ordre des versions de l'API",
|
||||
"reverseSort": "Tri inversé",
|
||||
"takeFirstLink": "Prendre le premier lien",
|
||||
"skipSort": "Sauter le tri",
|
||||
"skipSort": "Éviter le tri",
|
||||
"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",
|
||||
"versionExtractWholePage": "Appliquer l'expression régulière d'extraction de version sur l'ensemble de la page",
|
||||
"installing": "Installation",
|
||||
@@ -283,14 +284,14 @@
|
||||
"downloadingXNotifChannel": "Téléchargement {}",
|
||||
"completeAppInstallationNotifChannel": "Installation complète de l'application",
|
||||
"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",
|
||||
"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",
|
||||
"shizukuBinderNotFound": "Service Shizuku compatible non trouvé",
|
||||
"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",
|
||||
"shizukuOld": "Ancienne version de Shizuku (<11) — la mettre à jour",
|
||||
"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é)",
|
||||
"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",
|
||||
@@ -309,21 +310,23 @@
|
||||
"badDownload": "L'APK n'a pas pu être analysé (téléchargement incompatible ou partiel)",
|
||||
"beforeNewInstallsShareToAppVerifier": "Partager les nouvelles applications avec AppVerifier (si disponible)",
|
||||
"appVerifierInstructionToast": "Partagez avec AppVerifier, puis revenez ici lorsque vous êtes prêt.",
|
||||
"wiki": "Aide/Wiki",
|
||||
"crowdsourcedConfigsLabel": "Configurations d'applications participative (utilisation à vos risques et périls)",
|
||||
"removeAppQuestion": {
|
||||
"one": "Supprimer l'application ?",
|
||||
"other": "Supprimer les applications ?"
|
||||
"one": "Supprimer l'application ?",
|
||||
"other": "Supprimer les applications ?"
|
||||
},
|
||||
"tooManyRequestsTryAgainInMinutes": {
|
||||
"one": "Trop de demandes (taux limité) - réessayez dans {} minute",
|
||||
"other": "Trop de demandes (taux limité) - réessayez dans {} minutes"
|
||||
"one": "Trop de demandes (taux limité) — réessayez dans {} minute",
|
||||
"other": "Trop de demandes (taux limité) — réessayez dans {} minutes"
|
||||
},
|
||||
"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",
|
||||
"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": {
|
||||
"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"
|
||||
"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ée {} mises à jour — l'utilisateur sera notifié si nécessaire"
|
||||
},
|
||||
"apps": {
|
||||
"one": "{} Application",
|
||||
@@ -362,8 +365,8 @@
|
||||
"other": "Échec de la mise à jour de {} et {} autres applications."
|
||||
},
|
||||
"xAndNMoreUpdatesPossiblyInstalled": {
|
||||
"une": "{} et 1 application supplémentaire ont peut-être été mises à jour.",
|
||||
"other": "{} et {} autres applications peuvent avoir été mises à jour."
|
||||
"une": "{} et 1 application supplémentaire pourraient avoir été mises à jour.",
|
||||
"other": "{} et {} autres applications pourraient avoir été mises à jour."
|
||||
},
|
||||
"apk": {
|
||||
"one": "{} APK",
|
||||
|
@@ -113,6 +113,7 @@
|
||||
"dark": "Sötét",
|
||||
"light": "Világos",
|
||||
"followSystem": "Rendszer szerint",
|
||||
"followSystemThemeExplanation": "A következő rendszer téma csak harmadik féltől származó alkalmazások használatával lehetséges",
|
||||
"useBlackTheme": "Használjon teljesen fekete sötét témát",
|
||||
"appSortBy": "App rendezés...",
|
||||
"authorName": "Szerző/Név",
|
||||
@@ -309,6 +310,8 @@
|
||||
"badDownload": "Az APK-t nem lehetett elemezni (inkompatibilis vagy részleges letöltés)",
|
||||
"beforeNewInstallsShareToAppVerifier": "Új alkalmazások megosztása az AppVerifierrel (ha elérhető)",
|
||||
"appVerifierInstructionToast": "Ossza meg az AppVerifierrel, majd térjen vissza ide, ha kész.",
|
||||
"wiki": "Súgó/Wiki",
|
||||
"crowdsourcedConfigsLabel": "Crowdsourced App Configurations (használat saját felelősségre)",
|
||||
"removeAppQuestion": {
|
||||
"one": "Eltávolítja az alkalmazást?",
|
||||
"other": "Eltávolítja az alkalmazásokat?"
|
||||
|
@@ -113,6 +113,7 @@
|
||||
"dark": "Scuro",
|
||||
"light": "Chiaro",
|
||||
"followSystem": "Segui il sistema",
|
||||
"followSystemThemeExplanation": "È possibile seguire il tema di sistema solo utilizzando applicazioni di terze parti.",
|
||||
"useBlackTheme": "Usa il tema nero puro",
|
||||
"appSortBy": "App ordinate per",
|
||||
"authorName": "Autore/Nome",
|
||||
@@ -309,6 +310,8 @@
|
||||
"badDownload": "Non è stato possibile analizzare l'APK (download incompatibile o parziale).",
|
||||
"beforeNewInstallsShareToAppVerifier": "Condividere le nuove applicazioni con AppVerifier (se disponibile)",
|
||||
"appVerifierInstructionToast": "Condividete con AppVerifier, quindi tornate qui quando siete pronti.",
|
||||
"wiki": "Aiuto/Wiki",
|
||||
"crowdsourcedConfigsLabel": "Configurazioni di app in crowdsourcing (uso a proprio rischio)",
|
||||
"removeAppQuestion": {
|
||||
"one": "Rimuovere l'app?",
|
||||
"other": "Rimuovere le app?"
|
||||
|
@@ -24,7 +24,7 @@
|
||||
"colour": "カラー",
|
||||
"standard": "スタンダード",
|
||||
"custom": "カスタム",
|
||||
"useMaterialYou": "使用素材",
|
||||
"useMaterialYou": "Material Youを使用する",
|
||||
"githubStarredRepos": "Githubでスターしたリポジトリ",
|
||||
"uname": "ユーザー名",
|
||||
"wrongArgNum": "提供する引数の数が間違っています",
|
||||
@@ -113,6 +113,7 @@
|
||||
"dark": "ダーク",
|
||||
"light": "ライト",
|
||||
"followSystem": "システムに従う",
|
||||
"followSystemThemeExplanation": "以下のシステムテーマは、サードパーティのアプリケーションを使用することによってのみ可能です。",
|
||||
"useBlackTheme": "ピュアブラックダークテーマを使用する",
|
||||
"appSortBy": "アプリの並び方",
|
||||
"authorName": "作者名/アプリ名",
|
||||
@@ -287,11 +288,11 @@
|
||||
"supportFixedAPKURL": "固定されたAPKのURLをサポートする",
|
||||
"selectX": "{} 選択",
|
||||
"parallelDownloads": "並行ダウンロードを許可する",
|
||||
"useShizuku": "シズクまたはスイを使って設置する",
|
||||
"useShizuku": "ShizukuまたはSuiを使用してインストールする",
|
||||
"shizukuBinderNotFound": "Shizukuが起動していません",
|
||||
"shizukuOld": "古い雫バージョン (<11) - アップデートしてください。",
|
||||
"shizukuOldAndroidWithADB": "雫、Android < 8.1でADB動作 - Androidをアップデートするか、代わりにSuiを使うか",
|
||||
"shizukuPretendToBeGooglePlay": "インストール元をGoogle Playに設定する(雫を使用する場合)",
|
||||
"shizukuOld": "古いShizukuのバージョン (<11) - アップデートしてください",
|
||||
"shizukuOldAndroidWithADB": "ShizukuがAndroid 8.1未満でADBを使用して動作しています - Androidをアップデートするか、代わりにSuiを使用してください",
|
||||
"shizukuPretendToBeGooglePlay": "Google Playをインストール元として設定する(Shizukuを使用する場合)",
|
||||
"useSystemFont": "システムフォントを使用する",
|
||||
"useVersionCodeAsOSVersion": "アプリのバージョンコードをOSで検出されたバージョンとして使用する",
|
||||
"requestHeader": "リクエストヘッダー",
|
||||
@@ -309,6 +310,8 @@
|
||||
"badDownload": "APK を解析できませんでした(互換性がないか、部分的にダウンロードされています)。",
|
||||
"beforeNewInstallsShareToAppVerifier": "AppVerifierで新しいアプリを共有する(利用可能な場合)",
|
||||
"appVerifierInstructionToast": "AppVerifierに共有し、準備ができたらここに戻ってください。",
|
||||
"wiki": "ヘルプ/ウィキ",
|
||||
"crowdsourcedConfigsLabel": "クラウドソーシングによるアプリの設定(利用は自己責任で)",
|
||||
"removeAppQuestion": {
|
||||
"one": "アプリを削除しますか?",
|
||||
"other": "アプリを削除しますか?"
|
||||
|
@@ -1,134 +1,135 @@
|
||||
{
|
||||
"invalidURLForSource": "Geen valide {} app URL",
|
||||
"noReleaseFound": "Kan geen geschikte release vinden",
|
||||
"noVersionFound": "Kan de versie niet bepalen",
|
||||
"invalidURLForSource": "Ongeldige app-URL voor {}",
|
||||
"noReleaseFound": "Geen geschikte release gevonden",
|
||||
"noVersionFound": "Geen versie kunnen bepalen",
|
||||
"urlMatchesNoSource": "URL komt niet overeen met bekende bron",
|
||||
"cantInstallOlderVersion": "Kan geen oudere versie van de app installeren",
|
||||
"appIdMismatch": "Gedownloade pakket-ID komt niet overeen met de bestaande app-ID",
|
||||
"functionNotImplemented": "Deze class heeft deze functie niet geïmplementeerd.",
|
||||
"placeholder": "Plaatshouder",
|
||||
"appIdMismatch": "Gedownload pakket-ID komt niet overeen met de bestaande app-ID",
|
||||
"functionNotImplemented": "Deze klasse heeft deze functie niet geïmplementeerd.",
|
||||
"placeholder": "Dummy",
|
||||
"someErrors": "Er zijn enkele fouten opgetreden",
|
||||
"unexpectedError": "Onverwachte fout",
|
||||
"ok": "Ok",
|
||||
"ok": "Oké",
|
||||
"and": "en",
|
||||
"githubPATLabel": "GitHub Personal Access Token\n(Verhoogt limiet aantal verzoeken)",
|
||||
"includePrereleases": "Bevat prereleases",
|
||||
"includePrereleases": "Inclusief pre-releases",
|
||||
"fallbackToOlderReleases": "Terugvallen op oudere releases",
|
||||
"filterReleaseTitlesByRegEx": "Filter release-titels met reguliere expressies.",
|
||||
"filterReleaseTitlesByRegEx": "Release-titels filteren met reguliere expressies.",
|
||||
"invalidRegEx": "Ongeldige reguliere expressie",
|
||||
"noDescription": "Geen omschrijving",
|
||||
"cancel": "Annuleer",
|
||||
"continue": "Ga verder",
|
||||
"cancel": "Annuleren",
|
||||
"continue": "Doorgaan",
|
||||
"requiredInBrackets": "(Verplicht)",
|
||||
"dropdownNoOptsError": "FOUTMELDING: DROPDOWN MOET TENMINSTE ÉÉN OPT HEBBEN",
|
||||
"dropdownNoOptsError": "FOUTMELDING: UITKLAPMENU MOET TENMINSTE EEN OPT HEBBEN",
|
||||
"colour": "Kleur",
|
||||
"standard": "Standaard",
|
||||
"custom": "Aangepast",
|
||||
"useMaterialYou": "Gebruik materiaal",
|
||||
"useMaterialYou": "Material You gebruiken",
|
||||
"githubStarredRepos": "GitHub-repo's met ster",
|
||||
"uname": "Gebruikersnaam",
|
||||
"wrongArgNum": "Onjuist aantal argumenten verstrekt.",
|
||||
"xIsTrackOnly": "{} is alleen tracken",
|
||||
"wrongArgNum": "Incorrect aantal argumenten.",
|
||||
"xIsTrackOnly": "{} is 'Alleen volgen'",
|
||||
"source": "Bron",
|
||||
"app": "App",
|
||||
"appsFromSourceAreTrackOnly": "Apps van deze bron zijn 'Track-Only'.",
|
||||
"youPickedTrackOnly": "Je hebt de 'Track-Only' optie geselecteerd.",
|
||||
"appsFromSourceAreTrackOnly": "Apps van deze bron zijn 'Alleen volgen'.",
|
||||
"youPickedTrackOnly": "De optie 'Alleen volgen' is geselecteerd.",
|
||||
"trackOnlyAppDescription": "De app zal worden gevolgd voor updates, maar Obtainium zal niet in staat zijn om deze te downloaden of te installeren.",
|
||||
"cancelled": "Geannuleerd",
|
||||
"appAlreadyAdded": "App al toegevoegd",
|
||||
"alreadyUpToDateQuestion": "Is de app al up-to-date?",
|
||||
"appAlreadyAdded": "App reeds toegevoegd",
|
||||
"alreadyUpToDateQuestion": "App al bijgewerkt?",
|
||||
"addApp": "App toevoegen",
|
||||
"appSourceURL": "App bron URL",
|
||||
"appSourceURL": "App-bron URL",
|
||||
"error": "Foutmelding",
|
||||
"add": "Toevoegen",
|
||||
"searchSomeSourcesLabel": "Zoeken (Alleen sommige bronnen)",
|
||||
"searchSomeSourcesLabel": "Zoeken (sommige bronnen)",
|
||||
"search": "Zoeken",
|
||||
"additionalOptsFor": "Aanvullende opties voor {}",
|
||||
"supportedSources": "Ondersteunde bronnen",
|
||||
"trackOnlyInBrackets": "(Alleen track)",
|
||||
"trackOnlyInBrackets": "(Alleen volgen)",
|
||||
"searchableInBrackets": "(Doorzoekbaar)",
|
||||
"appsString": "Apps",
|
||||
"noApps": "Geen Apps",
|
||||
"noAppsForFilter": "Geen Apps voor filter",
|
||||
"byX": "Door {}",
|
||||
"percentProgress": "Vooruitgang: {}%",
|
||||
"percentProgress": "Voortgang: {}%",
|
||||
"pleaseWait": "Even geduld",
|
||||
"updateAvailable": "Update beschikbaar",
|
||||
"notInstalled": "Niet geinstalleerd",
|
||||
"pseudoVersion": "pseudo-versie",
|
||||
"selectAll": "Selecteer alles",
|
||||
"deselectX": "Deselecteer {}",
|
||||
"xWillBeRemovedButRemainInstalled": "{} zal worden verwijderd uit Obtainium, maar blijft geïnstalleerd op het apparaat.",
|
||||
"removeSelectedAppsQuestion": "Geselecteerde apps verwijderen??",
|
||||
"selectAll": "Alles selecteren",
|
||||
"deselectX": "Selectie opheffen {}",
|
||||
"xWillBeRemovedButRemainInstalled": "{} zal worden gewist uit Obtainium, maar blijft geïnstalleerd op het apparaat.",
|
||||
"removeSelectedAppsQuestion": "Geselecteerde apps verwijderen?",
|
||||
"removeSelectedApps": "Geselecteerde apps verwijderen",
|
||||
"updateX": "Update {}",
|
||||
"installX": "Installeer {}",
|
||||
"markXTrackOnlyAsUpdated": "Markeer {}\n(Track-Only)\nals up-to-date",
|
||||
"changeX": "Verander {}",
|
||||
"installUpdateApps": "Installeer/Update apps",
|
||||
"installUpdateSelectedApps": "Installeer/Update geselecteerde apps",
|
||||
"markXSelectedAppsAsUpdated": "{} geselecteerde apps markeren als up-to-date?",
|
||||
"updateX": "{} bijwerken",
|
||||
"installX": "{} installeren",
|
||||
"markXTrackOnlyAsUpdated": "{}\n(Alleen volgen)\nmarkeren als bijgewerkt",
|
||||
"changeX": "{} wijzigen",
|
||||
"installUpdateApps": "Apps installeren/bijwerken",
|
||||
"installUpdateSelectedApps": "Geselecteerde apps installeren/bijwerken",
|
||||
"markXSelectedAppsAsUpdated": "{} geselecteerde apps markeren als bijgewerkt?",
|
||||
"no": "Nee",
|
||||
"yes": "Ja",
|
||||
"markSelectedAppsUpdated": "Markeer geselecteerde aps als up-to-date",
|
||||
"pinToTop": "Vastzetten aan de bovenkant",
|
||||
"unpinFromTop": "Losmaken van de bovenkant",
|
||||
"resetInstallStatusForSelectedAppsQuestion": "Installatiestatus resetten voor geselecteerde apps?",
|
||||
"installStatusOfXWillBeResetExplanation": "De installatiestatus van alle geselecteerde apps zal worden gereset.\n\nDit kan helpen wanneer de versie van de app die in Obtainium wordt weergegeven onjuist is vanwege mislukte updates of andere problemen.",
|
||||
"customLinkMessage": "Deze links werken op apparaten waarop Obtainium is geïnstalleerd",
|
||||
"markSelectedAppsUpdated": "Geselecteerde apps markeren als bijgewerkt",
|
||||
"pinToTop": "Bovenaan plaatsen",
|
||||
"unpinFromTop": "Bovenaan wegnemen",
|
||||
"resetInstallStatusForSelectedAppsQuestion": "Installatiestatus herstellen voor geselecteerde apps?",
|
||||
"installStatusOfXWillBeResetExplanation": "De installatiestatus van alle geselecteerde apps zal worden hersteld.\n\nDit kan helpen wanneer de versie van de app die in Obtainium wordt weergegeven onjuist is vanwege mislukte updates of andere problemen.",
|
||||
"customLinkMessage": "Deze koppelingen werken op apparaten waarop Obtainium is geïnstalleerd",
|
||||
"shareAppConfigLinks": "App-configuratie delen als HTML-link",
|
||||
"shareSelectedAppURLs": "Deel geselecteerde app URL's",
|
||||
"resetInstallStatus": "Reset installatiestatus",
|
||||
"shareSelectedAppURLs": "Geselecteerde app-URL's delen",
|
||||
"resetInstallStatus": "Installatiestatus herstellen",
|
||||
"more": "Meer",
|
||||
"removeOutdatedFilter": "Verwijder out-of-date app filter",
|
||||
"showOutdatedOnly": "Toon alleen out-of-date apps",
|
||||
"filter": "Filter",
|
||||
"filterApps": "Filter apps",
|
||||
"appName": "App naam",
|
||||
"removeOutdatedFilter": "Verouderde apps-filter verwijderen",
|
||||
"showOutdatedOnly": "Alleen verouderde apps weergeven",
|
||||
"filter": "Filteren",
|
||||
"filterApps": "Apps filteren",
|
||||
"appName": "App-naam",
|
||||
"author": "Auteur",
|
||||
"upToDateApps": "Up-to-date apps",
|
||||
"upToDateApps": "Bijgewerkte apps",
|
||||
"nonInstalledApps": "Niet-geïnstalleerde apps",
|
||||
"importExport": "Importeren/Exporteren",
|
||||
"importExport": "Importeren/exporteren",
|
||||
"settings": "Instellingen",
|
||||
"exportedTo": "Geëxporteerd naar {}",
|
||||
"obtainiumExport": "Obtainium export",
|
||||
"invalidInput": "Ongeldige invoer",
|
||||
"importedX": "Geïmporteerd {}",
|
||||
"importedX": "{} geïmporteerd",
|
||||
"obtainiumImport": "Obtainium import",
|
||||
"importFromURLList": "Importeer van URL-lijsten",
|
||||
"importFromURLList": "Importeren van URL-lijsten",
|
||||
"searchQuery": "Zoekopdracht",
|
||||
"appURLList": "App URL-lijst",
|
||||
"line": "Lijn",
|
||||
"searchX": "Zoek {}",
|
||||
"line": "Regel",
|
||||
"searchX": "{} zoeken",
|
||||
"noResults": "Geen resultaten gevonden",
|
||||
"importX": "Importeer {}",
|
||||
"importedAppsIdDisclaimer": "Geïmporteerde apps kunnen mogelijk onjuist worden weergegeven als \"Niet geïnstalleerd\".\nOm dit op te lossen, herinstalleer ze via Obtainium.\nDit zou geen invloed moeten hebben op app-gegevens.\n\nDit heeft alleen invloed op URL- en importmethoden van derden.",
|
||||
"importErrors": "Import foutmeldingen",
|
||||
"importX": "{} importeren",
|
||||
"importedAppsIdDisclaimer": "Geïmporteerde apps kunnen mogelijk onjuist worden weergegeven als \"Niet geïnstalleerd\".\nOm dit op te lossen, installeer deze opnieuw via Obtainium.\nDit zou geen invloed moeten hebben op app-gegevens.\n\nDit heeft alleen invloed op URL- en importmethoden van derden.",
|
||||
"importErrors": "Fouten bij het importeren",
|
||||
"importedXOfYApps": "{} van {} apps geïmporteerd.",
|
||||
"followingURLsHadErrors": "De volgende URL's bevatten fouten:",
|
||||
"selectURL": "Selecteer URL",
|
||||
"selectURLs": "Selecteer URL's",
|
||||
"pick": "Kies",
|
||||
"selectURL": "URL selecteren",
|
||||
"selectURLs": "URL's selecteren",
|
||||
"pick": "Kiezen",
|
||||
"theme": "Thema",
|
||||
"dark": "Donker",
|
||||
"light": "Licht",
|
||||
"followSystem": "Volg systeem",
|
||||
"useBlackTheme": "Gebruik zwart thema",
|
||||
"appSortBy": "App sorteren op",
|
||||
"followSystem": "Systeem volgen",
|
||||
"followSystemThemeExplanation": "Het volgen van het systeemthema is alleen mogelijk met applicaties van derden",
|
||||
"useBlackTheme": "Zwart thema gebruiken",
|
||||
"appSortBy": "Sortering",
|
||||
"authorName": "Auteur/Naam",
|
||||
"nameAuthor": "Naam/Auteur",
|
||||
"asAdded": "Zoals toegevoegd",
|
||||
"appSortOrder": "App sorteervolgorde",
|
||||
"asAdded": "Datum toegevoegd",
|
||||
"appSortOrder": "Volgorde",
|
||||
"ascending": "Oplopend",
|
||||
"descending": "Aflopend",
|
||||
"bgUpdateCheckInterval": "Frequentie voor achtergrondupdatecontrole",
|
||||
"bgUpdateCheckInterval": "Frequentie voor achtergrond-updatecontrole",
|
||||
"neverManualOnly": "Nooit - Alleen handmatig",
|
||||
"appearance": "Weergave",
|
||||
"showWebInAppView": "Toon de bronwebpagina in app-weergave",
|
||||
"pinUpdates": "Updates bovenaan in de apps-weergave vastpinnen",
|
||||
"showWebInAppView": "Bron-webpagina weergeven in app-weergave",
|
||||
"pinUpdates": "Updates bovenaan plaatsen in de apps-weergave",
|
||||
"updates": "Updates",
|
||||
"sourceSpecific": "Bron-specifiek",
|
||||
"appSource": "App bron",
|
||||
"appSource": "App-bron",
|
||||
"noLogs": "Geen logs",
|
||||
"appLogs": "App logs",
|
||||
"close": "Sluiten",
|
||||
@@ -136,13 +137,13 @@
|
||||
"appNotFound": "App niet gevonden",
|
||||
"obtainiumExportHyphenatedLowercase": "obtainium-export",
|
||||
"pickAnAPK": "Kies een APK",
|
||||
"appHasMoreThanOnePackage": "{} heeft meer dan één package:",
|
||||
"deviceSupportsXArch": "Jouw apparaat support de {} CPU-architectuur.",
|
||||
"deviceSupportsFollowingArchs": "Je apparaat ondersteunt de volgende CPU-architecturen:",
|
||||
"appHasMoreThanOnePackage": "{} biedt verschillende pakketten:",
|
||||
"deviceSupportsXArch": "Dit apparaat ondersteunt de {} CPU-architectuur.",
|
||||
"deviceSupportsFollowingArchs": "Dit apparaat ondersteunt de volgende CPU-architecturen:",
|
||||
"warning": "Waarschuwing",
|
||||
"sourceIsXButPackageFromYPrompt": "De appbron is '{}' maar de release package komt van '{}'. Doorgaan?",
|
||||
"sourceIsXButPackageFromYPrompt": "De app-bron is '{}' maar het release-pakket komt van '{}'. Doorgaan?",
|
||||
"updatesAvailable": "Updates beschikbaar",
|
||||
"updatesAvailableNotifDescription": "Stelt de gebruiker op de hoogte dat er updates beschikbaar zijn voor één of meer apps die worden bijgehouden door Obtainium.",
|
||||
"updatesAvailableNotifDescription": "Stelt de gebruiker op de hoogte dat er updates beschikbaar zijn voor een of meer apps die worden bijgehouden door Obtainium.",
|
||||
"noNewUpdates": "Geen nieuwe updates.",
|
||||
"xHasAnUpdate": "{} heeft een update.",
|
||||
"appsUpdated": "Apps bijgewerkt",
|
||||
@@ -151,17 +152,17 @@
|
||||
"xWasUpdatedToY": "{} is bijgewerkt naar {}.",
|
||||
"xWasNotUpdatedToY": "Het bijwerken van {} naar {} is mislukt.",
|
||||
"errorCheckingUpdates": "Fout bij het controleren op updates",
|
||||
"errorCheckingUpdatesNotifDescription": "Een melding die verschijnt wanneer het controleren op updates in de achtergrond mislukt",
|
||||
"errorCheckingUpdatesNotifDescription": "Een melding die verschijnt wanneer de achtergrondcontrole op updates mislukt",
|
||||
"appsRemoved": "Apps verwijderd",
|
||||
"appsRemovedNotifDescription": "Stelt de gebruiker op de hoogte dat één of meer apps zijn verwijderd vanwege fouten tijdens het laden ervan",
|
||||
"xWasRemovedDueToErrorY": "{} is verwijderd vanwege deze foutmelding: {}",
|
||||
"completeAppInstallation": "Complete app installatie",
|
||||
"appsRemovedNotifDescription": "Stelt de gebruiker op de hoogte dat een of meer apps zijn verwijderd vanwege fouten tijdens het laden",
|
||||
"xWasRemovedDueToErrorY": "{} is verwijderd vanwege de fout: {}",
|
||||
"completeAppInstallation": "App-installatie voltooien",
|
||||
"obtainiumMustBeOpenToInstallApps": "Obtainium moet geopend zijn om apps te installeren",
|
||||
"completeAppInstallationNotifDescription": "Vraagt de gebruiker om terug te keren naar Obtainium om de installatie van een app af te ronden",
|
||||
"checkingForUpdates": "Controleren op updates",
|
||||
"checkingForUpdatesNotifDescription": "Tijdelijke melding die verschijnt tijdens het controleren op updates",
|
||||
"pleaseAllowInstallPerm": "Sta Obtainium toe om apps te installeren",
|
||||
"trackOnly": "Alleen track",
|
||||
"pleaseAllowInstallPerm": "Toestaan dat Obtainium apps installeert",
|
||||
"trackOnly": "'Alleen volgen'",
|
||||
"errorWithHttpStatusCode": "Foutmelding {}",
|
||||
"versionCorrectionDisabled": "Versiecorrectie uitgeschakeld (de plug-in lijkt niet te werken)",
|
||||
"unknown": "Onbekend",
|
||||
@@ -171,25 +172,25 @@
|
||||
"installedVersionX": "Geïnstalleerde versie: {}",
|
||||
"lastUpdateCheckX": "Laatste updatecontrole: {}",
|
||||
"remove": "Verwijderen",
|
||||
"yesMarkUpdated": "Ja, markeer als bijgewerkt",
|
||||
"fdroid": "F-Droid-ambtenaar",
|
||||
"appIdOrName": "App ID of naam",
|
||||
"yesMarkUpdated": "Ja, markeren als bijgewerkt",
|
||||
"fdroid": "F-Droid (Officieel)",
|
||||
"appIdOrName": "App-ID of naam",
|
||||
"appId": "App-ID",
|
||||
"appWithIdOrNameNotFound": "Er werd geen app gevonden met dat ID of die naam",
|
||||
"appWithIdOrNameNotFound": "Er is geen app gevonden met dat ID of die naam",
|
||||
"reposHaveMultipleApps": "Repositories kunnen meerdere apps bevatten",
|
||||
"fdroidThirdPartyRepo": "F-Droid Repository van derden",
|
||||
"steamMobile": "Stoommobiel",
|
||||
"steamChat": "Steamchat",
|
||||
"fdroidThirdPartyRepo": "F-Droid Repository voor derden",
|
||||
"steamMobile": "Steam Mobile",
|
||||
"steamChat": "Steam Chat",
|
||||
"install": "Installeren",
|
||||
"markInstalled": "Als geïnstalleerd markere",
|
||||
"update": "Update",
|
||||
"markUpdated": "Markeren als bijgewerkt",
|
||||
"markInstalled": "Als geïnstalleerd markeren",
|
||||
"update": "Bijwerken",
|
||||
"markUpdated": "Als bijgewerkt markeren",
|
||||
"additionalOptions": "Aanvullende opties",
|
||||
"disableVersionDetection": "Versieherkenning uitschakelen",
|
||||
"noVersionDetectionExplanation": "Deze optie moet alleen worden gebruikt voor apps waar versieherkenning niet correct werkt.",
|
||||
"downloadingX": "Downloaden {}",
|
||||
"downloadingX": "{} downloaden",
|
||||
"downloadX": "Downloaden",
|
||||
"downloadedX": "Gedownload {}",
|
||||
"downloadedX": "{} gedownload",
|
||||
"releaseAsset": "Release Activa",
|
||||
"downloadNotifDescription": "Stelt de gebruiker op de hoogte van de voortgang bij het downloaden van een app",
|
||||
"noAPKFound": "Geen APK gevonden",
|
||||
@@ -202,100 +203,100 @@
|
||||
"deleteCategoriesQuestion": "Categorieën verwijderen?",
|
||||
"categoryDeleteWarning": "Alle apps in verwijderde categorieën worden teruggezet naar 'ongecategoriseerd'.",
|
||||
"addCategory": "Categorie toevoegen",
|
||||
"label": "Etiket",
|
||||
"label": "Label",
|
||||
"language": "Taal",
|
||||
"copiedToClipboard": "Gekopieerd naar klembord",
|
||||
"storagePermissionDenied": "Toegang tot opslag geweigerd",
|
||||
"selectedCategorizeWarning": "Dit zal eventuele bestaande categorie-instellingen voor de geselecteerde apps vervangen.",
|
||||
"filterAPKsByRegEx": "Filter APK's op reguliere expressie",
|
||||
"removeFromObtainium": "Verwijder van Obtainium",
|
||||
"uninstallFromDevice": "Verwijder van apparaat",
|
||||
"filterAPKsByRegEx": "APK's flteren met reguliere expressie",
|
||||
"removeFromObtainium": "Uit Obtainium verwijderen",
|
||||
"uninstallFromDevice": "Van apparaat verwijderen",
|
||||
"onlyWorksWithNonVersionDetectApps": "Werkt alleen voor apps waarbij versieherkenning is uitgeschakeld.",
|
||||
"releaseDateAsVersion": "Gebruik de releasedatum als versie",
|
||||
"releaseDateAsVersion": "Releasedatum als versie gebruiken",
|
||||
"releaseDateAsVersionExplanation": "Deze optie moet alleen worden gebruikt voor apps waar versieherkenning niet correct werkt, maar waar wel een releasedatum beschikbaar is.",
|
||||
"changes": "Veranderingen",
|
||||
"changes": "Aanpassingen",
|
||||
"releaseDate": "Releasedatum",
|
||||
"importFromURLsInFile": "Importeren vanaf URL's in een bestand (zoals OPML)",
|
||||
"versionDetectionExplanation": "Versiereeks afstemmen met versie gedetecteerd door besturingssysteem",
|
||||
"versionDetection": "Versieherkenning",
|
||||
"standardVersionDetection": "Standaard versieherkenning",
|
||||
"groupByCategory": "Groepeer op categorie",
|
||||
"autoApkFilterByArch": "Poging om APK's te filteren op CPU-architectuur indien mogelijk",
|
||||
"groupByCategory": "Groeperen op categorie",
|
||||
"autoApkFilterByArch": "Probeer APK's te filteren op CPU-architectuur, indien mogelijk",
|
||||
"overrideSource": "Bron overschrijven",
|
||||
"dontShowAgain": "Laat dit niet meer zien",
|
||||
"dontShowTrackOnlyWarnings": "Geen waarschuwingen voor 'Track-Only' weergeven",
|
||||
"dontShowAPKOriginWarnings": "APK-herkomstwaarschuwingen niet weergeven",
|
||||
"moveNonInstalledAppsToBottom": "Verplaats niet-geïnstalleerde apps naar de onderkant van de apps-weergave",
|
||||
"dontShowTrackOnlyWarnings": "Geen waarschuwingen weergeven voor 'Alleen volgen'",
|
||||
"dontShowAPKOriginWarnings": "Geen waarschuwingen weergeven voor APK-herkomst",
|
||||
"moveNonInstalledAppsToBottom": "Niet-geïnstalleerde apps onderaan de apps-lijst plaatsen",
|
||||
"gitlabPATLabel": "GitLab persoonlijk toegangskenmerk",
|
||||
"about": "Over",
|
||||
"requiresCredentialsInSettings": "{}: Dit vereist aanvullende referenties (in Instellingen)",
|
||||
"checkOnStart": "Controleren op updates bij opstarten",
|
||||
"requiresCredentialsInSettings": "{} vereist aanvullende referenties (in Instellingen)",
|
||||
"checkOnStart": "Bij opstarten op updates controleren",
|
||||
"tryInferAppIdFromCode": "Probeer de app-ID af te leiden uit de broncode",
|
||||
"removeOnExternalUninstall": "Automatisch extern verwijderde apps verwijderen",
|
||||
"pickHighestVersionCode": "Automatisch de APK met de hoogste versiecode selecteren",
|
||||
"removeOnExternalUninstall": "Extern verwijderde apps automatisch verwijderen",
|
||||
"pickHighestVersionCode": "De APK met de hoogste versiecode automatisch selecteren",
|
||||
"checkUpdateOnDetailPage": "Controleren op updates bij het openen van een app-detailpagina",
|
||||
"disablePageTransitions": "Schakel overgangsanimaties tussen pagina's uit",
|
||||
"reversePageTransitions": "Omgekeerde overgangsanimaties tussen pagina's",
|
||||
"minStarCount": "Minimale Github Stars",
|
||||
"addInfoBelow": "Voeg deze informatie hieronder toe.",
|
||||
"addInfoInSettings": "Voeg deze informatie toe in de instellingen.",
|
||||
"disablePageTransitions": "Overgangsanimaties tussen pagina's uitschakelen",
|
||||
"reversePageTransitions": "Overgangsanimaties tussen pagina's herstellen",
|
||||
"minStarCount": "Minimum Github Stars",
|
||||
"addInfoBelow": "Deze informatie hieronder toevoegen.",
|
||||
"addInfoInSettings": "Deze informatie toevoegen in de instellingen.",
|
||||
"githubSourceNote": "Beperkingen van GitHub kunnen worden vermeden door het gebruik van een API-sleutel.",
|
||||
"sortByLastLinkSegment": "Sorteren op alleen het laatste segment van de link",
|
||||
"filterReleaseNotesByRegEx": "Filter release-opmerkingen met een reguliere expressie.",
|
||||
"customLinkFilterRegex": "Aangepaste APK-linkfilter met een reguliere expressie (Standaard '.apk$').",
|
||||
"appsPossiblyUpdated": "Poging tot app-updates",
|
||||
"sortByLastLinkSegment": "Alleen sorteren op het laatste segment van de link",
|
||||
"filterReleaseNotesByRegEx": "Release-opmerkingen fiteren met een reguliere expressie.",
|
||||
"customLinkFilterRegex": "Aangepaste APK-links filteren met een reguliere expressie (Standaard '.apk$').",
|
||||
"appsPossiblyUpdated": "Pogingen tot app-updates",
|
||||
"appsPossiblyUpdatedNotifDescription": "Stelt de gebruiker op de hoogte dat updates voor één of meer apps mogelijk in de achtergrond zijn toegepast",
|
||||
"xWasPossiblyUpdatedToY": "{} mogelijk bijgewerkt naar {}.",
|
||||
"enableBackgroundUpdates": "Achtergrondupdates inschakelen",
|
||||
"backgroundUpdateReqsExplanation": "Achtergrondupdates zijn mogelijk niet voor alle apps mogelijk.",
|
||||
"xWasPossiblyUpdatedToY": "{} kan bijgewerkt zijn naar {}.",
|
||||
"enableBackgroundUpdates": "Achtergrond-updates inschakelen",
|
||||
"backgroundUpdateReqsExplanation": "Achtergrond-updates zijn niet voor alle apps mogelijk.",
|
||||
"backgroundUpdateLimitsExplanation": "Het succes van een installatie in de achtergrond kan alleen worden bepaald wanneer Obtainium is geopend.",
|
||||
"verifyLatestTag": "Verifieer de 'Laatste'-tag",
|
||||
"intermediateLinkRegex": "Filter voor een 'Intermediaire' link om te bezoeken",
|
||||
"verifyLatestTag": "Het label 'Laatste' verifiëren",
|
||||
"intermediateLinkRegex": "Filteren op een 'Intermediaire' link om te bezoeken",
|
||||
"filterByLinkText": "Links filteren op linktekst",
|
||||
"intermediateLinkNotFound": "Tussenliggende link niet gevonden",
|
||||
"intermediateLinkNotFound": "Intermediaire link niet gevonden",
|
||||
"intermediateLink": "Intermediaire link",
|
||||
"exemptFromBackgroundUpdates": "Vrijgesteld van achtergrondupdates (indien ingeschakeld)",
|
||||
"bgUpdatesOnWiFiOnly": "Achtergrondupdates uitschakelen wanneer niet verbonden met WiFi",
|
||||
"autoSelectHighestVersionCode": "Automatisch de APK met de hoogste versiecode selecteren",
|
||||
"exemptFromBackgroundUpdates": "Vrijgesteld van achtergrond-updates (indien ingeschakeld)",
|
||||
"bgUpdatesOnWiFiOnly": "Achtergrond-updates uitschakelen wanneer niet verbonden met WiFi",
|
||||
"autoSelectHighestVersionCode": "De APK met de hoogste versiecode automatisch selecteren",
|
||||
"versionExtractionRegEx": "Reguliere expressie voor versie-extractie",
|
||||
"matchGroupToUse": "Overeenkomende groep om te gebruiken voor de reguliere expressie voor versie-extractie",
|
||||
"highlightTouchTargets": "Markeer minder voor de hand liggende aanraakdoelen.",
|
||||
"highlightTouchTargets": "Minder voor de hand liggende aanraakdoelen markeren.",
|
||||
"pickExportDir": "Kies de exportmap",
|
||||
"autoExportOnChanges": "Automatisch exporteren bij wijzigingen",
|
||||
"autoExportOnChanges": "Bij wijzigingen automatisch exporteren",
|
||||
"includeSettings": "Instellingen opnemen",
|
||||
"filterVersionsByRegEx": "Filter versies met een reguliere expressie",
|
||||
"filterVersionsByRegEx": "Versies met een reguliere expressie filteren",
|
||||
"trySelectingSuggestedVersionCode": "Probeer de voorgestelde versiecode APK te selecteren",
|
||||
"dontSortReleasesList": "Volgorde van releases behouden vanuit de API",
|
||||
"reverseSort": "Sortering omkeren",
|
||||
"reverseSort": "Omgekeerde sortering",
|
||||
"takeFirstLink": "Neem de eerste link",
|
||||
"skipSort": "Sorteren overslaan",
|
||||
"debugMenu": "Debug menu",
|
||||
"skipSort": "Sortering overslaan",
|
||||
"debugMenu": "Debug-menu",
|
||||
"bgTaskStarted": "Achtergrondtaak gestart - controleer de logs.",
|
||||
"runBgCheckNow": "Voer nu een achtergrondupdatecontrole uit",
|
||||
"runBgCheckNow": "Nu een achtergrond-updatecontrole uitvoeren",
|
||||
"versionExtractWholePage": "De reguliere expressie voor versie-extractie toepassen op de hele pagina",
|
||||
"installing": "Installeren",
|
||||
"skipUpdateNotifications": "Updatemeldingen overslaan",
|
||||
"updatesAvailableNotifChannel": "Updates beschikbaar",
|
||||
"appsUpdatedNotifChannel": "Apps bijgewerkt",
|
||||
"appsPossiblyUpdatedNotifChannel": "Poging tot app-updates",
|
||||
"appsPossiblyUpdatedNotifChannel": "Pogingen tot app-updates",
|
||||
"errorCheckingUpdatesNotifChannel": "Foutcontrole bij het zoeken naar updates",
|
||||
"appsRemovedNotifChannel": "Apps verwijderd",
|
||||
"downloadingXNotifChannel": "{} downloaden",
|
||||
"completeAppInstallationNotifChannel": "Voltooien van de app-installatie",
|
||||
"completeAppInstallationNotifChannel": "App-installatie voltooien",
|
||||
"checkingForUpdatesNotifChannel": "Controleren op updates",
|
||||
"onlyCheckInstalledOrTrackOnlyApps": "Alleen geïnstalleerde en Track-Only apps controleren op updates",
|
||||
"supportFixedAPKURL": "Ondersteuning vaste APK URL's",
|
||||
"selectX": "Selecteer {}",
|
||||
"onlyCheckInstalledOrTrackOnlyApps": "Alleen geïnstalleerde apps en 'Alleen volgen' controleren op updates",
|
||||
"supportFixedAPKURL": "Vaste APK-URL's ondersteunen",
|
||||
"selectX": "{} selecteren",
|
||||
"parallelDownloads": "Parallelle downloads toestaan",
|
||||
"useShizuku": "Gebruik Shizuku of Sui om te installeren",
|
||||
"shizukuBinderNotFound": "Shizuku draait niet",
|
||||
"shizukuOld": "Oude Shizuku-versie (<11) - bijwerken",
|
||||
"shizukuOldAndroidWithADB": "Shizuku draait op Android < 8.1 met ADB - update Android of gebruik Sui in plaats daarvan",
|
||||
"shizukuPretendToBeGooglePlay": "Google Play instellen als installatiebron (als Shizuku wordt gebruikt)",
|
||||
"useSystemFont": "Gebruik het systeemlettertype",
|
||||
"useVersionCodeAsOSVersion": "Gebruik app versieCode als door OS gedetecteerde versie",
|
||||
"useShizuku": "Shizuku of Sui gebruiken om te installeren",
|
||||
"shizukuBinderNotFound": "Shizuku is niet actief",
|
||||
"shizukuOld": "Verouderde Shizuku-versie (<11) - bijwerken",
|
||||
"shizukuOldAndroidWithADB": "Shizuku draait op Android < 8.1 met ADB - update Android of gebruik in plaats daarvan Sui",
|
||||
"shizukuPretendToBeGooglePlay": "Google Play instellen als installatiebron (bij Shizuku)",
|
||||
"useSystemFont": "Systeemlettertype gebruiken",
|
||||
"useVersionCodeAsOSVersion": "App versiecode gebruiken als door OS gedetecteerde versie",
|
||||
"requestHeader": "Verzoekkoptekst",
|
||||
"useLatestAssetDateAsReleaseDate": "Gebruik laatste upload als releasedatum",
|
||||
"useLatestAssetDateAsReleaseDate": "Laatste upload als releasedatum gebruiken",
|
||||
"defaultPseudoVersioningMethod": "Standaard pseudo-versiebeheermethode",
|
||||
"partialAPKHash": "Gedeeltelijke APK-hash",
|
||||
"APKLinkHash": "APK-link-hash",
|
||||
@@ -308,22 +309,24 @@
|
||||
"selfHostedNote": "De \"{}\" dropdown kan gebruikt worden om zelf gehoste/aangepaste instanties van elke bron te bereiken.",
|
||||
"badDownload": "De APK kon niet worden verwerkt (incompatibele of gedeeltelijke download)",
|
||||
"beforeNewInstallsShareToAppVerifier": "Nieuwe Apps delen met AppVerifier (indien beschikbaar)",
|
||||
"appVerifierInstructionToast": "Deel naar AppVerifier en keer hier terug als je klaar bent.",
|
||||
"appVerifierInstructionToast": "Deel het met AppVerifier en keer daarna hier terug.",
|
||||
"wiki": "Help/Wiki",
|
||||
"crowdsourcedConfigsLabel": "Crowdsourced App-configuraties (gebruik op eigen risico)",
|
||||
"removeAppQuestion": {
|
||||
"one": "App verwijderen?",
|
||||
"other": "Apps verwijderen?"
|
||||
},
|
||||
"tooManyRequestsTryAgainInMinutes": {
|
||||
"one": "Te veel verzoeken (aantal beperkt) - probeer het opnieuw in {} minuut",
|
||||
"other": "Te veel verzoeken (aantal beperkt) - probeer het opnieuw in {} minuten"
|
||||
"one": "Te veel verzoeken (aantal beperkt) - opnieuw proberen over {} minuut",
|
||||
"other": "Te veel verzoeken (aantal beperkt) - opnieuw proberen over {} minuten"
|
||||
},
|
||||
"bgUpdateGotErrorRetryInMinutes": {
|
||||
"one": "Achtergrondupdatecontrole heeft een {}, zal een hercontrole plannen over {} minuut",
|
||||
"other": "Achtergrondupdatecontrole heeft een {}, zal een hercontrole plannen over {} minuten"
|
||||
"one": "Achtergrond-updatecontrole heeft een {}, zal een nieuwe controle plannen over {} minuut",
|
||||
"other": "Achtergrond-updatecontrole heeft een {}, zal een nieuwe controle plannen over {} minuten"
|
||||
},
|
||||
"bgCheckFoundUpdatesWillNotifyIfNeeded": {
|
||||
"one": "Achtergrondupdatecontrole heeft {} update gevonden - zal de gebruiker op de hoogte stellen indien nodig",
|
||||
"other": "Achtergrondupdatecontrole heeft {} updates gevonden - zal de gebruiker op de hoogte stellen indien nodig"
|
||||
"one": "Achtergrond-updatecontrole heeft {} update gevonden - zal de gebruiker op de hoogte stellen indien nodig",
|
||||
"other": "Achtergrond-updatecontrole heeft {} updates gevonden - zal de gebruiker op de hoogte stellen indien nodig"
|
||||
},
|
||||
"apps": {
|
||||
"one": "{} app",
|
||||
@@ -351,19 +354,19 @@
|
||||
},
|
||||
"xAndNMoreUpdatesAvailable": {
|
||||
"one": "{} en nog 1 app hebben updates.",
|
||||
"other": "{} en {} meer apps hebben updates."
|
||||
"other": "{} en nog {} apps hebben updates."
|
||||
},
|
||||
"xAndNMoreUpdatesInstalled": {
|
||||
"one": "{} en nog 1 app is bijgewerkt.",
|
||||
"other": "{} en {} meer apps zijn bijgewerkt."
|
||||
"other": "{} en nog {} apps zijn bijgewerkt."
|
||||
},
|
||||
"xAndNMoreUpdatesFailed": {
|
||||
"one": "Bijwerken mislukt {} en nog 1 app.",
|
||||
"other": "Mislukt om {} en {} meer apps bij te werken."
|
||||
"one": "Bijwerken mislukt voor {} en nog 1 app.",
|
||||
"other": "Bijwerken mislukt voor {} en nog {} apps."
|
||||
},
|
||||
"xAndNMoreUpdatesPossiblyInstalled": {
|
||||
"one": "{} en nog 1 app zijn mogelijk bijgewerkt.",
|
||||
"other": "{} en {} meer apps zijn mogelijk bijgwerkt."
|
||||
"other": "{} en nog {} apps zijn mogelijk bijgwerkt."
|
||||
},
|
||||
"apk": {
|
||||
"one": "{} APK",
|
||||
|
@@ -113,6 +113,7 @@
|
||||
"dark": "Ciemny",
|
||||
"light": "Jasny",
|
||||
"followSystem": "Zgodny z systemem",
|
||||
"followSystemThemeExplanation": "Podążanie za motywem systemowym jest możliwe tylko przy użyciu aplikacji firm trzecich",
|
||||
"useBlackTheme": "Użyj czarnego motywu",
|
||||
"appSortBy": "Sortuj aplikacje według",
|
||||
"authorName": "Autor/Nazwa",
|
||||
@@ -309,6 +310,8 @@
|
||||
"badDownload": "Nie można przeanalizować pliku APK (niekompatybilny lub częściowo pobrany).",
|
||||
"beforeNewInstallsShareToAppVerifier": "Udostępnianie nowych aplikacji za pomocą AppVerifier (jeśli dostępne)",
|
||||
"appVerifierInstructionToast": "Udostępnij w AppVerifier, a następnie wróć tutaj, gdy będziesz gotowy.",
|
||||
"wiki": "Pomoc/Wiki",
|
||||
"crowdsourcedConfigsLabel": "Konfiguracje aplikacji pochodzące z crowdsourcingu (korzystanie na własne ryzyko)",
|
||||
"removeAppQuestion": {
|
||||
"one": "Usunąć aplikację?",
|
||||
"few": "Usunąć aplikacje?",
|
||||
|
@@ -113,6 +113,7 @@
|
||||
"dark": "Escuro",
|
||||
"light": "Claro",
|
||||
"followSystem": "Padrão do sistema",
|
||||
"followSystemThemeExplanation": "O tema do sistema seguinte só é possível através da utilização de aplicações de terceiros",
|
||||
"useBlackTheme": "Usar tema preto AMOLED",
|
||||
"appSortBy": "Classificar aplicativo por",
|
||||
"authorName": "Autor/Nome",
|
||||
@@ -309,6 +310,8 @@
|
||||
"badDownload": "Não foi possível analisar o APK (transferência incompatível ou parcial)",
|
||||
"beforeNewInstallsShareToAppVerifier": "Partilhar novas aplicações com o AppVerifier (se disponível)",
|
||||
"appVerifierInstructionToast": "Partilhe com o AppVerifier e, em seguida, regresse aqui quando estiver pronto.",
|
||||
"wiki": "Ajuda/Wiki",
|
||||
"crowdsourcedConfigsLabel": "Configurações de aplicações de crowdsourcing (utilização por sua conta e risco)",
|
||||
"removeAppQuestion": {
|
||||
"one": "Remover aplicativo?",
|
||||
"other": "Remover aplicativos?"
|
||||
|
@@ -9,7 +9,7 @@
|
||||
"placeholder": "Заполнитель",
|
||||
"someErrors": "Возникли некоторые ошибки",
|
||||
"unexpectedError": "Неожиданная ошибка",
|
||||
"ok": "Ok",
|
||||
"ok": "Ок",
|
||||
"and": "и",
|
||||
"githubPATLabel": "Персональный токен доступа GitHub\n(увеличивает лимит запросов)",
|
||||
"includePrereleases": "Включить предварительные релизы",
|
||||
@@ -113,6 +113,7 @@
|
||||
"dark": "Тёмная",
|
||||
"light": "Светлая",
|
||||
"followSystem": "Системная",
|
||||
"followSystemThemeExplanation": "Следование системной теме возможно только при использовании сторонних приложений",
|
||||
"useBlackTheme": "Использовать чёрную тему",
|
||||
"appSortBy": "Сортировка приложений",
|
||||
"authorName": "Автор/Название",
|
||||
@@ -134,7 +135,7 @@
|
||||
"close": "Закрыть",
|
||||
"share": "Поделиться",
|
||||
"appNotFound": "Приложение не найдено",
|
||||
"obtainiumExportHyphenatedLowercase": "получение-экспорт",
|
||||
"obtainiumExportHyphenatedLowercase": "экспорт-obtainium",
|
||||
"pickAnAPK": "Выберите APK-файл",
|
||||
"appHasMoreThanOnePackage": "{} имеет более одного пакета:",
|
||||
"deviceSupportsXArch": "Ваше устройство поддерживает архитектуру процессора {}",
|
||||
@@ -178,8 +179,8 @@
|
||||
"appWithIdOrNameNotFound": "Приложение с таким ID или названием не было найдено",
|
||||
"reposHaveMultipleApps": "В хранилище несколько приложений",
|
||||
"fdroidThirdPartyRepo": "Сторонние репозитории F-Droid",
|
||||
"steamMobile": "Стим Мобайл",
|
||||
"steamChat": "Стим-чат",
|
||||
"steamMobile": "Приложение Steam",
|
||||
"steamChat": "Steam Chat",
|
||||
"install": "Установить",
|
||||
"markInstalled": "Пометить как установленное",
|
||||
"update": "Обновить",
|
||||
@@ -190,7 +191,7 @@
|
||||
"downloadingX": "Загрузка {}",
|
||||
"downloadX": "Скачать {}",
|
||||
"downloadedX": "Загружено {}",
|
||||
"releaseAsset": "Освобождение актива",
|
||||
"releaseAsset": "Релизный объект",
|
||||
"downloadNotifDescription": "Уведомляет пользователя о прогрессе загрузки приложения",
|
||||
"noAPKFound": "APK не найден",
|
||||
"noVersionDetection": "Обнаружение версий отключено",
|
||||
@@ -253,7 +254,7 @@
|
||||
"intermediateLinkRegex": "Фильтр для \"промежуточной\" ссылки для посещения",
|
||||
"filterByLinkText": "Фильтрация ссылок по тексту ссылки",
|
||||
"intermediateLinkNotFound": "Промежуточная ссылка не найдена",
|
||||
"intermediateLink": "Промежуточное звено",
|
||||
"intermediateLink": "Промежуточная ссылка",
|
||||
"exemptFromBackgroundUpdates": "Исключить из фоновых обновлений (если включено)",
|
||||
"bgUpdatesOnWiFiOnly": "Отключить фоновые обновления, если нет соединения с Wi-Fi",
|
||||
"autoSelectHighestVersionCode": "Автоматически выбирать APK с актуальной версией кода",
|
||||
@@ -309,6 +310,8 @@
|
||||
"badDownload": "APK не удалось разобрать (несовместимая или неполная загрузка)",
|
||||
"beforeNewInstallsShareToAppVerifier": "Поделитесь новыми приложениями с AppVerifier (если доступно)",
|
||||
"appVerifierInstructionToast": "Поделитесь с AppVerifier, а затем вернитесь сюда, когда будете готовы.",
|
||||
"wiki": "Помощь/Вики",
|
||||
"crowdsourcedConfigsLabel": "Конфигурации приложений на основе краудсорсинга (используйте на свой страх и риск)",
|
||||
"removeAppQuestion": {
|
||||
"one": "Удалить приложение?",
|
||||
"other": "Удалить приложения?"
|
||||
|
@@ -113,6 +113,7 @@
|
||||
"dark": "Mörkt",
|
||||
"light": "Ljust",
|
||||
"followSystem": "Följ System",
|
||||
"followSystemThemeExplanation": "Följande systemtema är endast möjligt med hjälp av tredjepartsapplikationer",
|
||||
"useBlackTheme": "Använd svart tema",
|
||||
"appSortBy": "Sortera Appar via",
|
||||
"authorName": "Utvecklare/Namn",
|
||||
@@ -309,6 +310,8 @@
|
||||
"badDownload": "APK kunde inte analyseras (inkompatibel eller partiell nedladdning)",
|
||||
"beforeNewInstallsShareToAppVerifier": "Dela nya appar med AppVerifier (om tillgängligt)",
|
||||
"appVerifierInstructionToast": "Dela till AppVerifier och återvänd sedan hit när du är klar.",
|
||||
"wiki": "Hjälp/Wiki",
|
||||
"crowdsourcedConfigsLabel": "Crowdsourcade appkonfigurationer (använd på egen risk)",
|
||||
"removeAppQuestion": {
|
||||
"one": "Ta Bort App?",
|
||||
"other": "Ta Bort Appar?"
|
||||
|
@@ -113,6 +113,7 @@
|
||||
"dark": "Koyu",
|
||||
"light": "Aydınlık",
|
||||
"followSystem": "Sistemi Takip Et",
|
||||
"followSystemThemeExplanation": "Sistem temasını takip etmek yalnızca üçüncü taraf uygulamaları kullanarak mümkündür",
|
||||
"useBlackTheme": "Saf siyah koyu temasını kullan",
|
||||
"appSortBy": "Uygulama Sıralama Ölçütü",
|
||||
"authorName": "Yazar/Ad",
|
||||
@@ -309,6 +310,8 @@
|
||||
"badDownload": "APK ayrıştırılamadı (uyumsuz veya kısmi indirme)",
|
||||
"beforeNewInstallsShareToAppVerifier": "Yeni Uygulamaları AppVerifier ile paylaşın (varsa)",
|
||||
"appVerifierInstructionToast": "AppVerifier ile paylaşın, hazır olduğunuzda buraya dönün.",
|
||||
"wiki": "Yardım/Wiki",
|
||||
"crowdsourcedConfigsLabel": "Kitle Kaynaklı Uygulama Yapılandırmaları (riski size ait olmak üzere kullanın)",
|
||||
"removeAppQuestion": {
|
||||
"one": "Uygulamayı Kaldır?",
|
||||
"other": "Uygulamaları Kaldır?"
|
||||
|
@@ -113,6 +113,7 @@
|
||||
"dark": "Темна",
|
||||
"light": "Світла",
|
||||
"followSystem": "Дотримуватися системи",
|
||||
"followSystemThemeExplanation": "Зміна теми системи можлива лише за допомогою сторонніх додатків",
|
||||
"useBlackTheme": "Використовувати чорну тему (Amoled)",
|
||||
"appSortBy": "Сортувати застосунки за",
|
||||
"authorName": "Автор/Назва",
|
||||
@@ -309,6 +310,8 @@
|
||||
"badDownload": "APK не вдалося розпарсити (несумісний або часткове завантаження)",
|
||||
"beforeNewInstallsShareToAppVerifier": "Діліться новими додатками з AppVerifier (якщо доступно)",
|
||||
"appVerifierInstructionToast": "Надішліть на AppVerifier, а потім поверніться сюди, коли будете готові.",
|
||||
"wiki": "Довідка/Вікі",
|
||||
"crowdsourcedConfigsLabel": "Краудсорсингові конфігурації додатків (використовуйте на свій страх і ризик)",
|
||||
"removeAppQuestion": {
|
||||
"one": "Видалити застосунок?",
|
||||
"other": "Видалити застосунки?"
|
||||
|
@@ -22,9 +22,9 @@
|
||||
"requiredInBrackets": "(Yêu cầu)",
|
||||
"dropdownNoOptsError": "LỖI: TẢI XUỐNG PHẢI CÓ ÍT NHẤT MỘT LỰA CHỌN",
|
||||
"colour": "Màu sắc",
|
||||
"standard": "Standard",
|
||||
"custom": "Custom",
|
||||
"useMaterialYou": "Use Material You",
|
||||
"standard": "Mặc định",
|
||||
"custom": "Tùy chỉnh",
|
||||
"useMaterialYou": "Sử dụng Material You",
|
||||
"githubStarredRepos": "Kho lưu trữ có gắn dấu sao GitHub",
|
||||
"uname": "Tên người dùng",
|
||||
"wrongArgNum": "Số lượng đối số được cung cấp sai",
|
||||
@@ -113,6 +113,7 @@
|
||||
"dark": "Tối",
|
||||
"light": "Sáng",
|
||||
"followSystem": "Theo hệ thống",
|
||||
"followSystemThemeExplanation": "Following system theme is possible only by using third-party applications",
|
||||
"useBlackTheme": "Nền đen",
|
||||
"appSortBy": "Sắp xếp ứng dụng",
|
||||
"authorName": "Tác giả",
|
||||
@@ -146,10 +147,10 @@
|
||||
"noNewUpdates": "Không có bản cập nhật mới.",
|
||||
"xHasAnUpdate": "{} có bản 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",
|
||||
"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",
|
||||
"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ỏ",
|
||||
@@ -188,8 +189,8 @@
|
||||
"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.",
|
||||
"downloadingX": "Đang tải xuống {}",
|
||||
"downloadX": "Download {}",
|
||||
"downloadedX": "Downloaded {}",
|
||||
"downloadX": "Tải xuống {}",
|
||||
"downloadedX": "Đã tải xuống {}",
|
||||
"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",
|
||||
"noAPKFound": "Không tìm thấy APK",
|
||||
@@ -287,10 +288,10 @@
|
||||
"supportFixedAPKURL": "Hỗ trợ URL APK cố định",
|
||||
"selectX": "Lựa chọn {}",
|
||||
"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",
|
||||
"shizukuOld": "Old Shizuku version (<11) - update it",
|
||||
"shizukuOldAndroidWithADB": "Shizuku running on Android < 8.1 with ADB - update Android or use Sui instead",
|
||||
"shizukuOld": "Phiên bản Shizuku lỗi thời (<11) - hãy cập nhật nó",
|
||||
"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)",
|
||||
"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",
|
||||
@@ -309,6 +310,8 @@
|
||||
"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ó)",
|
||||
"appVerifierInstructionToast": "Chia sẻ lên AppVerifier, sau đó quay lại đây khi sẵn sàng.",
|
||||
"wiki": "Trợ giúp/Wiki",
|
||||
"crowdsourcedConfigsLabel": "Crowdsourced App Configurations (use at your own risk)",
|
||||
"removeAppQuestion": {
|
||||
"one": "Gỡ ứng dụng?",
|
||||
"other": "Gỡ ứng dụng?"
|
||||
@@ -358,8 +361,8 @@
|
||||
"other": "{} và {} ứng dụng khác đã được cập nhật."
|
||||
},
|
||||
"xAndNMoreUpdatesFailed": {
|
||||
"one": "Failed to update {} and 1 more app.",
|
||||
"other": "Failed to update {} and {} more apps."
|
||||
"one": "{} và 1 ứng dụng khác đã cập nhật không thành công.",
|
||||
"other": "{} và {} ứng dụng khác đã cập nhật không thảnh công."
|
||||
},
|
||||
"xAndNMoreUpdatesPossiblyInstalled": {
|
||||
"one": "{} và 1 ứng dụng khác có thể đã được cập nhật.",
|
||||
|
375
assets/translations/zh-TW.json
Normal file
375
assets/translations/zh-TW.json
Normal file
@@ -0,0 +1,375 @@
|
||||
{
|
||||
"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": "版本字串提取正則表達式",
|
||||
"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"
|
||||
}
|
||||
}
|
@@ -13,8 +13,8 @@
|
||||
"and": "和",
|
||||
"githubPATLabel": "GitHub 个人访问令牌(提升 API 请求限额)",
|
||||
"includePrereleases": "包含预发行版",
|
||||
"fallbackToOlderReleases": "将旧发行版作为备选",
|
||||
"filterReleaseTitlesByRegEx": "筛选发行标题(正则表达式)",
|
||||
"fallbackToOlderReleases": "将过往的发行版作为备选",
|
||||
"filterReleaseTitlesByRegEx": "筛选发行标题的正则表达式",
|
||||
"invalidRegEx": "无效的正则表达式",
|
||||
"noDescription": "无描述",
|
||||
"cancel": "取消",
|
||||
@@ -24,7 +24,7 @@
|
||||
"colour": "配色",
|
||||
"standard": "标准",
|
||||
"custom": "定制",
|
||||
"useMaterialYou": "使用您的材料",
|
||||
"useMaterialYou": "使用 Material You",
|
||||
"githubStarredRepos": "已星标的 GitHub 仓库",
|
||||
"uname": "用户名",
|
||||
"wrongArgNum": "参数数量错误",
|
||||
@@ -45,8 +45,8 @@
|
||||
"search": "搜索",
|
||||
"additionalOptsFor": "{} 的更多选项",
|
||||
"supportedSources": "支持的来源",
|
||||
"trackOnlyInBrackets": "(仅追踪)",
|
||||
"searchableInBrackets": "(可搜索)",
|
||||
"trackOnlyInBrackets": "(仅追踪)",
|
||||
"searchableInBrackets": "(可搜索)",
|
||||
"appsString": "应用列表",
|
||||
"noApps": "无应用",
|
||||
"noAppsForFilter": "没有符合条件的应用",
|
||||
@@ -75,8 +75,8 @@
|
||||
"unpinFromTop": "取消置顶",
|
||||
"resetInstallStatusForSelectedAppsQuestion": "是否重置选中应用的安装状态?",
|
||||
"installStatusOfXWillBeResetExplanation": "选中应用的安装状态将会被重置。\n\n当更新安装失败或其他问题导致 Obtainium 中的应用版本显示错误时,可以尝试通过此方法解决。",
|
||||
"customLinkMessage": "这些链接适用于安装了 Gettingium 的设备",
|
||||
"shareAppConfigLinks": "将应用程序配置共享为 HTML 链接",
|
||||
"customLinkMessage": "分享链接仅适用于已安装 Obtainium 的设备",
|
||||
"shareAppConfigLinks": "通过链接分享应用配置",
|
||||
"shareSelectedAppURLs": "分享选中应用的 URL",
|
||||
"resetInstallStatus": "重置安装状态",
|
||||
"more": "更多",
|
||||
@@ -113,6 +113,7 @@
|
||||
"dark": "深色",
|
||||
"light": "浅色",
|
||||
"followSystem": "跟随系统",
|
||||
"followSystemThemeExplanation": "跟随系统主题仅在使用第三方应用时有效",
|
||||
"useBlackTheme": "使用纯黑深色主题",
|
||||
"appSortBy": "排序依据",
|
||||
"authorName": "作者 / 应用名称",
|
||||
@@ -124,7 +125,7 @@
|
||||
"bgUpdateCheckInterval": "后台更新检查间隔",
|
||||
"neverManualOnly": "手动",
|
||||
"appearance": "外观",
|
||||
"showWebInAppView": "应用详情页显示来源网页",
|
||||
"showWebInAppView": "应用详情页显示来源网站内容",
|
||||
"pinUpdates": "将待更新应用置顶",
|
||||
"updates": "更新",
|
||||
"sourceSpecific": "来源",
|
||||
@@ -134,7 +135,7 @@
|
||||
"close": "关闭",
|
||||
"share": "分享",
|
||||
"appNotFound": "未找到应用",
|
||||
"obtainiumExportHyphenatedLowercase": "获取出口",
|
||||
"obtainiumExportHyphenatedLowercase": "obtainium-export",
|
||||
"pickAnAPK": "选择一个 APK 文件",
|
||||
"appHasMoreThanOnePackage": "“{}”有多个架构可用:",
|
||||
"deviceSupportsXArch": "您的设备支持 {} 架构。",
|
||||
@@ -146,7 +147,7 @@
|
||||
"noNewUpdates": "全部应用已是最新。",
|
||||
"xHasAnUpdate": "“{}”可以更新了。",
|
||||
"appsUpdated": "应用已更新",
|
||||
"appsNotUpdated": "更新应用程序失败",
|
||||
"appsNotUpdated": "更新应用失败",
|
||||
"appsUpdatedNotifDescription": "当应用在后台安装更新时发送通知",
|
||||
"xWasUpdatedToY": "“{}”已更新至 {}。",
|
||||
"xWasNotUpdatedToY": "未能将 {} 更新为 {}。",
|
||||
@@ -178,8 +179,8 @@
|
||||
"appWithIdOrNameNotFound": "未找到符合此 ID 或名称的应用",
|
||||
"reposHaveMultipleApps": "存储库中可能包含多个应用",
|
||||
"fdroidThirdPartyRepo": "F-Droid 第三方存储库",
|
||||
"steamMobile": "蒸汽手机",
|
||||
"steamChat": "蒸汽聊天",
|
||||
"steamMobile": "Steam Mobile",
|
||||
"steamChat": "Steam Chat",
|
||||
"install": "安装",
|
||||
"markInstalled": "标记为已安装",
|
||||
"update": "更新",
|
||||
@@ -190,7 +191,7 @@
|
||||
"downloadingX": "正在下载“{}”",
|
||||
"downloadX": "下载 {}",
|
||||
"downloadedX": "下载 {}",
|
||||
"releaseAsset": "释放资产",
|
||||
"releaseAsset": "发行版附件",
|
||||
"downloadNotifDescription": "提示应用的下载进度",
|
||||
"noAPKFound": "未找到 APK 文件",
|
||||
"noVersionDetection": "禁用版本检测",
|
||||
@@ -200,14 +201,14 @@
|
||||
"noCategory": "无类别",
|
||||
"noCategories": "无类别",
|
||||
"deleteCategoriesQuestion": "是否删除选中的类别?",
|
||||
"categoryDeleteWarning": "被删除类别下的应用将恢复为未分类状态。",
|
||||
"categoryDeleteWarning": "被删除类别的应用将恢复为未分类状态。",
|
||||
"addCategory": "添加类别",
|
||||
"label": "标签",
|
||||
"language": "语言",
|
||||
"copiedToClipboard": "已复制至剪贴板",
|
||||
"storagePermissionDenied": "已拒绝授予存储权限",
|
||||
"selectedCategorizeWarning": "这将覆盖选中应用当前的类别设置。",
|
||||
"filterAPKsByRegEx": "筛选 APK 文件(正则表达式)",
|
||||
"filterAPKsByRegEx": "筛选 APK 文件的正则表达式",
|
||||
"removeFromObtainium": "从 Obtainium 中删除",
|
||||
"uninstallFromDevice": "从设备中卸载",
|
||||
"onlyWorksWithNonVersionDetectApps": "仅适用于禁用版本检测的应用。",
|
||||
@@ -241,29 +242,29 @@
|
||||
"addInfoInSettings": "在“设置”中添加此凭据。",
|
||||
"githubSourceNote": "使用访问令牌可避免触发 GitHub 的 API 请求限制。",
|
||||
"sortByLastLinkSegment": "仅根据链接的末尾部分进行筛选",
|
||||
"filterReleaseNotesByRegEx": "筛选发行说明(正则表达式)",
|
||||
"filterReleaseNotesByRegEx": "筛选发行说明的正则表达式",
|
||||
"customLinkFilterRegex": "筛选自定义来源的 APK 文件链接\n(正则表达式,默认匹配模式为“.apk$”)",
|
||||
"appsPossiblyUpdated": "已尝试更新应用",
|
||||
"appsPossiblyUpdatedNotifDescription": "当应用已尝试在后台更新时发送通知",
|
||||
"xWasPossiblyUpdatedToY": "已尝试将“{}”更新至 {}。",
|
||||
"enableBackgroundUpdates": "启用后台更新",
|
||||
"enableBackgroundUpdates": "启用全局后台更新",
|
||||
"backgroundUpdateReqsExplanation": "后台更新未必适用于所有的应用。",
|
||||
"backgroundUpdateLimitsExplanation": "只有在启动 Obtainium 时才能确认安装是否成功。",
|
||||
"verifyLatestTag": "验证“Latest”标签",
|
||||
"intermediateLinkRegex": "筛选中转链接(正则表达式)",
|
||||
"intermediateLinkRegex": "筛选中转链接的正则表达式",
|
||||
"filterByLinkText": "根据链接文本进行筛选",
|
||||
"intermediateLinkNotFound": "未找到中转链接",
|
||||
"intermediateLink": "中转链接",
|
||||
"exemptFromBackgroundUpdates": "禁用后台更新(如果已经全局启用)",
|
||||
"exemptFromBackgroundUpdates": "禁用后台更新(仅此应用生效,即使已启用全局后台更新)",
|
||||
"bgUpdatesOnWiFiOnly": "未连接 Wi-Fi 时禁用后台更新",
|
||||
"autoSelectHighestVersionCode": "自动选择内部版本号最高的 APK 文件",
|
||||
"versionExtractionRegEx": "版本号提取规则(正则表达式)",
|
||||
"matchGroupToUse": "引用的捕获组",
|
||||
"highlightTouchTargets": "突出展示不明显的触摸区域",
|
||||
"versionExtractionRegEx": "提取版本号的正则表达式",
|
||||
"matchGroupToUse": "从上述匹配结果中引用的捕获组",
|
||||
"highlightTouchTargets": "突出展示不明显的可交互区域",
|
||||
"pickExportDir": "选择导出文件夹",
|
||||
"autoExportOnChanges": "数据变更时自动导出",
|
||||
"includeSettings": "同时导出应用设置",
|
||||
"filterVersionsByRegEx": "筛选版本号(正则表达式)",
|
||||
"filterVersionsByRegEx": "筛选版本号的正则表达式",
|
||||
"trySelectingSuggestedVersionCode": "尝试选择推荐版本的 APK 文件",
|
||||
"dontSortReleasesList": "保持来自 API 的发行顺序",
|
||||
"reverseSort": "反转排序",
|
||||
@@ -289,13 +290,13 @@
|
||||
"parallelDownloads": "启用并行下载",
|
||||
"useShizuku": "使用 Shizuku 或 Sui 安装",
|
||||
"shizukuBinderNotFound": "未发现兼容的 Shizuku 服务",
|
||||
"shizukuOld": "旧的 Shizuku 版本 (<11) - 更新它",
|
||||
"shizukuOldAndroidWithADB": "使用 ADB 在 Android < 8.1 上运行 Shizuku - 更新 Android 或使用 Sui 代替",
|
||||
"shizukuPretendToBeGooglePlay": "将 Google Play 设置为安装源(如果使用 Shizuku)",
|
||||
"shizukuOld": "Shizuku 版本过低(<11)- 请更新",
|
||||
"shizukuOldAndroidWithADB": "正在低版本 Android(<8.1)系统中以 ADB 模式运行 Shizuku - 请更新 Android 系统版本或使用 Sui 代替",
|
||||
"shizukuPretendToBeGooglePlay": "将安装来源伪装为 Google Play(需要使用 Shizuku)",
|
||||
"useSystemFont": "使用系统字体",
|
||||
"useVersionCodeAsOSVersion": "使用内部版本号代替应用定义的版本号",
|
||||
"requestHeader": "请求标头",
|
||||
"useLatestAssetDateAsReleaseDate": "使用最近文件上传时间作为发行日期",
|
||||
"useLatestAssetDateAsReleaseDate": "使用最新文件上传时间作为发行日期",
|
||||
"defaultPseudoVersioningMethod": "默认虚拟版本方案",
|
||||
"partialAPKHash": "APK 文件散列值片段",
|
||||
"APKLinkHash": "APK 文件链接散列值",
|
||||
@@ -307,19 +308,21 @@
|
||||
"note": "备注",
|
||||
"selfHostedNote": "可以通过“{}”下拉菜单来指向任意来源的自托管/自定义实例。",
|
||||
"badDownload": "无法解析 APK 文件(不兼容或文件不完整)",
|
||||
"beforeNewInstallsShareToAppVerifier": "与 AppVerifier 共享新应用程序(如有)",
|
||||
"appVerifierInstructionToast": "分享到 AppVerifier,准备就绪后返回此处。",
|
||||
"beforeNewInstallsShareToAppVerifier": "通过 AppVerifier 校验新应用(如果可用)",
|
||||
"appVerifierInstructionToast": "分享至 AppVerifier,完成后返回此处。",
|
||||
"wiki": "帮助/Wiki",
|
||||
"crowdsourcedConfigsLabel": "众包应用程序配置(使用风险自负)",
|
||||
"removeAppQuestion": {
|
||||
"one": "是否删除应用?",
|
||||
"other": "是否删除应用?"
|
||||
},
|
||||
"tooManyRequestsTryAgainInMinutes": {
|
||||
"one": "API 请求过于频繁(速率限制)- 在 {} 分钟后重试",
|
||||
"other": "API 请求过于频繁(速率限制)- 在 {} 分钟后重试"
|
||||
"one": "API 请求过于频繁(速率限制)- 请在 {} 分钟后重试",
|
||||
"other": "API 请求过于频繁(速率限制)- 请在 {} 分钟后重试"
|
||||
},
|
||||
"bgUpdateGotErrorRetryInMinutes": {
|
||||
"one": "后台更新检查遇到了“{}”问题,预定于 {} 分钟后重试",
|
||||
"other": "后台更新检查遇到了“{}”问题,预定于 {} 分钟后重试"
|
||||
"one": "后台更新检查遇到了“{}”问题,将于 {} 分钟后重试",
|
||||
"other": "后台更新检查遇到了“{}”问题,将于 {} 分钟后重试"
|
||||
},
|
||||
"bgCheckFoundUpdatesWillNotifyIfNeeded": {
|
||||
"one": "后台检查发现 {} 个应用更新 - 如有需要将发送通知",
|
||||
@@ -358,8 +361,8 @@
|
||||
"other": "“{}”和另外 {} 个应用已更新。"
|
||||
},
|
||||
"xAndNMoreUpdatesFailed": {
|
||||
"one": "更新 {} 和另外 1 个应用程序失败。",
|
||||
"other": "未能更新 {} 和 {} 更多应用程序。"
|
||||
"one": "{} 和另外 1 个应用更新失败。",
|
||||
"other": "{} 和另外 {} 个应用更新失败。"
|
||||
},
|
||||
"xAndNMoreUpdatesPossiblyInstalled": {
|
||||
"one": "{} 和另外 1 个应用已尝试更新。",
|
||||
|
@@ -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
|
||||
Future<APKDetails> getLatestAPKDetails(
|
||||
String standardUrl,
|
||||
|
@@ -9,7 +9,7 @@ class FDroidRepo extends AppSource {
|
||||
FDroidRepo() {
|
||||
name = tr('fdroidThirdPartyRepo');
|
||||
canSearch = true;
|
||||
excludeFromMassSearch = true;
|
||||
includeAdditionalOptsInMainSearch = true;
|
||||
neverAutoSelect = true;
|
||||
showReleaseDateAsVersionToggle = true;
|
||||
|
||||
@@ -86,6 +86,27 @@ class FDroidRepo extends AppSource {
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void runOnAddAppInputChange(String userInput) {
|
||||
this.additionalSourceAppSpecificSettingFormItems =
|
||||
this.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
|
||||
App endOfGetAppChanges(App app) {
|
||||
var uri = Uri.parse(app.url);
|
||||
@@ -142,6 +163,7 @@ class FDroidRepo extends AppSource {
|
||||
if (appIdOrName == null) {
|
||||
throw NoReleasesError();
|
||||
}
|
||||
additionalSettings['appIdOrName'] = appIdOrName;
|
||||
var res =
|
||||
await sourceRequestWithURLVariants(standardUrl, additionalSettings);
|
||||
if (res.statusCode == 200) {
|
||||
|
@@ -273,10 +273,11 @@ class GitHub extends AppSource {
|
||||
|
||||
List<MapEntry<String, String>> getReleaseAssetUrls(dynamic release) =>
|
||||
(release['assets'] as List<dynamic>?)?.map((e) {
|
||||
return (e['name'] != null) &&
|
||||
((e['url'] ?? e['browser_download_url']) != null)
|
||||
? MapEntry(e['name'] as String,
|
||||
(e['url'] ?? e['browser_download_url']) as String)
|
||||
var url = !e['name'].toString().toLowerCase().endsWith('.apk')
|
||||
? (e['browser_download_url'] ?? e['url'])
|
||||
: (e['url'] ?? e['browser_download_url']);
|
||||
return (e['name'] != null) && (url != null)
|
||||
? MapEntry(e['name'] as String, url as String)
|
||||
: const MapEntry('', '');
|
||||
}).toList() ??
|
||||
[];
|
||||
@@ -284,7 +285,9 @@ class GitHub extends AppSource {
|
||||
DateTime? getPublishDateFromRelease(dynamic rel) =>
|
||||
rel?['published_at'] != null
|
||||
? DateTime.parse(rel['published_at'])
|
||||
: null;
|
||||
: rel?['commit']?['created'] != null
|
||||
? DateTime.parse(rel['commit']['created'])
|
||||
: null;
|
||||
DateTime? getNewestAssetDateFromRelease(dynamic rel) {
|
||||
var t = (rel['assets'] as List<dynamic>?)
|
||||
?.map((e) {
|
||||
|
@@ -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
|
||||
Future<APKDetails> getLatestAPKDetails(
|
||||
String standardUrl,
|
||||
@@ -153,7 +161,8 @@ class GitLab extends AppSource {
|
||||
.toList();
|
||||
var apkUrlsSet = apkUrlsFromAssets.toSet();
|
||||
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 =
|
||||
releaseDateString != null ? DateTime.parse(releaseDateString) : null;
|
||||
return APKDetails(
|
||||
|
@@ -243,19 +243,28 @@ class HTML extends AppSource {
|
||||
if ((additionalSettings['customLinkFilterRegex'] as String?)?.isNotEmpty ==
|
||||
true) {
|
||||
var reg = RegExp(additionalSettings['customLinkFilterRegex']);
|
||||
links = allLinks
|
||||
.where((element) => reg.hasMatch(
|
||||
filterLinkByText ? element.value : Uri.decodeFull(element.key)))
|
||||
.toList();
|
||||
links = allLinks.where((element) {
|
||||
var link = element.key;
|
||||
try {
|
||||
link = Uri.decodeFull(element.key);
|
||||
} catch (e) {
|
||||
// Some links may not have valid encoding
|
||||
}
|
||||
return reg.hasMatch(filterLinkByText ? element.value : link);
|
||||
}).toList();
|
||||
} else {
|
||||
links = allLinks
|
||||
.where((element) => Uri.parse(filterLinkByText
|
||||
? element.value
|
||||
: Uri.decodeFull(element.key))
|
||||
.path
|
||||
.toLowerCase()
|
||||
.endsWith('.apk'))
|
||||
.toList();
|
||||
links = allLinks.where((element) {
|
||||
var link = element.key;
|
||||
try {
|
||||
link = Uri.decodeFull(element.key);
|
||||
} catch (e) {
|
||||
// Some links may not have valid encoding
|
||||
}
|
||||
return Uri.parse(filterLinkByText ? element.value : link)
|
||||
.path
|
||||
.toLowerCase()
|
||||
.endsWith('.apk');
|
||||
}).toList();
|
||||
}
|
||||
if (!skipSort) {
|
||||
links.sort((a, b) => additionalSettings['sortByLastLinkSegment'] == true
|
||||
@@ -310,17 +319,26 @@ class HTML extends AppSource {
|
||||
links = [MapEntry(currentUrl, currentUrl)];
|
||||
}
|
||||
var rel = links.last.key;
|
||||
var relDecoded = rel;
|
||||
try {
|
||||
relDecoded = Uri.decodeFull(rel);
|
||||
} catch (e) {
|
||||
// Some links may not have valid encoding
|
||||
}
|
||||
String? version;
|
||||
version = extractVersion(
|
||||
additionalSettings['versionExtractionRegEx'] as String?,
|
||||
additionalSettings['matchGroupToUse'] as String?,
|
||||
additionalSettings['versionExtractWholePage'] == true
|
||||
? versionExtractionWholePageString
|
||||
: Uri.decodeFull(rel));
|
||||
version ??=
|
||||
additionalSettings['defaultPseudoVersioningMethod'] == 'APKLinkHash'
|
||||
? rel.hashCode.toString()
|
||||
: (await checkPartialDownloadHashDynamic(rel)).toString();
|
||||
: relDecoded);
|
||||
version ??= additionalSettings['defaultPseudoVersioningMethod'] ==
|
||||
'APKLinkHash'
|
||||
? rel.hashCode.toString()
|
||||
: (await checkPartialDownloadHashDynamic(rel,
|
||||
headers: await getRequestHeaders(additionalSettings,
|
||||
forAPKDownload: true)))
|
||||
.toString();
|
||||
return APKDetails(version, [rel].map((e) => MapEntry(e, e)).toList(),
|
||||
AppNames(uri.host, tr('app')));
|
||||
}
|
||||
|
@@ -6,7 +6,7 @@ import 'package:obtainium/providers/source_provider.dart';
|
||||
class HuaweiAppGallery extends AppSource {
|
||||
HuaweiAppGallery() {
|
||||
name = 'Huawei AppGallery';
|
||||
hosts = ['appgallery.huawei.com'];
|
||||
hosts = ['appgallery.huawei.com', 'appgallery.cloud.huawei.com'];
|
||||
versionDetectionDisallowed = true;
|
||||
showReleaseDateAsVersionToggle = true;
|
||||
}
|
||||
@@ -14,7 +14,7 @@ class HuaweiAppGallery extends AppSource {
|
||||
@override
|
||||
String sourceSpecificStandardizeURL(String url) {
|
||||
RegExp standardUrlRegEx = RegExp(
|
||||
'^https?://(www\\.)?${getSourceRegex(hosts)}/app/[^/]+',
|
||||
'^https?://(www\\.)?${getSourceRegex(hosts)}(/#)?/(app|appdl)/[^/]+',
|
||||
caseSensitive: false);
|
||||
RegExpMatch? match = standardUrlRegEx.firstMatch(url);
|
||||
if (match == null) {
|
||||
@@ -24,7 +24,7 @@ class HuaweiAppGallery extends AppSource {
|
||||
}
|
||||
|
||||
getDlUrl(String standardUrl) =>
|
||||
'https://${hosts[0].replaceAll('appgallery.', 'appgallery.cloud.')}/appdl/${standardUrl.split('/').last}';
|
||||
'https://${hosts[0].replaceAll('appgallery.huawei', 'appgallery.cloud.huawei')}/appdl/${standardUrl.split('/').last}';
|
||||
|
||||
requestAppdlRedirect(
|
||||
String dlUrl, Map<String, dynamic> additionalSettings) async {
|
||||
@@ -73,21 +73,23 @@ class HuaweiAppGallery extends AppSource {
|
||||
throw NoReleasesError();
|
||||
}
|
||||
String appId = appIdFromRedirectDlUrl(res.headers['location']!);
|
||||
if (appId.isEmpty) {
|
||||
throw NoReleasesError();
|
||||
}
|
||||
var relDateStr =
|
||||
res.headers['location']?.split('?')[0].split('.').reversed.toList()[1];
|
||||
var relDateStrAdj = relDateStr?.split('');
|
||||
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').parse(relDateStrAdj.join(''));
|
||||
if (relDateStr == null) {
|
||||
if (relDateStr == null || relDateStr.length != 10) {
|
||||
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(
|
||||
relDateStr, [MapEntry('$appId.apk', dlUrl)], AppNames(name, appId),
|
||||
releaseDate: relDate);
|
||||
|
@@ -5,6 +5,7 @@ import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:obtainium/components/generated_form_modal.dart';
|
||||
import 'package:obtainium/providers/source_provider.dart';
|
||||
import 'package:flutter_typeahead/flutter_typeahead.dart';
|
||||
|
||||
abstract class GeneratedFormItem {
|
||||
late String key;
|
||||
@@ -28,6 +29,7 @@ class GeneratedFormTextField extends GeneratedFormItem {
|
||||
late String? hint;
|
||||
late bool password;
|
||||
late TextInputType? textInputType;
|
||||
late List<String>? autoCompleteOptions;
|
||||
|
||||
GeneratedFormTextField(super.key,
|
||||
{super.label,
|
||||
@@ -39,7 +41,8 @@ class GeneratedFormTextField extends GeneratedFormItem {
|
||||
this.max = 1,
|
||||
this.hint,
|
||||
this.password = false,
|
||||
this.textInputType});
|
||||
this.textInputType,
|
||||
this.autoCompleteOptions});
|
||||
|
||||
@override
|
||||
String ensureType(val) {
|
||||
@@ -274,38 +277,62 @@ class _GeneratedFormState extends State<GeneratedForm> {
|
||||
var formItem = e.value;
|
||||
if (formItem is GeneratedFormTextField) {
|
||||
final formFieldKey = GlobalKey<FormFieldState>();
|
||||
return TextFormField(
|
||||
keyboardType: formItem.textInputType,
|
||||
obscureText: formItem.password,
|
||||
autocorrect: !formItem.password,
|
||||
enableSuggestions: !formItem.password,
|
||||
key: formFieldKey,
|
||||
initialValue: values[formItem.key],
|
||||
autovalidateMode: AutovalidateMode.onUserInteraction,
|
||||
onChanged: (value) {
|
||||
var ctrl = TextEditingController(text: values[formItem.key]);
|
||||
return TypeAheadField<String>(
|
||||
controller: ctrl,
|
||||
builder: (context, controller, focusNode) {
|
||||
return TextFormField(
|
||||
controller: ctrl,
|
||||
focusNode: focusNode,
|
||||
keyboardType: formItem.textInputType,
|
||||
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(() {
|
||||
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;
|
||||
suggestionsCallback: (search) {
|
||||
return formItem.autoCompleteOptions
|
||||
?.where((t) => t.toLowerCase().contains(search.toLowerCase()))
|
||||
.toList();
|
||||
},
|
||||
hideOnEmpty: true,
|
||||
);
|
||||
} else if (formItem is GeneratedFormDropdown) {
|
||||
if (formItem.opts!.isEmpty) {
|
||||
|
@@ -40,6 +40,7 @@ List<MapEntry<Locale, String>> supportedLocales = const [
|
||||
MapEntry(Locale('vi'), 'Tiếng Việt'),
|
||||
MapEntry(Locale('tr'), 'Türkçe'),
|
||||
MapEntry(Locale('uk'), 'Українська'),
|
||||
MapEntry(Locale('da'), 'Dansk'),
|
||||
];
|
||||
const fallbackLocale = Locale('en');
|
||||
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
|
||||
ColorScheme lightColorScheme;
|
||||
ColorScheme darkColorScheme;
|
||||
if (lightDynamic != null && darkDynamic != null && settingsProvider.useMaterialYou) {
|
||||
if (lightDynamic != null &&
|
||||
darkDynamic != null &&
|
||||
settingsProvider.useMaterialYou) {
|
||||
lightColorScheme = lightDynamic.harmonized();
|
||||
darkColorScheme = darkDynamic.harmonized();
|
||||
} else {
|
||||
lightColorScheme = ColorScheme.fromSeed(seedColor: settingsProvider.themeColor);
|
||||
lightColorScheme =
|
||||
ColorScheme.fromSeed(seedColor: settingsProvider.themeColor);
|
||||
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
|
||||
if (settingsProvider.useBlackTheme) {
|
||||
darkColorScheme = darkColorScheme
|
||||
.copyWith(background: Colors.black, surface: Colors.black)
|
||||
.harmonized();
|
||||
darkColorScheme =
|
||||
darkColorScheme.copyWith(surface: Colors.black).harmonized();
|
||||
}
|
||||
|
||||
if (settingsProvider.useSystemFont) NativeFeatures.loadSystemFont();
|
||||
|
@@ -51,10 +51,13 @@ class AddAppPageState extends State<AddAppPage> {
|
||||
}
|
||||
|
||||
changeUserInput(String input, bool valid, bool isBuilding,
|
||||
{bool updateUrlInput = false}) {
|
||||
{bool updateUrlInput = false, String? overrideSource}) {
|
||||
userInput = input;
|
||||
if (!isBuilding) {
|
||||
setState(() {
|
||||
if (overrideSource != null) {
|
||||
pickedSourceOverride = overrideSource;
|
||||
}
|
||||
if (updateUrlInput) {
|
||||
urlInputKey++;
|
||||
}
|
||||
@@ -68,6 +71,7 @@ class AddAppPageState extends State<AddAppPage> {
|
||||
if (pickedSource.runtimeType != source.runtimeType ||
|
||||
(prevHost != null && prevHost != source?.hosts[0])) {
|
||||
pickedSource = source;
|
||||
pickedSource?.runOnAddAppInputChange(userInput);
|
||||
additionalSettings = source != null
|
||||
? getDefaultValuesFromFormItems(
|
||||
source.combinedAppSpecificSettingFormItems)
|
||||
@@ -259,9 +263,7 @@ class AddAppPageState extends State<AddAppPage> {
|
||||
searching = true;
|
||||
});
|
||||
var sourceStrings = <String, List<String>>{};
|
||||
sourceProvider.sources
|
||||
.where((e) => e.canSearch && !e.excludeFromMassSearch)
|
||||
.forEach((s) {
|
||||
sourceProvider.sources.where((e) => e.canSearch).forEach((s) {
|
||||
sourceStrings[s.name] = [s.name];
|
||||
});
|
||||
try {
|
||||
@@ -282,32 +284,78 @@ class AddAppPageState extends State<AddAppPage> {
|
||||
settingsProvider.searchDeselected = sourceStrings.keys
|
||||
.where((s) => !searchSources.contains(s))
|
||||
.toList();
|
||||
var results = await Future.wait(sourceProvider.sources
|
||||
.where((e) => searchSources.contains(e.name))
|
||||
.map((e) async {
|
||||
List<MapEntry<String, Map<String, List<String>>>?> results =
|
||||
(await Future.wait(sourceProvider.sources
|
||||
.where((e) => searchSources.contains(e.name))
|
||||
.map((e) async {
|
||||
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) {
|
||||
if (err is! CredsNeededError) {
|
||||
rethrow;
|
||||
} else {
|
||||
err.unexpected = true;
|
||||
showError(err, context);
|
||||
return <String, List<String>>{};
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}));
|
||||
})))
|
||||
.where((a) => a != null)
|
||||
.toList();
|
||||
|
||||
// Interleave results instead of simple reduce
|
||||
Map<String, List<String>> res = {};
|
||||
Map<String, MapEntry<String, List<String>>> res = {};
|
||||
var si = 0;
|
||||
var done = false;
|
||||
while (!done) {
|
||||
done = true;
|
||||
for (var r in results) {
|
||||
if (r.length > si) {
|
||||
var sourceName = r!.key;
|
||||
if (r.value.length > si) {
|
||||
done = false;
|
||||
res.addEntries([r.entries.elementAt(si)]);
|
||||
var singleRes = r.value.entries.elementAt(si);
|
||||
res[singleRes.key] = MapEntry(sourceName, singleRes.value);
|
||||
}
|
||||
}
|
||||
si++;
|
||||
@@ -322,13 +370,15 @@ class AddAppPageState extends State<AddAppPage> {
|
||||
context: context,
|
||||
builder: (BuildContext ctx) {
|
||||
return SelectionModal(
|
||||
entries: res,
|
||||
entries: res.map((k, v) => MapEntry(k, v.value)),
|
||||
selectedByDefault: false,
|
||||
onlyOneSelectionAllowed: true,
|
||||
);
|
||||
});
|
||||
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) {
|
||||
@@ -349,7 +399,7 @@ class AddAppPageState extends State<AddAppPage> {
|
||||
[
|
||||
GeneratedFormDropdown(
|
||||
'overrideSource',
|
||||
defaultValue: '',
|
||||
defaultValue: pickedSourceOverride ?? '',
|
||||
[
|
||||
MapEntry('', tr('none')),
|
||||
...sourceProvider.sources.map(
|
||||
|
@@ -133,7 +133,7 @@ class _AppPageState extends State<AppPage> {
|
||||
child: Text(
|
||||
app?.app.releaseDate == null
|
||||
? tr('changes')
|
||||
: app!.app.releaseDate.toString(),
|
||||
: app!.app.releaseDate!.toLocal().toString(),
|
||||
textAlign: TextAlign.center,
|
||||
style:
|
||||
Theme.of(context).textTheme.labelSmall!.copyWith(
|
||||
@@ -161,26 +161,46 @@ class _AppPageState extends State<AppPage> {
|
||||
if (app?.app.apkUrls.isNotEmpty == true ||
|
||||
app?.app.otherAssetUrls.isNotEmpty == true)
|
||||
GestureDetector(
|
||||
onTap: app?.app == null || updating
|
||||
? null
|
||||
: () async {
|
||||
try {
|
||||
await appsProvider
|
||||
.downloadAppAssets([app!.app.id], context);
|
||||
} catch (e) {
|
||||
showError(e, context);
|
||||
}
|
||||
},
|
||||
child: Text(
|
||||
tr('downloadX', args: [tr('releaseAsset').toLowerCase()]),
|
||||
textAlign: TextAlign.center,
|
||||
style: Theme.of(context).textTheme.labelSmall!.copyWith(
|
||||
decoration:
|
||||
changeLogFn != null ? TextDecoration.underline : null,
|
||||
fontStyle: changeLogFn != null ? FontStyle.italic : null,
|
||||
),
|
||||
),
|
||||
),
|
||||
onTap: app?.app == null || updating
|
||||
? null
|
||||
: () async {
|
||||
try {
|
||||
await appsProvider
|
||||
.downloadAppAssets([app!.app.id], context);
|
||||
} catch (e) {
|
||||
showError(e, context);
|
||||
}
|
||||
},
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
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(
|
||||
height: 48,
|
||||
),
|
||||
@@ -227,18 +247,26 @@ class _AppPageState extends State<AppPage> {
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
const SizedBox(height: 20),
|
||||
app?.icon != null
|
||||
? Row(mainAxisAlignment: MainAxisAlignment.center, children: [
|
||||
GestureDetector(
|
||||
child: Image.memory(
|
||||
app!.icon!,
|
||||
height: 150,
|
||||
gaplessPlayback: true,
|
||||
),
|
||||
onTap: () => pm.openApp(app.app.id),
|
||||
)
|
||||
])
|
||||
: Container(),
|
||||
FutureBuilder(
|
||||
future: appsProvider.updateAppIcon(app?.app.id),
|
||||
builder: (ctx, val) {
|
||||
return app?.icon != null
|
||||
? Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: app == null
|
||||
? null
|
||||
: () => pm.openApp(app.app.id),
|
||||
child: Image.memory(
|
||||
app!.icon!,
|
||||
height: 150,
|
||||
gaplessPlayback: true,
|
||||
),
|
||||
)
|
||||
])
|
||||
: Container();
|
||||
}),
|
||||
const SizedBox(
|
||||
height: 25,
|
||||
),
|
||||
@@ -287,7 +315,7 @@ class _AppPageState extends State<AppPage> {
|
||||
? WebViewWidget(
|
||||
controller: WebViewController()
|
||||
..setJavaScriptMode(JavaScriptMode.unrestricted)
|
||||
..setBackgroundColor(Theme.of(context).colorScheme.background)
|
||||
..setBackgroundColor(Theme.of(context).colorScheme.surface)
|
||||
..setJavaScriptMode(JavaScriptMode.unrestricted)
|
||||
..setNavigationDelegate(
|
||||
NavigationDelegate(
|
||||
|
@@ -143,11 +143,14 @@ class AppsPageState extends State<AppsPage> {
|
||||
final GlobalKey<RefreshIndicatorState> _refreshIndicatorKey =
|
||||
GlobalKey<RefreshIndicatorState>();
|
||||
|
||||
late final ScrollController scrollController = ScrollController();
|
||||
|
||||
var sourceProvider = SourceProvider();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var appsProvider = context.watch<AppsProvider>();
|
||||
var settingsProvider = context.watch<SettingsProvider>();
|
||||
var sourceProvider = SourceProvider();
|
||||
var listedApps = appsProvider.getAppValues().toList();
|
||||
|
||||
refresh() {
|
||||
@@ -354,7 +357,11 @@ class AppsPageState extends State<AppsPage> {
|
||||
SliverFillRemaining(
|
||||
child: Center(
|
||||
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,
|
||||
textAlign: TextAlign.center,
|
||||
))),
|
||||
@@ -402,29 +409,36 @@ class AppsPageState extends State<AppsPage> {
|
||||
}
|
||||
|
||||
getAppIcon(int appIndex) {
|
||||
return listedApps[appIndex].icon != null
|
||||
? Image.memory(
|
||||
listedApps[appIndex].icon!,
|
||||
gaplessPlayback: true,
|
||||
)
|
||||
: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Transform(
|
||||
alignment: Alignment.center,
|
||||
transform: Matrix4.rotationZ(0.31),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(15),
|
||||
child: Image(
|
||||
image: const AssetImage(
|
||||
'assets/graphics/icon_small.png'),
|
||||
color: Colors.white.withOpacity(0.3),
|
||||
colorBlendMode: BlendMode.modulate,
|
||||
gaplessPlayback: true,
|
||||
),
|
||||
)),
|
||||
]);
|
||||
return FutureBuilder(
|
||||
future: appsProvider.updateAppIcon(listedApps[appIndex].app.id),
|
||||
builder: (ctx, val) {
|
||||
return listedApps[appIndex].icon != null
|
||||
? Image.memory(
|
||||
listedApps[appIndex].icon!,
|
||||
gaplessPlayback: true,
|
||||
)
|
||||
: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Transform(
|
||||
alignment: Alignment.center,
|
||||
transform: Matrix4.rotationZ(0.31),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(15),
|
||||
child: Image(
|
||||
image: const AssetImage(
|
||||
'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) {
|
||||
@@ -437,7 +451,7 @@ class AppsPageState extends State<AppsPage> {
|
||||
? tr('changes')
|
||||
: ''
|
||||
: DateFormat('yyyy-MM-dd')
|
||||
.format(listedApps[appIndex].app.releaseDate!);
|
||||
.format(listedApps[appIndex].app.releaseDate!.toLocal());
|
||||
}
|
||||
|
||||
getSingleAppHorizTile(int index) {
|
||||
@@ -452,7 +466,7 @@ class AppsPageState extends State<AppsPage> {
|
||||
hasUpdate ? getUpdateButton(index) : const SizedBox.shrink(),
|
||||
hasUpdate
|
||||
? const SizedBox(
|
||||
width: 10,
|
||||
width: 5,
|
||||
)
|
||||
: const SizedBox.shrink(),
|
||||
GestureDetector(
|
||||
@@ -503,7 +517,7 @@ class AppsPageState extends State<AppsPage> {
|
||||
);
|
||||
|
||||
var transparent =
|
||||
Theme.of(context).colorScheme.background.withAlpha(0).value;
|
||||
Theme.of(context).colorScheme.surface.withAlpha(0).value;
|
||||
List<double> stops = [
|
||||
...listedApps[index].app.categories.asMap().entries.map(
|
||||
(e) => ((e.key / (listedApps[index].app.categories.length - 1)))),
|
||||
@@ -882,11 +896,10 @@ class AppsPageState extends State<AppsPage> {
|
||||
onPressed: selectedAppIds.isEmpty
|
||||
? null
|
||||
: () {
|
||||
String urls =
|
||||
'<p>${tr('customLinkMessage')}:</p>\n\n<ul>\n';
|
||||
String urls = '';
|
||||
for (var a in selectedApps) {
|
||||
urls +=
|
||||
' <li><a href="obtainium://app/${Uri.encodeComponent(jsonEncode({
|
||||
'https://apps.obtainium.imranr.dev/redirect?r=obtainium://app/${Uri.encodeComponent(jsonEncode({
|
||||
'id': a.id,
|
||||
'url': a.url,
|
||||
'author': a.author,
|
||||
@@ -894,11 +907,10 @@ class AppsPageState extends State<AppsPage> {
|
||||
'preferredApkIndex':
|
||||
a.preferredApkIndex,
|
||||
'additionalSettings':
|
||||
jsonEncode(a.additionalSettings)
|
||||
}))}">${a.name}</a></li>\n';
|
||||
jsonEncode(a.additionalSettings),
|
||||
'overrideSource': a.overrideSource
|
||||
}))}\n\n';
|
||||
}
|
||||
urls +=
|
||||
'</ul>\n\n<p><a href="$obtainiumUrl">${tr('about')}</a></p>';
|
||||
Share.share(urls,
|
||||
subject:
|
||||
'Obtainium - ${tr('appsString')}');
|
||||
@@ -1089,11 +1101,17 @@ class AppsPageState extends State<AppsPage> {
|
||||
body: RefreshIndicator(
|
||||
key: _refreshIndicatorKey,
|
||||
onRefresh: refresh,
|
||||
child: CustomScrollView(slivers: <Widget>[
|
||||
CustomAppBar(title: tr('appsString')),
|
||||
...getLoadingWidgets(),
|
||||
getDisplayedList()
|
||||
])),
|
||||
child: Scrollbar(
|
||||
interactive: true,
|
||||
controller: scrollController,
|
||||
child: CustomScrollView(
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
controller: scrollController,
|
||||
slivers: <Widget>[
|
||||
CustomAppBar(title: tr('appsString')),
|
||||
...getLoadingWidgets(),
|
||||
getDisplayedList()
|
||||
]))),
|
||||
persistentFooterButtons: appsProvider.apps.isEmpty
|
||||
? null
|
||||
: [
|
||||
|
@@ -13,6 +13,7 @@ import 'package:obtainium/pages/import_export.dart';
|
||||
import 'package:obtainium/pages/settings.dart';
|
||||
import 'package:obtainium/providers/apps_provider.dart';
|
||||
import 'package:obtainium/providers/settings_provider.dart';
|
||||
import 'package:obtainium/providers/source_provider.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class HomePage extends StatefulWidget {
|
||||
@@ -102,13 +103,22 @@ class _HomePageState extends State<HomePage> {
|
||||
}) !=
|
||||
null) {
|
||||
// ignore: use_build_context_synchronously
|
||||
var result = await context.read<AppsProvider>().import(
|
||||
action == 'app'
|
||||
? '{ "apps": [$dataStr] }'
|
||||
: '{ "apps": $dataStr }');
|
||||
var appsProvider = context.read<AppsProvider>();
|
||||
var result = await appsProvider.import(action == 'app'
|
||||
? '{ "apps": [$dataStr] }'
|
||||
: '{ "apps": $dataStr }');
|
||||
// ignore: use_build_context_synchronously
|
||||
showMessage(
|
||||
tr('importedX', args: [plural('apps', result.key)]), context);
|
||||
tr('importedX', args: [plural('apps', result.key.length)]),
|
||||
context);
|
||||
await appsProvider
|
||||
.checkUpdates(specificIds: result.key.map((e) => e.id).toList())
|
||||
.catchError((e) {
|
||||
if (e is Map && e['errors'] is MultiAppMultiError) {
|
||||
showError(e['errors'].toString(), context);
|
||||
}
|
||||
return <App>[];
|
||||
});
|
||||
}
|
||||
} else {
|
||||
throw ObtainiumError(tr('unknown'));
|
||||
@@ -119,7 +129,7 @@ class _HomePageState extends State<HomePage> {
|
||||
}
|
||||
|
||||
// Check initial link if app was in cold state (terminated)
|
||||
final appLink = await _appLinks.getInitialAppLink();
|
||||
final appLink = await _appLinks.getInitialLink();
|
||||
if (appLink != null) {
|
||||
await interpretLink(appLink);
|
||||
}
|
||||
|
@@ -33,7 +33,7 @@ class _ImportExportPageState extends State<ImportExportPage> {
|
||||
var settingsProvider = context.watch<SettingsProvider>();
|
||||
|
||||
var outlineButtonStyle = ButtonStyle(
|
||||
shape: MaterialStateProperty.all(
|
||||
shape: WidgetStateProperty.all(
|
||||
StadiumBorder(
|
||||
side: BorderSide(
|
||||
width: 1,
|
||||
@@ -144,7 +144,7 @@ class _ImportExportPageState extends State<ImportExportPage> {
|
||||
appsProvider.addMissingCategories(settingsProvider);
|
||||
showMessage(
|
||||
'${tr('importedX', args: [
|
||||
plural('apps', value.key)
|
||||
plural('apps', value.key.length)
|
||||
])}${value.value ? ' + ${tr('settings')}' : ''}',
|
||||
context);
|
||||
});
|
||||
|
@@ -5,6 +5,7 @@ import 'package:flex_color_picker/flex_color_picker.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:obtainium/components/custom_app_bar.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/main.dart';
|
||||
import 'package:obtainium/providers/apps_provider.dart';
|
||||
@@ -26,20 +27,33 @@ class SettingsPage extends StatefulWidget {
|
||||
|
||||
class _SettingsPageState extends State<SettingsPage> {
|
||||
List<int> updateIntervalNodes = [
|
||||
15, 30, 60, 120, 180, 360, 720, 1440, 4320, 10080, 20160, 43200];
|
||||
15,
|
||||
30,
|
||||
60,
|
||||
120,
|
||||
180,
|
||||
360,
|
||||
720,
|
||||
1440,
|
||||
4320,
|
||||
10080,
|
||||
20160,
|
||||
43200
|
||||
];
|
||||
int updateInterval = 0;
|
||||
late SplineInterpolation updateIntervalInterpolator; // 🤓
|
||||
late SplineInterpolation updateIntervalInterpolator; // 🤓
|
||||
String updateIntervalLabel = tr('neverManualOnly');
|
||||
bool showIntervalLabel = true;
|
||||
final Map<ColorSwatch<Object>, String> colorsNameMap =
|
||||
<ColorSwatch<Object>, String> {
|
||||
<ColorSwatch<Object>, String>{
|
||||
ColorTools.createPrimarySwatch(obtainiumThemeColor): 'Obtainium'
|
||||
};
|
||||
|
||||
void initUpdateIntervalInterpolator() {
|
||||
List<InterpolationNode> nodes = [];
|
||||
for (final (index, element) in updateIntervalNodes.indexed) {
|
||||
nodes.add(InterpolationNode(x: index.toDouble()+1, y: element.toDouble()));
|
||||
nodes.add(
|
||||
InterpolationNode(x: index.toDouble() + 1, y: element.toDouble()));
|
||||
}
|
||||
updateIntervalInterpolator = SplineInterpolation(nodes: nodes);
|
||||
}
|
||||
@@ -69,7 +83,7 @@ class _SettingsPageState extends State<SettingsPage> {
|
||||
int valRounded = (valInterpolated / 30).floor() * 30;
|
||||
updateInterval = valRounded;
|
||||
updateIntervalLabel = plural('hour', valRounded / 60);
|
||||
} else if (valInterpolated < 7 * 24 * 60){
|
||||
} else if (valInterpolated < 7 * 24 * 60) {
|
||||
int valRounded = (valInterpolated / (12 * 60)).floor() * 12 * 60;
|
||||
updateInterval = valRounded;
|
||||
updateIntervalLabel = plural('day', valRounded / (24 * 60));
|
||||
@@ -88,41 +102,20 @@ class _SettingsPageState extends State<SettingsPage> {
|
||||
initUpdateIntervalInterpolator();
|
||||
processIntervalSliderValue(settingsProvider.updateIntervalSliderVal);
|
||||
|
||||
var themeDropdown = FutureBuilder(
|
||||
var followSystemThemeExplanation = FutureBuilder(
|
||||
builder: (ctx, val) {
|
||||
return DropdownButtonFormField(
|
||||
decoration: InputDecoration(labelText: tr('theme')),
|
||||
value: settingsProvider.theme,
|
||||
items: [
|
||||
DropdownMenuItem(
|
||||
value: ThemeSettings.light,
|
||||
child: Text(tr('light')),
|
||||
),
|
||||
DropdownMenuItem(
|
||||
value: ThemeSettings.dark,
|
||||
child: Text(tr('dark')),
|
||||
),
|
||||
if ((val.data?.version.sdkInt ?? 0) >= 29) DropdownMenuItem(
|
||||
value: ThemeSettings.system,
|
||||
child: Text(tr('followSystem')),
|
||||
)
|
||||
],
|
||||
onChanged: (value) {
|
||||
if (value != null) {
|
||||
settingsProvider.theme = value;
|
||||
}
|
||||
});
|
||||
return ((val.data?.version.sdkInt ?? 30) < 29)
|
||||
? Text(tr('followSystemThemeExplanation'),
|
||||
style: Theme.of(context).textTheme.labelSmall)
|
||||
: const SizedBox.shrink();
|
||||
},
|
||||
future: DeviceInfoPlugin().androidInfo
|
||||
);
|
||||
future: DeviceInfoPlugin().androidInfo);
|
||||
|
||||
Future<bool> colorPickerDialog() async {
|
||||
return ColorPicker(
|
||||
color: settingsProvider.themeColor,
|
||||
onColorChanged: (Color color) =>
|
||||
setState(() =>
|
||||
settingsProvider.themeColor = color
|
||||
),
|
||||
setState(() => settingsProvider.themeColor = color),
|
||||
actionButtons: const ColorPickerActionButtons(
|
||||
okButton: true,
|
||||
closeButton: true,
|
||||
@@ -155,19 +148,17 @@ class _SettingsPageState extends State<SettingsPage> {
|
||||
showColorName: true,
|
||||
materialNameTextStyle: Theme.of(context).textTheme.bodySmall,
|
||||
colorNameTextStyle: Theme.of(context).textTheme.bodySmall,
|
||||
copyPasteBehavior: const ColorPickerCopyPasteBehavior(longPressMenu: true),
|
||||
copyPasteBehavior:
|
||||
const ColorPickerCopyPasteBehavior(longPressMenu: true),
|
||||
).showPickerDialog(
|
||||
context,
|
||||
transitionBuilder: (BuildContext context,
|
||||
Animation<double> a1, Animation<double> a2, Widget widget) {
|
||||
transitionBuilder: (BuildContext context, Animation<double> a1,
|
||||
Animation<double> a2, Widget widget) {
|
||||
final double curvedValue = Curves.easeInCubic.transform(a1.value);
|
||||
return Transform(
|
||||
alignment: Alignment.center,
|
||||
transform: Matrix4.diagonal3Values(curvedValue, curvedValue, 1),
|
||||
child: Opacity(
|
||||
opacity: curvedValue,
|
||||
child: widget
|
||||
),
|
||||
child: Opacity(opacity: curvedValue, child: widget),
|
||||
);
|
||||
},
|
||||
transitionDuration: const Duration(milliseconds: 250),
|
||||
@@ -175,46 +166,44 @@ class _SettingsPageState extends State<SettingsPage> {
|
||||
}
|
||||
|
||||
var colorPicker = ListTile(
|
||||
dense: true,
|
||||
contentPadding: EdgeInsets.zero,
|
||||
title: Text(tr('selectX', args: [tr('colour')])),
|
||||
subtitle: Text("${ColorTools.nameThatColor(settingsProvider.themeColor)} "
|
||||
"(${ColorTools.materialNameAndCode(settingsProvider.themeColor,
|
||||
colorSwatchNameMap: colorsNameMap)})"),
|
||||
trailing: ColorIndicator(
|
||||
width: 40,
|
||||
height: 40,
|
||||
borderRadius: 20,
|
||||
color: settingsProvider.themeColor,
|
||||
onSelectFocus: false,
|
||||
onSelect: () async {
|
||||
final Color colorBeforeDialog = settingsProvider.themeColor;
|
||||
if (!(await colorPickerDialog())) {
|
||||
setState(() {
|
||||
settingsProvider.themeColor = colorBeforeDialog;
|
||||
});
|
||||
}
|
||||
}
|
||||
)
|
||||
);
|
||||
dense: true,
|
||||
contentPadding: EdgeInsets.zero,
|
||||
title: Text(tr('selectX', args: [tr('colour')])),
|
||||
subtitle: Text(
|
||||
"${ColorTools.nameThatColor(settingsProvider.themeColor)} "
|
||||
"(${ColorTools.materialNameAndCode(settingsProvider.themeColor, colorSwatchNameMap: colorsNameMap)})"),
|
||||
trailing: ColorIndicator(
|
||||
width: 40,
|
||||
height: 40,
|
||||
borderRadius: 20,
|
||||
color: settingsProvider.themeColor,
|
||||
onSelectFocus: false,
|
||||
onSelect: () async {
|
||||
final Color colorBeforeDialog = settingsProvider.themeColor;
|
||||
if (!(await colorPickerDialog())) {
|
||||
setState(() {
|
||||
settingsProvider.themeColor = colorBeforeDialog;
|
||||
});
|
||||
}
|
||||
}));
|
||||
|
||||
var useMaterialThemeSwitch = FutureBuilder(
|
||||
builder: (ctx, val) {
|
||||
return ((val.data?.version.sdkInt ?? 0) >= 31) ?
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Flexible(child: Text(tr('useMaterialYou'))),
|
||||
Switch(
|
||||
value: settingsProvider.useMaterialYou,
|
||||
onChanged: (value) {
|
||||
settingsProvider.useMaterialYou = value;
|
||||
})
|
||||
],
|
||||
) : const SizedBox.shrink();
|
||||
return ((val.data?.version.sdkInt ?? 0) >= 31)
|
||||
? Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Flexible(child: Text(tr('useMaterialYou'))),
|
||||
Switch(
|
||||
value: settingsProvider.useMaterialYou,
|
||||
onChanged: (value) {
|
||||
settingsProvider.useMaterialYou = value;
|
||||
})
|
||||
],
|
||||
)
|
||||
: const SizedBox.shrink();
|
||||
},
|
||||
future: DeviceInfoPlugin().androidInfo
|
||||
);
|
||||
future: DeviceInfoPlugin().androidInfo);
|
||||
|
||||
var sortDropdown = DropdownButtonFormField(
|
||||
isExpanded: true,
|
||||
@@ -361,13 +350,20 @@ class _SettingsPageState extends State<SettingsPage> {
|
||||
),
|
||||
//intervalDropdown,
|
||||
height16,
|
||||
if (showIntervalLabel) SizedBox(
|
||||
child: Text("${tr('bgUpdateCheckInterval')}: $updateIntervalLabel")
|
||||
) else const SizedBox(height: 16),
|
||||
if (showIntervalLabel)
|
||||
SizedBox(
|
||||
child: Text(
|
||||
"${tr('bgUpdateCheckInterval')}: $updateIntervalLabel"))
|
||||
else
|
||||
const SizedBox(height: 16),
|
||||
intervalSlider,
|
||||
FutureBuilder(
|
||||
builder: (ctx, val) {
|
||||
return ((val.data?.version.sdkInt ?? 0) >= 30) || settingsProvider.useShizuku
|
||||
return (settingsProvider.updateInterval >
|
||||
0) &&
|
||||
(((val.data?.version.sdkInt ?? 0) >=
|
||||
30) ||
|
||||
settingsProvider.useShizuku)
|
||||
? Column(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
@@ -509,33 +505,33 @@ class _SettingsPageState extends State<SettingsPage> {
|
||||
children: [
|
||||
Flexible(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(tr(
|
||||
'beforeNewInstallsShareToAppVerifier')),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
launchUrlString(
|
||||
'https://github.com/soupslurpr/AppVerifier',
|
||||
mode: LaunchMode
|
||||
.externalApplication);
|
||||
},
|
||||
child: Text(
|
||||
tr('about'),
|
||||
style: const TextStyle(
|
||||
decoration:
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(tr(
|
||||
'beforeNewInstallsShareToAppVerifier')),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
launchUrlString(
|
||||
'https://github.com/soupslurpr/AppVerifier',
|
||||
mode: LaunchMode
|
||||
.externalApplication);
|
||||
},
|
||||
child: Text(
|
||||
tr('about'),
|
||||
style: const TextStyle(
|
||||
decoration:
|
||||
TextDecoration.underline,
|
||||
fontSize: 12),
|
||||
)),
|
||||
],
|
||||
)),
|
||||
fontSize: 12),
|
||||
)),
|
||||
],
|
||||
)),
|
||||
Switch(
|
||||
value: settingsProvider
|
||||
.beforeNewInstallsShareToAppVerifier,
|
||||
onChanged: (value) {
|
||||
settingsProvider
|
||||
.beforeNewInstallsShareToAppVerifier =
|
||||
.beforeNewInstallsShareToAppVerifier =
|
||||
value;
|
||||
})
|
||||
],
|
||||
@@ -549,17 +545,31 @@ class _SettingsPageState extends State<SettingsPage> {
|
||||
value: settingsProvider.useShizuku,
|
||||
onChanged: (useShizuku) {
|
||||
if (useShizuku) {
|
||||
ShizukuApkInstaller.checkPermission().then((resCode) {
|
||||
settingsProvider.useShizuku = resCode!.startsWith('granted');
|
||||
switch(resCode){
|
||||
ShizukuApkInstaller.checkPermission()
|
||||
.then((resCode) {
|
||||
settingsProvider.useShizuku =
|
||||
resCode!.startsWith('granted');
|
||||
switch (resCode) {
|
||||
case 'binder_not_found':
|
||||
showError(ObtainiumError(tr('shizukuBinderNotFound')), context);
|
||||
showError(
|
||||
ObtainiumError(tr(
|
||||
'shizukuBinderNotFound')),
|
||||
context);
|
||||
case 'old_shizuku':
|
||||
showError(ObtainiumError(tr('shizukuOld')), context);
|
||||
showError(
|
||||
ObtainiumError(
|
||||
tr('shizukuOld')),
|
||||
context);
|
||||
case 'old_android_with_adb':
|
||||
showError(ObtainiumError(tr('shizukuOldAndroidWithADB')), context);
|
||||
showError(
|
||||
ObtainiumError(tr(
|
||||
'shizukuOldAndroidWithADB')),
|
||||
context);
|
||||
case 'denied':
|
||||
showError(ObtainiumError(tr('cancelled')), context);
|
||||
showError(
|
||||
ObtainiumError(
|
||||
tr('cancelled')),
|
||||
context);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
@@ -583,20 +593,47 @@ class _SettingsPageState extends State<SettingsPage> {
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context).colorScheme.primary),
|
||||
),
|
||||
themeDropdown,
|
||||
height16,
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Flexible(child: Text(tr('useBlackTheme'))),
|
||||
Switch(
|
||||
value: settingsProvider.useBlackTheme,
|
||||
onChanged: (value) {
|
||||
settingsProvider.useBlackTheme = value;
|
||||
})
|
||||
],
|
||||
),
|
||||
DropdownButtonFormField(
|
||||
decoration:
|
||||
InputDecoration(labelText: tr('theme')),
|
||||
value: settingsProvider.theme,
|
||||
items: [
|
||||
DropdownMenuItem(
|
||||
value: ThemeSettings.system,
|
||||
child: Text(tr('followSystem')),
|
||||
),
|
||||
DropdownMenuItem(
|
||||
value: ThemeSettings.light,
|
||||
child: Text(tr('light')),
|
||||
),
|
||||
DropdownMenuItem(
|
||||
value: ThemeSettings.dark,
|
||||
child: Text(tr('dark')),
|
||||
)
|
||||
],
|
||||
onChanged: (value) {
|
||||
if (value != null) {
|
||||
settingsProvider.theme = value;
|
||||
}
|
||||
}),
|
||||
height8,
|
||||
if (settingsProvider.theme == ThemeSettings.system)
|
||||
followSystemThemeExplanation,
|
||||
height16,
|
||||
if (settingsProvider.theme != ThemeSettings.light)
|
||||
Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Flexible(child: Text(tr('useBlackTheme'))),
|
||||
Switch(
|
||||
value: settingsProvider.useBlackTheme,
|
||||
onChanged: (value) {
|
||||
settingsProvider.useBlackTheme =
|
||||
value;
|
||||
})
|
||||
]),
|
||||
height8,
|
||||
useMaterialThemeSwitch,
|
||||
if (!settingsProvider.useMaterialYou) colorPicker,
|
||||
Row(
|
||||
@@ -616,28 +653,39 @@ class _SettingsPageState extends State<SettingsPage> {
|
||||
builder: (ctx, val) {
|
||||
return (val.data?.version.sdkInt ?? 0) >= 34
|
||||
? Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
height16,
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Flexible(child: Text(tr('useSystemFont'))),
|
||||
Switch(
|
||||
value: settingsProvider.useSystemFont,
|
||||
onChanged: (useSystemFont) {
|
||||
if (useSystemFont) {
|
||||
NativeFeatures.loadSystemFont().then((val) {
|
||||
settingsProvider.useSystemFont = true;
|
||||
});
|
||||
} else {
|
||||
settingsProvider.useSystemFont = false;
|
||||
}
|
||||
})
|
||||
]
|
||||
)
|
||||
]
|
||||
)
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
children: [
|
||||
height16,
|
||||
Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment
|
||||
.spaceBetween,
|
||||
children: [
|
||||
Flexible(
|
||||
child: Text(tr(
|
||||
'useSystemFont'))),
|
||||
Switch(
|
||||
value: settingsProvider
|
||||
.useSystemFont,
|
||||
onChanged:
|
||||
(useSystemFont) {
|
||||
if (useSystemFont) {
|
||||
NativeFeatures
|
||||
.loadSystemFont()
|
||||
.then((val) {
|
||||
settingsProvider
|
||||
.useSystemFont =
|
||||
true;
|
||||
});
|
||||
} else {
|
||||
settingsProvider
|
||||
.useSystemFont =
|
||||
false;
|
||||
}
|
||||
})
|
||||
])
|
||||
])
|
||||
: const SizedBox.shrink();
|
||||
},
|
||||
future: DeviceInfoPlugin().androidInfo),
|
||||
@@ -793,17 +841,31 @@ class _SettingsPageState extends State<SettingsPage> {
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
TextButton.icon(
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
launchUrlString(settingsProvider.sourceUrl,
|
||||
mode: LaunchMode.externalApplication);
|
||||
},
|
||||
icon: const Icon(Icons.code),
|
||||
label: Text(
|
||||
tr('appSource'),
|
||||
),
|
||||
tooltip: tr('appSource'),
|
||||
),
|
||||
TextButton.icon(
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
launchUrlString('${settingsProvider.sourceUrl}/wiki',
|
||||
mode: LaunchMode.externalApplication);
|
||||
},
|
||||
icon: const Icon(Icons.help_outline_rounded),
|
||||
tooltip: tr('wiki'),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
launchUrlString('https://apps.obtainium.imranr.dev/',
|
||||
mode: LaunchMode.externalApplication);
|
||||
},
|
||||
icon: const Icon(Icons.apps_rounded),
|
||||
tooltip: tr('crowdsourcedConfigsLabel'),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
context.read<LogsProvider>().get().then((logs) {
|
||||
if (logs.isEmpty) {
|
||||
@@ -819,7 +881,7 @@ class _SettingsPageState extends State<SettingsPage> {
|
||||
});
|
||||
},
|
||||
icon: const Icon(Icons.bug_report_outlined),
|
||||
label: Text(tr('appLogs'))),
|
||||
tooltip: tr('appLogs'))
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
@@ -884,6 +946,25 @@ class _LogsDialogState extends State<LogsDialog> {
|
||||
],
|
||||
),
|
||||
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(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
|
@@ -142,19 +142,20 @@ List<MapEntry<String, int>> moveStrToEndMapEntryWithCount(
|
||||
return arr;
|
||||
}
|
||||
|
||||
Future<File> downloadFileWithRetry(
|
||||
String url, String fileNameNoExt, Function? onProgress, String destDir,
|
||||
Future<File> downloadFileWithRetry(String url, String fileName,
|
||||
bool fileNameHasExt, Function? onProgress, String destDir,
|
||||
{bool useExisting = true,
|
||||
Map<String, String>? headers,
|
||||
int retries = 3}) async {
|
||||
try {
|
||||
return await downloadFile(url, fileNameNoExt, onProgress, destDir,
|
||||
return await downloadFile(
|
||||
url, fileName, fileNameHasExt, onProgress, destDir,
|
||||
useExisting: useExisting, headers: headers);
|
||||
} catch (e) {
|
||||
if (retries > 0 && e is ClientException) {
|
||||
await Future.delayed(const Duration(seconds: 5));
|
||||
return await downloadFileWithRetry(
|
||||
url, fileNameNoExt, onProgress, destDir,
|
||||
url, fileName, fileNameHasExt, onProgress, destDir,
|
||||
useExisting: useExisting, headers: headers, retries: (retries - 1));
|
||||
} else {
|
||||
rethrow;
|
||||
@@ -201,8 +202,8 @@ Future<String> checkPartialDownloadHash(String url, int bytesToGrab,
|
||||
return hashListOfLists(bytes);
|
||||
}
|
||||
|
||||
Future<File> downloadFile(
|
||||
String url, String fileNameNoExt, Function? onProgress, String destDir,
|
||||
Future<File> downloadFile(String url, String fileName, bool fileNameHasExt,
|
||||
Function? onProgress, String destDir,
|
||||
{bool useExisting = true, Map<String, String>? headers}) async {
|
||||
// Send the initial request but cancel it as soon as you have the headers
|
||||
var reqHeaders = headers ?? {};
|
||||
@@ -222,7 +223,12 @@ Future<File> downloadFile(
|
||||
if (url.toLowerCase().endsWith('.apk') && ext != 'apk') {
|
||||
ext = 'apk';
|
||||
}
|
||||
File downloadedFile = File('$destDir/$fileNameNoExt.$ext');
|
||||
fileName = fileName.split('/').last; // Ensure the fileName is a file name
|
||||
File downloadedFile = File('$destDir/$fileName.$ext');
|
||||
if (fileNameHasExt) {
|
||||
// If the user says the filename already has an ext, ignore whatever you inferred from above
|
||||
downloadedFile = File('$destDir/$fileName');
|
||||
}
|
||||
|
||||
bool rangeFeatureEnabled = false;
|
||||
if (resHeaders['accept-ranges']?.isNotEmpty == true) {
|
||||
@@ -323,6 +329,10 @@ Future<Map<String, String>> getHeaders(String url,
|
||||
return returnHeaders;
|
||||
}
|
||||
|
||||
Future<List<PackageInfo>> getAllInstalledInfo() async {
|
||||
return await pm.getInstalledPackages() ?? [];
|
||||
}
|
||||
|
||||
Future<PackageInfo?> getInstalledInfo(String? packageName,
|
||||
{bool printErr = true}) async {
|
||||
if (packageName != null) {
|
||||
@@ -358,7 +368,9 @@ class AppsProvider with ChangeNotifier {
|
||||
foregroundStream = FGBGEvents.stream.asBroadcastStream();
|
||||
foregroundSubscription = foregroundStream?.listen((event) async {
|
||||
isForeground = event == FGBGType.foreground;
|
||||
if (isForeground) loadApps();
|
||||
if (isForeground) {
|
||||
await loadApps();
|
||||
}
|
||||
});
|
||||
() async {
|
||||
await settingsProvider.initializeSettings();
|
||||
@@ -415,7 +427,8 @@ class AppsProvider with ChangeNotifier {
|
||||
}
|
||||
|
||||
Future<Object> downloadApp(App app, BuildContext? context,
|
||||
{NotificationsProvider? notificationsProvider}) async {
|
||||
{NotificationsProvider? notificationsProvider,
|
||||
bool useExisting = true}) async {
|
||||
var notifId = DownloadNotification(app.finalName, 0).id;
|
||||
if (apps[app.id] != null) {
|
||||
apps[app.id]!.downloadProgress = 0;
|
||||
@@ -435,8 +448,8 @@ class AppsProvider with ChangeNotifier {
|
||||
var headers = await source.getRequestHeaders(app.additionalSettings,
|
||||
forAPKDownload: true);
|
||||
var downloadedFile = await downloadFileWithRetry(
|
||||
downloadUrl, fileNameNoExt,
|
||||
headers: headers, (double? progress) {
|
||||
downloadUrl, fileNameNoExt, false, headers: headers,
|
||||
(double? progress) {
|
||||
int? prog = progress?.ceil();
|
||||
if (apps[app.id] != null) {
|
||||
apps[app.id]!.downloadProgress = progress;
|
||||
@@ -447,7 +460,7 @@ class AppsProvider with ChangeNotifier {
|
||||
notificationsProvider?.notify(notif);
|
||||
}
|
||||
prevProg = prog;
|
||||
}, APKDir.path);
|
||||
}, APKDir.path, useExisting: useExisting);
|
||||
// Set to 90 for remaining steps, will make null in 'finally'
|
||||
if (apps[app.id] != null) {
|
||||
apps[app.id]!.downloadProgress = -1;
|
||||
@@ -525,10 +538,11 @@ class AppsProvider with ChangeNotifier {
|
||||
?.installingPackageName
|
||||
: (await pm.getInstallerPackageName(packageName: app.id));
|
||||
} catch (e) {
|
||||
return false; // App probably not installed
|
||||
return false; // App probably not installed
|
||||
}
|
||||
|
||||
int? targetSDK = (await getInstalledInfo(app.id))?.applicationInfo?.targetSdkVersion;
|
||||
int? targetSDK =
|
||||
(await getInstalledInfo(app.id))?.applicationInfo?.targetSdkVersion;
|
||||
// The APK should target a new enough API
|
||||
// https://developer.android.com/reference/android/content/pm/PackageInstaller.SessionParams#setRequireUserAction(int)
|
||||
if (!(targetSDK != null && targetSDK >= (osInfo.version.sdkInt - 3))) {
|
||||
@@ -571,7 +585,8 @@ class AppsProvider with ChangeNotifier {
|
||||
|
||||
Future<bool> installXApkDir(
|
||||
DownloadedXApkDir dir, BuildContext? firstTimeWithContext,
|
||||
{bool needsBGWorkaround = false, bool shizukuPretendToBeGooglePlay = false}) async {
|
||||
{bool needsBGWorkaround = false,
|
||||
bool shizukuPretendToBeGooglePlay = false}) async {
|
||||
// We don't know which APKs in an XAPK are supported by the user's device
|
||||
// So we try installing all of them and assume success if at least one installed
|
||||
// If 0 APKs installed, throw the first install error encountered
|
||||
@@ -610,7 +625,8 @@ class AppsProvider with ChangeNotifier {
|
||||
|
||||
Future<bool> installApk(
|
||||
DownloadedApk file, BuildContext? firstTimeWithContext,
|
||||
{bool needsBGWorkaround = false, bool shizukuPretendToBeGooglePlay = false}) async {
|
||||
{bool needsBGWorkaround = false,
|
||||
bool shizukuPretendToBeGooglePlay = false}) async {
|
||||
if (firstTimeWithContext != null &&
|
||||
settingsProvider.beforeNewInstallsShareToAppVerifier &&
|
||||
(await getInstalledInfo('dev.soupslurpr.appverifier')) != null) {
|
||||
@@ -651,7 +667,8 @@ class AppsProvider with ChangeNotifier {
|
||||
}
|
||||
int? code;
|
||||
if (!settingsProvider.useShizuku) {
|
||||
code = await AndroidPackageInstaller.installApk(apkFilePath: file.file.path);
|
||||
code =
|
||||
await AndroidPackageInstaller.installApk(apkFilePath: file.file.path);
|
||||
} else {
|
||||
code = await ShizukuApkInstaller.installAPK(file.file.uri.toString(),
|
||||
shizukuPretendToBeGooglePlay ? "com.android.vending" : "");
|
||||
@@ -700,7 +717,8 @@ class AppsProvider with ChangeNotifier {
|
||||
}
|
||||
|
||||
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;
|
||||
if (pickAnyAsset) {
|
||||
urlsToSelectFrom = [...urlsToSelectFrom, ...app.otherAssetUrls];
|
||||
@@ -711,7 +729,8 @@ class AppsProvider with ChangeNotifier {
|
||||
// get device supported architecture
|
||||
List<String> archs = (await DeviceInfoPlugin().androidInfo).supportedAbis;
|
||||
|
||||
if (urlsToSelectFrom.length > 1 && context != null) {
|
||||
if ((urlsToSelectFrom.length > 1 || evenIfSingleChoice) &&
|
||||
context != null) {
|
||||
appFileUrl = await showDialog(
|
||||
// ignore: use_build_context_synchronously
|
||||
context: context,
|
||||
@@ -756,7 +775,8 @@ class AppsProvider with ChangeNotifier {
|
||||
Future<List<String>> downloadAndInstallLatestApps(
|
||||
List<String> appIds, BuildContext? context,
|
||||
{NotificationsProvider? notificationsProvider,
|
||||
bool forceParallelDownloads = false}) async {
|
||||
bool forceParallelDownloads = false,
|
||||
bool useExisting = true}) async {
|
||||
notificationsProvider =
|
||||
notificationsProvider ?? context?.read<NotificationsProvider>();
|
||||
List<String> appsToInstall = [];
|
||||
@@ -808,27 +828,88 @@ class AppsProvider with ChangeNotifier {
|
||||
appsToInstall =
|
||||
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 {
|
||||
var downloadedArtifact =
|
||||
// ignore: use_build_context_synchronously
|
||||
await downloadApp(apps[id]!.app, context,
|
||||
notificationsProvider: notificationsProvider);
|
||||
DownloadedApk? downloadedFile;
|
||||
DownloadedXApkDir? downloadedDir;
|
||||
notificationsProvider: notificationsProvider,
|
||||
useExisting: useExisting);
|
||||
if (downloadedArtifact is DownloadedApk) {
|
||||
downloadedFile = downloadedArtifact;
|
||||
} else {
|
||||
downloadedDir = downloadedArtifact as DownloadedXApkDir;
|
||||
}
|
||||
id = downloadedFile?.appId ?? downloadedDir!.appId;
|
||||
bool willBeSilent = await canInstallSilently(apps[id]!.app);
|
||||
willBeSilent = await canInstallSilently(apps[id]!.app);
|
||||
if (!settingsProvider.useShizuku) {
|
||||
if (!(await settingsProvider.getInstallPermission(enforce: false))) {
|
||||
throw ObtainiumError(tr('cancelled'));
|
||||
}
|
||||
} else {
|
||||
switch((await ShizukuApkInstaller.checkPermission())!){
|
||||
switch ((await ShizukuApkInstaller.checkPermission())!) {
|
||||
case 'binder_not_found':
|
||||
throw ObtainiumError(tr('shizukuBinderNotFound'));
|
||||
case 'old_shizuku':
|
||||
@@ -839,69 +920,37 @@ class AppsProvider with ChangeNotifier {
|
||||
throw ObtainiumError(tr('cancelled'));
|
||||
}
|
||||
}
|
||||
if (!willBeSilent && context != null) {
|
||||
if (!willBeSilent && context != null && !settingsProvider.useShizuku) {
|
||||
// ignore: use_build_context_synchronously
|
||||
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) {
|
||||
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) {
|
||||
for (var id in appsToInstall) {
|
||||
await updateFn(id);
|
||||
downloadResults.add(await downloadFn(id));
|
||||
}
|
||||
} else {
|
||||
List<String> ids = await Future.wait(
|
||||
appsToInstall.map((id) => updateFn(id, skipInstalls: true)));
|
||||
for (var id in ids) {
|
||||
if (!errors.appIdNames.containsKey(id)) {
|
||||
await updateFn(id);
|
||||
}
|
||||
downloadResults = await Future.wait(
|
||||
appsToInstall.map((id) => downloadFn(id, skipInstalls: true)));
|
||||
}
|
||||
for (var res in downloadResults) {
|
||||
if (!errors.appIdNames.containsKey(res['id'])) {
|
||||
await installFn(
|
||||
res['id'] as String,
|
||||
res['willBeSilent'] as bool,
|
||||
res['downloadedFile'] as DownloadedApk?,
|
||||
res['downloadedDir'] as DownloadedXApkDir?);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -926,7 +975,8 @@ class AppsProvider with ChangeNotifier {
|
||||
if (apps[id]!.app.apkUrls.isNotEmpty ||
|
||||
apps[id]!.app.otherAssetUrls.isNotEmpty) {
|
||||
// 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) {
|
||||
filesToDownload.add(MapEntry(fileUrl, apps[id]!.app));
|
||||
@@ -950,15 +1000,8 @@ class AppsProvider with ChangeNotifier {
|
||||
if (!downloadsAccessible && exportDir != null) {
|
||||
downloadPath = exportDir.path;
|
||||
}
|
||||
await downloadFile(
|
||||
fileUrl.value,
|
||||
fileUrl.key
|
||||
.split('.')
|
||||
.reversed
|
||||
.toList()
|
||||
.sublist(1)
|
||||
.reversed
|
||||
.join('.'), (double? progress) {
|
||||
await downloadFile(fileUrl.value, fileUrl.key, true,
|
||||
(double? progress) {
|
||||
notificationsProvider
|
||||
.notify(DownloadNotification(fileUrl.key, progress?.ceil() ?? 0));
|
||||
}, downloadPath,
|
||||
@@ -1126,17 +1169,6 @@ class AppsProvider with ChangeNotifier {
|
||||
: 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 {
|
||||
while (loadingApps) {
|
||||
await Future.delayed(const Duration(microseconds: 1));
|
||||
@@ -1145,67 +1177,75 @@ class AppsProvider with ChangeNotifier {
|
||||
notifyListeners();
|
||||
var sp = SourceProvider();
|
||||
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()
|
||||
.where((item) => item.path.toLowerCase().endsWith('.json'))
|
||||
.where((item) =>
|
||||
singleId == null ||
|
||||
item.path.split('/').last.toLowerCase() ==
|
||||
'${singleId.toLowerCase()}.json')
|
||||
.map((e) {
|
||||
try {
|
||||
return App.fromJson(jsonDecode(File(e.path).readAsStringSync()));
|
||||
} catch (err) {
|
||||
if (err is FormatException) {
|
||||
logs.add('Corrupt JSON when loading App (will be ignored): $e');
|
||||
e.renameSync('${e.path}.corrupt');
|
||||
} else {
|
||||
rethrow;
|
||||
.map((item) async {
|
||||
App? app;
|
||||
if (item.path.toLowerCase().endsWith('.json') &&
|
||||
(singleId == null ||
|
||||
item.path.split('/').last.toLowerCase() ==
|
||||
'${singleId.toLowerCase()}.json')) {
|
||||
try {
|
||||
app = App.fromJson(jsonDecode(File(item.path).readAsStringSync()));
|
||||
} catch (err) {
|
||||
if (err is FormatException) {
|
||||
logs.add('Corrupt JSON when loading App (will be ignored): $e');
|
||||
item.renameSync('${item.path}.corrupt');
|
||||
} else {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
||||
}).toList();
|
||||
for (var app in newApps) {
|
||||
// Put Apps into memory to list them (fast)
|
||||
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 getting the app's source to ensure no invalid apps get loaded
|
||||
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(
|
||||
app.id,
|
||||
(value) => AppInMemory(
|
||||
app, value.downloadProgress, value.installedInfo, value.icon),
|
||||
ifAbsent: () => AppInMemory(app, null, null, null));
|
||||
app!, value.downloadProgress, installedInfo, value.icon),
|
||||
ifAbsent: () => AppInMemory(app!, null, installedInfo, null));
|
||||
notifyListeners();
|
||||
} catch (e) {
|
||||
errors.add([app.id, app.finalName, e.toString()]);
|
||||
errors.add([app!.id, app.finalName, e.toString()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
notifyListeners();
|
||||
}));
|
||||
if (errors.isNotEmpty) {
|
||||
removeApps(errors.map((e) => e[0]).toList());
|
||||
NotificationsProvider().notify(
|
||||
AppsRemovedNotification(errors.map((e) => [e[1], e[2]]).toList()));
|
||||
}
|
||||
// Get install status and other OS info for each App (slow)
|
||||
await Future.wait(apps.values.map((app) {
|
||||
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
|
||||
// Delete externally uninstalled Apps if needed
|
||||
if (removedAppIds.isNotEmpty) {
|
||||
if (removedAppIds.isNotEmpty) {
|
||||
if (settingsProvider.removeOnExternalUninstall) {
|
||||
await removeApps(removedAppIds);
|
||||
@@ -1216,11 +1256,27 @@ class AppsProvider with ChangeNotifier {
|
||||
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,
|
||||
{bool attemptToCorrectInstallStatus = true,
|
||||
bool onlyIfExists = true}) async {
|
||||
attemptToCorrectInstallStatus = attemptToCorrectInstallStatus;
|
||||
for (var a in apps) {
|
||||
await Future.wait(apps.map((a) async {
|
||||
var app = a.deepCopy();
|
||||
PackageInfo? info = await getInstalledInfo(app.id);
|
||||
var icon = await info?.applicationInfo?.getAppIcon();
|
||||
@@ -1242,14 +1298,14 @@ class AppsProvider with ChangeNotifier {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
notifyListeners();
|
||||
export(isAuto: true);
|
||||
}
|
||||
|
||||
Future<void> removeApps(List<String> appIds) async {
|
||||
var apkFiles = APKDir.listSync();
|
||||
for (var appId in appIds) {
|
||||
await Future.wait(appIds.map((appId) async {
|
||||
File file = File('${(await getAppsDir()).path}/$appId.json');
|
||||
if (file.existsSync()) {
|
||||
file.deleteSync(recursive: true);
|
||||
@@ -1263,7 +1319,7 @@ class AppsProvider with ChangeNotifier {
|
||||
if (apps.containsKey(appId)) {
|
||||
apps.remove(appId);
|
||||
}
|
||||
}
|
||||
}));
|
||||
if (appIds.isNotEmpty) {
|
||||
notifyListeners();
|
||||
export(isAuto: true);
|
||||
@@ -1498,7 +1554,7 @@ class AppsProvider with ChangeNotifier {
|
||||
return returnPath;
|
||||
}
|
||||
|
||||
Future<MapEntry<int, bool>> import(String appsJSON) async {
|
||||
Future<MapEntry<List<App>, bool>> import(String appsJSON) async {
|
||||
var decodedJSON = jsonDecode(appsJSON);
|
||||
var newFormat = decodedJSON is! List;
|
||||
List<App> importedApps =
|
||||
@@ -1522,6 +1578,8 @@ class AppsProvider with ChangeNotifier {
|
||||
settingsMap.forEach((key, value) {
|
||||
if (value is int) {
|
||||
settingsProvider.prefs?.setInt(key, value);
|
||||
} else if (value is double) {
|
||||
settingsProvider.prefs?.setDouble(key, value);
|
||||
} else if (value is bool) {
|
||||
settingsProvider.prefs?.setBool(key, value);
|
||||
} else if (value is List) {
|
||||
@@ -1532,8 +1590,8 @@ class AppsProvider with ChangeNotifier {
|
||||
}
|
||||
});
|
||||
}
|
||||
return MapEntry<int, bool>(
|
||||
importedApps.length, newFormat && decodedJSON['settings'] != null);
|
||||
return MapEntry<List<App>, bool>(
|
||||
importedApps, newFormat && decodedJSON['settings'] != null);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -1595,7 +1653,9 @@ class _AppFilePickerState extends State<AppFilePicker> {
|
||||
? tr('selectX', args: [tr('releaseAsset').toLowerCase()])
|
||||
: tr('pickAnAPK')),
|
||||
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),
|
||||
...urlsToSelectFrom.map(
|
||||
(u) => RadioListTile<String>(
|
||||
|
@@ -19,7 +19,7 @@ String obtainiumId = 'dev.imranr.obtainium';
|
||||
String obtainiumUrl = 'https://github.com/ImranR98/Obtainium';
|
||||
Color obtainiumThemeColor = const Color(0xFF6438B5);
|
||||
|
||||
enum ThemeSettings { light, dark, system }
|
||||
enum ThemeSettings { system, light, dark }
|
||||
|
||||
enum SortColumnSettings { added, nameAuthor, authorName, releaseDate }
|
||||
|
||||
@@ -59,7 +59,7 @@ class SettingsProvider with ChangeNotifier {
|
||||
|
||||
ThemeSettings get theme {
|
||||
return ThemeSettings
|
||||
.values[prefs?.getInt('theme') ?? ThemeSettings.light.index];
|
||||
.values[prefs?.getInt('theme') ?? ThemeSettings.system.index];
|
||||
}
|
||||
|
||||
set theme(ThemeSettings t) {
|
||||
|
@@ -354,11 +354,15 @@ preStandardizeUrl(String url) {
|
||||
url.toLowerCase().indexOf('https://') != 0) {
|
||||
url = 'https://$url';
|
||||
}
|
||||
var uri = Uri.tryParse(url);
|
||||
var trailingSlash = (uri?.path.endsWith('/') ?? false) &&
|
||||
(uri?.queryParameters.isEmpty ?? false);
|
||||
url = url
|
||||
.split('/')
|
||||
.where((e) => e.isNotEmpty)
|
||||
.join('/')
|
||||
.replaceFirst(':/', '://');
|
||||
.split('/')
|
||||
.where((e) => e.isNotEmpty)
|
||||
.join('/')
|
||||
.replaceFirst(':/', '://') +
|
||||
(trailingSlash ? '/' : '');
|
||||
return url;
|
||||
}
|
||||
|
||||
@@ -461,6 +465,10 @@ abstract class AppSource {
|
||||
}
|
||||
}
|
||||
|
||||
void runOnAddAppInputChange(String inputUrl) {
|
||||
//
|
||||
}
|
||||
|
||||
String sourceSpecificStandardizeURL(String url) {
|
||||
throw NotImplementedError();
|
||||
}
|
||||
@@ -523,8 +531,7 @@ abstract class AppSource {
|
||||
[GeneratedFormTextField('appName', label: tr('appName'), required: false)],
|
||||
[
|
||||
GeneratedFormSwitch('shizukuPretendToBeGooglePlay',
|
||||
label: tr('shizukuPretendToBeGooglePlay'),
|
||||
defaultValue: false)
|
||||
label: tr('shizukuPretendToBeGooglePlay'), defaultValue: false)
|
||||
],
|
||||
[
|
||||
GeneratedFormSwitch('exemptFromBackgroundUpdates',
|
||||
@@ -616,7 +623,7 @@ abstract class AppSource {
|
||||
}
|
||||
|
||||
bool canSearch = false;
|
||||
bool excludeFromMassSearch = false;
|
||||
bool includeAdditionalOptsInMainSearch = false;
|
||||
List<GeneratedFormItem> searchQuerySettingFormItems = [];
|
||||
Future<Map<String, List<String>>> search(String query,
|
||||
{Map<String, dynamic> querySettings = const {}}) {
|
||||
|
306
pubspec.lock
306
pubspec.lock
@@ -47,18 +47,42 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: app_links
|
||||
sha256: "42dc15aecf2618ace4ffb74a2e58a50e45cd1b9f2c17c8f0cafe4c297f08c815"
|
||||
sha256: a9905d6a60e814503fabc7523a9ed161b812d7ca69c99ad8ceea14279dc4f06b
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.1"
|
||||
version: "6.1.3"
|
||||
app_links_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: app_links_linux
|
||||
sha256: "567139eca3ca9fb113f2082f3aaa75a26f30f0ebdbe5fa7f09a3913c5bebd630"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.2"
|
||||
app_links_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: app_links_platform_interface
|
||||
sha256: "58cff6f11df59b0e514dd5e4a61e988348ad5662f0e75d45d4e214ebea55c94c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
app_links_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: app_links_web
|
||||
sha256: "74586ed5f3c4786341e82a0fa43c39ec3f13108a550f74e80d8bf68aa11349d1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.3"
|
||||
archive:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: archive
|
||||
sha256: "22600aa1e926be775fa5fe7e6894e7fb3df9efda8891c73f70fb3262399a432d"
|
||||
sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.4.10"
|
||||
version: "3.6.1"
|
||||
args:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -79,10 +103,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: background_fetch
|
||||
sha256: dbffec0317ccdef6e2014cb543e147f52441e29c4fcb53dfd23558c4d92ddece
|
||||
sha256: b5c298c911bc2ce41152668bc72eb0488f0665d75bc6d1e69e7d8367763eddcd
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.2"
|
||||
version: "1.3.5"
|
||||
boolean_selector:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -135,10 +159,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: connectivity_plus
|
||||
sha256: ebe15d94de9dd7c31dc2ac54e42780acdf3384b1497c69290c9f3c5b0279fc57
|
||||
sha256: db7a4e143dc72cc3cb2044ef9b052a7ebfe729513e6a82943bc3526f784365b8
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.0.2"
|
||||
version: "6.0.3"
|
||||
connectivity_plus_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -147,14 +171,6 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
convert:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: convert
|
||||
sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.1"
|
||||
cross_file:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -223,10 +239,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: easy_localization
|
||||
sha256: c145aeb6584aedc7c862ab8c737c3277788f47488bfdf9bae0fe112bd0a4789c
|
||||
sha256: fa59bcdbbb911a764aa6acf96bbb6fa7a5cf8234354fc45ec1a43a0349ef0201
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.5"
|
||||
version: "3.0.7"
|
||||
easy_logger:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -271,10 +287,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: file_picker
|
||||
sha256: b6283d7387310ad83bc4f3bc245b75d223a032ae6eba275afcd585de2b9a1476
|
||||
sha256: "2ca051989f69d1b2ca012b2cf3ccf78c70d40144f0861ff2c063493f7c8c3d45"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "8.0.1"
|
||||
version: "8.0.5"
|
||||
fixnum:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -287,18 +303,18 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flex_color_picker
|
||||
sha256: "5c846437069fb7afdd7ade6bf37e628a71d2ab0787095ddcb1253bf9345d5f3a"
|
||||
sha256: "809af4ec82ede3b140ed0219b97d548de99e47aa4b99b14a10f705a2dbbcba5e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.4.1"
|
||||
version: "3.5.1"
|
||||
flex_seed_scheme:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flex_seed_scheme
|
||||
sha256: "4cee2f1d07259f77e8b36f4ec5f35499d19e74e17c7dce5b819554914082bc01"
|
||||
sha256: "6c595e545b0678e1fe17e8eec3d1fbca7237482da194fadc20ad8607dc7a7f3d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.5.0"
|
||||
version: "3.0.0"
|
||||
flutter:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
@@ -320,6 +336,54 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
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:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
@@ -332,18 +396,18 @@ packages:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: flutter_lints
|
||||
sha256: "9e8c3858111da373efc5aa341de011d9bd23e2c5c5e0c62bccf32438e192d7b1"
|
||||
sha256: "3f41d009ba7172d5ff9be5f6e6e6abb4300e263aab8866d2a0842ed2a70f8f0c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.2"
|
||||
version: "4.0.0"
|
||||
flutter_local_notifications:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_local_notifications
|
||||
sha256: a701df4866f9a38bb8e4450a54c143bbeeb0ce2381e7df5a36e1006f3b43bb28
|
||||
sha256: ced76d337f54de33d7d9f06092137b4ac2da5079e00cee8a11a1794ffc7c61c6
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "17.0.1"
|
||||
version: "17.2.1"
|
||||
flutter_local_notifications_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -356,10 +420,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_local_notifications_platform_interface
|
||||
sha256: "7cf643d6d5022f3baed0be777b0662cce5919c0a7b86e700299f22dc4ae660ef"
|
||||
sha256: "85f8d07fe708c1bdcf45037f2c0109753b26ae077e9d9e899d55971711a4ea66"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.0.0+1"
|
||||
version: "7.2.0"
|
||||
flutter_localizations:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
@@ -369,23 +433,31 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_markdown
|
||||
sha256: "9921f9deda326f8a885e202b1e35237eadfc1345239a0f6f0f1ff287e047547f"
|
||||
sha256: "2e8a801b1ded5ea001a4529c97b1f213dcb11c6b20668e081cafb23468593514"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.1"
|
||||
version: "0.7.3"
|
||||
flutter_plugin_android_lifecycle:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_plugin_android_lifecycle
|
||||
sha256: "8cf40eebf5dec866a6d1956ad7b4f7016e6c0cc69847ab946833b7d43743809f"
|
||||
sha256: c6b0b4c05c458e1c01ad9bcc14041dd7b1f6783d487be4386f793f47a8a4d03e
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.19"
|
||||
version: "2.0.20"
|
||||
flutter_test:
|
||||
dependency: "direct dev"
|
||||
description: flutter
|
||||
source: sdk
|
||||
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:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
@@ -395,10 +467,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: fluttertoast
|
||||
sha256: "81b68579e23fcbcada2db3d50302813d2371664afe6165bc78148050ab94bf66"
|
||||
sha256: "7eae679e596a44fdf761853a706f74979f8dd3cd92cf4e23cae161fda091b847"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "8.2.5"
|
||||
version: "8.2.6"
|
||||
fraction:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -451,68 +523,60 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image
|
||||
sha256: "4c68bfd5ae83e700b5204c1e74451e7bf3cf750e6843c6e158289cf56bda018e"
|
||||
sha256: "2237616a36c0d69aef7549ab439b833fb7f9fb9fc861af2cc9ac3eedddd69ca8"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.1.7"
|
||||
version: "4.2.0"
|
||||
intl:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: intl
|
||||
sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d"
|
||||
sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.18.1"
|
||||
js:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: js
|
||||
sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.1"
|
||||
version: "0.19.0"
|
||||
json_annotation:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: json_annotation
|
||||
sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467
|
||||
sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.8.1"
|
||||
version: "4.9.0"
|
||||
leak_tracker:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: leak_tracker
|
||||
sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa"
|
||||
sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "10.0.0"
|
||||
version: "10.0.4"
|
||||
leak_tracker_flutter_testing:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: leak_tracker_flutter_testing
|
||||
sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0
|
||||
sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
version: "3.0.3"
|
||||
leak_tracker_testing:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: leak_tracker_testing
|
||||
sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47
|
||||
sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
version: "3.0.1"
|
||||
lints:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: lints
|
||||
sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290
|
||||
sha256: "976c774dd944a42e83e2467f4cc670daef7eed6295b10b36ae8c85bcbf828235"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.0"
|
||||
version: "4.0.0"
|
||||
markdown:
|
||||
dependency: transitive
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: markdown
|
||||
sha256: ef2a1298144e3f985cc736b22e0ccdaf188b5b3970648f2d9dc13efd1d9df051
|
||||
@@ -539,10 +603,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: meta
|
||||
sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04
|
||||
sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.11.0"
|
||||
version: "1.12.0"
|
||||
mime:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -587,18 +651,18 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_android
|
||||
sha256: a248d8146ee5983446bf03ed5ea8f6533129a12b11f12057ad1b4a67a2b3b41d
|
||||
sha256: bca87b0165ffd7cdb9cad8edd22d18d2201e886d9a9f19b4fb3452ea7df3a72a
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.4"
|
||||
version: "2.2.6"
|
||||
path_provider_foundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_foundation
|
||||
sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f"
|
||||
sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.2"
|
||||
version: "2.4.0"
|
||||
path_provider_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -635,18 +699,18 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: permission_handler_android
|
||||
sha256: "1acac6bae58144b442f11e66621c062aead9c99841093c38f5bcdcc24c1c3474"
|
||||
sha256: b29a799ca03be9f999aa6c39f7de5209482d638e6f857f6b93b0875c618b7e54
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "12.0.5"
|
||||
version: "12.0.7"
|
||||
permission_handler_apple:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: permission_handler_apple
|
||||
sha256: e9ad66020b89ff1b63908f247c2c6f931c6e62699b756ef8b3c4569350cd8662
|
||||
sha256: e6f6d73b12438ef13e648c4ae56bd106ec60d17e90a59c4545db6781229082a0
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "9.4.4"
|
||||
version: "9.4.5"
|
||||
permission_handler_html:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -683,10 +747,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: platform
|
||||
sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec"
|
||||
sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.4"
|
||||
version: "3.1.5"
|
||||
plugin_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -695,14 +759,38 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.8"
|
||||
pointycastle:
|
||||
pointer_interceptor:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pointycastle
|
||||
sha256: "79fbafed02cfdbe85ef3fd06c7f4bc2cbcba0177e61b765264853d4253b21744"
|
||||
name: pointer_interceptor
|
||||
sha256: d0a8e660d1204eaec5bd34b34cc92174690e076d2e4f893d9d68c486a13b07c4
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.9.0"
|
||||
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:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -715,18 +803,18 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: share_plus
|
||||
sha256: fb5319f3aab4c5dda5ebb92dca978179ba21f8c783ee4380910ef4c1c6824f51
|
||||
sha256: ef3489a969683c4f3d0239010cc8b7a2a46543a8d139e111c06c558875083544
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "8.0.3"
|
||||
version: "9.0.0"
|
||||
share_plus_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: share_plus_platform_interface
|
||||
sha256: "251eb156a8b5fa9ce033747d73535bf53911071f8d3b6f4f0b578505ce0d4496"
|
||||
sha256: "0f9e4418835d1b2c3ae78fdb918251959106cefdbc4dd43526e182f80e82f6d4"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.4.0"
|
||||
version: "4.0.0"
|
||||
shared_preferences:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -739,18 +827,18 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_android
|
||||
sha256: "1ee8bf911094a1b592de7ab29add6f826a7331fb854273d55918693d5364a1f2"
|
||||
sha256: "93d0ec9dd902d85f326068e6a899487d1f65ffcd5798721a95330b26c8131577"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.2"
|
||||
version: "2.2.3"
|
||||
shared_preferences_foundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_foundation
|
||||
sha256: "7708d83064f38060c7b39db12aefe449cb8cdc031d6062280087bc4cdb988f5c"
|
||||
sha256: "0a8a893bf4fd1152f93fec03a415d11c27c74454d96e2318a7ac38dd18683ab7"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.5"
|
||||
version: "2.4.0"
|
||||
shared_preferences_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -825,10 +913,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: sqflite
|
||||
sha256: "5ce2e1a15e822c3b4bfb5400455775e421da7098eed8adc8f26298ada7c9308c"
|
||||
sha256: a43e5a27235518c03ca238e7b4732cf35eabe863a369ceba6cbefa537a66f16d
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.3"
|
||||
version: "2.3.3+1"
|
||||
sqflite_common:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -881,18 +969,18 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_api
|
||||
sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b"
|
||||
sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.6.1"
|
||||
version: "0.7.0"
|
||||
timezone:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: timezone
|
||||
sha256: "1cfd8ddc2d1cfd836bc93e67b9be88c3adaeca6f40a00ca999104c30693cdca0"
|
||||
sha256: a6ccda4a69a442098b602c44e61a1e2b4bf6f5516e875bbf0f427d5df14745d5
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.9.2"
|
||||
version: "0.9.3"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -905,26 +993,26 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: url_launcher
|
||||
sha256: "6ce1e04375be4eed30548f10a315826fd933c1e493206eab82eed01f438c8d2e"
|
||||
sha256: "21b704ce5fa560ea9f3b525b43601c678728ba46725bab9b01187b4831377ed3"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.2.6"
|
||||
version: "6.3.0"
|
||||
url_launcher_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_android
|
||||
sha256: "360a6ed2027f18b73c8d98e159dda67a61b7f2e0f6ec26e86c3ada33b0621775"
|
||||
sha256: ceb2625f0c24ade6ef6778d1de0b2e44f2db71fded235eb52295247feba8c5cf
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.3.1"
|
||||
version: "6.3.3"
|
||||
url_launcher_ios:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_ios
|
||||
sha256: "9149d493b075ed740901f3ee844a38a00b33116c7c5c10d7fb27df8987fb51d5"
|
||||
sha256: "7068716403343f6ba4969b4173cbf3b84fc768042124bc2c011e5d782b24fe89"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.2.5"
|
||||
version: "6.3.0"
|
||||
url_launcher_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -937,10 +1025,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_macos
|
||||
sha256: b7244901ea3cf489c5335bdacda07264a6e960b1c1b1a9f91e4bc371d9e68234
|
||||
sha256: "9a1a42d5d2d95400c795b2914c36fdcb525870c752569438e4ebb09a2b5d90de"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.0"
|
||||
version: "3.2.0"
|
||||
url_launcher_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -985,10 +1073,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vm_service
|
||||
sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957
|
||||
sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "13.0.0"
|
||||
version: "14.2.1"
|
||||
web:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1001,18 +1089,18 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: webview_flutter
|
||||
sha256: "25e1b6e839e8cbfbd708abc6f85ed09d1727e24e08e08c6b8590d7c65c9a8932"
|
||||
sha256: "6869c8786d179f929144b4a1f86e09ac0eddfe475984951ea6c634774c16b522"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.7.0"
|
||||
version: "4.8.0"
|
||||
webview_flutter_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: webview_flutter_android
|
||||
sha256: f038ee2fae73b509dde1bc9d2c5a50ca92054282de17631a9a3d515883740934
|
||||
sha256: f42447ca49523f11d8f70abea55ea211b3cafe172dd7a0e7ac007bb35dd356dc
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.16.0"
|
||||
version: "3.16.4"
|
||||
webview_flutter_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1025,18 +1113,18 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: webview_flutter_wkwebview
|
||||
sha256: f12f8d8a99784b863e8b85e4a9a5e3cf1839d6803d2c0c3e0533a8f3c5a992a7
|
||||
sha256: "7affdf9d680c015b11587181171d3cad8093e449db1f7d9f0f08f4f33d24f9a0"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.13.0"
|
||||
version: "3.13.1"
|
||||
win32:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: win32
|
||||
sha256: "0a989dc7ca2bb51eac91e8fd00851297cfffd641aa7538b165c62637ca0eaa4a"
|
||||
sha256: a79dbe579cb51ecd6d30b17e0cae4e0ea15e2c0e66f69ad4198f22a6789e94f4
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.4.0"
|
||||
version: "5.5.1"
|
||||
win32_registry:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1070,5 +1158,5 @@ packages:
|
||||
source: hosted
|
||||
version: "3.1.2"
|
||||
sdks:
|
||||
dart: ">=3.3.3 <4.0.0"
|
||||
flutter: ">=3.19.0"
|
||||
dart: ">=3.4.0 <4.0.0"
|
||||
flutter: ">=3.22.0"
|
||||
|
10
pubspec.yaml
10
pubspec.yaml
@@ -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
|
||||
# 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.
|
||||
version: 1.1.5+2262
|
||||
version: 1.1.12+2269
|
||||
|
||||
environment:
|
||||
sdk: '>=3.0.0 <4.0.0'
|
||||
@@ -56,7 +56,7 @@ dependencies:
|
||||
url: https://github.com/ImranR98/android_package_installer
|
||||
ref: main
|
||||
android_package_manager: ^0.7.0
|
||||
share_plus: ^8.0.2
|
||||
share_plus: ^9.0.0
|
||||
sqflite: ^2.2.0+3
|
||||
easy_localization: ^3.0.1
|
||||
android_intent_plus: ^5.0.1
|
||||
@@ -66,7 +66,7 @@ dependencies:
|
||||
connectivity_plus: ^6.0.1
|
||||
shared_storage: ^0.8.0
|
||||
crypto: ^3.0.3
|
||||
app_links: ^4.0.0
|
||||
app_links: ^6.0.1
|
||||
background_fetch: ^1.2.1
|
||||
equations: ^5.0.2
|
||||
flex_color_picker: ^3.4.1
|
||||
@@ -79,6 +79,8 @@ dependencies:
|
||||
url: https://github.com/re7gog/shizuku_apk_installer
|
||||
ref: master
|
||||
|
||||
markdown: any
|
||||
flutter_typeahead: ^5.2.0
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
@@ -89,7 +91,7 @@ dev_dependencies:
|
||||
# activated in the `analysis_options.yaml` file located at the root of your
|
||||
# package. See that file for information about deactivating specific lint
|
||||
# rules and activating additional ones.
|
||||
flutter_lints: ^3.0.0
|
||||
flutter_lints: ^4.0.0
|
||||
|
||||
flutter_launcher_icons:
|
||||
android: "ic_launcher"
|
||||
|
Reference in New Issue
Block a user