feat: bottom sheet polish
This commit is contained in:
@@ -32,6 +32,7 @@
|
||||
"delete": "Löschen",
|
||||
"shuffle": "Zufall",
|
||||
"addTo": "Hinzufügen zu...",
|
||||
"createNew": "Neu erstellen",
|
||||
"remove": "Entfernen",
|
||||
"paste": "Einfügen",
|
||||
"connect": "Verbinden",
|
||||
@@ -634,7 +635,6 @@
|
||||
"itemAdded": "Zur Wiedergabeliste hinzugefügt",
|
||||
"itemRemoved": "Aus Wiedergabeliste entfernt",
|
||||
"selectPlaylist": "Wiedergabeliste auswählen",
|
||||
"createNewPlaylist": "Neue Wiedergabeliste erstellen",
|
||||
"errorCreating": "Wiedergabeliste konnte nicht erstellt werden",
|
||||
"errorDeleting": "Wiedergabeliste konnte nicht gelöscht werden",
|
||||
"errorLoading": "Wiedergabelisten konnten nicht geladen werden",
|
||||
@@ -655,7 +655,6 @@
|
||||
"deleteFailedWithError": "Sammlung konnte nicht gelöscht werden: ${error}",
|
||||
"failedToLoadItems": "Sammlungselemente konnten nicht geladen werden: ${error}",
|
||||
"selectCollection": "Sammlung auswählen",
|
||||
"createNewCollection": "Neue Sammlung erstellen",
|
||||
"collectionName": "Sammlungsname",
|
||||
"enterCollectionName": "Sammlungsnamen eingeben",
|
||||
"addedToCollection": "Zur Sammlung hinzugefügt",
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
"delete": "Delete",
|
||||
"shuffle": "Shuffle",
|
||||
"addTo": "Add to...",
|
||||
"createNew": "Create new",
|
||||
"remove": "Remove",
|
||||
"paste": "Paste",
|
||||
"connect": "Connect",
|
||||
@@ -607,7 +608,6 @@
|
||||
"deleteFailedWithError": "Failed to delete collection: ${error}",
|
||||
"failedToLoadItems": "Failed to load collection items: ${error}",
|
||||
"selectCollection": "Select Collection",
|
||||
"createNewCollection": "Create New Collection",
|
||||
"collectionName": "Collection Name",
|
||||
"enterCollectionName": "Enter collection name",
|
||||
"addedToCollection": "Added to collection",
|
||||
@@ -639,7 +639,6 @@
|
||||
"itemAdded": "Added to playlist",
|
||||
"itemRemoved": "Removed from playlist",
|
||||
"selectPlaylist": "Select Playlist",
|
||||
"createNewPlaylist": "Create New Playlist",
|
||||
"errorCreating": "Failed to create playlist",
|
||||
"errorDeleting": "Failed to delete playlist",
|
||||
"errorLoading": "Failed to load playlists",
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
"delete": "Eliminar",
|
||||
"shuffle": "Aleatorio",
|
||||
"addTo": "Añadir a...",
|
||||
"createNew": "Crear",
|
||||
"remove": "Eliminar",
|
||||
"paste": "Pegar",
|
||||
"connect": "Conectar",
|
||||
@@ -607,7 +608,6 @@
|
||||
"deleteFailedWithError": "Error al eliminar la colección: ${error}",
|
||||
"failedToLoadItems": "Error al cargar los elementos de la colección: ${error}",
|
||||
"selectCollection": "Seleccionar Colección",
|
||||
"createNewCollection": "Crear Nueva Colección",
|
||||
"collectionName": "Nombre de la Colección",
|
||||
"enterCollectionName": "Introduce el nombre de la colección",
|
||||
"addedToCollection": "Añadido a la colección",
|
||||
@@ -639,7 +639,6 @@
|
||||
"itemAdded": "Añadido a la lista",
|
||||
"itemRemoved": "Eliminado de la lista",
|
||||
"selectPlaylist": "Seleccionar Lista",
|
||||
"createNewPlaylist": "Crear Nueva Lista",
|
||||
"errorCreating": "Error al crear la lista",
|
||||
"errorDeleting": "Error al eliminar la lista",
|
||||
"errorLoading": "Error al cargar las listas",
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
"delete": "Supprimer",
|
||||
"shuffle": "Mélanger",
|
||||
"addTo": "Ajouter à...",
|
||||
"createNew": "Créer",
|
||||
"remove": "Supprimer",
|
||||
"paste": "Coller",
|
||||
"connect": "Connecter",
|
||||
@@ -607,7 +608,6 @@
|
||||
"deleteFailedWithError": "Échec de la suppression de la collection: ${error}",
|
||||
"failedToLoadItems": "Échec du chargement des éléments de la collection: ${error}",
|
||||
"selectCollection": "Sélectionner une collection",
|
||||
"createNewCollection": "Créer une nouvelle collection",
|
||||
"collectionName": "Nom de la collection",
|
||||
"enterCollectionName": "Entrez le nom de la collection",
|
||||
"addedToCollection": "Ajouté à la collection",
|
||||
@@ -639,7 +639,6 @@
|
||||
"itemAdded": "Ajouté à la playlist",
|
||||
"itemRemoved": "Retiré de la playlist",
|
||||
"selectPlaylist": "Select Playlist",
|
||||
"createNewPlaylist": "Créer une nouvelle playlist",
|
||||
"errorCreating": "Échec de la création de playlist",
|
||||
"errorDeleting": "Échec de suppression de playlist",
|
||||
"errorLoading": "Échec de chargement de playlists",
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
"delete": "Elimina",
|
||||
"shuffle": "Casuale",
|
||||
"addTo": "Aggiungi a...",
|
||||
"createNew": "Crea",
|
||||
"remove": "Rimuovi",
|
||||
"paste": "Incolla",
|
||||
"connect": "Connetti",
|
||||
@@ -634,7 +635,6 @@
|
||||
"itemAdded": "Aggiunto alla playlist",
|
||||
"itemRemoved": "Rimosso dalla playlist",
|
||||
"selectPlaylist": "Seleziona playlist",
|
||||
"createNewPlaylist": "Crea nuova playlist",
|
||||
"errorCreating": "Errore durante la creazione della playlist",
|
||||
"errorDeleting": "Errore durante l'eliminazione della playlist",
|
||||
"errorLoading": "Errore durante il caricamento delle playlist",
|
||||
@@ -655,7 +655,6 @@
|
||||
"deleteFailedWithError": "Impossibile eliminare la raccolta: ${error}",
|
||||
"failedToLoadItems": "Impossibile caricare gli elementi della raccolta: ${error}",
|
||||
"selectCollection": "Seleziona raccolta",
|
||||
"createNewCollection": "Crea nuova raccolta",
|
||||
"collectionName": "Nome raccolta",
|
||||
"enterCollectionName": "Inserisci nome raccolta",
|
||||
"addedToCollection": "Aggiunto alla raccolta",
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
"delete": "삭제",
|
||||
"shuffle": "무작위 재생",
|
||||
"addTo": "추가하기...",
|
||||
"createNew": "새로 만들기",
|
||||
"remove": "삭제",
|
||||
"paste": "붙여넣기",
|
||||
"connect": "연결",
|
||||
@@ -607,7 +608,6 @@
|
||||
"deleteFailedWithError": "컬렉션 삭제 실패: ${error}",
|
||||
"failedToLoadItems": "컬렉션 항목 로드 실패: ${error}",
|
||||
"selectCollection": "컬렉션 선택",
|
||||
"createNewCollection": "새 컬렉션 생성",
|
||||
"collectionName": "컬렉션 이름",
|
||||
"enterCollectionName": "컬렉션 이름 입력",
|
||||
"addedToCollection": "컬렉션에 추가됨",
|
||||
@@ -639,7 +639,6 @@
|
||||
"itemAdded": "재생 목록에 추가 되었습니다",
|
||||
"itemRemoved": "재생 목록에서 제거됨",
|
||||
"selectPlaylist": "재생 목록 선택",
|
||||
"createNewPlaylist": "새 재생 목록 생성",
|
||||
"errorCreating": "재생 목록 생성 실패",
|
||||
"errorDeleting": "재생 목록 삭제 실패",
|
||||
"errorLoading": "재생 목록 로드 실패",
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
"delete": "Verwijderen",
|
||||
"shuffle": "Willekeurig",
|
||||
"addTo": "Toevoegen aan...",
|
||||
"createNew": "Nieuw aanmaken",
|
||||
"remove": "Verwijderen",
|
||||
"paste": "Plakken",
|
||||
"connect": "Verbinden",
|
||||
@@ -634,7 +635,6 @@
|
||||
"itemAdded": "Toegevoegd aan afspeellijst",
|
||||
"itemRemoved": "Verwijderd uit afspeellijst",
|
||||
"selectPlaylist": "Selecteer afspeellijst",
|
||||
"createNewPlaylist": "Nieuwe afspeellijst maken",
|
||||
"errorCreating": "Fout bij maken afspeellijst",
|
||||
"errorDeleting": "Fout bij verwijderen afspeellijst",
|
||||
"errorLoading": "Fout bij laden afspeellijsten",
|
||||
@@ -655,7 +655,6 @@
|
||||
"deleteFailedWithError": "Collectie verwijderen mislukt: ${error}",
|
||||
"failedToLoadItems": "Collectie-items laden mislukt: ${error}",
|
||||
"selectCollection": "Selecteer collectie",
|
||||
"createNewCollection": "Nieuwe collectie maken",
|
||||
"collectionName": "Collectienaam",
|
||||
"enterCollectionName": "Voer collectienaam in",
|
||||
"addedToCollection": "Toegevoegd aan collectie",
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
/// To regenerate, run: `dart run slang`
|
||||
///
|
||||
/// Locales: 9
|
||||
/// Strings: 7272 (808 per locale)
|
||||
/// Strings: 7263 (807 per locale)
|
||||
///
|
||||
/// Built on 2026-03-02 at 16:42 UTC
|
||||
/// Built on 2026-03-02 at 20:21 UTC
|
||||
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: type=lint, unused_import
|
||||
|
||||
@@ -130,6 +130,7 @@ class _TranslationsCommonDe implements TranslationsCommonEn {
|
||||
@override String get delete => 'Löschen';
|
||||
@override String get shuffle => 'Zufall';
|
||||
@override String get addTo => 'Hinzufügen zu...';
|
||||
@override String get createNew => 'Neu erstellen';
|
||||
@override String get remove => 'Entfernen';
|
||||
@override String get paste => 'Einfügen';
|
||||
@override String get connect => 'Verbinden';
|
||||
@@ -506,7 +507,7 @@ class _TranslationsVideoControlsDe implements TranslationsVideoControlsEn {
|
||||
@override String get timelineSlider => 'Video-Zeitleiste';
|
||||
@override String get volumeSlider => 'Lautstärkepegel';
|
||||
@override String endsAt({required Object time}) => 'Endet um ${time}';
|
||||
@override String get pipActive => 'Playing in Picture-in-Picture';
|
||||
@override String get pipActive => 'Wiedergabe im Bild-in-Bild-Modus';
|
||||
@override String get pipFailed => 'Bild-in-Bild konnte nicht gestartet werden';
|
||||
@override late final _TranslationsVideoControlsPipErrorsDe pipErrors = _TranslationsVideoControlsPipErrorsDe._(_root);
|
||||
@override String get chapters => 'Kapitel';
|
||||
@@ -888,7 +889,6 @@ class _TranslationsPlaylistsDe implements TranslationsPlaylistsEn {
|
||||
@override String get itemAdded => 'Zur Wiedergabeliste hinzugefügt';
|
||||
@override String get itemRemoved => 'Aus Wiedergabeliste entfernt';
|
||||
@override String get selectPlaylist => 'Wiedergabeliste auswählen';
|
||||
@override String get createNewPlaylist => 'Neue Wiedergabeliste erstellen';
|
||||
@override String get errorCreating => 'Wiedergabeliste konnte nicht erstellt werden';
|
||||
@override String get errorDeleting => 'Wiedergabeliste konnte nicht gelöscht werden';
|
||||
@override String get errorLoading => 'Wiedergabelisten konnten nicht geladen werden';
|
||||
@@ -916,7 +916,6 @@ class _TranslationsCollectionsDe implements TranslationsCollectionsEn {
|
||||
@override String deleteFailedWithError({required Object error}) => 'Sammlung konnte nicht gelöscht werden: ${error}';
|
||||
@override String failedToLoadItems({required Object error}) => 'Sammlungselemente konnten nicht geladen werden: ${error}';
|
||||
@override String get selectCollection => 'Sammlung auswählen';
|
||||
@override String get createNewCollection => 'Neue Sammlung erstellen';
|
||||
@override String get collectionName => 'Sammlungsname';
|
||||
@override String get enterCollectionName => 'Sammlungsnamen eingeben';
|
||||
@override String get addedToCollection => 'Zur Sammlung hinzugefügt';
|
||||
@@ -1333,6 +1332,7 @@ extension on TranslationsDe {
|
||||
'common.delete' => 'Löschen',
|
||||
'common.shuffle' => 'Zufall',
|
||||
'common.addTo' => 'Hinzufügen zu...',
|
||||
'common.createNew' => 'Neu erstellen',
|
||||
'common.remove' => 'Entfernen',
|
||||
'common.paste' => 'Einfügen',
|
||||
'common.connect' => 'Verbinden',
|
||||
@@ -1628,7 +1628,7 @@ extension on TranslationsDe {
|
||||
'videoControls.timelineSlider' => 'Video-Zeitleiste',
|
||||
'videoControls.volumeSlider' => 'Lautstärkepegel',
|
||||
'videoControls.endsAt' => ({required Object time}) => 'Endet um ${time}',
|
||||
'videoControls.pipActive' => 'Playing in Picture-in-Picture',
|
||||
'videoControls.pipActive' => 'Wiedergabe im Bild-in-Bild-Modus',
|
||||
'videoControls.pipFailed' => 'Bild-in-Bild konnte nicht gestartet werden',
|
||||
'videoControls.pipErrors.androidVersion' => 'Erfordert Android 8.0 oder neuer',
|
||||
'videoControls.pipErrors.iosVersion' => 'Erfordert iOS 15.0 oder neuer',
|
||||
@@ -1816,9 +1816,9 @@ extension on TranslationsDe {
|
||||
'liveTv.noChannels' => 'Keine Kanäle verfügbar',
|
||||
'liveTv.noDvr' => 'Kein DVR auf einem Server konfiguriert',
|
||||
'liveTv.tuneFailed' => 'Kanal konnte nicht eingestellt werden',
|
||||
'liveTv.loading' => 'Kanäle werden geladen...',
|
||||
_ => null,
|
||||
} ?? switch (path) {
|
||||
'liveTv.loading' => 'Kanäle werden geladen...',
|
||||
'liveTv.nowPlaying' => 'Läuft gerade',
|
||||
'liveTv.noPrograms' => 'Keine Programmdaten verfügbar',
|
||||
'liveTv.channelNumber' => ({required Object number}) => 'Kanal ${number}',
|
||||
@@ -1873,7 +1873,6 @@ extension on TranslationsDe {
|
||||
'playlists.itemAdded' => 'Zur Wiedergabeliste hinzugefügt',
|
||||
'playlists.itemRemoved' => 'Aus Wiedergabeliste entfernt',
|
||||
'playlists.selectPlaylist' => 'Wiedergabeliste auswählen',
|
||||
'playlists.createNewPlaylist' => 'Neue Wiedergabeliste erstellen',
|
||||
'playlists.errorCreating' => 'Wiedergabeliste konnte nicht erstellt werden',
|
||||
'playlists.errorDeleting' => 'Wiedergabeliste konnte nicht gelöscht werden',
|
||||
'playlists.errorLoading' => 'Wiedergabelisten konnten nicht geladen werden',
|
||||
@@ -1892,7 +1891,6 @@ extension on TranslationsDe {
|
||||
'collections.deleteFailedWithError' => ({required Object error}) => 'Sammlung konnte nicht gelöscht werden: ${error}',
|
||||
'collections.failedToLoadItems' => ({required Object error}) => 'Sammlungselemente konnten nicht geladen werden: ${error}',
|
||||
'collections.selectCollection' => 'Sammlung auswählen',
|
||||
'collections.createNewCollection' => 'Neue Sammlung erstellen',
|
||||
'collections.collectionName' => 'Sammlungsname',
|
||||
'collections.enterCollectionName' => 'Sammlungsnamen eingeben',
|
||||
'collections.addedToCollection' => 'Zur Sammlung hinzugefügt',
|
||||
|
||||
@@ -190,6 +190,9 @@ class TranslationsCommonEn {
|
||||
/// en: 'Add to...'
|
||||
String get addTo => 'Add to...';
|
||||
|
||||
/// en: 'Create new'
|
||||
String get createNew => 'Create new';
|
||||
|
||||
/// en: 'Remove'
|
||||
String get remove => 'Remove';
|
||||
|
||||
@@ -1871,9 +1874,6 @@ class TranslationsCollectionsEn {
|
||||
/// en: 'Select Collection'
|
||||
String get selectCollection => 'Select Collection';
|
||||
|
||||
/// en: 'Create New Collection'
|
||||
String get createNewCollection => 'Create New Collection';
|
||||
|
||||
/// en: 'Collection Name'
|
||||
String get collectionName => 'Collection Name';
|
||||
|
||||
@@ -1970,9 +1970,6 @@ class TranslationsPlaylistsEn {
|
||||
/// en: 'Select Playlist'
|
||||
String get selectPlaylist => 'Select Playlist';
|
||||
|
||||
/// en: 'Create New Playlist'
|
||||
String get createNewPlaylist => 'Create New Playlist';
|
||||
|
||||
/// en: 'Failed to create playlist'
|
||||
String get errorCreating => 'Failed to create playlist';
|
||||
|
||||
@@ -2956,6 +2953,7 @@ extension on Translations {
|
||||
'common.delete' => 'Delete',
|
||||
'common.shuffle' => 'Shuffle',
|
||||
'common.addTo' => 'Add to...',
|
||||
'common.createNew' => 'Create new',
|
||||
'common.remove' => 'Remove',
|
||||
'common.paste' => 'Paste',
|
||||
'common.connect' => 'Connect',
|
||||
@@ -3439,9 +3437,9 @@ extension on Translations {
|
||||
'liveTv.noChannels' => 'No channels available',
|
||||
'liveTv.noDvr' => 'No DVR configured on any server',
|
||||
'liveTv.tuneFailed' => 'Failed to tune channel',
|
||||
'liveTv.loading' => 'Loading channels...',
|
||||
_ => null,
|
||||
} ?? switch (path) {
|
||||
'liveTv.loading' => 'Loading channels...',
|
||||
'liveTv.nowPlaying' => 'Now Playing',
|
||||
'liveTv.noPrograms' => 'No program data available',
|
||||
'liveTv.channelNumber' => ({required Object number}) => 'Ch. ${number}',
|
||||
@@ -3471,7 +3469,6 @@ extension on Translations {
|
||||
'collections.deleteFailedWithError' => ({required Object error}) => 'Failed to delete collection: ${error}',
|
||||
'collections.failedToLoadItems' => ({required Object error}) => 'Failed to load collection items: ${error}',
|
||||
'collections.selectCollection' => 'Select Collection',
|
||||
'collections.createNewCollection' => 'Create New Collection',
|
||||
'collections.collectionName' => 'Collection Name',
|
||||
'collections.enterCollectionName' => 'Enter collection name',
|
||||
'collections.addedToCollection' => 'Added to collection',
|
||||
@@ -3501,7 +3498,6 @@ extension on Translations {
|
||||
'playlists.itemAdded' => 'Added to playlist',
|
||||
'playlists.itemRemoved' => 'Removed from playlist',
|
||||
'playlists.selectPlaylist' => 'Select Playlist',
|
||||
'playlists.createNewPlaylist' => 'Create New Playlist',
|
||||
'playlists.errorCreating' => 'Failed to create playlist',
|
||||
'playlists.errorDeleting' => 'Failed to delete playlist',
|
||||
'playlists.errorLoading' => 'Failed to load playlists',
|
||||
|
||||
@@ -130,6 +130,7 @@ class _TranslationsCommonEs implements TranslationsCommonEn {
|
||||
@override String get delete => 'Eliminar';
|
||||
@override String get shuffle => 'Aleatorio';
|
||||
@override String get addTo => 'Añadir a...';
|
||||
@override String get createNew => 'Crear';
|
||||
@override String get remove => 'Eliminar';
|
||||
@override String get paste => 'Pegar';
|
||||
@override String get connect => 'Conectar';
|
||||
@@ -506,7 +507,7 @@ class _TranslationsVideoControlsEs implements TranslationsVideoControlsEn {
|
||||
@override String get timelineSlider => 'Línea de tiempo del video';
|
||||
@override String get volumeSlider => 'Nivel de volumen';
|
||||
@override String endsAt({required Object time}) => 'Termina a las ${time}';
|
||||
@override String get pipActive => 'Playing in Picture-in-Picture';
|
||||
@override String get pipActive => 'Reproduciendo en Imagen en Imagen';
|
||||
@override String get pipFailed => 'Error al iniciar Imagen en Imagen';
|
||||
@override late final _TranslationsVideoControlsPipErrorsEs pipErrors = _TranslationsVideoControlsPipErrorsEs._(_root);
|
||||
@override String get chapters => 'Capítulos';
|
||||
@@ -854,7 +855,6 @@ class _TranslationsCollectionsEs implements TranslationsCollectionsEn {
|
||||
@override String deleteFailedWithError({required Object error}) => 'Error al eliminar la colección: ${error}';
|
||||
@override String failedToLoadItems({required Object error}) => 'Error al cargar los elementos de la colección: ${error}';
|
||||
@override String get selectCollection => 'Seleccionar Colección';
|
||||
@override String get createNewCollection => 'Crear Nueva Colección';
|
||||
@override String get collectionName => 'Nombre de la Colección';
|
||||
@override String get enterCollectionName => 'Introduce el nombre de la colección';
|
||||
@override String get addedToCollection => 'Añadido a la colección';
|
||||
@@ -893,7 +893,6 @@ class _TranslationsPlaylistsEs implements TranslationsPlaylistsEn {
|
||||
@override String get itemAdded => 'Añadido a la lista';
|
||||
@override String get itemRemoved => 'Eliminado de la lista';
|
||||
@override String get selectPlaylist => 'Seleccionar Lista';
|
||||
@override String get createNewPlaylist => 'Crear Nueva Lista';
|
||||
@override String get errorCreating => 'Error al crear la lista';
|
||||
@override String get errorDeleting => 'Error al eliminar la lista';
|
||||
@override String get errorLoading => 'Error al cargar las listas';
|
||||
@@ -1333,6 +1332,7 @@ extension on TranslationsEs {
|
||||
'common.delete' => 'Eliminar',
|
||||
'common.shuffle' => 'Aleatorio',
|
||||
'common.addTo' => 'Añadir a...',
|
||||
'common.createNew' => 'Crear',
|
||||
'common.remove' => 'Eliminar',
|
||||
'common.paste' => 'Pegar',
|
||||
'common.connect' => 'Conectar',
|
||||
@@ -1628,7 +1628,7 @@ extension on TranslationsEs {
|
||||
'videoControls.timelineSlider' => 'Línea de tiempo del video',
|
||||
'videoControls.volumeSlider' => 'Nivel de volumen',
|
||||
'videoControls.endsAt' => ({required Object time}) => 'Termina a las ${time}',
|
||||
'videoControls.pipActive' => 'Playing in Picture-in-Picture',
|
||||
'videoControls.pipActive' => 'Reproduciendo en Imagen en Imagen',
|
||||
'videoControls.pipFailed' => 'Error al iniciar Imagen en Imagen',
|
||||
'videoControls.pipErrors.androidVersion' => 'Requiere Android 8.0 o más reciente',
|
||||
'videoControls.pipErrors.iosVersion' => 'Requiere iOS 15.0 o más reciente',
|
||||
@@ -1816,9 +1816,9 @@ extension on TranslationsEs {
|
||||
'liveTv.noChannels' => 'No hay canales disponibles',
|
||||
'liveTv.noDvr' => 'No hay DVR configurado en ningún servidor',
|
||||
'liveTv.tuneFailed' => 'Error al sintonizar el canal',
|
||||
'liveTv.loading' => 'Cargando canales...',
|
||||
_ => null,
|
||||
} ?? switch (path) {
|
||||
'liveTv.loading' => 'Cargando canales...',
|
||||
'liveTv.nowPlaying' => 'Reproduciendo ahora',
|
||||
'liveTv.noPrograms' => 'No hay datos de programación disponibles',
|
||||
'liveTv.channelNumber' => ({required Object number}) => 'Canal ${number}',
|
||||
@@ -1848,7 +1848,6 @@ extension on TranslationsEs {
|
||||
'collections.deleteFailedWithError' => ({required Object error}) => 'Error al eliminar la colección: ${error}',
|
||||
'collections.failedToLoadItems' => ({required Object error}) => 'Error al cargar los elementos de la colección: ${error}',
|
||||
'collections.selectCollection' => 'Seleccionar Colección',
|
||||
'collections.createNewCollection' => 'Crear Nueva Colección',
|
||||
'collections.collectionName' => 'Nombre de la Colección',
|
||||
'collections.enterCollectionName' => 'Introduce el nombre de la colección',
|
||||
'collections.addedToCollection' => 'Añadido a la colección',
|
||||
@@ -1878,7 +1877,6 @@ extension on TranslationsEs {
|
||||
'playlists.itemAdded' => 'Añadido a la lista',
|
||||
'playlists.itemRemoved' => 'Eliminado de la lista',
|
||||
'playlists.selectPlaylist' => 'Seleccionar Lista',
|
||||
'playlists.createNewPlaylist' => 'Crear Nueva Lista',
|
||||
'playlists.errorCreating' => 'Error al crear la lista',
|
||||
'playlists.errorDeleting' => 'Error al eliminar la lista',
|
||||
'playlists.errorLoading' => 'Error al cargar las listas',
|
||||
|
||||
@@ -130,6 +130,7 @@ class _TranslationsCommonFr implements TranslationsCommonEn {
|
||||
@override String get delete => 'Supprimer';
|
||||
@override String get shuffle => 'Mélanger';
|
||||
@override String get addTo => 'Ajouter à...';
|
||||
@override String get createNew => 'Créer';
|
||||
@override String get remove => 'Supprimer';
|
||||
@override String get paste => 'Coller';
|
||||
@override String get connect => 'Connecter';
|
||||
@@ -506,7 +507,7 @@ class _TranslationsVideoControlsFr implements TranslationsVideoControlsEn {
|
||||
@override String get timelineSlider => 'Timeline vidéo';
|
||||
@override String get volumeSlider => 'Niveau sonore';
|
||||
@override String endsAt({required Object time}) => 'Fin à ${time}';
|
||||
@override String get pipActive => 'Playing in Picture-in-Picture';
|
||||
@override String get pipActive => 'Lecture en mode image dans l\'image';
|
||||
@override String get pipFailed => 'Échec du démarrage du mode image dans l\'image';
|
||||
@override late final _TranslationsVideoControlsPipErrorsFr pipErrors = _TranslationsVideoControlsPipErrorsFr._(_root);
|
||||
@override String get chapters => 'Chapitres';
|
||||
@@ -854,7 +855,6 @@ class _TranslationsCollectionsFr implements TranslationsCollectionsEn {
|
||||
@override String deleteFailedWithError({required Object error}) => 'Échec de la suppression de la collection: ${error}';
|
||||
@override String failedToLoadItems({required Object error}) => 'Échec du chargement des éléments de la collection: ${error}';
|
||||
@override String get selectCollection => 'Sélectionner une collection';
|
||||
@override String get createNewCollection => 'Créer une nouvelle collection';
|
||||
@override String get collectionName => 'Nom de la collection';
|
||||
@override String get enterCollectionName => 'Entrez le nom de la collection';
|
||||
@override String get addedToCollection => 'Ajouté à la collection';
|
||||
@@ -893,7 +893,6 @@ class _TranslationsPlaylistsFr implements TranslationsPlaylistsEn {
|
||||
@override String get itemAdded => 'Ajouté à la playlist';
|
||||
@override String get itemRemoved => 'Retiré de la playlist';
|
||||
@override String get selectPlaylist => 'Select Playlist';
|
||||
@override String get createNewPlaylist => 'Créer une nouvelle playlist';
|
||||
@override String get errorCreating => 'Échec de la création de playlist';
|
||||
@override String get errorDeleting => 'Échec de suppression de playlist';
|
||||
@override String get errorLoading => 'Échec de chargement de playlists';
|
||||
@@ -1333,6 +1332,7 @@ extension on TranslationsFr {
|
||||
'common.delete' => 'Supprimer',
|
||||
'common.shuffle' => 'Mélanger',
|
||||
'common.addTo' => 'Ajouter à...',
|
||||
'common.createNew' => 'Créer',
|
||||
'common.remove' => 'Supprimer',
|
||||
'common.paste' => 'Coller',
|
||||
'common.connect' => 'Connecter',
|
||||
@@ -1628,7 +1628,7 @@ extension on TranslationsFr {
|
||||
'videoControls.timelineSlider' => 'Timeline vidéo',
|
||||
'videoControls.volumeSlider' => 'Niveau sonore',
|
||||
'videoControls.endsAt' => ({required Object time}) => 'Fin à ${time}',
|
||||
'videoControls.pipActive' => 'Playing in Picture-in-Picture',
|
||||
'videoControls.pipActive' => 'Lecture en mode image dans l\'image',
|
||||
'videoControls.pipFailed' => 'Échec du démarrage du mode image dans l\'image',
|
||||
'videoControls.pipErrors.androidVersion' => 'Nécessite Android 8.0 ou plus récent',
|
||||
'videoControls.pipErrors.iosVersion' => 'Nécessite iOS 15.0 ou plus récent',
|
||||
@@ -1816,9 +1816,9 @@ extension on TranslationsFr {
|
||||
'liveTv.noChannels' => 'Aucune chaîne disponible',
|
||||
'liveTv.noDvr' => 'Aucun DVR configuré sur les serveurs',
|
||||
'liveTv.tuneFailed' => 'Impossible de syntoniser la chaîne',
|
||||
'liveTv.loading' => 'Chargement des chaînes...',
|
||||
_ => null,
|
||||
} ?? switch (path) {
|
||||
'liveTv.loading' => 'Chargement des chaînes...',
|
||||
'liveTv.nowPlaying' => 'En cours de lecture',
|
||||
'liveTv.noPrograms' => 'Aucune donnée de programme disponible',
|
||||
'liveTv.channelNumber' => ({required Object number}) => 'Ch. ${number}',
|
||||
@@ -1848,7 +1848,6 @@ extension on TranslationsFr {
|
||||
'collections.deleteFailedWithError' => ({required Object error}) => 'Échec de la suppression de la collection: ${error}',
|
||||
'collections.failedToLoadItems' => ({required Object error}) => 'Échec du chargement des éléments de la collection: ${error}',
|
||||
'collections.selectCollection' => 'Sélectionner une collection',
|
||||
'collections.createNewCollection' => 'Créer une nouvelle collection',
|
||||
'collections.collectionName' => 'Nom de la collection',
|
||||
'collections.enterCollectionName' => 'Entrez le nom de la collection',
|
||||
'collections.addedToCollection' => 'Ajouté à la collection',
|
||||
@@ -1878,7 +1877,6 @@ extension on TranslationsFr {
|
||||
'playlists.itemAdded' => 'Ajouté à la playlist',
|
||||
'playlists.itemRemoved' => 'Retiré de la playlist',
|
||||
'playlists.selectPlaylist' => 'Select Playlist',
|
||||
'playlists.createNewPlaylist' => 'Créer une nouvelle playlist',
|
||||
'playlists.errorCreating' => 'Échec de la création de playlist',
|
||||
'playlists.errorDeleting' => 'Échec de suppression de playlist',
|
||||
'playlists.errorLoading' => 'Échec de chargement de playlists',
|
||||
|
||||
@@ -130,6 +130,7 @@ class _TranslationsCommonIt implements TranslationsCommonEn {
|
||||
@override String get delete => 'Elimina';
|
||||
@override String get shuffle => 'Casuale';
|
||||
@override String get addTo => 'Aggiungi a...';
|
||||
@override String get createNew => 'Crea';
|
||||
@override String get remove => 'Rimuovi';
|
||||
@override String get paste => 'Incolla';
|
||||
@override String get connect => 'Connetti';
|
||||
@@ -506,7 +507,7 @@ class _TranslationsVideoControlsIt implements TranslationsVideoControlsEn {
|
||||
@override String get timelineSlider => 'Timeline video';
|
||||
@override String get volumeSlider => 'Livello volume';
|
||||
@override String endsAt({required Object time}) => 'Finisce alle ${time}';
|
||||
@override String get pipActive => 'Playing in Picture-in-Picture';
|
||||
@override String get pipActive => 'Riproduzione in Picture-in-Picture';
|
||||
@override String get pipFailed => 'Impossibile avviare la modalità Picture-in-Picture';
|
||||
@override late final _TranslationsVideoControlsPipErrorsIt pipErrors = _TranslationsVideoControlsPipErrorsIt._(_root);
|
||||
@override String get chapters => 'Capitoli';
|
||||
@@ -888,7 +889,6 @@ class _TranslationsPlaylistsIt implements TranslationsPlaylistsEn {
|
||||
@override String get itemAdded => 'Aggiunto alla playlist';
|
||||
@override String get itemRemoved => 'Rimosso dalla playlist';
|
||||
@override String get selectPlaylist => 'Seleziona playlist';
|
||||
@override String get createNewPlaylist => 'Crea nuova playlist';
|
||||
@override String get errorCreating => 'Errore durante la creazione della playlist';
|
||||
@override String get errorDeleting => 'Errore durante l\'eliminazione della playlist';
|
||||
@override String get errorLoading => 'Errore durante il caricamento delle playlist';
|
||||
@@ -916,7 +916,6 @@ class _TranslationsCollectionsIt implements TranslationsCollectionsEn {
|
||||
@override String deleteFailedWithError({required Object error}) => 'Impossibile eliminare la raccolta: ${error}';
|
||||
@override String failedToLoadItems({required Object error}) => 'Impossibile caricare gli elementi della raccolta: ${error}';
|
||||
@override String get selectCollection => 'Seleziona raccolta';
|
||||
@override String get createNewCollection => 'Crea nuova raccolta';
|
||||
@override String get collectionName => 'Nome raccolta';
|
||||
@override String get enterCollectionName => 'Inserisci nome raccolta';
|
||||
@override String get addedToCollection => 'Aggiunto alla raccolta';
|
||||
@@ -1333,6 +1332,7 @@ extension on TranslationsIt {
|
||||
'common.delete' => 'Elimina',
|
||||
'common.shuffle' => 'Casuale',
|
||||
'common.addTo' => 'Aggiungi a...',
|
||||
'common.createNew' => 'Crea',
|
||||
'common.remove' => 'Rimuovi',
|
||||
'common.paste' => 'Incolla',
|
||||
'common.connect' => 'Connetti',
|
||||
@@ -1628,7 +1628,7 @@ extension on TranslationsIt {
|
||||
'videoControls.timelineSlider' => 'Timeline video',
|
||||
'videoControls.volumeSlider' => 'Livello volume',
|
||||
'videoControls.endsAt' => ({required Object time}) => 'Finisce alle ${time}',
|
||||
'videoControls.pipActive' => 'Playing in Picture-in-Picture',
|
||||
'videoControls.pipActive' => 'Riproduzione in Picture-in-Picture',
|
||||
'videoControls.pipFailed' => 'Impossibile avviare la modalità Picture-in-Picture',
|
||||
'videoControls.pipErrors.androidVersion' => 'Richiede Android 8.0 o versioni successive',
|
||||
'videoControls.pipErrors.iosVersion' => 'Richiede iOS 15.0 o versioni successive',
|
||||
@@ -1816,9 +1816,9 @@ extension on TranslationsIt {
|
||||
'liveTv.noChannels' => 'Nessun canale disponibile',
|
||||
'liveTv.noDvr' => 'Nessun DVR configurato su nessun server',
|
||||
'liveTv.tuneFailed' => 'Impossibile sintonizzare il canale',
|
||||
'liveTv.loading' => 'Caricamento canali...',
|
||||
_ => null,
|
||||
} ?? switch (path) {
|
||||
'liveTv.loading' => 'Caricamento canali...',
|
||||
'liveTv.nowPlaying' => 'In riproduzione',
|
||||
'liveTv.noPrograms' => 'Nessun dato di programma disponibile',
|
||||
'liveTv.channelNumber' => ({required Object number}) => 'Canale ${number}',
|
||||
@@ -1873,7 +1873,6 @@ extension on TranslationsIt {
|
||||
'playlists.itemAdded' => 'Aggiunto alla playlist',
|
||||
'playlists.itemRemoved' => 'Rimosso dalla playlist',
|
||||
'playlists.selectPlaylist' => 'Seleziona playlist',
|
||||
'playlists.createNewPlaylist' => 'Crea nuova playlist',
|
||||
'playlists.errorCreating' => 'Errore durante la creazione della playlist',
|
||||
'playlists.errorDeleting' => 'Errore durante l\'eliminazione della playlist',
|
||||
'playlists.errorLoading' => 'Errore durante il caricamento delle playlist',
|
||||
@@ -1892,7 +1891,6 @@ extension on TranslationsIt {
|
||||
'collections.deleteFailedWithError' => ({required Object error}) => 'Impossibile eliminare la raccolta: ${error}',
|
||||
'collections.failedToLoadItems' => ({required Object error}) => 'Impossibile caricare gli elementi della raccolta: ${error}',
|
||||
'collections.selectCollection' => 'Seleziona raccolta',
|
||||
'collections.createNewCollection' => 'Crea nuova raccolta',
|
||||
'collections.collectionName' => 'Nome raccolta',
|
||||
'collections.enterCollectionName' => 'Inserisci nome raccolta',
|
||||
'collections.addedToCollection' => 'Aggiunto alla raccolta',
|
||||
|
||||
@@ -130,6 +130,7 @@ class _TranslationsCommonKo implements TranslationsCommonEn {
|
||||
@override String get delete => '삭제';
|
||||
@override String get shuffle => '무작위 재생';
|
||||
@override String get addTo => '추가하기...';
|
||||
@override String get createNew => '새로 만들기';
|
||||
@override String get remove => '삭제';
|
||||
@override String get paste => '붙여넣기';
|
||||
@override String get connect => '연결';
|
||||
@@ -506,7 +507,7 @@ class _TranslationsVideoControlsKo implements TranslationsVideoControlsEn {
|
||||
@override String get timelineSlider => '타임라인';
|
||||
@override String get volumeSlider => '볼륨 조절';
|
||||
@override String endsAt({required Object time}) => '${time}에 종료';
|
||||
@override String get pipActive => 'Playing in Picture-in-Picture';
|
||||
@override String get pipActive => '화면 속 화면으로 재생 중';
|
||||
@override String get pipFailed => '화면 속 화면 모드를 시작할 수 없습니다';
|
||||
@override late final _TranslationsVideoControlsPipErrorsKo pipErrors = _TranslationsVideoControlsPipErrorsKo._(_root);
|
||||
@override String get chapters => '챕터';
|
||||
@@ -854,7 +855,6 @@ class _TranslationsCollectionsKo implements TranslationsCollectionsEn {
|
||||
@override String deleteFailedWithError({required Object error}) => '컬렉션 삭제 실패: ${error}';
|
||||
@override String failedToLoadItems({required Object error}) => '컬렉션 항목 로드 실패: ${error}';
|
||||
@override String get selectCollection => '컬렉션 선택';
|
||||
@override String get createNewCollection => '새 컬렉션 생성';
|
||||
@override String get collectionName => '컬렉션 이름';
|
||||
@override String get enterCollectionName => '컬렉션 이름 입력';
|
||||
@override String get addedToCollection => '컬렉션에 추가됨';
|
||||
@@ -893,7 +893,6 @@ class _TranslationsPlaylistsKo implements TranslationsPlaylistsEn {
|
||||
@override String get itemAdded => '재생 목록에 추가 되었습니다';
|
||||
@override String get itemRemoved => '재생 목록에서 제거됨';
|
||||
@override String get selectPlaylist => '재생 목록 선택';
|
||||
@override String get createNewPlaylist => '새 재생 목록 생성';
|
||||
@override String get errorCreating => '재생 목록 생성 실패';
|
||||
@override String get errorDeleting => '재생 목록 삭제 실패';
|
||||
@override String get errorLoading => '재생 목록 로드 실패';
|
||||
@@ -1333,6 +1332,7 @@ extension on TranslationsKo {
|
||||
'common.delete' => '삭제',
|
||||
'common.shuffle' => '무작위 재생',
|
||||
'common.addTo' => '추가하기...',
|
||||
'common.createNew' => '새로 만들기',
|
||||
'common.remove' => '삭제',
|
||||
'common.paste' => '붙여넣기',
|
||||
'common.connect' => '연결',
|
||||
@@ -1628,7 +1628,7 @@ extension on TranslationsKo {
|
||||
'videoControls.timelineSlider' => '타임라인',
|
||||
'videoControls.volumeSlider' => '볼륨 조절',
|
||||
'videoControls.endsAt' => ({required Object time}) => '${time}에 종료',
|
||||
'videoControls.pipActive' => 'Playing in Picture-in-Picture',
|
||||
'videoControls.pipActive' => '화면 속 화면으로 재생 중',
|
||||
'videoControls.pipFailed' => '화면 속 화면 모드를 시작할 수 없습니다',
|
||||
'videoControls.pipErrors.androidVersion' => 'Android 8.0 이상이 필요합니다',
|
||||
'videoControls.pipErrors.iosVersion' => 'iOS 15.0 이상이 필요합니다',
|
||||
@@ -1816,9 +1816,9 @@ extension on TranslationsKo {
|
||||
'liveTv.noChannels' => '사용 가능한 채널이 없습니다',
|
||||
'liveTv.noDvr' => '서버에 DVR이 구성되어 있지 않습니다',
|
||||
'liveTv.tuneFailed' => '채널 튜닝에 실패했습니다',
|
||||
'liveTv.loading' => '채널 로딩 중...',
|
||||
_ => null,
|
||||
} ?? switch (path) {
|
||||
'liveTv.loading' => '채널 로딩 중...',
|
||||
'liveTv.nowPlaying' => '현재 재생 중',
|
||||
'liveTv.noPrograms' => '프로그램 데이터가 없습니다',
|
||||
'liveTv.channelNumber' => ({required Object number}) => '채널 ${number}',
|
||||
@@ -1848,7 +1848,6 @@ extension on TranslationsKo {
|
||||
'collections.deleteFailedWithError' => ({required Object error}) => '컬렉션 삭제 실패: ${error}',
|
||||
'collections.failedToLoadItems' => ({required Object error}) => '컬렉션 항목 로드 실패: ${error}',
|
||||
'collections.selectCollection' => '컬렉션 선택',
|
||||
'collections.createNewCollection' => '새 컬렉션 생성',
|
||||
'collections.collectionName' => '컬렉션 이름',
|
||||
'collections.enterCollectionName' => '컬렉션 이름 입력',
|
||||
'collections.addedToCollection' => '컬렉션에 추가됨',
|
||||
@@ -1878,7 +1877,6 @@ extension on TranslationsKo {
|
||||
'playlists.itemAdded' => '재생 목록에 추가 되었습니다',
|
||||
'playlists.itemRemoved' => '재생 목록에서 제거됨',
|
||||
'playlists.selectPlaylist' => '재생 목록 선택',
|
||||
'playlists.createNewPlaylist' => '새 재생 목록 생성',
|
||||
'playlists.errorCreating' => '재생 목록 생성 실패',
|
||||
'playlists.errorDeleting' => '재생 목록 삭제 실패',
|
||||
'playlists.errorLoading' => '재생 목록 로드 실패',
|
||||
|
||||
@@ -130,6 +130,7 @@ class _TranslationsCommonNl implements TranslationsCommonEn {
|
||||
@override String get delete => 'Verwijderen';
|
||||
@override String get shuffle => 'Willekeurig';
|
||||
@override String get addTo => 'Toevoegen aan...';
|
||||
@override String get createNew => 'Nieuw aanmaken';
|
||||
@override String get remove => 'Verwijderen';
|
||||
@override String get paste => 'Plakken';
|
||||
@override String get connect => 'Verbinden';
|
||||
@@ -506,7 +507,7 @@ class _TranslationsVideoControlsNl implements TranslationsVideoControlsEn {
|
||||
@override String get timelineSlider => 'Videotijdlijn';
|
||||
@override String get volumeSlider => 'Volumeniveau';
|
||||
@override String endsAt({required Object time}) => 'Eindigt om ${time}';
|
||||
@override String get pipActive => 'Playing in Picture-in-Picture';
|
||||
@override String get pipActive => 'Afspelen in beeld-in-beeld';
|
||||
@override String get pipFailed => 'Beeld-in-beeld kon niet worden gestart';
|
||||
@override late final _TranslationsVideoControlsPipErrorsNl pipErrors = _TranslationsVideoControlsPipErrorsNl._(_root);
|
||||
@override String get chapters => 'Hoofdstukken';
|
||||
@@ -888,7 +889,6 @@ class _TranslationsPlaylistsNl implements TranslationsPlaylistsEn {
|
||||
@override String get itemAdded => 'Toegevoegd aan afspeellijst';
|
||||
@override String get itemRemoved => 'Verwijderd uit afspeellijst';
|
||||
@override String get selectPlaylist => 'Selecteer afspeellijst';
|
||||
@override String get createNewPlaylist => 'Nieuwe afspeellijst maken';
|
||||
@override String get errorCreating => 'Fout bij maken afspeellijst';
|
||||
@override String get errorDeleting => 'Fout bij verwijderen afspeellijst';
|
||||
@override String get errorLoading => 'Fout bij laden afspeellijsten';
|
||||
@@ -916,7 +916,6 @@ class _TranslationsCollectionsNl implements TranslationsCollectionsEn {
|
||||
@override String deleteFailedWithError({required Object error}) => 'Collectie verwijderen mislukt: ${error}';
|
||||
@override String failedToLoadItems({required Object error}) => 'Collectie-items laden mislukt: ${error}';
|
||||
@override String get selectCollection => 'Selecteer collectie';
|
||||
@override String get createNewCollection => 'Nieuwe collectie maken';
|
||||
@override String get collectionName => 'Collectienaam';
|
||||
@override String get enterCollectionName => 'Voer collectienaam in';
|
||||
@override String get addedToCollection => 'Toegevoegd aan collectie';
|
||||
@@ -1333,6 +1332,7 @@ extension on TranslationsNl {
|
||||
'common.delete' => 'Verwijderen',
|
||||
'common.shuffle' => 'Willekeurig',
|
||||
'common.addTo' => 'Toevoegen aan...',
|
||||
'common.createNew' => 'Nieuw aanmaken',
|
||||
'common.remove' => 'Verwijderen',
|
||||
'common.paste' => 'Plakken',
|
||||
'common.connect' => 'Verbinden',
|
||||
@@ -1628,7 +1628,7 @@ extension on TranslationsNl {
|
||||
'videoControls.timelineSlider' => 'Videotijdlijn',
|
||||
'videoControls.volumeSlider' => 'Volumeniveau',
|
||||
'videoControls.endsAt' => ({required Object time}) => 'Eindigt om ${time}',
|
||||
'videoControls.pipActive' => 'Playing in Picture-in-Picture',
|
||||
'videoControls.pipActive' => 'Afspelen in beeld-in-beeld',
|
||||
'videoControls.pipFailed' => 'Beeld-in-beeld kon niet worden gestart',
|
||||
'videoControls.pipErrors.androidVersion' => 'Vereist Android 8.0 of nieuwer',
|
||||
'videoControls.pipErrors.iosVersion' => 'Vereist iOS 15.0 of nieuwer',
|
||||
@@ -1816,9 +1816,9 @@ extension on TranslationsNl {
|
||||
'liveTv.noChannels' => 'Geen zenders beschikbaar',
|
||||
'liveTv.noDvr' => 'Geen DVR geconfigureerd op een server',
|
||||
'liveTv.tuneFailed' => 'Kan zender niet afstemmen',
|
||||
'liveTv.loading' => 'Zenders laden...',
|
||||
_ => null,
|
||||
} ?? switch (path) {
|
||||
'liveTv.loading' => 'Zenders laden...',
|
||||
'liveTv.nowPlaying' => 'Nu aan het afspelen',
|
||||
'liveTv.noPrograms' => 'Geen programmagegevens beschikbaar',
|
||||
'liveTv.channelNumber' => ({required Object number}) => 'Kanaal ${number}',
|
||||
@@ -1873,7 +1873,6 @@ extension on TranslationsNl {
|
||||
'playlists.itemAdded' => 'Toegevoegd aan afspeellijst',
|
||||
'playlists.itemRemoved' => 'Verwijderd uit afspeellijst',
|
||||
'playlists.selectPlaylist' => 'Selecteer afspeellijst',
|
||||
'playlists.createNewPlaylist' => 'Nieuwe afspeellijst maken',
|
||||
'playlists.errorCreating' => 'Fout bij maken afspeellijst',
|
||||
'playlists.errorDeleting' => 'Fout bij verwijderen afspeellijst',
|
||||
'playlists.errorLoading' => 'Fout bij laden afspeellijsten',
|
||||
@@ -1892,7 +1891,6 @@ extension on TranslationsNl {
|
||||
'collections.deleteFailedWithError' => ({required Object error}) => 'Collectie verwijderen mislukt: ${error}',
|
||||
'collections.failedToLoadItems' => ({required Object error}) => 'Collectie-items laden mislukt: ${error}',
|
||||
'collections.selectCollection' => 'Selecteer collectie',
|
||||
'collections.createNewCollection' => 'Nieuwe collectie maken',
|
||||
'collections.collectionName' => 'Collectienaam',
|
||||
'collections.enterCollectionName' => 'Voer collectienaam in',
|
||||
'collections.addedToCollection' => 'Toegevoegd aan collectie',
|
||||
|
||||
@@ -130,6 +130,7 @@ class _TranslationsCommonSv implements TranslationsCommonEn {
|
||||
@override String get delete => 'Ta bort';
|
||||
@override String get shuffle => 'Blanda';
|
||||
@override String get addTo => 'Lägg till i...';
|
||||
@override String get createNew => 'Skapa ny';
|
||||
@override String get remove => 'Ta bort';
|
||||
@override String get paste => 'Klistra in';
|
||||
@override String get connect => 'Anslut';
|
||||
@@ -506,7 +507,7 @@ class _TranslationsVideoControlsSv implements TranslationsVideoControlsEn {
|
||||
@override String get timelineSlider => 'Videotidslinje';
|
||||
@override String get volumeSlider => 'Volymnivå';
|
||||
@override String endsAt({required Object time}) => 'Slutar ${time}';
|
||||
@override String get pipActive => 'Playing in Picture-in-Picture';
|
||||
@override String get pipActive => 'Spelar i bild-i-bild';
|
||||
@override String get pipFailed => 'Bild-i-bild kunde inte starta';
|
||||
@override late final _TranslationsVideoControlsPipErrorsSv pipErrors = _TranslationsVideoControlsPipErrorsSv._(_root);
|
||||
@override String get chapters => 'Kapitel';
|
||||
@@ -888,7 +889,6 @@ class _TranslationsPlaylistsSv implements TranslationsPlaylistsEn {
|
||||
@override String get itemAdded => 'Tillagd i spellista';
|
||||
@override String get itemRemoved => 'Borttagen från spellista';
|
||||
@override String get selectPlaylist => 'Välj spellista';
|
||||
@override String get createNewPlaylist => 'Skapa ny spellista';
|
||||
@override String get errorCreating => 'Det gick inte att skapa spellista';
|
||||
@override String get errorDeleting => 'Det gick inte att ta bort spellista';
|
||||
@override String get errorLoading => 'Det gick inte att ladda spellistor';
|
||||
@@ -916,7 +916,6 @@ class _TranslationsCollectionsSv implements TranslationsCollectionsEn {
|
||||
@override String deleteFailedWithError({required Object error}) => 'Det gick inte att ta bort samlingen: ${error}';
|
||||
@override String failedToLoadItems({required Object error}) => 'Det gick inte att läsa in samlingsobjekt: ${error}';
|
||||
@override String get selectCollection => 'Välj samling';
|
||||
@override String get createNewCollection => 'Skapa ny samling';
|
||||
@override String get collectionName => 'Samlingsnamn';
|
||||
@override String get enterCollectionName => 'Ange samlingsnamn';
|
||||
@override String get addedToCollection => 'Tillagd i samling';
|
||||
@@ -1333,6 +1332,7 @@ extension on TranslationsSv {
|
||||
'common.delete' => 'Ta bort',
|
||||
'common.shuffle' => 'Blanda',
|
||||
'common.addTo' => 'Lägg till i...',
|
||||
'common.createNew' => 'Skapa ny',
|
||||
'common.remove' => 'Ta bort',
|
||||
'common.paste' => 'Klistra in',
|
||||
'common.connect' => 'Anslut',
|
||||
@@ -1628,7 +1628,7 @@ extension on TranslationsSv {
|
||||
'videoControls.timelineSlider' => 'Videotidslinje',
|
||||
'videoControls.volumeSlider' => 'Volymnivå',
|
||||
'videoControls.endsAt' => ({required Object time}) => 'Slutar ${time}',
|
||||
'videoControls.pipActive' => 'Playing in Picture-in-Picture',
|
||||
'videoControls.pipActive' => 'Spelar i bild-i-bild',
|
||||
'videoControls.pipFailed' => 'Bild-i-bild kunde inte starta',
|
||||
'videoControls.pipErrors.androidVersion' => 'Kräver Android 8.0 eller nyare',
|
||||
'videoControls.pipErrors.iosVersion' => 'Kräver iOS 15.0 eller nyare',
|
||||
@@ -1816,9 +1816,9 @@ extension on TranslationsSv {
|
||||
'liveTv.noChannels' => 'Inga kanaler tillgängliga',
|
||||
'liveTv.noDvr' => 'Ingen DVR konfigurerad på någon server',
|
||||
'liveTv.tuneFailed' => 'Kunde inte ställa in kanalen',
|
||||
'liveTv.loading' => 'Laddar kanaler...',
|
||||
_ => null,
|
||||
} ?? switch (path) {
|
||||
'liveTv.loading' => 'Laddar kanaler...',
|
||||
'liveTv.nowPlaying' => 'Spelas nu',
|
||||
'liveTv.noPrograms' => 'Ingen programdata tillgänglig',
|
||||
'liveTv.channelNumber' => ({required Object number}) => 'Kanal ${number}',
|
||||
@@ -1873,7 +1873,6 @@ extension on TranslationsSv {
|
||||
'playlists.itemAdded' => 'Tillagd i spellista',
|
||||
'playlists.itemRemoved' => 'Borttagen från spellista',
|
||||
'playlists.selectPlaylist' => 'Välj spellista',
|
||||
'playlists.createNewPlaylist' => 'Skapa ny spellista',
|
||||
'playlists.errorCreating' => 'Det gick inte att skapa spellista',
|
||||
'playlists.errorDeleting' => 'Det gick inte att ta bort spellista',
|
||||
'playlists.errorLoading' => 'Det gick inte att ladda spellistor',
|
||||
@@ -1892,7 +1891,6 @@ extension on TranslationsSv {
|
||||
'collections.deleteFailedWithError' => ({required Object error}) => 'Det gick inte att ta bort samlingen: ${error}',
|
||||
'collections.failedToLoadItems' => ({required Object error}) => 'Det gick inte att läsa in samlingsobjekt: ${error}',
|
||||
'collections.selectCollection' => 'Välj samling',
|
||||
'collections.createNewCollection' => 'Skapa ny samling',
|
||||
'collections.collectionName' => 'Samlingsnamn',
|
||||
'collections.enterCollectionName' => 'Ange samlingsnamn',
|
||||
'collections.addedToCollection' => 'Tillagd i samling',
|
||||
|
||||
@@ -130,6 +130,7 @@ class _TranslationsCommonZh implements TranslationsCommonEn {
|
||||
@override String get delete => '删除';
|
||||
@override String get shuffle => '随机播放';
|
||||
@override String get addTo => '添加到...';
|
||||
@override String get createNew => '新建';
|
||||
@override String get remove => '删除';
|
||||
@override String get paste => '粘贴';
|
||||
@override String get connect => '连接';
|
||||
@@ -506,7 +507,7 @@ class _TranslationsVideoControlsZh implements TranslationsVideoControlsEn {
|
||||
@override String get timelineSlider => '视频时间轴';
|
||||
@override String get volumeSlider => '音量调节';
|
||||
@override String endsAt({required Object time}) => '${time} 结束';
|
||||
@override String get pipActive => 'Playing in Picture-in-Picture';
|
||||
@override String get pipActive => '正在画中画模式中播放';
|
||||
@override String get pipFailed => '画中画启动失败';
|
||||
@override late final _TranslationsVideoControlsPipErrorsZh pipErrors = _TranslationsVideoControlsPipErrorsZh._(_root);
|
||||
@override String get chapters => '章节';
|
||||
@@ -888,7 +889,6 @@ class _TranslationsPlaylistsZh implements TranslationsPlaylistsEn {
|
||||
@override String get itemAdded => '已添加到播放列表';
|
||||
@override String get itemRemoved => '已从播放列表中移除';
|
||||
@override String get selectPlaylist => '选择播放列表';
|
||||
@override String get createNewPlaylist => '创建新播放列表';
|
||||
@override String get errorCreating => '创建播放列表失败';
|
||||
@override String get errorDeleting => '删除播放列表失败';
|
||||
@override String get errorLoading => '加载播放列表失败';
|
||||
@@ -916,7 +916,6 @@ class _TranslationsCollectionsZh implements TranslationsCollectionsEn {
|
||||
@override String deleteFailedWithError({required Object error}) => '删除合集失败:${error}';
|
||||
@override String failedToLoadItems({required Object error}) => '加载合集项目失败:${error}';
|
||||
@override String get selectCollection => '选择合集';
|
||||
@override String get createNewCollection => '创建新合集';
|
||||
@override String get collectionName => '合集名称';
|
||||
@override String get enterCollectionName => '输入合集名称';
|
||||
@override String get addedToCollection => '已添加到合集';
|
||||
@@ -1333,6 +1332,7 @@ extension on TranslationsZh {
|
||||
'common.delete' => '删除',
|
||||
'common.shuffle' => '随机播放',
|
||||
'common.addTo' => '添加到...',
|
||||
'common.createNew' => '新建',
|
||||
'common.remove' => '删除',
|
||||
'common.paste' => '粘贴',
|
||||
'common.connect' => '连接',
|
||||
@@ -1628,7 +1628,7 @@ extension on TranslationsZh {
|
||||
'videoControls.timelineSlider' => '视频时间轴',
|
||||
'videoControls.volumeSlider' => '音量调节',
|
||||
'videoControls.endsAt' => ({required Object time}) => '${time} 结束',
|
||||
'videoControls.pipActive' => 'Playing in Picture-in-Picture',
|
||||
'videoControls.pipActive' => '正在画中画模式中播放',
|
||||
'videoControls.pipFailed' => '画中画启动失败',
|
||||
'videoControls.pipErrors.androidVersion' => '需要 Android 8.0 或更高版本',
|
||||
'videoControls.pipErrors.iosVersion' => '需要 iOS 15.0 或更高版本',
|
||||
@@ -1816,9 +1816,9 @@ extension on TranslationsZh {
|
||||
'liveTv.noChannels' => '没有可用的频道',
|
||||
'liveTv.noDvr' => '没有服务器配置了DVR',
|
||||
'liveTv.tuneFailed' => '无法调谐频道',
|
||||
'liveTv.loading' => '正在加载频道...',
|
||||
_ => null,
|
||||
} ?? switch (path) {
|
||||
'liveTv.loading' => '正在加载频道...',
|
||||
'liveTv.nowPlaying' => '正在播放',
|
||||
'liveTv.noPrograms' => '没有可用的节目数据',
|
||||
'liveTv.channelNumber' => ({required Object number}) => '频道 ${number}',
|
||||
@@ -1873,7 +1873,6 @@ extension on TranslationsZh {
|
||||
'playlists.itemAdded' => '已添加到播放列表',
|
||||
'playlists.itemRemoved' => '已从播放列表中移除',
|
||||
'playlists.selectPlaylist' => '选择播放列表',
|
||||
'playlists.createNewPlaylist' => '创建新播放列表',
|
||||
'playlists.errorCreating' => '创建播放列表失败',
|
||||
'playlists.errorDeleting' => '删除播放列表失败',
|
||||
'playlists.errorLoading' => '加载播放列表失败',
|
||||
@@ -1892,7 +1891,6 @@ extension on TranslationsZh {
|
||||
'collections.deleteFailedWithError' => ({required Object error}) => '删除合集失败:${error}',
|
||||
'collections.failedToLoadItems' => ({required Object error}) => '加载合集项目失败:${error}',
|
||||
'collections.selectCollection' => '选择合集',
|
||||
'collections.createNewCollection' => '创建新合集',
|
||||
'collections.collectionName' => '合集名称',
|
||||
'collections.enterCollectionName' => '输入合集名称',
|
||||
'collections.addedToCollection' => '已添加到合集',
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
"delete": "Ta bort",
|
||||
"shuffle": "Blanda",
|
||||
"addTo": "Lägg till i...",
|
||||
"createNew": "Skapa ny",
|
||||
"remove": "Ta bort",
|
||||
"paste": "Klistra in",
|
||||
"connect": "Anslut",
|
||||
@@ -634,7 +635,6 @@
|
||||
"itemAdded": "Tillagd i spellista",
|
||||
"itemRemoved": "Borttagen från spellista",
|
||||
"selectPlaylist": "Välj spellista",
|
||||
"createNewPlaylist": "Skapa ny spellista",
|
||||
"errorCreating": "Det gick inte att skapa spellista",
|
||||
"errorDeleting": "Det gick inte att ta bort spellista",
|
||||
"errorLoading": "Det gick inte att ladda spellistor",
|
||||
@@ -655,7 +655,6 @@
|
||||
"deleteFailedWithError": "Det gick inte att ta bort samlingen: ${error}",
|
||||
"failedToLoadItems": "Det gick inte att läsa in samlingsobjekt: ${error}",
|
||||
"selectCollection": "Välj samling",
|
||||
"createNewCollection": "Skapa ny samling",
|
||||
"collectionName": "Samlingsnamn",
|
||||
"enterCollectionName": "Ange samlingsnamn",
|
||||
"addedToCollection": "Tillagd i samling",
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
"delete": "删除",
|
||||
"shuffle": "随机播放",
|
||||
"addTo": "添加到...",
|
||||
"createNew": "新建",
|
||||
"remove": "删除",
|
||||
"paste": "粘贴",
|
||||
"connect": "连接",
|
||||
@@ -634,7 +635,6 @@
|
||||
"itemAdded": "已添加到播放列表",
|
||||
"itemRemoved": "已从播放列表中移除",
|
||||
"selectPlaylist": "选择播放列表",
|
||||
"createNewPlaylist": "创建新播放列表",
|
||||
"errorCreating": "创建播放列表失败",
|
||||
"errorDeleting": "删除播放列表失败",
|
||||
"errorLoading": "加载播放列表失败",
|
||||
@@ -655,7 +655,6 @@
|
||||
"deleteFailedWithError": "删除合集失败:${error}",
|
||||
"failedToLoadItems": "加载合集项目失败:${error}",
|
||||
"selectCollection": "选择合集",
|
||||
"createNewCollection": "创建新合集",
|
||||
"collectionName": "合集名称",
|
||||
"enterCollectionName": "输入合集名称",
|
||||
"addedToCollection": "已添加到合集",
|
||||
|
||||
@@ -314,6 +314,7 @@ class MediaContextMenuState extends State<MediaContextMenu> {
|
||||
if (useBottomSheet) {
|
||||
selected = await OverlaySheetController.showAdaptive<String>(
|
||||
context,
|
||||
showDragHandle: true,
|
||||
builder: (context) => _FocusableContextMenuSheet(
|
||||
title: widget.item.title,
|
||||
actions: menuActions,
|
||||
@@ -576,7 +577,6 @@ class MediaContextMenuState extends State<MediaContextMenu> {
|
||||
await OverlaySheetController.showAdaptive(
|
||||
context,
|
||||
isScrollControlled: true,
|
||||
backgroundColor: Colors.transparent,
|
||||
builder: (context) => FileInfoBottomSheet(fileInfo: fileInfo, title: metadata.title),
|
||||
);
|
||||
} else if (context.mounted) {
|
||||
@@ -611,58 +611,27 @@ class MediaContextMenuState extends State<MediaContextMenu> {
|
||||
|
||||
/// Show submenu for Add to... (Playlist or Collection)
|
||||
Future<void> _showAddToSubmenu(BuildContext context) async {
|
||||
final useBottomSheet = Platform.isIOS || Platform.isAndroid;
|
||||
|
||||
final submenuActions = [
|
||||
_MenuAction(value: 'playlist', icon: Symbols.playlist_play_rounded, label: t.playlists.playlist),
|
||||
_MenuAction(value: 'collection', icon: Symbols.collections_rounded, label: t.collections.collection),
|
||||
];
|
||||
|
||||
String? selected;
|
||||
if (useBottomSheet) {
|
||||
selected = await OverlaySheetController.pushAdaptive<String>(
|
||||
context,
|
||||
builder: (context) => SafeArea(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Text(t.common.addTo, style: Theme.of(context).textTheme.titleMedium),
|
||||
),
|
||||
...submenuActions.map((action) {
|
||||
return ListTile(
|
||||
leading: AppIcon(action.icon, fill: 1),
|
||||
title: Text(action.label),
|
||||
onTap: () => OverlaySheetController.popAdaptive(context, action.value),
|
||||
);
|
||||
}),
|
||||
const SizedBox(height: 8),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
selected = await showMenu<String>(
|
||||
context: context,
|
||||
position: RelativeRect.fromLTRB(
|
||||
_tapPosition?.dx ?? 0,
|
||||
_tapPosition?.dy ?? 0,
|
||||
_tapPosition?.dx ?? 0,
|
||||
_tapPosition?.dy ?? 0,
|
||||
),
|
||||
items: submenuActions.map((action) {
|
||||
return PopupMenuItem<String>(
|
||||
value: action.value,
|
||||
final selected = await showDialog<String>(
|
||||
context: context,
|
||||
builder: (dialogContext) => SimpleDialog(
|
||||
title: Text(t.common.addTo),
|
||||
contentPadding: const EdgeInsets.symmetric(vertical: 8),
|
||||
children: submenuActions.map((action) {
|
||||
return SimpleDialogOption(
|
||||
onPressed: () => Navigator.pop(dialogContext, action.value),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [AppIcon(action.icon, fill: 1, size: 20), const SizedBox(width: 12), Text(action.label)],
|
||||
children: [AppIcon(action.icon, fill: 1, size: 24), const SizedBox(width: 16), Text(action.label, style: Theme.of(dialogContext).textTheme.bodyLarge)],
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
);
|
||||
}
|
||||
),
|
||||
);
|
||||
|
||||
// Handle the submenu selection
|
||||
if (selected == 'playlist' && context.mounted) {
|
||||
@@ -839,7 +808,7 @@ class MediaContextMenuState extends State<MediaContextMenu> {
|
||||
// Create new collection flow
|
||||
final collectionName = await showTextInputDialog(
|
||||
context,
|
||||
title: t.collections.createNewCollection,
|
||||
title: t.common.createNew,
|
||||
labelText: t.collections.collectionName,
|
||||
hintText: t.collections.enterCollectionName,
|
||||
);
|
||||
@@ -932,8 +901,9 @@ class MediaContextMenuState extends State<MediaContextMenu> {
|
||||
final currentStarValue = (metadata.userRating != null && metadata.userRating! > 0)
|
||||
? metadata.userRating! / 2.0
|
||||
: 0.0;
|
||||
await showModalBottomSheet(
|
||||
context: context,
|
||||
await OverlaySheetController.showAdaptive(
|
||||
context,
|
||||
showDragHandle: true,
|
||||
builder: (context) => RatingBottomSheet(
|
||||
currentRating: currentStarValue,
|
||||
onRate: (stars) async {
|
||||
@@ -1212,7 +1182,7 @@ class _PlaylistSelectionDialog extends StatelessWidget {
|
||||
// Create new playlist option (always shown first)
|
||||
return ListTile(
|
||||
leading: const AppIcon(Symbols.add_rounded, fill: 1),
|
||||
title: Text(t.playlists.createNewPlaylist),
|
||||
title: Text(t.common.createNew),
|
||||
onTap: () => Navigator.pop(context, '_create_new'),
|
||||
);
|
||||
}
|
||||
@@ -1266,7 +1236,7 @@ class _CollectionSelectionDialog extends StatelessWidget {
|
||||
// Create new collection option (always shown first)
|
||||
return ListTile(
|
||||
leading: const AppIcon(Symbols.add_rounded, fill: 1),
|
||||
title: Text(t.collections.createNewCollection),
|
||||
title: Text(t.common.createNew),
|
||||
onTap: () => Navigator.pop(context, '_create_new'),
|
||||
);
|
||||
}
|
||||
@@ -1325,7 +1295,7 @@ class _FocusableContextMenuSheetState extends State<_FocusableContextMenuSheet>
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
padding: const EdgeInsets.fromLTRB(16, 4, 16, 8),
|
||||
child: Text(
|
||||
widget.title,
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
|
||||
+124
-31
@@ -1,5 +1,6 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
@@ -60,6 +61,7 @@ class OverlaySheetController {
|
||||
bool barrierDismissible = true,
|
||||
FocusNode? initialFocusNode,
|
||||
Alignment alignment = Alignment.bottomCenter,
|
||||
bool showDragHandle = false,
|
||||
}) {
|
||||
return _state._show<T>(
|
||||
builder: builder,
|
||||
@@ -68,6 +70,7 @@ class OverlaySheetController {
|
||||
barrierDismissible: barrierDismissible,
|
||||
initialFocusNode: initialFocusNode,
|
||||
alignment: alignment,
|
||||
showDragHandle: showDragHandle,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -104,6 +107,7 @@ class OverlaySheetController {
|
||||
bool isScrollControlled = false,
|
||||
FocusNode? initialFocusNode,
|
||||
Alignment alignment = Alignment.bottomCenter,
|
||||
bool showDragHandle = false,
|
||||
}) {
|
||||
final controller = maybeOf(context);
|
||||
if (controller != null) {
|
||||
@@ -114,6 +118,7 @@ class OverlaySheetController {
|
||||
barrierDismissible: barrierDismissible,
|
||||
initialFocusNode: initialFocusNode,
|
||||
alignment: alignment,
|
||||
showDragHandle: showDragHandle,
|
||||
);
|
||||
}
|
||||
return showModalBottomSheet<T>(
|
||||
@@ -193,6 +198,7 @@ class _OverlaySheetHostState extends State<OverlaySheetHost> with SingleTickerPr
|
||||
bool _isOpen = false;
|
||||
bool _isClosing = false;
|
||||
bool _barrierDismissible = true;
|
||||
bool _showDragHandle = false;
|
||||
BoxConstraints? _constraints;
|
||||
Color? _explicitBackgroundColor;
|
||||
Alignment _alignment = Alignment.bottomCenter;
|
||||
@@ -200,6 +206,7 @@ class _OverlaySheetHostState extends State<OverlaySheetHost> with SingleTickerPr
|
||||
// Drag-to-dismiss state
|
||||
double _dragOffset = 0;
|
||||
bool _isDragging = false;
|
||||
final _sheetKey = GlobalKey();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -240,6 +247,7 @@ class _OverlaySheetHostState extends State<OverlaySheetHost> with SingleTickerPr
|
||||
bool barrierDismissible = true,
|
||||
FocusNode? initialFocusNode,
|
||||
Alignment alignment = Alignment.bottomCenter,
|
||||
bool showDragHandle = false,
|
||||
}) {
|
||||
// If already open, close first (instant)
|
||||
if (_isOpen) {
|
||||
@@ -260,6 +268,7 @@ class _OverlaySheetHostState extends State<OverlaySheetHost> with SingleTickerPr
|
||||
_isOpen = true;
|
||||
_isClosing = false;
|
||||
_barrierDismissible = barrierDismissible;
|
||||
_showDragHandle = showDragHandle;
|
||||
_constraints = constraints;
|
||||
_explicitBackgroundColor = backgroundColor;
|
||||
_alignment = alignment;
|
||||
@@ -458,10 +467,28 @@ class _OverlaySheetHostState extends State<OverlaySheetHost> with SingleTickerPr
|
||||
);
|
||||
}
|
||||
|
||||
double _getSheetHeight() {
|
||||
final renderBox = _sheetKey.currentContext?.findRenderObject() as RenderBox?;
|
||||
return renderBox?.size.height ?? 300;
|
||||
}
|
||||
|
||||
void _checkDismiss(double velocity) {
|
||||
final sheetHeight = _getSheetHeight();
|
||||
if (_dragOffset > sheetHeight * 0.25 || velocity > 500) {
|
||||
_close();
|
||||
} else {
|
||||
setState(() {
|
||||
_dragOffset = 0;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Widget _buildSheet(BuildContext context) {
|
||||
final size = MediaQuery.of(context).size;
|
||||
final isDesktop = size.width > 600;
|
||||
final isTop = _alignment.y < 0;
|
||||
final isTV = PlatformDetector.isTV();
|
||||
final showHandle = _showDragHandle && !isTV && !isTop;
|
||||
|
||||
final effectiveConstraints =
|
||||
_constraints ??
|
||||
@@ -473,6 +500,73 @@ class _OverlaySheetHostState extends State<OverlaySheetHost> with SingleTickerPr
|
||||
? const BorderRadius.vertical(bottom: Radius.circular(16))
|
||||
: const BorderRadius.vertical(top: Radius.circular(16));
|
||||
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
|
||||
Widget content = _pageStack.isNotEmpty ? _pageStack.last.builder(context) : const SizedBox.shrink();
|
||||
|
||||
// Wrap content in NotificationListener for scroll-aware drag-to-dismiss
|
||||
if (showHandle) {
|
||||
content = NotificationListener<ScrollNotification>(
|
||||
onNotification: (notification) {
|
||||
if (notification is OverscrollNotification) {
|
||||
// Android (ClampingScrollPhysics): overscroll fires reliably
|
||||
if (notification.overscroll < 0) {
|
||||
setState(() {
|
||||
_dragOffset += -notification.overscroll;
|
||||
});
|
||||
return true;
|
||||
}
|
||||
} else if (notification is ScrollUpdateNotification) {
|
||||
// iOS (BouncingScrollPhysics): pixels go negative when bouncing past top
|
||||
if (notification.metrics.pixels < 0) {
|
||||
setState(() {
|
||||
_dragOffset = -notification.metrics.pixels;
|
||||
});
|
||||
return true;
|
||||
}
|
||||
// If user scrolled back down from overscroll, reset drag offset
|
||||
if (_dragOffset > 0 && notification.metrics.pixels >= 0) {
|
||||
setState(() {
|
||||
_dragOffset = 0;
|
||||
});
|
||||
}
|
||||
} else if (notification is ScrollEndNotification) {
|
||||
if (_dragOffset > 0) {
|
||||
_checkDismiss(0);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
child: content,
|
||||
);
|
||||
}
|
||||
|
||||
// Build the sheet content column (handle + content)
|
||||
Widget sheetContent;
|
||||
if (showHandle) {
|
||||
sheetContent = Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
// M3 drag handle: 32x4, rounded, with 12dp top / 4dp bottom margin
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 12, bottom: 4),
|
||||
child: Container(
|
||||
width: 32,
|
||||
height: 4,
|
||||
decoration: BoxDecoration(
|
||||
color: colorScheme.onSurfaceVariant.withValues(alpha: 0.4),
|
||||
borderRadius: const BorderRadius.all(Radius.circular(2)),
|
||||
),
|
||||
),
|
||||
),
|
||||
Flexible(child: content),
|
||||
],
|
||||
);
|
||||
} else {
|
||||
sheetContent = content;
|
||||
}
|
||||
|
||||
Widget sheet = FocusScope(
|
||||
node: _sheetFocusScopeNode,
|
||||
child: Focus(
|
||||
@@ -493,15 +587,16 @@ class _OverlaySheetHostState extends State<OverlaySheetHost> with SingleTickerPr
|
||||
child: Transform.translate(
|
||||
offset: Offset(0, _dragOffset.clamp(0, double.infinity)),
|
||||
child: Material(
|
||||
color: _explicitBackgroundColor ?? Theme.of(context).colorScheme.surface,
|
||||
key: _sheetKey,
|
||||
color: _explicitBackgroundColor ?? colorScheme.surface,
|
||||
borderRadius: borderRadius,
|
||||
clipBehavior: Clip.antiAlias,
|
||||
child: SafeArea(
|
||||
top: !isTop,
|
||||
bottom: isTop,
|
||||
top: isTop,
|
||||
bottom: !isTop,
|
||||
child: ConstrainedBox(
|
||||
constraints: effectiveConstraints,
|
||||
child: _pageStack.isNotEmpty ? _pageStack.last.builder(context) : const SizedBox.shrink(),
|
||||
child: sheetContent,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -511,33 +606,31 @@ class _OverlaySheetHostState extends State<OverlaySheetHost> with SingleTickerPr
|
||||
),
|
||||
);
|
||||
|
||||
// Swipe-down-to-dismiss (skip on TV and for top-aligned sheets)
|
||||
if (!PlatformDetector.isTV() && !isTop) {
|
||||
sheet = GestureDetector(
|
||||
onVerticalDragStart: (_) {
|
||||
_isDragging = true;
|
||||
_dragOffset = 0;
|
||||
},
|
||||
onVerticalDragUpdate: (details) {
|
||||
if (!_isDragging) return;
|
||||
setState(() {
|
||||
_dragOffset += details.delta.dy;
|
||||
});
|
||||
},
|
||||
onVerticalDragEnd: (details) {
|
||||
if (!_isDragging) return;
|
||||
_isDragging = false;
|
||||
|
||||
final sheetHeight = effectiveConstraints.minHeight;
|
||||
final velocity = details.primaryVelocity ?? 0;
|
||||
|
||||
if (_dragOffset > sheetHeight * 0.25 || velocity > 500) {
|
||||
_close();
|
||||
} else {
|
||||
setState(() {
|
||||
_dragOffset = 0;
|
||||
});
|
||||
}
|
||||
// Swipe-down-to-dismiss on non-scrollable areas (skip on TV and top-aligned)
|
||||
if (showHandle) {
|
||||
sheet = RawGestureDetector(
|
||||
gestures: <Type, GestureRecognizerFactory>{
|
||||
VerticalDragGestureRecognizer: GestureRecognizerFactoryWithHandlers<VerticalDragGestureRecognizer>(
|
||||
() => VerticalDragGestureRecognizer()..onlyAcceptDragOnThreshold = true,
|
||||
(instance) {
|
||||
instance
|
||||
..onStart = (_) {
|
||||
_isDragging = true;
|
||||
_dragOffset = 0;
|
||||
}
|
||||
..onUpdate = (details) {
|
||||
if (!_isDragging) return;
|
||||
setState(() {
|
||||
_dragOffset += details.delta.dy;
|
||||
});
|
||||
}
|
||||
..onEnd = (details) {
|
||||
if (!_isDragging) return;
|
||||
_isDragging = false;
|
||||
_checkDismiss(details.primaryVelocity ?? 0);
|
||||
};
|
||||
},
|
||||
),
|
||||
},
|
||||
child: sheet,
|
||||
);
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
import '../widgets/app_icon.dart';
|
||||
import '../widgets/overlay_sheet.dart';
|
||||
import '../focus/dpad_navigator.dart';
|
||||
import '../i18n/strings.g.dart';
|
||||
|
||||
@@ -44,116 +45,105 @@ class _RatingBottomSheetState extends State<RatingBottomSheet> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
return SafeArea(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(24, 16, 24, 24),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Container(
|
||||
width: 32,
|
||||
height: 4,
|
||||
decoration: BoxDecoration(
|
||||
color: theme.colorScheme.onSurfaceVariant.withValues(alpha: 0.4),
|
||||
borderRadius: const BorderRadius.all(Radius.circular(2)),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Text(
|
||||
_selectedRating > 0
|
||||
? '${formatRating(_selectedRating)} / 5'
|
||||
: t.mediaMenu.rate,
|
||||
style: theme.textTheme.titleMedium,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Focus(
|
||||
focusNode: _starsFocusNode,
|
||||
autofocus: true,
|
||||
onKeyEvent: _handleStarsKeyEvent,
|
||||
child: LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
final starSize = (constraints.maxWidth / 5).clamp(0.0, 48.0);
|
||||
return GestureDetector(
|
||||
onTapDown: (details) => _handleStarTap(details.localPosition.dx, starSize),
|
||||
onPanUpdate: (details) => _handleStarTap(details.localPosition.dx, starSize),
|
||||
child: AnimatedBuilder(
|
||||
animation: _starsFocusNode,
|
||||
builder: (context, child) {
|
||||
final hasFocus = _starsFocusNode.hasFocus;
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(12)),
|
||||
color: hasFocus
|
||||
? theme.colorScheme.primary.withValues(alpha: 0.12)
|
||||
: null,
|
||||
),
|
||||
child: child,
|
||||
);
|
||||
},
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: List.generate(5, (i) {
|
||||
final starIndex = i + 1;
|
||||
final IconData icon;
|
||||
if (_selectedRating >= starIndex) {
|
||||
icon = Symbols.star_rounded;
|
||||
} else if (_selectedRating >= starIndex - 0.5) {
|
||||
icon = Symbols.star_half_rounded;
|
||||
} else {
|
||||
icon = Symbols.star_rounded;
|
||||
}
|
||||
return SizedBox(
|
||||
width: starSize,
|
||||
height: starSize,
|
||||
child: Center(
|
||||
child: AppIcon(
|
||||
icon,
|
||||
fill: _selectedRating >= starIndex - 0.5 ? 1 : 0,
|
||||
color: _selectedRating >= starIndex - 0.5
|
||||
? Colors.amber
|
||||
: theme.colorScheme.onSurfaceVariant.withValues(alpha: 0.3),
|
||||
size: starSize * 0.8,
|
||||
),
|
||||
return Padding(
|
||||
padding: const EdgeInsets.fromLTRB(24, 4, 24, 24),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
_selectedRating > 0
|
||||
? '${formatRating(_selectedRating)} / 5'
|
||||
: t.mediaMenu.rate,
|
||||
style: theme.textTheme.titleMedium,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Focus(
|
||||
focusNode: _starsFocusNode,
|
||||
autofocus: true,
|
||||
onKeyEvent: _handleStarsKeyEvent,
|
||||
child: LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
final starSize = (constraints.maxWidth / 5).clamp(0.0, 48.0);
|
||||
return GestureDetector(
|
||||
onTapDown: (details) => _handleStarTap(details.localPosition.dx, starSize),
|
||||
onPanUpdate: (details) => _handleStarTap(details.localPosition.dx, starSize),
|
||||
child: AnimatedBuilder(
|
||||
animation: _starsFocusNode,
|
||||
builder: (context, child) {
|
||||
final hasFocus = _starsFocusNode.hasFocus;
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(12)),
|
||||
color: hasFocus
|
||||
? theme.colorScheme.primary.withValues(alpha: 0.12)
|
||||
: null,
|
||||
),
|
||||
child: child,
|
||||
);
|
||||
},
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: List.generate(5, (i) {
|
||||
final starIndex = i + 1;
|
||||
final IconData icon;
|
||||
if (_selectedRating >= starIndex) {
|
||||
icon = Symbols.star_rounded;
|
||||
} else if (_selectedRating >= starIndex - 0.5) {
|
||||
icon = Symbols.star_half_rounded;
|
||||
} else {
|
||||
icon = Symbols.star_rounded;
|
||||
}
|
||||
return SizedBox(
|
||||
width: starSize,
|
||||
height: starSize,
|
||||
child: Center(
|
||||
child: AppIcon(
|
||||
icon,
|
||||
fill: _selectedRating >= starIndex - 0.5 ? 1 : 0,
|
||||
color: _selectedRating >= starIndex - 0.5
|
||||
? Colors.amber
|
||||
: theme.colorScheme.onSurfaceVariant.withValues(alpha: 0.3),
|
||||
size: starSize * 0.8,
|
||||
),
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Row(
|
||||
children: [
|
||||
if (widget.currentRating > 0)
|
||||
Expanded(
|
||||
child: OutlinedButton(
|
||||
onPressed: () {
|
||||
widget.onClear();
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: Text(t.common.clear),
|
||||
),
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
if (widget.currentRating > 0) const SizedBox(width: 12),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Row(
|
||||
children: [
|
||||
if (widget.currentRating > 0)
|
||||
Expanded(
|
||||
child: FilledButton(
|
||||
onPressed: _selectedRating > 0
|
||||
? () {
|
||||
widget.onRate(_selectedRating);
|
||||
Navigator.pop(context);
|
||||
}
|
||||
: null,
|
||||
child: Text(t.mediaMenu.rate),
|
||||
child: OutlinedButton(
|
||||
onPressed: () {
|
||||
widget.onClear();
|
||||
OverlaySheetController.closeAdaptive(context);
|
||||
},
|
||||
child: Text(t.common.clear),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
if (widget.currentRating > 0) const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: FilledButton(
|
||||
onPressed: _selectedRating > 0
|
||||
? () {
|
||||
widget.onRate(_selectedRating);
|
||||
OverlaySheetController.closeAdaptive(context);
|
||||
}
|
||||
: null,
|
||||
child: Text(t.mediaMenu.rate),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -177,7 +167,7 @@ class _RatingBottomSheetState extends State<RatingBottomSheet> {
|
||||
if (key == LogicalKeyboardKey.select || key == LogicalKeyboardKey.enter) {
|
||||
if (_selectedRating > 0) {
|
||||
widget.onRate(_selectedRating);
|
||||
Navigator.pop(context);
|
||||
OverlaySheetController.closeAdaptive(context);
|
||||
}
|
||||
return KeyEventResult.handled;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user