diff --git a/composeApp/build.gradle.kts b/composeApp/build.gradle.kts
index 71d3b924..5c5811e4 100644
--- a/composeApp/build.gradle.kts
+++ b/composeApp/build.gradle.kts
@@ -260,6 +260,7 @@ kotlin {
commonMain.dependencies {
implementation(libs.coil.compose)
implementation(libs.coil.network.ktor3)
+ implementation(libs.coil.svg)
implementation("dev.chrisbanes.haze:haze:1.7.2")
implementation(libs.compose.runtime)
implementation(libs.compose.foundation)
diff --git a/composeApp/src/androidMain/res/xml/locale_config.xml b/composeApp/src/androidMain/res/xml/locale_config.xml
index 7d3f2e85..2badd023 100644
--- a/composeApp/src/androidMain/res/xml/locale_config.xml
+++ b/composeApp/src/androidMain/res/xml/locale_config.xml
@@ -9,4 +9,5 @@
+
diff --git a/composeApp/src/commonMain/composeResources/values-cs/strings.xml b/composeApp/src/commonMain/composeResources/values-cs/strings.xml
new file mode 100644
index 00000000..d1c9be28
--- /dev/null
+++ b/composeApp/src/commonMain/composeResources/values-cs/strings.xml
@@ -0,0 +1,1245 @@
+
+ Otevřené uznání a kredity projektu
+ Zpět
+ Zrušit
+ Zavřít
+ Smazat
+ Hotovo
+ Upravit
+ Importovat
+ Další
+ OK
+ Přehrát
+ Předchozí
+ Odstranit
+ Změnit pořadí
+ Obnovit výchozí
+ Pokračovat
+ Opakovat
+ Uložit
+ Instaluje se
+ Doplňky
+ Aktivní
+ %1$d katalogů
+ Nastavitelné
+ Obnovuje se
+ %1$d zdrojů
+ Nedostupné
+ Konfigurovat doplněk
+ Smazat doplněk
+ Přidejte URL manifestu a začněte do Nuvia načítat katalogy, metadata, streamy nebo titulky.
+ Zatím nejsou nainstalovány žádné doplňky.
+ Zadejte URL doplňku.
+ URL doplňku
+ Nainstalovat doplněk
+ Načítání podrobností manifestu...
+ Ověřování URL manifestu a načítání podrobností o doplňku před instalací.
+ Kontrola doplňku
+ Instalace selhala
+ Doplněk %1$s byl úspěšně ověřen a přidán.
+ Doplněk nainstalován
+ Posunout doplněk dolů
+ Posunout doplněk nahoru
+ Aktivní
+ Doplňky
+ Katalogy
+ Obnovit doplněk
+ Přidat doplněk
+ Nainstalované doplňky
+ Přehled
+ %1$d pravidel id
+ Verze %1$s
+ Vybráno
+ Kopírovat JSON
+ %1$d kolekce, %2$d složka(y)
+ Smazat "%1$s"? Tuto akci nelze vrátit zpět.
+ Smazat kolekci
+ Přidat katalog
+ Přidat složku
+ Všechny žánry
+ Přidejte katalogy z nainstalovaných doplňků a určete, co se má v této složce zobrazovat.
+ Zatím žádné zdroje katalogů
+ Vybrat
+ Emoji
+ URL obrázku
+ Žádný
+ Obal
+ Vytvořit kolekci
+ Hotovo
+ Upravit kolekci
+ Upravit složku
+ Nastavte identitu složky, vzhled a zdroje katalogů se stejnou strukturou jako v hlavním editoru kolekcí.
+ Přidejte jednu a začněte.
+ Zatím žádné složky
+ Složky
+ Filtr žánrů
+ Zobrazit pouze obal
+ Skrýt název
+ Nová složka
+ Zobrazit tuto kolekci nad všemi běžnými katalogy na domovské obrazovce. Více připnutých kolekcí se řadí podle pořadí vytvoření.
+ Připnout nad katalogy
+ URL obrázku na pozadí (volitelné)
+ Název složky
+ URL animovaného GIFu (přehrává se pouze při zaměření)
+ Název kolekce
+ Uložit změny
+ Uložit
+ Vzhled
+ Základy
+ Zdroje katalogů
+ Vyberte katalogy doplňků, které by měla tato složka sdružovat.
+ Vybrat katalogy
+ Vybrat žánr
+ %1$d vybráno
+ %1$d katalogů
+ %1$d vybráno
+ Plakát
+ Čtverec
+ Širokoúhlý
+ Sloučit všechny katalogy do jedné karty
+ Zobrazit kartu \"Vše\"
+ Přehrát nastavený GIF místo statického obalu, pokud je k dispozici.
+ Zobrazit GIF, když je nastavený
+ %1$d zdroj(ů) · %2$s
+ Tvar dlaždice
+ Řádky
+ Karty
+ Režim zobrazení
+ Zdroje TMDB
+ Veřejný seznam
+ Produkce
+ Síť
+ Kolekce
+ Osoba
+ Režisér
+ Vlastní
+ Vyberte si předpřipravený zdroj. Po přidání ho můžete upravit nebo odstranit.
+ Vložte URL veřejného seznamu TMDB nebo pouze číslo z URL.
+ Vyhledávejte podle názvu studia, nebo vložte ID/URL společnosti na TMDB a rovnou ji přidejte.
+ Zadejte ID sítě. Běžné sítě jsou k dispozici v předvolbách a rychlých filtrech.
+ Vyhledejte název filmové kolekce nebo vložte ID kolekce z TMDB.
+ Zadejte ID nebo URL osoby na TMDB pro vytvoření řádku z hereckých rolí.
+ Zadejte ID nebo URL osoby na TMDB pro vytvoření řádku z režisérských rolí.
+ Vytvořte živý řádek TMDB pomocí volitelných filtrů. Pokud filtr nepotřebujete, nechte pole prázdná.
+ Veřejný seznam TMDB
+ ID sítě
+ ID kolekce
+ ID osoby
+ Název, ID nebo URL produkční společnosti
+ TMDB ID nebo URL
+ https://www.themoviedb.org/list/8504994 nebo 8504994
+ 213 pro Netflix, 49 pro HBO, 2739 pro Disney+
+ 10 pro Star Wars Collection
+ Marvel Studios, 420, nebo URL společnosti
+ 31 pro Toma Hankse, nebo URL osoby
+ Příklady: Marvel Studios, 420, nebo https://www.themoviedb.org/company/420.
+ Příklad: Star Wars Collection, Harry Potter Collection, nebo URL kolekce.
+ Příklady ID: Netflix 213, HBO 49, Disney+ 2739.
+ Příklad: https://www.themoviedb.org/list/8504994 nebo 8504994.
+ Příklad: https://www.themoviedb.org/person/31-tom-hanks nebo 31.
+ Zobrazovaný název
+ Zobrazí se jako název řádku/karty. Pokud je prázdné, Nuvio jej vytvoří ze zdroje.
+ Filmy Marvel, Netflix Originals, Pixar
+ Filmy s Tomem Hanksem, Oblíbení herci
+ Filmy od Christophera Nolana, Oblíbení režiséři
+ Nejlepší akční filmy, Korejská dramata, Animace 2024
+ Výsledky vyhledávání
+ Kolekce TMDB
+ Společnost TMDB %1$d
+ Kolekce TMDB %1$d
+ Typ
+ Filmy
+ Seriály
+ Obojí
+ Seřadit
+ Filtry
+ Pokud filtr nepotřebujete, nechte pole prázdná.
+ Rychlé žánry
+ Rychlé jazyky
+ Rychlé země
+ Rychlá klíčová slova
+ Rychlá studia
+ Rychlé sítě
+ ID žánrů
+ Použijte čísla žánrů TMDB. Oddělte více žánrů čárkami pro „A“, nebo svislítky pro „NEBO“.
+ Datum vydání nebo vysílání od
+ Datum vydání nebo vysílání do
+ Použijte formát RRRR-MM-DD, například 2024-01-01.
+ Minimální hodnocení
+ Maximální hodnocení
+ Hodnocení TMDB od 0 do 10. Příklad: 7.0.
+ Minimální počet hlasů
+ Slouží k vynechání neznámých titulů s malým počtem hlasů. Příklad: 100.
+ Původní jazyk
+ Použijte dvoupísmenné kódy jazyků, například en, ko, ja, cs.
+ Země původu
+ Použijte dvoupísmenné kódy zemí, například US, KR, JP, CZ.
+ ID klíčových slov
+ Použijte čísla klíčových slov TMDB. Rychlé volby vyplní běžné příklady.
+ 9715 pro superhrdinu
+ ID společností
+ Použijte ID studií/společností. Rychlé volby vyplní běžné příklady.
+ 420 pro Marvel Studios
+ ID sítí
+ Pouze pro seriály. Použijte ID sítí jako Netflix 213 nebo HBO 49.
+ 213 pro Netflix
+ Rok
+ Použijte čtyřmístný rok, například 2024.
+ Předvolby
+ Hledat
+ Přidat zdroj
+ Přidat seznam Trakt
+ Upravit seznam Trakt
+ Seznamy Trakt
+ Seznam Trakt
+ Vyhledat název, URL na Trakltu, nebo ID seznamu
+ Použijte URL veřejného seznamu Trakt, číselné ID seznamu, nebo vyhledávejte podle názvu.
+ Víkendové sledování, Vítězové ocenění
+ Výsledky vyhledávání
+ Trendy seznamy
+ Populární seznamy
+ Směr řazení
+ Vzestupně
+ Sestupně
+ Pořadí v seznamu
+ Nedávno přidáno
+ Název
+ Datum vydání
+ Délka
+ Populární
+ Procenta
+ Hlasy
+ Akční
+ Dobrodružný
+ Animovaný
+ Komedie
+ Horor
+ Sci-Fi
+ Drama
+ Krimi
+ Reality
+ Angličtina
+ Korejština
+ Japonština
+ Hindština
+ Španělština
+ Spojené státy
+ Korea
+ Japonsko
+ Indie
+ Velká Británie
+ Superhrdina
+ Podle knižní předlohy
+ Cestování v čase
+ Vesmír
+ Marvel
+ Disney
+ Pixar
+ Lucasfilm
+ Warner Bros.
+ Netflix
+ HBO
+ Disney+
+ Prime Video
+ Hulu
+ Původní
+ Populární
+ Nejlépe hodnocené
+ Nedávné
+ Seznam TMDB
+ Filmová kolekce TMDB
+ Produkce
+ Síť
+ Osoba
+ Režisér
+ Objevování TMDB
+ Vytvořte ji pro organizaci vašich katalogů.
+ Zatím žádné kolekce
+ %1$d složka(y)
+ Nebyly nalezeny žádné položky
+ Složka nebyla nalezena
+ Kolekce
+ Importovat kolekce
+ JSON
+ Vložte níže JSON vašich kolekcí.
+ Import
+ Nová kolekce
+ Připnuté
+ Vše
+ Vaše kolekce
+ Vytvořeno s ❤️ od Tapframe a přátel
+ Verze %1$s (%2$s)
+ Vypnuto
+ Zapnuto
+ Pozastavit
+ Znovu načíst
+ Už máte účet?
+ Pokračovat bez účtu
+ Vytvořit účet
+ Nemáte účet?
+ E-mail
+ nebo
+ Heslo
+ Přihlaste se pro přístup k vaší knihovně a postupu
+ Přihlásit se
+ Zaregistrujte se pro synchronizaci dat napříč zařízeními
+ Zaregistrovovat se
+ Vaše data budou uložena pouze lokálně
+ Streamujte všechno, všude
+ Vítejte zpět
+ Knihovna
+ Knihovna Trakt
+ Domů
+ Knihovna
+ Profil
+ Hledat
+ Zvukové stopy
+ Zvuk
+ Vestavěné
+ Spodní odsazení
+ Zavřít přehrávač
+ Barva
+ Právě hraje
+ E%1$d
+ S%1$dE%2$d
+ S%1$dE%2$d • %3$s
+ Epizody
+ Velikost písma
+ %1$dsp
+ Uzamknout ovládání přehrávače
+ Nejsou k dispozici žádné zvukové stopy
+ Nejsou k dispozici žádné epizody
+ Nebyly nalezeny žádné streamy
+ Žádné
+ Obrys
+ Epizody
+ Zdroje
+ Streamy
+ Chyba přehrávání
+ Přehrávání
+ Klepnutím načtěte titulky
+ Vrátit se zpět
+ Obnovit výchozí
+ Vyplnit
+ Přizpůsobit
+ Přiblížit
+ Přetočit o 10 sekund zpět
+ -%1$ds
+ +%1$ds
+ -%1$ds
+ +%1$ds
+ Přetočit o 10 sekund vpřed
+ Zdroje
+ Styl
+ Titulky
+ Titulky
+ Jas %1$s
+ Hlasitost %1$s
+ Ztlumeno
+ Staženo
+ Vysílá se
+ Bude oznámeno
+ Klepnutím odemknete
+ Stopa %1$d
+ Odemknout ovládání přehrávače
+ Právě sledujete
+ Přidat profil
+ Vymazat hledání
+ Objevovat
+ Nainstalovaným doplňkům se nepodařilo vrátit platné výsledky vyhledávání.
+ Hledání selhalo
+ Před vyhledáváním nainstalujte a ověřte alespoň jeden doplněk.
+ Žádné aktivní doplňky
+ Nainstalované prohledávatelné katalogy nevrátily žádné shody pro tento dotaz.
+ Nebyly nalezeny žádné výsledky
+ Vaše nainstalované doplňky neumožňují vyhledávání v katalozích.
+ Žádné prohledávatelné katalogy
+ Hledat filmy, seriály...
+ Nedávná hledání
+ Odstranit nedávné hledání
+ O aplikaci
+ Obecné
+ Účet
+ Doplňky
+ Rozvržení
+ Obsah a objevování
+ Pokračovat ve sledování
+ Rozvržení domovské obrazovky
+ Integrace
+ Hodnocení MDBList
+ Stránka podrobností
+ Oznámení
+ Přehrávání
+ Pluginy
+ Styl karty plakátu
+ Nastavení
+ Podporovatelé a přispěvatelé
+ Obohacení TMDB
+ Trakt
+ O APLIKACI
+ Účet a stav synchronizace
+ ÚČET
+ Struktura domovské obrazovky a styly plakátů
+ Stáhnout nejnovější verzi
+ Zkontrolovat aktualizace
+ Spravovat doplňky a zdroje objevování.
+ Spravovat vaše stažené filmy a epizody.
+ Stahování
+ OBECNÉ
+ Spravovat dostupné integrace
+ Spravovat upozornění na vydání epizod a odeslat zkušební oznámení.
+ Přepnout na jiný profil.
+ Přepnout profil
+ Otevřít obrazovku připojení k Trakt
+ Nebylo nalezeno žádné nastavení.
+ Hledat v nastavení...
+ VÝSLEDKY
+ Načítání vašich seznamů Trakt…
+ Vyberte, kam na Trakt chcete tento titul uložit
+ Přispět
+ Přejít na podrobnosti
+ Odstranit
+ Spustit od začátku
+ Přehrát
+ %1$d/10
+ Recenze
+ Spoiler
+ Zatím nejsou k dispozici žádné recenze Trakt.
+ %1$d To se mi líbí
+ Tento komentář obsahuje spoilery.
+ Tento komentář obsahuje spoilery a byl skryt.
+ Komentáře
+ Trailer
+ %1$s (%2$d)
+ Trailery
+ Žádné dokončené epizody
+ Zatím žádná stahování
+ %1$d stažená epizoda (epizody)
+ Aktivní
+ Filmy
+ Seriály
+ Zobrazit stahování
+ Dokončeno • %1$s
+ Stahování • %1$s
+ Selhalo
+ Pozastaveno • %1$s
+ Zhlédnuto
+ Série %1$d
+ Speciály
+ Pokračujte tam, kde jste přestali
+ Přidat do knihovny
+ Označit jako nezhlédnuté
+ Označit jako zhlédnuté
+ Odebrat z knihovny
+ Zobrazit vše
+ Přehrát ručně
+ Logo %1$s
+ Účet
+ Smazat účet
+ Tímto trvale smažete svůj účet a všechna přidružená data.
+ Tuto akci nelze vrátit zpět. Všechna vaše data, profily a historie synchronizace budou trvale smazány.
+ Smazat účet?
+ E-mail
+ Nepřihlášen
+ Odhlásit se
+ Budete vráceni na přihlašovací obrazovku.
+ Odhlásit se?
+ Stav
+ Anonymní
+ Přihlášen
+ AMOLED Černá
+ Použít čistě černé pozadí pro OLED obrazovky.
+ Jazyk aplikace
+ Vyberte jazyk
+ Nastavení pro sekci Pokračovat ve sledování.
+ Tekuté sklo (Liquid Glass)
+ Použít nativní lištu panelů na iPhonu v iOS 26 a novějším. Okamžité přepínání profilů z lišty panelů není při zapnutí dostupné.
+ Vyladit šířku karty a poloměr rohů.
+ ZOBRAZENÍ
+ DOMŮ
+ MOTIV
+ Kolekce • %1$s
+ Zobrazovaný název
+ Nainstalujte doplněk s katalogy kompatibilními s dlaždicemi pro konfiguraci řádků domovské obrazovky.
+ Žádné domácí katalogy
+ Zdroj pro Carousel (Hero)
+ Skryto
+ Ponechat zaměření na Domů
+ %1$s • Dosažen limit (max %2$d)
+ Nebyly vybrány žádné zdroje pro Carousel
+ Není v Carouselu
+ Chcete-li kolekci přesunout, odeberte její připnutí nahoru
+ Připnuto
+ Připnuto nahoru
+ Změnit pořadí
+ KATALOGY
+ KATALOGY A KOLEKCE
+ KOLEKCE
+ Rozvržení domovské obrazovky
+ Katalogy Carouselu (Hero)
+ Vybráno %1$d z %2$d
+ Zobrazit sekci Carousel (Hero)
+ Zobrazit carousel na vrcholu domovské obrazovky.
+ Skrýt nevydaný obsah
+ Skrýt filmy a seriály, které ještě nebyly vydány.
+ %1$d z %2$d katalogů je viditelných • %3$d vybraných zdrojů Carouselu
+ Otevřete katalog pouze tehdy, když jej potřebujete přejmenovat nebo změnit jeho pořadí.
+ Viditelné
+ Skrýt hodnotu
+ Přehrávač, titulky a automatické přehrávání
+ Poloměr rohů
+ Styl karty plakátu
+ Šířka
+ Vlastní
+ Vyladit šířku karty a poloměr rohů.
+ Skrýt štítky
+ Plakáty na šířku
+ Živý náhled
+ %1$s (%2$s)
+ Poloměr rohů: %1$ddp
+ Výška: %1$ddp
+ Šířka: %1$ddp
+ Klasický
+ Pilulka
+ Zaoblený
+ Ostrý
+ Decentní
+ Vyvážená
+ Komfortní
+ Kompaktní
+ Hustá
+ Velká
+ Standardní
+ Zobrazit hodnotu
+ Zobrazit vyskakovací okno pro pokračování, když aplikaci otevřete poté, co jste ji opustili z přehrávače.
+ Výzva k pokračování po spuštění
+ Rozmazat náhledy dalších epizod v sekci Pokračovat ve sledování, abyste se vyhnuli spoilerům.
+ Rozmazat nezhlédnuté v Pokračovat ve sledování
+ Zahrnout do Pokračovat ve sledování i nadcházející epizody, než se budou vysílat.
+ Zobrazit nevysílané v Další na řadě
+ Styl karty plakátu
+ PŘI SPUŠTĚNÍ
+ CHOVÁNÍ DALŠÍ NA ŘADĚ
+ VIDITELNOST
+ Zobrazit lištu Pokračovat ve sledování na domovské obrazovce.
+ Zobrazit Pokračovat ve sledování
+ Plakát
+ Karta plakátu zaměřená na grafiku
+ Široký
+ Horizontální karta s vysokou hustotou informací
+ Zobrazit další epizodu podle nejdále zhlédnuté epizody. Vypněte pro opakované sledování, aby se použila naposledy zhlédnutá epizoda.
+ Další na řadě od nejdále zhlédnuté
+ Upřednostňovat náhledy epizod, pokud jsou k dispozici.
+ Upřednostňovat náhledy epizod v Pokračovat ve sledování
+ DOMŮ
+ ZDROJE
+ Instalujte, odebírejte, obnovujte a řaďte své zdroje obsahu.
+ Interní instalace repozitářů JavaScriptových scraperů a testovacích poskytovatelů.
+ Upravte rozložení domovské obrazovky, viditelnost obsahu a chování plakátů.
+ Nastavení pro obrazovky podrobností a epizod.
+ Vytvářejte vlastní seskupení katalogů se složkami na domovské obrazovce.
+ Integrace
+ Ovládací prvky pro obohacení metadat
+ Externí poskytovatelé hodnocení
+ Než zapnete hodnocení, přidejte níže svůj MDBList API klíč.
+ Vyžadováno pro načítání hodnocení z MDBListu
+ API klíč
+ API klíč
+ Povolit hodnocení MDBList
+ Načítat hodnocení od externích poskytovatelů na obrazovce s metadaty
+ API klíč
+ Externí poskytovatelé hodnocení
+ Hodnocení MDBList
+ Akce
+ Ovládací prvky pro přehrávání a ukládání.
+ Obsazení
+ Hlavní seznam herců.
+ Filmové pozadí
+ Rozmazané pozadí za obsahem, podobné obrazovce streamu.
+ Kolekce
+ Související kolekce nebo filmová série.
+ Komentáře
+ Recenze z Trakt
+ Podrobnosti
+ Délka, stav, vydání, jazyk a související informace.
+ Karty epizod
+ Vyberte, jak se budou epizody vykreslovat na obrazovce s metadaty.
+ Horizontální
+ Řádkové karty ve stylu pozadí
+ Seznam
+ Skládané karty zaměřené na detaily
+ Epizody
+ Sezóny a seznam epizod pro seriály.
+ Rozmazat nezhlédnuté epizody
+ Rozmazat náhledy epizod, dokud nebudou zhlédnuty, abyste se vyhnuli spoilerům.
+ Skupina %1$d
+ Podobné
+ Doporučení TMDB na stránce podrobností
+ Žádné
+ Přehled
+ Synopse, hodnocení, žánry a hlavní tvůrci.
+ Produkce
+ Studia a sítě.
+ VZHLED
+ SEKCE
+ Skupina karet %1$d
+ Rozvržení karet
+ Seskupte sekce do karet podobně jako v TV aplikaci. Přiřaďte až 3 sekce do jedné skupiny.
+ Trailery
+ Trailery a zástupci pro přehrávání.
+ Oznámení jsou v Nuviu momentálně zakázána.
+ Upozornění na vydání epizod
+ Naplánovat lokální oznámení, když bude dostupná nová epizoda pro uložený seriál.
+ Systémová oznámení jsou pro Nuvio zakázána. Povolte je pro přijímání upozornění a zkušebních oznámení.
+ Na tomto zařízení je aktuálně naplánováno %1$d upozornění na vydání.
+ UPOZORNĚNÍ
+ TEST
+ Odeslat zkušební oznámení
+ Odesílání zkušebního oznámení...
+ Odeslat lokální zkušební oznámení pro %1$s.
+ Pro otestování oznámení nejprve uložte nějaký seriál do knihovny.
+ Zkušební oznámení
+ Komunita
+ Podívejte se na lidi, kteří budují a podporují Nuvio napříč Mobilem, TV a Webem.
+ API pro podporovatele není nakonfigurováno. Přidejte DONATIONS_BASE_URL do local.properties.
+ Přispěvatelé
+ Podporovatelé
+ Otevřít GitHub
+ Profil na GitHubu není k dispozici
+ Nebyla připojena žádná zpráva.
+ Načítání přispěvatelů...
+ Načítání podporovatelů...
+ Nepodařilo se načíst přispěvatele
+ Nepodařilo se načíst podporovatele
+ Nebyli nalezeni žádní přispěvatelé.
+ Nebyli nalezeni žádní podporovatelé.
+ Nelze načíst přispěvatele.
+ Nelze načíst podporovatele.
+ Momentálně nelze načíst přispěvatele.
+ Momentálně nelze načíst podporovatele.
+ %1$d celkových commitů
+ Led
+ Úno
+ Bře
+ Dub
+ Kvě
+ Čvn
+ Čvc
+ Srp
+ Zář
+ Říj
+ Lis
+ Pro
+ %1$s %2$s, %3$s
+ Všechny nainstalované doplňky
+ Všechny povolené pluginy
+ Povolené doplňky
+ Povolené pluginy
+ Anime Skip (přeskakování)
+ AnimeSkip Client ID
+ Zadejte své AnimeSkip API klientské ID. Získáte jej na anime-skip.com.
+ Povolit odesílání intra
+ Zobrazit tlačítko pro odeslání časových značek intra/outra do komunitní databáze.
+ IntroDB API klíč
+ Zadejte svůj IntroDB API klíč pro odesílání časových značek. Vyžadováno pro odesílání.
+ Hledat také časové značky pro přeskočení v AnimeSkip (vyžaduje klientské ID).
+ Automaticky přehrát další epizodu
+ Po zobrazení výzvy automaticky spustit další epizodu.
+ Pouze dekodéry zařízení
+ Upřednostnit dekodéry aplikace (FFmpeg)
+ Upřednostnit dekodéry zařízení
+ Priorita dekodéru
+ Klepnutím mimo zavřete
+ Klepnutím mimo uložíte a zavřete
+ %1$d den
+ %1$d dní
+ %1$d hodina
+ %1$d hodin
+ Použít libass pro titulky ASS/SSA
+ Experimentální: pokročilé vykreslování ASS/SSA (styly, pozicování, animace)
+ Rychlost při podržení
+ Podržet pro zrychlení
+ Dlouhým stisknutím kdekoli na ploše přehrávače dočasně zvýšíte rychlost přehrávání.
+ Neplatný vzor regulárního výrazu (regex)
+ Doba mezipaměti posledního odkazu
+ Záložní DV7 - HEVC
+ Mapovat Dolby Vision profil 7 na standardní HEVC pro zařízení bez hardwarové podpory DV
+ Prahové minuty
+ Záložní řešení, pokud neexistuje časová značka pro outro.
+ %1$s min
+ Žádné položky nejsou k dispozici
+ Nenastaveno
+ Výchozí (soubor médií)
+ Jazyk zařízení
+ Vynucené
+ Žádné
+ Upřednostnit Binge skupinu (Další epizoda)
+ Zkusit přednostně stejný profil zdroje (stejný doplněk/skupinu kvality) před běžnými pravidly automatického přehrávání.
+ Preferovaný jazyk zvuku
+ Preferovaný jazyk titulků
+ Předvolby
+ Porovnává se s názvem streamu/titulem/popisem/doplňkem/url. Příklad: 4K|2160p|Remux
+ Vzor regulárního výrazu
+ Není nastaven žádný vzor. Příklad: 4K|2160p|Remux
+ Jakékoli 1080p+
+ AVC / x264
+ BluRay kvalita
+ Dolby Atmos / DTS
+ Angličtina
+ HDR / Dolby Vision
+ HEVC / x265
+ Žádné CAM/TS
+ Žádné REMUX/HDR
+ 1080p Standard
+ 4K / Remux
+ 720p / Menší
+ WEB zdroje
+ Režim vykreslování Libass
+ Standardní Cues
+ Efekty Canvas
+ Efekty OpenGL
+ Překrytí Canvas
+ Překrytí OpenGL (Doporučeno)
+ Znovu použít poslední odkaz
+ Automaticky přehrát poslední funkční stream pro tento stejný film/epizodu, pokud je mezipaměť stále platná.
+ Sekundární jazyk zvuku
+ Sekundární preferovaný jazyk
+ DEKODÉR
+ DALŠÍ EPIZODA
+ PŘEHRÁVAČ
+ PŘESKOČENÍ SEGMENTŮ
+ AUTOMATICKÉ PŘEHRÁVÁNÍ STREAMU
+ VÝBĚR STREAMU
+ TITULKY A ZVUK
+ VYKRESLOVÁNÍ TITULKŮ
+ %1$d vybráno
+ Načítací obrazovka
+ Zobrazovat načítací obrazovku, dokud se neobjeví první snímek videa.
+ Přeskočit intro
+ Použít introdb.app k detekci inter a shrnutí děje.
+ Rozsah zdrojů pro auto. přehrávání
+ Všechny nainstalované doplňky
+ Automatické přehrávání zvažuje pouze streamy pocházející z vašich nainstalovaných doplňků.
+ Všechny zdroje
+ Automatické přehrávání může používat nainstalované doplňky i povolené pluginy.
+ Pouze povolené pluginy
+ Automatické přehrávání zvažuje pouze streamy pocházející z povolených pluginů.
+ Pouze nainstalované doplňky
+ Automatické přehrávání zvažuje pouze streamy pocházející z vašich nainstalovaných doplňků.
+ Automatický výběr streamu
+ Automaticky přehrát první zdroj
+ Automaticky přehrát první dostupný zdroj.
+ Ručně (vybrat stream)
+ Vždy zobrazit seznam zdrojů a nechat mě vybrat.
+ Automatické přehrávání (shoda regex)
+ Přehrát první zdroj, jehož text odpovídá vašemu vzoru regulárního výrazu.
+ Časový limit výběru streamu
+ Čas čekání na doplňky před výběrem.
+ Prahové minuty
+ Režim prahu další epizody
+ Minut před koncem
+ Procenta
+ Prahová procenta
+ Záložní řešení, pokud neexistuje časová značka pro outro.
+ %1$s%
+ Okamžitě
+ %1$ss
+ Neomezeně
+ Tunelované přehrávání (Tunneled Playback)
+ Hardwarová synchronizace zvuku a videa. Může zlepšit přehrávání na některých zařízeních Android TV.
+ Před zapnutím obohacení zadejte níže svůj vlastní TMDB API klíč.
+ API klíč
+ Povolit obohacení TMDB
+ Použít TMDB jako zdroj metadat k vylepšení dat z doplňků.
+ Zadejte svůj TMDB v3 API klíč.
+ Kód jazyka
+ Grafika
+ Loga a obrázky na pozadí z TMDB
+ Základní informace
+ Popis, žánry a hodnocení z TMDB
+ Kolekce
+ Filmové kolekce TMDB v pořadí vydání
+ Obsazení a štáb
+ Obsazení s fotkami, režisér a scénárista z TMDB
+ Podrobnosti
+ Délka, stav, země a jazyk z TMDB
+ Epizody
+ Názvy epizod, přehledy, náhledy a délka z TMDB
+ Podobné
+ Doporučení TMDB na stránce podrobností
+ Sítě
+ Sítě s logy z TMDB
+ Produkce
+ Produkční společnosti z TMDB
+ Plakáty sérií
+ Použít plakáty sérií z TMDB ve výběru sérií na obrazovce s metadaty u seriálů.
+ Trailery
+ Kandidáti na trailery z videí na TMDB pro sekci detailů o trailerech
+ Osobní API klíč
+ Jazyk
+ Jazyk metadat z TMDB pro název, logo a povolená pole
+ PŘIHLAŠOVACÍ ÚDAJE
+ LOKALIZACE
+ MODULY
+ Obohacení TMDB
+ Po schválení budete automaticky přesměrováni zpět.
+ AUTENTIZACE
+ Komentáře
+ Zobrazit recenze z Traktu na stránkách s metadaty
+ Připojit Trakt
+ Připojeno jako %1$s
+ Uživatel Traktu
+ Odpojit
+ Nepodařilo se otevřít prohlížeč
+ FUNKCE
+ Dokončete přihlášení k Traktu ve vašem prohlížeči
+ Synchronizujte svůj seznam ke zhlédnutí, postup sledování, pokračování ve sledování, scrobbling a osobní seznamy s Traktem.
+ Chybí přihlašovací údaje k Traktu v local.properties (TRAKT_CLIENT_ID / TRAKT_CLIENT_SECRET).
+ Otevřít přihlášení k Traktu
+ Vaše akce uložení nyní mohou cílit na seznam ke zhlédnutí a osobní seznamy na Traktu.
+ Přihlaste se pomocí Traktu pro povolení ukládání do seznamů a režimu knihovny Trakt.
+ Zdroj knihovny
+ Vyberte, kterou knihovnu použít pro ukládání a prohlížení vaší kolekce
+ Zdroj knihovny
+ Vyberte, kam ukládat a spravovat položky vaší knihovny
+ Trakt
+ Knihovna Nuvio
+ Vybrána knihovna Trakt
+ Vybrána knihovna Nuvio
+ Postup sledování
+ Vyberte, který zdroj postupu pohání obnovení a pokračování ve sledování
+ Postup sledování
+ Vyberte, zda by obnovení a pokračování ve sledování mělo využívat Trakt nebo Nuvio Sync, zatímco Trakt scrobbling zůstane aktivní.
+ Trakt
+ Nuvio Sync
+ Zdroj postupu sledování nastaven na Trakt
+ Zdroj postupu sledování nastaven na Nuvio Sync
+ Okno pro pokračování ve sledování
+ Historie Traktu zohledněná pro pokračování ve sledování
+ Okno pro pokračování ve sledování
+ Vyberte, kolik aktivity z Traktu se má objevit v sekci pokračování ve sledování.
+ Celá historie
+ %1$d dní
+ Hodnocení diváků
+ IMDb
+ Letterboxd
+ Metacritic
+ Rotten Tomatoes
+ TMDB
+ Trakt
+ Neznámý
+ Jantarový
+ Karmínový
+ Smaragdový
+ Oceán
+ Růžový
+ Fialový
+ Bílý
+ Další epizoda
+ Hledání zdroje…
+ Přehrávání přes %1$s za %2$d…
+ Náhled další epizody
+ Nevysílané
+ Přeskočit
+ Přeskočit intro
+ Přeskočit outro
+ Přeskočit shrnutí
+ Nebyly nalezeny žádné titulky
+ Afrikánština
+ Albánština
+ Amharština
+ Arabština
+ Arménština
+ Ázerbájdžánština
+ Baskičtina
+ Běloruština
+ Bengálština
+ Bosenština
+ Bulharština
+ Barmština
+ Katalánština
+ Čínština
+ Čínština (zjednodušená)
+ Čínština (tradiční)
+ Chorvatština
+ Čeština
+ Dánština
+ Nizozemština
+ Angličtina
+ Estonština
+ Filipínština
+ Finština
+ Francouzština
+ Galicijština
+ Gruzínština
+ Němčina
+ Řečtina
+ Gudžarátština
+ Hebrejština
+ Hindština
+ Maďarština
+ Islandština
+ Indonéština
+ Irština
+ Italština
+ Japonština
+ Kannadština
+ Kazaština
+ Khmerština
+ Korejština
+ Laoština
+ Lotyština
+ Litevština
+ Makedonština
+ Malajština
+ Malajálamština
+ Maltština
+ Maráthština
+ Mongolština
+ Nepálština
+ Norština
+ Perština
+ Polština
+ Portugalština (Portugalsko)
+ Portugalština (Brazílie)
+ Paňdžábština
+ Rumunština
+ Ruština
+ Srbština
+ Sinhálština
+ Slovenština
+ Slovinština
+ Španělština
+ Španělština (Latinská Amerika)
+ Svahilština
+ Švédština
+ Tamilština
+ Telugština
+ Thajština
+ Turečtina
+ Ukrajinština
+ Urdština
+ Uzbečtina
+ Vietnamština
+ Velština
+ Zuluština
+ Vymazat
+ Pokračovat
+ Ignorovat
+ Instalovat
+ Později
+ Ne
+ Aktualizovat
+ Ano
+ Opravdu chcete ukončit aplikaci?
+ Ukončit aplikaci
+ Tento katalog nevrátil žádné položky.
+ Nebyly nalezeny žádné tituly
+ Zkontrolujte své připojení k Wi-Fi nebo mobilním datům a zkuste to znovu.
+ Režisér
+ Nepodařilo se načíst
+ Podobné
+ Série
+ Tento doplněk vrátil videa pro seriál, ale žádné neobsahovalo čísla série nebo epizody.
+ Tento doplněk neposkytl metadata epizod pro tento seriál.
+ Epizody ještě nebyly tímto doplňkem zveřejněny.
+ Vaše zařízení je online, ale Nuvio se nemohlo spojit s požadovanými servery.
+ Zobrazit méně
+ Zobrazit více ▾
+ Scénárista
+ Všechny žánry
+ Katalog
+ %1$s • %2$s
+ Vybranému katalogu se nepodařilo vrátit položky objevování.
+ Nepodařilo se načíst objevování
+ Nainstalované doplňky neposkytují katalogy kompatibilní s dlaždicemi pro objevování.
+ Žádné katalogy pro objevování
+ Vybraný katalog a filtry nevrátily žádné položky.
+ Nebyly nalezeny žádné tituly
+ Před procházením katalogů pro objevování nainstalujte a ověřte alespoň jeden doplněk.
+ Vybrat katalog
+ Vybrat žánr
+ Vybrat typ
+ Typ
+ Označit předchozí jako nezhlédnuté
+ Označit předchozí jako zhlédnuté
+ Označit %1$s jako nezhlédnutou
+ Označit %1$s jako zhlédnutou
+ Označit jako nezhlédnuté
+ Označit jako zhlédnuté
+ Další na řadě
+ %1$s zhlédnuto
+ Nainstalujte a ověřte alespoň jeden doplněk, než se načtou řádky katalogu na domovské obrazovce.
+ Nainstalované doplňky aktuálně neposkytují katalogy kompatibilní s dlaždicemi bez vyžadovaných doplňujících dat.
+ Žádné řádky domovské obrazovky nejsou k dispozici
+ Zobrazit podrobnosti
+ Ovládací prvky pro přehrávání a ukládání.
+ Akce
+ Hlavní seznam herců.
+ Související kolekce nebo filmová série.
+ Kolekce
+ Sekce komentářů Trakt.
+ Délka, stav, vydání, jazyk a související informace.
+ Podrobnosti
+ Sezóny a seznam epizod pro seriály.
+ Řádek doporučení.
+ Podobné
+ Synopse, hodnocení, žánry a hlavní tvůrci.
+ Přehled
+ Studia a sítě.
+ Produkce
+ Trailery a zástupci pro přehrávání.
+ Zpět online
+ Nelze se spojit se servery
+ Žádné připojení k internetu
+ (věk %1$d)
+ Narozen(a) %1$s%2$s
+ Zemřel(a) %1$s
+ Známý(á) z: %1$s
+ Nejnovější
+ Nepodařilo se načíst podrobnosti pro %1$s
+ Populární
+ Něco se pokazilo
+ Připravované
+ Zpět
+ Zrušit
+ Zadejte PIN
+ Zadejte PIN pro %1$s
+ Zapomněli jste PIN?
+ Nesprávný PIN
+ Uzamčeno. Zkuste to znovu za %1$ds
+ Možnosti avatarů se zobrazí zde, jakmile se načte katalog.
+ Avatar: %1$s
+ Zadejte platnou URL adresu obrázku s http:// nebo https://.
+ Vyberte avatara
+ Níže vyberte avatara.
+ Vytvořit profil
+ Vybrána vlastní URL avatara.
+ Vlastní URL avatara
+ Vložte odkaz na obrázek, nebo ponechte prázdné pro použití vestavěného katalogu avatarů.
+ https://example.com/avatar.png
+ Všechna data pro "%1$s" budou trvale smazána.
+ Smazat profil
+ Přidat profil
+ Upravit profil
+ Zadejte aktuální PIN
+ Zadejte nový PIN
+ Profil %1$d
+ Načítání avatarů...
+ Spravovat profily
+ Název profilu
+ Nový profil
+ Primární doplňky vypnuty
+ Primární doplňky zapnuty
+ Odstranit PIN pro %1$s
+ Odstranit zámek PIN
+ Ukládání...
+ Zabezpečení
+ Přidejte PIN, pokud chcete mít tento profil před přepnutím uzamčený.
+ Tento profil je chráněn kódem PIN.
+ Vyberte avatara pro tento profil.
+ Nastavit zámek PIN
+ Nepojmenovaný profil
+ Použít primární doplňky
+ Sdílet nastavení doplňků hlavního profilu namísto správy samostatného seznamu.
+ Kdo se dívá?
+ Staženo
+ Pokračovat
+ Aktivní scrapery
+ Kontrola dalších doplňků…
+ Kopírovat odkaz na stream
+ Stáhnout soubor
+ Nainstalovaným doplňkům se nepodařilo vrátit platnou odpověď pro streamy.
+ Nepodařilo se načíst streamy
+ Nejprve nainstalujte doplněk, abyste mohli načíst streamy pro tento titul.
+ Vaše nainstalované doplňky neposkytují streamy pro tento typ titulu.
+ Není k dispozici žádný doplněk pro streamování
+ Žádný z vašich nainstalovaných doplňků nevrátil streamy pro tento titul.
+ S%1$d E%2$d
+ Epizoda
+ S%1$dE%2$d - %3$s
+ Načítání…
+ Hledání zdroje…
+ Hledání streamů…
+ Odkaz na stream zkopírován
+ Není k dispozici žádný přímý odkaz na stream
+ Nejsou k dispozici žádná metadata
+ Obnovit streamy
+ Pokračovat od %1$d%%
+ Pokračovat od %1$s
+ VELIKOST %1$s
+ Torrent streamy nejsou podporovány
+ Zavřít trailer
+ Trailer nelze přehrát
+ Nepodařilo se načíst seznamy Trakt
+ Nepodařilo se aktualizovat seznamy Trakt
+ %1$s • %2$s
+ Kontrola aktualizací selhala
+ Stahování selhalo
+ Stahování %1$d%%
+ Nelze zahájit instalaci
+ Používáte nejnovější verzi.
+ Povolte instalace aplikací pro Nuvio, poté se vraťte a pokračujte.
+ Stahování aktualizace...
+ Nebyly nalezeny žádné aktualizace.
+ Nová verze je připravena k instalaci.
+ Aktualizace v aplikaci nejsou v tomto sestavení k dispozici.
+ Příprava stahování
+ Poznámky k vydání
+ Povolte instalace pro pokračování
+ Aktualizace k dispozici
+ Stav aktualizace
+ Tento doplněk je již nainstalován.
+ Zadejte platnou URL doplňku
+ Nelze načíst manifest
+ Nuvio
+ Smazání účtu selhalo
+ Přihlášení selhalo
+ Odhlášení selhalo
+ Registrace selhala
+ Nelze načíst položky katalogu.
+ Další na řadě
+ Další na řadě • S%1$dE%2$d
+ Logo %1$s
+ Nepodařilo se načíst komentáře
+ Nepodařilo se načíst podrobnosti z žádného doplňku.
+ Sítě
+ Žádný doplněk neposkytuje metadata pro tento obsah.
+ Stahování selhalo
+ Zobrazuje aktuální průběh a ovládání stahování.
+ Stahování
+ Stahování dokončeno
+ Stahování %1$s • %2$s
+ Stahování %1$s • %2$s / %3$s
+ Stahování selhalo
+ Pozastaveno %1$s
+ Odebrat
+ Odebrat %1$s z %2$s?
+ Odebrat %1$s z vaší knihovny?
+ Odebrat z knihovny?
+ Film
+ Upozornění na vydání nové epizody uloženého seriálu.
+ Náhled upozornění na vydání epizody.
+ Nepodařilo se odeslat zkušební oznámení.
+ Zkušební oznámení odesláno pro %1$s.
+ Tento stream nelze přehrát.
+ PIN tohoto profilu se změnil. Pro obnovení zámku na tomto zařízení se jednou připojte k internetu.
+ Zámek PIN se nepodařilo odstranit. Zkuste to znovu.
+ Pro odstranění zámku PIN se připojte k internetu.
+ Tento PIN zatím nelze na tomto zařízení ověřit offline. Nejprve se připojte a odemkněte jej online.
+ Nepodařilo se nastavit PIN. Zkuste to znovu.
+ Pro nastavení PIN kódu se připojte k internetu.
+ Tento profil používá primární doplňky.
+ Nepodařilo se načíst %1$s
+ Stream
+ Vložené
+ Autorizace odepřena
+ Dokončete přihlášení k Traktu ve vašem prohlížeči
+ Neplatný Trakt callback
+ Neplatný stav Trakt callbacku
+ Neplatná odpověď s tokenem Trakt
+ Nepodařilo se načíst knihovnu Trakt
+ Seznam %1$d
+ Trakt nevrátil autorizační kód
+ Chybí přihlašovací údaje k Traktu
+ Nepodařilo se načíst postup na Traktu
+ Nepodařilo se dokončit přihlášení k Traktu
+ Uživatel Traktu
+ Seznam ke zhlédnutí
+ Trailer
+ Neznámé
+ Doplněk
+ Uloženo
+ Přehrát %1$s
+ Pokračovat %1$s
+ JSON je prázdný.
+ Kolekce %1$d má prázdné ID.
+ Kolekce '%1$s' má prázdný název.
+ Složka %1$d v '%2$s' má prázdné ID.
+ Složka '%1$s' v '%2$s' má prázdný název.
+ Zdroj %1$d ve složce '%2$s' má prázdná pole.
+ Zdroj %1$d ve složce '%2$s' nemá ID seznamu Trakt.
+ Neplatný JSON: %1$s
+ Doplněk nenalezen: %1$s
+ Leden
+ Únor
+ Březen
+ Duben
+ Květen
+ Červen
+ Červenec
+ Srpen
+ Září
+ Říjen
+ Listopad
+ Prosinec
+ Led
+ Úno
+ Bře
+ Dub
+ Kvě
+ Čvn
+ Čvc
+ Srp
+ Zář
+ Říj
+ Lis
+ Pro
+ Produkční společnost
+ Síť
+ Nepodařilo se načíst %1$s
+ Populární
+ Nedávné
+ %1$s • %2$s
+ Nejlépe hodnocené
+ Věkové hodnocení
+ Podrobnosti o filmu
+ Původní jazyk
+ Země původu
+ Informace o vydání
+ Délka
+ Plakáty
+ Text
+ Podrobnosti o seriálu
+ Stav
+ Videa
+ SOUBOR
+ Není k dispozici žádný přímý odkaz na stream
+ Nahradilo předchozí stahování
+ Stahování zahájeno
+ Nepodporovaný formát streamu pro stahování
+ Prázdné tělo odpovědi
+ Požadavek selhal s chybou HTTP %1$d
+ Systém stahování není inicializován
+ Požadavek na stažení selhal
+ %1$s - %2$s
+ Uložené tituly se zde objeví poté, co klepnete na Uložit na obrazovce s podrobnostmi.
+ Vaše knihovna je prázdná
+ Knihovnu se nepodařilo načíst
+ Ostatní
+ Knihovna
+ Připojte Trakt a ukládejte tituly do svého seznamu ke zhlédnutí nebo do osobních seznamů.
+ Vaše knihovna Trakt je prázdná
+ Knihovnu Trakt se nepodařilo načíst
+ Knihovna Trakt
+ Anime
+ Kanály
+ Filmy
+ Seriály
+ TV
+ %1$s je nyní venku
+ %1$s • %2$s je nyní venku
+ Nová epizoda je nyní venku
+ %1$s je nyní venku
+ Vydání epizod
+ Tvůrce
+ Režisér
+ Scénárista
+ Hodnocení diváků
+ Nebyl nalezen žádný přehratelný stream traileru.
+ Série %1$d - %2$s
+ B
+ KB
+ MB
+ GB
+
diff --git a/composeApp/src/commonMain/composeResources/values/strings.xml b/composeApp/src/commonMain/composeResources/values/strings.xml
index 86c0d019..cd8a97e2 100644
--- a/composeApp/src/commonMain/composeResources/values/strings.xml
+++ b/composeApp/src/commonMain/composeResources/values/strings.xml
@@ -541,6 +541,12 @@
Blur Unwatched in Continue Watching
Include upcoming episodes in Continue Watching before they air.
Show Unaired Next Up Episodes
+ SORT ORDER
+ Sort Order
+ Default
+ Sort all items by recency
+ Streaming Style
+ Released items first, upcoming at the end
Poster Card Style
ON LAUNCH
UP NEXT BEHAVIOR
diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/App.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/App.kt
index 9a7be453..1508344b 100644
--- a/composeApp/src/commonMain/kotlin/com/nuvio/app/App.kt
+++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/App.kt
@@ -73,6 +73,7 @@ import coil3.ImageLoader
import coil3.compose.setSingletonImageLoaderFactory
import coil3.request.CachePolicy
import coil3.request.crossfade
+import coil3.svg.SvgDecoder
import com.nuvio.app.core.build.AppFeaturePolicy
import com.nuvio.app.core.auth.AuthRepository
import com.nuvio.app.core.auth.AuthState
@@ -304,6 +305,9 @@ fun App() {
.crossfade(true)
.diskCachePolicy(CachePolicy.ENABLED)
.memoryCachePolicy(CachePolicy.ENABLED)
+ .components {
+ add(SvgDecoder.Factory())
+ }
.configurePlatformImageLoader()
.build()
}
diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/HomeScreen.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/HomeScreen.kt
index 0b1fe5b5..c3c1a2a6 100644
--- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/HomeScreen.kt
+++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/HomeScreen.kt
@@ -42,6 +42,7 @@ import com.nuvio.app.features.watchprogress.ContinueWatchingEnrichmentCache
import com.nuvio.app.features.watchprogress.CurrentDateProvider
import com.nuvio.app.features.watchprogress.ContinueWatchingPreferencesRepository
import com.nuvio.app.features.watchprogress.ContinueWatchingItem
+import com.nuvio.app.features.watchprogress.ContinueWatchingSortMode
import com.nuvio.app.features.watchprogress.isSeriesTypeForContinueWatching
import com.nuvio.app.features.watchprogress.nextUpDismissKey
import com.nuvio.app.features.watchprogress.WatchProgressClock
@@ -247,11 +248,14 @@ fun HomeScreen(
visibleContinueWatchingEntries,
cachedInProgressItems,
effectivNextUpItems,
+ continueWatchingPreferences.sortMode,
) {
buildHomeContinueWatchingItems(
visibleEntries = visibleContinueWatchingEntries,
cachedInProgressByVideoId = cachedInProgressItems,
nextUpItemsBySeries = effectivNextUpItems,
+ sortMode = continueWatchingPreferences.sortMode,
+ todayIsoDate = CurrentDateProvider.todayIsoDate(),
)
}
val availableManifests = remember(addonsUiState.addons) {
@@ -639,6 +643,8 @@ internal fun buildHomeContinueWatchingItems(
visibleEntries: List,
cachedInProgressByVideoId: Map = emptyMap(),
nextUpItemsBySeries: Map>,
+ sortMode: ContinueWatchingSortMode = ContinueWatchingSortMode.DEFAULT,
+ todayIsoDate: String = "",
): List {
val inProgressSeriesIds = visibleEntries
.asSequence()
@@ -647,7 +653,7 @@ internal fun buildHomeContinueWatchingItems(
.filter(String::isNotBlank)
.toSet()
- return buildList {
+ val candidates = buildList {
addAll(
visibleEntries.map { entry ->
val liveItem = entry.toContinueWatchingItem()
@@ -669,13 +675,62 @@ internal fun buildHomeContinueWatchingItems(
},
)
}
+
+ // Deduplicate by series/content id first (order-stable)
+ val seen = mutableSetOf()
+ val deduplicated = candidates
.sortedWith(
compareByDescending { it.lastUpdatedEpochMs }
.thenByDescending { it.isProgressEntry },
)
.filter { candidate -> candidate.item.shouldDisplayInContinueWatching() }
- .distinctBy { candidate -> candidate.item.parentMetaId.ifBlank { candidate.item.videoId } }
+ .filter { candidate ->
+ val key = candidate.item.parentMetaId.ifBlank { candidate.item.videoId }
+ seen.add(key)
+ }
+
+ return when (sortMode) {
+ ContinueWatchingSortMode.DEFAULT -> deduplicated.map(HomeContinueWatchingCandidate::item)
+ ContinueWatchingSortMode.STREAMING_STYLE -> applyStreamingStyleSort(deduplicated, todayIsoDate)
+ }
+}
+
+private fun applyStreamingStyleSort(
+ candidates: List,
+ todayIsoDate: String,
+): List {
+ val (released, unreleased) = candidates.partition { candidate ->
+ val item = candidate.item
+ if (!item.isNextUp) {
+ true // in-progress items are always "released"
+ } else {
+ val itemReleased = item.released
+ if (itemReleased.isNullOrBlank() || todayIsoDate.isBlank()) {
+ true // no date info → treat as released
+ } else {
+ isReleasedBy(todayIsoDate = todayIsoDate, releasedDate = itemReleased)
+ }
+ }
+ }
+
+ // Released: most recently watched first (already sorted by dedup pass)
+ val sortedReleased = released.map(HomeContinueWatchingCandidate::item)
+
+ // Unaired: soonest air date first; unknown dates go to the end
+ val sortedUnreleased = unreleased
+ .sortedWith { a, b ->
+ val dateA = a.item.released?.takeIf { it.isNotBlank() }
+ val dateB = b.item.released?.takeIf { it.isNotBlank() }
+ when {
+ dateA == null && dateB == null -> 0
+ dateA == null -> 1
+ dateB == null -> -1
+ else -> dateA.compareTo(dateB)
+ }
+ }
.map(HomeContinueWatchingCandidate::item)
+
+ return sortedReleased + sortedUnreleased
}
private data class CompletedSeriesCandidate(
diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/AppLanguage.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/AppLanguage.kt
index 025d6acc..e629434d 100644
--- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/AppLanguage.kt
+++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/AppLanguage.kt
@@ -10,6 +10,7 @@ import nuvio.composeapp.generated.resources.lang_turkish
import nuvio.composeapp.generated.resources.lang_italian
import nuvio.composeapp.generated.resources.lang_greek
import nuvio.composeapp.generated.resources.lang_polish
+import nuvio.composeapp.generated.resources.lang_czech
import org.jetbrains.compose.resources.StringResource
enum class AppLanguage(
@@ -25,6 +26,7 @@ enum class AppLanguage(
ITALIAN("it", Res.string.lang_italian),
GREEK("el", Res.string.lang_greek),
POLISH("pl", Res.string.lang_polish),
+ CZECH("cs", Res.string.lang_czech),
;
companion object {
diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/ContinueWatchingSettingsPage.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/ContinueWatchingSettingsPage.kt
index c3d81354..f0483992 100644
--- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/ContinueWatchingSettingsPage.kt
+++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/ContinueWatchingSettingsPage.kt
@@ -5,18 +5,27 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.rounded.Check
import androidx.compose.material.icons.rounded.CheckCircle
+import androidx.compose.material3.BasicAlertDialog
+import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
@@ -25,6 +34,7 @@ import androidx.compose.ui.unit.dp
import com.nuvio.app.features.home.components.ContinueWatchingStylePreview
import com.nuvio.app.features.watchprogress.ContinueWatchingPreferencesRepository
import com.nuvio.app.features.watchprogress.ContinueWatchingSectionStyle
+import com.nuvio.app.features.watchprogress.ContinueWatchingSortMode
import nuvio.composeapp.generated.resources.Res
import nuvio.composeapp.generated.resources.settings_continue_watching_resume_prompt_description
import nuvio.composeapp.generated.resources.settings_continue_watching_resume_prompt_title
@@ -34,10 +44,16 @@ import nuvio.composeapp.generated.resources.settings_continue_watching_show_unai
import nuvio.composeapp.generated.resources.settings_continue_watching_show_unaired_next_up_title
import nuvio.composeapp.generated.resources.settings_continue_watching_section_card_style
import nuvio.composeapp.generated.resources.settings_continue_watching_section_on_launch
+import nuvio.composeapp.generated.resources.settings_continue_watching_section_sort_order
import nuvio.composeapp.generated.resources.settings_continue_watching_section_up_next_behavior
import nuvio.composeapp.generated.resources.settings_continue_watching_section_visibility
import nuvio.composeapp.generated.resources.settings_continue_watching_show_description
import nuvio.composeapp.generated.resources.settings_continue_watching_show_title
+import nuvio.composeapp.generated.resources.settings_continue_watching_sort_mode_default
+import nuvio.composeapp.generated.resources.settings_continue_watching_sort_mode_default_desc
+import nuvio.composeapp.generated.resources.settings_continue_watching_sort_mode_streaming
+import nuvio.composeapp.generated.resources.settings_continue_watching_sort_mode_streaming_desc
+import nuvio.composeapp.generated.resources.settings_continue_watching_sort_mode_title
import nuvio.composeapp.generated.resources.settings_continue_watching_style_poster
import nuvio.composeapp.generated.resources.settings_continue_watching_style_poster_description
import nuvio.composeapp.generated.resources.settings_continue_watching_style_wide
@@ -58,6 +74,7 @@ internal fun LazyListScope.continueWatchingSettingsContent(
showUnairedNextUp: Boolean,
blurNextUp: Boolean,
showResumePromptOnLaunch: Boolean,
+ sortMode: ContinueWatchingSortMode,
) {
item {
SettingsSection(
@@ -145,6 +162,39 @@ internal fun LazyListScope.continueWatchingSettingsContent(
}
}
}
+ item {
+ var showSortModeSheet by remember { mutableStateOf(false) }
+ SettingsSection(
+ title = stringResource(Res.string.settings_continue_watching_section_sort_order),
+ isTablet = isTablet,
+ ) {
+ SettingsGroup(isTablet = isTablet) {
+ val currentModeLabel = stringResource(
+ when (sortMode) {
+ ContinueWatchingSortMode.DEFAULT -> Res.string.settings_continue_watching_sort_mode_default
+ ContinueWatchingSortMode.STREAMING_STYLE -> Res.string.settings_continue_watching_sort_mode_streaming
+ }
+ )
+ SettingsNavigationRow(
+ title = stringResource(Res.string.settings_continue_watching_sort_mode_title),
+ description = currentModeLabel,
+ isTablet = isTablet,
+ onClick = { showSortModeSheet = true },
+ )
+ }
+ }
+
+ if (showSortModeSheet) {
+ ContinueWatchingSortModeDialog(
+ currentMode = sortMode,
+ onModeSelected = { mode ->
+ ContinueWatchingPreferencesRepository.setSortMode(mode)
+ showSortModeSheet = false
+ },
+ onDismiss = { showSortModeSheet = false },
+ )
+ }
+ }
}
@Composable
@@ -250,3 +300,101 @@ private val ContinueWatchingSectionStyle.descriptionRes: StringResource
ContinueWatchingSectionStyle.Wide -> Res.string.settings_continue_watching_style_wide_description
ContinueWatchingSectionStyle.Poster -> Res.string.settings_continue_watching_style_poster_description
}
+
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+private fun ContinueWatchingSortModeDialog(
+ currentMode: ContinueWatchingSortMode,
+ onModeSelected: (ContinueWatchingSortMode) -> Unit,
+ onDismiss: () -> Unit,
+) {
+ val options = listOf(
+ Triple(
+ ContinueWatchingSortMode.DEFAULT,
+ Res.string.settings_continue_watching_sort_mode_default,
+ Res.string.settings_continue_watching_sort_mode_default_desc,
+ ),
+ Triple(
+ ContinueWatchingSortMode.STREAMING_STYLE,
+ Res.string.settings_continue_watching_sort_mode_streaming,
+ Res.string.settings_continue_watching_sort_mode_streaming_desc,
+ ),
+ )
+
+ BasicAlertDialog(
+ onDismissRequest = onDismiss,
+ ) {
+ Surface(
+ modifier = Modifier.fillMaxWidth(),
+ shape = RoundedCornerShape(20.dp),
+ color = MaterialTheme.colorScheme.surface,
+ ) {
+ Column(
+ modifier = Modifier.padding(20.dp),
+ verticalArrangement = Arrangement.spacedBy(12.dp),
+ ) {
+ Text(
+ text = stringResource(Res.string.settings_continue_watching_sort_mode_title),
+ style = MaterialTheme.typography.titleLarge,
+ color = MaterialTheme.colorScheme.onSurface,
+ fontWeight = FontWeight.SemiBold,
+ )
+
+ Column(
+ modifier = Modifier.fillMaxWidth(),
+ verticalArrangement = Arrangement.spacedBy(8.dp),
+ ) {
+ options.forEach { (mode, titleRes, descriptionRes) ->
+ val isSelected = mode == currentMode
+ val containerColor = if (isSelected) {
+ MaterialTheme.colorScheme.primary.copy(alpha = 0.14f)
+ } else {
+ MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.35f)
+ }
+
+ Surface(
+ modifier = Modifier
+ .fillMaxWidth()
+ .clickable { onModeSelected(mode) },
+ shape = RoundedCornerShape(12.dp),
+ color = containerColor,
+ ) {
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(horizontal = 14.dp, vertical = 12.dp),
+ verticalAlignment = Alignment.CenterVertically,
+ ) {
+ Column(modifier = Modifier.weight(1f)) {
+ Text(
+ text = stringResource(titleRes),
+ style = MaterialTheme.typography.bodyLarge,
+ color = MaterialTheme.colorScheme.onSurface,
+ )
+ Spacer(modifier = Modifier.height(2.dp))
+ Text(
+ text = stringResource(descriptionRes),
+ style = MaterialTheme.typography.bodySmall,
+ color = MaterialTheme.colorScheme.onSurfaceVariant,
+ )
+ }
+ Box(
+ modifier = Modifier.size(24.dp),
+ contentAlignment = Alignment.Center,
+ ) {
+ if (isSelected) {
+ Icon(
+ imageVector = Icons.Rounded.Check,
+ contentDescription = null,
+ tint = MaterialTheme.colorScheme.primary,
+ )
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/SettingsFullScreenPages.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/SettingsFullScreenPages.kt
index 143ef517..cbb6bfa4 100644
--- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/SettingsFullScreenPages.kt
+++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/SettingsFullScreenPages.kt
@@ -135,6 +135,7 @@ fun ContinueWatchingSettingsScreen(
showUnairedNextUp = continueWatchingPreferencesUiState.showUnairedNextUp,
blurNextUp = continueWatchingPreferencesUiState.blurNextUp,
showResumePromptOnLaunch = continueWatchingPreferencesUiState.showResumePromptOnLaunch,
+ sortMode = continueWatchingPreferencesUiState.sortMode,
)
}
}
diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/SettingsScreen.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/SettingsScreen.kt
index 7d3b0e04..668a3c2e 100644
--- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/SettingsScreen.kt
+++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/SettingsScreen.kt
@@ -509,6 +509,7 @@ private fun MobileSettingsScreen(
showUnairedNextUp = continueWatchingPreferencesUiState.showUnairedNextUp,
blurNextUp = continueWatchingPreferencesUiState.blurNextUp,
showResumePromptOnLaunch = continueWatchingPreferencesUiState.showResumePromptOnLaunch,
+ sortMode = continueWatchingPreferencesUiState.sortMode,
)
SettingsPage.PosterCustomization -> posterCustomizationSettingsContent(
isTablet = false,
@@ -866,6 +867,7 @@ private fun TabletSettingsScreen(
showUnairedNextUp = continueWatchingPreferencesUiState.showUnairedNextUp,
blurNextUp = continueWatchingPreferencesUiState.blurNextUp,
showResumePromptOnLaunch = continueWatchingPreferencesUiState.showResumePromptOnLaunch,
+ sortMode = continueWatchingPreferencesUiState.sortMode,
)
SettingsPage.PosterCustomization -> posterCustomizationSettingsContent(
isTablet = true,
diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/trakt/TraktCommentsRepository.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/trakt/TraktCommentsRepository.kt
index 378b8ef3..a2bd8a03 100644
--- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/trakt/TraktCommentsRepository.kt
+++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/trakt/TraktCommentsRepository.kt
@@ -15,8 +15,7 @@ private const val COMMENTS_SORT = "likes"
private const val COMMENTS_LIMIT = 100
private const val COMMENTS_CACHE_TTL_MS = 10 * 60_000L
private val INLINE_SPOILER_REGEX = Regex(
- "\\[spoiler\\].*?\\[/spoiler\\]",
- setOf(RegexOption.IGNORE_CASE, RegexOption.DOT_MATCHES_ALL),
+ "(?is)\\[spoiler\\].*?\\[/spoiler\\]"
)
private val INLINE_SPOILER_TAG_REGEX = Regex("\\[/?spoiler\\]", RegexOption.IGNORE_CASE)
diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/watchprogress/ContinueWatchingPreferencesRepository.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/watchprogress/ContinueWatchingPreferencesRepository.kt
index 9845b680..93704067 100644
--- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/watchprogress/ContinueWatchingPreferencesRepository.kt
+++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/watchprogress/ContinueWatchingPreferencesRepository.kt
@@ -22,6 +22,8 @@ private data class StoredContinueWatchingPreferences(
val blurNextUp: Boolean = false,
val dismissedNextUpKeys: Set = emptySet(),
val showResumePromptOnLaunch: Boolean = true,
+ @SerialName("sort_mode")
+ val sortMode: ContinueWatchingSortMode = ContinueWatchingSortMode.DEFAULT,
)
object ContinueWatchingPreferencesRepository {
@@ -97,6 +99,7 @@ object ContinueWatchingPreferencesRepository {
blurNextUp = stored.blurNextUp,
dismissedNextUpKeys = stored.dismissedNextUpKeys,
showResumePromptOnLaunch = stored.showResumePromptOnLaunch,
+ sortMode = stored.sortMode,
)
} else {
ContinueWatchingPreferencesUiState()
@@ -155,6 +158,13 @@ object ContinueWatchingPreferencesRepository {
persist()
}
+ fun setSortMode(mode: ContinueWatchingSortMode) {
+ ensureLoaded()
+ if (_uiState.value.sortMode == mode) return
+ _uiState.value = _uiState.value.copy(sortMode = mode)
+ persist()
+ }
+
fun removeDismissedNextUpKeysForContent(contentId: String) {
ensureLoaded()
val normalizedContentId = contentId.trim()
@@ -178,6 +188,7 @@ object ContinueWatchingPreferencesRepository {
blurNextUp = _uiState.value.blurNextUp,
dismissedNextUpKeys = _uiState.value.dismissedNextUpKeys,
showResumePromptOnLaunch = _uiState.value.showResumePromptOnLaunch,
+ sortMode = _uiState.value.sortMode,
),
),
)
diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/watchprogress/WatchProgressModels.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/watchprogress/WatchProgressModels.kt
index 1c27213d..0485986b 100644
--- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/watchprogress/WatchProgressModels.kt
+++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/watchprogress/WatchProgressModels.kt
@@ -17,6 +17,12 @@ enum class ContinueWatchingSectionStyle {
Poster,
}
+@Serializable
+enum class ContinueWatchingSortMode {
+ DEFAULT,
+ STREAMING_STYLE,
+}
+
@Serializable
data class WatchProgressEntry(
val contentType: String,
@@ -175,6 +181,7 @@ data class ContinueWatchingPreferencesUiState(
val blurNextUp: Boolean = false,
val dismissedNextUpKeys: Set = emptySet(),
val showResumePromptOnLaunch: Boolean = true,
+ val sortMode: ContinueWatchingSortMode = ContinueWatchingSortMode.DEFAULT,
)
internal fun nextUpDismissKey(
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index ae480b9f..d260a9e5 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -51,6 +51,7 @@ compose-uiToolingPreview = { module = "org.jetbrains.compose.ui:ui-tooling-previ
coil-compose = { module = "io.coil-kt.coil3:coil-compose", version.ref = "coil" }
coil-gif = { module = "io.coil-kt.coil3:coil-gif", version.ref = "coil" }
coil-network-ktor3 = { module = "io.coil-kt.coil3:coil-network-ktor3", version.ref = "coil" }
+coil-svg = { module = "io.coil-kt.coil3:coil-svg", version.ref = "coil" }
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinx-serialization" }
ktor-client-android = { module = "io.ktor:ktor-client-android", version.ref = "ktor" }
kermit = { module = "co.touchlab:kermit", version.ref = "kermit" }