feat: adjustable subtitle position

close #426
This commit is contained in:
edde746
2026-02-09 21:22:19 +01:00
parent 4d50c778ad
commit 2de92e660d
25 changed files with 129 additions and 23 deletions
@@ -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)
}
+2 -1
View File
@@ -365,7 +365,8 @@
"borderSize": "Rahmengröße",
"borderColor": "Rahmenfarbe",
"backgroundOpacity": "Hintergrunddeckkraft",
"backgroundColor": "Hintergrundfarbe"
"backgroundColor": "Hintergrundfarbe",
"position": "Position"
},
"mpvConfig": {
"title": "MPV-Konfiguration",
+2 -1
View File
@@ -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",
+2 -1
View File
@@ -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",
+2 -1
View File
@@ -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",
+2 -1
View File
@@ -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",
+2 -1
View File
@@ -365,7 +365,8 @@
"borderSize": "테두리 크기",
"borderColor": "테두리 색상",
"backgroundOpacity": "배경 불투명도",
"backgroundColor": "배경색"
"backgroundColor": "배경색",
"position": "Position"
},
"mpvConfig": {
"title": "MPV 설정",
+2 -1
View File
@@ -365,7 +365,8 @@
"borderSize": "Rand grootte",
"borderColor": "Randkleur",
"backgroundOpacity": "Achtergrond transparantie",
"backgroundColor": "Achtergrondkleur"
"backgroundColor": "Achtergrondkleur",
"position": "Position"
},
"mpvConfig": {
"title": "MPV-configuratie",
+2 -2
View File
@@ -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
+3 -1
View File
@@ -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',
+5 -1
View File
@@ -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?',
+3 -1
View File
@@ -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?',
+3 -1
View File
@@ -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 ?',
+3 -1
View File
@@ -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',
+3 -1
View File
@@ -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' => '누가 재생을 제어할 수 있나요?',
+3 -1
View File
@@ -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',
+3 -1
View File
@@ -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',
+3 -1
View File
@@ -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' => '添加到合集失败',
+2 -1
View File
@@ -365,7 +365,8 @@
"borderSize": "Kantstorlek",
"borderColor": "Kantfärg",
"backgroundOpacity": "Bakgrundsopacitet",
"backgroundColor": "Bakgrundsfärg"
"backgroundColor": "Bakgrundsfärg",
"position": "Position"
},
"mpvConfig": {
"title": "MPV-konfiguration",
+2 -1
View File
@@ -365,7 +365,8 @@
"borderSize": "边框大小",
"borderColor": "边框颜色",
"backgroundOpacity": "背景不透明度",
"backgroundColor": "背景颜色"
"backgroundColor": "背景颜色",
"position": "Position"
},
"mpvConfig": {
"title": "MPV 配置",
+2
View File
@@ -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,
+2
View File
@@ -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(),
);
}
+11
View File
@@ -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),