diff --git a/composeApp/src/androidFull/kotlin/com/nuvio/app/core/build/AppFeaturePolicy.android.kt b/composeApp/src/androidFull/kotlin/com/nuvio/app/core/build/AppFeaturePolicy.android.kt index 364def91..f4de81fc 100644 --- a/composeApp/src/androidFull/kotlin/com/nuvio/app/core/build/AppFeaturePolicy.android.kt +++ b/composeApp/src/androidFull/kotlin/com/nuvio/app/core/build/AppFeaturePolicy.android.kt @@ -4,7 +4,7 @@ actual object AppFeaturePolicy { actual val pluginsEnabled: Boolean = true actual val supportersContributorsPageEnabled: Boolean = true actual val accountDeletionEnabled: Boolean = false - actual val personalMediaAddonCopyEnabled: Boolean = false + actual val storeNarrativeEnabled: Boolean = false actual val p2pEnabled: Boolean = true actual val trailerPlaybackMode: TrailerPlaybackMode = TrailerPlaybackMode.IN_APP actual val heroTrailerPlaybackSupported: Boolean = true diff --git a/composeApp/src/androidPlaystore/kotlin/com/nuvio/app/core/build/AppFeaturePolicy.android.kt b/composeApp/src/androidPlaystore/kotlin/com/nuvio/app/core/build/AppFeaturePolicy.android.kt index f0ee56ff..3db44aa5 100644 --- a/composeApp/src/androidPlaystore/kotlin/com/nuvio/app/core/build/AppFeaturePolicy.android.kt +++ b/composeApp/src/androidPlaystore/kotlin/com/nuvio/app/core/build/AppFeaturePolicy.android.kt @@ -4,7 +4,7 @@ actual object AppFeaturePolicy { actual val pluginsEnabled: Boolean = false actual val supportersContributorsPageEnabled: Boolean = true actual val accountDeletionEnabled: Boolean = false - actual val personalMediaAddonCopyEnabled: Boolean = false + actual val storeNarrativeEnabled: Boolean = true actual val p2pEnabled: Boolean = true actual val trailerPlaybackMode: TrailerPlaybackMode = TrailerPlaybackMode.EXTERNAL actual val heroTrailerPlaybackSupported: Boolean = false diff --git a/composeApp/src/commonMain/composeResources/values-bg/strings.xml b/composeApp/src/commonMain/composeResources/values-bg/strings.xml index d02723c2..b14cd5ff 100644 --- a/composeApp/src/commonMain/composeResources/values-bg/strings.xml +++ b/composeApp/src/commonMain/composeResources/values-bg/strings.xml @@ -433,7 +433,9 @@ Изтегли последна версия Провери за актуализации Управлявай добавки и източници за discovery. + Управлявайте добавките и изберете какво да се показва в Nuvio. Управлявай изтеглените филми и епизоди. + Управлявайте запазеното на това устройство. Изтегляния ОБЩИ Управлявай наличните интеграции @@ -1845,11 +1847,13 @@ Грешка в торента: %1$s Превключи - Свържете собствен медиен сървър, за да разглеждате и възпроизвеждате от личната си библиотека. - Добавете URL на сървър по-горе, когато искате Nuvio да показва вашата лична библиотека. - Няма свързани лични библиотеки. - URL на сървър - Добави + Пренесете библиотеката си в Nuvio с добавките, които използвате. + Добавете добавка, за да започнете да изграждате библиотеката си. + Настройте Nuvio по свой начин. + URL на добавка + Добавяне на добавка + Все още няма нищо тук + Текущите ви добавки все още нямат какво да покажат тук. Сървър и поддръжка за този месец Покрито. Допълнителната подкрепа вече отива за разработка. След 100% допълнителната подкрепа отива за разработка. @@ -1861,7 +1865,7 @@ Още действия Неизвестна грешка в торента Език на устройството - Свържете лични медийни източници и управлявайте достъпа до собствената си библиотека. + Добавяйте и управлявайте добавките, които използвате с Nuvio. Изпращане на времеви маркери за интро и аутро Предайте откритите времеви маркери за интро и аутро към външния плейър за автоматично прескачане. Работи само в плейъри, които го поддържат; останалите плейъри го игнорират. Жестове с докосване diff --git a/composeApp/src/commonMain/composeResources/values-cs/strings.xml b/composeApp/src/commonMain/composeResources/values-cs/strings.xml index 40533419..039e9d5d 100644 --- a/composeApp/src/commonMain/composeResources/values-cs/strings.xml +++ b/composeApp/src/commonMain/composeResources/values-cs/strings.xml @@ -32,11 +32,13 @@ Nedostupné Konfigurovat doplněk Smazat doplněk - Připojte svůj vlastní mediální server a procházejte i přehrávejte ze své osobní knihovny. - Přidejte výše adresu URL serveru, pokud chcete, aby Nuvio zobrazovalo vaši soukromou knihovnu. - Nejsou připojeny žádné osobní knihovny. - URL serveru - Přidat + Přeneste svou knihovnu do Nuvia pomocí doplňků, které používáte. + Přidejte doplněk a začněte vytvářet svou knihovnu. + Přizpůsobte si Nuvio. + URL doplňku + Přidat doplněk + Zatím tu nic není + Vaše současné doplňky tu zatím nemají co zobrazit. Přidejte URL manifestu, abyste mohli do Nuvio začít načítat katalogy, metadata, streamy nebo titulky. Zatím nejsou nainstalovány žádné doplňky. Zadejte URL doplňku. @@ -442,7 +444,9 @@ Stáhnout nejnovější verzi Zkontrolovat aktualizace Správa doplňků a zdrojů objevování. + Spravujte doplňky a vyberte, co se má v Nuviu zobrazovat. Spravujte své stažené filmy a epizody. + Spravujte obsah uložený v tomto zařízení. Stažené položky OBECNÉ Spravovat dostupné integrace @@ -638,7 +642,7 @@ DOMŮ ZDROJE Instalovat, odstraňovat, obnovovat a třídit vaše zdroje obsahu. - Připojit osobní mediální zdroje a spravovat přístup k vlastní knihovně. + Přidávejte a spravujte doplňky, které používáte s Nuviem. Instalovat repozitáře pro JavaScriptové scarpování a testovat poskytovatele interně. Upravit rozvržení domovské obrazovky, viditelnost obsahu a chování plakátů. Nastavení pro obrazovku detailu a epizody. diff --git a/composeApp/src/commonMain/composeResources/values-de/strings.xml b/composeApp/src/commonMain/composeResources/values-de/strings.xml index 3afb1161..09a97502 100644 --- a/composeApp/src/commonMain/composeResources/values-de/strings.xml +++ b/composeApp/src/commonMain/composeResources/values-de/strings.xml @@ -27,6 +27,13 @@ Nicht verfügbar Addon konfigurieren Addon löschen + Bring deine Mediathek mit den Addons, die du nutzt, zu Nuvio. + Füge ein Addon hinzu, um deine Mediathek aufzubauen. + Richte Nuvio für dich ein. + Addon-URL + Addon hinzufügen + Hier gibt es noch nichts + Deine aktuellen Addons zeigen hier noch nichts an. Füge eine Manifest-URL hinzu, um Kataloge, Metadaten, Streams oder Untertitel in Nuvio zu laden. Noch keine Addons installiert. Gib eine Addon-URL ein. @@ -383,7 +390,9 @@ Suche nach neuen Versionen der App. Nach Updates suchen Verwalte Addons und Entdeckungsquellen. + Verwalte Addons und wähle aus, was in Nuvio angezeigt wird. Verwalte deine heruntergeladenen Filme und Episoden. + Verwalte, was du auf diesem Gerät gespeichert hast. Downloads ALLGEMEIN TMDB- und MDBList-Dienste verbinden. @@ -519,6 +528,7 @@ START QUELLEN Installiere, entferne, aktualisiere und sortiere deine Inhaltsquellen. + Füge die Addons hinzu, die du mit Nuvio nutzt, und verwalte sie. Installiere JavaScript-Scraper-Repositories und teste Anbieter intern. Lege fest, welche Kataloge auf der Startseite und in welcher Reihenfolge erscheinen. Detail-Abschnitte deaktivieren und alles unterhalb des Hero neu anordnen. diff --git a/composeApp/src/commonMain/composeResources/values-el/strings.xml b/composeApp/src/commonMain/composeResources/values-el/strings.xml index 4c2fd176..01c48e62 100644 --- a/composeApp/src/commonMain/composeResources/values-el/strings.xml +++ b/composeApp/src/commonMain/composeResources/values-el/strings.xml @@ -233,7 +233,9 @@ Ελέγξτε για νέες εκδόσεις της εφαρμογής. Έλεγχος για ενημερώσεις Διαχείριση πρόσθετων και πηγών ανακάλυψης. + Διαχειριστείτε τα πρόσθετα και επιλέξτε τι εμφανίζεται στο Nuvio. Διαχειριστείτε τις κατεβασμένες ταινίες και επεισόδιά σας. + Διαχειριστείτε όσα έχετε αποθηκεύσει σε αυτή τη συσκευή. Λήψεις ΓΕΝΙΚΑ Σύνδεση υπηρεσιών TMDB και MDBList. @@ -1061,11 +1063,13 @@ Αποθήκευση… Εναλλαγή Επικύρωση - Συνδέστε τον δικό σας διακομιστή μέσων για να περιηγηθείτε και να αναπαραγάγετε από τη δική σας προσωπική βιβλιοθήκη. - Προσθέστε μια διεύθυνση URL διακομιστή παραπάνω όταν θέλετε το Nuvio να εμφανίζει τη δική σας ιδιωτική βιβλιοθήκη. - Δεν υπάρχουν προσωπικές βιβλιοθήκες συνδεδεμένες. - Διεύθυνση URL διακομιστή - Προσθήκη + Φέρτε τη βιβλιοθήκη σας στο Nuvio με τα πρόσθετα που χρησιμοποιείτε. + Προσθέστε ένα πρόσθετο για να αρχίσετε να δημιουργείτε τη βιβλιοθήκη σας. + Κάντε το Nuvio δικό σας. + URL πρόσθετου + Προσθήκη πρόσθετου + Δεν υπάρχει τίποτα εδώ ακόμη + Τα πρόσθετα που χρησιμοποιείτε δεν έχουν ακόμη τίποτα να εμφανίσουν εδώ. Απενεργοποιημένο Το manifest είναι κενό "%1$s" Σύνδεση λογαριασμού @@ -1520,7 +1524,7 @@ Device Γλώσσα Liquid Glass Use the native iPhone tab bar on iOS 26 and later. - Connect personal media sources and manage access to your own Βιβλιοθήκη. + Προσθέστε και διαχειριστείτε τα πρόσθετα που χρησιμοποιείτε με το Nuvio. Blur next episode thumbnails in Συνέχεια Watching to avoid spoilers. Blur Unwatched in Συνέχεια Watching Ταξινόμηση ORDER diff --git a/composeApp/src/commonMain/composeResources/values-es/strings.xml b/composeApp/src/commonMain/composeResources/values-es/strings.xml index e591930a..02427ae4 100644 --- a/composeApp/src/commonMain/composeResources/values-es/strings.xml +++ b/composeApp/src/commonMain/composeResources/values-es/strings.xml @@ -32,11 +32,13 @@ No disponible Configurar complemento Eliminar complemento - Conecte su propio servidor multimedia para navegar y reproducir desde su biblioteca personal. - Agregue una URL de servidor arriba cuando desee que Nuvio muestre su biblioteca privada. - No hay bibliotecas personales conectadas. - URL del servidor - Agregar + Lleva tu biblioteca a Nuvio con los complementos que utilizas. + Agrega un complemento para empezar a crear tu biblioteca. + Haz tuyo Nuvio. + URL del complemento + Agregar complemento + Aún no hay nada aquí + Tus complementos actuales aún no tienen nada que mostrar aquí. Agrega una URL de manifiesto para empezar a cargar catálogos, metadatos, streams o subtítulos en Nuvio. Aún no hay complementos instalados. Introduce una URL de complemento. @@ -442,7 +444,9 @@ Buscar nuevas versiones de la app. Buscar actualizaciones Administra complementos y fuentes de descubrimiento. + Administra tus complementos y elige qué aparece en Nuvio. Administra tus películas y episodios descargados. + Administra lo que has guardado en este dispositivo. Descargas GENERAL Conecta los servicios TMDB y MDBList. @@ -638,7 +642,7 @@ INICIO FUENTES Instala, elimina, actualiza y ordena tus fuentes de contenido. - Conecte fuentes de medios personales y administre el acceso a su propia biblioteca. + Agrega y administra los complementos que utilizas con Nuvio. Instala repositorios de scrapers en JavaScript y prueba proveedores internamente. Controla qué catálogos aparecen en Inicio y en qué orden. Desactiva secciones de detalles y reordena todo debajo del Destacado. diff --git a/composeApp/src/commonMain/composeResources/values-fr/strings.xml b/composeApp/src/commonMain/composeResources/values-fr/strings.xml index ffb979e2..a6a53665 100644 --- a/composeApp/src/commonMain/composeResources/values-fr/strings.xml +++ b/composeApp/src/commonMain/composeResources/values-fr/strings.xml @@ -33,11 +33,13 @@ Indisponible Configurer l’addon Supprimer l’addon - Connectez votre propre serveur multimédia pour parcourir et lire depuis votre bibliothèque personnelle. - Ajoutez une URL de serveur ci-dessus pour que Nuvio affiche votre bibliothèque privée. - Aucune bibliothèque personnelle connectée. - URL du serveur - Ajouter + Retrouvez votre bibliothèque dans Nuvio avec les addons que vous utilisez. + Ajoutez un addon pour commencer à créer votre bibliothèque. + Personnalisez Nuvio. + URL de l’addon + Ajouter un addon + Rien à afficher pour le moment + Vos addons actuels n’ont encore rien à afficher ici. Ajoutez une URL de manifeste pour commencer à charger des catalogues, métadonnées, streams ou sous-titres dans Nuvio. Aucun addon installé. Saisissez une URL d’addon. @@ -434,7 +436,9 @@ Rechercher de nouvelles versions de l’application. Vérifier les mises à jour Gérez les addons et sources de découverte. + Gérez vos addons et choisissez ce qui apparaît dans Nuvio. Gérez vos films et épisodes téléchargés. + Gérez ce que vous avez enregistré sur cet appareil. Téléchargements GÉNÉRAL Connectez les services TMDB et MDBList. @@ -648,7 +652,7 @@ ACCUEIL SOURCES Installez, supprimez, mettez à jour et ordonnez vos sources de contenu. - Connectez des sources multimédias personnelles et gérez l’accès à votre propre bibliothèque. + Ajoutez et gérez les addons que vous utilisez avec Nuvio. Installez des dépôts de scrapers JavaScript et testez des fournisseurs en interne. Contrôle quels catalogues apparaissent à l’accueil et dans quel ordre. Désactivez des sections de détails et réorganisez tout sous le Hero. diff --git a/composeApp/src/commonMain/composeResources/values-hu/strings.xml b/composeApp/src/commonMain/composeResources/values-hu/strings.xml index 6979d2fa..3dda499a 100644 --- a/composeApp/src/commonMain/composeResources/values-hu/strings.xml +++ b/composeApp/src/commonMain/composeResources/values-hu/strings.xml @@ -401,7 +401,9 @@ A legújabb verzió letöltése Frissítések keresése Kiegészítők és tartalomforrások kezelése + Kezeld a kiegészítőket, és válaszd ki, mi jelenjen meg a Nuvióban. A letöltött filmek és epizódok kezelése + Kezeld az eszközre mentett tartalmakat. Letöltések ÁLTALÁNOS Elérhető integrációk kezelése @@ -1339,11 +1341,13 @@ GB Váltás Kikapcsolva - Csatlakoztasd saját médiaszerveredet a személyes könyvtárad böngészéséhez és lejátszásához. - Adj meg egy szerver URL-t fent, ha szeretnéd, hogy a Nuvio megjelenítse a privát könyvtáradat. - Nincsenek csatlakoztatott személyes könyvtárak. - Szerver URL - Hozzáadás + Hozd el a könyvtáradat a Nuvióba a használt kiegészítőkkel. + Adj hozzá egy kiegészítőt a könyvtárad felépítéséhez. + Szabd személyre a Nuviót. + Kiegészítő URL-je + Kiegészítő hozzáadása + Itt még nincs semmi + A jelenlegi kiegészítőid még nem jelenítenek meg itt semmit. 28,12 18,35 2020-01-01 @@ -1397,7 +1401,7 @@ Érték megjelenítése Kártya TV-stílusú fekvő kártya - Személyes médiaforrások csatlakoztatása és a saját könyvtáradhoz való hozzáférés kezelése. + Add hozzá és kezeld a Nuvióval használt kiegészítőket. Felhő könyvtár A csatlakoztatott fiókjaidban már meglévő fájlok böngészése és lejátszása. Feloldás ezzel diff --git a/composeApp/src/commonMain/composeResources/values-id/strings.xml b/composeApp/src/commonMain/composeResources/values-id/strings.xml index 35a923d9..0c79d268 100644 --- a/composeApp/src/commonMain/composeResources/values-id/strings.xml +++ b/composeApp/src/commonMain/composeResources/values-id/strings.xml @@ -31,6 +31,13 @@ Tidak Tersedia Konfigurasi addon Hapus addon + Bawa pustaka Anda ke Nuvio dengan addon yang Anda gunakan. + Tambahkan addon untuk mulai membangun pustaka Anda. + Jadikan Nuvio milik Anda. + URL Addon + Tambah Addon + Belum ada apa pun di sini + Addon yang Anda gunakan belum memiliki apa pun untuk ditampilkan di sini. Tambahkan URL manifes untuk mulai memuat katalog, metadata, streaming, atau subtitle ke Nuvio. Belum ada addon yang terpasang. Masukkan URL addon. @@ -412,7 +419,9 @@ Unduh versi terbaru Periksa pembaruan Kelola addon dan sumber penemuan. + Kelola addon dan pilih apa yang tampil di Nuvio. Kelola film dan episode yang telah diunduh. + Kelola yang Anda simpan di perangkat ini. Unduhan UMUM Kelola integrasi yang tersedia @@ -597,6 +606,7 @@ BERANDA SUMBER Pasang, hapus, perbarui, dan urutkan sumber konten Anda. + Tambahkan dan kelola addon yang Anda gunakan dengan Nuvio. Pasang repositori scraper JavaScript dan uji penyedia secara internal. Sesuaikan tata letak beranda, visibilitas konten, dan poster Pengaturan untuk layar detail dan episode. diff --git a/composeApp/src/commonMain/composeResources/values-in/strings.xml b/composeApp/src/commonMain/composeResources/values-in/strings.xml index e442e971..b56c75ce 100644 --- a/composeApp/src/commonMain/composeResources/values-in/strings.xml +++ b/composeApp/src/commonMain/composeResources/values-in/strings.xml @@ -31,6 +31,13 @@ Tidak Tersedia Konfigurasi addon Hapus addon + Bawa pustaka Anda ke Nuvio dengan addon yang Anda gunakan. + Tambahkan addon untuk mulai membangun pustaka Anda. + Jadikan Nuvio milik Anda. + URL Addon + Tambah Addon + Belum ada apa pun di sini + Addon yang Anda gunakan belum memiliki apa pun untuk ditampilkan di sini. Tambahkan URL manifes untuk mulai memuat katalog, metadata, streaming, atau subtitle ke Nuvio. Belum ada addon yang terpasang. Masukkan URL addon. @@ -412,7 +419,9 @@ Unduh versi terbaru Periksa pembaruan Kelola addon dan sumber penemuan. + Kelola addon dan pilih apa yang tampil di Nuvio. Kelola film dan episode yang telah diunduh. + Kelola yang Anda simpan di perangkat ini. Unduhan UMUM Kelola integrasi yang tersedia @@ -597,6 +606,7 @@ BERANDA SUMBER Pasang, hapus, perbarui, dan urutkan sumber konten Anda. + Tambahkan dan kelola addon yang Anda gunakan dengan Nuvio. Pasang repositori scraper JavaScript dan uji penyedia secara internal. Sesuaikan tata letak beranda, visibilitas konten, dan poster Pengaturan untuk layar detail dan episode. diff --git a/composeApp/src/commonMain/composeResources/values-it/strings.xml b/composeApp/src/commonMain/composeResources/values-it/strings.xml index 035580c2..a4cfd0c4 100644 --- a/composeApp/src/commonMain/composeResources/values-it/strings.xml +++ b/composeApp/src/commonMain/composeResources/values-it/strings.xml @@ -27,6 +27,13 @@ Non Disponibile Configura addon Cancella addon + Porta la tua libreria su Nuvio con gli addon che usi. + Aggiungi un addon per iniziare a creare la tua libreria. + Fai tuo Nuvio. + URL addon + Aggiungi addon + Non c’è ancora niente qui + Gli addon che usi non hanno ancora nulla da mostrare qui. Aggiungi un manifest URL per iniziare a caricare cataloghi , metadata, flussi o sottotitoli dentro Nuvio. Nessun addon installato ancora. Inserisci l'URL dell'addon. @@ -245,7 +252,9 @@ Controlla se ci sono nuove versioni dell'app. Verifica aggiornamenti Gestisci gli addon e le sorgenti di scoperta. + Gestisci gli addon e scegli cosa mostrare in Nuvio. Gestisci i film e gli episodi scaricati. + Gestisci ciò che hai salvato su questo dispositivo. Download GENERALI Collega i servizi TMDB e MDBList. @@ -382,6 +391,7 @@ HOME SORGENTI Installa, rimuovi, aggiorna e ordina le tue sorgenti di contenuto. + Aggiungi e gestisci gli addon che usi con Nuvio. Installa repository di scraper JavaScript e testa i provider internamente. Controlla quali cataloghi appaiono in Home e in quale ordine. Disabilita le sezioni dei dettagli e riordina tutto ciò che sta sotto l'elemento Hero. diff --git a/composeApp/src/commonMain/composeResources/values-ja/strings.xml b/composeApp/src/commonMain/composeResources/values-ja/strings.xml index 45688cd9..885e1c81 100644 --- a/composeApp/src/commonMain/composeResources/values-ja/strings.xml +++ b/composeApp/src/commonMain/composeResources/values-ja/strings.xml @@ -32,11 +32,13 @@ 利用不可 アドオンを設定 アドオンを削除 - 独自のメディアサーバーを接続して、個人ライブラリを参照・再生します。 - Nuvioに個人ライブラリを表示させたい場合は、上にサーバーURLを追加してください。 - 接続された個人ライブラリはありません。 - サーバーURL - 追加 + いつものアドオンで、ライブラリをNuvioにまとめましょう。 + アドオンを追加して、ライブラリを作り始めましょう。 + Nuvioを自分好みに。 + アドオンURL + アドオンを追加 + まだ何もありません + 現在のアドオンには、ここに表示できるものがまだありません。 マニフェストURLを追加して、カタログ・メタデータ・ストリーム・字幕をNuvioに読み込みましょう。 アドオンがありません アドオンのURLを入力してください。 @@ -442,7 +444,9 @@ 最新リリースをダウンロード アップデートを確認 アドオンと探索ソースを管理 + アドオンを管理して、Nuvioに表示する内容を選べます。 ダウンロードした映画とエピソードを管理 + このデバイスに保存した項目を管理します。 ダウンロード 一般 利用可能な連携を管理 @@ -638,7 +642,7 @@ ホーム ソース コンテンツソースのインストール・削除・更新・並べ替え - 個人メディアソースを接続し、自分専用ライブラリへのアクセスを管理します。 + Nuvioで使うアドオンを追加・管理します。 JavaScriptスクレイパーリポジトリのインストールと内部テスト ホームレイアウト・コンテンツ表示・ポスターの動作を調整 詳細画面とエピソード画面の設定 diff --git a/composeApp/src/commonMain/composeResources/values-nb/strings.xml b/composeApp/src/commonMain/composeResources/values-nb/strings.xml index ad7cea8c..9957c3db 100644 --- a/composeApp/src/commonMain/composeResources/values-nb/strings.xml +++ b/composeApp/src/commonMain/composeResources/values-nb/strings.xml @@ -29,6 +29,13 @@ Utilgjengelig Konfigurer tillegg Slett tillegg + Ta med biblioteket ditt til Nuvio med tilleggene du bruker. + Legg til et tillegg for å begynne å bygge biblioteket ditt. + Gjør Nuvio til ditt. + URL til tillegg + Legg til tillegg + Det er ingenting her ennå + Tilleggene du bruker, har ingenting å vise her ennå. Legg til en manifest-URL for å starte lasting av kataloger, metadata, strømmer eller undertekster i Nuvio. Ingen tillegg installert ennå. Skriv inn en tilleggs-URL. @@ -400,7 +407,9 @@ Last ned nyeste versjon Se etter oppdateringer Administrer tillegg og oppdagelseskilder. + Administrer tillegg og velg hva som vises i Nuvio. Administrer nedlastede filmer og episoder. + Administrer det du har lagret på denne enheten. Nedlastinger GENERELT Administrer tilgjengelige integrasjoner @@ -581,6 +590,7 @@ HJEM KILDER Installer, fjern, oppdater og sorter innholdskilder. + Legg til og administrer tilleggene du bruker med Nuvio. Installer JavaScript-scraper-repositories og test providere internt. Juster hjemmeoppsett, synlighet og plakat-oppførsel. Innstillinger for detalj- og episodeskjermer. diff --git a/composeApp/src/commonMain/composeResources/values-nl/strings.xml b/composeApp/src/commonMain/composeResources/values-nl/strings.xml index 59504af9..c2fdc267 100644 --- a/composeApp/src/commonMain/composeResources/values-nl/strings.xml +++ b/composeApp/src/commonMain/composeResources/values-nl/strings.xml @@ -32,11 +32,13 @@ Niet beschikbaar Addon configureren Addon verwijderen - Verbind je eigen mediaserver om je persoonlijke bibliotheek te bekijken en af te spelen. - Voeg hierboven een server-URL toe als je wilt dat Nuvio je privébibliotheek toont. - Geen persoonlijke bibliotheken verbonden. - Server-URL - Toevoegen + Breng je bibliotheek naar Nuvio met de add-ons die je gebruikt. + Voeg een add-on toe om je bibliotheek op te bouwen. + Maak Nuvio helemaal van jou. + Add-on-URL + Add-on toevoegen + Hier is nog niets + Je huidige add-ons hebben hier nog niets om te tonen. Voeg een manifest-URL toe om catalogi, metadata, streams of ondertitels in Nuvio te laden. Nog geen addons geïnstalleerd. Voer een addon-URL in. @@ -442,7 +444,9 @@ Download de laatste versie Controleren op updates Beheer addons en ontdekkingsbronnen. + Beheer add-ons en kies wat er in Nuvio verschijnt. Beheer je gedownloade films en afleveringen. + Beheer wat je op dit apparaat hebt opgeslagen. Downloads ALGEMEEN Beheer beschikbare integraties @@ -656,7 +660,7 @@ HOME BRONNEN Installeer, verwijder, vernieuw en sorteer je contentbronnen. - Verbind persoonlijke mediabronnen en beheer toegang tot je eigen bibliotheek. + Voeg de add-ons toe die je met Nuvio gebruikt en beheer ze. Installeer JavaScript-scraperrepository's en test providers intern. Pas startschermindeling, zichtbaarheid van inhoud en postergedrag aan Instellingen voor de detail- en afleveringsschermen. diff --git a/composeApp/src/commonMain/composeResources/values-pl/strings.xml b/composeApp/src/commonMain/composeResources/values-pl/strings.xml index c500dfcf..473e6a21 100644 --- a/composeApp/src/commonMain/composeResources/values-pl/strings.xml +++ b/composeApp/src/commonMain/composeResources/values-pl/strings.xml @@ -31,6 +31,13 @@ Niedostępny Konfiguruj dodatek Usuń dodatek + Przenieś swoją bibliotekę do Nuvio za pomocą używanych dodatków. + Dodaj dodatek, aby zacząć tworzyć swoją bibliotekę. + Dostosuj Nuvio do siebie. + URL dodatku + Dodaj dodatek + Na razie nic tu nie ma + Używane dodatki nie mają jeszcze nic do wyświetlenia. Dodaj URL manifestu, aby zacząć ładować katalogi, metadane, strumienie lub napisy do Nuvio. Brak zainstalowanych dodatków. Wprowadź URL dodatku. @@ -412,7 +419,9 @@ Sprawdź dostępność nowych wersji aplikacji. Sprawdź aktualizacje Zarządzaj dodatkami i źródłami odkrywania. + Zarządzaj dodatkami i wybierz, co ma być widoczne w Nuvio. Zarządzaj pobranymi filmami i odcinkami. + Zarządzaj zawartością zapisaną na tym urządzeniu. Pobrane OGÓLNE Połącz usługi TMDB i MDBList. @@ -597,6 +606,7 @@ EKRAN GŁÓWNY ŹRÓDŁA Instaluj, usuwaj, odświeżaj i sortuj źródła treści. + Dodawaj używane w Nuvio dodatki i zarządzaj nimi. Instaluj repozytoria scraperów JavaScript i testuj dostawców wewnętrznie. Kontroluj, które katalogi pojawiają się na ekranie głównym i w jakiej kolejności. Wyłącz sekcje szczegółów i zmień kolejność wszystkiego poniżej Hero. diff --git a/composeApp/src/commonMain/composeResources/values-pt-rBR/strings.xml b/composeApp/src/commonMain/composeResources/values-pt-rBR/strings.xml index 49fb2960..97b5fde2 100644 --- a/composeApp/src/commonMain/composeResources/values-pt-rBR/strings.xml +++ b/composeApp/src/commonMain/composeResources/values-pt-rBR/strings.xml @@ -30,6 +30,13 @@ Indisponível Configurar addon Excluir addon + Leve sua biblioteca para o Nuvio com os addons que você usa. + Adicione um addon para começar a montar sua biblioteca. + Deixe o Nuvio do seu jeito. + URL do addon + Adicionar addon + Ainda não há nada aqui + Os addons que você usa ainda não têm nada para mostrar aqui. Adicione uma URL de manifesto para começar a carregar catálogos, metadados, streams ou legendas no Nuvio. Nenhum addon instalado ainda. Insira uma URL de addon. @@ -401,7 +408,9 @@ Baixar a versão mais recente Verificar atualizações Gerenciar addons e fontes de descoberta. + Gerencie addons e escolha o que aparece no Nuvio. Gerencie seus filmes e episódios baixados. + Gerencie o que você salvou neste dispositivo. Downloads GERAL Gerenciar integrações disponíveis @@ -582,6 +591,7 @@ PÁGINA INICIAL FONTES Instale, remova, atualize e ordene suas fontes de conteúdo. + Adicione e gerencie os addons que você usa com o Nuvio. Instale repositórios de scraper JavaScript e teste provedores internamente. Ajuste layout da página inicial, visibilidade de conteúdo e comportamento de pôsteres Configurações para as telas de detalhes e episódios. diff --git a/composeApp/src/commonMain/composeResources/values-pt/strings.xml b/composeApp/src/commonMain/composeResources/values-pt/strings.xml index 51a4a704..e6719a5f 100644 --- a/composeApp/src/commonMain/composeResources/values-pt/strings.xml +++ b/composeApp/src/commonMain/composeResources/values-pt/strings.xml @@ -31,6 +31,13 @@ Indisponível Configurar addon Eliminar addon + Leva a tua biblioteca para o Nuvio com os addons que usas. + Adiciona um addon para começares a criar a tua biblioteca. + Deixa o Nuvio à tua maneira. + URL do addon + Adicionar addon + Ainda não há nada aqui + Os addons que usas ainda não têm nada para mostrar aqui. Adiciona um URL de manifesto para começares a carregar catálogos, metadados, streams ou legendas no Nuvio. Ainda não tens addons instalados. Introduz o URL de um addon. @@ -432,7 +439,9 @@ Transferir a versão mais recente Procurar atualizações Gere addons e fontes de descoberta. + Gere os addons e escolhe o que aparece no Nuvio. Gere os teus filmes e episódios transferidos. + Gere o que guardaste neste dispositivo. Transferências GERAL Gere as integrações disponíveis @@ -627,6 +636,7 @@ PÁGINA INICIAL FONTES Instala, remove, atualiza e ordena as tuas fontes de conteúdo. + Adiciona e gere os addons que usas com o Nuvio. Instala repositórios de scrapers JavaScript e testa fornecedores internamente. Ajusta o esquema da página inicial, a visibilidade do conteúdo e o comportamento dos cartazes. Definições para as páginas de detalhes e de episódios. diff --git a/composeApp/src/commonMain/composeResources/values-ro/strings.xml b/composeApp/src/commonMain/composeResources/values-ro/strings.xml index a2633569..f002ef42 100644 --- a/composeApp/src/commonMain/composeResources/values-ro/strings.xml +++ b/composeApp/src/commonMain/composeResources/values-ro/strings.xml @@ -32,11 +32,13 @@ Indisponibil Configurează extensia Șterge extensia - Conectează-ți propriul server media pentru a naviga și a reda din biblioteca personală. - Adaugă un URL de server mai sus când vrei ca Nuvio să îți afișeze biblioteca privată. - Nicio bibliotecă personală conectată. - URL Server - Adaugă + Folosește extensiile preferate pentru a-ți aduce biblioteca în Nuvio. + Adaugă o extensie pentru a începe să-ți construiești biblioteca. + Personalizează Nuvio. + URL extensie + Adaugă extensie + Nu este nimic aici încă + Extensiile pe care le folosești nu au încă nimic de afișat aici. Adaugă un URL de manifest pentru a începe încărcarea de cataloage, metadate, fluxuri sau subtitrări în Nuvio. Nu există extensii instalate încă. Introdu un URL pentru extensie. @@ -442,7 +444,9 @@ Descarcă cea mai recentă versiune Caută actualizări Gestionează extensiile și sursele de descoperire. + Gestionează extensiile și alege ce apare în Nuvio. Gestionează filmele și episoadele descărcate. + Gestionează ce ai salvat pe acest dispozitiv. Descărcări GENERAL Gestionează integrările disponibile @@ -656,7 +660,7 @@ ECRAN PRINCIPAL SURSE Instalează, elimină, reîmprospătează și sortează sursele de conținut. - Conectează surse media personale și gestionează accesul la propria bibliotecă. + Adaugă și gestionează extensiile pe care le folosești cu Nuvio. Instalează depozite de scraper JavaScript și testează furnizorii intern. Ajustează aspectul ecranului principal, vizibilitatea conținutului și comportamentul posterului Setări pentru ecranele de detalii și de episoade. @@ -1932,4 +1936,4 @@ %d titlu %d titluri - \ No newline at end of file + diff --git a/composeApp/src/commonMain/composeResources/values-sk/strings.xml b/composeApp/src/commonMain/composeResources/values-sk/strings.xml index f554f531..9f1c7563 100644 --- a/composeApp/src/commonMain/composeResources/values-sk/strings.xml +++ b/composeApp/src/commonMain/composeResources/values-sk/strings.xml @@ -434,7 +434,9 @@ Stiahnuť najnovšie vydanie Skontrolovať aktualizácie Spravovať doplnky a zdroje objavovania. + Spravujte doplnky a vyberte, čo sa má zobrazovať v Nuviu. Spravovať stiahnuté filmy a epizódy. + Spravujte obsah uložený v tomto zariadení. Stiahnuté VŠEOBECNÉ Spravovať dostupné integrácie @@ -1898,15 +1900,17 @@ Chyba torrentu: %1$s Prepnúť - Pripojte vlastný mediálny server na prehliadanie a prehrávanie z vašej osobnej knižnice. - Pridajte URL servera vyššie, ak chcete, aby Nuvio zobrazovalo vašu súkromnú knižnicu. - Nie sú pripojené žiadne osobné knižnice. - URL servera - Pridať + Preneste svoju knižnicu do Nuvia pomocou doplnkov, ktoré používate. + Pridajte doplnok a začnite si vytvárať knižnicu. + Prispôsobte si Nuvio. + URL doplnku + Pridať doplnok + Zatiaľ tu nič nie je + Doplnky, ktoré používate, tu zatiaľ nemajú čo zobraziť. Registráciou súhlasím s Podmienkami Jazyk zariadenia - Pripojte osobné mediálne zdroje a spravujte prístup k vlastnej knižnici. + Pridávajte a spravujte doplnky, ktoré používate s Nuviom. Odosielať časové značky intra a outra Odovzdať vyriešené časové značky intra a outra externému prehrávaču na automatické preskakovanie. Funguje iba v prehrávačoch, ktoré to podporujú; ostatné prehrávače to ignorujú. Pôvodný jazyk diff --git a/composeApp/src/commonMain/composeResources/values-tr/strings.xml b/composeApp/src/commonMain/composeResources/values-tr/strings.xml index 1340bde9..7a6fb839 100644 --- a/composeApp/src/commonMain/composeResources/values-tr/strings.xml +++ b/composeApp/src/commonMain/composeResources/values-tr/strings.xml @@ -31,6 +31,13 @@ Kullanılamıyor Eklentiyi ayarla Eklentiyi sil + Kullandığın eklentilerle kitaplığını Nuvio'ya taşı. + Kitaplığını oluşturmaya başlamak için bir eklenti ekle. + Nuvio'yu kendine göre ayarla. + Eklenti URL'si + Eklenti ekle + Burada henüz bir şey yok + Kullandığın eklentilerin burada gösterecek bir şeyi yok. Nuvio'ya katalog, meta veri, yayın veya altyazı yüklemeye başlamak için bir manifest URL'si ekle. Henüz eklenti kurulmamış. Bir eklenti URL'si gir. @@ -402,7 +409,9 @@ Uygulamanın yeni sürümü var mı kontrol et. Güncellemeleri kontrol et Eklentileri ve keşif kaynaklarını yönet. + Eklentileri yönet ve Nuvio’da nelerin görüneceğini seç. İndirdiğin film ve bölümleri yönet. + Bu cihaza kaydettiklerini yönet. İndirilenler GENEL TMDB ve MDBList servislerini bağla. @@ -587,6 +596,7 @@ ANA SAYFA KAYNAKLAR İçerik kaynaklarını kur, kaldır, yenile ve sırala. + Nuvio ile kullandığın eklentileri ekle ve yönet. JavaScript scraper depoları kur ve sağlayıcıları içeriden test et. Ana sayfada hangi katalogların hangi sırayla görüneceğini kontrol et. Detay bölümlerini kapat ve öne çıkanların altındaki her şeyi yeniden sırala. diff --git a/composeApp/src/commonMain/composeResources/values-vi/strings.xml b/composeApp/src/commonMain/composeResources/values-vi/strings.xml index 946da7e6..5e80d643 100644 --- a/composeApp/src/commonMain/composeResources/values-vi/strings.xml +++ b/composeApp/src/commonMain/composeResources/values-vi/strings.xml @@ -32,11 +32,13 @@ Không khả dụng Cấu hình addon Xóa addon - Kết nối máy chủ nội dung của bạn để duyệt và phát thư viện cá nhân. - Thêm URL máy chủ ở trên để Nuvio hiển thị thư viện riêng của bạn. - Chưa kết nối thư viện cá nhân. - URL máy chủ - Thêm + Đưa thư viện của bạn vào Nuvio với các addon bạn sử dụng. + Thêm một addon để bắt đầu xây dựng thư viện của bạn. + Tùy chỉnh Nuvio theo cách của bạn. + URL addon + Thêm addon + Chưa có nội dung nào ở đây + Các addon bạn đang dùng chưa có nội dung để hiển thị ở đây. Thêm URL manifest để tải danh mục, thông tin, nguồn phát hoặc phụ đề vào Nuvio. Chưa cài addon nào. Nhập URL addon. @@ -442,7 +444,9 @@ Tải phiên bản mới nhất. Kiểm tra cập nhật Quản lý addon và các nguồn khám phá nội dung. + Quản lý addon và chọn nội dung hiển thị trong Nuvio. Quản lý phim và tập đã tải xuống. + Quản lý nội dung bạn đã lưu trên thiết bị này. Tải xuống CHUNG Quản lý các dịch vụ tích hợp. @@ -641,7 +645,7 @@ TRANG CHỦ NGUỒN Cài đặt, xóa, làm mới và sắp xếp các nguồn nội dung. - Kết nối nguồn nội dung cá nhân và quản lý thư viện riêng của bạn. + Thêm và quản lý các addon bạn sử dụng với Nuvio. Cài đặt kho Plugin JavaScript và thử nghiệm các dịch vụ nội bộ. Điều chỉnh bố cục Trang chủ, khả năng hiển thị nội dung và cách hiển thị poster. Thiết lập cho trang chi tiết và danh sách tập. @@ -1924,4 +1928,4 @@ Đang khởi động Engine P2P… Không thể khởi động torrent: %1$s Lỗi torrent: %1$s - \ No newline at end of file + diff --git a/composeApp/src/commonMain/composeResources/values/strings.xml b/composeApp/src/commonMain/composeResources/values/strings.xml index e06f8af6..d81ca03d 100644 --- a/composeApp/src/commonMain/composeResources/values/strings.xml +++ b/composeApp/src/commonMain/composeResources/values/strings.xml @@ -32,11 +32,13 @@ Unavailable Configure addon Delete addon - Connect your own media server to browse and play from your personal library. - Add a server URL above when you want Nuvio to show your private library. - No personal libraries connected. - Server URL - Add + Bring your library into Nuvio with the addons you use. + Add an addon to start building your library. + Make Nuvio yours. + Addon URL + Add Addon + Nothing here yet + Your current addons don’t have anything to show here. Add a manifest URL to start loading catalogs, metadata, streams or subtitles into Nuvio. No addons installed yet. Enter an addon URL. @@ -442,7 +444,9 @@ Download latest release Check for updates Manage addons and discovery sources. + Manage addons and choose what appears in Nuvio. Manage your downloaded movies and episodes. + Manage what you’ve saved on this device. Downloads GENERAL Manage available integrations @@ -687,7 +691,7 @@ HOME SOURCES Install, remove, refresh, and sort your content sources. - Connect personal media sources and manage access to your own library. + Add and manage the addons you use with Nuvio. Install JavaScript scraper repositories and test providers internally. Adjust home layout, content visibility, and poster behavior Settings for the detail and episode screens. diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/core/build/AppFeaturePolicy.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/core/build/AppFeaturePolicy.kt index ec7ed177..95584b5a 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/core/build/AppFeaturePolicy.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/core/build/AppFeaturePolicy.kt @@ -9,7 +9,7 @@ expect object AppFeaturePolicy { val pluginsEnabled: Boolean val supportersContributorsPageEnabled: Boolean val accountDeletionEnabled: Boolean - val personalMediaAddonCopyEnabled: Boolean + val storeNarrativeEnabled: Boolean val p2pEnabled: Boolean val trailerPlaybackMode: TrailerPlaybackMode val heroTrailerPlaybackSupported: Boolean diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/core/ui/EmptyState.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/core/ui/EmptyState.kt new file mode 100644 index 00000000..7cce6612 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/core/ui/EmptyState.kt @@ -0,0 +1,83 @@ +package com.nuvio.app.core.ui + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +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.material.icons.Icons +import androidx.compose.material.icons.rounded.SearchOff +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp + +@Composable +fun NuvioEmptyState( + title: String, + message: String? = null, + modifier: Modifier = Modifier, + icon: ImageVector = Icons.Rounded.SearchOff, + iconPainter: Painter? = null, + actionLabel: String? = null, + onActionClick: (() -> Unit)? = null, +) { + Column( + modifier = modifier + .fillMaxWidth() + .padding(32.dp), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(8.dp, Alignment.CenterVertically), + ) { + if (iconPainter != null) { + Icon( + painter = iconPainter, + contentDescription = null, + modifier = Modifier.size(48.dp), + tint = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.5f), + ) + } else { + Icon( + imageVector = icon, + contentDescription = null, + modifier = Modifier.size(48.dp), + tint = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.5f), + ) + } + Spacer(modifier = Modifier.height(8.dp)) + Text( + text = title, + style = MaterialTheme.typography.bodyLarge.copy( + fontSize = 16.sp, + fontWeight = FontWeight.SemiBold, + ), + color = MaterialTheme.colorScheme.onSurfaceVariant, + textAlign = TextAlign.Center, + ) + if (!message.isNullOrBlank()) { + Text( + text = message, + style = MaterialTheme.typography.bodySmall.copy(fontSize = 14.sp), + color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.7f), + textAlign = TextAlign.Center, + ) + } + if (actionLabel != null && onActionClick != null) { + Spacer(modifier = Modifier.height(8.dp)) + NuvioPrimaryButton( + text = actionLabel, + onClick = onActionClick, + ) + } + } +} diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/addons/AddonsScreen.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/addons/AddonsScreen.kt index 2d7db4a8..57ddd621 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/addons/AddonsScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/addons/AddonsScreen.kt @@ -9,6 +9,7 @@ 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.heightIn import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width @@ -47,6 +48,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.nuvio.app.core.build.AppFeaturePolicy import coil3.compose.AsyncImage import com.nuvio.app.core.ui.NuvioIconActionButton +import com.nuvio.app.core.ui.NuvioEmptyState import com.nuvio.app.core.ui.NuvioInfoBadge import com.nuvio.app.core.ui.NuvioInputField import com.nuvio.app.core.ui.NuvioPrimaryButton @@ -94,7 +96,7 @@ internal fun AddonsSettingsPageContent( var formMessage by rememberSaveable { mutableStateOf(null) } var installModalState by remember { mutableStateOf(null) } val enterAddonUrlMessage = stringResource(Res.string.addons_error_enter_url) - val usePersonalMediaCopy = AppFeaturePolicy.personalMediaAddonCopyEnabled + val useStoreNarrative = AppFeaturePolicy.storeNarrativeEnabled val overview = remember(uiState.addons) { uiState.addons.toOverview() } @@ -109,7 +111,7 @@ internal fun AddonsSettingsPageContent( AddAddonCard( addonUrl = addonUrl, formMessage = formMessage, - usePersonalMediaCopy = usePersonalMediaCopy, + useStoreNarrative = useStoreNarrative, onAddonUrlChange = { addonUrl = it formMessage = null @@ -141,7 +143,7 @@ internal fun AddonsSettingsPageContent( SectionHeader(stringResource(Res.string.addons_section_installed)) if (uiState.addons.isEmpty()) { - EmptyStateCard(usePersonalMediaCopy = usePersonalMediaCopy) + EmptyStateCard(useStoreNarrative = useStoreNarrative) } else { val lastIndex = uiState.addons.lastIndex uiState.addons.forEachIndexed { index, addon -> @@ -286,7 +288,7 @@ private fun VerticalSeparator() { private fun AddAddonCard( addonUrl: String, formMessage: String?, - usePersonalMediaCopy: Boolean, + useStoreNarrative: Boolean, onAddonUrlChange: (String) -> Unit, onAddClick: () -> Unit, ) { @@ -294,27 +296,15 @@ private fun AddAddonCard( NuvioInputField( value = addonUrl, onValueChange = onAddonUrlChange, - placeholder = stringResource( - if (usePersonalMediaCopy) { - Res.string.addons_appstore_input_placeholder - } else { - Res.string.addons_input_placeholder - }, - ), + placeholder = stringResource(Res.string.addons_input_placeholder), ) Spacer(modifier = Modifier.height(18.dp)) NuvioPrimaryButton( - text = stringResource( - if (usePersonalMediaCopy) { - Res.string.addons_appstore_install_button - } else { - Res.string.addons_install_button - }, - ), + text = stringResource(Res.string.addons_install_button), enabled = addonUrl.isNotBlank(), onClick = onAddClick, ) - if (usePersonalMediaCopy) { + if (useStoreNarrative) { Spacer(modifier = Modifier.height(14.dp)) Text( text = stringResource(Res.string.addons_appstore_add_description), @@ -355,33 +345,26 @@ private sealed interface AddonInstallModalState { @Composable private fun EmptyStateCard( - usePersonalMediaCopy: Boolean, + useStoreNarrative: Boolean, ) { - NuvioSurfaceCard { - Text( - text = stringResource( - if (usePersonalMediaCopy) { - Res.string.addons_appstore_empty_title - } else { - Res.string.addons_empty_title - }, - ), - style = MaterialTheme.typography.titleLarge, - color = MaterialTheme.colorScheme.onSurface, - ) - Spacer(modifier = Modifier.height(8.dp)) - Text( - text = stringResource( - if (usePersonalMediaCopy) { - Res.string.addons_appstore_empty_subtitle - } else { - Res.string.addons_empty_subtitle - }, - ), - style = MaterialTheme.typography.bodyLarge, - color = MaterialTheme.colorScheme.onSurfaceVariant, - ) - } + NuvioEmptyState( + modifier = Modifier.heightIn(min = 220.dp), + icon = Icons.Rounded.Extension, + title = stringResource( + if (useStoreNarrative) { + Res.string.addons_appstore_empty_title + } else { + Res.string.addons_empty_title + }, + ), + message = stringResource( + if (useStoreNarrative) { + Res.string.addons_appstore_empty_subtitle + } else { + Res.string.addons_empty_subtitle + }, + ), + ) } @Composable diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/catalog/CatalogScreen.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/catalog/CatalogScreen.kt index c11312d5..362fe6d8 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/catalog/CatalogScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/catalog/CatalogScreen.kt @@ -23,6 +23,7 @@ import androidx.compose.foundation.lazy.grid.items import androidx.compose.foundation.lazy.grid.rememberLazyGridState import androidx.compose.foundation.shape.RoundedCornerShape import com.nuvio.app.core.ui.NuvioLoadingIndicator +import com.nuvio.app.core.ui.NuvioEmptyState import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -162,6 +163,7 @@ fun CatalogScreen( .background(MaterialTheme.colorScheme.background), ) { val columns = remember(maxWidth) { catalogGridColumnsForWidth(maxWidth) } + val viewportHeight = maxHeight Box(modifier = Modifier.fillMaxSize()) { LazyVerticalGrid( @@ -184,6 +186,9 @@ fun CatalogScreen( } else if (uiState.items.isEmpty()) { item(span = { GridItemSpan(maxLineSpan) }) { CatalogEmptyState( + modifier = Modifier.height( + (viewportHeight - 120.dp).coerceAtLeast(280.dp), + ), errorMessage = uiState.errorMessage, networkCondition = networkStatusUiState.condition, onRetry = { @@ -361,6 +366,7 @@ private fun CatalogEmptyState( errorMessage: String?, networkCondition: NetworkCondition, onRetry: (() -> Unit)? = null, + modifier: Modifier = Modifier, ) { if (networkCondition == NetworkCondition.NoInternet || networkCondition == NetworkCondition.ServersUnreachable) { NuvioNetworkOfflineCard( @@ -370,24 +376,11 @@ private fun CatalogEmptyState( return } - Column( - modifier = Modifier - .fillMaxWidth() - .padding(vertical = 48.dp), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.spacedBy(10.dp), - ) { - Text( - text = stringResource(Res.string.catalog_empty_title), - style = MaterialTheme.typography.titleLarge, - color = MaterialTheme.colorScheme.onBackground, - ) - Text( - text = errorMessage ?: stringResource(Res.string.catalog_empty_message), - style = MaterialTheme.typography.bodyMedium, - color = MaterialTheme.colorScheme.onSurfaceVariant, - ) - } + NuvioEmptyState( + modifier = modifier, + title = stringResource(Res.string.catalog_empty_title), + message = errorMessage ?: stringResource(Res.string.catalog_empty_message), + ) } @Composable diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/downloads/DownloadsScreen.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/downloads/DownloadsScreen.kt index ef6a1eb2..d96fae0b 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/downloads/DownloadsScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/downloads/DownloadsScreen.kt @@ -2,7 +2,6 @@ package com.nuvio.app.features.downloads import androidx.compose.foundation.clickable 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 @@ -14,7 +13,7 @@ import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.foundation.lazy.items import androidx.compose.material.icons.Icons import androidx.compose.material.icons.rounded.Delete -import androidx.compose.material.icons.rounded.Folder +import androidx.compose.material.icons.rounded.Download import androidx.compose.material.icons.rounded.Pause import androidx.compose.material.icons.rounded.PlayArrow import androidx.compose.material.icons.rounded.Refresh @@ -38,8 +37,8 @@ import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.nuvio.app.core.i18n.localizedByteUnit import com.nuvio.app.core.ui.NuvioScreen +import com.nuvio.app.core.ui.NuvioEmptyState import com.nuvio.app.core.ui.NuvioScreenHeader -import com.nuvio.app.core.ui.NuvioToastController import nuvio.composeapp.generated.resources.* import org.jetbrains.compose.resources.stringResource @@ -57,8 +56,6 @@ fun DownloadsScreen( }.collectAsStateWithLifecycle() var selectedShowId by rememberSaveable(initialShowId) { mutableStateOf(initialShowId) } - val openDownloadsDirectoryFailedText = stringResource(Res.string.downloads_open_directory_failed) - val completedEpisodes = remember(uiState.items) { uiState.completedItems .filter { it.isEpisode } @@ -86,20 +83,6 @@ fun DownloadsScreen( onBack() } }, - actions = { - IconButton( - onClick = { - if (!DownloadsPlatformDownloader.openDownloadsDirectory()) { - NuvioToastController.show(openDownloadsDirectoryFailedText) - } - }, - ) { - Icon( - imageVector = Icons.Rounded.Folder, - contentDescription = stringResource(Res.string.downloads_open_directory), - ) - } - }, ) } @@ -228,18 +211,11 @@ private fun LazyListScope.downloadsRootContent( if (uiState.items.isEmpty()) { item { - Box( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 20.dp, vertical = 40.dp), - contentAlignment = Alignment.Center, - ) { - Text( - text = stringResource(Res.string.downloads_empty_title), - style = MaterialTheme.typography.titleMedium, - color = MaterialTheme.colorScheme.onSurfaceVariant, - ) - } + NuvioEmptyState( + modifier = Modifier.fillParentMaxHeight(), + icon = Icons.Rounded.Download, + title = stringResource(Res.string.downloads_empty_title), + ) } } } @@ -264,18 +240,11 @@ private fun LazyListScope.downloadsShowContent( if (seasons.isEmpty()) { item { - Box( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 20.dp, vertical = 40.dp), - contentAlignment = Alignment.Center, - ) { - Text( - text = stringResource(Res.string.downloads_empty_episodes), - style = MaterialTheme.typography.titleMedium, - color = MaterialTheme.colorScheme.onSurfaceVariant, - ) - } + NuvioEmptyState( + modifier = Modifier.fillParentMaxHeight(), + icon = Icons.Rounded.Download, + title = stringResource(Res.string.downloads_empty_episodes), + ) } return } 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 0cb70075..d2642216 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 @@ -15,6 +15,7 @@ import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.nuvio.app.core.auth.AuthRepository import com.nuvio.app.core.auth.AuthState +import com.nuvio.app.core.build.AppFeaturePolicy import com.nuvio.app.core.network.NetworkCondition import com.nuvio.app.core.network.NetworkStatusRepository import com.nuvio.app.core.ui.LocalNuvioBottomNavigationOverlayPadding @@ -36,7 +37,6 @@ import com.nuvio.app.features.details.seriesPrimaryAction import com.nuvio.app.features.home.components.HomeCatalogRowSection import com.nuvio.app.features.home.components.HomeContinueWatchingSection import com.nuvio.app.features.home.components.HomeEmptyStateCard -import com.nuvio.app.features.home.components.HomeHeroReservedSpace import com.nuvio.app.features.home.components.HomeHeroSection import com.nuvio.app.features.home.components.HomeSkeletonHero import com.nuvio.app.features.home.components.HomeSkeletonRow @@ -107,7 +107,6 @@ fun HomeScreen( onFirstCatalogRendered: (() -> Unit)? = null, ) { LaunchedEffect(Unit) { - AddonRepository.initialize() CollectionRepository.initialize() ContinueWatchingPreferencesRepository.ensureLoaded() WatchedRepository.ensureLoaded() @@ -118,7 +117,10 @@ fun HomeScreen( } } - val addonsUiState by AddonRepository.uiState.collectAsStateWithLifecycle() + val addonsUiState by remember { + AddonRepository.initialize() + AddonRepository.uiState + }.collectAsStateWithLifecycle() val homeUiState by HomeRepository.uiState.collectAsStateWithLifecycle() val homeSettingsUiState by remember { HomeCatalogSettingsRepository.snapshot() @@ -440,7 +442,6 @@ fun HomeScreen( } LaunchedEffect(catalogRefreshKey) { - if (catalogRefreshKey.isEmpty()) return@LaunchedEffect HomeCatalogSettingsRepository.syncCatalogs(enabledAddons) HomeRepository.refresh(enabledAddons) } @@ -655,11 +656,15 @@ fun HomeScreen( } val hasActiveAddons = enabledAddons.any { it.manifest != null } - val showHeroSlot = homeSettingsUiState.heroEnabled + val hasCurrentHeroSource = enabledAddons.any { it.manifest != null || it.isRefreshing } || + collections.any { it.folders.isNotEmpty() } val isResolvingHeroSources = enabledAddons.any { it.isRefreshing } || homeUiState.isLoading - val showHeroSkeleton = showHeroSlot && + val showHeroSkeleton = homeSettingsUiState.heroEnabled && + enabledAddons.isNotEmpty() && homeUiState.heroItems.isEmpty() && isResolvingHeroSources + val showHeroSlot = homeSettingsUiState.heroEnabled && hasCurrentHeroSource && + (homeUiState.heroItems.isNotEmpty() || showHeroSkeleton) var firstCatalogReported by remember { mutableStateOf(false) } LaunchedEffect(homeUiState.sections.firstOrNull()?.key, onFirstCatalogRendered) { @@ -749,14 +754,14 @@ fun HomeScreen( ) { if (showHeroSlot) { item { - when { - showHeroSkeleton -> HomeSkeletonHero( + if (showHeroSkeleton) { + HomeSkeletonHero( modifier = Modifier, viewportHeight = maxHeight, mobileBelowSectionHeightHint = mobileHeroBelowSectionHeightHint, ) - - homeUiState.heroItems.isNotEmpty() -> HomeHeroSection( + } else { + HomeHeroSection( items = homeUiState.heroItems, modifier = Modifier, viewportHeight = maxHeight, @@ -764,12 +769,6 @@ fun HomeScreen( listState = homeListState, onItemClick = onPosterClick, ) - - else -> HomeHeroReservedSpace( - modifier = Modifier, - viewportHeight = maxHeight, - mobileBelowSectionHeightHint = mobileHeroBelowSectionHeightHint, - ) } } } @@ -792,10 +791,31 @@ fun HomeScreen( } } item { + val emptyStateModifier = if ( + continueWatchingPreferences.isVisible && continueWatchingItems.isNotEmpty() + ) { + Modifier.padding(horizontal = 16.dp) + } else { + Modifier + .fillParentMaxHeight() + .padding(horizontal = 16.dp) + } HomeEmptyStateCard( - modifier = Modifier.padding(horizontal = 16.dp), - title = stringResource(Res.string.compose_search_empty_no_active_addons_title), - message = stringResource(Res.string.home_empty_no_active_addons_message), + modifier = emptyStateModifier, + title = stringResource( + if (AppFeaturePolicy.storeNarrativeEnabled) { + Res.string.addons_empty_title + } else { + Res.string.compose_search_empty_no_active_addons_title + }, + ), + message = stringResource( + if (AppFeaturePolicy.storeNarrativeEnabled) { + Res.string.addons_appstore_empty_subtitle + } else { + Res.string.home_empty_no_active_addons_message + }, + ), ) } } @@ -839,10 +859,22 @@ fun HomeScreen( ) } else { HomeEmptyStateCard( - modifier = Modifier.padding(horizontal = 16.dp), - title = stringResource(Res.string.home_empty_no_rows_title), - message = homeUiState.errorMessage - ?: stringResource(Res.string.home_empty_no_rows_message), + modifier = Modifier + .fillParentMaxHeight() + .padding(horizontal = 16.dp), + title = stringResource( + if (AppFeaturePolicy.storeNarrativeEnabled) { + Res.string.store_empty_unavailable_title + } else { + Res.string.home_empty_no_rows_title + }, + ), + message = if (AppFeaturePolicy.storeNarrativeEnabled) { + stringResource(Res.string.store_empty_unavailable_message) + } else { + homeUiState.errorMessage + ?: stringResource(Res.string.home_empty_no_rows_message) + }, ) } } diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/components/HomeStateCards.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/components/HomeStateCards.kt index ad8db153..262a9eef 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/components/HomeStateCards.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/components/HomeStateCards.kt @@ -1,41 +1,25 @@ package com.nuvio.app.features.home.components -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.height -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.unit.dp -import com.nuvio.app.core.ui.NuvioPrimaryButton -import com.nuvio.app.core.ui.NuvioSurfaceCard +import androidx.compose.ui.graphics.painter.Painter +import com.nuvio.app.core.ui.NuvioEmptyState @Composable fun HomeEmptyStateCard( title: String, message: String, modifier: Modifier = Modifier, + iconPainter: Painter? = null, actionLabel: String? = null, onActionClick: (() -> Unit)? = null, ) { - NuvioSurfaceCard(modifier = modifier) { - Text( - text = title, - style = MaterialTheme.typography.titleLarge, - color = MaterialTheme.colorScheme.onSurface, - ) - Spacer(modifier = Modifier.height(8.dp)) - Text( - text = message, - style = MaterialTheme.typography.bodyLarge, - color = MaterialTheme.colorScheme.onSurfaceVariant, - ) - if (actionLabel != null && onActionClick != null) { - Spacer(modifier = Modifier.height(16.dp)) - NuvioPrimaryButton( - text = actionLabel, - onClick = onActionClick, - ) - } - } + NuvioEmptyState( + modifier = modifier, + title = title, + message = message, + iconPainter = iconPainter, + actionLabel = actionLabel, + onActionClick = onActionClick, + ) } diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/library/LibraryScreen.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/library/LibraryScreen.kt index 9e29c577..4f06bff8 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/library/LibraryScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/library/LibraryScreen.kt @@ -84,6 +84,7 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.launch import nuvio.composeapp.generated.resources.* +import org.jetbrains.compose.resources.painterResource import org.jetbrains.compose.resources.stringResource @Composable @@ -268,7 +269,10 @@ fun LibraryScreen( ) } else { HomeEmptyStateCard( - modifier = Modifier.padding(horizontal = 16.dp), + modifier = Modifier + .fillParentMaxHeight(0.55f) + .padding(horizontal = 16.dp), + iconPainter = painterResource(Res.drawable.sidebar_library), title = if (isTraktSource) { stringResource(Res.string.library_trakt_load_failed) } else { @@ -292,7 +296,10 @@ fun LibraryScreen( ) } else { HomeEmptyStateCard( - modifier = Modifier.padding(horizontal = 16.dp), + modifier = Modifier + .fillParentMaxHeight(0.55f) + .padding(horizontal = 16.dp), + iconPainter = painterResource(Res.drawable.sidebar_library), title = if (isTraktSource) { stringResource(Res.string.library_trakt_empty_title) } else { @@ -345,7 +352,10 @@ private fun LazyListScope.cloudLibraryContent( !uiState.isEnabled -> { item { HomeEmptyStateCard( - modifier = Modifier.padding(horizontal = 16.dp), + modifier = Modifier + .fillParentMaxHeight(0.55f) + .padding(horizontal = 16.dp), + iconPainter = painterResource(Res.drawable.sidebar_library), title = stringResource(Res.string.cloud_library_disabled_title), message = stringResource(Res.string.cloud_library_disabled_message), actionLabel = stringResource(Res.string.cloud_library_disabled_action), @@ -357,7 +367,10 @@ private fun LazyListScope.cloudLibraryContent( !uiState.hasConnectedProvider -> { item { HomeEmptyStateCard( - modifier = Modifier.padding(horizontal = 16.dp), + modifier = Modifier + .fillParentMaxHeight(0.55f) + .padding(horizontal = 16.dp), + iconPainter = painterResource(Res.drawable.sidebar_library), title = stringResource(Res.string.cloud_library_connect_title), message = stringResource(Res.string.cloud_library_connect_message), actionLabel = stringResource(Res.string.cloud_library_connect_action), @@ -407,6 +420,7 @@ private fun LazyListScope.cloudLibraryContent( item(key = "cloud-error-${providerState.providerId}") { HomeEmptyStateCard( modifier = Modifier.padding(horizontal = 16.dp), + iconPainter = painterResource(Res.drawable.sidebar_library), title = stringResource(Res.string.cloud_library_load_failed, providerState.providerName), message = providerState.errorMessage.orEmpty(), actionLabel = stringResource(Res.string.action_retry), @@ -420,7 +434,10 @@ private fun LazyListScope.cloudLibraryContent( } else if (filteredItems.isEmpty()) { item { HomeEmptyStateCard( - modifier = Modifier.padding(horizontal = 16.dp), + modifier = Modifier + .fillParentMaxHeight(0.5f) + .padding(horizontal = 16.dp), + iconPainter = painterResource(Res.drawable.sidebar_library), title = stringResource(Res.string.cloud_library_empty_title), message = stringResource(Res.string.cloud_library_empty_message), actionLabel = stringResource(Res.string.action_retry), diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/search/SearchDiscoverContent.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/search/SearchDiscoverContent.kt index ed58b7f2..d3221b88 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/search/SearchDiscoverContent.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/search/SearchDiscoverContent.kt @@ -31,6 +31,7 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import coil3.compose.AsyncImage +import com.nuvio.app.core.build.AppFeaturePolicy import com.nuvio.app.core.network.NetworkCondition import com.nuvio.app.core.format.formatReleaseDateForDisplay import com.nuvio.app.core.ui.NuvioDropdownChip @@ -94,7 +95,9 @@ internal fun LazyListScope.discoverContent( items(2) { DiscoverSkeletonRow( columns = columns, - modifier = Modifier.padding(horizontal = 16.dp), + modifier = Modifier + .fillParentMaxHeight(0.72f) + .padding(horizontal = 16.dp), ) } } @@ -353,13 +356,37 @@ private fun DiscoverEmptyStateCard( when (reason) { DiscoverEmptyStateReason.NoActiveAddons -> { - title = stringResource(Res.string.compose_search_empty_no_active_addons_title) - message = stringResource(Res.string.discover_empty_no_active_addons_message) + title = stringResource( + if (AppFeaturePolicy.storeNarrativeEnabled) { + Res.string.addons_empty_title + } else { + Res.string.compose_search_empty_no_active_addons_title + }, + ) + message = stringResource( + if (AppFeaturePolicy.storeNarrativeEnabled) { + Res.string.addons_appstore_empty_subtitle + } else { + Res.string.discover_empty_no_active_addons_message + }, + ) } DiscoverEmptyStateReason.NoDiscoverCatalogs -> { - title = stringResource(Res.string.discover_empty_no_catalogs_title) - message = stringResource(Res.string.discover_empty_no_catalogs_message) + title = stringResource( + if (AppFeaturePolicy.storeNarrativeEnabled) { + Res.string.store_empty_unavailable_title + } else { + Res.string.discover_empty_no_catalogs_title + }, + ) + message = stringResource( + if (AppFeaturePolicy.storeNarrativeEnabled) { + Res.string.store_empty_unavailable_message + } else { + Res.string.discover_empty_no_catalogs_message + }, + ) } DiscoverEmptyStateReason.RequestFailed -> { diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/search/SearchScreen.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/search/SearchScreen.kt index 4520befe..0448e368 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/search/SearchScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/search/SearchScreen.kt @@ -40,6 +40,7 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.nuvio.app.core.build.AppFeaturePolicy import com.nuvio.app.core.network.NetworkCondition import com.nuvio.app.core.network.NetworkStatusRepository import com.nuvio.app.core.ui.NuvioInputField @@ -64,6 +65,8 @@ import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.map import nuvio.composeapp.generated.resources.Res +import nuvio.composeapp.generated.resources.addons_appstore_empty_subtitle +import nuvio.composeapp.generated.resources.addons_empty_title import nuvio.composeapp.generated.resources.compose_nav_search import nuvio.composeapp.generated.resources.compose_search_clear import nuvio.composeapp.generated.resources.compose_search_discover_title @@ -78,6 +81,8 @@ import nuvio.composeapp.generated.resources.compose_search_empty_no_search_catal import nuvio.composeapp.generated.resources.compose_search_placeholder import nuvio.composeapp.generated.resources.compose_search_recent_searches import nuvio.composeapp.generated.resources.compose_search_remove_recent_search +import nuvio.composeapp.generated.resources.store_empty_unavailable_message +import nuvio.composeapp.generated.resources.store_empty_unavailable_title import org.jetbrains.compose.resources.stringResource @Composable @@ -317,7 +322,9 @@ fun SearchScreen( isWaitingForSearch -> { items(2) { HomeSkeletonRow( - modifier = Modifier.padding(horizontal = homeSectionPadding), + modifier = Modifier + .fillParentMaxHeight() + .padding(horizontal = homeSectionPadding), showHeaderAccent = !homeCatalogSettingsUiState.hideCatalogUnderline, ) } @@ -413,13 +420,37 @@ private fun SearchEmptyStateCard( when (reason) { SearchEmptyStateReason.NoActiveAddons -> { - title = stringResource(Res.string.compose_search_empty_no_active_addons_title) - message = stringResource(Res.string.compose_search_empty_no_active_addons_message) + title = stringResource( + if (AppFeaturePolicy.storeNarrativeEnabled) { + Res.string.addons_empty_title + } else { + Res.string.compose_search_empty_no_active_addons_title + }, + ) + message = stringResource( + if (AppFeaturePolicy.storeNarrativeEnabled) { + Res.string.addons_appstore_empty_subtitle + } else { + Res.string.compose_search_empty_no_active_addons_message + }, + ) } SearchEmptyStateReason.NoSearchCatalogs -> { - title = stringResource(Res.string.compose_search_empty_no_search_catalogs_title) - message = stringResource(Res.string.compose_search_empty_no_search_catalogs_message) + title = stringResource( + if (AppFeaturePolicy.storeNarrativeEnabled) { + Res.string.store_empty_unavailable_title + } else { + Res.string.compose_search_empty_no_search_catalogs_title + }, + ) + message = stringResource( + if (AppFeaturePolicy.storeNarrativeEnabled) { + Res.string.store_empty_unavailable_message + } else { + Res.string.compose_search_empty_no_search_catalogs_message + }, + ) } SearchEmptyStateReason.RequestFailed -> { diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/ContentDiscoverySettingsPage.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/ContentDiscoverySettingsPage.kt index e4d92387..51188e97 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/ContentDiscoverySettingsPage.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/ContentDiscoverySettingsPage.kt @@ -19,14 +19,20 @@ internal fun LazyListScope.contentDiscoveryContent( ) { item { SettingsSection( - title = stringResource(Res.string.settings_content_discovery_section_sources), + title = stringResource( + if (AppFeaturePolicy.storeNarrativeEnabled) { + Res.string.compose_settings_page_addons + } else { + Res.string.settings_content_discovery_section_sources + }, + ), isTablet = isTablet, ) { SettingsGroup(isTablet = isTablet) { SettingsNavigationRow( title = stringResource(Res.string.compose_settings_page_addons), description = stringResource( - if (AppFeaturePolicy.personalMediaAddonCopyEnabled) { + if (AppFeaturePolicy.storeNarrativeEnabled) { Res.string.settings_content_discovery_addons_description_appstore } else { Res.string.settings_content_discovery_addons_description diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/HomescreenSettingsPage.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/HomescreenSettingsPage.kt index 254d49e1..43ce1519 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/HomescreenSettingsPage.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/HomescreenSettingsPage.kt @@ -31,6 +31,7 @@ import androidx.compose.ui.hapticfeedback.HapticFeedbackType import androidx.compose.ui.platform.LocalHapticFeedback import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp +import com.nuvio.app.core.build.AppFeaturePolicy import com.nuvio.app.core.ui.NuvioActionLabel import com.nuvio.app.core.ui.NuvioToastController import com.nuvio.app.features.home.HomeCatalogSettingsItem @@ -58,6 +59,8 @@ import nuvio.composeapp.generated.resources.settings_homescreen_show_hero import nuvio.composeapp.generated.resources.settings_homescreen_show_hero_description import nuvio.composeapp.generated.resources.settings_homescreen_summary import nuvio.composeapp.generated.resources.settings_homescreen_summary_hint +import nuvio.composeapp.generated.resources.store_empty_unavailable_message +import nuvio.composeapp.generated.resources.store_empty_unavailable_title import org.jetbrains.compose.resources.stringResource import sh.calvin.reorderable.ReorderableCollectionItemScope import sh.calvin.reorderable.ReorderableItem @@ -133,9 +136,23 @@ internal fun LazyListScope.homescreenSettingsContent( item { if (items.isEmpty()) { HomeEmptyStateCard( - modifier = Modifier.fillMaxWidth(), - title = stringResource(Res.string.settings_homescreen_empty_title), - message = stringResource(Res.string.settings_homescreen_empty_message), + modifier = Modifier + .fillMaxWidth() + .heightIn(min = 280.dp), + title = stringResource( + if (AppFeaturePolicy.storeNarrativeEnabled) { + Res.string.store_empty_unavailable_title + } else { + Res.string.settings_homescreen_empty_title + }, + ), + message = stringResource( + if (AppFeaturePolicy.storeNarrativeEnabled) { + Res.string.store_empty_unavailable_message + } else { + Res.string.settings_homescreen_empty_message + }, + ), ) } else { val catalogCount = items.count { !it.isCollection } diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/SettingsRootPage.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/SettingsRootPage.kt index 1ed8b5d8..fb460046 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/SettingsRootPage.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/SettingsRootPage.kt @@ -20,6 +20,7 @@ import androidx.compose.material3.Text import androidx.compose.ui.Modifier import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp +import com.nuvio.app.core.build.AppFeaturePolicy import com.nuvio.app.core.build.AppVersionConfig import nuvio.composeapp.generated.resources.Res import nuvio.composeapp.generated.resources.compose_about_made_with @@ -37,7 +38,9 @@ import nuvio.composeapp.generated.resources.compose_settings_root_appearance_des import nuvio.composeapp.generated.resources.compose_settings_root_check_updates_description import nuvio.composeapp.generated.resources.compose_settings_root_check_updates_title import nuvio.composeapp.generated.resources.compose_settings_root_content_discovery_description +import nuvio.composeapp.generated.resources.compose_settings_root_content_discovery_description_appstore import nuvio.composeapp.generated.resources.compose_settings_root_downloads_description +import nuvio.composeapp.generated.resources.compose_settings_root_downloads_description_appstore import nuvio.composeapp.generated.resources.compose_settings_root_downloads_title import nuvio.composeapp.generated.resources.compose_settings_root_general_section import nuvio.composeapp.generated.resources.compose_settings_root_integrations_description @@ -130,7 +133,13 @@ internal fun LazyListScope.settingsRootContent( SettingsGroupDivider(isTablet = isTablet) SettingsNavigationRow( title = stringResource(Res.string.compose_settings_page_content_discovery), - description = stringResource(Res.string.compose_settings_root_content_discovery_description), + description = stringResource( + if (AppFeaturePolicy.storeNarrativeEnabled) { + Res.string.compose_settings_root_content_discovery_description_appstore + } else { + Res.string.compose_settings_root_content_discovery_description + }, + ), icon = Icons.Rounded.Extension, isTablet = isTablet, onClick = onContentDiscoveryClick, @@ -138,7 +147,13 @@ internal fun LazyListScope.settingsRootContent( SettingsGroupDivider(isTablet = isTablet) SettingsNavigationRow( title = stringResource(Res.string.compose_settings_root_downloads_title), - description = stringResource(Res.string.compose_settings_root_downloads_description), + description = stringResource( + if (AppFeaturePolicy.storeNarrativeEnabled) { + Res.string.compose_settings_root_downloads_description_appstore + } else { + Res.string.compose_settings_root_downloads_description + }, + ), icon = Icons.Rounded.CloudDownload, isTablet = isTablet, onClick = onDownloadsClick, 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 6f42f03e..e21a8032 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 @@ -567,7 +567,7 @@ private fun MobileSettingsScreen( pluginsEnabled = AppFeaturePolicy.pluginsEnabled, supportersContributorsPageEnabled = AppFeaturePolicy.supportersContributorsPageEnabled, accountDeletionEnabled = AppFeaturePolicy.accountDeletionEnabled, - personalMediaAddonCopyEnabled = AppFeaturePolicy.personalMediaAddonCopyEnabled, + storeNarrativeEnabled = AppFeaturePolicy.storeNarrativeEnabled, liquidGlassNativeTabBarSupported = liquidGlassNativeTabBarSupported, switchProfileAvailable = onSwitchProfile != null, checkForUpdatesAvailable = onCheckForUpdatesClick != null, @@ -955,7 +955,7 @@ private fun TabletSettingsScreen( pluginsEnabled = AppFeaturePolicy.pluginsEnabled, supportersContributorsPageEnabled = AppFeaturePolicy.supportersContributorsPageEnabled, accountDeletionEnabled = AppFeaturePolicy.accountDeletionEnabled, - personalMediaAddonCopyEnabled = AppFeaturePolicy.personalMediaAddonCopyEnabled, + storeNarrativeEnabled = AppFeaturePolicy.storeNarrativeEnabled, liquidGlassNativeTabBarSupported = liquidGlassNativeTabBarSupported, switchProfileAvailable = onSwitchProfile != null, checkForUpdatesAvailable = onCheckForUpdatesClick != null, diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/SettingsSearch.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/SettingsSearch.kt index 419d5567..47206f87 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/SettingsSearch.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/SettingsSearch.kt @@ -8,6 +8,7 @@ import androidx.compose.animation.fadeIn import androidx.compose.animation.slideInVertically import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.material.icons.Icons @@ -43,6 +44,7 @@ import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import com.nuvio.app.core.ui.NuvioTokens +import com.nuvio.app.core.ui.NuvioEmptyState import com.nuvio.app.core.ui.nuvio import com.nuvio.app.isIos import nuvio.composeapp.generated.resources.* @@ -81,7 +83,7 @@ internal fun settingsSearchEntries( pluginsEnabled: Boolean, supportersContributorsPageEnabled: Boolean, accountDeletionEnabled: Boolean, - personalMediaAddonCopyEnabled: Boolean, + storeNarrativeEnabled: Boolean, liquidGlassNativeTabBarSupported: Boolean, switchProfileAvailable: Boolean, checkForUpdatesAvailable: Boolean, @@ -225,13 +227,25 @@ internal fun settingsSearchEntries( page = SettingsPage.ContentDiscovery, key = "content-discovery", title = contentDiscoveryPage, - description = stringResource(Res.string.compose_settings_root_content_discovery_description), + description = stringResource( + if (storeNarrativeEnabled) { + Res.string.compose_settings_root_content_discovery_description_appstore + } else { + Res.string.compose_settings_root_content_discovery_description + }, + ), icon = Icons.Rounded.Extension, ) add( key = "downloads", title = downloadsPage, - description = stringResource(Res.string.compose_settings_root_downloads_description), + description = stringResource( + if (storeNarrativeEnabled) { + Res.string.compose_settings_root_downloads_description_appstore + } else { + Res.string.compose_settings_root_downloads_description + }, + ), category = generalCategory, icon = Icons.Rounded.CloudDownload, target = SettingsSearchTarget.Downloads, @@ -448,7 +462,7 @@ internal fun settingsSearchEntries( key = "addons", title = addonsPage, description = stringResource( - if (personalMediaAddonCopyEnabled) { + if (storeNarrativeEnabled) { Res.string.settings_content_discovery_addons_description_appstore } else { Res.string.settings_content_discovery_addons_description @@ -1106,25 +1120,14 @@ private fun SettingsSearchField( @Composable private fun SettingsSearchEmptyState(isTablet: Boolean) { - val tokens = MaterialTheme.nuvio SettingsSection( title = stringResource(Res.string.settings_search_results_section), isTablet = isTablet, ) { - SettingsGroup(isTablet = isTablet) { - Column( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = if (isTablet) 20.dp else 16.dp, vertical = 18.dp), - ) { - Text( - text = stringResource(Res.string.settings_search_empty), - style = MaterialTheme.typography.bodyLarge, - color = tokens.colors.textPrimary, - fontWeight = FontWeight.Medium, - ) - } - } + NuvioEmptyState( + modifier = Modifier.heightIn(min = 280.dp), + title = stringResource(Res.string.settings_search_empty), + ) } } diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/streams/StreamsScreen.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/streams/StreamsScreen.kt index 0d3e1677..e94adf57 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/streams/StreamsScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/streams/StreamsScreen.kt @@ -41,7 +41,6 @@ import androidx.compose.material.icons.automirrored.rounded.OpenInNew import androidx.compose.material.icons.rounded.ContentCopy import androidx.compose.material.icons.rounded.Download import androidx.compose.material.icons.rounded.Refresh -import androidx.compose.material.icons.rounded.SearchOff import com.nuvio.app.core.ui.NuvioLoadingIndicator import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme @@ -75,6 +74,7 @@ import com.nuvio.app.core.build.AppFeaturePolicy import com.nuvio.app.core.ui.NuvioBackButton import com.nuvio.app.core.ui.NuvioBottomSheetActionRow import com.nuvio.app.core.ui.NuvioBottomSheetDivider +import com.nuvio.app.core.ui.NuvioEmptyState import com.nuvio.app.core.ui.NuvioModalBottomSheet import com.nuvio.app.core.ui.NuvioToastController import com.nuvio.app.core.ui.dismissNuvioBottomSheet @@ -892,7 +892,10 @@ internal fun StreamList( !hasAnyStreams && !uiState.isAnyLoading -> { item { - EmptyStateBlock(reason = uiState.emptyStateReason) + EmptyStateBlock( + reason = uiState.emptyStateReason, + modifier = Modifier.fillParentMaxHeight(), + ) } } @@ -1249,13 +1252,37 @@ private fun EmptyStateBlock( when (reason) { StreamsEmptyStateReason.NoAddonsInstalled -> { - title = stringResource(Res.string.compose_search_empty_no_active_addons_title) - message = stringResource(Res.string.streams_empty_no_addons_message) + title = stringResource( + if (AppFeaturePolicy.storeNarrativeEnabled) { + Res.string.addons_empty_title + } else { + Res.string.compose_search_empty_no_active_addons_title + }, + ) + message = stringResource( + if (AppFeaturePolicy.storeNarrativeEnabled) { + Res.string.addons_appstore_empty_subtitle + } else { + Res.string.streams_empty_no_addons_message + }, + ) } StreamsEmptyStateReason.NoCompatibleAddons -> { - title = stringResource(Res.string.streams_empty_no_stream_addon_title) - message = stringResource(Res.string.streams_empty_no_stream_addon_message) + title = stringResource( + if (AppFeaturePolicy.storeNarrativeEnabled) { + Res.string.store_empty_unavailable_title + } else { + Res.string.streams_empty_no_stream_addon_title + }, + ) + message = stringResource( + if (AppFeaturePolicy.storeNarrativeEnabled) { + Res.string.store_empty_unavailable_message + } else { + Res.string.streams_empty_no_stream_addon_message + }, + ) } StreamsEmptyStateReason.StreamFetchFailed -> { @@ -1269,35 +1296,11 @@ private fun EmptyStateBlock( } } - Column( - modifier = modifier - .fillMaxWidth() - .padding(32.dp), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.spacedBy(8.dp), - ) { - Icon( - imageVector = Icons.Rounded.SearchOff, - contentDescription = null, - modifier = Modifier.size(48.dp), - tint = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.5f), - ) - Spacer(modifier = Modifier.height(8.dp)) - Text( - text = title, - style = MaterialTheme.typography.bodyLarge.copy( - fontSize = 16.sp, - fontWeight = FontWeight.SemiBold, - ), - color = MaterialTheme.colorScheme.onSurfaceVariant, - ) - Text( - text = message, - style = MaterialTheme.typography.bodySmall.copy(fontSize = 14.sp), - color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.7f), - textAlign = TextAlign.Center, - ) - } + NuvioEmptyState( + modifier = modifier, + title = title, + message = message, + ) } @Composable diff --git a/composeApp/src/desktopMain/kotlin/com/nuvio/app/core/build/AppFeaturePolicy.desktop.kt b/composeApp/src/desktopMain/kotlin/com/nuvio/app/core/build/AppFeaturePolicy.desktop.kt index bc70435f..aa8fb74f 100644 --- a/composeApp/src/desktopMain/kotlin/com/nuvio/app/core/build/AppFeaturePolicy.desktop.kt +++ b/composeApp/src/desktopMain/kotlin/com/nuvio/app/core/build/AppFeaturePolicy.desktop.kt @@ -4,7 +4,7 @@ actual object AppFeaturePolicy { actual val pluginsEnabled: Boolean = false actual val supportersContributorsPageEnabled: Boolean = true actual val accountDeletionEnabled: Boolean = false - actual val personalMediaAddonCopyEnabled: Boolean = false + actual val storeNarrativeEnabled: Boolean = false actual val p2pEnabled: Boolean = false actual val trailerPlaybackMode: TrailerPlaybackMode = TrailerPlaybackMode.EXTERNAL actual val heroTrailerPlaybackSupported: Boolean = false diff --git a/composeApp/src/iosAppStore/kotlin/com/nuvio/app/core/build/AppFeaturePolicy.ios.kt b/composeApp/src/iosAppStore/kotlin/com/nuvio/app/core/build/AppFeaturePolicy.ios.kt index 6cc679aa..4267d324 100644 --- a/composeApp/src/iosAppStore/kotlin/com/nuvio/app/core/build/AppFeaturePolicy.ios.kt +++ b/composeApp/src/iosAppStore/kotlin/com/nuvio/app/core/build/AppFeaturePolicy.ios.kt @@ -4,7 +4,7 @@ actual object AppFeaturePolicy { actual val pluginsEnabled: Boolean = false actual val supportersContributorsPageEnabled: Boolean = false actual val accountDeletionEnabled: Boolean = true - actual val personalMediaAddonCopyEnabled: Boolean = true + actual val storeNarrativeEnabled: Boolean = true actual val p2pEnabled: Boolean = false actual val trailerPlaybackMode: TrailerPlaybackMode = TrailerPlaybackMode.EXTERNAL actual val heroTrailerPlaybackSupported: Boolean = false diff --git a/composeApp/src/iosFull/kotlin/com/nuvio/app/core/build/AppFeaturePolicy.ios.kt b/composeApp/src/iosFull/kotlin/com/nuvio/app/core/build/AppFeaturePolicy.ios.kt index b86fa9f4..b8f0d837 100644 --- a/composeApp/src/iosFull/kotlin/com/nuvio/app/core/build/AppFeaturePolicy.ios.kt +++ b/composeApp/src/iosFull/kotlin/com/nuvio/app/core/build/AppFeaturePolicy.ios.kt @@ -4,7 +4,7 @@ actual object AppFeaturePolicy { actual val pluginsEnabled: Boolean = true actual val supportersContributorsPageEnabled: Boolean = true actual val accountDeletionEnabled: Boolean = false - actual val personalMediaAddonCopyEnabled: Boolean = false + actual val storeNarrativeEnabled: Boolean = false actual val p2pEnabled: Boolean = false actual val trailerPlaybackMode: TrailerPlaybackMode = TrailerPlaybackMode.IN_APP actual val heroTrailerPlaybackSupported: Boolean = false diff --git a/iosApp/iosApp.xcodeproj/project.pbxproj b/iosApp/iosApp.xcodeproj/project.pbxproj index 2a2c1e59..b0fd8c3f 100644 --- a/iosApp/iosApp.xcodeproj/project.pbxproj +++ b/iosApp/iosApp.xcodeproj/project.pbxproj @@ -246,7 +246,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "if [ \"YES\" = \"$OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED\" ]; then\n echo \"Skipping Gradle build task invocation due to OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED environment variable set to \\\"YES\\\"\"\n exit 0\nfi\nif [ -z \"$JAVA_HOME\" ] && [ -x \"/opt/homebrew/opt/openjdk@17/libexec/openjdk.jdk/Contents/Home/bin/java\" ]; then\n export JAVA_HOME=\"/opt/homebrew/opt/openjdk@17/libexec/openjdk.jdk/Contents/Home\"\nfi\nif [ -n \"$JAVA_HOME\" ]; then\n export PATH=\"$JAVA_HOME/bin:/opt/homebrew/bin:$PATH\"\nelse\n export PATH=\"/opt/homebrew/bin:$PATH\"\nfi\nif [ -z \"$GRADLE_OPTS\" ]; then\n export GRADLE_OPTS=\"-Xmx12288M -Dfile.encoding=UTF-8 -XX:MaxMetaspaceSize=2048m\"\nfi\nif [ -z \"$KOTLIN_DAEMON_JVMARGS\" ]; then\n export KOTLIN_DAEMON_JVMARGS=\"-Xmx8192M\"\nfi\ncd \"$SRCROOT/..\"\n./gradlew :composeApp:embedAndSignAppleFrameworkForXcode\n"; + shellScript = "if [ \"YES\" = \"$OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED\" ]; then\n echo \"Skipping Gradle build task invocation due to OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED environment variable set to \\\"YES\\\"\"\n exit 0\nfi\nexport JAVA_HOME=\"/Applications/Android Studio.app/Contents/jbr/Contents/Home\"\nexport PATH=\"$JAVA_HOME/bin:/opt/homebrew/bin:$PATH\"\nif [ -z \"$GRADLE_OPTS\" ]; then\n export GRADLE_OPTS=\"-Xmx12288M -Dfile.encoding=UTF-8 -XX:MaxMetaspaceSize=2048m\"\nfi\nif [ -z \"$KOTLIN_DAEMON_JVMARGS\" ]; then\n export KOTLIN_DAEMON_JVMARGS=\"-Xmx8192M\"\nfi\ncd \"$SRCROOT/..\"\n./gradlew :composeApp:embedAndSignAppleFrameworkForXcode\n"; }; /* End PBXShellScriptBuildPhase section */