fix: file info bitrate units, multi-track display, tv scrolling
close #840, close #841
This commit is contained in:
@@ -287,6 +287,8 @@
|
||||
"colorPrimaries": "Farveprimærer",
|
||||
"chromaSubsampling": "Chroma-subsampling",
|
||||
"channels": "Kanaler",
|
||||
"subtitles": "Undertekster",
|
||||
"overallBitrate": "Samlet bitrate",
|
||||
"path": "Sti",
|
||||
"size": "Størrelse",
|
||||
"container": "Container",
|
||||
|
||||
@@ -287,6 +287,8 @@
|
||||
"colorPrimaries": "Primärfarben",
|
||||
"chromaSubsampling": "Chroma-Subsampling",
|
||||
"channels": "Kanäle",
|
||||
"subtitles": "Untertitel",
|
||||
"overallBitrate": "Gesamt-Bitrate",
|
||||
"path": "Pfad",
|
||||
"size": "Größe",
|
||||
"container": "Container",
|
||||
|
||||
@@ -287,6 +287,8 @@
|
||||
"colorPrimaries": "Color Primaries",
|
||||
"chromaSubsampling": "Chroma Subsampling",
|
||||
"channels": "Channels",
|
||||
"subtitles": "Subtitles",
|
||||
"overallBitrate": "Overall Bitrate",
|
||||
"path": "Path",
|
||||
"size": "Size",
|
||||
"container": "Container",
|
||||
|
||||
@@ -287,6 +287,8 @@
|
||||
"colorPrimaries": "Primarias de color",
|
||||
"chromaSubsampling": "Submuestreo de croma",
|
||||
"channels": "Canales",
|
||||
"subtitles": "Subtítulos",
|
||||
"overallBitrate": "Bitrate total",
|
||||
"path": "Ruta",
|
||||
"size": "Tamaño",
|
||||
"container": "Contenedor",
|
||||
|
||||
@@ -287,6 +287,8 @@
|
||||
"colorPrimaries": "Couleurs primaires",
|
||||
"chromaSubsampling": "Sous-échantillonnage chromatique",
|
||||
"channels": "Canaux",
|
||||
"subtitles": "Sous-titres",
|
||||
"overallBitrate": "Débit global",
|
||||
"path": "Chemin",
|
||||
"size": "Taille",
|
||||
"container": "Conteneur",
|
||||
|
||||
@@ -287,6 +287,8 @@
|
||||
"colorPrimaries": "Colori primari",
|
||||
"chromaSubsampling": "Sottocampionamento cromatico",
|
||||
"channels": "Canali",
|
||||
"subtitles": "Sottotitoli",
|
||||
"overallBitrate": "Bitrate complessivo",
|
||||
"path": "Percorso",
|
||||
"size": "Dimensione",
|
||||
"container": "Contenitore",
|
||||
|
||||
@@ -287,6 +287,8 @@
|
||||
"colorPrimaries": "色原色",
|
||||
"chromaSubsampling": "クロマサブサンプリング",
|
||||
"channels": "チャンネル",
|
||||
"subtitles": "字幕",
|
||||
"overallBitrate": "全体ビットレート",
|
||||
"path": "パス",
|
||||
"size": "サイズ",
|
||||
"container": "コンテナ",
|
||||
|
||||
@@ -287,6 +287,8 @@
|
||||
"colorPrimaries": "색상 원색",
|
||||
"chromaSubsampling": "채도 서브샘플링",
|
||||
"channels": "채널",
|
||||
"subtitles": "자막",
|
||||
"overallBitrate": "전체 비트레이트",
|
||||
"path": "경로",
|
||||
"size": "크기",
|
||||
"container": "컨테이너",
|
||||
|
||||
@@ -287,6 +287,8 @@
|
||||
"colorPrimaries": "Fargeprimærer",
|
||||
"chromaSubsampling": "Krominansnedsampling",
|
||||
"channels": "Kanaler",
|
||||
"subtitles": "Undertekster",
|
||||
"overallBitrate": "Total bitrate",
|
||||
"path": "Sti",
|
||||
"size": "Størrelse",
|
||||
"container": "Beholder",
|
||||
|
||||
@@ -287,6 +287,8 @@
|
||||
"colorPrimaries": "Kleurprimaires",
|
||||
"chromaSubsampling": "Chroma subsampling",
|
||||
"channels": "Kanalen",
|
||||
"subtitles": "Ondertitels",
|
||||
"overallBitrate": "Totale bitrate",
|
||||
"path": "Pad",
|
||||
"size": "Grootte",
|
||||
"container": "Container",
|
||||
|
||||
@@ -287,6 +287,8 @@
|
||||
"colorPrimaries": "Kolory podstawowe",
|
||||
"chromaSubsampling": "Subsampling chrominancji",
|
||||
"channels": "Kanały",
|
||||
"subtitles": "Napisy",
|
||||
"overallBitrate": "Całkowity bitrate",
|
||||
"path": "Ścieżka",
|
||||
"size": "Rozmiar",
|
||||
"container": "Kontener",
|
||||
|
||||
@@ -287,6 +287,8 @@
|
||||
"colorPrimaries": "Primárias de Cor",
|
||||
"chromaSubsampling": "Subamostragem de Croma",
|
||||
"channels": "Canais",
|
||||
"subtitles": "Legendas",
|
||||
"overallBitrate": "Taxa de bits total",
|
||||
"path": "Caminho",
|
||||
"size": "Tamanho",
|
||||
"container": "Container",
|
||||
|
||||
@@ -287,6 +287,8 @@
|
||||
"colorPrimaries": "Цветовые первичные",
|
||||
"chromaSubsampling": "Субдискретизация цветности",
|
||||
"channels": "Каналы",
|
||||
"subtitles": "Субтитры",
|
||||
"overallBitrate": "Общий битрейт",
|
||||
"path": "Путь",
|
||||
"size": "Размер",
|
||||
"container": "Контейнер",
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
/// To regenerate, run: `dart run slang`
|
||||
///
|
||||
/// Locales: 15
|
||||
/// Strings: 12945 (863 per locale)
|
||||
/// Strings: 12975 (865 per locale)
|
||||
///
|
||||
/// Built on 2026-04-10 at 16:32 UTC
|
||||
/// Built on 2026-04-11 at 05:59 UTC
|
||||
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: type=lint, unused_import
|
||||
|
||||
@@ -407,6 +407,8 @@ class _TranslationsFileInfoDa implements TranslationsFileInfoEn {
|
||||
@override String get colorPrimaries => 'Farveprimærer';
|
||||
@override String get chromaSubsampling => 'Chroma-subsampling';
|
||||
@override String get channels => 'Kanaler';
|
||||
@override String get subtitles => 'Undertekster';
|
||||
@override String get overallBitrate => 'Samlet bitrate';
|
||||
@override String get path => 'Sti';
|
||||
@override String get size => 'Størrelse';
|
||||
@override String get container => 'Container';
|
||||
@@ -1629,6 +1631,8 @@ extension on TranslationsDa {
|
||||
'fileInfo.colorPrimaries' => 'Farveprimærer',
|
||||
'fileInfo.chromaSubsampling' => 'Chroma-subsampling',
|
||||
'fileInfo.channels' => 'Kanaler',
|
||||
'fileInfo.subtitles' => 'Undertekster',
|
||||
'fileInfo.overallBitrate' => 'Samlet bitrate',
|
||||
'fileInfo.path' => 'Sti',
|
||||
'fileInfo.size' => 'Størrelse',
|
||||
'fileInfo.container' => 'Container',
|
||||
@@ -1870,10 +1874,10 @@ extension on TranslationsDa {
|
||||
'about.versionLabel' => ({required Object version}) => 'Version ${version}',
|
||||
'about.appDescription' => 'En smuk Plex-klient til Flutter',
|
||||
'about.viewLicensesDescription' => 'Se licenser for tredjepartsbiblioteker',
|
||||
'serverSelection.allServerConnectionsFailed' => 'Kunne ikke forbinde til nogen servere. Tjek dit netværk og prøv igen.',
|
||||
'serverSelection.noServersFoundForAccount' => ({required Object username, required Object email}) => 'Ingen servere fundet for ${username} (${email})',
|
||||
_ => null,
|
||||
} ?? switch (path) {
|
||||
'serverSelection.allServerConnectionsFailed' => 'Kunne ikke forbinde til nogen servere. Tjek dit netværk og prøv igen.',
|
||||
'serverSelection.noServersFoundForAccount' => ({required Object username, required Object email}) => 'Ingen servere fundet for ${username} (${email})',
|
||||
'serverSelection.failedToLoadServers' => ({required Object error}) => 'Kunne ikke indlæse servere: ${error}',
|
||||
'hubDetail.title' => 'Titel',
|
||||
'hubDetail.releaseYear' => 'Udgivelsesår',
|
||||
|
||||
@@ -407,6 +407,8 @@ class _TranslationsFileInfoDe implements TranslationsFileInfoEn {
|
||||
@override String get colorPrimaries => 'Primärfarben';
|
||||
@override String get chromaSubsampling => 'Chroma-Subsampling';
|
||||
@override String get channels => 'Kanäle';
|
||||
@override String get subtitles => 'Untertitel';
|
||||
@override String get overallBitrate => 'Gesamt-Bitrate';
|
||||
@override String get path => 'Pfad';
|
||||
@override String get size => 'Größe';
|
||||
@override String get container => 'Container';
|
||||
@@ -1629,6 +1631,8 @@ extension on TranslationsDe {
|
||||
'fileInfo.colorPrimaries' => 'Primärfarben',
|
||||
'fileInfo.chromaSubsampling' => 'Chroma-Subsampling',
|
||||
'fileInfo.channels' => 'Kanäle',
|
||||
'fileInfo.subtitles' => 'Untertitel',
|
||||
'fileInfo.overallBitrate' => 'Gesamt-Bitrate',
|
||||
'fileInfo.path' => 'Pfad',
|
||||
'fileInfo.size' => 'Größe',
|
||||
'fileInfo.container' => 'Container',
|
||||
@@ -1870,10 +1874,10 @@ extension on TranslationsDe {
|
||||
'about.versionLabel' => ({required Object version}) => 'Version ${version}',
|
||||
'about.appDescription' => 'Ein schöner Plex-Client für Flutter',
|
||||
'about.viewLicensesDescription' => 'Lizenzen von Drittanbieter-Bibliotheken anzeigen',
|
||||
'serverSelection.allServerConnectionsFailed' => 'Verbindung zu allen Servern fehlgeschlagen. Bitte Netzwerk prüfen und erneut versuchen.',
|
||||
'serverSelection.noServersFoundForAccount' => ({required Object username, required Object email}) => 'Keine Server gefunden für ${username} (${email})',
|
||||
_ => null,
|
||||
} ?? switch (path) {
|
||||
'serverSelection.allServerConnectionsFailed' => 'Verbindung zu allen Servern fehlgeschlagen. Bitte Netzwerk prüfen und erneut versuchen.',
|
||||
'serverSelection.noServersFoundForAccount' => ({required Object username, required Object email}) => 'Keine Server gefunden für ${username} (${email})',
|
||||
'serverSelection.failedToLoadServers' => ({required Object error}) => 'Server konnten nicht geladen werden: ${error}',
|
||||
'hubDetail.title' => 'Titel',
|
||||
'hubDetail.releaseYear' => 'Erscheinungsjahr',
|
||||
|
||||
@@ -912,6 +912,12 @@ class TranslationsFileInfoEn {
|
||||
/// en: 'Channels'
|
||||
String get channels => 'Channels';
|
||||
|
||||
/// en: 'Subtitles'
|
||||
String get subtitles => 'Subtitles';
|
||||
|
||||
/// en: 'Overall Bitrate'
|
||||
String get overallBitrate => 'Overall Bitrate';
|
||||
|
||||
/// en: 'Path'
|
||||
String get path => 'Path';
|
||||
|
||||
@@ -3362,6 +3368,8 @@ extension on Translations {
|
||||
'fileInfo.colorPrimaries' => 'Color Primaries',
|
||||
'fileInfo.chromaSubsampling' => 'Chroma Subsampling',
|
||||
'fileInfo.channels' => 'Channels',
|
||||
'fileInfo.subtitles' => 'Subtitles',
|
||||
'fileInfo.overallBitrate' => 'Overall Bitrate',
|
||||
'fileInfo.path' => 'Path',
|
||||
'fileInfo.size' => 'Size',
|
||||
'fileInfo.container' => 'Container',
|
||||
@@ -3603,10 +3611,10 @@ extension on Translations {
|
||||
'about.versionLabel' => ({required Object version}) => 'Version ${version}',
|
||||
'about.appDescription' => 'A beautiful Plex client for Flutter',
|
||||
'about.viewLicensesDescription' => 'View licenses of third-party libraries',
|
||||
'serverSelection.allServerConnectionsFailed' => 'Failed to connect to any servers. Please check your network and try again.',
|
||||
'serverSelection.noServersFoundForAccount' => ({required Object username, required Object email}) => 'No servers found for ${username} (${email})',
|
||||
_ => null,
|
||||
} ?? switch (path) {
|
||||
'serverSelection.allServerConnectionsFailed' => 'Failed to connect to any servers. Please check your network and try again.',
|
||||
'serverSelection.noServersFoundForAccount' => ({required Object username, required Object email}) => 'No servers found for ${username} (${email})',
|
||||
'serverSelection.failedToLoadServers' => ({required Object error}) => 'Failed to load servers: ${error}',
|
||||
'hubDetail.title' => 'Title',
|
||||
'hubDetail.releaseYear' => 'Release Year',
|
||||
|
||||
@@ -407,6 +407,8 @@ class _TranslationsFileInfoEs implements TranslationsFileInfoEn {
|
||||
@override String get colorPrimaries => 'Primarias de color';
|
||||
@override String get chromaSubsampling => 'Submuestreo de croma';
|
||||
@override String get channels => 'Canales';
|
||||
@override String get subtitles => 'Subtítulos';
|
||||
@override String get overallBitrate => 'Bitrate total';
|
||||
@override String get path => 'Ruta';
|
||||
@override String get size => 'Tamaño';
|
||||
@override String get container => 'Contenedor';
|
||||
@@ -1629,6 +1631,8 @@ extension on TranslationsEs {
|
||||
'fileInfo.colorPrimaries' => 'Primarias de color',
|
||||
'fileInfo.chromaSubsampling' => 'Submuestreo de croma',
|
||||
'fileInfo.channels' => 'Canales',
|
||||
'fileInfo.subtitles' => 'Subtítulos',
|
||||
'fileInfo.overallBitrate' => 'Bitrate total',
|
||||
'fileInfo.path' => 'Ruta',
|
||||
'fileInfo.size' => 'Tamaño',
|
||||
'fileInfo.container' => 'Contenedor',
|
||||
@@ -1870,10 +1874,10 @@ extension on TranslationsEs {
|
||||
'about.versionLabel' => ({required Object version}) => 'Versión ${version}',
|
||||
'about.appDescription' => 'Un cliente de Plex para Flutter',
|
||||
'about.viewLicensesDescription' => 'Ver licencias de librerías de terceros',
|
||||
'serverSelection.allServerConnectionsFailed' => 'No se pudo conectar con ningún servidor. Por favor, comprueba tu conexión e inténtalo de nuevo.',
|
||||
'serverSelection.noServersFoundForAccount' => ({required Object username, required Object email}) => 'No se encontraron servidores para ${username} (${email})',
|
||||
_ => null,
|
||||
} ?? switch (path) {
|
||||
'serverSelection.allServerConnectionsFailed' => 'No se pudo conectar con ningún servidor. Por favor, comprueba tu conexión e inténtalo de nuevo.',
|
||||
'serverSelection.noServersFoundForAccount' => ({required Object username, required Object email}) => 'No se encontraron servidores para ${username} (${email})',
|
||||
'serverSelection.failedToLoadServers' => ({required Object error}) => 'Error al cargar servidores: ${error}',
|
||||
'hubDetail.title' => 'Título',
|
||||
'hubDetail.releaseYear' => 'Año de lanzamiento',
|
||||
|
||||
@@ -407,6 +407,8 @@ class _TranslationsFileInfoFr implements TranslationsFileInfoEn {
|
||||
@override String get colorPrimaries => 'Couleurs primaires';
|
||||
@override String get chromaSubsampling => 'Sous-échantillonnage chromatique';
|
||||
@override String get channels => 'Canaux';
|
||||
@override String get subtitles => 'Sous-titres';
|
||||
@override String get overallBitrate => 'Débit global';
|
||||
@override String get path => 'Chemin';
|
||||
@override String get size => 'Taille';
|
||||
@override String get container => 'Conteneur';
|
||||
@@ -1629,6 +1631,8 @@ extension on TranslationsFr {
|
||||
'fileInfo.colorPrimaries' => 'Couleurs primaires',
|
||||
'fileInfo.chromaSubsampling' => 'Sous-échantillonnage chromatique',
|
||||
'fileInfo.channels' => 'Canaux',
|
||||
'fileInfo.subtitles' => 'Sous-titres',
|
||||
'fileInfo.overallBitrate' => 'Débit global',
|
||||
'fileInfo.path' => 'Chemin',
|
||||
'fileInfo.size' => 'Taille',
|
||||
'fileInfo.container' => 'Conteneur',
|
||||
@@ -1870,10 +1874,10 @@ extension on TranslationsFr {
|
||||
'about.versionLabel' => ({required Object version}) => 'Version ${version}',
|
||||
'about.appDescription' => 'Un magnifique client Plex pour Flutter',
|
||||
'about.viewLicensesDescription' => 'Afficher les licences des bibliothèques tierces',
|
||||
'serverSelection.allServerConnectionsFailed' => 'Impossible de se connecter à un serveur. Veuillez vérifier votre connexion réseau et réessayer.',
|
||||
'serverSelection.noServersFoundForAccount' => ({required Object username, required Object email}) => 'Aucun serveur trouvé pour ${username} (${email})',
|
||||
_ => null,
|
||||
} ?? switch (path) {
|
||||
'serverSelection.allServerConnectionsFailed' => 'Impossible de se connecter à un serveur. Veuillez vérifier votre connexion réseau et réessayer.',
|
||||
'serverSelection.noServersFoundForAccount' => ({required Object username, required Object email}) => 'Aucun serveur trouvé pour ${username} (${email})',
|
||||
'serverSelection.failedToLoadServers' => ({required Object error}) => 'Échec du chargement des serveurs: ${error}',
|
||||
'hubDetail.title' => 'Titre',
|
||||
'hubDetail.releaseYear' => 'Année de sortie',
|
||||
|
||||
@@ -407,6 +407,8 @@ class _TranslationsFileInfoIt implements TranslationsFileInfoEn {
|
||||
@override String get colorPrimaries => 'Colori primari';
|
||||
@override String get chromaSubsampling => 'Sottocampionamento cromatico';
|
||||
@override String get channels => 'Canali';
|
||||
@override String get subtitles => 'Sottotitoli';
|
||||
@override String get overallBitrate => 'Bitrate complessivo';
|
||||
@override String get path => 'Percorso';
|
||||
@override String get size => 'Dimensione';
|
||||
@override String get container => 'Contenitore';
|
||||
@@ -1629,6 +1631,8 @@ extension on TranslationsIt {
|
||||
'fileInfo.colorPrimaries' => 'Colori primari',
|
||||
'fileInfo.chromaSubsampling' => 'Sottocampionamento cromatico',
|
||||
'fileInfo.channels' => 'Canali',
|
||||
'fileInfo.subtitles' => 'Sottotitoli',
|
||||
'fileInfo.overallBitrate' => 'Bitrate complessivo',
|
||||
'fileInfo.path' => 'Percorso',
|
||||
'fileInfo.size' => 'Dimensione',
|
||||
'fileInfo.container' => 'Contenitore',
|
||||
@@ -1870,10 +1874,10 @@ extension on TranslationsIt {
|
||||
'about.versionLabel' => ({required Object version}) => 'Versione ${version}',
|
||||
'about.appDescription' => 'Un bellissimo client Plex per Flutter',
|
||||
'about.viewLicensesDescription' => 'Visualizza le licenze delle librerie di terze parti',
|
||||
'serverSelection.allServerConnectionsFailed' => 'Impossibile connettersi a nessun server. Controlla la tua rete e riprova.',
|
||||
'serverSelection.noServersFoundForAccount' => ({required Object username, required Object email}) => 'Nessun server trovato per ${username} (${email})',
|
||||
_ => null,
|
||||
} ?? switch (path) {
|
||||
'serverSelection.allServerConnectionsFailed' => 'Impossibile connettersi a nessun server. Controlla la tua rete e riprova.',
|
||||
'serverSelection.noServersFoundForAccount' => ({required Object username, required Object email}) => 'Nessun server trovato per ${username} (${email})',
|
||||
'serverSelection.failedToLoadServers' => ({required Object error}) => 'Impossibile caricare i server: ${error}',
|
||||
'hubDetail.title' => 'Titolo',
|
||||
'hubDetail.releaseYear' => 'Anno rilascio',
|
||||
|
||||
@@ -407,6 +407,8 @@ class _TranslationsFileInfoJa implements TranslationsFileInfoEn {
|
||||
@override String get colorPrimaries => '色原色';
|
||||
@override String get chromaSubsampling => 'クロマサブサンプリング';
|
||||
@override String get channels => 'チャンネル';
|
||||
@override String get subtitles => '字幕';
|
||||
@override String get overallBitrate => '全体ビットレート';
|
||||
@override String get path => 'パス';
|
||||
@override String get size => 'サイズ';
|
||||
@override String get container => 'コンテナ';
|
||||
@@ -1629,6 +1631,8 @@ extension on TranslationsJa {
|
||||
'fileInfo.colorPrimaries' => '色原色',
|
||||
'fileInfo.chromaSubsampling' => 'クロマサブサンプリング',
|
||||
'fileInfo.channels' => 'チャンネル',
|
||||
'fileInfo.subtitles' => '字幕',
|
||||
'fileInfo.overallBitrate' => '全体ビットレート',
|
||||
'fileInfo.path' => 'パス',
|
||||
'fileInfo.size' => 'サイズ',
|
||||
'fileInfo.container' => 'コンテナ',
|
||||
@@ -1870,10 +1874,10 @@ extension on TranslationsJa {
|
||||
'about.versionLabel' => ({required Object version}) => 'バージョン ${version}',
|
||||
'about.appDescription' => 'Flutter製の美しいPlexクライアント',
|
||||
'about.viewLicensesDescription' => 'サードパーティライブラリのライセンスを表示',
|
||||
'serverSelection.allServerConnectionsFailed' => 'どのサーバーにも接続できませんでした。ネットワークを確認してもう一度お試しください。',
|
||||
'serverSelection.noServersFoundForAccount' => ({required Object username, required Object email}) => '${username} (${email})のサーバーが見つかりません',
|
||||
_ => null,
|
||||
} ?? switch (path) {
|
||||
'serverSelection.allServerConnectionsFailed' => 'どのサーバーにも接続できませんでした。ネットワークを確認してもう一度お試しください。',
|
||||
'serverSelection.noServersFoundForAccount' => ({required Object username, required Object email}) => '${username} (${email})のサーバーが見つかりません',
|
||||
'serverSelection.failedToLoadServers' => ({required Object error}) => 'サーバーの読み込みに失敗しました: ${error}',
|
||||
'hubDetail.title' => 'タイトル',
|
||||
'hubDetail.releaseYear' => '公開年',
|
||||
|
||||
@@ -407,6 +407,8 @@ class _TranslationsFileInfoKo implements TranslationsFileInfoEn {
|
||||
@override String get colorPrimaries => '색상 원색';
|
||||
@override String get chromaSubsampling => '채도 서브샘플링';
|
||||
@override String get channels => '채널';
|
||||
@override String get subtitles => '자막';
|
||||
@override String get overallBitrate => '전체 비트레이트';
|
||||
@override String get path => '경로';
|
||||
@override String get size => '크기';
|
||||
@override String get container => '컨테이너';
|
||||
@@ -1629,6 +1631,8 @@ extension on TranslationsKo {
|
||||
'fileInfo.colorPrimaries' => '색상 원색',
|
||||
'fileInfo.chromaSubsampling' => '채도 서브샘플링',
|
||||
'fileInfo.channels' => '채널',
|
||||
'fileInfo.subtitles' => '자막',
|
||||
'fileInfo.overallBitrate' => '전체 비트레이트',
|
||||
'fileInfo.path' => '경로',
|
||||
'fileInfo.size' => '크기',
|
||||
'fileInfo.container' => '컨테이너',
|
||||
@@ -1870,10 +1874,10 @@ extension on TranslationsKo {
|
||||
'about.versionLabel' => ({required Object version}) => '버전 ${version}',
|
||||
'about.appDescription' => '아름다운 Flutter Plex 클라이언트',
|
||||
'about.viewLicensesDescription' => '타사 라이브러리 라이선스 보기',
|
||||
'serverSelection.allServerConnectionsFailed' => '어떤 서버에도 연결할 수 없습니다. 네트워크를 확인하고 다시 시도하세요.',
|
||||
'serverSelection.noServersFoundForAccount' => ({required Object username, required Object email}) => '${username} (${email})의 서버를 찾을 수 없습니다.',
|
||||
_ => null,
|
||||
} ?? switch (path) {
|
||||
'serverSelection.allServerConnectionsFailed' => '어떤 서버에도 연결할 수 없습니다. 네트워크를 확인하고 다시 시도하세요.',
|
||||
'serverSelection.noServersFoundForAccount' => ({required Object username, required Object email}) => '${username} (${email})의 서버를 찾을 수 없습니다.',
|
||||
'serverSelection.failedToLoadServers' => ({required Object error}) => '서버를 로드할 수 없습니다: ${error}',
|
||||
'hubDetail.title' => '제목',
|
||||
'hubDetail.releaseYear' => '출시 연도',
|
||||
|
||||
@@ -407,6 +407,8 @@ class _TranslationsFileInfoNb implements TranslationsFileInfoEn {
|
||||
@override String get colorPrimaries => 'Fargeprimærer';
|
||||
@override String get chromaSubsampling => 'Krominansnedsampling';
|
||||
@override String get channels => 'Kanaler';
|
||||
@override String get subtitles => 'Undertekster';
|
||||
@override String get overallBitrate => 'Total bitrate';
|
||||
@override String get path => 'Sti';
|
||||
@override String get size => 'Størrelse';
|
||||
@override String get container => 'Beholder';
|
||||
@@ -1629,6 +1631,8 @@ extension on TranslationsNb {
|
||||
'fileInfo.colorPrimaries' => 'Fargeprimærer',
|
||||
'fileInfo.chromaSubsampling' => 'Krominansnedsampling',
|
||||
'fileInfo.channels' => 'Kanaler',
|
||||
'fileInfo.subtitles' => 'Undertekster',
|
||||
'fileInfo.overallBitrate' => 'Total bitrate',
|
||||
'fileInfo.path' => 'Sti',
|
||||
'fileInfo.size' => 'Størrelse',
|
||||
'fileInfo.container' => 'Beholder',
|
||||
@@ -1870,10 +1874,10 @@ extension on TranslationsNb {
|
||||
'about.versionLabel' => ({required Object version}) => 'Versjon ${version}',
|
||||
'about.appDescription' => 'En vakker Plex-klient for Flutter',
|
||||
'about.viewLicensesDescription' => 'Vis lisenser for tredjepartsbiblioteker',
|
||||
'serverSelection.allServerConnectionsFailed' => 'Kunne ikke koble til noen servere. Sjekk nettverket ditt og prøv igjen.',
|
||||
'serverSelection.noServersFoundForAccount' => ({required Object username, required Object email}) => 'Ingen servere funnet for ${username} (${email})',
|
||||
_ => null,
|
||||
} ?? switch (path) {
|
||||
'serverSelection.allServerConnectionsFailed' => 'Kunne ikke koble til noen servere. Sjekk nettverket ditt og prøv igjen.',
|
||||
'serverSelection.noServersFoundForAccount' => ({required Object username, required Object email}) => 'Ingen servere funnet for ${username} (${email})',
|
||||
'serverSelection.failedToLoadServers' => ({required Object error}) => 'Kunne ikke laste servere: ${error}',
|
||||
'hubDetail.title' => 'Tittel',
|
||||
'hubDetail.releaseYear' => 'Utgivelsesår',
|
||||
|
||||
@@ -407,6 +407,8 @@ class _TranslationsFileInfoNl implements TranslationsFileInfoEn {
|
||||
@override String get colorPrimaries => 'Kleurprimaires';
|
||||
@override String get chromaSubsampling => 'Chroma subsampling';
|
||||
@override String get channels => 'Kanalen';
|
||||
@override String get subtitles => 'Ondertitels';
|
||||
@override String get overallBitrate => 'Totale bitrate';
|
||||
@override String get path => 'Pad';
|
||||
@override String get size => 'Grootte';
|
||||
@override String get container => 'Container';
|
||||
@@ -1629,6 +1631,8 @@ extension on TranslationsNl {
|
||||
'fileInfo.colorPrimaries' => 'Kleurprimaires',
|
||||
'fileInfo.chromaSubsampling' => 'Chroma subsampling',
|
||||
'fileInfo.channels' => 'Kanalen',
|
||||
'fileInfo.subtitles' => 'Ondertitels',
|
||||
'fileInfo.overallBitrate' => 'Totale bitrate',
|
||||
'fileInfo.path' => 'Pad',
|
||||
'fileInfo.size' => 'Grootte',
|
||||
'fileInfo.container' => 'Container',
|
||||
@@ -1870,10 +1874,10 @@ extension on TranslationsNl {
|
||||
'about.versionLabel' => ({required Object version}) => 'Versie ${version}',
|
||||
'about.appDescription' => 'Een mooie Plex client voor Flutter',
|
||||
'about.viewLicensesDescription' => 'Bekijk licenties van third-party bibliotheken',
|
||||
'serverSelection.allServerConnectionsFailed' => 'Kon niet verbinden met servers. Controleer je netwerk en probeer opnieuw.',
|
||||
'serverSelection.noServersFoundForAccount' => ({required Object username, required Object email}) => 'Geen servers gevonden voor ${username} (${email})',
|
||||
_ => null,
|
||||
} ?? switch (path) {
|
||||
'serverSelection.allServerConnectionsFailed' => 'Kon niet verbinden met servers. Controleer je netwerk en probeer opnieuw.',
|
||||
'serverSelection.noServersFoundForAccount' => ({required Object username, required Object email}) => 'Geen servers gevonden voor ${username} (${email})',
|
||||
'serverSelection.failedToLoadServers' => ({required Object error}) => 'Kon servers niet laden: ${error}',
|
||||
'hubDetail.title' => 'Titel',
|
||||
'hubDetail.releaseYear' => 'Uitgavejaar',
|
||||
|
||||
@@ -407,6 +407,8 @@ class _TranslationsFileInfoPl implements TranslationsFileInfoEn {
|
||||
@override String get colorPrimaries => 'Kolory podstawowe';
|
||||
@override String get chromaSubsampling => 'Subsampling chrominancji';
|
||||
@override String get channels => 'Kanały';
|
||||
@override String get subtitles => 'Napisy';
|
||||
@override String get overallBitrate => 'Całkowity bitrate';
|
||||
@override String get path => 'Ścieżka';
|
||||
@override String get size => 'Rozmiar';
|
||||
@override String get container => 'Kontener';
|
||||
@@ -1629,6 +1631,8 @@ extension on TranslationsPl {
|
||||
'fileInfo.colorPrimaries' => 'Kolory podstawowe',
|
||||
'fileInfo.chromaSubsampling' => 'Subsampling chrominancji',
|
||||
'fileInfo.channels' => 'Kanały',
|
||||
'fileInfo.subtitles' => 'Napisy',
|
||||
'fileInfo.overallBitrate' => 'Całkowity bitrate',
|
||||
'fileInfo.path' => 'Ścieżka',
|
||||
'fileInfo.size' => 'Rozmiar',
|
||||
'fileInfo.container' => 'Kontener',
|
||||
@@ -1870,10 +1874,10 @@ extension on TranslationsPl {
|
||||
'about.versionLabel' => ({required Object version}) => 'Wersja ${version}',
|
||||
'about.appDescription' => 'Piękny klient Plex na Flutter',
|
||||
'about.viewLicensesDescription' => 'Zobacz licencje bibliotek zewnętrznych',
|
||||
'serverSelection.allServerConnectionsFailed' => 'Nie udało się połączyć z żadnym serwerem. Sprawdź sieć i spróbuj ponownie.',
|
||||
'serverSelection.noServersFoundForAccount' => ({required Object username, required Object email}) => 'Nie znaleziono serwerów dla ${username} (${email})',
|
||||
_ => null,
|
||||
} ?? switch (path) {
|
||||
'serverSelection.allServerConnectionsFailed' => 'Nie udało się połączyć z żadnym serwerem. Sprawdź sieć i spróbuj ponownie.',
|
||||
'serverSelection.noServersFoundForAccount' => ({required Object username, required Object email}) => 'Nie znaleziono serwerów dla ${username} (${email})',
|
||||
'serverSelection.failedToLoadServers' => ({required Object error}) => 'Nie udało się załadować serwerów: ${error}',
|
||||
'hubDetail.title' => 'Tytuł',
|
||||
'hubDetail.releaseYear' => 'Rok premiery',
|
||||
|
||||
@@ -407,6 +407,8 @@ class _TranslationsFileInfoPt implements TranslationsFileInfoEn {
|
||||
@override String get colorPrimaries => 'Primárias de Cor';
|
||||
@override String get chromaSubsampling => 'Subamostragem de Croma';
|
||||
@override String get channels => 'Canais';
|
||||
@override String get subtitles => 'Legendas';
|
||||
@override String get overallBitrate => 'Taxa de bits total';
|
||||
@override String get path => 'Caminho';
|
||||
@override String get size => 'Tamanho';
|
||||
@override String get container => 'Container';
|
||||
@@ -1629,6 +1631,8 @@ extension on TranslationsPt {
|
||||
'fileInfo.colorPrimaries' => 'Primárias de Cor',
|
||||
'fileInfo.chromaSubsampling' => 'Subamostragem de Croma',
|
||||
'fileInfo.channels' => 'Canais',
|
||||
'fileInfo.subtitles' => 'Legendas',
|
||||
'fileInfo.overallBitrate' => 'Taxa de bits total',
|
||||
'fileInfo.path' => 'Caminho',
|
||||
'fileInfo.size' => 'Tamanho',
|
||||
'fileInfo.container' => 'Container',
|
||||
@@ -1870,10 +1874,10 @@ extension on TranslationsPt {
|
||||
'about.versionLabel' => ({required Object version}) => 'Versão ${version}',
|
||||
'about.appDescription' => 'Um belo cliente Plex para Flutter',
|
||||
'about.viewLicensesDescription' => 'Ver licenças de bibliotecas de terceiros',
|
||||
'serverSelection.allServerConnectionsFailed' => 'Falha ao conectar a qualquer servidor. Verifique sua rede e tente novamente.',
|
||||
'serverSelection.noServersFoundForAccount' => ({required Object username, required Object email}) => 'Nenhum servidor encontrado para ${username} (${email})',
|
||||
_ => null,
|
||||
} ?? switch (path) {
|
||||
'serverSelection.allServerConnectionsFailed' => 'Falha ao conectar a qualquer servidor. Verifique sua rede e tente novamente.',
|
||||
'serverSelection.noServersFoundForAccount' => ({required Object username, required Object email}) => 'Nenhum servidor encontrado para ${username} (${email})',
|
||||
'serverSelection.failedToLoadServers' => ({required Object error}) => 'Falha ao carregar servidores: ${error}',
|
||||
'hubDetail.title' => 'Título',
|
||||
'hubDetail.releaseYear' => 'Ano de Lançamento',
|
||||
|
||||
@@ -407,6 +407,8 @@ class _TranslationsFileInfoRu implements TranslationsFileInfoEn {
|
||||
@override String get colorPrimaries => 'Цветовые первичные';
|
||||
@override String get chromaSubsampling => 'Субдискретизация цветности';
|
||||
@override String get channels => 'Каналы';
|
||||
@override String get subtitles => 'Субтитры';
|
||||
@override String get overallBitrate => 'Общий битрейт';
|
||||
@override String get path => 'Путь';
|
||||
@override String get size => 'Размер';
|
||||
@override String get container => 'Контейнер';
|
||||
@@ -1629,6 +1631,8 @@ extension on TranslationsRu {
|
||||
'fileInfo.colorPrimaries' => 'Цветовые первичные',
|
||||
'fileInfo.chromaSubsampling' => 'Субдискретизация цветности',
|
||||
'fileInfo.channels' => 'Каналы',
|
||||
'fileInfo.subtitles' => 'Субтитры',
|
||||
'fileInfo.overallBitrate' => 'Общий битрейт',
|
||||
'fileInfo.path' => 'Путь',
|
||||
'fileInfo.size' => 'Размер',
|
||||
'fileInfo.container' => 'Контейнер',
|
||||
@@ -1870,10 +1874,10 @@ extension on TranslationsRu {
|
||||
'about.versionLabel' => ({required Object version}) => 'Версия ${version}',
|
||||
'about.appDescription' => 'Красивый клиент Plex на Flutter',
|
||||
'about.viewLicensesDescription' => 'Просмотр лицензий сторонних библиотек',
|
||||
'serverSelection.allServerConnectionsFailed' => 'Не удалось подключиться ни к одному серверу. Проверьте сеть и попробуйте снова.',
|
||||
'serverSelection.noServersFoundForAccount' => ({required Object username, required Object email}) => 'Серверы не найдены для ${username} (${email})',
|
||||
_ => null,
|
||||
} ?? switch (path) {
|
||||
'serverSelection.allServerConnectionsFailed' => 'Не удалось подключиться ни к одному серверу. Проверьте сеть и попробуйте снова.',
|
||||
'serverSelection.noServersFoundForAccount' => ({required Object username, required Object email}) => 'Серверы не найдены для ${username} (${email})',
|
||||
'serverSelection.failedToLoadServers' => ({required Object error}) => 'Не удалось загрузить серверы: ${error}',
|
||||
'hubDetail.title' => 'Название',
|
||||
'hubDetail.releaseYear' => 'Год выпуска',
|
||||
|
||||
@@ -407,6 +407,8 @@ class _TranslationsFileInfoSv implements TranslationsFileInfoEn {
|
||||
@override String get colorPrimaries => 'Färggrunder';
|
||||
@override String get chromaSubsampling => 'Kroma-undersampling';
|
||||
@override String get channels => 'Kanaler';
|
||||
@override String get subtitles => 'Undertexter';
|
||||
@override String get overallBitrate => 'Total bithastighet';
|
||||
@override String get path => 'Sökväg';
|
||||
@override String get size => 'Storlek';
|
||||
@override String get container => 'Container';
|
||||
@@ -1629,6 +1631,8 @@ extension on TranslationsSv {
|
||||
'fileInfo.colorPrimaries' => 'Färggrunder',
|
||||
'fileInfo.chromaSubsampling' => 'Kroma-undersampling',
|
||||
'fileInfo.channels' => 'Kanaler',
|
||||
'fileInfo.subtitles' => 'Undertexter',
|
||||
'fileInfo.overallBitrate' => 'Total bithastighet',
|
||||
'fileInfo.path' => 'Sökväg',
|
||||
'fileInfo.size' => 'Storlek',
|
||||
'fileInfo.container' => 'Container',
|
||||
@@ -1870,10 +1874,10 @@ extension on TranslationsSv {
|
||||
'about.versionLabel' => ({required Object version}) => 'Version ${version}',
|
||||
'about.appDescription' => 'En vacker Plex-klient för Flutter',
|
||||
'about.viewLicensesDescription' => 'Visa licenser för tredjepartsbibliotek',
|
||||
'serverSelection.allServerConnectionsFailed' => 'Misslyckades att ansluta till servrar. Kontrollera ditt nätverk och försök igen.',
|
||||
'serverSelection.noServersFoundForAccount' => ({required Object username, required Object email}) => 'Inga servrar hittades för ${username} (${email})',
|
||||
_ => null,
|
||||
} ?? switch (path) {
|
||||
'serverSelection.allServerConnectionsFailed' => 'Misslyckades att ansluta till servrar. Kontrollera ditt nätverk och försök igen.',
|
||||
'serverSelection.noServersFoundForAccount' => ({required Object username, required Object email}) => 'Inga servrar hittades för ${username} (${email})',
|
||||
'serverSelection.failedToLoadServers' => ({required Object error}) => 'Misslyckades att ladda servrar: ${error}',
|
||||
'hubDetail.title' => 'Titel',
|
||||
'hubDetail.releaseYear' => 'Utgivningsår',
|
||||
|
||||
@@ -407,6 +407,8 @@ class _TranslationsFileInfoZh implements TranslationsFileInfoEn {
|
||||
@override String get colorPrimaries => '颜色原色';
|
||||
@override String get chromaSubsampling => '色度子采样';
|
||||
@override String get channels => '声道';
|
||||
@override String get subtitles => '字幕';
|
||||
@override String get overallBitrate => '总比特率';
|
||||
@override String get path => '路径';
|
||||
@override String get size => '大小';
|
||||
@override String get container => '容器';
|
||||
@@ -1629,6 +1631,8 @@ extension on TranslationsZh {
|
||||
'fileInfo.colorPrimaries' => '颜色原色',
|
||||
'fileInfo.chromaSubsampling' => '色度子采样',
|
||||
'fileInfo.channels' => '声道',
|
||||
'fileInfo.subtitles' => '字幕',
|
||||
'fileInfo.overallBitrate' => '总比特率',
|
||||
'fileInfo.path' => '路径',
|
||||
'fileInfo.size' => '大小',
|
||||
'fileInfo.container' => '容器',
|
||||
@@ -1870,10 +1874,10 @@ extension on TranslationsZh {
|
||||
'about.versionLabel' => ({required Object version}) => '版本 ${version}',
|
||||
'about.appDescription' => '一款精美的 Flutter Plex 客户端',
|
||||
'about.viewLicensesDescription' => '查看第三方库的许可证',
|
||||
'serverSelection.allServerConnectionsFailed' => '无法连接到任何服务器。请检查你的网络并重试。',
|
||||
'serverSelection.noServersFoundForAccount' => ({required Object username, required Object email}) => '未找到 ${username} (${email}) 的服务器',
|
||||
_ => null,
|
||||
} ?? switch (path) {
|
||||
'serverSelection.allServerConnectionsFailed' => '无法连接到任何服务器。请检查你的网络并重试。',
|
||||
'serverSelection.noServersFoundForAccount' => ({required Object username, required Object email}) => '未找到 ${username} (${email}) 的服务器',
|
||||
'serverSelection.failedToLoadServers' => ({required Object error}) => '无法加载服务器: ${error}',
|
||||
'hubDetail.title' => '标题',
|
||||
'hubDetail.releaseYear' => '发行年份',
|
||||
|
||||
@@ -287,6 +287,8 @@
|
||||
"colorPrimaries": "Färggrunder",
|
||||
"chromaSubsampling": "Kroma-undersampling",
|
||||
"channels": "Kanaler",
|
||||
"subtitles": "Undertexter",
|
||||
"overallBitrate": "Total bithastighet",
|
||||
"path": "Sökväg",
|
||||
"size": "Storlek",
|
||||
"container": "Container",
|
||||
|
||||
@@ -287,6 +287,8 @@
|
||||
"colorPrimaries": "颜色原色",
|
||||
"chromaSubsampling": "色度子采样",
|
||||
"channels": "声道",
|
||||
"subtitles": "字幕",
|
||||
"overallBitrate": "总比特率",
|
||||
"path": "路径",
|
||||
"size": "大小",
|
||||
"container": "容器",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import '../utils/formatters.dart';
|
||||
import 'plex_media_info.dart';
|
||||
|
||||
class PlexFileInfo {
|
||||
// Media level properties
|
||||
@@ -30,8 +31,13 @@ class PlexFileInfo {
|
||||
final String? chromaSubsampling;
|
||||
final double? frameRate;
|
||||
final int? bitDepth;
|
||||
final int? videoBitrate;
|
||||
final String? audioChannelLayout;
|
||||
|
||||
// Multi-track support
|
||||
final List<PlexAudioTrack> audioTracks;
|
||||
final List<PlexSubtitleTrack> subtitleTracks;
|
||||
|
||||
PlexFileInfo({
|
||||
this.container,
|
||||
this.videoCodec,
|
||||
@@ -57,7 +63,10 @@ class PlexFileInfo {
|
||||
this.chromaSubsampling,
|
||||
this.frameRate,
|
||||
this.bitDepth,
|
||||
this.videoBitrate,
|
||||
this.audioChannelLayout,
|
||||
this.audioTracks = const [],
|
||||
this.subtitleTracks = const [],
|
||||
});
|
||||
|
||||
/// Format file size in human-readable format (GB, MB, KB, bytes)
|
||||
@@ -78,10 +87,16 @@ class PlexFileInfo {
|
||||
return hours > 0 ? '${hours}h ${minutes}m ${secs}s' : '${minutes}m ${secs}s';
|
||||
}
|
||||
|
||||
/// Format bitrate in Mbps or Kbps
|
||||
/// Format overall bitrate in Mbps or kbps (Plex API returns kbps)
|
||||
String get bitrateFormatted {
|
||||
if (bitrate == null) return 'Unknown';
|
||||
return ByteFormatter.formatBitrateBps(bitrate!);
|
||||
return ByteFormatter.formatBitrate(bitrate!);
|
||||
}
|
||||
|
||||
/// Format video stream bitrate in Mbps or kbps
|
||||
String get videoBitrateFormatted {
|
||||
if (videoBitrate == null) return 'Unknown';
|
||||
return ByteFormatter.formatBitrate(videoBitrate!);
|
||||
}
|
||||
|
||||
/// Format resolution as widthxheight
|
||||
|
||||
@@ -1266,7 +1266,7 @@ class PlexClient {
|
||||
final media = metadataJson['Media'][0];
|
||||
final part = media['Part'] != null && (media['Part'] as List).isNotEmpty ? media['Part'][0] : null;
|
||||
|
||||
// Extract video stream details
|
||||
// Extract video stream details and all audio/subtitle tracks
|
||||
final streams = part?['Stream'] as List<dynamic>? ?? [];
|
||||
Map<String, dynamic>? videoStream;
|
||||
Map<String, dynamic>? audioStream;
|
||||
@@ -1280,6 +1280,8 @@ class PlexClient {
|
||||
}
|
||||
}
|
||||
|
||||
final parsedTracks = _parseStreams(streams);
|
||||
|
||||
return PlexFileInfo(
|
||||
// Media level properties
|
||||
container: media['container'] as String?,
|
||||
@@ -1308,8 +1310,12 @@ class PlexClient {
|
||||
chromaSubsampling: videoStream?['chromaSubsampling'] as String?,
|
||||
frameRate: (videoStream?['frameRate'] as num?)?.toDouble(),
|
||||
bitDepth: videoStream?['bitDepth'] as int?,
|
||||
videoBitrate: videoStream?['bitrate'] as int?,
|
||||
// Audio stream details
|
||||
audioChannelLayout: audioStream?['audioChannelLayout'] as String?,
|
||||
// All audio and subtitle tracks
|
||||
audioTracks: parsedTracks.audio,
|
||||
subtitleTracks: parsedTracks.subtitles,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
import '../models/plex_file_info.dart';
|
||||
import '../i18n/strings.g.dart';
|
||||
import '../utils/scroll_utils.dart';
|
||||
import 'bottom_sheet_header.dart';
|
||||
|
||||
class FileInfoBottomSheet extends StatefulWidget {
|
||||
@@ -58,7 +59,8 @@ class _FileInfoBottomSheetState extends State<FileInfoBottomSheet> {
|
||||
const SizedBox(height: 8),
|
||||
_buildInfoRow(t.fileInfo.codec, widget.fileInfo.videoCodec ?? t.common.unknown),
|
||||
_buildInfoRow(t.fileInfo.resolution, widget.fileInfo.resolutionFormatted),
|
||||
_buildInfoRow(t.fileInfo.bitrate, widget.fileInfo.bitrateFormatted),
|
||||
if (widget.fileInfo.videoBitrate != null)
|
||||
_buildInfoRow(t.fileInfo.bitrate, widget.fileInfo.videoBitrateFormatted),
|
||||
_buildInfoRow(t.fileInfo.frameRate, widget.fileInfo.frameRateFormatted),
|
||||
_buildInfoRow(t.fileInfo.aspectRatio, widget.fileInfo.aspectRatioFormatted),
|
||||
if (widget.fileInfo.videoProfile != null)
|
||||
@@ -76,12 +78,26 @@ class _FileInfoBottomSheetState extends State<FileInfoBottomSheet> {
|
||||
// Audio Section
|
||||
_buildSectionHeader(t.fileInfo.audio),
|
||||
const SizedBox(height: 8),
|
||||
_buildInfoRow(t.fileInfo.codec, widget.fileInfo.audioCodec ?? t.common.unknown),
|
||||
_buildInfoRow(t.fileInfo.channels, widget.fileInfo.audioChannelsFormatted),
|
||||
if (widget.fileInfo.audioProfile != null)
|
||||
_buildInfoRow(t.fileInfo.profile, widget.fileInfo.audioProfile!),
|
||||
if (widget.fileInfo.audioTracks.isNotEmpty)
|
||||
for (int i = 0; i < widget.fileInfo.audioTracks.length; i++)
|
||||
_buildInfoRow('${i + 1}', widget.fileInfo.audioTracks[i].label),
|
||||
if (widget.fileInfo.audioTracks.isEmpty) ...[
|
||||
_buildInfoRow(t.fileInfo.codec, widget.fileInfo.audioCodec ?? t.common.unknown),
|
||||
_buildInfoRow(t.fileInfo.channels, widget.fileInfo.audioChannelsFormatted),
|
||||
if (widget.fileInfo.audioProfile != null)
|
||||
_buildInfoRow(t.fileInfo.profile, widget.fileInfo.audioProfile!),
|
||||
],
|
||||
const SizedBox(height: 20),
|
||||
|
||||
// Subtitles Section
|
||||
if (widget.fileInfo.subtitleTracks.isNotEmpty) ...[
|
||||
_buildSectionHeader(t.fileInfo.subtitles),
|
||||
const SizedBox(height: 8),
|
||||
for (int i = 0; i < widget.fileInfo.subtitleTracks.length; i++)
|
||||
_buildInfoRow('${i + 1}', widget.fileInfo.subtitleTracks[i].label),
|
||||
const SizedBox(height: 20),
|
||||
],
|
||||
|
||||
// File Section
|
||||
_buildSectionHeader(t.fileInfo.file),
|
||||
const SizedBox(height: 8),
|
||||
@@ -90,6 +106,7 @@ class _FileInfoBottomSheetState extends State<FileInfoBottomSheet> {
|
||||
_buildInfoRow(t.fileInfo.size, widget.fileInfo.fileSizeFormatted),
|
||||
_buildInfoRow(t.fileInfo.container, widget.fileInfo.container ?? t.common.unknown),
|
||||
_buildInfoRow(t.fileInfo.duration, widget.fileInfo.durationFormatted),
|
||||
_buildInfoRow(t.fileInfo.overallBitrate, widget.fileInfo.bitrateFormatted),
|
||||
const SizedBox(height: 20),
|
||||
|
||||
// Advanced Section
|
||||
@@ -118,22 +135,65 @@ class _FileInfoBottomSheetState extends State<FileInfoBottomSheet> {
|
||||
}
|
||||
|
||||
Widget _buildInfoRow(String label, String value, {bool isMonospace = false}) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 6),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 140,
|
||||
child: Text(label, style: TextStyle(color: Theme.of(context).textTheme.bodySmall?.color, fontSize: 14)),
|
||||
),
|
||||
Expanded(
|
||||
child: Text(
|
||||
value,
|
||||
style: TextStyle(fontSize: 14, fontFamily: isMonospace ? 'monospace' : null),
|
||||
return _FocusableInfoRow(label: label, value: value, isMonospace: isMonospace);
|
||||
}
|
||||
}
|
||||
|
||||
class _FocusableInfoRow extends StatefulWidget {
|
||||
final String label;
|
||||
final String value;
|
||||
final bool isMonospace;
|
||||
|
||||
const _FocusableInfoRow({required this.label, required this.value, this.isMonospace = false});
|
||||
|
||||
@override
|
||||
State<_FocusableInfoRow> createState() => _FocusableInfoRowState();
|
||||
}
|
||||
|
||||
class _FocusableInfoRowState extends State<_FocusableInfoRow> {
|
||||
late final FocusNode _focusNode;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_focusNode = FocusNode();
|
||||
_focusNode.addListener(_onFocusChange);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_focusNode.removeListener(_onFocusChange);
|
||||
_focusNode.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _onFocusChange() {
|
||||
if (_focusNode.hasFocus) {
|
||||
scrollContextToCenter(context);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Focus(
|
||||
focusNode: _focusNode,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 6),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 140,
|
||||
child: Text(widget.label, style: TextStyle(color: Theme.of(context).textTheme.bodySmall?.color, fontSize: 14)),
|
||||
),
|
||||
),
|
||||
],
|
||||
Expanded(
|
||||
child: Text(
|
||||
widget.value,
|
||||
style: TextStyle(fontSize: 14, fontFamily: widget.isMonospace ? 'monospace' : null),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user