Merge branch 'main' into patch-1

This commit is contained in:
Imran Remtulla
2023-07-23 01:26:51 -04:00
committed by GitHub
7 changed files with 346 additions and 33 deletions

290
assets/translations/bs.json Normal file
View File

@@ -0,0 +1,290 @@
{
"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",
"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."
}
}

View File

@@ -237,8 +237,8 @@
"removeOnExternalUninstall": "外部でアンインストールされたアプリを自動的に削除する",
"pickHighestVersionCode": "最も高いバージョンコードのAPKを自動的に選択する",
"checkUpdateOnDetailPage": "アプリの詳細ページを開く際にアップデートを確認する",
"disablePageTransitions": "Disable page transition animations",
"reversePageTransitions": "Reverse page transition animations",
"disablePageTransitions": "ページ遷移アニメーションを無効化する",
"reversePageTransitions": "ページ遷移アニメーションを反転する",
"removeAppQuestion": {
"one": "アプリを削除しますか?",
"other": "アプリを削除しますか?"

View File

@@ -1,5 +1,6 @@
import 'dart:math';
import 'package:hsluv/hsluv.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:obtainium/components/generated_form_modal.dart';
@@ -132,19 +133,19 @@ class GeneratedForm extends StatefulWidget {
State<GeneratedForm> createState() => _GeneratedFormState();
}
// Generates a random light color
// Courtesy of ChatGPT 😭 (with a bugfix 🥳)
// Generates a color in the HSLuv (Pastel) color space
// https://pub.dev/documentation/hsluv/latest/hsluv/Hsluv/hpluvToRgb.html
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();
final randomSeed = Random().nextInt(120);
// https://en.wikipedia.org/wiki/Golden_angle
final goldenAngle = 180 * (3 - sqrt(5));
// Generate next golden angle hue
final double hue = randomSeed * goldenAngle;
// Map from HPLuv color space to RGB, use constant saturation=100, lightness=70
final List<double> rgbValuesDbl = Hsluv.hpluvToRgb([hue, 100, 70]);
// Map RBG values from 0-1 to 0-255:
final List<int> rgbValues = rgbValuesDbl.map((rgb) => (rgb * 255).toInt()).toList();
return Color.fromARGB(255, rgbValues[0], rgbValues[1], rgbValues[2]);
}
class _GeneratedFormState extends State<GeneratedForm> {
@@ -368,6 +369,36 @@ class _GeneratedFormState extends State<GeneratedForm> {
));
}) ??
[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]
as Map<String, MapEntry<int, bool>>?)
?.values

View File

@@ -38,7 +38,8 @@ List<MapEntry<Locale, String>> supportedLocales = const [
MapEntry(Locale('fr'), 'Français'),
MapEntry(Locale('es'), 'Español'),
MapEntry(Locale('pl'), 'Polski'),
MapEntry(Locale('ru'), 'Русский'),
MapEntry(Locale('ru'), 'Русский язык'),
MapEntry(Locale('bs'), 'Bosanski'),Z
];
const fallbackLocale = Locale('en');
const localeDir = 'assets/translations';

View File

@@ -1,5 +1,3 @@
import 'dart:math';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:obtainium/components/custom_app_bar.dart';
@@ -21,21 +19,6 @@ class SettingsPage extends StatefulWidget {
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> {
@override
Widget build(BuildContext context) {

View File

@@ -326,6 +326,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "8.2.2"
hsluv:
dependency: "direct main"
description:
name: hsluv
sha256: f33e63b0c24ceee0f6492874424aa8edc671ef9a20cc889e4b969284d8f02eb1
url: "https://pub.dev"
source: hosted
version: "1.1.3"
html:
dependency: "direct main"
description:

View File

@@ -64,7 +64,7 @@ dependencies:
android_intent_plus: ^4.0.0
flutter_markdown: ^0.6.14
flutter_archive: ^5.0.0
hsluv: ^1.1.3
dev_dependencies:
flutter_test: