mirror of
https://github.com/ImranR98/Obtainium.git
synced 2025-07-13 13:26:43 +02:00
Compare commits
104 Commits
v0.13.8-be
...
v0.13.19-b
Author | SHA1 | Date | |
---|---|---|---|
bb5bd23263 | |||
58361a0493 | |||
7671ab95f9 | |||
41f102c0ce | |||
5cee527d6f | |||
c2eb13d5e5 | |||
ed89e20826 | |||
e50c7554e3 | |||
00354f10a3 | |||
031d0b7444 | |||
2ced06367b | |||
9ef3279bae | |||
b055486d74 | |||
c70f2c481e | |||
e4b26be01f | |||
b27bdc63c1 | |||
543e7d8cdc | |||
852decbe7d | |||
d2150320fa | |||
9c723c7522 | |||
ac5660de88 | |||
e6467452a6 | |||
04b49c2e61 | |||
324773ba58 | |||
d885ca5db7 | |||
e093fc28b0 | |||
579bc94847 | |||
53dba06cc3 | |||
1c390a7f04 | |||
6b16857186 | |||
785bba1f45 | |||
3befcbc16d | |||
be300608a9 | |||
f05902925d | |||
d32e7acc8f | |||
fda9e6195a | |||
b5d91adb21 | |||
1b52cb6233 | |||
5669634b44 | |||
d6bb365cf1 | |||
53b7cfb9bf | |||
2558c851c0 | |||
a8aa63daa3 | |||
d587e9f708 | |||
e2a8f40e3e | |||
1cc4241fac | |||
bb98dfe0b3 | |||
6395dd820b | |||
e909c03356 | |||
6a3278432d | |||
81c51970aa | |||
7f9d431b9b | |||
360591ebb9 | |||
814ff2c2e5 | |||
f74df57400 | |||
6b29a0f0f3 | |||
2a58ee8729 | |||
41d9edcf83 | |||
3ec33a1c77 | |||
3f4c6a1b76 | |||
60ad3199ca | |||
1984ffb1c0 | |||
7877a14f07 | |||
568a94968b | |||
a6a68af24e | |||
5cdd110544 | |||
5bbe306f8f | |||
48acbc563a | |||
ab1f7e7179 | |||
667e909a70 | |||
bcc0d280ab | |||
da027b7734 | |||
09056665c2 | |||
f4c3951f6d | |||
00f42bb881 | |||
d8408a26c2 | |||
ede54531c8 | |||
0fa0a4b19a | |||
af5ea3db0f | |||
e75ca05aa4 | |||
3483190b78 | |||
69656e65c3 | |||
e6c6841fac | |||
16d63a4416 | |||
2eaf443359 | |||
5979957d60 | |||
049eb5914c | |||
7577f3ac9b | |||
5b05745b02 | |||
4366b4e369 | |||
9c60f10005 | |||
a0d02043c4 | |||
ff5152bf79 | |||
995a826917 | |||
2965e159cb | |||
0dcd5163d4 | |||
d31bbd9ea8 | |||
423ba07fad | |||
3697d74185 | |||
038f089aac | |||
ba3f512445 | |||
0fc1cff0a8 | |||
40bec4b732 | |||
8ca1e09c86 |
@ -32,9 +32,6 @@ Currently supported App sources:
|
|||||||
[<img src="https://github.com/machiav3lli/oandbackupx/blob/034b226cea5c1b30eb4f6a6f313e4dadcbb0ece4/badge_github.png"
|
[<img src="https://github.com/machiav3lli/oandbackupx/blob/034b226cea5c1b30eb4f6a6f313e4dadcbb0ece4/badge_github.png"
|
||||||
alt="Get it on GitHub"
|
alt="Get it on GitHub"
|
||||||
height="80">](https://github.com/ImranR98/Obtainium/releases)
|
height="80">](https://github.com/ImranR98/Obtainium/releases)
|
||||||
[<img src="https://gitlab.com/IzzyOnDroid/repo/-/raw/master/assets/IzzyOnDroid.png"
|
|
||||||
alt="Get it on IzzyOnDroid"
|
|
||||||
height="80">](https://apt.izzysoft.de/fdroid/index/apk/dev.imranr.obtainium)
|
|
||||||
|
|
||||||
## Limitations
|
## Limitations
|
||||||
- Auto (unattended) updates are unsupported due to a lack of any capable Flutter plugin.
|
- Auto (unattended) updates are unsupported due to a lack of any capable Flutter plugin.
|
||||||
|
291
assets/translations/bs.json
Normal file
291
assets/translations/bs.json
Normal file
@ -0,0 +1,291 @@
|
|||||||
|
{
|
||||||
|
"invalidURLForSource": "Nije važeći URL aplikacije {}",
|
||||||
|
"noReleaseFound": "Nije moguće pronaći odgovarajuće izdanje",
|
||||||
|
"noVersionFound": "Nije moguće odrediti verziju izdanja",
|
||||||
|
"urlMatchesNoSource": "URL se ne podudara s poznatim izvorom",
|
||||||
|
"cantInstallOlderVersion": "Nije moguće instalirati stariju verziju aplikacije",
|
||||||
|
"appIdMismatch": "ID preuzetog paketa se ne podudara s postojećim ID-om aplikacije",
|
||||||
|
"functionNotImplemented": "Ova klasa nije implementirala ovu funkciju",
|
||||||
|
"placeholder": "Rezervirano mjesto",
|
||||||
|
"someErrors": "Došlo je do nekih grešaka",
|
||||||
|
"unexpectedError": "Neočekivana greška",
|
||||||
|
"ok": "Dobro",
|
||||||
|
"and": "i",
|
||||||
|
"startedBgUpdateTask": "Započeo je pozadinski zadatak provjere ažuriranja",
|
||||||
|
"bgUpdateIgnoreAfterIs": "ignoreAfter pozadinskog zadataka je {}",
|
||||||
|
"startedActualBGUpdateCheck": "Započela je stvarna provjera ažuriranja",
|
||||||
|
"bgUpdateTaskFinished": "Završen zadatak provjere ažuriranja",
|
||||||
|
"firstRun": "Ovo je prvi put da pokrećete Obtainium",
|
||||||
|
"settingUpdateCheckIntervalTo": "Podešavanje intervala ažuriranja na {}",
|
||||||
|
"githubPATLabel": "GitHub token za lični pristup (eng. PAT, povećava ograničenje stope)",
|
||||||
|
"githubPATHint": "PAT mora biti u ovom formatu: korisničko_ime:token",
|
||||||
|
"githubPATFormat": "korisničko_ime:token",
|
||||||
|
"includePrereleases": "Uključi preliminarna izdanja",
|
||||||
|
"fallbackToOlderReleases": "Povratak na starija izdanja",
|
||||||
|
"filterReleaseTitlesByRegEx": "Filtrirajte naslove izdanja prema regularnom izrazu",
|
||||||
|
"invalidRegEx": "Nevažeći regularni izraz",
|
||||||
|
"noDescription": "Bez opisa",
|
||||||
|
"cancel": "Otkaži",
|
||||||
|
"continue": "Nastavite",
|
||||||
|
"requiredInBrackets": "(obavezno)",
|
||||||
|
"dropdownNoOptsError": "GREŠKA: PADAJUĆI MENI MORA IMATI NAJMANJE JEDNU OPCIJU",
|
||||||
|
"colour": "Boja",
|
||||||
|
"githubStarredRepos": "GitHub repo-i sa zvjezdicom",
|
||||||
|
"uname": "Korisničko ime",
|
||||||
|
"wrongArgNum": "Naveden je pogrešan broj argumenata",
|
||||||
|
"xIsTrackOnly": "{} je samo za praćenje",
|
||||||
|
"source": "Izvor",
|
||||||
|
"app": "Aplikacija. ",
|
||||||
|
"appsFromSourceAreTrackOnly": "Aplikacije iz ovog izvora su 'Samo za praćenje'.",
|
||||||
|
"youPickedTrackOnly": "Odabrali ste opciju „Samo za praćenje”.",
|
||||||
|
"trackOnlyAppDescription": "Aplikacija će se pratiti radi ažuriranja, ali Obtainium neće moći da je preuzme ili instalira.",
|
||||||
|
"cancelled": "Otkazano",
|
||||||
|
"appAlreadyAdded": "Aplikacija je već dodana",
|
||||||
|
"alreadyUpToDateQuestion": "Aplikacija je već ažurirana?",
|
||||||
|
"addApp": "Dodaj aplikaciju",
|
||||||
|
"appSourceURL": "Izvorni URL aplikacije",
|
||||||
|
"error": "Greška",
|
||||||
|
"add": "Dodaj",
|
||||||
|
"searchSomeSourcesLabel": "Pretraživanje (samo neki izvori)",
|
||||||
|
"search": "Pretraživanje",
|
||||||
|
"additionalOptsFor": "Dodatne opcije za {}",
|
||||||
|
"supportedSourcesBelow": "Podržani izvori:",
|
||||||
|
"trackOnlyInBrackets": "(Samo za praćenje)",
|
||||||
|
"searchableInBrackets": "(Može se pretraživati)",
|
||||||
|
"appsString": "Aplikacije",
|
||||||
|
"noApps": "Nema aplikacija",
|
||||||
|
"noAppsForFilter": "Nema aplikacija za filter",
|
||||||
|
"byX": "Autor {}",
|
||||||
|
"percentProgress": "Napredak: {}%",
|
||||||
|
"pleaseWait": "Molimo sačekajte",
|
||||||
|
"updateAvailable": "Ažuriranje dostupno",
|
||||||
|
"estimateInBracketsShort": "(Procjena)",
|
||||||
|
"notInstalled": "Nije instalirano",
|
||||||
|
"estimateInBrackets": "(Procjena)",
|
||||||
|
"selectAll": "Označi sve",
|
||||||
|
"deselectN": "Poništi odabir {}",
|
||||||
|
"xWillBeRemovedButRemainInstalled": "{} će biti uklonjen iz Obtainiuma, ali će ostati instaliran na uređaju.",
|
||||||
|
"removeSelectedAppsQuestion": "Želite li ukloniti odabrane aplikacije?",
|
||||||
|
"removeSelectedApps": "Ukloni odabrane aplikacije",
|
||||||
|
"updateX": "Nadogradi {}",
|
||||||
|
"installX": "Instaliraj {}",
|
||||||
|
"markXTrackOnlyAsUpdated": "Označi {}\n(samo za praćenje)\nkao ažurirano",
|
||||||
|
"changeX": "Promjena {}",
|
||||||
|
"installUpdateApps": "Instalirajte/ažurirajte aplikacije",
|
||||||
|
"installUpdateSelectedApps": "Instalirajte/ažurirajte odabrane aplikacije",
|
||||||
|
"markXSelectedAppsAsUpdated": "Označite {} odabrane aplikacije kao ažurirane?",
|
||||||
|
"no": "Ne",
|
||||||
|
"yes": "Da",
|
||||||
|
"markSelectedAppsUpdated": "Označi odabrane aplikacije kao ažurirane",
|
||||||
|
"pinToTop": "Prikvači na vrh",
|
||||||
|
"unpinFromTop": "Otkvači sa vrha",
|
||||||
|
"resetInstallStatusForSelectedAppsQuestion": "Resetujte status instalacije za odabrane aplikacije?",
|
||||||
|
"installStatusOfXWillBeResetExplanation": "Status instalacije bilo koje odabrane aplikacije će se resetovati.\n\nTo može pomoći kada je verzija aplikacije prikazana u Obtainiumu netačna zbog neuspjelih ažuriranja ili drugih problema.",
|
||||||
|
"shareSelectedAppURLs": "Podijeli odabrane URL-ove aplikacija",
|
||||||
|
"resetInstallStatus": "Resetujte status instalacije",
|
||||||
|
"more": "Više",
|
||||||
|
"removeOutdatedFilter": "Uklonite zastarjeli filter aplikacija",
|
||||||
|
"showOutdatedOnly": "Prikaži samo zastarjele aplikacije",
|
||||||
|
"filter": "Filtriranje",
|
||||||
|
"filterActive": "Filtriranje",
|
||||||
|
"filterApps": "Filtriraj aplikacije",
|
||||||
|
"appName": "Naziv aplikacije",
|
||||||
|
"author": "Autor",
|
||||||
|
"upToDateApps": "Ažurirane aplikacije",
|
||||||
|
"nonInstalledApps": "Neinstalirane aplikacije",
|
||||||
|
"importExport": "Uvoz/izvoz",
|
||||||
|
"settings": "Postavke",
|
||||||
|
"exportedTo": "Izvezeno u {}",
|
||||||
|
"obtainiumExport": "Obtainium Export",
|
||||||
|
"invalidInput": "Neispravan unos.",
|
||||||
|
"importedX": "Uvezeno {}",
|
||||||
|
"obtainiumImport": "Obtainium uvoz",
|
||||||
|
"importFromURLList": "Uvoz iz URL liste",
|
||||||
|
"searchQuery": "Pretraga za: ",
|
||||||
|
"appURLList": "Lista URL adresa aplikacija",
|
||||||
|
"line": "Linija",
|
||||||
|
"searchX": "Pretraživanje {}",
|
||||||
|
"noResults": "Nema rezultata",
|
||||||
|
"importX": "Uvoz {}",
|
||||||
|
"importedAppsIdDisclaimer": "Uvezene aplikacije mogu se pogrešno prikazati kao „Nije instalirano”.\nDa biste to riješili, ponovo ih instalirajte putem aplikacije Obtainium.\nTo ne bi trebalo uticati na podatke aplikacije.\n\nUtječe samo na URL i metode uvoza treće strane.",
|
||||||
|
"importErrors": "Uvezi greške",
|
||||||
|
"importedXOfYApps": "{} od {} aplikacija uvezeno.",
|
||||||
|
"followingURLsHadErrors": "Sljedeći URL-ovi su imali greške:",
|
||||||
|
"okay": "Dobro",
|
||||||
|
"selectURL": "Odaberite URL",
|
||||||
|
"selectURLs": "Odaberite URL-ove",
|
||||||
|
"pick": "Odaberi",
|
||||||
|
"theme": "Tema",
|
||||||
|
"dark": "Tamna",
|
||||||
|
"light": "Svijetla",
|
||||||
|
"followSystem": "Pratite sistem",
|
||||||
|
"obtainium": "Obtainium",
|
||||||
|
"materialYou": "Material You",
|
||||||
|
"useBlackTheme": "Koristite čisto crnu tamnu temu",
|
||||||
|
"appSortBy": "Aplikacije sortirane po",
|
||||||
|
"authorName": "Autor/Ime",
|
||||||
|
"nameAuthor": "Ime/Autor",
|
||||||
|
"asAdded": "Kao što je dodano",
|
||||||
|
"appSortOrder": "Redoslijed sortiranja aplikacija",
|
||||||
|
"ascending": "Uzlazno",
|
||||||
|
"descending": "Silazno",
|
||||||
|
"bgUpdateCheckInterval": "Interval provjere ažuriranja u pozadini",
|
||||||
|
"neverManualOnly": "Nikada - samo ručno",
|
||||||
|
"appearance": "Izgled",
|
||||||
|
"showWebInAppView": "Prikaži izvornu web stranicu u prikazu aplikacije",
|
||||||
|
"pinUpdates": "Prikvačite ažuriranja na vrh prikaza aplikacija",
|
||||||
|
"updates": "Nadogradnje",
|
||||||
|
"sourceSpecific": "Specifično za izvor",
|
||||||
|
"appSource": "Izvor aplikacije",
|
||||||
|
"noLogs": "Nema evidencije",
|
||||||
|
"appLogs": "Evidencije aplikacija",
|
||||||
|
"close": "Zatvori",
|
||||||
|
"share": "Podijeli",
|
||||||
|
"appNotFound": "Aplikacija nije pronađena",
|
||||||
|
"obtainiumExportHyphenatedLowercase": "obtainium-export",
|
||||||
|
"pickAnAPK": "Odaberite APK",
|
||||||
|
"appHasMoreThanOnePackage": "{} ima više od jednog paketa:",
|
||||||
|
"deviceSupportsXArch": "Vaš uređaj podržava {} arhitekturu procesora.",
|
||||||
|
"deviceSupportsFollowingArchs": "Vaš uređaj podržava sljedeće arhitekture procesora:",
|
||||||
|
"warning": "Upozorenje",
|
||||||
|
"sourceIsXButPackageFromYPrompt": "Izvor aplikacije je '{}', ali paket za izdavanje dolazi iz '{}'. Želite li nastaviti?",
|
||||||
|
"updatesAvailable": "Dostupna ažuriranja",
|
||||||
|
"updatesAvailableNotifDescription": "Obavještava korisnika da su ažuriranja dostupna za jednu ili više aplikacija koje prati Obtainium",
|
||||||
|
"noNewUpdates": "Nema novih ažuriranja.",
|
||||||
|
"xHasAnUpdate": "{} ima ažuriranje.",
|
||||||
|
"appsUpdated": "Aplikacije su ažurirane",
|
||||||
|
"appsUpdatedNotifDescription": "Obavještava korisnika da su u pozadini primijenjena ažuriranja na jednu ili više aplikacija",
|
||||||
|
"xWasUpdatedToY": "{} je ažuriran na {}.",
|
||||||
|
"errorCheckingUpdates": "Greška pri provjeri ažuriranja",
|
||||||
|
"errorCheckingUpdatesNotifDescription": "Obavijest koja se prikazuje kada provjera sigurnosnog ažuriranja ne uspije",
|
||||||
|
"appsRemoved": "Aplikacije su uklonjene",
|
||||||
|
"appsRemovedNotifDescription": "Obavještava korisnika da je jedna ili više aplikacija uklonjeno zbog grešaka prilikom učitavanja",
|
||||||
|
"xWasRemovedDueToErrorY": "{} je uklonjen zbog ove greške: {}",
|
||||||
|
"completeAppInstallation": "Dovršite instalaciju aplikacije",
|
||||||
|
"obtainiumMustBeOpenToInstallApps": "Obtainium mora biti otvoren za instalaciju aplikacija",
|
||||||
|
"completeAppInstallationNotifDescription": "Traži od korisnika da se vrati u Obtainium kako bi dovršio instalaciju aplikacije",
|
||||||
|
"checkingForUpdates": "Tražim moguće nadogradnje",
|
||||||
|
"checkingForUpdatesNotifDescription": "Privremeno obavještenje koje se pojavljuje prilikom provjere ažuriranja",
|
||||||
|
"pleaseAllowInstallPerm": "Dozvolite Obtainiumu da instalira aplikacije",
|
||||||
|
"trackOnly": "Samo za praćenje",
|
||||||
|
"errorWithHttpStatusCode": "Greška {}",
|
||||||
|
"versionCorrectionDisabled": "Ispravka verzije je onemogućena (izgleda da plugin ne radi)",
|
||||||
|
"unknown": "Nepoznato",
|
||||||
|
"none": "Ništa",
|
||||||
|
"never": "Nikad",
|
||||||
|
"latestVersionX": "Najnovija verzija: {}",
|
||||||
|
"installedVersionX": "Instalirana verzija: {}",
|
||||||
|
"lastUpdateCheckX": "Posljednja provjera ažuriranja: {}",
|
||||||
|
"remove": "Izbriši",
|
||||||
|
"yesMarkUpdated": "Da, označi kao ažurirano",
|
||||||
|
"fdroid": "F-Droid Official",
|
||||||
|
"appIdOrName": "ID ili ime aplikacije",
|
||||||
|
"appId": "Apl ID",
|
||||||
|
"appWithIdOrNameNotFound": "Nije pronađena aplikacija s tim ID-om ili imenom",
|
||||||
|
"reposHaveMultipleApps": "Repo-i mogu sadržavati više aplikacija",
|
||||||
|
"fdroidThirdPartyRepo": "F-Droid Repo treće strane",
|
||||||
|
"steam": "Steam",
|
||||||
|
"steamMobile": "Steam Mobile",
|
||||||
|
"steamChat": "Razgovor na Steamu (chat)",
|
||||||
|
"install": "Instaliraj",
|
||||||
|
"markInstalled": "Označi kao instalirano",
|
||||||
|
"update": "Nadogradi",
|
||||||
|
"markUpdated": "Označi kao ažurirano",
|
||||||
|
"additionalOptions": "Dodatne opcije",
|
||||||
|
"disableVersionDetection": "Onemogući detekciju verzije",
|
||||||
|
"noVersionDetectionExplanation": "Ova opcija bi se trebala koristiti samo za aplikacije gdje detekcija verzije ne radi ispravno.",
|
||||||
|
"downloadingX": "Preuzimanje {}",
|
||||||
|
"downloadNotifDescription": "Obavještava korisnika o napretku u preuzimanju aplikacije",
|
||||||
|
"noAPKFound": "APK nije pronađen",
|
||||||
|
"noVersionDetection": "Nema detekcije verzije",
|
||||||
|
"categorize": "Kategoriziraj",
|
||||||
|
"categories": "Kategorije",
|
||||||
|
"category": "Kategorija",
|
||||||
|
"noCategory": "Nema kategorije",
|
||||||
|
"noCategories": "Nema kategorija",
|
||||||
|
"deleteCategoriesQuestion": "Želite li izbrisati kategorije?",
|
||||||
|
"categoryDeleteWarning": "Sve aplikacije u izbrisanim kategorijama će biti postavljene kao nekategorisane.",
|
||||||
|
"addCategory": "Dodaj kategoriju",
|
||||||
|
"label": "Oznaka",
|
||||||
|
"language": "Jezik",
|
||||||
|
"copiedToClipboard": "Podaci kopirani u međuspremnik",
|
||||||
|
"storagePermissionDenied": "Dozvola za pohranu je odbijena",
|
||||||
|
"selectedCategorizeWarning": "Ovo će zamijeniti sve postojeće postavke kategorije za odabrane aplikacije.",
|
||||||
|
"filterAPKsByRegEx": "Filtrirajte APK-ove prema regularnom izrazu",
|
||||||
|
"removeFromObtainium": "Ukloni iz Obtainiuma",
|
||||||
|
"uninstallFromDevice": "Deinstaliraj s uređaja",
|
||||||
|
"onlyWorksWithNonVersionDetectApps": "Radi samo za aplikacije s onemogućenom detekcijom verzije.",
|
||||||
|
"releaseDateAsVersion": "Koristi datum izdanja kao verziju",
|
||||||
|
"releaseDateAsVersionExplanation": "Ova opcija bi se trebala koristiti samo za aplikacije gdje detekcija verzije ne radi ispravno, ali je datum izdavanja dostupan.",
|
||||||
|
"changes": "Promjene",
|
||||||
|
"releaseDate": "Datum izdavanja",
|
||||||
|
"importFromURLsInFile": "Uvoz iz URL-ova u datoteci (kao što je OPML)",
|
||||||
|
"versionDetection": "Otkrivanje verzije",
|
||||||
|
"standardVersionDetection": "Detekcija standardne verzije",
|
||||||
|
"groupByCategory": "Grupiši po kategoriji",
|
||||||
|
"autoApkFilterByArch": "Pokušajte filtrirati APK-ove po arhitekturi procesora ako je moguće",
|
||||||
|
"overrideSource": "Premosti izvor",
|
||||||
|
"dontShowAgain": "Ne prikazuj ovo ponovo",
|
||||||
|
"dontShowTrackOnlyWarnings": "Ne prikazuj upozorenja „Samo za praćenje”",
|
||||||
|
"dontShowAPKOriginWarnings": "Ne prikazuj upozorenja o porijeklu APK-a",
|
||||||
|
"moveNonInstalledAppsToBottom": "Premjesti neinstalirane aplikacije na dno prikaza aplikacija",
|
||||||
|
"gitlabPATLabel": "GitLab token za lični pristup\n(Omogućava pretraživanje i bolje otkrivanje APK-a)",
|
||||||
|
"about": "O nama",
|
||||||
|
"requiresCredentialsInSettings": "Za ovo su potrebni dodatni akreditivi (u Postavkama)",
|
||||||
|
"checkOnStart": "Provjerite ima li novosti pri pokretanju",
|
||||||
|
"tryInferAppIdFromCode": "Pokušati otkriti ID aplikacije iz izvornog koda",
|
||||||
|
"removeOnExternalUninstall": "Automatski ukloni eksterno deinstalirane aplikacije",
|
||||||
|
"pickHighestVersionCode": "Automatski odaberite najviši kôd verzije APK-a",
|
||||||
|
"checkUpdateOnDetailPage": "Provjerite ima li novosti pri otvaranju stranice s detaljima aplikacije",
|
||||||
|
"disablePageTransitions": "Ugasite animaciju prijelaza stranice",
|
||||||
|
"reversePageTransitions": "Reverzne animacije prijelaza stranice",
|
||||||
|
"minStarCount": "Minimum Star Count",
|
||||||
|
"removeAppQuestion": {
|
||||||
|
"one": "Želite li ukloniti aplikaciju?",
|
||||||
|
"other": "Želite li ukloniti aplikacije?"
|
||||||
|
},
|
||||||
|
"tooManyRequestsTryAgainInMinutes": {
|
||||||
|
"one": "Previše zahtjeva (ograničena broj zahteva) - pokušajte ponovo za {} minutu",
|
||||||
|
"other": "Previše zahtjeva (ograničena cijena) - pokušajte ponovo za {} min."
|
||||||
|
},
|
||||||
|
"bgUpdateGotErrorRetryInMinutes": {
|
||||||
|
"one": "Provjera ažuriranja u pozadini naišla je na {}, zakazuje se ponovni pokušaj za {} minutu",
|
||||||
|
"other": "Provjera ažuriranja u pozadini naišla je na {}, zakazuje se ponovni pokušaj za {} min."
|
||||||
|
},
|
||||||
|
"bgCheckFoundUpdatesWillNotifyIfNeeded": {
|
||||||
|
"one": "Provjera ažuriranja u pozadini je pronašla {} ažuriranje - korisnik će biti obavješten ako je to potrebno",
|
||||||
|
"other": "Provjera ažuriranja u pozadini je pronašla {} ažuriranja - korisnik će biti obavješten ako je to potrebno"
|
||||||
|
},
|
||||||
|
"apps": {
|
||||||
|
"one": "{} aplikacija",
|
||||||
|
"other": "{} aplikacije"
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
"one": "{} URL",
|
||||||
|
"other": "{} URL-ovi"
|
||||||
|
},
|
||||||
|
"minute": {
|
||||||
|
"one": "{} minuta",
|
||||||
|
"other": "min."
|
||||||
|
},
|
||||||
|
"hour": {
|
||||||
|
"one": "{} sat",
|
||||||
|
"other": "{} sat/i"
|
||||||
|
},
|
||||||
|
"day": {
|
||||||
|
"one": "{} dan",
|
||||||
|
"other": "{} dana"
|
||||||
|
},
|
||||||
|
"clearedNLogsBeforeXAfterY": {
|
||||||
|
"one": "Izbrisan {n} log (prije = {before}, nakon = {after})",
|
||||||
|
"other": "Izbrisano {n} log-ova (prije = {before}, nakon = {after})"
|
||||||
|
},
|
||||||
|
"xAndNMoreUpdatesAvailable": {
|
||||||
|
"one": "{} i još 1 aplikacija ima ažuriranja.",
|
||||||
|
"other": "{} i još {} aplikacija imaju ažuriranja."
|
||||||
|
},
|
||||||
|
"xAndNMoreUpdatesInstalled": {
|
||||||
|
"one": "{} i još 1 aplikacija je ažurirana.",
|
||||||
|
"other": "{} i još {} aplikacija je ažurirano."
|
||||||
|
}
|
||||||
|
}
|
@ -229,11 +229,17 @@
|
|||||||
"dontShowTrackOnlyWarnings": "Warnung für 'Nur Nachverfolgen' nicht anzeigen",
|
"dontShowTrackOnlyWarnings": "Warnung für 'Nur Nachverfolgen' nicht anzeigen",
|
||||||
"dontShowAPKOriginWarnings": "Warnung für APK-Herkunft nicht anzeigen",
|
"dontShowAPKOriginWarnings": "Warnung für APK-Herkunft nicht anzeigen",
|
||||||
"moveNonInstalledAppsToBottom": "Nicht installierte Apps ans Ende der Apps Ansicht verschieben",
|
"moveNonInstalledAppsToBottom": "Nicht installierte Apps ans Ende der Apps Ansicht verschieben",
|
||||||
"gitlabPATLabel": "GitLab Personal Access Token (Aktiviert Suche)",
|
"gitlabPATLabel": "GitLab Personal Access Token\n(Aktiviert Suche and Better APK Discovery)",
|
||||||
"about": "Über",
|
"about": "Über",
|
||||||
"requiresCredentialsInSettings": "Benötigt zusätzliche Anmeldedaten (in den Einstellungen)",
|
"requiresCredentialsInSettings": "Benötigt zusätzliche Anmeldedaten (in den Einstellungen)",
|
||||||
"checkOnStart": "Überprüfe einmalig beim Start",
|
"checkOnStart": "Überprüfe einmalig beim Start",
|
||||||
"tryInferAppIdFromCode": "Try inferring App ID from source code",
|
"tryInferAppIdFromCode": "Try inferring App ID from source code",
|
||||||
|
"removeOnExternalUninstall": "Automatically remove externally uninstalled Apps",
|
||||||
|
"pickHighestVersionCode": "Auto-select highest version code APK",
|
||||||
|
"checkUpdateOnDetailPage": "Check for updates on opening an App detail page",
|
||||||
|
"disablePageTransitions": "Disable page transition animations",
|
||||||
|
"reversePageTransitions": "Reverse page transition animations",
|
||||||
|
"minStarCount": "Minimum Star Count",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "App entfernen?",
|
"one": "App entfernen?",
|
||||||
"other": "Apps entfernen?"
|
"other": "Apps entfernen?"
|
||||||
|
@ -121,7 +121,7 @@
|
|||||||
"followSystem": "Follow System",
|
"followSystem": "Follow System",
|
||||||
"obtainium": "Obtainium",
|
"obtainium": "Obtainium",
|
||||||
"materialYou": "Material You",
|
"materialYou": "Material You",
|
||||||
"useBlackTheme": "Use Pure Black Dark Theme",
|
"useBlackTheme": "Use pure black dark theme",
|
||||||
"appSortBy": "App Sort By",
|
"appSortBy": "App Sort By",
|
||||||
"authorName": "Author/Name",
|
"authorName": "Author/Name",
|
||||||
"nameAuthor": "Name/Author",
|
"nameAuthor": "Name/Author",
|
||||||
@ -132,8 +132,8 @@
|
|||||||
"bgUpdateCheckInterval": "Background Update Checking Interval",
|
"bgUpdateCheckInterval": "Background Update Checking Interval",
|
||||||
"neverManualOnly": "Never - Manual Only",
|
"neverManualOnly": "Never - Manual Only",
|
||||||
"appearance": "Appearance",
|
"appearance": "Appearance",
|
||||||
"showWebInAppView": "Show Source Webpage in App View",
|
"showWebInAppView": "Show Source webpage in App view",
|
||||||
"pinUpdates": "Pin Updates to Top of Apps View",
|
"pinUpdates": "Pin updates to top of Apps view",
|
||||||
"updates": "Updates",
|
"updates": "Updates",
|
||||||
"sourceSpecific": "Source-Specific",
|
"sourceSpecific": "Source-Specific",
|
||||||
"appSource": "App Source",
|
"appSource": "App Source",
|
||||||
@ -226,14 +226,20 @@
|
|||||||
"autoApkFilterByArch": "Attempt to filter APKs by CPU architecture if possible",
|
"autoApkFilterByArch": "Attempt to filter APKs by CPU architecture if possible",
|
||||||
"overrideSource": "Override Source",
|
"overrideSource": "Override Source",
|
||||||
"dontShowAgain": "Don't show this again",
|
"dontShowAgain": "Don't show this again",
|
||||||
"dontShowTrackOnlyWarnings": "Don't Show 'Track-Only' Warnings",
|
"dontShowTrackOnlyWarnings": "Don't show 'Track-Only' warnings",
|
||||||
"dontShowAPKOriginWarnings": "Don't Show APK Origin Warnings",
|
"dontShowAPKOriginWarnings": "Don't show APK origin warnings",
|
||||||
"moveNonInstalledAppsToBottom": "Move Non-Installed Apps to Bottom of Apps View",
|
"moveNonInstalledAppsToBottom": "Move non-installed Apps to bottom of Apps view",
|
||||||
"gitlabPATLabel": "GitLab Personal Access Token (Enables Search)",
|
"gitlabPATLabel": "GitLab Personal Access Token\n(Enables Search and Better APK Discovery)",
|
||||||
"about": "About",
|
"about": "About",
|
||||||
"requiresCredentialsInSettings": "This needs additional credentials (in Settings)",
|
"requiresCredentialsInSettings": "This needs additional credentials (in Settings)",
|
||||||
"checkOnStart": "Check Once on Start",
|
"checkOnStart": "Check for updates on startup",
|
||||||
"tryInferAppIdFromCode": "Try inferring App ID from source code",
|
"tryInferAppIdFromCode": "Try inferring App ID from source code",
|
||||||
|
"removeOnExternalUninstall": "Automatically remove externally uninstalled Apps",
|
||||||
|
"pickHighestVersionCode": "Auto-select highest version code APK",
|
||||||
|
"checkUpdateOnDetailPage": "Check for updates on opening an App detail page",
|
||||||
|
"disablePageTransitions": "Disable page transition animations",
|
||||||
|
"reversePageTransitions": "Reverse page transition animations",
|
||||||
|
"minStarCount": "Minimum Star Count",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "Remove App?",
|
"one": "Remove App?",
|
||||||
"other": "Remove Apps?"
|
"other": "Remove Apps?"
|
||||||
|
@ -228,12 +228,18 @@
|
|||||||
"dontShowAgain": "No mostrar de nuevo",
|
"dontShowAgain": "No mostrar de nuevo",
|
||||||
"dontShowTrackOnlyWarnings": "No mostrar avisos de 'Solo Seguimiento'",
|
"dontShowTrackOnlyWarnings": "No mostrar avisos de 'Solo Seguimiento'",
|
||||||
"dontShowAPKOriginWarnings": "No mostrar avisos de las fuentes de las APks",
|
"dontShowAPKOriginWarnings": "No mostrar avisos de las fuentes de las APks",
|
||||||
"moveNonInstalledAppsToBottom": "Move Non-Installed Apps to Bottom of Apps View",
|
"moveNonInstalledAppsToBottom": "Move non-installed Apps to bottom of Apps view",
|
||||||
"gitlabPATLabel": "GitLab Personal Access Token (Enables Search)",
|
"gitlabPATLabel": "GitLab Personal Access Token\n(Enables Search and Better APK Discovery)",
|
||||||
"about": "About",
|
"about": "About",
|
||||||
"requiresCredentialsInSettings": "This needs additional credentials (in Settings)",
|
"requiresCredentialsInSettings": "This needs additional credentials (in Settings)",
|
||||||
"checkOnStart": "Check Once on Start",
|
"checkOnStart": "Check for updates on startup",
|
||||||
"tryInferAppIdFromCode": "Try inferring App ID from source code",
|
"tryInferAppIdFromCode": "Try inferring App ID from source code",
|
||||||
|
"removeOnExternalUninstall": "Automatically remove externally uninstalled Apps",
|
||||||
|
"pickHighestVersionCode": "Auto-select highest version code APK",
|
||||||
|
"checkUpdateOnDetailPage": "Check for updates on opening an App detail page",
|
||||||
|
"disablePageTransitions": "Disable page transition animations",
|
||||||
|
"reversePageTransitions": "Reverse page transition animations",
|
||||||
|
"minStarCount": "Minimum Star Count",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "¿Eliminar Aplicación?",
|
"one": "¿Eliminar Aplicación?",
|
||||||
"other": "¿Eliminar Aplicaciones?"
|
"other": "¿Eliminar Aplicaciones?"
|
||||||
|
@ -228,12 +228,18 @@
|
|||||||
"dontShowAgain": "دوباره این را نشان نده",
|
"dontShowAgain": "دوباره این را نشان نده",
|
||||||
"dontShowTrackOnlyWarnings": "هشدار 'فقط ردیابی' را نشان ندهید",
|
"dontShowTrackOnlyWarnings": "هشدار 'فقط ردیابی' را نشان ندهید",
|
||||||
"dontShowAPKOriginWarnings": "هشدارهای منبع APK را نشان ندهید",
|
"dontShowAPKOriginWarnings": "هشدارهای منبع APK را نشان ندهید",
|
||||||
"moveNonInstalledAppsToBottom": "Move Non-Installed Apps to Bottom of Apps View",
|
"moveNonInstalledAppsToBottom": "برنامه های نصب نشده را به نمای پایین برنامه ها منتقل کنید",
|
||||||
"gitlabPATLabel": "GitLab Personal Access Token (Enables Search)",
|
"gitlabPATLabel": "رمز دسترسی شخصی GitLab\n(جستجو را فعال می کند and Better APK Discovery)",
|
||||||
"about": "About",
|
"about": "درباره",
|
||||||
"requiresCredentialsInSettings": "This needs additional credentials (in Settings)",
|
"requiresCredentialsInSettings": "این به اعتبارنامه های اضافی نیاز دارد (در تنظیمات)",
|
||||||
"checkOnStart": "Check Once on Start",
|
"checkOnStart": "بررسی در شروع",
|
||||||
"tryInferAppIdFromCode": "Try inferring App ID from source code",
|
"tryInferAppIdFromCode": "شناسه برنامه را از کد منبع استنباط کنید",
|
||||||
|
"removeOnExternalUninstall": "Automatically remove externally uninstalled Apps",
|
||||||
|
"pickHighestVersionCode": "Auto-select highest version code APK",
|
||||||
|
"checkUpdateOnDetailPage": "Check for updates on opening an App detail page",
|
||||||
|
"disablePageTransitions": "Disable page transition animations",
|
||||||
|
"reversePageTransitions": "Reverse page transition animations",
|
||||||
|
"minStarCount": "Minimum Star Count",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "برنامه حذف شود؟",
|
"one": "برنامه حذف شود؟",
|
||||||
"other": "برنامه ها حذف شوند؟"
|
"other": "برنامه ها حذف شوند؟"
|
||||||
|
@ -121,7 +121,7 @@
|
|||||||
"followSystem": "Suivre le système",
|
"followSystem": "Suivre le système",
|
||||||
"obtainium": "Obtainium",
|
"obtainium": "Obtainium",
|
||||||
"materialYou": "Material You",
|
"materialYou": "Material You",
|
||||||
"useBlackTheme": "Use Pure Black Dark Theme",
|
"useBlackTheme": "Use pure black dark theme",
|
||||||
"appSortBy": "Applications triées par",
|
"appSortBy": "Applications triées par",
|
||||||
"authorName": "Auteur/Nom",
|
"authorName": "Auteur/Nom",
|
||||||
"nameAuthor": "Nom/Auteur",
|
"nameAuthor": "Nom/Auteur",
|
||||||
@ -227,13 +227,19 @@
|
|||||||
"overrideSource": "Override Source",
|
"overrideSource": "Override Source",
|
||||||
"dontShowAgain": "Don't show this again",
|
"dontShowAgain": "Don't show this again",
|
||||||
"dontShowTrackOnlyWarnings": "Don't Show the 'Track-Only' Warning",
|
"dontShowTrackOnlyWarnings": "Don't Show the 'Track-Only' Warning",
|
||||||
"dontShowAPKOriginWarnings": "Don't Show APK Origin Warnings",
|
"dontShowAPKOriginWarnings": "Don't show APK origin warnings",
|
||||||
"moveNonInstalledAppsToBottom": "Move Non-Installed Apps to Bottom of Apps View",
|
"moveNonInstalledAppsToBottom": "Move non-installed Apps to bottom of Apps view",
|
||||||
"gitlabPATLabel": "GitLab Personal Access Token (Enables Search)",
|
"gitlabPATLabel": "GitLab Personal Access Token\n(Enables Search and Better APK Discovery)",
|
||||||
"about": "About",
|
"about": "About",
|
||||||
"requiresCredentialsInSettings": "This needs additional credentials (in Settings)",
|
"requiresCredentialsInSettings": "This needs additional credentials (in Settings)",
|
||||||
"checkOnStart": "Check Once on Start",
|
"checkOnStart": "Check for updates on startup",
|
||||||
"tryInferAppIdFromCode": "Try inferring App ID from source code",
|
"tryInferAppIdFromCode": "Try inferring App ID from source code",
|
||||||
|
"removeOnExternalUninstall": "Automatically remove externally uninstalled Apps",
|
||||||
|
"pickHighestVersionCode": "Auto-select highest version code APK",
|
||||||
|
"checkUpdateOnDetailPage": "Check for updates on opening an App detail page",
|
||||||
|
"disablePageTransitions": "Disable page transition animations",
|
||||||
|
"reversePageTransitions": "Reverse page transition animations",
|
||||||
|
"minStarCount": "Minimum Star Count",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "Supprimer l'application ?",
|
"one": "Supprimer l'application ?",
|
||||||
"other": "Supprimer les applications ?"
|
"other": "Supprimer les applications ?"
|
||||||
|
@ -228,11 +228,17 @@
|
|||||||
"dontShowTrackOnlyWarnings": "Ne jelenítsen meg 'Csak nyomon követés' figyelmeztetést",
|
"dontShowTrackOnlyWarnings": "Ne jelenítsen meg 'Csak nyomon követés' figyelmeztetést",
|
||||||
"dontShowAPKOriginWarnings": "Ne jelenítsen meg az APK eredetére vonatkozó figyelmeztetéseket",
|
"dontShowAPKOriginWarnings": "Ne jelenítsen meg az APK eredetére vonatkozó figyelmeztetéseket",
|
||||||
"moveNonInstalledAppsToBottom": "Helyezze át a nem telepített appokat az App nézet aljára",
|
"moveNonInstalledAppsToBottom": "Helyezze át a nem telepített appokat az App nézet aljára",
|
||||||
"gitlabPATLabel": "GitLab Personal Access Token (Engedélyezi a Keresést)",
|
"gitlabPATLabel": "GitLab Personal Access Token\n(Engedélyezi a Keresést and Better APK Discovery)",
|
||||||
"about": "Rólunk",
|
"about": "Rólunk",
|
||||||
"requiresCredentialsInSettings": "Ehhez további hitelesítő adatokra van szükség (a Beállításokban)",
|
"requiresCredentialsInSettings": "Ehhez további hitelesítő adatokra van szükség (a Beállításokban)",
|
||||||
"checkOnStart": "Egyszer az indításkor",
|
"checkOnStart": "Egyszer az indításkor",
|
||||||
"tryInferAppIdFromCode": "Try inferring App ID from source code",
|
"tryInferAppIdFromCode": "Próbálja kikövetkeztetni az app azonosítót a forráskódból",
|
||||||
|
"removeOnExternalUninstall": "A külsőleg eltávolított appok auto. eltávolítása",
|
||||||
|
"pickHighestVersionCode": "A legmagasabb verziószámú APK auto. kiválasztása",
|
||||||
|
"checkUpdateOnDetailPage": "Frissítések keresése az app részleteit tartalmazó oldal megnyitásakor",
|
||||||
|
"disablePageTransitions": "Disable page transition animations",
|
||||||
|
"reversePageTransitions": "Reverse page transition animations",
|
||||||
|
"minStarCount": "Minimum Star Count",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "Eltávolítja az alkalmazást?",
|
"one": "Eltávolítja az alkalmazást?",
|
||||||
"other": "Eltávolítja az alkalmazást?"
|
"other": "Eltávolítja az alkalmazást?"
|
||||||
|
@ -1,25 +1,25 @@
|
|||||||
{
|
{
|
||||||
"invalidURLForSource": "URL dell'App da {} non valido",
|
"invalidURLForSource": "URL dell'app {} non valido",
|
||||||
"noReleaseFound": "Impossibile trovare una release adatta",
|
"noReleaseFound": "Impossibile trovare una release adatta",
|
||||||
"noVersionFound": "Impossibile determinare la versione della release",
|
"noVersionFound": "Impossibile determinare la versione della release",
|
||||||
"urlMatchesNoSource": "L'URL non corrisponde ad alcuna fonte conosciuta",
|
"urlMatchesNoSource": "L'URL non corrisponde ad alcuna fonte conosciuta",
|
||||||
"cantInstallOlderVersion": "Impossibile installare una versione precedente di un'App",
|
"cantInstallOlderVersion": "Impossibile installare una versione precedente di un'app",
|
||||||
"appIdMismatch": "L'ID del pacchetto scaricato non corrisponde all'ID dell'App esistente",
|
"appIdMismatch": "L'ID del pacchetto scaricato non corrisponde all'ID dell'app esistente",
|
||||||
"functionNotImplemented": "Questa classe non ha implementato questa funzione",
|
"functionNotImplemented": "Questa classe non ha implementato questa funzione",
|
||||||
"placeholder": "Segnaposto",
|
"placeholder": "Segnaposto",
|
||||||
"someErrors": "Si sono verificati degli errori",
|
"someErrors": "Si sono verificati degli errori",
|
||||||
"unexpectedError": "Errore imprevisto",
|
"unexpectedError": "Errore imprevisto",
|
||||||
"ok": "Va bene",
|
"ok": "Va bene",
|
||||||
"and": "e",
|
"and": "e",
|
||||||
"startedBgUpdateTask": "Avviata l'attività di controllo degli aggiornamenti in background",
|
"startedBgUpdateTask": "Avviata l'attività di controllo degli aggiornamenti in secondo piano",
|
||||||
"bgUpdateIgnoreAfterIs": "Bg update ignoreAfter is {}",
|
"bgUpdateIgnoreAfterIs": "Il parametro di agg. in secondo piano 'ignoreAfter' è {}",
|
||||||
"startedActualBGUpdateCheck": "Avviato il controllo effettivo degli aggiornamenti in background",
|
"startedActualBGUpdateCheck": "Avviato il controllo effettivo degli aggiornamenti in secondo piano",
|
||||||
"bgUpdateTaskFinished": "Terminata l'attività di controllo degli aggiornamenti in background",
|
"bgUpdateTaskFinished": "Terminata l'attività di controllo degli aggiornamenti in secondo piano",
|
||||||
"firstRun": "Questo è il primo avvio di sempre di Obtainium",
|
"firstRun": "Questo è il primo avvio di sempre di Obtainium",
|
||||||
"settingUpdateCheckIntervalTo": "Fissato intervallo di aggiornamento a {}",
|
"settingUpdateCheckIntervalTo": "Fissato intervallo di aggiornamento a {}",
|
||||||
"githubPATLabel": "GitHub Personal Access Token (diminuisce limite di traffico)",
|
"githubPATLabel": "GitHub Personal Access Token (diminuisce limite di traffico)",
|
||||||
"githubPATHint": "PAT deve seguire questo formato: username:token",
|
"githubPATHint": "PAT deve seguire questo formato: nomeutente:token",
|
||||||
"githubPATFormat": "username:token",
|
"githubPATFormat": "nomeutente:token",
|
||||||
"includePrereleases": "Includi prerelease",
|
"includePrereleases": "Includi prerelease",
|
||||||
"fallbackToOlderReleases": "Ripiega su release precedenti",
|
"fallbackToOlderReleases": "Ripiega su release precedenti",
|
||||||
"filterReleaseTitlesByRegEx": "Filtra release con espressioni regolari",
|
"filterReleaseTitlesByRegEx": "Filtra release con espressioni regolari",
|
||||||
@ -31,19 +31,19 @@
|
|||||||
"dropdownNoOptsError": "ERRORE: LA TENDINA DEVE AVERE ALMENO UN'OPZIONE",
|
"dropdownNoOptsError": "ERRORE: LA TENDINA DEVE AVERE ALMENO UN'OPZIONE",
|
||||||
"colour": "Colore",
|
"colour": "Colore",
|
||||||
"githubStarredRepos": "repository stellati da GitHub",
|
"githubStarredRepos": "repository stellati da GitHub",
|
||||||
"uname": "Username",
|
"uname": "Nome utente",
|
||||||
"wrongArgNum": "Numero di argomenti forniti errato",
|
"wrongArgNum": "Numero di argomenti forniti errato",
|
||||||
"xIsTrackOnly": "{} è in modalità Solo-Monitoraggio",
|
"xIsTrackOnly": "{} è in modalità Solo-Monitoraggio",
|
||||||
"source": "Fonte",
|
"source": "Fonte",
|
||||||
"app": "App",
|
"app": "App",
|
||||||
"appsFromSourceAreTrackOnly": "Le App da questa fonte sono in modalità 'Solo-Monitoraggio'.",
|
"appsFromSourceAreTrackOnly": "Le app da questa fonte sono in modalità 'Solo-Monitoraggio'.",
|
||||||
"youPickedTrackOnly": "È stata selezionata l'opzione 'Solo-Monitoraggio'.",
|
"youPickedTrackOnly": "È stata selezionata l'opzione 'Solo-Monitoraggio'.",
|
||||||
"trackOnlyAppDescription": "L'App sarà monitorata per gli aggiornamenti, ma Obtainium non sarà in grado di scaricarli o di installarli.",
|
"trackOnlyAppDescription": "L'app sarà monitorata per gli aggiornamenti, ma Obtainium non sarà in grado di scaricarli o di installarli.",
|
||||||
"cancelled": "Annullato",
|
"cancelled": "Annullato",
|
||||||
"appAlreadyAdded": "App già aggiunta",
|
"appAlreadyAdded": "App già aggiunta",
|
||||||
"alreadyUpToDateQuestion": "L'App è già aggiornata?",
|
"alreadyUpToDateQuestion": "L'app è già aggiornata?",
|
||||||
"addApp": "Aggiungi App",
|
"addApp": "Aggiungi app",
|
||||||
"appSourceURL": "URL della fonte dell'App",
|
"appSourceURL": "URL della fonte dell'app",
|
||||||
"error": "Errore",
|
"error": "Errore",
|
||||||
"add": "Aggiungi",
|
"add": "Aggiungi",
|
||||||
"searchSomeSourcesLabel": "Cerca (solo per alcune fonti)",
|
"searchSomeSourcesLabel": "Cerca (solo per alcune fonti)",
|
||||||
@ -53,10 +53,10 @@
|
|||||||
"trackOnlyInBrackets": "(Solo-Monitoraggio)",
|
"trackOnlyInBrackets": "(Solo-Monitoraggio)",
|
||||||
"searchableInBrackets": "(ricercabile)",
|
"searchableInBrackets": "(ricercabile)",
|
||||||
"appsString": "App",
|
"appsString": "App",
|
||||||
"noApps": "Nessuna App",
|
"noApps": "Nessuna app",
|
||||||
"noAppsForFilter": "Nessuna App per i filtri selezionati",
|
"noAppsForFilter": "Nessuna app per i filtri selezionati",
|
||||||
"byX": "Di {}",
|
"byX": "Di {}",
|
||||||
"percentProgress": "Progresso: {}%",
|
"percentProgress": "Avanzamento: {}%",
|
||||||
"pleaseWait": "In attesa",
|
"pleaseWait": "In attesa",
|
||||||
"updateAvailable": "Aggiornamento disponibile",
|
"updateAvailable": "Aggiornamento disponibile",
|
||||||
"estimateInBracketsShort": "(prev.)",
|
"estimateInBracketsShort": "(prev.)",
|
||||||
@ -65,31 +65,31 @@
|
|||||||
"selectAll": "Seleziona tutto",
|
"selectAll": "Seleziona tutto",
|
||||||
"deselectN": "Deseleziona {}",
|
"deselectN": "Deseleziona {}",
|
||||||
"xWillBeRemovedButRemainInstalled": "Verà effettuata la rimozione di {}, ma non la disinstallazione.",
|
"xWillBeRemovedButRemainInstalled": "Verà effettuata la rimozione di {}, ma non la disinstallazione.",
|
||||||
"removeSelectedAppsQuestion": "Rimuovere le App selezionate?",
|
"removeSelectedAppsQuestion": "Rimuovere le app selezionate?",
|
||||||
"removeSelectedApps": "Rimuovi le App selezionate",
|
"removeSelectedApps": "Rimuovi le app selezionate",
|
||||||
"updateX": "Aggiorna {}",
|
"updateX": "Aggiorna {}",
|
||||||
"installX": "Installa {}",
|
"installX": "Installa {}",
|
||||||
"markXTrackOnlyAsUpdated": "Contrassegna {}\n(Solo-Monitoraggio)\ncome aggiornato",
|
"markXTrackOnlyAsUpdated": "Contrassegna {}\n(Solo-Monitoraggio)\ncome aggiornato",
|
||||||
"changeX": "Modifica {}",
|
"changeX": "Modifica {}",
|
||||||
"installUpdateApps": "Installa/Aggiorna App",
|
"installUpdateApps": "Installa/Aggiorna app",
|
||||||
"installUpdateSelectedApps": "Installa/Aggiorna le App selezionate",
|
"installUpdateSelectedApps": "Installa/Aggiorna le app selezionate",
|
||||||
"markXSelectedAppsAsUpdated": "Contrassegnare le {} App selezionate come aggiornate?",
|
"markXSelectedAppsAsUpdated": "Contrassegnare le {} app selezionate come aggiornate?",
|
||||||
"no": "No",
|
"no": "No",
|
||||||
"yes": "Sì",
|
"yes": "Sì",
|
||||||
"markSelectedAppsUpdated": "Contrassegna le App selezionate come aggiornate",
|
"markSelectedAppsUpdated": "Contrassegna le app selezionate come aggiornate",
|
||||||
"pinToTop": "Fissa in alto",
|
"pinToTop": "Fissa in alto",
|
||||||
"unpinFromTop": "Rimuovi dall'alto",
|
"unpinFromTop": "Rimuovi dall'alto",
|
||||||
"resetInstallStatusForSelectedAppsQuestion": "Ripristinare lo stato d'installazione delle App selezionate?",
|
"resetInstallStatusForSelectedAppsQuestion": "Ripristinare lo stato d'installazione delle app selezionate?",
|
||||||
"installStatusOfXWillBeResetExplanation": "Lo stato d'installazione di ogni App selezionata sarà ripristinato.\n\nCiò può essere d'aiuto nel caso in cui la versione mostrata dell'App in Obtainium non è corretta a causa di un aggiornamento fallito o di altri problemi.",
|
"installStatusOfXWillBeResetExplanation": "Lo stato d'installazione di ogni app selezionata sarà ripristinato.\n\nCiò può essere d'aiuto nel caso in cui la versione mostrata dell'app in Obtainium non sia corretta a causa di un aggiornamento fallito o di altri problemi.",
|
||||||
"shareSelectedAppURLs": "Condividi gli URL delle App selezionate",
|
"shareSelectedAppURLs": "Condividi gli URL delle app selezionate",
|
||||||
"resetInstallStatus": "Ripristina lo stato d'installazione",
|
"resetInstallStatus": "Ripristina lo stato d'installazione",
|
||||||
"more": "Di più",
|
"more": "Altro",
|
||||||
"removeOutdatedFilter": "Rimuovi il filtro per le App non aggiornate",
|
"removeOutdatedFilter": "Rimuovi il filtro per le app non aggiornate",
|
||||||
"showOutdatedOnly": "Mostra solo le App non aggiornate",
|
"showOutdatedOnly": "Mostra solo le app non aggiornate",
|
||||||
"filter": "Filtri",
|
"filter": "Filtri",
|
||||||
"filterActive": "Filtri *",
|
"filterActive": "Filtri *",
|
||||||
"filterApps": "Filtra App",
|
"filterApps": "Filtra app",
|
||||||
"appName": "Nome dell'App",
|
"appName": "Nome dell'app",
|
||||||
"author": "Autore",
|
"author": "Autore",
|
||||||
"upToDateApps": "App aggiornate",
|
"upToDateApps": "App aggiornate",
|
||||||
"nonInstalledApps": "App non installate",
|
"nonInstalledApps": "App non installate",
|
||||||
@ -102,14 +102,14 @@
|
|||||||
"obtainiumImport": "Importa in Obtainium",
|
"obtainiumImport": "Importa in Obtainium",
|
||||||
"importFromURLList": "Importa da lista di URL",
|
"importFromURLList": "Importa da lista di URL",
|
||||||
"searchQuery": "Stringa di ricerca",
|
"searchQuery": "Stringa di ricerca",
|
||||||
"appURLList": "Lista di URL delle App",
|
"appURLList": "Lista di URL delle app",
|
||||||
"line": "Linea",
|
"line": "Linea",
|
||||||
"searchX": "Cerca su {}",
|
"searchX": "Cerca su {}",
|
||||||
"noResults": "Nessun risultato trovato",
|
"noResults": "Nessun risultato trovato",
|
||||||
"importX": "Importa {}",
|
"importX": "Importa {}",
|
||||||
"importedAppsIdDisclaimer": "Le App importate potrebbero essere visualizzate erroneamente come \"Non installate\".\nPer risolvere il problema, reinstallale con Obtainium.\nQuesto non dovrebbe influire sui dati delle App.\n\nRiguarda solo l'URL e i metodi di importazione di terze parti.",
|
"importedAppsIdDisclaimer": "Le app importate potrebbero essere visualizzate erroneamente come \"Non installate\".\nPer risolvere il problema, reinstallale con Obtainium.\nCiò non dovrebbe influire sui dati delle app.\n\nRiguarda solo l'URL e i metodi di importazione di terze parti.",
|
||||||
"importErrors": "Errori dell'importazione",
|
"importErrors": "Errori di importazione",
|
||||||
"importedXOfYApps": "{} App di {} importate.",
|
"importedXOfYApps": "{} app di {} importate.",
|
||||||
"followingURLsHadErrors": "I seguenti URL contengono errori:",
|
"followingURLsHadErrors": "I seguenti URL contengono errori:",
|
||||||
"okay": "Va bene",
|
"okay": "Va bene",
|
||||||
"selectURL": "Seleziona l'URL",
|
"selectURL": "Seleziona l'URL",
|
||||||
@ -118,27 +118,27 @@
|
|||||||
"theme": "Tema",
|
"theme": "Tema",
|
||||||
"dark": "Scuro",
|
"dark": "Scuro",
|
||||||
"light": "Chiaro",
|
"light": "Chiaro",
|
||||||
"followSystem": "Segui sistema",
|
"followSystem": "Segui il sistema",
|
||||||
"obtainium": "Obtainium",
|
"obtainium": "Obtainium",
|
||||||
"materialYou": "Material You",
|
"materialYou": "Material You",
|
||||||
"useBlackTheme": "Use Pure Black Dark Theme",
|
"useBlackTheme": "Usa il tema Nero puro",
|
||||||
"appSortBy": "App ordinate per",
|
"appSortBy": "App ordinate per",
|
||||||
"authorName": "Autore/Nome",
|
"authorName": "Autore/Nome",
|
||||||
"nameAuthor": "Nome/Autore",
|
"nameAuthor": "Nome/Autore",
|
||||||
"asAdded": "Data di aggiunta",
|
"asAdded": "Data di aggiunta",
|
||||||
"appSortOrder": "Ordinamento",
|
"appSortOrder": "Ordine",
|
||||||
"ascending": "Ascendente",
|
"ascending": "Ascendente",
|
||||||
"descending": "Discendente",
|
"descending": "Discendente",
|
||||||
"bgUpdateCheckInterval": "Intervallo di controllo degli aggiornamenti in background",
|
"bgUpdateCheckInterval": "Intervallo di controllo degli aggiornamenti in secondo piano",
|
||||||
"neverManualOnly": "Mai - Solo manuale",
|
"neverManualOnly": "Mai - Solo manuale",
|
||||||
"appearance": "Aspetto",
|
"appearance": "Aspetto",
|
||||||
"showWebInAppView": "Mostra pagina web dell'App se selezionata",
|
"showWebInAppView": "Mostra pagina web dell'app se selezionata",
|
||||||
"pinUpdates": "Fissa aggiornamenti disponibili in alto",
|
"pinUpdates": "Fissa aggiornamenti disponibili in alto",
|
||||||
"updates": "Aggiornamenti",
|
"updates": "Aggiornamenti",
|
||||||
"sourceSpecific": "Specifiche per la fonte",
|
"sourceSpecific": "Specifiche per la fonte",
|
||||||
"appSource": "Sorgente dell'App",
|
"appSource": "Sorgente dell'app",
|
||||||
"noLogs": "Nessun log",
|
"noLogs": "Nessun log",
|
||||||
"appLogs": "Log dell'App",
|
"appLogs": "Log dell'app",
|
||||||
"close": "Chiudi",
|
"close": "Chiudi",
|
||||||
"share": "Condividi",
|
"share": "Condividi",
|
||||||
"appNotFound": "App non trovata",
|
"appNotFound": "App non trovata",
|
||||||
@ -148,28 +148,28 @@
|
|||||||
"deviceSupportsXArch": "Il dispositivo in uso supporta l'architettura {} della CPU.",
|
"deviceSupportsXArch": "Il dispositivo in uso supporta l'architettura {} della CPU.",
|
||||||
"deviceSupportsFollowingArchs": "Il dispositivo in uso supporta le seguenti architetture della CPU:",
|
"deviceSupportsFollowingArchs": "Il dispositivo in uso supporta le seguenti architetture della CPU:",
|
||||||
"warning": "Attenzione",
|
"warning": "Attenzione",
|
||||||
"sourceIsXButPackageFromYPrompt": "L'origine dell'App è '{}' ma il pacchetto della release proviene da '{}'. Continuare?",
|
"sourceIsXButPackageFromYPrompt": "L'origine dell'app è '{}' ma il pacchetto della release proviene da '{}'. Continuare?",
|
||||||
"updatesAvailable": "Aggiornamenti disponibili",
|
"updatesAvailable": "Aggiornamenti disponibili",
|
||||||
"updatesAvailableNotifDescription": "Notifica all'utente che sono disponibili gli aggiornamenti di una o più App monitorate da Obtainium",
|
"updatesAvailableNotifDescription": "Notifica all'utente che sono disponibili gli aggiornamenti di una o più app monitorate da Obtainium",
|
||||||
"noNewUpdates": "Nessun nuovo aggiornamento.",
|
"noNewUpdates": "Nessun nuovo aggiornamento.",
|
||||||
"xHasAnUpdate": "Aggiornamento disponibile per {}",
|
"xHasAnUpdate": "Aggiornamento disponibile per {}",
|
||||||
"appsUpdated": "App aggiornate",
|
"appsUpdated": "App aggiornate",
|
||||||
"appsUpdatedNotifDescription": "Notifica all'utente che una o più App sono state aggiornate in background",
|
"appsUpdatedNotifDescription": "Notifica all'utente che una o più app sono state aggiornate in secondo piano",
|
||||||
"xWasUpdatedToY": "{} è stato aggiornato a {}.",
|
"xWasUpdatedToY": "{} è stato aggiornato alla {}.",
|
||||||
"errorCheckingUpdates": "Controllo degli errori per gli aggiornamenti",
|
"errorCheckingUpdates": "Controllo degli errori per gli aggiornamenti",
|
||||||
"errorCheckingUpdatesNotifDescription": "Una notifica che mostra quando il controllo degli aggiornamenti in background fallisce",
|
"errorCheckingUpdatesNotifDescription": "Una notifica che mostra quando il controllo degli aggiornamenti in secondo piano fallisce",
|
||||||
"appsRemoved": "App rimosse",
|
"appsRemoved": "App rimosse",
|
||||||
"appsRemovedNotifDescription": "Notifica all'utente che una o più App sono state rimosse a causa di errori durante il caricamento",
|
"appsRemovedNotifDescription": "Notifica all'utente che una o più app sono state rimosse a causa di errori durante il caricamento",
|
||||||
"xWasRemovedDueToErrorY": "{} è stata rimosso a causa di questo errore: {}",
|
"xWasRemovedDueToErrorY": "{} è stata rimosso a causa di questo errore: {}",
|
||||||
"completeAppInstallation": "Completa l'installazione dell'App",
|
"completeAppInstallation": "Completa l'installazione dell'app",
|
||||||
"obtainiumMustBeOpenToInstallApps": "Obtainium deve essere aperto per poter installare le App",
|
"obtainiumMustBeOpenToInstallApps": "Obtainium deve essere aperto per poter installare le app",
|
||||||
"completeAppInstallationNotifDescription": "Chiede all'utente di riaprire Obtainium per terminare l'installazione di un App",
|
"completeAppInstallationNotifDescription": "Chiede all'utente di riaprire Obtainium per terminare l'installazione di un'app",
|
||||||
"checkingForUpdates": "Controllo degli aggiornamenti in corso",
|
"checkingForUpdates": "Controllo degli aggiornamenti in corso",
|
||||||
"checkingForUpdatesNotifDescription": "Notifica transitoria che appare durante la verifica degli aggiornamenti",
|
"checkingForUpdatesNotifDescription": "Notifica transitoria che appare durante la verifica degli aggiornamenti",
|
||||||
"pleaseAllowInstallPerm": "Per favore permetti a Obtainium di installare le App",
|
"pleaseAllowInstallPerm": "Per favore permetti a Obtainium di installare le app",
|
||||||
"trackOnly": "Solo-Monitoraggio",
|
"trackOnly": "Solo-Monitoraggio",
|
||||||
"errorWithHttpStatusCode": "Errore {}",
|
"errorWithHttpStatusCode": "Errore {}",
|
||||||
"versionCorrectionDisabled": "Correzione della versione disabilitata (il plugin non pare funzionare)",
|
"versionCorrectionDisabled": "Correzione della versione disattivata (il plugin sembra non funzionare)",
|
||||||
"unknown": "Sconosciuto",
|
"unknown": "Sconosciuto",
|
||||||
"none": "Nessuno",
|
"none": "Nessuno",
|
||||||
"never": "Mai",
|
"never": "Mai",
|
||||||
@ -178,11 +178,11 @@
|
|||||||
"lastUpdateCheckX": "Ultimo controllo degli aggiornamenti: {}",
|
"lastUpdateCheckX": "Ultimo controllo degli aggiornamenti: {}",
|
||||||
"remove": "Rimuovi",
|
"remove": "Rimuovi",
|
||||||
"yesMarkUpdated": "Sì, contrassegna come aggiornato",
|
"yesMarkUpdated": "Sì, contrassegna come aggiornato",
|
||||||
"fdroid": "F-Droid Official",
|
"fdroid": "F-Droid ufficiale",
|
||||||
"appIdOrName": "ID o nome dell'App",
|
"appIdOrName": "ID o nome dell'app",
|
||||||
"appId": "ID dell'App",
|
"appId": "ID dell'app",
|
||||||
"appWithIdOrNameNotFound": "Non è stata trovata alcuna App con quell'ID o nome",
|
"appWithIdOrNameNotFound": "Non è stata trovata alcuna app con quell'ID o nome",
|
||||||
"reposHaveMultipleApps": "I repository possono contenere più App",
|
"reposHaveMultipleApps": "I repository possono contenere più app",
|
||||||
"fdroidThirdPartyRepo": "Repository F-Droid di terze parti",
|
"fdroidThirdPartyRepo": "Repository F-Droid di terze parti",
|
||||||
"steam": "Steam",
|
"steam": "Steam",
|
||||||
"steamMobile": "Steam Mobile",
|
"steamMobile": "Steam Mobile",
|
||||||
@ -193,9 +193,9 @@
|
|||||||
"markUpdated": "Contrassegna come aggiornato",
|
"markUpdated": "Contrassegna come aggiornato",
|
||||||
"additionalOptions": "Opzioni aggiuntive",
|
"additionalOptions": "Opzioni aggiuntive",
|
||||||
"disableVersionDetection": "Disattiva il rilevamento della versione",
|
"disableVersionDetection": "Disattiva il rilevamento della versione",
|
||||||
"noVersionDetectionExplanation": "Questa opzione dovrebbe essere usata solo per le App la cui versione non viene rilevata correttamente.",
|
"noVersionDetectionExplanation": "Questa opzione dovrebbe essere usata solo per le app la cui versione non viene rilevata correttamente.",
|
||||||
"downloadingX": "Scaricamento di {} in corso",
|
"downloadingX": "Scaricamento di {} in corso",
|
||||||
"downloadNotifDescription": "Notifica all'utente lo stato di avanzamento del download di un'App",
|
"downloadNotifDescription": "Notifica all'utente lo stato di avanzamento del download di un'app",
|
||||||
"noAPKFound": "Nessun APK trovato",
|
"noAPKFound": "Nessun APK trovato",
|
||||||
"noVersionDetection": "Disattiva rilevamento di versione",
|
"noVersionDetection": "Disattiva rilevamento di versione",
|
||||||
"categorize": "Aggiungi a categoria",
|
"categorize": "Aggiungi a categoria",
|
||||||
@ -204,19 +204,19 @@
|
|||||||
"noCategory": "Nessuna categoria",
|
"noCategory": "Nessuna categoria",
|
||||||
"noCategories": "Nessuna categoria",
|
"noCategories": "Nessuna categoria",
|
||||||
"deleteCategoriesQuestion": "Eliminare le categorie?",
|
"deleteCategoriesQuestion": "Eliminare le categorie?",
|
||||||
"categoryDeleteWarning": "Tutte le App nelle categorie eliminate saranno impostate come non categorizzate.",
|
"categoryDeleteWarning": "Tutte le app nelle categorie eliminate saranno impostate come non categorizzate.",
|
||||||
"addCategory": "Aggiungi categoria",
|
"addCategory": "Aggiungi categoria",
|
||||||
"label": "Etichetta",
|
"label": "Etichetta",
|
||||||
"language": "Lingua",
|
"language": "Lingua",
|
||||||
"copiedToClipboard": "Copiato negli appunti",
|
"copiedToClipboard": "Copiato negli appunti",
|
||||||
"storagePermissionDenied": "Accesso ai file non autorizzato",
|
"storagePermissionDenied": "Accesso ai file non autorizzato",
|
||||||
"selectedCategorizeWarning": "Ciò sostituirà le impostazioni di categoria esistenti per le App selezionate.",
|
"selectedCategorizeWarning": "Ciò sostituirà le impostazioni di categoria esistenti per le app selezionate.",
|
||||||
"filterAPKsByRegEx": "Filtra file APK con espressioni regolari",
|
"filterAPKsByRegEx": "Filtra file APK con espressioni regolari",
|
||||||
"removeFromObtainium": "Rimuovi da Obtainium",
|
"removeFromObtainium": "Rimuovi da Obtainium",
|
||||||
"uninstallFromDevice": "Disinstalla dal dispositivo",
|
"uninstallFromDevice": "Disinstalla dal dispositivo",
|
||||||
"onlyWorksWithNonVersionDetectApps": "Funziona solo per le App con il rilevamento della versione disattivato.",
|
"onlyWorksWithNonVersionDetectApps": "Funziona solo per le app con il rilevamento della versione disattivato.",
|
||||||
"releaseDateAsVersion": "Usa data di rilascio come versione",
|
"releaseDateAsVersion": "Usa data di rilascio come versione",
|
||||||
"releaseDateAsVersionExplanation": "Questa opzione dovrebbe essere usata solo per le App in cui il rilevamento della versione non funziona correttamente, ma è disponibile una data di rilascio.",
|
"releaseDateAsVersionExplanation": "Questa opzione dovrebbe essere usata solo per le app in cui il rilevamento della versione non funziona correttamente, ma è disponibile una data di rilascio.",
|
||||||
"changes": "Novità",
|
"changes": "Novità",
|
||||||
"releaseDate": "Data di rilascio",
|
"releaseDate": "Data di rilascio",
|
||||||
"importFromURLsInFile": "Importa da URL in file (come OPML)",
|
"importFromURLsInFile": "Importa da URL in file (come OPML)",
|
||||||
@ -224,35 +224,41 @@
|
|||||||
"standardVersionDetection": "Rilevamento di versione standard",
|
"standardVersionDetection": "Rilevamento di versione standard",
|
||||||
"groupByCategory": "Raggruppa per categoria",
|
"groupByCategory": "Raggruppa per categoria",
|
||||||
"autoApkFilterByArch": "Tenta di filtrare gli APK in base all'architettura della CPU, se possibile",
|
"autoApkFilterByArch": "Tenta di filtrare gli APK in base all'architettura della CPU, se possibile",
|
||||||
"overrideSource": "Override Source",
|
"overrideSource": "Sovrascrivi fonte",
|
||||||
"dontShowAgain": "Don't show this again",
|
"dontShowAgain": "Non mostrarlo più",
|
||||||
"dontShowTrackOnlyWarnings": "Don't Show the 'Track-Only' Warning",
|
"dontShowTrackOnlyWarnings": "Non mostrare gli avvisi 'Solo-Monitoraggio'",
|
||||||
"dontShowAPKOriginWarnings": "Don't Show APK Origin Warnings",
|
"dontShowAPKOriginWarnings": "Non mostrare gli avvisi di origine dell'APK",
|
||||||
"moveNonInstalledAppsToBottom": "Move Non-Installed Apps to Bottom of Apps View",
|
"moveNonInstalledAppsToBottom": "Sposta le app non installate in fondo alla lista",
|
||||||
"gitlabPATLabel": "GitLab Personal Access Token (Enables Search)",
|
"gitlabPATLabel": "GitLab Personal Access Token\n(attiva la ricerca and Better APK Discovery)",
|
||||||
"about": "About",
|
"about": "Informazioni",
|
||||||
"requiresCredentialsInSettings": "This needs additional credentials (in Settings)",
|
"requiresCredentialsInSettings": "Servono credenziali aggiuntive (in Impostazioni)",
|
||||||
"checkOnStart": "Check Once on Start",
|
"checkOnStart": "Controlla una volta all'avvio",
|
||||||
"tryInferAppIdFromCode": "Try inferring App ID from source code",
|
"tryInferAppIdFromCode": "Prova a dedurre l'ID dell'app dal codice sorgente",
|
||||||
|
"removeOnExternalUninstall": "Automatically remove externally uninstalled Apps",
|
||||||
|
"pickHighestVersionCode": "Auto-select highest version code APK",
|
||||||
|
"checkUpdateOnDetailPage": "Check for updates on opening an App detail page",
|
||||||
|
"disablePageTransitions": "Disable page transition animations",
|
||||||
|
"reversePageTransitions": "Reverse page transition animations",
|
||||||
|
"minStarCount": "Minimum Star Count",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "Rimuovere l'App?",
|
"one": "Rimuovere l'app?",
|
||||||
"other": "Rimuovere le App?"
|
"other": "Rimuovere le app?"
|
||||||
},
|
},
|
||||||
"tooManyRequestsTryAgainInMinutes": {
|
"tooManyRequestsTryAgainInMinutes": {
|
||||||
"one": "Troppe richieste (traffico limitato) - riprova tra {} minuto",
|
"one": "Troppe richieste (traffico limitato) - riprova tra {} minuto",
|
||||||
"other": "Troppe richieste (traffico limitato) - riprova tra {} minuti"
|
"other": "Troppe richieste (traffico limitato) - riprova tra {} minuti"
|
||||||
},
|
},
|
||||||
"bgUpdateGotErrorRetryInMinutes": {
|
"bgUpdateGotErrorRetryInMinutes": {
|
||||||
"one": "Il controllo degli aggiornamenti in background ha incontrato un {}, nuovo tentativo tra {} minuto",
|
"one": "Il controllo degli aggiornamenti in secondo piano ha riscontrato un {}, nuovo tentativo tra {} minuto",
|
||||||
"other": "Il controllo degli aggiornamenti in background ha incontrato un {}, nuovo tentativo tra {} minuti"
|
"other": "Il controllo degli aggiornamenti in secondo piano ha riscontrato un {}, nuovo tentativo tra {} minuti"
|
||||||
},
|
},
|
||||||
"bgCheckFoundUpdatesWillNotifyIfNeeded": {
|
"bgCheckFoundUpdatesWillNotifyIfNeeded": {
|
||||||
"one": "Il controllo degli aggiornamenti in background ha trovato {} aggiornamento - notificherà l'utente se necessario",
|
"one": "Il controllo degli aggiornamenti in secondo piano ha trovato {} aggiornamento - notificherà l'utente se necessario",
|
||||||
"other": "Il controllo degli aggiornamenti in background ha trovato {} aggiornamenti - notificherà l'utente se necessario"
|
"other": "Il controllo degli aggiornamenti in secondo piano ha trovato {} aggiornamenti - notificherà l'utente se necessario"
|
||||||
},
|
},
|
||||||
"apps": {
|
"apps": {
|
||||||
"one": "{} App",
|
"one": "{} app",
|
||||||
"other": "{} App"
|
"other": "{} app"
|
||||||
},
|
},
|
||||||
"url": {
|
"url": {
|
||||||
"one": "{} URL",
|
"one": "{} URL",
|
||||||
@ -271,15 +277,15 @@
|
|||||||
"other": "{} giorni"
|
"other": "{} giorni"
|
||||||
},
|
},
|
||||||
"clearedNLogsBeforeXAfterY": {
|
"clearedNLogsBeforeXAfterY": {
|
||||||
"one": "Pulito {n} log (prima = {before}, dopo = {after})",
|
"one": "Rimosso {n} log (prima = {before}, dopo = {after})",
|
||||||
"other": "Puliti {n} log (prima = {before}, dopo = {after})"
|
"other": "Rimossi {n} log (prima = {before}, dopo = {after})"
|
||||||
},
|
},
|
||||||
"xAndNMoreUpdatesAvailable": {
|
"xAndNMoreUpdatesAvailable": {
|
||||||
"one": "{} e un'altra App hanno aggiornamenti disponibili.",
|
"one": "{} e un'altra app hanno aggiornamenti disponibili.",
|
||||||
"other": "{} e altre {} App hanno aggiornamenti disponibili."
|
"other": "{} e altre {} app hanno aggiornamenti disponibili."
|
||||||
},
|
},
|
||||||
"xAndNMoreUpdatesInstalled": {
|
"xAndNMoreUpdatesInstalled": {
|
||||||
"one": "{} e un'altra App sono state aggiornate.",
|
"one": "{} e un'altra app sono state aggiornate.",
|
||||||
"other": "{} e altre {} App sono state aggiornate."
|
"other": "{} e altre {} app sono state aggiornate."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -135,7 +135,7 @@
|
|||||||
"showWebInAppView": "アプリページにソースのWebページを表示する",
|
"showWebInAppView": "アプリページにソースのWebページを表示する",
|
||||||
"pinUpdates": "アップデートがあるアプリをトップに固定する",
|
"pinUpdates": "アップデートがあるアプリをトップに固定する",
|
||||||
"updates": "アップデート",
|
"updates": "アップデート",
|
||||||
"sourceSpecific": "Github アクセストークン",
|
"sourceSpecific": "ソース別の設定",
|
||||||
"appSource": "アプリのソース",
|
"appSource": "アプリのソース",
|
||||||
"noLogs": "ログはありません",
|
"noLogs": "ログはありません",
|
||||||
"appLogs": "アプリのログ",
|
"appLogs": "アプリのログ",
|
||||||
@ -227,13 +227,19 @@
|
|||||||
"overrideSource": "ソースの上書き",
|
"overrideSource": "ソースの上書き",
|
||||||
"dontShowAgain": "二度と表示しない",
|
"dontShowAgain": "二度と表示しない",
|
||||||
"dontShowTrackOnlyWarnings": "「追跡のみ」の警告を表示しない",
|
"dontShowTrackOnlyWarnings": "「追跡のみ」の警告を表示しない",
|
||||||
"dontShowAPKOriginWarnings": "APK Originの警告を表示しない",
|
"dontShowAPKOriginWarnings": "APKのダウンロード元の警告を表示しない",
|
||||||
"moveNonInstalledAppsToBottom": "未インストールのアプリをアプリ一覧の下部に移動させる",
|
"moveNonInstalledAppsToBottom": "未インストールのアプリをアプリ一覧の下部に移動させる",
|
||||||
"gitlabPATLabel": "GitLab パーソナルアクセストークン (検索を有効化する)",
|
"gitlabPATLabel": "GitLab パーソナルアクセストークン\n(検索とより良いAPK検出の有効化)",
|
||||||
"about": "概要",
|
"about": "概要",
|
||||||
"requiresCredentialsInSettings": "これには追加の認証が必要です (設定にて)",
|
"requiresCredentialsInSettings": "これには追加の認証が必要です (設定にて)",
|
||||||
"checkOnStart": "Check Once on Start",
|
"checkOnStart": "起動時にアップデートを確認する",
|
||||||
"tryInferAppIdFromCode": "Try inferring App ID from source code",
|
"tryInferAppIdFromCode": "ソースコードからApp IDを推測する",
|
||||||
|
"removeOnExternalUninstall": "外部でアンインストールされたアプリを自動的に削除する",
|
||||||
|
"pickHighestVersionCode": "最も高いバージョンコードのAPKを自動的に選択する",
|
||||||
|
"checkUpdateOnDetailPage": "アプリの詳細ページを開く際にアップデートを確認する",
|
||||||
|
"disablePageTransitions": "ページ遷移アニメーションを無効化する",
|
||||||
|
"reversePageTransitions": "ページ遷移アニメーションを反転する",
|
||||||
|
"minStarCount": "Minimum Star Count",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "アプリを削除しますか?",
|
"one": "アプリを削除しますか?",
|
||||||
"other": "アプリを削除しますか?"
|
"other": "アプリを削除しますか?"
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
"noVersionFound": "Nie można określić wersji wydania",
|
"noVersionFound": "Nie można określić wersji wydania",
|
||||||
"urlMatchesNoSource": "Adres URL nie pasuje do znanego źródła",
|
"urlMatchesNoSource": "Adres URL nie pasuje do znanego źródła",
|
||||||
"cantInstallOlderVersion": "Nie można zainstalować starszej wersji aplikacji",
|
"cantInstallOlderVersion": "Nie można zainstalować starszej wersji aplikacji",
|
||||||
"appIdMismatch": "Pobrany identyfikator pakietu nie pasuje do istniejącego identyfikatora aplikacji",
|
"appIdMismatch": "Pobrane ID pakietu nie pasuje do istniejącego ID aplikacji",
|
||||||
"functionNotImplemented": "Ta klasa nie zaimplementowała tej funkcji",
|
"functionNotImplemented": "Ta klasa nie zaimplementowała tej funkcji",
|
||||||
"placeholder": "Placeholder",
|
"placeholder": "Placeholder",
|
||||||
"someErrors": "Wystąpiły pewne błędy",
|
"someErrors": "Wystąpiły pewne błędy",
|
||||||
@ -25,8 +25,8 @@
|
|||||||
"bgUpdateTaskFinished": "Zakończono zadanie sprawdzania aktualizacji w tle",
|
"bgUpdateTaskFinished": "Zakończono zadanie sprawdzania aktualizacji w tle",
|
||||||
"firstRun": "Jest to pierwsze uruchomienie Obtainium",
|
"firstRun": "Jest to pierwsze uruchomienie Obtainium",
|
||||||
"settingUpdateCheckIntervalTo": "Ustawianie interwału aktualizacji na {}",
|
"settingUpdateCheckIntervalTo": "Ustawianie interwału aktualizacji na {}",
|
||||||
"githubPATLabel": "Osobisty Token Dostępu GitHub (zwiększa limit zapytań)",
|
"githubPATLabel": "Osobisty token dostępu GitHub (zwiększa limit zapytań)",
|
||||||
"githubPATHint": "Wymagany format OTD: użytkownik:token",
|
"githubPATHint": "Wymagany format: użytkownik:token",
|
||||||
"githubPATFormat": "użytkownik:token",
|
"githubPATFormat": "użytkownik:token",
|
||||||
"includePrereleases": "Uwzględnij wersje wstępne",
|
"includePrereleases": "Uwzględnij wersje wstępne",
|
||||||
"fallbackToOlderReleases": "Powracaj do starszych wersji",
|
"fallbackToOlderReleases": "Powracaj do starszych wersji",
|
||||||
@ -230,14 +230,20 @@
|
|||||||
"autoApkFilterByArch": "Spróbuj filtrować pliki APK według architektury procesora, jeśli to możliwe",
|
"autoApkFilterByArch": "Spróbuj filtrować pliki APK według architektury procesora, jeśli to możliwe",
|
||||||
"overrideSource": "Nadpisz źródło",
|
"overrideSource": "Nadpisz źródło",
|
||||||
"dontShowAgain": "Nie pokazuj tego ponownie",
|
"dontShowAgain": "Nie pokazuj tego ponownie",
|
||||||
"dontShowTrackOnlyWarnings": "Nie wyświetlaj ostrzeżeń „Tylko obserwowana”",
|
"dontShowTrackOnlyWarnings": "Nie pokazuj ostrzeżeń „Tylko obserwowana”",
|
||||||
"dontShowAPKOriginWarnings": "Nie pokazuj ostrzeżeń o pochodzeniu APK",
|
"dontShowAPKOriginWarnings": "Nie pokazuj ostrzeżeń o pochodzeniu APK",
|
||||||
"moveNonInstalledAppsToBottom": "Przenieś niezainstalowane aplikacje na dół widoku aplikacji",
|
"moveNonInstalledAppsToBottom": "Przenieś niezainstalowane aplikacje na dół widoku aplikacji",
|
||||||
"gitlabPATLabel": "Osobisty Token Dostępu GitLab (umożliwia wyszukiwanie)",
|
"gitlabPATLabel": "Osobisty token dostępu GitLab\n(Umożliwia wyszukiwanie i lepsze wykrywanie APK)",
|
||||||
"about": "Więcej informacji",
|
"about": "Więcej informacji",
|
||||||
"requiresCredentialsInSettings": "Wymaga to dodatkowych poświadczeń (w Ustawieniach)",
|
"requiresCredentialsInSettings": "Wymaga to dodatkowych poświadczeń (w Ustawieniach)",
|
||||||
"checkOnStart": "Sprawdź raz przy starcie",
|
"checkOnStart": "Sprawdź aktualizacje przy uruchomieniu",
|
||||||
"tryInferAppIdFromCode": "Spróbuj wywnioskować identyfikator aplikacji z kodu źródłowego",
|
"tryInferAppIdFromCode": "Spróbuj wywnioskować identyfikator aplikacji z kodu źródłowego",
|
||||||
|
"removeOnExternalUninstall": "Automatyczne usuń odinstalowane zewnętrznie aplikacje",
|
||||||
|
"pickHighestVersionCode": "Automatycznie wybierz najwyższy kod wersji APK",
|
||||||
|
"checkUpdateOnDetailPage": "Sprawdzaj aktualizacje podczas otwierania strony szczegółów aplikacji",
|
||||||
|
"disablePageTransitions": "Wyłącz animacje przejścia między stronami",
|
||||||
|
"reversePageTransitions": "Odwróć animacje przejścia pomiędzy stronami",
|
||||||
|
"minStarCount": "Minimum Star Count",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "Usunąć aplikację?",
|
"one": "Usunąć aplikację?",
|
||||||
"other": "Usunąć aplikacje?"
|
"other": "Usunąć aplikacje?"
|
||||||
|
291
assets/translations/ru.json
Normal file
291
assets/translations/ru.json
Normal file
@ -0,0 +1,291 @@
|
|||||||
|
{
|
||||||
|
"invalidURLForSource": "Неверный URL-адрес {} приложения",
|
||||||
|
"noReleaseFound": "Не удалось найти подходящий релиз",
|
||||||
|
"noVersionFound": "Не удалось определить версию релиза",
|
||||||
|
"urlMatchesNoSource": "URL-адрес не соответствует известному источнику",
|
||||||
|
"cantInstallOlderVersion": "Невозможно установить более старую версию приложения",
|
||||||
|
"appIdMismatch": "ID загруженного пакета не совпадает с существующим ID приложения",
|
||||||
|
"functionNotImplemented": "Этот класс не реализовал эту функцию",
|
||||||
|
"placeholder": "Заполнитель",
|
||||||
|
"someErrors": "Возникли некоторые ошибки",
|
||||||
|
"unexpectedError": "Неожиданная ошибка",
|
||||||
|
"ok": "Окей",
|
||||||
|
"and": "и",
|
||||||
|
"startedBgUpdateTask": "Запущена задача фоновой проверки обновлений",
|
||||||
|
"bgUpdateIgnoreAfterIs": "Параметр игнорирования фоновых обновлений: {}",
|
||||||
|
"startedActualBGUpdateCheck": "Запущена фактическая проверка фоновых обновлений",
|
||||||
|
"bgUpdateTaskFinished": "Завершена задача фоновой проверки обновлений",
|
||||||
|
"firstRun": "Это первый запуск Obtainium",
|
||||||
|
"settingUpdateCheckIntervalTo": "Установка интервала проверки обновлений: {}",
|
||||||
|
"githubPATLabel": "Персональный токен доступа GitHub (увеличивает лимит запросов)",
|
||||||
|
"githubPATHint": "Токен доступа должен быть в формате: имя_пользователя:токен",
|
||||||
|
"githubPATFormat": "имя_пользователя:токен",
|
||||||
|
"includePrereleases": "Включить предварительные релизы",
|
||||||
|
"fallbackToOlderReleases": "Откатиться к более старым версиям",
|
||||||
|
"filterReleaseTitlesByRegEx": "Фильтровать заголовки релизов\nс помощью регулярного выражения",
|
||||||
|
"invalidRegEx": "Неверное регулярное выражение",
|
||||||
|
"noDescription": "Нет описания",
|
||||||
|
"cancel": "Отмена",
|
||||||
|
"continue": "Продолжить",
|
||||||
|
"requiredInBrackets": "(Обязательно)",
|
||||||
|
"dropdownNoOptsError": "Ошибка: Выпадающий список должен содержать хотя бы одну опцию",
|
||||||
|
"colour": "Цвет",
|
||||||
|
"githubStarredRepos": "Помеченные звездочкой репозитории на GitHub",
|
||||||
|
"uname": "Имя пользователя",
|
||||||
|
"wrongArgNum": "Неправильное количество предоставленных аргументов",
|
||||||
|
"xIsTrackOnly": "{} только для отслеживания",
|
||||||
|
"source": "Источник",
|
||||||
|
"app": "Приложение",
|
||||||
|
"appsFromSourceAreTrackOnly": "Приложения из этого источника являются 'только для отслеживания'.",
|
||||||
|
"youPickedTrackOnly": "Вы выбрали опцию 'Только для отслеживания'.",
|
||||||
|
"trackOnlyAppDescription": "Приложение будет отслеживаться на предмет обновлений, но Obtainium не сможет загрузить или установить его.",
|
||||||
|
"cancelled": "Отменено",
|
||||||
|
"appAlreadyAdded": "Приложение уже добавлено",
|
||||||
|
"alreadyUpToDateQuestion": "Приложение уже обновлено?",
|
||||||
|
"addApp": "Добавить приложение",
|
||||||
|
"appSourceURL": "URL-источник приложения",
|
||||||
|
"error": "Ошибка",
|
||||||
|
"add": "Добавить",
|
||||||
|
"searchSomeSourcesLabel": "Поиск (только в некоторых источниках)",
|
||||||
|
"search": "Поиск",
|
||||||
|
"additionalOptsFor": "Дополнительные опции для {}",
|
||||||
|
"supportedSourcesBelow": "Поддерживаемые источники:",
|
||||||
|
"trackOnlyInBrackets": "(Только для отслеживания)",
|
||||||
|
"searchableInBrackets": "(Поиск)",
|
||||||
|
"appsString": "Приложения",
|
||||||
|
"noApps": "Нет приложений",
|
||||||
|
"noAppsForFilter": "Нет приложений для фильтра",
|
||||||
|
"byX": "От {}",
|
||||||
|
"percentProgress": "Прогресс: {}%",
|
||||||
|
"pleaseWait": "Пожалуйста, подождите",
|
||||||
|
"updateAvailable": "Доступно обновление",
|
||||||
|
"estimateInBracketsShort": "(Оценка)",
|
||||||
|
"notInstalled": "Не установлено",
|
||||||
|
"estimateInBrackets": "(Оценка)",
|
||||||
|
"selectAll": "Выбрать все",
|
||||||
|
"deselectN": "Отменить выбор {}",
|
||||||
|
"xWillBeRemovedButRemainInstalled": "{} будет удалено из Obtainium, но останется установленным на устройстве.",
|
||||||
|
"removeSelectedAppsQuestion": "Удалить выбранные приложения?",
|
||||||
|
"removeSelectedApps": "Удалить выбранные приложения",
|
||||||
|
"updateX": "Обновить {}",
|
||||||
|
"installX": "Установить {}",
|
||||||
|
"markXTrackOnlyAsUpdated": "Отметить {}\n(Только для отслеживания)\nкак обновленное",
|
||||||
|
"changeX": "Изменить {}",
|
||||||
|
"installUpdateApps": "Установить/Обновить приложения",
|
||||||
|
"installUpdateSelectedApps": "Установить/Обновить выбранные приложения",
|
||||||
|
"markXSelectedAppsAsUpdated": "Отметить {} выбранные приложения как обновленные?",
|
||||||
|
"no": "Нет",
|
||||||
|
"yes": "Да",
|
||||||
|
"markSelectedAppsUpdated": "Отметить выбранные приложения как обновленные",
|
||||||
|
"pinToTop": "Закрепить сверху",
|
||||||
|
"unpinFromTop": "Открепить",
|
||||||
|
"resetInstallStatusForSelectedAppsQuestion": "Сбросить статус установки для выбранных приложений?",
|
||||||
|
"installStatusOfXWillBeResetExplanation": "Статус установки для выбранных приложений будет сброшен.\n\nЭто может помочь, если версия приложения, отображаемая в Obtainium, неправильная из-за неудачных обновлений или других проблем.",
|
||||||
|
"shareSelectedAppURLs": "Поделиться выбранными URL-адресами приложений",
|
||||||
|
"resetInstallStatus": "Сбросить статус установки",
|
||||||
|
"more": "Еще",
|
||||||
|
"removeOutdatedFilter": "Удалить фильтр для устаревших приложений",
|
||||||
|
"showOutdatedOnly": "Показывать только устаревшие приложения",
|
||||||
|
"filter": "Фильтр",
|
||||||
|
"filterActive": "Фильтр *",
|
||||||
|
"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-адреса содержали ошибки:",
|
||||||
|
"okay": "Окей",
|
||||||
|
"selectURL": "Выбрать URL-адрес",
|
||||||
|
"selectURLs": "Выбрать URL-адреса",
|
||||||
|
"pick": "Выбрать",
|
||||||
|
"theme": "Тема",
|
||||||
|
"dark": "Темная",
|
||||||
|
"light": "Светлая",
|
||||||
|
"followSystem": "Как в системе",
|
||||||
|
"obtainium": "Obtainium",
|
||||||
|
"materialYou": "Material You",
|
||||||
|
"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": "Ваше устройство поддерживает архитектуру процессора {}.",
|
||||||
|
"deviceSupportsFollowingArchs": "Ваше устройство поддерживает следующие архитектуры процессора:",
|
||||||
|
"warning": "Предупреждение",
|
||||||
|
"sourceIsXButPackageFromYPrompt": "Источник приложения - '{}', но пакет для установки получен из '{}'. Продолжить?",
|
||||||
|
"updatesAvailable": "Доступны обновления",
|
||||||
|
"updatesAvailableNotifDescription": "Уведомляет пользователя о наличии обновлений для одного или нескольких приложений, отслеживаемых Obtainium",
|
||||||
|
"noNewUpdates": "Нет новых обновлений.",
|
||||||
|
"xHasAnUpdate": "{} есть обновление.",
|
||||||
|
"appsUpdated": "Приложения обновлены",
|
||||||
|
"appsUpdatedNotifDescription": "Уведомляет пользователя о том, что обновления для одного или нескольких приложений были применены в фоновом режиме",
|
||||||
|
"xWasUpdatedToY": "{} была обновлена до версии {}.",
|
||||||
|
"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",
|
||||||
|
"steam": "Steam",
|
||||||
|
"steamMobile": "Steam Mobile",
|
||||||
|
"steamChat": "Steam Chat",
|
||||||
|
"install": "Установить",
|
||||||
|
"markInstalled": "Пометить как установленное",
|
||||||
|
"update": "Обновить",
|
||||||
|
"markUpdated": "Отметить обновленным",
|
||||||
|
"additionalOptions": "Дополнительные опции",
|
||||||
|
"disableVersionDetection": "Отключить обнаружение версии",
|
||||||
|
"noVersionDetectionExplanation": "Эта опция должна использоваться только для приложений, где обнаружение версии не работает корректно.",
|
||||||
|
"downloadingX": "Загрузка {}",
|
||||||
|
"downloadNotifDescription": "Уведомляет пользователя о прогрессе загрузки приложения",
|
||||||
|
"noAPKFound": "APK не найден",
|
||||||
|
"noVersionDetection": "Версий не обнаружено",
|
||||||
|
"categorize": "Категоризировать",
|
||||||
|
"categories": "Категории",
|
||||||
|
"category": "Категория",
|
||||||
|
"noCategory": "Без категории",
|
||||||
|
"noCategories": "Без категорий",
|
||||||
|
"deleteCategoriesQuestion": "Удалить категории?",
|
||||||
|
"categoryDeleteWarning": "Все приложения в удаленных категориях будут помечены как без категории.",
|
||||||
|
"addCategory": "Добавить категорию",
|
||||||
|
"label": "Метка",
|
||||||
|
"language": "Язык",
|
||||||
|
"copiedToClipboard": "Скопировано в буфер обмена",
|
||||||
|
"storagePermissionDenied": "Отказано в доступе к хранилищу",
|
||||||
|
"selectedCategorizeWarning": "Это заменит все текущие настройки категорий для выбранных приложений.",
|
||||||
|
"filterAPKsByRegEx": "Фильтровать APK-файлы с помощью\nрегулярного выражения",
|
||||||
|
"removeFromObtainium": "Удалить из Obtainium",
|
||||||
|
"uninstallFromDevice": "Удалить с устройства",
|
||||||
|
"onlyWorksWithNonVersionDetectApps": "Работает только для приложений с отключенным определением версии.",
|
||||||
|
"releaseDateAsVersion": "Использовать дату выпуска в качестве версии",
|
||||||
|
"releaseDateAsVersionExplanation": "Этот параметр следует использовать только для приложений, в которых определение версии не работает правильно, но имеется дата выпуска.",
|
||||||
|
"changes": "Изменения",
|
||||||
|
"releaseDate": "Дата выпуска",
|
||||||
|
"importFromURLsInFile": "Импорт URL-адресов из файла (например, OPML)",
|
||||||
|
"versionDetection": "Определение версии",
|
||||||
|
"standardVersionDetection": "Стандартное определение версии",
|
||||||
|
"groupByCategory": "Группировать по категориям",
|
||||||
|
"autoApkFilterByArch": "Попытка фильтрации APK-файлов по архитектуре процессора, если это возможно",
|
||||||
|
"overrideSource": "Переопределить источник",
|
||||||
|
"dontShowAgain": "Не показывать снова",
|
||||||
|
"dontShowTrackOnlyWarnings": "Не показывать предупреждения о только отслеживаемых приложениях",
|
||||||
|
"dontShowAPKOriginWarnings": "Не показывать предупреждения об источнике APK-файлов",
|
||||||
|
"moveNonInstalledAppsToBottom": "Переместить неустановленные приложения вниз списка",
|
||||||
|
"gitlabPATLabel": "Персональный токен доступа GitLab\n(Включает поиск и улучшает обнаружение APK)",
|
||||||
|
"about": "О приложении",
|
||||||
|
"requiresCredentialsInSettings": "Для этого требуются дополнительные учетные данные (в настройках)",
|
||||||
|
"checkOnStart": "Проверять наличие обновлений при запуске",
|
||||||
|
"tryInferAppIdFromCode": "Попытаться определить ID приложения из исходного кода",
|
||||||
|
"removeOnExternalUninstall": "Автоматически убирать из списка удаленные извне приложения",
|
||||||
|
"pickHighestVersionCode": "Автовыбор кода наивысшей версии APK",
|
||||||
|
"checkUpdateOnDetailPage": "Проверять наличие обновлений при открытии страницы представления приложения",
|
||||||
|
"disablePageTransitions": "Отключить анимацию перехода между страницами",
|
||||||
|
"reversePageTransitions": "Реверс анимации перехода между страницами",
|
||||||
|
"minStarCount": "Minimum Star Count",
|
||||||
|
"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": "{} и еще {} приложений были обновлены."
|
||||||
|
}
|
||||||
|
}
|
@ -135,7 +135,7 @@
|
|||||||
"showWebInAppView": "在应用详情页显示来源网页",
|
"showWebInAppView": "在应用详情页显示来源网页",
|
||||||
"pinUpdates": "将待更新应用置顶",
|
"pinUpdates": "将待更新应用置顶",
|
||||||
"updates": "更新",
|
"updates": "更新",
|
||||||
"sourceSpecific": "来源相关",
|
"sourceSpecific": "来源",
|
||||||
"appSource": "源代码",
|
"appSource": "源代码",
|
||||||
"noLogs": "无日志",
|
"noLogs": "无日志",
|
||||||
"appLogs": "日志",
|
"appLogs": "日志",
|
||||||
@ -229,11 +229,17 @@
|
|||||||
"dontShowTrackOnlyWarnings": "不显示“仅追踪”模式警告",
|
"dontShowTrackOnlyWarnings": "不显示“仅追踪”模式警告",
|
||||||
"dontShowAPKOriginWarnings": "不显示 APK 文件来源警告",
|
"dontShowAPKOriginWarnings": "不显示 APK 文件来源警告",
|
||||||
"moveNonInstalledAppsToBottom": "将未安装应用置底",
|
"moveNonInstalledAppsToBottom": "将未安装应用置底",
|
||||||
"gitlabPATLabel": "GitLab 个人访问令牌(用于搜索)",
|
"gitlabPATLabel": "GitLab 个人访问令牌\n(用于搜索应用 and Better APK Discovery)",
|
||||||
"about": "相关文档",
|
"about": "相关文档",
|
||||||
"requiresCredentialsInSettings": "此功能需要额外的凭据(在“设置”中添加)",
|
"requiresCredentialsInSettings": "此功能需要额外的凭据(在“设置”中添加)",
|
||||||
"checkOnStart": "启动时进行一次检查",
|
"checkOnStart": "启动时进行一次检查",
|
||||||
"tryInferAppIdFromCode": "Try inferring App ID from source code",
|
"tryInferAppIdFromCode": "尝试从源代码推断应用 ID",
|
||||||
|
"removeOnExternalUninstall": "Automatically remove externally uninstalled Apps",
|
||||||
|
"pickHighestVersionCode": "Auto-select highest version code APK",
|
||||||
|
"checkUpdateOnDetailPage": "Check for updates on opening an App detail page",
|
||||||
|
"disablePageTransitions": "Disable page transition animations",
|
||||||
|
"reversePageTransitions": "Reverse page transition animations",
|
||||||
|
"minStarCount": "Minimum Star Count",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "是否删除应用?",
|
"one": "是否删除应用?",
|
||||||
"other": "是否删除应用?"
|
"other": "是否删除应用?"
|
||||||
|
@ -37,8 +37,10 @@ class APKPure extends AppSource {
|
|||||||
String appId = (await tryInferringAppId(standardUrl))!;
|
String appId = (await tryInferringAppId(standardUrl))!;
|
||||||
String host = Uri.parse(standardUrl).host;
|
String host = Uri.parse(standardUrl).host;
|
||||||
var res = await sourceRequest('$standardUrl/download');
|
var res = await sourceRequest('$standardUrl/download');
|
||||||
if (res.statusCode == 200) {
|
var resChangelog = await sourceRequest(standardUrl);
|
||||||
|
if (res.statusCode == 200 && resChangelog.statusCode == 200) {
|
||||||
var html = parse(res.body);
|
var html = parse(res.body);
|
||||||
|
var htmlChangelog = parse(resChangelog.body);
|
||||||
String? version = html.querySelector('span.info-sdk span')?.text.trim();
|
String? version = html.querySelector('span.info-sdk span')?.text.trim();
|
||||||
if (version == null) {
|
if (version == null) {
|
||||||
throw NoVersionError();
|
throw NoVersionError();
|
||||||
@ -68,8 +70,11 @@ class APKPure extends AppSource {
|
|||||||
Uri.parse(standardUrl).pathSegments.reversed.last;
|
Uri.parse(standardUrl).pathSegments.reversed.last;
|
||||||
String appName =
|
String appName =
|
||||||
html.querySelector('h1.info-title')?.text.trim() ?? appId;
|
html.querySelector('h1.info-title')?.text.trim() ?? appId;
|
||||||
|
String? changeLog = htmlChangelog.querySelector("div.whats-new-info p:not(.date)")?.innerHtml
|
||||||
|
.trim().replaceAll("<br>", " \n");
|
||||||
return APKDetails(version, apkUrls, AppNames(author, appName),
|
return APKDetails(version, apkUrls, AppNames(author, appName),
|
||||||
releaseDate: releaseDate);
|
releaseDate: releaseDate,
|
||||||
|
changeLog: changeLog);
|
||||||
} else {
|
} else {
|
||||||
throw getObtainiumHttpError(res);
|
throw getObtainiumHttpError(res);
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import 'package:obtainium/custom_errors.dart';
|
|||||||
import 'package:obtainium/providers/source_provider.dart';
|
import 'package:obtainium/providers/source_provider.dart';
|
||||||
|
|
||||||
class Codeberg extends AppSource {
|
class Codeberg extends AppSource {
|
||||||
|
GitHub gh = GitHub();
|
||||||
Codeberg() {
|
Codeberg() {
|
||||||
host = 'codeberg.org';
|
host = 'codeberg.org';
|
||||||
|
|
||||||
@ -32,10 +33,9 @@ class Codeberg extends AppSource {
|
|||||||
];
|
];
|
||||||
|
|
||||||
canSearch = true;
|
canSearch = true;
|
||||||
|
searchQuerySettingFormItems = gh.searchQuerySettingFormItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
var gh = GitHub();
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String sourceSpecificStandardizeURL(String url) {
|
String sourceSpecificStandardizeURL(String url) {
|
||||||
RegExp standardUrlRegEx = RegExp('^https?://$host/[^/]+/[^/]+');
|
RegExp standardUrlRegEx = RegExp('^https?://$host/[^/]+/[^/]+');
|
||||||
@ -68,10 +68,12 @@ class Codeberg extends AppSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Map<String, List<String>>> search(String query) async {
|
Future<Map<String, List<String>>> search(String query,
|
||||||
|
{Map<String, dynamic> querySettings = const {}}) async {
|
||||||
return gh.searchCommon(
|
return gh.searchCommon(
|
||||||
query,
|
query,
|
||||||
'https://$host/api/v1/repos/search?q=${Uri.encodeQueryComponent(query)}&limit=100',
|
'https://$host/api/v1/repos/search?q=${Uri.encodeQueryComponent(query)}&limit=100',
|
||||||
'data');
|
'data',
|
||||||
|
querySettings: querySettings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -72,7 +72,8 @@ class FDroid extends AppSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Map<String, List<String>>> search(String query) async {
|
Future<Map<String, List<String>>> search(String query,
|
||||||
|
{Map<String, dynamic> querySettings = const {}}) async {
|
||||||
Response res = await sourceRequest(
|
Response res = await sourceRequest(
|
||||||
'https://search.$host/?q=${Uri.encodeQueryComponent(query)}');
|
'https://search.$host/?q=${Uri.encodeQueryComponent(query)}');
|
||||||
if (res.statusCode == 200) {
|
if (res.statusCode == 200) {
|
||||||
|
@ -14,6 +14,10 @@ class FDroidRepo extends AppSource {
|
|||||||
label: tr('appIdOrName'),
|
label: tr('appIdOrName'),
|
||||||
hint: tr('reposHaveMultipleApps'),
|
hint: tr('reposHaveMultipleApps'),
|
||||||
required: true)
|
required: true)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
GeneratedFormSwitch('pickHighestVersionCode',
|
||||||
|
label: tr('pickHighestVersionCode'), defaultValue: false)
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@ -24,6 +28,7 @@ class FDroidRepo extends AppSource {
|
|||||||
Map<String, dynamic> additionalSettings,
|
Map<String, dynamic> additionalSettings,
|
||||||
) async {
|
) async {
|
||||||
String? appIdOrName = additionalSettings['appIdOrName'];
|
String? appIdOrName = additionalSettings['appIdOrName'];
|
||||||
|
bool pickHighestVersionCode = additionalSettings['pickHighestVersionCode'];
|
||||||
if (appIdOrName == null) {
|
if (appIdOrName == null) {
|
||||||
throw NoReleasesError();
|
throw NoReleasesError();
|
||||||
}
|
}
|
||||||
@ -62,10 +67,19 @@ class FDroidRepo extends AppSource {
|
|||||||
if (latestVersion == null) {
|
if (latestVersion == null) {
|
||||||
throw NoVersionError();
|
throw NoVersionError();
|
||||||
}
|
}
|
||||||
List<String> apkUrls = releases
|
var latestVersionReleases = releases
|
||||||
.where((element) =>
|
.where((element) =>
|
||||||
element.querySelector('version')?.innerHtml == latestVersion &&
|
element.querySelector('version')?.innerHtml == latestVersion &&
|
||||||
element.querySelector('apkname') != null)
|
element.querySelector('apkname') != null)
|
||||||
|
.toList();
|
||||||
|
if (latestVersionReleases.length > 1 && pickHighestVersionCode) {
|
||||||
|
latestVersionReleases.sort((e1, e2) {
|
||||||
|
return int.parse(e2.querySelector('versioncode')!.innerHtml)
|
||||||
|
.compareTo(int.parse(e1.querySelector('versioncode')!.innerHtml));
|
||||||
|
});
|
||||||
|
latestVersionReleases = [latestVersionReleases[0]];
|
||||||
|
}
|
||||||
|
List<String> apkUrls = latestVersionReleases
|
||||||
.map((e) => '$standardUrl/${e.querySelector('apkname')!.innerHtml}')
|
.map((e) => '$standardUrl/${e.querySelector('apkname')!.innerHtml}')
|
||||||
.toList();
|
.toList();
|
||||||
return APKDetails(latestVersion, getApkUrlsFromUrls(apkUrls),
|
return APKDetails(latestVersion, getApkUrlsFromUrls(apkUrls),
|
||||||
|
@ -79,6 +79,21 @@ class GitHub extends AppSource {
|
|||||||
];
|
];
|
||||||
|
|
||||||
canSearch = true;
|
canSearch = true;
|
||||||
|
searchQuerySettingFormItems = [
|
||||||
|
GeneratedFormTextField('minStarCount',
|
||||||
|
label: tr('minStarCount'),
|
||||||
|
defaultValue: '0',
|
||||||
|
additionalValidators: [
|
||||||
|
(value) {
|
||||||
|
try {
|
||||||
|
int.parse(value ?? '0');
|
||||||
|
} catch (e) {
|
||||||
|
return tr('invalidInput');
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
])
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -102,15 +117,18 @@ class GitHub extends AppSource {
|
|||||||
.split('\n')
|
.split('\n')
|
||||||
.map((e) => e.trim());
|
.map((e) => e.trim());
|
||||||
var appId = trimmedLines
|
var appId = trimmedLines
|
||||||
.where((l) => l.startsWith('applicationId "'))
|
.where((l) =>
|
||||||
.first
|
l.startsWith('applicationId "') ||
|
||||||
.split('"')[1];
|
l.startsWith('applicationId \''))
|
||||||
|
.first;
|
||||||
|
appId = appId
|
||||||
|
.split(appId.startsWith('applicationId "') ? '"' : '\'')[1];
|
||||||
if (appId.startsWith('\${') && appId.endsWith('}')) {
|
if (appId.startsWith('\${') && appId.endsWith('}')) {
|
||||||
appId = trimmedLines
|
appId = trimmedLines
|
||||||
.where((l) => l.startsWith(
|
.where((l) => l.startsWith(
|
||||||
'def ${appId.substring(2, appId.length - 1)}'))
|
'def ${appId.substring(2, appId.length - 1)}'))
|
||||||
.first
|
.first;
|
||||||
.split('"')[1];
|
appId = appId.split(appId.contains('"') ? '"' : '\'')[1];
|
||||||
}
|
}
|
||||||
if (appId.isNotEmpty) {
|
if (appId.isNotEmpty) {
|
||||||
return appId;
|
return appId;
|
||||||
@ -208,8 +226,8 @@ class GitHub extends AppSource {
|
|||||||
(nameA as String).substring(matchA!.start, matchA.end),
|
(nameA as String).substring(matchA!.start, matchA.end),
|
||||||
(nameB as String).substring(matchB!.start, matchB.end));
|
(nameB as String).substring(matchB!.start, matchB.end));
|
||||||
} else {
|
} else {
|
||||||
return getReleaseDateFromRelease(a)!
|
return (getReleaseDateFromRelease(a) ?? DateTime(1))
|
||||||
.compareTo(getReleaseDateFromRelease(b)!);
|
.compareTo(getReleaseDateFromRelease(b) ?? DateTime(0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -307,20 +325,26 @@ class GitHub extends AppSource {
|
|||||||
|
|
||||||
Future<Map<String, List<String>>> searchCommon(
|
Future<Map<String, List<String>>> searchCommon(
|
||||||
String query, String requestUrl, String rootProp,
|
String query, String requestUrl, String rootProp,
|
||||||
{Function(Response)? onHttpErrorCode}) async {
|
{Function(Response)? onHttpErrorCode,
|
||||||
|
Map<String, dynamic> querySettings = const {}}) async {
|
||||||
Response res = await sourceRequest(requestUrl);
|
Response res = await sourceRequest(requestUrl);
|
||||||
if (res.statusCode == 200) {
|
if (res.statusCode == 200) {
|
||||||
|
int minStarCount = querySettings['minStarCount'] != null
|
||||||
|
? int.parse(querySettings['minStarCount'])
|
||||||
|
: 0;
|
||||||
Map<String, List<String>> urlsWithDescriptions = {};
|
Map<String, List<String>> urlsWithDescriptions = {};
|
||||||
for (var e in (jsonDecode(res.body)[rootProp] as List<dynamic>)) {
|
for (var e in (jsonDecode(res.body)[rootProp] as List<dynamic>)) {
|
||||||
urlsWithDescriptions.addAll({
|
if ((e['stargazers_count'] ?? e['stars_count'] ?? 0) >= minStarCount) {
|
||||||
e['html_url'] as String: [
|
urlsWithDescriptions.addAll({
|
||||||
e['full_name'] as String,
|
e['html_url'] as String: [
|
||||||
((e['archived'] == true ? '[ARCHIVED] ' : '') +
|
e['full_name'] as String,
|
||||||
(e['description'] != null
|
((e['archived'] == true ? '[ARCHIVED] ' : '') +
|
||||||
? e['description'] as String
|
(e['description'] != null
|
||||||
: tr('noDescription')))
|
? e['description'] as String
|
||||||
]
|
: tr('noDescription')))
|
||||||
});
|
]
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return urlsWithDescriptions;
|
return urlsWithDescriptions;
|
||||||
} else {
|
} else {
|
||||||
@ -332,13 +356,14 @@ class GitHub extends AppSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Map<String, List<String>>> search(String query) async {
|
Future<Map<String, List<String>>> search(String query,
|
||||||
|
{Map<String, dynamic> querySettings = const {}}) async {
|
||||||
return searchCommon(
|
return searchCommon(
|
||||||
query,
|
query,
|
||||||
'${await getAPIHost()}/search/repositories?q=${Uri.encodeQueryComponent(query)}&per_page=100',
|
'${await getAPIHost()}/search/repositories?q=${Uri.encodeQueryComponent(query)}&per_page=100',
|
||||||
'items', onHttpErrorCode: (Response res) {
|
'items', onHttpErrorCode: (Response res) {
|
||||||
rateLimitErrorCheck(res);
|
rateLimitErrorCheck(res);
|
||||||
});
|
}, querySettings: querySettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
rateLimitErrorCheck(Response res) {
|
rateLimitErrorCheck(Response res) {
|
||||||
|
@ -69,7 +69,8 @@ class GitLab extends AppSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Map<String, List<String>>> search(String query) async {
|
Future<Map<String, List<String>>> search(String query,
|
||||||
|
{Map<String, dynamic> querySettings = const {}}) async {
|
||||||
String? PAT = await getPATIfAny();
|
String? PAT = await getPATIfAny();
|
||||||
if (PAT == null) {
|
if (PAT == null) {
|
||||||
throw CredsNeededError(name);
|
throw CredsNeededError(name);
|
||||||
@ -102,11 +103,53 @@ class GitLab extends AppSource {
|
|||||||
) async {
|
) async {
|
||||||
bool fallbackToOlderReleases =
|
bool fallbackToOlderReleases =
|
||||||
additionalSettings['fallbackToOlderReleases'] == true;
|
additionalSettings['fallbackToOlderReleases'] == true;
|
||||||
Response res = await sourceRequest('$standardUrl/-/tags?format=atom');
|
String? PAT = await getPATIfAny();
|
||||||
if (res.statusCode == 200) {
|
Iterable<APKDetails> apkDetailsList = [];
|
||||||
|
if (PAT != null) {
|
||||||
|
var names = GitHub().getAppNames(standardUrl);
|
||||||
|
Response res = await sourceRequest(
|
||||||
|
'https://$host/api/v4/projects/${names.author}%2F${names.name}/releases?private_token=$PAT');
|
||||||
|
if (res.statusCode != 200) {
|
||||||
|
throw getObtainiumHttpError(res);
|
||||||
|
}
|
||||||
|
var json = jsonDecode(res.body) as List<dynamic>;
|
||||||
|
apkDetailsList = json.map((e) {
|
||||||
|
var apkUrlsFromAssets = (e['assets']?['links'] as List<dynamic>? ?? [])
|
||||||
|
.map((e) {
|
||||||
|
return (e['direct_asset_url'] ?? e['url'] ?? '') as String;
|
||||||
|
})
|
||||||
|
.where((s) => s.isNotEmpty)
|
||||||
|
.toList();
|
||||||
|
List<String> uploadedAPKsFromDescription =
|
||||||
|
((e['description'] ?? '') as String)
|
||||||
|
.split('](')
|
||||||
|
.join('\n')
|
||||||
|
.split('.apk)')
|
||||||
|
.join('.apk\n')
|
||||||
|
.split('\n')
|
||||||
|
.where((s) => s.startsWith('/uploads/') && s.endsWith('apk'))
|
||||||
|
.map((s) => '$standardUrl$s')
|
||||||
|
.toList();
|
||||||
|
var apkUrlsSet = apkUrlsFromAssets.toSet();
|
||||||
|
apkUrlsSet.addAll(uploadedAPKsFromDescription);
|
||||||
|
var releaseDateString = e['released_at'] ?? e['created_at'];
|
||||||
|
DateTime? releaseDate = releaseDateString != null
|
||||||
|
? DateTime.parse(releaseDateString)
|
||||||
|
: null;
|
||||||
|
return APKDetails(
|
||||||
|
e['tag_name'] ?? e['name'],
|
||||||
|
getApkUrlsFromUrls(apkUrlsSet.toList()),
|
||||||
|
GitHub().getAppNames(standardUrl),
|
||||||
|
releaseDate: releaseDate);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
Response res = await sourceRequest('$standardUrl/-/tags?format=atom');
|
||||||
|
if (res.statusCode != 200) {
|
||||||
|
throw getObtainiumHttpError(res);
|
||||||
|
}
|
||||||
var standardUri = Uri.parse(standardUrl);
|
var standardUri = Uri.parse(standardUrl);
|
||||||
var parsedHtml = parse(res.body);
|
var parsedHtml = parse(res.body);
|
||||||
var apkDetailsList = parsedHtml.querySelectorAll('entry').map((entry) {
|
apkDetailsList = parsedHtml.querySelectorAll('entry').map((entry) {
|
||||||
var entryContent = parse(
|
var entryContent = parse(
|
||||||
parseFragment(entry.querySelector('content')!.innerHtml).text);
|
parseFragment(entry.querySelector('content')!.innerHtml).text);
|
||||||
var apkUrls = [
|
var apkUrls = [
|
||||||
@ -124,7 +167,6 @@ class GitLab extends AppSource {
|
|||||||
.where((element) => Uri.parse(element).host != '')
|
.where((element) => Uri.parse(element).host != '')
|
||||||
.toList()
|
.toList()
|
||||||
];
|
];
|
||||||
|
|
||||||
var entryId = entry.querySelector('id')?.innerHtml;
|
var entryId = entry.querySelector('id')?.innerHtml;
|
||||||
var version =
|
var version =
|
||||||
entryId == null ? null : Uri.parse(entryId).pathSegments.last;
|
entryId == null ? null : Uri.parse(entryId).pathSegments.last;
|
||||||
@ -139,21 +181,19 @@ class GitLab extends AppSource {
|
|||||||
GitHub().getAppNames(standardUrl),
|
GitHub().getAppNames(standardUrl),
|
||||||
releaseDate: releaseDate);
|
releaseDate: releaseDate);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
if (apkDetailsList.isEmpty) {
|
||||||
|
throw NoReleasesError();
|
||||||
|
}
|
||||||
|
if (fallbackToOlderReleases) {
|
||||||
|
if (additionalSettings['trackOnly'] != true) {
|
||||||
|
apkDetailsList =
|
||||||
|
apkDetailsList.where((e) => e.apkUrls.isNotEmpty).toList();
|
||||||
|
}
|
||||||
if (apkDetailsList.isEmpty) {
|
if (apkDetailsList.isEmpty) {
|
||||||
throw NoReleasesError();
|
throw NoReleasesError();
|
||||||
}
|
}
|
||||||
if (fallbackToOlderReleases) {
|
|
||||||
if (additionalSettings['trackOnly'] != true) {
|
|
||||||
apkDetailsList =
|
|
||||||
apkDetailsList.where((e) => e.apkUrls.isNotEmpty).toList();
|
|
||||||
}
|
|
||||||
if (apkDetailsList.isEmpty) {
|
|
||||||
throw NoReleasesError();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return apkDetailsList.first;
|
|
||||||
} else {
|
|
||||||
throw getObtainiumHttpError(res);
|
|
||||||
}
|
}
|
||||||
|
return apkDetailsList.first;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -111,8 +111,7 @@ class HTML extends AppSource {
|
|||||||
.where((element) =>
|
.where((element) =>
|
||||||
Uri.parse(element).path.toLowerCase().endsWith('.apk'))
|
Uri.parse(element).path.toLowerCase().endsWith('.apk'))
|
||||||
.toList();
|
.toList();
|
||||||
links.sort(
|
links.sort((a, b) => compareAlphaNumeric(a, b));
|
||||||
(a, b) => compareAlphaNumeric(a.split('/').last, b.split('/').last));
|
|
||||||
if (additionalSettings['apkFilterRegEx'] != null) {
|
if (additionalSettings['apkFilterRegEx'] != null) {
|
||||||
var reg = RegExp(additionalSettings['apkFilterRegEx']);
|
var reg = RegExp(additionalSettings['apkFilterRegEx']);
|
||||||
links = links.where((element) => reg.hasMatch(element)).toList();
|
links = links.where((element) => reg.hasMatch(element)).toList();
|
||||||
@ -121,12 +120,11 @@ class HTML extends AppSource {
|
|||||||
throw NoReleasesError();
|
throw NoReleasesError();
|
||||||
}
|
}
|
||||||
var rel = links.last;
|
var rel = links.last;
|
||||||
var apkName = rel.split('/').last;
|
var version = rel.hashCode.toString();
|
||||||
var version = apkName.substring(0, apkName.length - 4);
|
|
||||||
List<String> apkUrls =
|
List<String> apkUrls =
|
||||||
[rel].map((e) => ensureAbsoluteUrl(e, uri)).toList();
|
[rel].map((e) => ensureAbsoluteUrl(e, uri)).toList();
|
||||||
return APKDetails(
|
return APKDetails(version, apkUrls.map((e) => MapEntry(e, e)).toList(),
|
||||||
version, getApkUrlsFromUrls(apkUrls), AppNames(uri.host, tr('app')));
|
AppNames(uri.host, tr('app')));
|
||||||
} else {
|
} else {
|
||||||
throw getObtainiumHttpError(res);
|
throw getObtainiumHttpError(res);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
|
import 'package:hsluv/hsluv.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:obtainium/components/generated_form_modal.dart';
|
import 'package:obtainium/components/generated_form_modal.dart';
|
||||||
@ -132,19 +133,19 @@ class GeneratedForm extends StatefulWidget {
|
|||||||
State<GeneratedForm> createState() => _GeneratedFormState();
|
State<GeneratedForm> createState() => _GeneratedFormState();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generates a random light color
|
// Generates a color in the HSLuv (Pastel) color space
|
||||||
// Courtesy of ChatGPT 😭 (with a bugfix 🥳)
|
// https://pub.dev/documentation/hsluv/latest/hsluv/Hsluv/hpluvToRgb.html
|
||||||
Color generateRandomLightColor() {
|
Color generateRandomLightColor() {
|
||||||
// Create a random number generator
|
final randomSeed = Random().nextInt(120);
|
||||||
final Random random = Random();
|
// https://en.wikipedia.org/wiki/Golden_angle
|
||||||
|
final goldenAngle = 180 * (3 - sqrt(5));
|
||||||
// Generate random hue, saturation, and value values
|
// Generate next golden angle hue
|
||||||
final double hue = random.nextDouble() * 360;
|
final double hue = randomSeed * goldenAngle;
|
||||||
final double saturation = 0.5 + random.nextDouble() * 0.5;
|
// Map from HPLuv color space to RGB, use constant saturation=100, lightness=70
|
||||||
final double value = 0.9 + random.nextDouble() * 0.1;
|
final List<double> rgbValuesDbl = Hsluv.hpluvToRgb([hue, 100, 70]);
|
||||||
|
// Map RBG values from 0-1 to 0-255:
|
||||||
// Create a HSV color with the random values
|
final List<int> rgbValues = rgbValuesDbl.map((rgb) => (rgb * 255).toInt()).toList();
|
||||||
return HSVColor.fromAHSV(1.0, hue, saturation, value).toColor();
|
return Color.fromARGB(255, rgbValues[0], rgbValues[1], rgbValues[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
class _GeneratedFormState extends State<GeneratedForm> {
|
class _GeneratedFormState extends State<GeneratedForm> {
|
||||||
@ -368,6 +369,36 @@ class _GeneratedFormState extends State<GeneratedForm> {
|
|||||||
));
|
));
|
||||||
}) ??
|
}) ??
|
||||||
[const SizedBox.shrink()],
|
[const SizedBox.shrink()],
|
||||||
|
(values[widget.items[r][e].key]
|
||||||
|
as Map<String, MapEntry<int, bool>>?)
|
||||||
|
?.values
|
||||||
|
.where((e) => e.value)
|
||||||
|
.length == 1
|
||||||
|
? Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 4),
|
||||||
|
child: IconButton(
|
||||||
|
onPressed: () {
|
||||||
|
setState(() {
|
||||||
|
var temp = values[widget.items[r][e].key]
|
||||||
|
as Map<String, MapEntry<int, bool>>;
|
||||||
|
// get selected category str where bool is true
|
||||||
|
final oldEntry = temp.entries.firstWhere((entry) => entry.value.value);
|
||||||
|
// generate new color, ensure it is not the same
|
||||||
|
int newColor = oldEntry.value.key;
|
||||||
|
while(oldEntry.value.key == newColor) {
|
||||||
|
newColor = generateRandomLightColor().value;
|
||||||
|
}
|
||||||
|
// Update entry with new color, remain selected
|
||||||
|
temp.update(oldEntry.key, (old) => MapEntry(newColor, old.value));
|
||||||
|
values[widget.items[r][e].key] = temp;
|
||||||
|
someValueChanged();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
icon: const Icon(Icons.format_color_fill_rounded),
|
||||||
|
visualDensity: VisualDensity.compact,
|
||||||
|
tooltip: tr('colour'),
|
||||||
|
))
|
||||||
|
: const SizedBox.shrink(),
|
||||||
(values[widget.items[r][e].key]
|
(values[widget.items[r][e].key]
|
||||||
as Map<String, MapEntry<int, bool>>?)
|
as Map<String, MapEntry<int, bool>>?)
|
||||||
?.values
|
?.values
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import 'package:android_package_installer/android_package_installer.dart';
|
import 'package:android_package_installer/android_package_installer.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:obtainium/providers/logs_provider.dart';
|
import 'package:obtainium/providers/logs_provider.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
@ -56,7 +57,7 @@ class InstallError extends ObtainiumError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class IDChangedError extends ObtainiumError {
|
class IDChangedError extends ObtainiumError {
|
||||||
IDChangedError() : super(tr('appIdMismatch'));
|
IDChangedError(String newId) : super('${tr('appIdMismatch')} - $newId');
|
||||||
}
|
}
|
||||||
|
|
||||||
class NotImplementedError extends ObtainiumError {
|
class NotImplementedError extends ObtainiumError {
|
||||||
@ -101,7 +102,14 @@ showError(dynamic e, BuildContext context) {
|
|||||||
title: Text(e is MultiAppMultiError
|
title: Text(e is MultiAppMultiError
|
||||||
? tr('someErrors')
|
? tr('someErrors')
|
||||||
: tr('unexpectedError')),
|
: tr('unexpectedError')),
|
||||||
content: Text(e.toString()),
|
content: GestureDetector(
|
||||||
|
onLongPress: () {
|
||||||
|
Clipboard.setData(ClipboardData(text: e.toString()));
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
|
||||||
|
content: Text(tr('copiedToClipboard')),
|
||||||
|
));
|
||||||
|
},
|
||||||
|
child: Text(e.toString())),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
|
@ -21,7 +21,7 @@ import 'package:easy_localization/src/easy_localization_controller.dart';
|
|||||||
// ignore: implementation_imports
|
// ignore: implementation_imports
|
||||||
import 'package:easy_localization/src/localization.dart';
|
import 'package:easy_localization/src/localization.dart';
|
||||||
|
|
||||||
const String currentVersion = '0.13.8';
|
const String currentVersion = '0.13.19';
|
||||||
const String currentReleaseTag =
|
const String currentReleaseTag =
|
||||||
'v$currentVersion-beta'; // KEEP THIS IN SYNC WITH GITHUB RELEASES
|
'v$currentVersion-beta'; // KEEP THIS IN SYNC WITH GITHUB RELEASES
|
||||||
|
|
||||||
@ -38,6 +38,8 @@ List<MapEntry<Locale, String>> supportedLocales = const [
|
|||||||
MapEntry(Locale('fr'), 'Français'),
|
MapEntry(Locale('fr'), 'Français'),
|
||||||
MapEntry(Locale('es'), 'Español'),
|
MapEntry(Locale('es'), 'Español'),
|
||||||
MapEntry(Locale('pl'), 'Polski'),
|
MapEntry(Locale('pl'), 'Polski'),
|
||||||
|
MapEntry(Locale('ru'), 'Русский язык'),
|
||||||
|
MapEntry(Locale('bs'), 'Bosanski'),
|
||||||
];
|
];
|
||||||
const fallbackLocale = Locale('en');
|
const fallbackLocale = Locale('en');
|
||||||
const localeDir = 'assets/translations';
|
const localeDir = 'assets/translations';
|
||||||
@ -225,9 +227,9 @@ class _ObtainiumState extends State<Obtainium> {
|
|||||||
if (!supportedLocales
|
if (!supportedLocales
|
||||||
.map((e) => e.key.languageCode)
|
.map((e) => e.key.languageCode)
|
||||||
.contains(context.locale.languageCode) ||
|
.contains(context.locale.languageCode) ||
|
||||||
settingsProvider.forcedLocale == null &&
|
(settingsProvider.forcedLocale == null &&
|
||||||
context.deviceLocale.languageCode !=
|
context.deviceLocale.languageCode !=
|
||||||
context.locale.languageCode) {
|
context.locale.languageCode)) {
|
||||||
settingsProvider.resetLocaleSafe(context);
|
settingsProvider.resetLocaleSafe(context);
|
||||||
}
|
}
|
||||||
// Register the background update task according to the user's setting
|
// Register the background update task according to the user's setting
|
||||||
|
@ -44,7 +44,10 @@ class _AppPageState extends State<AppPage> {
|
|||||||
? sourceProvider.getSource(app.app.url,
|
? sourceProvider.getSource(app.app.url,
|
||||||
overrideSource: app.app.overrideSource)
|
overrideSource: app.app.overrideSource)
|
||||||
: null;
|
: null;
|
||||||
if (!areDownloadsRunning && prevApp == null && app != null) {
|
if (!areDownloadsRunning &&
|
||||||
|
prevApp == null &&
|
||||||
|
app != null &&
|
||||||
|
settingsProvider.checkUpdateOnDetailPage) {
|
||||||
prevApp = app;
|
prevApp = app;
|
||||||
getUpdate(app.app.id);
|
getUpdate(app.app.id);
|
||||||
}
|
}
|
||||||
@ -54,6 +57,11 @@ class _AppPageState extends State<AppPage> {
|
|||||||
app?.app.additionalSettings['versionDetection'] ==
|
app?.app.additionalSettings['versionDetection'] ==
|
||||||
'standardVersionDetection';
|
'standardVersionDetection';
|
||||||
|
|
||||||
|
bool installedVersionIsEstimate = trackOnly ||
|
||||||
|
(app?.app.installedVersion != null &&
|
||||||
|
app?.app.additionalSettings['versionDetection'] ==
|
||||||
|
'noVersionDetection');
|
||||||
|
|
||||||
getInfoColumn() => Column(
|
getInfoColumn() => Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
@ -82,31 +90,32 @@ class _AppPageState extends State<AppPage> {
|
|||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 32,
|
height: 32,
|
||||||
),
|
),
|
||||||
Text(
|
Column(
|
||||||
tr('latestVersionX',
|
children: [
|
||||||
args: [app?.app.latestVersion ?? tr('unknown')]),
|
Text(
|
||||||
textAlign: TextAlign.center,
|
'${tr('latestVersionX', args: [
|
||||||
style: Theme.of(context).textTheme.bodyLarge,
|
app?.app.latestVersion ?? tr('unknown')
|
||||||
),
|
])}\n${tr('installedVersionX', args: [
|
||||||
Text(
|
app?.app.installedVersion ?? tr('none')
|
||||||
'${tr('installedVersionX', args: [
|
])}${installedVersionIsEstimate ? '\n${tr('estimateInBrackets')}' : ''}',
|
||||||
app?.app.installedVersion ?? tr('none')
|
textAlign: TextAlign.end,
|
||||||
])}${trackOnly ? ' ${tr('estimateInBrackets')}\n\n${tr('xIsTrackOnly', args: [
|
style: Theme.of(context).textTheme.bodyLarge!,
|
||||||
tr('app')
|
),
|
||||||
])}' : ''}',
|
],
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: Theme.of(context).textTheme.bodyLarge,
|
|
||||||
),
|
),
|
||||||
if (app?.app.installedVersion != null &&
|
if (app?.app.installedVersion != null &&
|
||||||
!isVersionDetectionStandard)
|
!isVersionDetectionStandard)
|
||||||
Column(
|
Column(
|
||||||
children: [
|
children: [
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 4,
|
height: 16,
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
tr('noVersionDetection'),
|
'${trackOnly ? '${tr('xIsTrackOnly', args: [
|
||||||
|
tr('app')
|
||||||
|
])}\n' : ''}${tr('noVersionDetection')}',
|
||||||
style: Theme.of(context).textTheme.labelSmall,
|
style: Theme.of(context).textTheme.labelSmall,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -329,7 +338,8 @@ class _AppPageState extends State<AppPage> {
|
|||||||
try {
|
try {
|
||||||
HapticFeedback.heavyImpact();
|
HapticFeedback.heavyImpact();
|
||||||
var res = await appsProvider.downloadAndInstallLatestApps(
|
var res = await appsProvider.downloadAndInstallLatestApps(
|
||||||
[app!.app.id], globalNavigatorKey.currentContext);
|
app?.app.id != null ? [app!.app.id] : [],
|
||||||
|
globalNavigatorKey.currentContext);
|
||||||
if (res.isNotEmpty && mounted) {
|
if (res.isNotEmpty && mounted) {
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
}
|
}
|
||||||
@ -426,8 +436,10 @@ class _AppPageState extends State<AppPage> {
|
|||||||
onPressed: app?.downloadProgress != null
|
onPressed: app?.downloadProgress != null
|
||||||
? null
|
? null
|
||||||
: () {
|
: () {
|
||||||
appsProvider.removeAppsWithModal(
|
appsProvider
|
||||||
context, [app!.app]).then((value) {
|
.removeAppsWithModal(
|
||||||
|
context, app != null ? [app.app] : [])
|
||||||
|
.then((value) {
|
||||||
if (value == true) {
|
if (value == true) {
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import 'package:obtainium/pages/apps.dart';
|
|||||||
import 'package:obtainium/pages/import_export.dart';
|
import 'package:obtainium/pages/import_export.dart';
|
||||||
import 'package:obtainium/pages/settings.dart';
|
import 'package:obtainium/pages/settings.dart';
|
||||||
import 'package:obtainium/providers/apps_provider.dart';
|
import 'package:obtainium/providers/apps_provider.dart';
|
||||||
|
import 'package:obtainium/providers/settings_provider.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
class HomePage extends StatefulWidget {
|
class HomePage extends StatefulWidget {
|
||||||
@ -26,6 +27,7 @@ class NavigationPageItem {
|
|||||||
|
|
||||||
class _HomePageState extends State<HomePage> {
|
class _HomePageState extends State<HomePage> {
|
||||||
List<int> selectedIndexHistory = [];
|
List<int> selectedIndexHistory = [];
|
||||||
|
bool isReversing = false;
|
||||||
int prevAppCount = -1;
|
int prevAppCount = -1;
|
||||||
bool prevIsLoading = true;
|
bool prevIsLoading = true;
|
||||||
|
|
||||||
@ -41,8 +43,18 @@ class _HomePageState extends State<HomePage> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
AppsProvider appsProvider = context.watch<AppsProvider>();
|
AppsProvider appsProvider = context.watch<AppsProvider>();
|
||||||
|
SettingsProvider settingsProvider = context.watch<SettingsProvider>();
|
||||||
|
|
||||||
|
setIsReversing(int targetIndex) {
|
||||||
|
bool reversing = selectedIndexHistory.isNotEmpty &&
|
||||||
|
selectedIndexHistory.last > targetIndex;
|
||||||
|
setState(() {
|
||||||
|
isReversing = reversing;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
switchToPage(int index) async {
|
switchToPage(int index) async {
|
||||||
|
setIsReversing(index);
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
while ((pages[0].widget.key as GlobalKey<AppsPageState>).currentState !=
|
while ((pages[0].widget.key as GlobalKey<AppsPageState>).currentState !=
|
||||||
null) {
|
null) {
|
||||||
@ -79,6 +91,12 @@ class _HomePageState extends State<HomePage> {
|
|||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
backgroundColor: Theme.of(context).colorScheme.surface,
|
backgroundColor: Theme.of(context).colorScheme.surface,
|
||||||
body: PageTransitionSwitcher(
|
body: PageTransitionSwitcher(
|
||||||
|
duration: Duration(
|
||||||
|
milliseconds:
|
||||||
|
settingsProvider.disablePageTransitions ? 0 : 300),
|
||||||
|
reverse: settingsProvider.reversePageTransitions
|
||||||
|
? !isReversing
|
||||||
|
: isReversing,
|
||||||
transitionBuilder: (
|
transitionBuilder: (
|
||||||
Widget child,
|
Widget child,
|
||||||
Animation<double> animation,
|
Animation<double> animation,
|
||||||
@ -104,13 +122,16 @@ class _HomePageState extends State<HomePage> {
|
|||||||
.toList(),
|
.toList(),
|
||||||
onDestinationSelected: (int index) async {
|
onDestinationSelected: (int index) async {
|
||||||
HapticFeedback.selectionClick();
|
HapticFeedback.selectionClick();
|
||||||
await switchToPage(index);
|
switchToPage(index);
|
||||||
},
|
},
|
||||||
selectedIndex:
|
selectedIndex:
|
||||||
selectedIndexHistory.isEmpty ? 0 : selectedIndexHistory.last,
|
selectedIndexHistory.isEmpty ? 0 : selectedIndexHistory.last,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
onWillPop: () async {
|
onWillPop: () async {
|
||||||
|
setIsReversing(selectedIndexHistory.length >= 2
|
||||||
|
? selectedIndexHistory.reversed.toList()[1]
|
||||||
|
: 0);
|
||||||
if (selectedIndexHistory.isNotEmpty) {
|
if (selectedIndexHistory.isNotEmpty) {
|
||||||
setState(() {
|
setState(() {
|
||||||
selectedIndexHistory.removeLast();
|
selectedIndexHistory.removeLast();
|
||||||
|
@ -182,7 +182,8 @@ class _ImportExportPageState extends State<ImportExportPage> {
|
|||||||
[
|
[
|
||||||
GeneratedFormTextField('searchQuery',
|
GeneratedFormTextField('searchQuery',
|
||||||
label: tr('searchQuery'))
|
label: tr('searchQuery'))
|
||||||
]
|
],
|
||||||
|
...source.searchQuerySettingFormItems.map((e) => [e])
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -191,8 +192,8 @@ class _ImportExportPageState extends State<ImportExportPage> {
|
|||||||
setState(() {
|
setState(() {
|
||||||
importInProgress = true;
|
importInProgress = true;
|
||||||
});
|
});
|
||||||
var urlsWithDescriptions =
|
var urlsWithDescriptions = await source
|
||||||
await source.search(values['searchQuery'] as String);
|
.search(values['searchQuery'] as String, querySettings: values);
|
||||||
if (urlsWithDescriptions.isNotEmpty) {
|
if (urlsWithDescriptions.isNotEmpty) {
|
||||||
var selectedUrls =
|
var selectedUrls =
|
||||||
// ignore: use_build_context_synchronously
|
// ignore: use_build_context_synchronously
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
import 'dart:math';
|
|
||||||
|
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:obtainium/components/custom_app_bar.dart';
|
import 'package:obtainium/components/custom_app_bar.dart';
|
||||||
@ -21,21 +19,6 @@ class SettingsPage extends StatefulWidget {
|
|||||||
State<SettingsPage> createState() => _SettingsPageState();
|
State<SettingsPage> createState() => _SettingsPageState();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generates a random light color
|
|
||||||
// Courtesy of ChatGPT 😭 (with a bugfix 🥳)
|
|
||||||
Color generateRandomLightColor() {
|
|
||||||
// Create a random number generator
|
|
||||||
final Random random = Random();
|
|
||||||
|
|
||||||
// Generate random hue, saturation, and value values
|
|
||||||
final double hue = random.nextDouble() * 360;
|
|
||||||
final double saturation = 0.5 + random.nextDouble() * 0.5;
|
|
||||||
final double value = 0.9 + random.nextDouble() * 0.1;
|
|
||||||
|
|
||||||
// Create a HSV color with the random values
|
|
||||||
return HSVColor.fromAHSV(1.0, hue, saturation, value).toColor();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _SettingsPageState extends State<SettingsPage> {
|
class _SettingsPageState extends State<SettingsPage> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -240,6 +223,21 @@ class _SettingsPageState extends State<SettingsPage> {
|
|||||||
})
|
})
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
height16,
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Flexible(
|
||||||
|
child: Text(tr('checkUpdateOnDetailPage'))),
|
||||||
|
Switch(
|
||||||
|
value: settingsProvider
|
||||||
|
.checkUpdateOnDetailPage,
|
||||||
|
onChanged: (value) {
|
||||||
|
settingsProvider.checkUpdateOnDetailPage =
|
||||||
|
value;
|
||||||
|
})
|
||||||
|
],
|
||||||
|
),
|
||||||
height32,
|
height32,
|
||||||
Text(
|
Text(
|
||||||
tr('sourceSpecific'),
|
tr('sourceSpecific'),
|
||||||
@ -322,6 +320,22 @@ class _SettingsPageState extends State<SettingsPage> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
height16,
|
height16,
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Flexible(
|
||||||
|
child:
|
||||||
|
Text(tr('removeOnExternalUninstall'))),
|
||||||
|
Switch(
|
||||||
|
value: settingsProvider
|
||||||
|
.removeOnExternalUninstall,
|
||||||
|
onChanged: (value) {
|
||||||
|
settingsProvider
|
||||||
|
.removeOnExternalUninstall = value;
|
||||||
|
})
|
||||||
|
],
|
||||||
|
),
|
||||||
|
height16,
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
@ -365,6 +379,36 @@ class _SettingsPageState extends State<SettingsPage> {
|
|||||||
})
|
})
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
height16,
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Flexible(
|
||||||
|
child: Text(tr('disablePageTransitions'))),
|
||||||
|
Switch(
|
||||||
|
value:
|
||||||
|
settingsProvider.disablePageTransitions,
|
||||||
|
onChanged: (value) {
|
||||||
|
settingsProvider.disablePageTransitions =
|
||||||
|
value;
|
||||||
|
})
|
||||||
|
],
|
||||||
|
),
|
||||||
|
height16,
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Flexible(
|
||||||
|
child: Text(tr('reversePageTransitions'))),
|
||||||
|
Switch(
|
||||||
|
value:
|
||||||
|
settingsProvider.reversePageTransitions,
|
||||||
|
onChanged: (value) {
|
||||||
|
settingsProvider.reversePageTransitions =
|
||||||
|
value;
|
||||||
|
})
|
||||||
|
],
|
||||||
|
),
|
||||||
height32,
|
height32,
|
||||||
Text(
|
Text(
|
||||||
tr('categories'),
|
tr('categories'),
|
||||||
|
@ -27,7 +27,7 @@ import 'package:flutter_fgbg/flutter_fgbg.dart';
|
|||||||
import 'package:obtainium/providers/source_provider.dart';
|
import 'package:obtainium/providers/source_provider.dart';
|
||||||
import 'package:http/http.dart';
|
import 'package:http/http.dart';
|
||||||
import 'package:android_intent_plus/android_intent.dart';
|
import 'package:android_intent_plus/android_intent.dart';
|
||||||
import 'package:archive/archive.dart';
|
import 'package:flutter_archive/flutter_archive.dart';
|
||||||
|
|
||||||
class AppInMemory {
|
class AppInMemory {
|
||||||
late App app;
|
late App app;
|
||||||
@ -117,7 +117,7 @@ class AppsProvider with ChangeNotifier {
|
|||||||
foregroundStream = FGBGEvents.stream.asBroadcastStream();
|
foregroundStream = FGBGEvents.stream.asBroadcastStream();
|
||||||
foregroundSubscription = foregroundStream?.listen((event) async {
|
foregroundSubscription = foregroundStream?.listen((event) async {
|
||||||
isForeground = event == FGBGType.foreground;
|
isForeground = event == FGBGType.foreground;
|
||||||
if (isForeground) await refreshInstallStatuses();
|
if (isForeground) await loadApps();
|
||||||
});
|
});
|
||||||
() async {
|
() async {
|
||||||
var cacheDirs = await getExternalCacheDirectories();
|
var cacheDirs = await getExternalCacheDirectories();
|
||||||
@ -202,16 +202,18 @@ class AppsProvider with ChangeNotifier {
|
|||||||
// The former case should be handled (give the App its real ID), the latter is a security issue
|
// The former case should be handled (give the App its real ID), the latter is a security issue
|
||||||
if (app.id != newInfo.packageName) {
|
if (app.id != newInfo.packageName) {
|
||||||
var isTempId = SourceProvider().isTempId(app);
|
var isTempId = SourceProvider().isTempId(app);
|
||||||
if (apps[app.id] != null && !isTempId) {
|
if (apps[app.id] != null && !isTempId && !app.allowIdChange) {
|
||||||
throw IDChangedError();
|
throw IDChangedError(newInfo.packageName);
|
||||||
}
|
}
|
||||||
|
var idChangeWasAllowed = app.allowIdChange;
|
||||||
|
app.allowIdChange = false;
|
||||||
var originalAppId = app.id;
|
var originalAppId = app.id;
|
||||||
app.id = newInfo.packageName;
|
app.id = newInfo.packageName;
|
||||||
downloadedFile = downloadedFile.renameSync(
|
downloadedFile = downloadedFile.renameSync(
|
||||||
'${downloadedFile.parent.path}/${app.id}-${downloadUrl.hashCode}.${downloadedFile.path.split('.').last}');
|
'${downloadedFile.parent.path}/${app.id}-${downloadUrl.hashCode}.${downloadedFile.path.split('.').last}');
|
||||||
if (apps[originalAppId] != null) {
|
if (apps[originalAppId] != null) {
|
||||||
await removeApps([originalAppId]);
|
await removeApps([originalAppId]);
|
||||||
await saveApps([app], onlyIfExists: !isTempId);
|
await saveApps([app], onlyIfExists: !isTempId && !idChangeWasAllowed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return downloadedFile;
|
return downloadedFile;
|
||||||
@ -262,7 +264,7 @@ class AppsProvider with ChangeNotifier {
|
|||||||
} else {
|
} else {
|
||||||
// Assume XAPK
|
// Assume XAPK
|
||||||
String xapkDirPath = '${downloadedFile.path}-dir';
|
String xapkDirPath = '${downloadedFile.path}-dir';
|
||||||
unzipFile(downloadedFile.path, '${downloadedFile.path}-dir');
|
await unzipFile(downloadedFile.path, '${downloadedFile.path}-dir');
|
||||||
xapkDir = Directory(xapkDirPath);
|
xapkDir = Directory(xapkDirPath);
|
||||||
var apks = xapkDir
|
var apks = xapkDir
|
||||||
.listSync()
|
.listSync()
|
||||||
@ -332,36 +334,40 @@ class AppsProvider with ChangeNotifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void unzipFile(String filePath, String destinationPath) {
|
Future<void> unzipFile(String filePath, String destinationPath) async {
|
||||||
final bytes = File(filePath).readAsBytesSync();
|
await ZipFile.extractToDirectory(
|
||||||
final archive = ZipDecoder().decodeBytes(bytes);
|
zipFile: File(filePath), destinationDir: Directory(destinationPath));
|
||||||
|
|
||||||
for (final file in archive) {
|
|
||||||
final filename = '$destinationPath/${file.name}';
|
|
||||||
if (file.isFile) {
|
|
||||||
final data = file.content as List<int>;
|
|
||||||
File(filename)
|
|
||||||
..createSync(recursive: true)
|
|
||||||
..writeAsBytesSync(data);
|
|
||||||
} else {
|
|
||||||
Directory(filename).create(recursive: true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> installXApkDir(DownloadedXApkDir dir,
|
Future<void> installXApkDir(DownloadedXApkDir dir,
|
||||||
{bool silent = false}) async {
|
{bool silent = 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
|
||||||
try {
|
try {
|
||||||
var somethingInstalled = false;
|
var somethingInstalled = false;
|
||||||
for (var apk in dir.extracted
|
Object? firstError;
|
||||||
.listSync()
|
for (var file in dir.extracted
|
||||||
.where((f) => f is File && f.path.toLowerCase().endsWith('.apk'))) {
|
.listSync(recursive: true, followLinks: false)
|
||||||
somethingInstalled = somethingInstalled ||
|
.whereType<File>()) {
|
||||||
await installApk(DownloadedApk(dir.appId, apk as File),
|
if (file.path.toLowerCase().endsWith('.apk')) {
|
||||||
silent: silent);
|
try {
|
||||||
|
somethingInstalled = somethingInstalled ||
|
||||||
|
await installApk(DownloadedApk(dir.appId, file),
|
||||||
|
silent: silent);
|
||||||
|
} catch (e) {
|
||||||
|
logs.add(
|
||||||
|
'Could not install APK from XAPK \'${file.path}\': ${e.toString()}');
|
||||||
|
firstError ??= e;
|
||||||
|
}
|
||||||
|
} else if (file.path.toLowerCase().endsWith('.obb')) {
|
||||||
|
await moveObbFile(file, dir.appId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (somethingInstalled) {
|
if (somethingInstalled) {
|
||||||
dir.file.delete(recursive: true);
|
dir.file.delete(recursive: true);
|
||||||
|
} else if (firstError != null) {
|
||||||
|
throw firstError;
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
dir.extracted.delete(recursive: true);
|
dir.extracted.delete(recursive: true);
|
||||||
@ -397,6 +403,21 @@ class AppsProvider with ChangeNotifier {
|
|||||||
return installed;
|
return installed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> moveObbFile(File file, String appId) async {
|
||||||
|
if (!file.path.toLowerCase().endsWith('.obb')) return;
|
||||||
|
|
||||||
|
// TODO: Does not support Android 11+
|
||||||
|
if ((await DeviceInfoPlugin().androidInfo).version.sdkInt <= 29) {
|
||||||
|
await Permission.storage.request();
|
||||||
|
}
|
||||||
|
|
||||||
|
String obbDirPath = "/storage/emulated/0/Android/obb/$appId";
|
||||||
|
Directory(obbDirPath).createSync(recursive: true);
|
||||||
|
|
||||||
|
String obbFileName = file.path.split("/").last;
|
||||||
|
await file.copy("$obbDirPath/$obbFileName");
|
||||||
|
}
|
||||||
|
|
||||||
void uninstallApp(String appId) async {
|
void uninstallApp(String appId) async {
|
||||||
var intent = AndroidIntent(
|
var intent = AndroidIntent(
|
||||||
action: 'android.intent.action.DELETE',
|
action: 'android.intent.action.DELETE',
|
||||||
@ -717,21 +738,12 @@ class AppsProvider with ChangeNotifier {
|
|||||||
notifyListeners();
|
notifyListeners();
|
||||||
var sp = SourceProvider();
|
var sp = SourceProvider();
|
||||||
List<List<String>> errors = [];
|
List<List<String>> errors = [];
|
||||||
List<FileSystemEntity> newApps = (await getAppsDir())
|
List<App?> newApps = (await getAppsDir()) // Parse Apps from JSON
|
||||||
.listSync()
|
.listSync()
|
||||||
.where((item) => item.path.toLowerCase().endsWith('.json'))
|
.where((item) => item.path.toLowerCase().endsWith('.json'))
|
||||||
.toList();
|
.map((e) {
|
||||||
for (var e in newApps) {
|
|
||||||
try {
|
try {
|
||||||
var app = App.fromJson(jsonDecode(File(e.path).readAsStringSync()));
|
return App.fromJson(jsonDecode(File(e.path).readAsStringSync()));
|
||||||
try {
|
|
||||||
var info = await getInstalledInfo(app.id);
|
|
||||||
sp.getSource(app.url, overrideSource: app.overrideSource);
|
|
||||||
apps[app.id] = AppInMemory(app, null, info);
|
|
||||||
notifyListeners();
|
|
||||||
} catch (e) {
|
|
||||||
errors.add([app.id, app.finalName, e.toString()]);
|
|
||||||
}
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err is FormatException) {
|
if (err is FormatException) {
|
||||||
logs.add('Corrupt JSON when loading App (will be ignored): $e');
|
logs.add('Corrupt JSON when loading App (will be ignored): $e');
|
||||||
@ -740,19 +752,36 @@ class AppsProvider with ChangeNotifier {
|
|||||||
rethrow;
|
rethrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}).toList();
|
||||||
|
for (var app in newApps) {
|
||||||
|
// Put Apps into memory to list them (fast)
|
||||||
|
if (app != null) {
|
||||||
|
try {
|
||||||
|
sp.getSource(app.url, overrideSource: app.overrideSource);
|
||||||
|
apps.update(
|
||||||
|
app.id,
|
||||||
|
(value) =>
|
||||||
|
AppInMemory(app, value.downloadProgress, value.installedInfo),
|
||||||
|
ifAbsent: () => AppInMemory(app, null, null));
|
||||||
|
} catch (e) {
|
||||||
|
errors.add([app.id, app.finalName, e.toString()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
notifyListeners();
|
||||||
if (errors.isNotEmpty) {
|
if (errors.isNotEmpty) {
|
||||||
removeApps(errors.map((e) => e[0]).toList());
|
removeApps(errors.map((e) => e[0]).toList());
|
||||||
NotificationsProvider().notify(
|
NotificationsProvider().notify(
|
||||||
AppsRemovedNotification(errors.map((e) => [e[1], e[2]]).toList()));
|
AppsRemovedNotification(errors.map((e) => [e[1], e[2]]).toList()));
|
||||||
}
|
}
|
||||||
loadingApps = false;
|
|
||||||
notifyListeners();
|
|
||||||
refreshInstallStatuses();
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> refreshInstallStatuses() async {
|
|
||||||
if (await doesInstalledAppsPluginWork()) {
|
if (await doesInstalledAppsPluginWork()) {
|
||||||
|
for (var app in apps.values) {
|
||||||
|
// Check install status for each App (slow)
|
||||||
|
apps[app.app.id]?.installedInfo = await getInstalledInfo(app.app.id);
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
// Reconcile version differences
|
||||||
List<App> modifiedApps = [];
|
List<App> modifiedApps = [];
|
||||||
for (var app in apps.values) {
|
for (var app in apps.values) {
|
||||||
var moddedApp =
|
var moddedApp =
|
||||||
@ -763,8 +792,23 @@ class AppsProvider with ChangeNotifier {
|
|||||||
}
|
}
|
||||||
if (modifiedApps.isNotEmpty) {
|
if (modifiedApps.isNotEmpty) {
|
||||||
await saveApps(modifiedApps, attemptToCorrectInstallStatus: false);
|
await saveApps(modifiedApps, attemptToCorrectInstallStatus: false);
|
||||||
|
var removedAppIds = modifiedApps
|
||||||
|
.where((a) => a.installedVersion == null)
|
||||||
|
.map((e) => e.id)
|
||||||
|
.toList();
|
||||||
|
// After reconciliation, delete externally uninstalled Apps if needed
|
||||||
|
if (removedAppIds.isNotEmpty) {
|
||||||
|
var settingsProvider = SettingsProvider();
|
||||||
|
await settingsProvider.initializeSettings();
|
||||||
|
if (settingsProvider.removeOnExternalUninstall) {
|
||||||
|
await removeApps(removedAppIds);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loadingApps = false;
|
||||||
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> saveApps(List<App> apps,
|
Future<void> saveApps(List<App> apps,
|
||||||
@ -779,8 +823,10 @@ class AppsProvider with ChangeNotifier {
|
|||||||
if (attemptToCorrectInstallStatus) {
|
if (attemptToCorrectInstallStatus) {
|
||||||
app = getCorrectedInstallStatusAppIfPossible(app, info) ?? app;
|
app = getCorrectedInstallStatusAppIfPossible(app, info) ?? app;
|
||||||
}
|
}
|
||||||
File('${(await getAppsDir()).path}/${app.id}.json')
|
if (!onlyIfExists || this.apps.containsKey(app.id)) {
|
||||||
.writeAsStringSync(jsonEncode(app.toJson()));
|
File('${(await getAppsDir()).path}/${app.id}.json')
|
||||||
|
.writeAsStringSync(jsonEncode(app.toJson()));
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
this.apps.update(
|
this.apps.update(
|
||||||
app.id, (value) => AppInMemory(app, value.downloadProgress, info),
|
app.id, (value) => AppInMemory(app, value.downloadProgress, info),
|
||||||
|
@ -273,4 +273,40 @@ class SettingsProvider with ChangeNotifier {
|
|||||||
context.deleteSaveLocale();
|
context.deleteSaveLocale();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool get removeOnExternalUninstall {
|
||||||
|
return prefs?.getBool('removeOnExternalUninstall') ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
set removeOnExternalUninstall(bool show) {
|
||||||
|
prefs?.setBool('removeOnExternalUninstall', show);
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get checkUpdateOnDetailPage {
|
||||||
|
return prefs?.getBool('checkUpdateOnDetailPage') ?? true;
|
||||||
|
}
|
||||||
|
|
||||||
|
set checkUpdateOnDetailPage(bool show) {
|
||||||
|
prefs?.setBool('checkUpdateOnDetailPage', show);
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get disablePageTransitions {
|
||||||
|
return prefs?.getBool('disablePageTransitions') ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
set disablePageTransitions(bool show) {
|
||||||
|
prefs?.setBool('disablePageTransitions', show);
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get reversePageTransitions {
|
||||||
|
return prefs?.getBool('reversePageTransitions') ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
set reversePageTransitions(bool show) {
|
||||||
|
prefs?.setBool('reversePageTransitions', show);
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -163,6 +163,7 @@ class App {
|
|||||||
late DateTime? releaseDate;
|
late DateTime? releaseDate;
|
||||||
late String? changeLog;
|
late String? changeLog;
|
||||||
late String? overrideSource;
|
late String? overrideSource;
|
||||||
|
bool allowIdChange = false;
|
||||||
App(
|
App(
|
||||||
this.id,
|
this.id,
|
||||||
this.url,
|
this.url,
|
||||||
@ -178,7 +179,8 @@ class App {
|
|||||||
{this.categories = const [],
|
{this.categories = const [],
|
||||||
this.releaseDate,
|
this.releaseDate,
|
||||||
this.changeLog,
|
this.changeLog,
|
||||||
this.overrideSource});
|
this.overrideSource,
|
||||||
|
this.allowIdChange = false});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
@ -209,7 +211,8 @@ class App {
|
|||||||
categories: categories,
|
categories: categories,
|
||||||
changeLog: changeLog,
|
changeLog: changeLog,
|
||||||
releaseDate: releaseDate,
|
releaseDate: releaseDate,
|
||||||
overrideSource: overrideSource);
|
overrideSource: overrideSource,
|
||||||
|
allowIdChange: allowIdChange);
|
||||||
|
|
||||||
factory App.fromJson(Map<String, dynamic> json) {
|
factory App.fromJson(Map<String, dynamic> json) {
|
||||||
json = appJSONCompatibilityModifiers(json);
|
json = appJSONCompatibilityModifiers(json);
|
||||||
@ -241,7 +244,8 @@ class App {
|
|||||||
: DateTime.fromMicrosecondsSinceEpoch(json['releaseDate']),
|
: DateTime.fromMicrosecondsSinceEpoch(json['releaseDate']),
|
||||||
changeLog:
|
changeLog:
|
||||||
json['changeLog'] == null ? null : json['changeLog'] as String,
|
json['changeLog'] == null ? null : json['changeLog'] as String,
|
||||||
overrideSource: json['overrideSource']);
|
overrideSource: json['overrideSource'],
|
||||||
|
allowIdChange: json['allowIdChange'] ?? false);
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => {
|
Map<String, dynamic> toJson() => {
|
||||||
@ -259,7 +263,8 @@ class App {
|
|||||||
'categories': categories,
|
'categories': categories,
|
||||||
'releaseDate': releaseDate?.microsecondsSinceEpoch,
|
'releaseDate': releaseDate?.microsecondsSinceEpoch,
|
||||||
'changeLog': changeLog,
|
'changeLog': changeLog,
|
||||||
'overrideSource': overrideSource
|
'overrideSource': overrideSource,
|
||||||
|
'allowIdChange': allowIdChange
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -431,7 +436,9 @@ abstract class AppSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool canSearch = false;
|
bool canSearch = false;
|
||||||
Future<Map<String, List<String>>> search(String query) {
|
List<GeneratedFormItem> searchQuerySettingFormItems = [];
|
||||||
|
Future<Map<String, List<String>>> search(String query,
|
||||||
|
{Map<String, dynamic> querySettings = const {}}) {
|
||||||
throw NotImplementedError();
|
throw NotImplementedError();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -589,9 +596,7 @@ class SourceProvider {
|
|||||||
}
|
}
|
||||||
String apkVersion = apk.version.replaceAll('/', '-');
|
String apkVersion = apk.version.replaceAll('/', '-');
|
||||||
var name = currentApp != null ? currentApp.name.trim() : '';
|
var name = currentApp != null ? currentApp.name.trim() : '';
|
||||||
name = name.isNotEmpty
|
name = name.isNotEmpty ? name : apk.names.name;
|
||||||
? name
|
|
||||||
: apk.names.name[0].toUpperCase() + apk.names.name.substring(1);
|
|
||||||
return App(
|
return App(
|
||||||
currentApp?.id ??
|
currentApp?.id ??
|
||||||
((!source.appIdInferIsOptional ||
|
((!source.appIdInferIsOptional ||
|
||||||
@ -601,7 +606,7 @@ class SourceProvider {
|
|||||||
: null) ??
|
: null) ??
|
||||||
generateTempID(standardUrl, additionalSettings),
|
generateTempID(standardUrl, additionalSettings),
|
||||||
standardUrl,
|
standardUrl,
|
||||||
apk.names.author[0].toUpperCase() + apk.names.author.substring(1),
|
apk.names.author,
|
||||||
name,
|
name,
|
||||||
currentApp?.installedVersion,
|
currentApp?.installedVersion,
|
||||||
apkVersion,
|
apkVersion,
|
||||||
@ -613,7 +618,11 @@ class SourceProvider {
|
|||||||
categories: currentApp?.categories ?? const [],
|
categories: currentApp?.categories ?? const [],
|
||||||
releaseDate: apk.releaseDate,
|
releaseDate: apk.releaseDate,
|
||||||
changeLog: apk.changeLog,
|
changeLog: apk.changeLog,
|
||||||
overrideSource: overrideSource ?? currentApp?.overrideSource);
|
overrideSource: overrideSource ?? currentApp?.overrideSource,
|
||||||
|
allowIdChange: currentApp?.allowIdChange ??
|
||||||
|
source.appIdInferIsOptional &&
|
||||||
|
inferAppIdIfOptional // Optional ID inferring may be incorrect - allow correction on first install
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns errors in [results, errors] instead of throwing them
|
// Returns errors in [results, errors] instead of throwing them
|
||||||
|
188
pubspec.lock
188
pubspec.lock
@ -35,7 +35,7 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.7"
|
version: "2.0.7"
|
||||||
archive:
|
archive:
|
||||||
dependency: "direct main"
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: archive
|
name: archive
|
||||||
sha256: "0c8368c9b3f0abbc193b9d6133649a614204b528982bebc7026372d61677ce3a"
|
sha256: "0c8368c9b3f0abbc193b9d6133649a614204b528982bebc7026372d61677ce3a"
|
||||||
@ -46,10 +46,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: args
|
name: args
|
||||||
sha256: c372bb384f273f0c2a8aaaa226dad84dc27c8519a691b888725dec59518ad53a
|
sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.1"
|
version: "2.4.2"
|
||||||
async:
|
async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -134,10 +134,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: csslib
|
name: csslib
|
||||||
sha256: "831883fb353c8bdc1d71979e5b342c7d88acfbc643113c14ae51e2442ea0f20f"
|
sha256: "706b5707578e0c1b4b7550f64078f0a0f19dec3f50a178ffae7006b0a9ca58fb"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.17.3"
|
version: "1.0.0"
|
||||||
cupertino_icons:
|
cupertino_icons:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -174,10 +174,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: dynamic_color
|
name: dynamic_color
|
||||||
sha256: "74dff1435a695887ca64899b8990004f8d1232b0e84bfc4faa1fdda7c6f57cc1"
|
sha256: de4798a7069121aee12d5895315680258415de9b00e717723a1bd73d58f0126d
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.6.5"
|
version: "1.6.6"
|
||||||
easy_localization:
|
easy_localization:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -222,23 +222,31 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: file_picker
|
name: file_picker
|
||||||
sha256: "9d6e95ec73abbd31ec54d0e0df8a961017e165aba1395e462e5b31ea0c165daf"
|
sha256: b1729fc96627dd44012d0a901558177418818d6bd428df59dcfeb594e5f66432
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.3.1"
|
version: "5.3.2"
|
||||||
flutter:
|
flutter:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
flutter_archive:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: flutter_archive
|
||||||
|
sha256: aec85d1da65e5b33a529db00a86df0b8e92bda78088a7cfaeeba5187701d0d85
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "5.0.0"
|
||||||
flutter_fgbg:
|
flutter_fgbg:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: flutter_fgbg
|
name: flutter_fgbg
|
||||||
sha256: d37511eef6afb7e2e3f2278ec6498bb12c650ed517c81bcd09452d910e8b9174
|
sha256: "08c4d2fd229e3df26083d5aecc3dea9ff4f2d188f8cd57aaf2b3f047bd08a047"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.2.2"
|
version: "0.3.0"
|
||||||
flutter_launcher_icons:
|
flutter_launcher_icons:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
@ -251,18 +259,18 @@ packages:
|
|||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: flutter_lints
|
name: flutter_lints
|
||||||
sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c
|
sha256: "2118df84ef0c3ca93f96123a616ae8540879991b8b57af2f81b76a7ada49b2a4"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.1"
|
version: "2.0.2"
|
||||||
flutter_local_notifications:
|
flutter_local_notifications:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: flutter_local_notifications
|
name: flutter_local_notifications
|
||||||
sha256: "812791d43ccfc1b443a0d39fa02a206fc228c597e28ff9337e09e3ca8d370391"
|
sha256: "3cc40fe8c50ab8383f3e053a499f00f975636622ecdc8e20a77418ece3b1e975"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "14.1.1"
|
version: "15.1.0+1"
|
||||||
flutter_local_notifications_linux:
|
flutter_local_notifications_linux:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -288,10 +296,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: flutter_markdown
|
name: flutter_markdown
|
||||||
sha256: dc6d5258653f6857135b32896ccda7f7af0c54dcec832495ad6835154c6c77c0
|
sha256: "4b1bfbb802d76320a1a46d9ce984106135093efd9d969765d07c2125af107bdf"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.6.15"
|
version: "0.6.17"
|
||||||
flutter_plugin_android_lifecycle:
|
flutter_plugin_android_lifecycle:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -318,22 +326,30 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "8.2.2"
|
version: "8.2.2"
|
||||||
|
hsluv:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: hsluv
|
||||||
|
sha256: f33e63b0c24ceee0f6492874424aa8edc671ef9a20cc889e4b969284d8f02eb1
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.3"
|
||||||
html:
|
html:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: html
|
name: html
|
||||||
sha256: "58e3491f7bf0b6a4ea5110c0c688877460d1a6366731155c4a4580e7ded773e8"
|
sha256: "3a7812d5bcd2894edf53dfaf8cd640876cf6cef50a8f238745c8b8120ea74d3a"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.15.3"
|
version: "0.15.4"
|
||||||
http:
|
http:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: http
|
name: http
|
||||||
sha256: "4c3f04bfb64d3efd508d06b41b825542f08122d30bda4933fb95c069d22a4fa3"
|
sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.0"
|
version: "1.1.0"
|
||||||
http_parser:
|
http_parser:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -394,10 +410,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: markdown
|
name: markdown
|
||||||
sha256: "8e332924094383133cee218b676871f42db2514f1f6ac617b6cf6152a7faab8e"
|
sha256: acf35edccc0463a9d7384e437c015a3535772e09714cf60e07eeef3a15870dcd
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "7.1.0"
|
version: "7.1.1"
|
||||||
matcher:
|
matcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -482,10 +498,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: path_provider_foundation
|
name: path_provider_foundation
|
||||||
sha256: "1995d88ec2948dac43edf8fe58eb434d35d22a2940ecee1a9fefcd62beee6eb3"
|
sha256: "916731ccbdce44d545414dd9961f26ba5fbaa74bcbb55237d8e65a623a8c7297"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.3"
|
version: "2.2.4"
|
||||||
path_provider_linux:
|
path_provider_linux:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -506,50 +522,50 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: path_provider_windows
|
name: path_provider_windows
|
||||||
sha256: d3f80b32e83ec208ac95253e0cd4d298e104fbc63cb29c5c69edaed43b0c69d6
|
sha256: "1cb68ba4cd3a795033de62ba1b7b4564dace301f952de6bfb3cd91b202b6ee96"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.6"
|
version: "2.1.7"
|
||||||
permission_handler:
|
permission_handler:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: permission_handler
|
name: permission_handler
|
||||||
sha256: "33c6a1253d1f95fd06fa74b65b7ba907ae9811f9d5c1d3150e51417d04b8d6a8"
|
sha256: "63e5216aae014a72fe9579ccd027323395ce7a98271d9defa9d57320d001af81"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "10.2.0"
|
version: "10.4.3"
|
||||||
permission_handler_android:
|
permission_handler_android:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: permission_handler_android
|
name: permission_handler_android
|
||||||
sha256: d8cc6a62ded6d0f49c6eac337e080b066ee3bce4d405bd9439a61e1f1927bfe8
|
sha256: "2ffaf52a21f64ac9b35fe7369bb9533edbd4f698e5604db8645b1064ff4cf221"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "10.2.1"
|
version: "10.3.3"
|
||||||
permission_handler_apple:
|
permission_handler_apple:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: permission_handler_apple
|
name: permission_handler_apple
|
||||||
sha256: ee96ac32f5a8e6f80756e25b25b9f8e535816c8e6665a96b6d70681f8c4f7e85
|
sha256: "99e220bce3f8877c78e4ace901082fb29fa1b4ebde529ad0932d8d664b34f3f5"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "9.0.8"
|
version: "9.1.4"
|
||||||
permission_handler_platform_interface:
|
permission_handler_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: permission_handler_platform_interface
|
name: permission_handler_platform_interface
|
||||||
sha256: "68abbc472002b5e6dfce47fe9898c6b7d8328d58b5d2524f75e277c07a97eb84"
|
sha256: "7c6b1500385dd1d2ca61bb89e2488ca178e274a69144d26bbd65e33eae7c02a9"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.9.0"
|
version: "3.11.3"
|
||||||
permission_handler_windows:
|
permission_handler_windows:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: permission_handler_windows
|
name: permission_handler_windows
|
||||||
sha256: f67cab14b4328574938ecea2db3475dad7af7ead6afab6338772c5f88963e38b
|
sha256: cc074aace208760f1eee6aa4fae766b45d947df85bc831cde77009cdb4720098
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.1.2"
|
version: "0.1.3"
|
||||||
petitparser:
|
petitparser:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -570,10 +586,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: plugin_platform_interface
|
name: plugin_platform_interface
|
||||||
sha256: "6a2128648c854906c53fa8e33986fc0247a1116122f9534dd20e3ab9e16a32bc"
|
sha256: "43798d895c929056255600343db8f049921cbec94d31ec87f1dc5c16c01935dd"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.4"
|
version: "2.1.5"
|
||||||
pointycastle:
|
pointycastle:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -582,14 +598,6 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.7.3"
|
version: "3.7.3"
|
||||||
process:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: process
|
|
||||||
sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "4.2.4"
|
|
||||||
provider:
|
provider:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -618,58 +626,58 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: shared_preferences
|
name: shared_preferences
|
||||||
sha256: "16d3fb6b3692ad244a695c0183fca18cf81fd4b821664394a781de42386bf022"
|
sha256: "0344316c947ffeb3a529eac929e1978fcd37c26be4e8468628bac399365a3ca1"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.1"
|
version: "2.2.0"
|
||||||
shared_preferences_android:
|
shared_preferences_android:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shared_preferences_android
|
name: shared_preferences_android
|
||||||
sha256: "6478c6bbbecfe9aced34c483171e90d7c078f5883558b30ec3163cf18402c749"
|
sha256: fe8401ec5b6dcd739a0fe9588802069e608c3fdbfd3c3c93e546cf2f90438076
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.4"
|
version: "2.2.0"
|
||||||
shared_preferences_foundation:
|
shared_preferences_foundation:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shared_preferences_foundation
|
name: shared_preferences_foundation
|
||||||
sha256: e014107bb79d6d3297196f4f2d0db54b5d1f85b8ea8ff63b8e8b391a02700feb
|
sha256: f39696b83e844923b642ce9dd4bd31736c17e697f6731a5adf445b1274cf3cd4
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.2"
|
version: "2.3.2"
|
||||||
shared_preferences_linux:
|
shared_preferences_linux:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shared_preferences_linux
|
name: shared_preferences_linux
|
||||||
sha256: "9d387433ca65717bbf1be88f4d5bb18f10508917a8fa2fb02e0fd0d7479a9afa"
|
sha256: "71d6806d1449b0a9d4e85e0c7a917771e672a3d5dc61149cc9fac871115018e1"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.0"
|
version: "2.3.0"
|
||||||
shared_preferences_platform_interface:
|
shared_preferences_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shared_preferences_platform_interface
|
name: shared_preferences_platform_interface
|
||||||
sha256: fb5cf25c0235df2d0640ac1b1174f6466bd311f621574997ac59018a6664548d
|
sha256: "23b052f17a25b90ff2b61aad4cc962154da76fb62848a9ce088efe30d7c50ab1"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.0"
|
version: "2.3.0"
|
||||||
shared_preferences_web:
|
shared_preferences_web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shared_preferences_web
|
name: shared_preferences_web
|
||||||
sha256: "74083203a8eae241e0de4a0d597dbedab3b8fef5563f33cf3c12d7e93c655ca5"
|
sha256: "7347b194fb0bbeb4058e6a4e87ee70350b6b2b90f8ac5f8bd5b3a01548f6d33a"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.0"
|
version: "2.2.0"
|
||||||
shared_preferences_windows:
|
shared_preferences_windows:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shared_preferences_windows
|
name: shared_preferences_windows
|
||||||
sha256: "5e588e2efef56916a3b229c3bfe81e6a525665a454519ca51dbcc4236a274173"
|
sha256: f95e6a43162bce43c9c3405f3eb6f39e5b5d11f65fab19196cf8225e2777624d
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.0"
|
version: "2.3.0"
|
||||||
sky_engine:
|
sky_engine:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
@ -695,10 +703,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: sqflite_common
|
name: sqflite_common
|
||||||
sha256: e77abf6ff961d69dfef41daccbb66b51e9983cdd5cb35bf30733598057401555
|
sha256: "8f7603f3f8f126740bc55c4ca2d1027aab4b74a1267a3e31ce51fe40e3b65b8f"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.5"
|
version: "2.4.5+1"
|
||||||
stack_trace:
|
stack_trace:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -767,18 +775,18 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: url_launcher
|
name: url_launcher
|
||||||
sha256: eb1e00ab44303d50dd487aab67ebc575456c146c6af44422f9c13889984c00f3
|
sha256: "781bd58a1eb16069412365c98597726cd8810ae27435f04b3b4d3a470bacd61e"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.1.11"
|
version: "6.1.12"
|
||||||
url_launcher_android:
|
url_launcher_android:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: url_launcher_android
|
name: url_launcher_android
|
||||||
sha256: eed4e6a1164aa9794409325c3b707ff424d4d1c2a785e7db67f8bbda00e36e51
|
sha256: "78cb6dea3e93148615109e58e42c35d1ffbf5ef66c44add673d0ab75f12ff3af"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.0.35"
|
version: "6.0.37"
|
||||||
url_launcher_ios:
|
url_launcher_ios:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -799,34 +807,34 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: url_launcher_macos
|
name: url_launcher_macos
|
||||||
sha256: "91ee3e75ea9dadf38036200c5d3743518f4a5eb77a8d13fda1ee5764373f185e"
|
sha256: "1c4fdc0bfea61a70792ce97157e5cc17260f61abbe4f39354513f39ec6fd73b1"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.5"
|
version: "3.0.6"
|
||||||
url_launcher_platform_interface:
|
url_launcher_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: url_launcher_platform_interface
|
name: url_launcher_platform_interface
|
||||||
sha256: "6c9ca697a5ae218ce56cece69d46128169a58aa8653c1b01d26fcd4aad8c4370"
|
sha256: bfdfa402f1f3298637d71ca8ecfe840b4696698213d5346e9d12d4ab647ee2ea
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.2"
|
version: "2.1.3"
|
||||||
url_launcher_web:
|
url_launcher_web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: url_launcher_web
|
name: url_launcher_web
|
||||||
sha256: "6bb1e5d7fe53daf02a8fee85352432a40b1f868a81880e99ec7440113d5cfcab"
|
sha256: cc26720eefe98c1b71d85f9dc7ef0cada5132617046369d9dc296b3ecaa5cbb4
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.17"
|
version: "2.0.18"
|
||||||
url_launcher_windows:
|
url_launcher_windows:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: url_launcher_windows
|
name: url_launcher_windows
|
||||||
sha256: "254708f17f7c20a9c8c471f67d86d76d4a3f9c1591aad1e15292008aceb82771"
|
sha256: "7967065dd2b5fccc18c653b97958fdf839c5478c28e767c61ee879f4e7882422"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.6"
|
version: "3.0.7"
|
||||||
uuid:
|
uuid:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -847,58 +855,58 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: webview_flutter
|
name: webview_flutter
|
||||||
sha256: "5604dac1178680a34fbe4a08c7b69ec42cca6601dc300009ec9ff69bef284cc2"
|
sha256: "789d52bd789373cc1e100fb634af2127e86c99cf9abde09499743270c5de8d00"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.2.1"
|
version: "4.2.2"
|
||||||
webview_flutter_android:
|
webview_flutter_android:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: webview_flutter_android
|
name: webview_flutter_android
|
||||||
sha256: "57a22c86065375c1598b57224f92d6008141be0c877c64100de8bfb6f71083d8"
|
sha256: "8587d0b4991bd0f223f4b4957101c2c7449f905601571315f4967072498dd3fb"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.7.1"
|
version: "3.9.1"
|
||||||
webview_flutter_platform_interface:
|
webview_flutter_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: webview_flutter_platform_interface
|
name: webview_flutter_platform_interface
|
||||||
sha256: "656e2aeaef318900fffd21468b6ddc7958c7092a642f0e7220bac328b70d4a81"
|
sha256: "564ef378cafc1a0e29f1d76ce175ef517a0a6115875dff7b43fccbef2b0aeb30"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.1"
|
version: "2.4.0"
|
||||||
webview_flutter_wkwebview:
|
webview_flutter_wkwebview:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: webview_flutter_wkwebview
|
name: webview_flutter_wkwebview
|
||||||
sha256: "6bbc6ade302b842999b27cbaa7171241c273deea8a9c73f92ceb3d811c767de2"
|
sha256: "3e36a8f564809cb7c257ff4278502b185e2191349df0ddee98837f91805c74b8"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.4.4"
|
version: "3.7.1"
|
||||||
win32:
|
win32:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: win32
|
name: win32
|
||||||
sha256: "5a751eddf9db89b3e5f9d50c20ab8612296e4e8db69009788d6c8b060a84191c"
|
sha256: dfdf0136e0aa7a1b474ea133e67cb0154a0acd2599c4f3ada3b49d38d38793ee
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.1.4"
|
version: "5.0.5"
|
||||||
win32_registry:
|
win32_registry:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: win32_registry
|
name: win32_registry
|
||||||
sha256: "1c52f994bdccb77103a6231ad4ea331a244dbcef5d1f37d8462f713143b0bfae"
|
sha256: e4506d60b7244251bc59df15656a3093501c37fb5af02105a944d73eb95be4c9
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.0"
|
version: "1.1.1"
|
||||||
xdg_directories:
|
xdg_directories:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: xdg_directories
|
name: xdg_directories
|
||||||
sha256: ee1505df1426458f7f60aac270645098d318a8b4766d85fde75f76f2e21807d1
|
sha256: e0b1147eec179d3911f1f19b59206448f78195ca1d20514134e10641b7d7fbff
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.0"
|
version: "1.0.1"
|
||||||
xml:
|
xml:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -917,4 +925,4 @@ packages:
|
|||||||
version: "3.1.2"
|
version: "3.1.2"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.0.0 <4.0.0"
|
dart: ">=3.0.0 <4.0.0"
|
||||||
flutter: ">=3.4.0-17.0.pre"
|
flutter: ">=3.10.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
|
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||||
# In Windows, build-name is used as the major, minor, and patch parts
|
# In Windows, build-name is used as the major, minor, and patch parts
|
||||||
# of the product and file versions while build-number is used as the build suffix.
|
# of the product and file versions while build-number is used as the build suffix.
|
||||||
version: 0.13.8+172 # When changing this, update the tag in main() accordingly
|
version: 0.13.19+183 # When changing this, update the tag in main() accordingly
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=2.18.2 <3.0.0'
|
sdk: '>=2.18.2 <3.0.0'
|
||||||
@ -37,8 +37,8 @@ dependencies:
|
|||||||
# Use with the CupertinoIcons class for iOS style icons.
|
# Use with the CupertinoIcons class for iOS style icons.
|
||||||
cupertino_icons: ^1.0.5
|
cupertino_icons: ^1.0.5
|
||||||
path_provider: ^2.0.11
|
path_provider: ^2.0.11
|
||||||
flutter_fgbg: ^0.2.0 # Try removing reliance on this
|
flutter_fgbg: ^0.3.0 # Try removing reliance on this
|
||||||
flutter_local_notifications: ^14.0.0+1
|
flutter_local_notifications: ^15.1.0+1
|
||||||
provider: ^6.0.3
|
provider: ^6.0.3
|
||||||
http: ^1.0.0
|
http: ^1.0.0
|
||||||
webview_flutter: ^4.0.0
|
webview_flutter: ^4.0.0
|
||||||
@ -63,8 +63,8 @@ dependencies:
|
|||||||
easy_localization: ^3.0.1
|
easy_localization: ^3.0.1
|
||||||
android_intent_plus: ^4.0.0
|
android_intent_plus: ^4.0.0
|
||||||
flutter_markdown: ^0.6.14
|
flutter_markdown: ^0.6.14
|
||||||
archive: ^3.3.7
|
flutter_archive: ^5.0.0
|
||||||
|
hsluv: ^1.1.3
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
Reference in New Issue
Block a user