@@ -858,7 +858,8 @@ class ExoPlayerCore(private val activity: Activity) : Player.Listener {
|
||||
borderSize: Float,
|
||||
borderColor: String,
|
||||
bgColor: String,
|
||||
bgOpacity: Int
|
||||
bgOpacity: Int,
|
||||
subtitlePosition: Int = 100
|
||||
) {
|
||||
activity.runOnUiThread {
|
||||
// 1. Non-ASS subtitles: CaptionStyleCompat on SubtitleView
|
||||
@@ -885,6 +886,25 @@ class ExoPlayerCore(private val activity: Activity) : Player.Listener {
|
||||
val fraction = fontSize / 720f
|
||||
subtitleView?.setFractionalTextSize(fraction)
|
||||
|
||||
// Subtitle position: adjust gravity and bottom padding
|
||||
val clampedPosition = subtitlePosition.coerceIn(0, 100)
|
||||
val gravity = when {
|
||||
clampedPosition <= 33 -> Gravity.TOP
|
||||
clampedPosition <= 66 -> Gravity.CENTER
|
||||
else -> Gravity.BOTTOM
|
||||
}
|
||||
(subtitleView?.layoutParams as? FrameLayout.LayoutParams)?.let { params ->
|
||||
params.gravity = gravity or Gravity.CENTER_HORIZONTAL
|
||||
subtitleView?.layoutParams = params
|
||||
}
|
||||
// Fine-grained positioning within bottom region via bottom padding fraction
|
||||
if (clampedPosition > 66) {
|
||||
val bottomFraction = (100 - clampedPosition) / 100f
|
||||
subtitleView?.setBottomPaddingFraction(bottomFraction)
|
||||
} else {
|
||||
subtitleView?.setBottomPaddingFraction(0f)
|
||||
}
|
||||
|
||||
// 2. ASS subtitles: font scale via libass
|
||||
// MPV default sub-font-size is 38
|
||||
val defaultSize = 38f
|
||||
@@ -895,7 +915,7 @@ class ExoPlayerCore(private val activity: Activity) : Player.Listener {
|
||||
Log.w(TAG, "Failed to set ASS font scale: ${e.message}")
|
||||
}
|
||||
|
||||
Log.d(TAG, "setSubtitleStyle: fontSize=$fontSize, textColor=$textColor, borderSize=$borderSize, bgOpacity=$bgOpacity, assScale=$scale")
|
||||
Log.d(TAG, "setSubtitleStyle: fontSize=$fontSize, textColor=$textColor, borderSize=$borderSize, bgOpacity=$bgOpacity, position=$subtitlePosition, assScale=$scale")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -419,6 +419,7 @@ class ExoPlayerPlugin : FlutterPlugin, MethodChannel.MethodCallHandler,
|
||||
val borderColor = call.argument<String>("borderColor") ?: "#000000"
|
||||
val bgColor = call.argument<String>("bgColor") ?: "#000000"
|
||||
val bgOpacity = call.argument<Number>("bgOpacity")?.toInt() ?: 0
|
||||
val subtitlePosition = call.argument<Number>("subtitlePosition")?.toInt() ?: 100
|
||||
|
||||
if (usingMpvFallback) {
|
||||
// MPV fallback handles styling via setProperty, no-op here
|
||||
@@ -426,7 +427,7 @@ class ExoPlayerPlugin : FlutterPlugin, MethodChannel.MethodCallHandler,
|
||||
return
|
||||
}
|
||||
|
||||
playerCore?.setSubtitleStyle(fontSize, textColor, borderSize, borderColor, bgColor, bgOpacity)
|
||||
playerCore?.setSubtitleStyle(fontSize, textColor, borderSize, borderColor, bgColor, bgOpacity, subtitlePosition)
|
||||
result.success(null)
|
||||
}
|
||||
|
||||
|
||||
@@ -365,7 +365,8 @@
|
||||
"borderSize": "Rahmengröße",
|
||||
"borderColor": "Rahmenfarbe",
|
||||
"backgroundOpacity": "Hintergrunddeckkraft",
|
||||
"backgroundColor": "Hintergrundfarbe"
|
||||
"backgroundColor": "Hintergrundfarbe",
|
||||
"position": "Position"
|
||||
},
|
||||
"mpvConfig": {
|
||||
"title": "MPV-Konfiguration",
|
||||
|
||||
@@ -365,7 +365,8 @@
|
||||
"borderSize": "Border Size",
|
||||
"borderColor": "Border Color",
|
||||
"backgroundOpacity": "Background Opacity",
|
||||
"backgroundColor": "Background Color"
|
||||
"backgroundColor": "Background Color",
|
||||
"position": "Position"
|
||||
},
|
||||
"mpvConfig": {
|
||||
"title": "MPV Configuration",
|
||||
|
||||
@@ -365,7 +365,8 @@
|
||||
"borderSize": "Tamaño de Borde",
|
||||
"borderColor": "Color de Borde",
|
||||
"backgroundOpacity": "Opacidad de Fondo",
|
||||
"backgroundColor": "Color de Fondo"
|
||||
"backgroundColor": "Color de Fondo",
|
||||
"position": "Position"
|
||||
},
|
||||
"mpvConfig": {
|
||||
"title": "Configuración de MPV",
|
||||
|
||||
@@ -365,7 +365,8 @@
|
||||
"borderSize": "Taille de la bordure",
|
||||
"borderColor": "Couleur de la bordure",
|
||||
"backgroundOpacity": "Opacité d'arrière-plan",
|
||||
"backgroundColor": "Couleur d'arrière-plan"
|
||||
"backgroundColor": "Couleur d'arrière-plan",
|
||||
"position": "Position"
|
||||
},
|
||||
"mpvConfig": {
|
||||
"title": "Configuration MPV",
|
||||
|
||||
@@ -365,7 +365,8 @@
|
||||
"borderSize": "Dimensione bordo",
|
||||
"borderColor": "Colore bordo",
|
||||
"backgroundOpacity": "Opacità sfondo",
|
||||
"backgroundColor": "Colore sfondo"
|
||||
"backgroundColor": "Colore sfondo",
|
||||
"position": "Position"
|
||||
},
|
||||
"mpvConfig": {
|
||||
"title": "Configurazione MPV",
|
||||
|
||||
@@ -365,7 +365,8 @@
|
||||
"borderSize": "테두리 크기",
|
||||
"borderColor": "테두리 색상",
|
||||
"backgroundOpacity": "배경 불투명도",
|
||||
"backgroundColor": "배경색"
|
||||
"backgroundColor": "배경색",
|
||||
"position": "Position"
|
||||
},
|
||||
"mpvConfig": {
|
||||
"title": "MPV 설정",
|
||||
|
||||
@@ -365,7 +365,8 @@
|
||||
"borderSize": "Rand grootte",
|
||||
"borderColor": "Randkleur",
|
||||
"backgroundOpacity": "Achtergrond transparantie",
|
||||
"backgroundColor": "Achtergrondkleur"
|
||||
"backgroundColor": "Achtergrondkleur",
|
||||
"position": "Position"
|
||||
},
|
||||
"mpvConfig": {
|
||||
"title": "MPV-configuratie",
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
/// To regenerate, run: `dart run slang`
|
||||
///
|
||||
/// Locales: 9
|
||||
/// Strings: 5121 (569 per locale)
|
||||
/// Strings: 5130 (570 per locale)
|
||||
///
|
||||
/// Built on 2026-02-08 at 11:03 UTC
|
||||
/// Built on 2026-02-09 at 17:54 UTC
|
||||
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: type=lint, unused_import
|
||||
|
||||
@@ -532,6 +532,7 @@ class _TranslationsSubtitlingStylingDe implements TranslationsSubtitlingStylingE
|
||||
@override String get borderColor => 'Rahmenfarbe';
|
||||
@override String get backgroundOpacity => 'Hintergrunddeckkraft';
|
||||
@override String get backgroundColor => 'Hintergrundfarbe';
|
||||
@override String get position => 'Position';
|
||||
}
|
||||
|
||||
// Path: mpvConfig
|
||||
@@ -1316,6 +1317,7 @@ extension on TranslationsDe {
|
||||
'subtitlingStyling.borderColor' => 'Rahmenfarbe',
|
||||
'subtitlingStyling.backgroundOpacity' => 'Hintergrunddeckkraft',
|
||||
'subtitlingStyling.backgroundColor' => 'Hintergrundfarbe',
|
||||
'subtitlingStyling.position' => 'Position',
|
||||
'mpvConfig.title' => 'MPV-Konfiguration',
|
||||
'mpvConfig.description' => 'Erweiterte Videoplayer-Einstellungen',
|
||||
'mpvConfig.properties' => 'Eigenschaften',
|
||||
@@ -1497,9 +1499,9 @@ extension on TranslationsDe {
|
||||
'collections.failedToLoadItems' => ({required Object error}) => 'Sammlungselemente konnten nicht geladen werden: ${error}',
|
||||
'collections.selectCollection' => 'Sammlung auswählen',
|
||||
'collections.createNewCollection' => 'Neue Sammlung erstellen',
|
||||
'collections.collectionName' => 'Sammlungsname',
|
||||
_ => null,
|
||||
} ?? switch (path) {
|
||||
'collections.collectionName' => 'Sammlungsname',
|
||||
'collections.enterCollectionName' => 'Sammlungsnamen eingeben',
|
||||
'collections.addedToCollection' => 'Zur Sammlung hinzugefügt',
|
||||
'collections.errorAddingToCollection' => 'Fehler beim Hinzufügen zur Sammlung',
|
||||
|
||||
@@ -1151,6 +1151,9 @@ class TranslationsSubtitlingStylingEn {
|
||||
|
||||
/// en: 'Background Color'
|
||||
String get backgroundColor => 'Background Color';
|
||||
|
||||
/// en: 'Position'
|
||||
String get position => 'Position';
|
||||
}
|
||||
|
||||
// Path: mpvConfig
|
||||
@@ -2460,6 +2463,7 @@ extension on Translations {
|
||||
'subtitlingStyling.borderColor' => 'Border Color',
|
||||
'subtitlingStyling.backgroundOpacity' => 'Background Opacity',
|
||||
'subtitlingStyling.backgroundColor' => 'Background Color',
|
||||
'subtitlingStyling.position' => 'Position',
|
||||
'mpvConfig.title' => 'MPV Configuration',
|
||||
'mpvConfig.description' => 'Advanced video player settings',
|
||||
'mpvConfig.properties' => 'Properties',
|
||||
@@ -2641,9 +2645,9 @@ extension on Translations {
|
||||
'watchTogether.description' => 'Watch content in sync with friends and family',
|
||||
'watchTogether.createSession' => 'Create Session',
|
||||
'watchTogether.creating' => 'Creating...',
|
||||
'watchTogether.joinSession' => 'Join Session',
|
||||
_ => null,
|
||||
} ?? switch (path) {
|
||||
'watchTogether.joinSession' => 'Join Session',
|
||||
'watchTogether.joining' => 'Joining...',
|
||||
'watchTogether.controlMode' => 'Control Mode',
|
||||
'watchTogether.controlModeQuestion' => 'Who can control playback?',
|
||||
|
||||
@@ -532,6 +532,7 @@ class _TranslationsSubtitlingStylingEs implements TranslationsSubtitlingStylingE
|
||||
@override String get borderColor => 'Color de Borde';
|
||||
@override String get backgroundOpacity => 'Opacidad de Fondo';
|
||||
@override String get backgroundColor => 'Color de Fondo';
|
||||
@override String get position => 'Position';
|
||||
}
|
||||
|
||||
// Path: mpvConfig
|
||||
@@ -1316,6 +1317,7 @@ extension on TranslationsEs {
|
||||
'subtitlingStyling.borderColor' => 'Color de Borde',
|
||||
'subtitlingStyling.backgroundOpacity' => 'Opacidad de Fondo',
|
||||
'subtitlingStyling.backgroundColor' => 'Color de Fondo',
|
||||
'subtitlingStyling.position' => 'Position',
|
||||
'mpvConfig.title' => 'Configuración de MPV',
|
||||
'mpvConfig.description' => 'Ajustes avanzados del reproductor de video',
|
||||
'mpvConfig.properties' => 'Propiedades',
|
||||
@@ -1497,9 +1499,9 @@ extension on TranslationsEs {
|
||||
'watchTogether.description' => 'Mira contenido en sincronía con amigos y familiares',
|
||||
'watchTogether.createSession' => 'Crear Sesión',
|
||||
'watchTogether.creating' => 'Creando...',
|
||||
'watchTogether.joinSession' => 'Unirse a Sesión',
|
||||
_ => null,
|
||||
} ?? switch (path) {
|
||||
'watchTogether.joinSession' => 'Unirse a Sesión',
|
||||
'watchTogether.joining' => 'Uniendo...',
|
||||
'watchTogether.controlMode' => 'Modo de Control',
|
||||
'watchTogether.controlModeQuestion' => '¿Quién puede controlar la reproducción?',
|
||||
|
||||
@@ -532,6 +532,7 @@ class _TranslationsSubtitlingStylingFr implements TranslationsSubtitlingStylingE
|
||||
@override String get borderColor => 'Couleur de la bordure';
|
||||
@override String get backgroundOpacity => 'Opacité d\'arrière-plan';
|
||||
@override String get backgroundColor => 'Couleur d\'arrière-plan';
|
||||
@override String get position => 'Position';
|
||||
}
|
||||
|
||||
// Path: mpvConfig
|
||||
@@ -1316,6 +1317,7 @@ extension on TranslationsFr {
|
||||
'subtitlingStyling.borderColor' => 'Couleur de la bordure',
|
||||
'subtitlingStyling.backgroundOpacity' => 'Opacité d\'arrière-plan',
|
||||
'subtitlingStyling.backgroundColor' => 'Couleur d\'arrière-plan',
|
||||
'subtitlingStyling.position' => 'Position',
|
||||
'mpvConfig.title' => 'Configuration MPV',
|
||||
'mpvConfig.description' => 'Paramètres avancés du lecteur vidéo',
|
||||
'mpvConfig.properties' => 'Propriétés',
|
||||
@@ -1497,9 +1499,9 @@ extension on TranslationsFr {
|
||||
'watchTogether.description' => 'Regardez du contenu en synchronisation avec vos amis et votre famille',
|
||||
'watchTogether.createSession' => 'Créer une session',
|
||||
'watchTogether.creating' => 'Création...',
|
||||
'watchTogether.joinSession' => 'Rejoindre la session',
|
||||
_ => null,
|
||||
} ?? switch (path) {
|
||||
'watchTogether.joinSession' => 'Rejoindre la session',
|
||||
'watchTogether.joining' => 'Rejoindre...',
|
||||
'watchTogether.controlMode' => 'Mode de contrôle',
|
||||
'watchTogether.controlModeQuestion' => 'Qui peut contrôler la lecture ?',
|
||||
|
||||
@@ -532,6 +532,7 @@ class _TranslationsSubtitlingStylingIt implements TranslationsSubtitlingStylingE
|
||||
@override String get borderColor => 'Colore bordo';
|
||||
@override String get backgroundOpacity => 'Opacità sfondo';
|
||||
@override String get backgroundColor => 'Colore sfondo';
|
||||
@override String get position => 'Position';
|
||||
}
|
||||
|
||||
// Path: mpvConfig
|
||||
@@ -1316,6 +1317,7 @@ extension on TranslationsIt {
|
||||
'subtitlingStyling.borderColor' => 'Colore bordo',
|
||||
'subtitlingStyling.backgroundOpacity' => 'Opacità sfondo',
|
||||
'subtitlingStyling.backgroundColor' => 'Colore sfondo',
|
||||
'subtitlingStyling.position' => 'Position',
|
||||
'mpvConfig.title' => 'Configurazione MPV',
|
||||
'mpvConfig.description' => 'Impostazioni avanzate del lettore video',
|
||||
'mpvConfig.properties' => 'Proprietà',
|
||||
@@ -1497,9 +1499,9 @@ extension on TranslationsIt {
|
||||
'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',
|
||||
_ => null,
|
||||
} ?? switch (path) {
|
||||
'collections.collectionName' => 'Nome raccolta',
|
||||
'collections.enterCollectionName' => 'Inserisci nome raccolta',
|
||||
'collections.addedToCollection' => 'Aggiunto alla raccolta',
|
||||
'collections.errorAddingToCollection' => 'Errore nell\'aggiunta alla raccolta',
|
||||
|
||||
@@ -532,6 +532,7 @@ class _TranslationsSubtitlingStylingKo implements TranslationsSubtitlingStylingE
|
||||
@override String get borderColor => '테두리 색상';
|
||||
@override String get backgroundOpacity => '배경 불투명도';
|
||||
@override String get backgroundColor => '배경색';
|
||||
@override String get position => 'Position';
|
||||
}
|
||||
|
||||
// Path: mpvConfig
|
||||
@@ -1316,6 +1317,7 @@ extension on TranslationsKo {
|
||||
'subtitlingStyling.borderColor' => '테두리 색상',
|
||||
'subtitlingStyling.backgroundOpacity' => '배경 불투명도',
|
||||
'subtitlingStyling.backgroundColor' => '배경색',
|
||||
'subtitlingStyling.position' => 'Position',
|
||||
'mpvConfig.title' => 'MPV 설정',
|
||||
'mpvConfig.description' => '고급 비디오 플레이어 설정',
|
||||
'mpvConfig.properties' => '속성',
|
||||
@@ -1497,9 +1499,9 @@ extension on TranslationsKo {
|
||||
'watchTogether.description' => '친구 및 가족과 콘텐츠를 동시에 시청하세요',
|
||||
'watchTogether.createSession' => '세션 생성',
|
||||
'watchTogether.creating' => '생성 중...',
|
||||
'watchTogether.joinSession' => '세션 참여',
|
||||
_ => null,
|
||||
} ?? switch (path) {
|
||||
'watchTogether.joinSession' => '세션 참여',
|
||||
'watchTogether.joining' => '참가 중...',
|
||||
'watchTogether.controlMode' => '제어 모드',
|
||||
'watchTogether.controlModeQuestion' => '누가 재생을 제어할 수 있나요?',
|
||||
|
||||
@@ -532,6 +532,7 @@ class _TranslationsSubtitlingStylingNl implements TranslationsSubtitlingStylingE
|
||||
@override String get borderColor => 'Randkleur';
|
||||
@override String get backgroundOpacity => 'Achtergrond transparantie';
|
||||
@override String get backgroundColor => 'Achtergrondkleur';
|
||||
@override String get position => 'Position';
|
||||
}
|
||||
|
||||
// Path: mpvConfig
|
||||
@@ -1316,6 +1317,7 @@ extension on TranslationsNl {
|
||||
'subtitlingStyling.borderColor' => 'Randkleur',
|
||||
'subtitlingStyling.backgroundOpacity' => 'Achtergrond transparantie',
|
||||
'subtitlingStyling.backgroundColor' => 'Achtergrondkleur',
|
||||
'subtitlingStyling.position' => 'Position',
|
||||
'mpvConfig.title' => 'MPV-configuratie',
|
||||
'mpvConfig.description' => 'Geavanceerde videospeler-instellingen',
|
||||
'mpvConfig.properties' => 'Eigenschappen',
|
||||
@@ -1497,9 +1499,9 @@ extension on TranslationsNl {
|
||||
'collections.failedToLoadItems' => ({required Object error}) => 'Collectie-items laden mislukt: ${error}',
|
||||
'collections.selectCollection' => 'Selecteer collectie',
|
||||
'collections.createNewCollection' => 'Nieuwe collectie maken',
|
||||
'collections.collectionName' => 'Collectienaam',
|
||||
_ => null,
|
||||
} ?? switch (path) {
|
||||
'collections.collectionName' => 'Collectienaam',
|
||||
'collections.enterCollectionName' => 'Voer collectienaam in',
|
||||
'collections.addedToCollection' => 'Toegevoegd aan collectie',
|
||||
'collections.errorAddingToCollection' => 'Fout bij toevoegen aan collectie',
|
||||
|
||||
@@ -532,6 +532,7 @@ class _TranslationsSubtitlingStylingSv implements TranslationsSubtitlingStylingE
|
||||
@override String get borderColor => 'Kantfärg';
|
||||
@override String get backgroundOpacity => 'Bakgrundsopacitet';
|
||||
@override String get backgroundColor => 'Bakgrundsfärg';
|
||||
@override String get position => 'Position';
|
||||
}
|
||||
|
||||
// Path: mpvConfig
|
||||
@@ -1316,6 +1317,7 @@ extension on TranslationsSv {
|
||||
'subtitlingStyling.borderColor' => 'Kantfärg',
|
||||
'subtitlingStyling.backgroundOpacity' => 'Bakgrundsopacitet',
|
||||
'subtitlingStyling.backgroundColor' => 'Bakgrundsfärg',
|
||||
'subtitlingStyling.position' => 'Position',
|
||||
'mpvConfig.title' => 'MPV-konfiguration',
|
||||
'mpvConfig.description' => 'Avancerade videospelares inställningar',
|
||||
'mpvConfig.properties' => 'Egenskaper',
|
||||
@@ -1497,9 +1499,9 @@ extension on TranslationsSv {
|
||||
'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',
|
||||
_ => null,
|
||||
} ?? switch (path) {
|
||||
'collections.collectionName' => 'Samlingsnamn',
|
||||
'collections.enterCollectionName' => 'Ange samlingsnamn',
|
||||
'collections.addedToCollection' => 'Tillagd i samling',
|
||||
'collections.errorAddingToCollection' => 'Fel vid tillägg i samling',
|
||||
|
||||
@@ -532,6 +532,7 @@ class _TranslationsSubtitlingStylingZh implements TranslationsSubtitlingStylingE
|
||||
@override String get borderColor => '边框颜色';
|
||||
@override String get backgroundOpacity => '背景不透明度';
|
||||
@override String get backgroundColor => '背景颜色';
|
||||
@override String get position => 'Position';
|
||||
}
|
||||
|
||||
// Path: mpvConfig
|
||||
@@ -1316,6 +1317,7 @@ extension on TranslationsZh {
|
||||
'subtitlingStyling.borderColor' => '边框颜色',
|
||||
'subtitlingStyling.backgroundOpacity' => '背景不透明度',
|
||||
'subtitlingStyling.backgroundColor' => '背景颜色',
|
||||
'subtitlingStyling.position' => 'Position',
|
||||
'mpvConfig.title' => 'MPV 配置',
|
||||
'mpvConfig.description' => '高级视频播放器设置',
|
||||
'mpvConfig.properties' => '属性',
|
||||
@@ -1497,9 +1499,9 @@ extension on TranslationsZh {
|
||||
'collections.failedToLoadItems' => ({required Object error}) => '加载合集项目失败:${error}',
|
||||
'collections.selectCollection' => '选择合集',
|
||||
'collections.createNewCollection' => '创建新合集',
|
||||
'collections.collectionName' => '合集名称',
|
||||
_ => null,
|
||||
} ?? switch (path) {
|
||||
'collections.collectionName' => '合集名称',
|
||||
'collections.enterCollectionName' => '输入合集名称',
|
||||
'collections.addedToCollection' => '已添加到合集',
|
||||
'collections.errorAddingToCollection' => '添加到合集失败',
|
||||
|
||||
@@ -365,7 +365,8 @@
|
||||
"borderSize": "Kantstorlek",
|
||||
"borderColor": "Kantfärg",
|
||||
"backgroundOpacity": "Bakgrundsopacitet",
|
||||
"backgroundColor": "Bakgrundsfärg"
|
||||
"backgroundColor": "Bakgrundsfärg",
|
||||
"position": "Position"
|
||||
},
|
||||
"mpvConfig": {
|
||||
"title": "MPV-konfiguration",
|
||||
|
||||
@@ -365,7 +365,8 @@
|
||||
"borderSize": "边框大小",
|
||||
"borderColor": "边框颜色",
|
||||
"backgroundOpacity": "背景不透明度",
|
||||
"backgroundColor": "背景颜色"
|
||||
"backgroundColor": "背景颜色",
|
||||
"position": "Position"
|
||||
},
|
||||
"mpvConfig": {
|
||||
"title": "MPV 配置",
|
||||
|
||||
@@ -276,6 +276,7 @@ class PlayerAndroid extends PlayerBase {
|
||||
required String borderColor,
|
||||
required String bgColor,
|
||||
required int bgOpacity,
|
||||
int subtitlePosition = 100,
|
||||
}) async {
|
||||
checkDisposed();
|
||||
if (!initialized) return;
|
||||
@@ -286,6 +287,7 @@ class PlayerAndroid extends PlayerBase {
|
||||
'borderColor': borderColor,
|
||||
'bgColor': bgColor,
|
||||
'bgOpacity': bgOpacity,
|
||||
'subtitlePosition': subtitlePosition,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -121,6 +121,7 @@ class _SubtitleStylingScreenState extends State<SubtitleStylingScreen> {
|
||||
String _borderColor = '#000000';
|
||||
String _backgroundColor = '#000000';
|
||||
int _backgroundOpacity = 0;
|
||||
int _subtitlePosition = 100;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -138,6 +139,7 @@ class _SubtitleStylingScreenState extends State<SubtitleStylingScreen> {
|
||||
_borderColor = _settingsService.getSubtitleBorderColor();
|
||||
_backgroundColor = _settingsService.getSubtitleBackgroundColor();
|
||||
_backgroundOpacity = _settingsService.getSubtitleBackgroundOpacity();
|
||||
_subtitlePosition = _settingsService.getSubtitlePosition();
|
||||
_isLoading = false;
|
||||
});
|
||||
}
|
||||
@@ -340,6 +342,45 @@ class _SubtitleStylingScreenState extends State<SubtitleStylingScreen> {
|
||||
},
|
||||
),
|
||||
const Divider(),
|
||||
// Subtitle Position Slider
|
||||
if (PlatformDetector.isTV())
|
||||
ListTile(
|
||||
title: Text(t.subtitlingStyling.position),
|
||||
trailing: Text(_subtitlePosition == 0 ? 'Top' : _subtitlePosition == 100 ? 'Bottom' : '$_subtitlePosition%'),
|
||||
onTap: () => _showTvSpinnerDialog(
|
||||
title: t.subtitlingStyling.position,
|
||||
currentValue: _subtitlePosition,
|
||||
min: 0,
|
||||
max: 100,
|
||||
step: 5,
|
||||
onSave: (value) {
|
||||
setState(() => _subtitlePosition = value);
|
||||
_settingsService.setSubtitlePosition(value);
|
||||
},
|
||||
),
|
||||
)
|
||||
else
|
||||
_StylingSliderSection(
|
||||
label: t.subtitlingStyling.position,
|
||||
value: _subtitlePosition,
|
||||
min: 0,
|
||||
max: 100,
|
||||
divisions: 20,
|
||||
valueFormatter: (value) {
|
||||
if (value == 0) return 'Top';
|
||||
if (value == 100) return 'Bottom';
|
||||
return '$value%';
|
||||
},
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
_subtitlePosition = value.toInt();
|
||||
});
|
||||
},
|
||||
onChangeEnd: (value) {
|
||||
_settingsService.setSubtitlePosition(_subtitlePosition);
|
||||
},
|
||||
),
|
||||
const Divider(),
|
||||
// Text Color
|
||||
_ColorSettingTile(
|
||||
label: t.subtitlingStyling.textColor,
|
||||
|
||||
@@ -343,6 +343,7 @@ class VideoPlayerScreenState extends State<VideoPlayerScreen> with WidgetsBindin
|
||||
'#${bgOpacity.toRadixString(16).padLeft(2, '0').toUpperCase()}$bgColor',
|
||||
);
|
||||
await player!.setProperty('sub-ass-override', 'no');
|
||||
await player!.setProperty('sub-pos', settingsService.getSubtitlePosition().toString());
|
||||
|
||||
// Platform-specific settings
|
||||
if (Platform.isIOS) {
|
||||
@@ -858,6 +859,7 @@ class VideoPlayerScreenState extends State<VideoPlayerScreen> with WidgetsBindin
|
||||
borderColor: settingsService.getSubtitleBorderColor(),
|
||||
bgColor: settingsService.getSubtitleBackgroundColor(),
|
||||
bgOpacity: settingsService.getSubtitleBackgroundOpacity(),
|
||||
subtitlePosition: settingsService.getSubtitlePosition(),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@ class SettingsService extends BaseSharedPreferencesService {
|
||||
static const String _keySubtitleBorderColor = 'subtitle_border_color';
|
||||
static const String _keySubtitleBackgroundColor = 'subtitle_background_color';
|
||||
static const String _keySubtitleBackgroundOpacity = 'subtitle_background_opacity';
|
||||
static const String _keySubtitlePosition = 'subtitle_position';
|
||||
static const String _keyAppLocale = 'app_locale';
|
||||
static const String _keyRememberTrackSelections = 'remember_track_selections';
|
||||
static const String _keyClickVideoTogglesPlayback = 'click_video_toggles_playback';
|
||||
@@ -345,6 +346,15 @@ class SettingsService extends BaseSharedPreferencesService {
|
||||
return prefs.getInt(_keySubtitleBackgroundOpacity) ?? 0;
|
||||
}
|
||||
|
||||
// Subtitle Position (0 = top, 100 = bottom, default 100)
|
||||
Future<void> setSubtitlePosition(int position) async {
|
||||
await prefs.setInt(_keySubtitlePosition, position.clamp(0, 100));
|
||||
}
|
||||
|
||||
int getSubtitlePosition() {
|
||||
return prefs.getInt(_keySubtitlePosition) ?? 100; // Default: bottom
|
||||
}
|
||||
|
||||
// Keyboard Shortcuts (Legacy String-based)
|
||||
Map<String, String> getDefaultKeyboardShortcuts() {
|
||||
return {
|
||||
@@ -1068,6 +1078,7 @@ class SettingsService extends BaseSharedPreferencesService {
|
||||
prefs.remove(_keySubtitleBorderColor),
|
||||
prefs.remove(_keySubtitleBackgroundColor),
|
||||
prefs.remove(_keySubtitleBackgroundOpacity),
|
||||
prefs.remove(_keySubtitlePosition),
|
||||
prefs.remove(_keyAppLocale),
|
||||
prefs.remove(_keyRememberTrackSelections),
|
||||
prefs.remove(_keyCustomDownloadPath),
|
||||
|
||||
Reference in New Issue
Block a user