Files
sm-emby-share/lib/providers/subtitle_settings_provider.dart
2026-07-14 11:11:36 +08:00

188 lines
4.9 KiB
Dart

import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'shared/settings_persistence.dart';
const kLanguageNames = <String, String>{
'chi': '中文',
'zho': '中文',
'eng': '英语',
'jpn': '日语',
'kor': '韩语',
'fre': '法语',
'fra': '法语',
'ger': '德语',
'deu': '德语',
'spa': '西班牙语',
'ita': '意大利语',
'por': '葡萄牙语',
'rus': '俄语',
'ara': '阿拉伯语',
'hin': '印地语',
'tha': '泰语',
'vie': '越南语',
'pol': '波兰语',
'tur': '土耳其语',
'dut': '荷兰语',
'nld': '荷兰语',
'dan': '丹麦语',
'fin': '芬兰语',
'swe': '瑞典语',
'nor': '挪威语',
'nob': '书面挪威语',
'cat': '加泰罗尼亚语',
'cze': '捷克语',
'ces': '捷克语',
'hun': '匈牙利语',
'gre': '希腊语',
'ell': '希腊语',
'heb': '希伯来语',
'ind': '印度尼西亚语',
'may': '马来语',
'msa': '马来语',
'hrv': '克罗地亚语',
'baq': '巴斯克语',
'eus': '巴斯克语',
'glg': '加利西亚语',
'fil': '菲律宾语',
'rum': '罗马尼亚语',
'ron': '罗马尼亚语',
'bul': '保加利亚语',
'ukr': '乌克兰语',
'srp': '塞尔维亚语',
'slk': '斯洛伐克语',
'slv': '斯洛文尼亚语',
'lit': '立陶宛语',
'lav': '拉脱维亚语',
'est': '爱沙尼亚语',
};
class RememberedSubtitleTrack {
final int streamIndex;
final String? language;
final String? title;
final DateTime updatedAt;
const RememberedSubtitleTrack({
required this.streamIndex,
this.language,
this.title,
required this.updatedAt,
});
bool get isNone => streamIndex == -1;
Map<String, dynamic> toJson() => {
'streamIndex': streamIndex,
if (language != null) 'language': language,
if (title != null) 'title': title,
'updatedAt': updatedAt.toIso8601String(),
};
factory RememberedSubtitleTrack.fromJson(Map<String, dynamic> json) {
return RememberedSubtitleTrack(
streamIndex: (json['streamIndex'] as num?)?.toInt() ?? -1,
language: json['language'] as String?,
title: json['title'] as String?,
updatedAt:
DateTime.tryParse(json['updatedAt'] as String? ?? '') ??
DateTime.now(),
);
}
}
class SubtitleStyleSettings {
final int position;
final double fontSize;
final double delay;
final double bgOpacity;
const SubtitleStyleSettings({
this.position = 100,
this.fontSize = 55,
this.delay = 0.0,
this.bgOpacity = 0.0,
});
SubtitleStyleSettings copyWith({
int? position,
double? fontSize,
double? delay,
double? bgOpacity,
}) => SubtitleStyleSettings(
position: position ?? this.position,
fontSize: fontSize ?? this.fontSize,
delay: delay ?? this.delay,
bgOpacity: bgOpacity ?? this.bgOpacity,
);
}
class SubtitleSettingsNotifier extends AsyncNotifier<SubtitleStyleSettings>
with SettingsPersistence {
static const _keyPosition = 'smplayer.subtitle_position';
static const _keyFontSize = 'smplayer.subtitle_font_size';
static const _keyDelay = 'smplayer.subtitle_delay';
static const _keyBgOpacity = 'smplayer.subtitle_bg_opacity';
static const _keyLastTracks = 'smplayer.subtitle_last_tracks_primary';
static const _maxRememberedTracks = 200;
@override
Future<SubtitleStyleSettings> build() async {
final prefs = await getPrefs();
for (final stale in const [
'smplayer.subtitle_default_policy',
'smplayer.subtitle_preferred_language',
'smplayer.subtitle_secondary_position',
'smplayer.subtitle_secondary_font_size',
'smplayer.subtitle_secondary_delay',
'smplayer.subtitle_secondary_bg_opacity',
'smplayer.subtitle_secondary_follow_primary',
'smplayer.subtitle_last_tracks_secondary',
]) {
await prefs.remove(stale);
}
return SubtitleStyleSettings(
position: prefs.getInt(_keyPosition) ?? 100,
fontSize: prefs.getDouble(_keyFontSize) ?? 55,
delay: prefs.getDouble(_keyDelay) ?? 0.0,
bgOpacity: prefs.getDouble(_keyBgOpacity) ?? 0.0,
);
}
Future<void> setSettings(SubtitleStyleSettings settings) async {
state = AsyncValue.data(settings);
await persistFields({
_keyPosition: settings.position,
_keyFontSize: settings.fontSize,
_keyDelay: settings.delay,
_keyBgOpacity: settings.bgOpacity,
});
}
Future<void> saveLastSubtitleTrack(
String key,
RememberedSubtitleTrack? track,
) async {
if (track == null) return;
await putRemembered(
_keyLastTracks,
key,
track.toJson(),
_maxRememberedTracks,
);
}
Future<RememberedSubtitleTrack?> getLastSubtitleTrack(String key) async {
final entry = await readRemembered(_keyLastTracks, key);
return entry == null ? null : RememberedSubtitleTrack.fromJson(entry);
}
}
final subtitleSettingsProvider =
AsyncNotifierProvider<SubtitleSettingsNotifier, SubtitleStyleSettings>(
SubtitleSettingsNotifier.new,
);