설정 A: 재생 분야 (PlaybackSettings) - 동영상 열기 · 재생 목록 · 외부 플레이어 · 자막 크기 · 기본 자막 언어
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>modular
parent
7fe2f0562f
commit
e828227693
|
|
@ -153,9 +153,9 @@ class AppController extends ChangeNotifier {
|
|||
}
|
||||
|
||||
void _applySettings() {
|
||||
playerSubtitleScale.value = settings.subtitleScale;
|
||||
playerSubtitleScale.value = settings.playback.subtitleScale;
|
||||
// 61: 기본 자막 언어 (MKV 기본 자막 트랙 · 플레이어가 먼저 켜는 자막)
|
||||
preferredSubtitleSetting = settings.preferredSubtitleLanguage;
|
||||
preferredSubtitleSetting = settings.playback.preferredSubtitleLanguage;
|
||||
// WebDAV 서버 (파일 탐색기 · Rsync 화면 · 복사 · 동기화가 dav:// 경로로 쓴다)
|
||||
DavRegistry.configure(settings.remote.webdavServers);
|
||||
// 88: SFTP 서버 (sftp:// 경로)
|
||||
|
|
@ -1294,7 +1294,7 @@ class AppController extends ChangeNotifier {
|
|||
final videos = files.where((f) => isVideoFile(f) || isAudioFile(f)).toList();
|
||||
if (videos.isEmpty) return null;
|
||||
final ext = p.extension(videos.first).replaceFirst('.', '').toLowerCase();
|
||||
final program = settings.externalPlayers[ext];
|
||||
final program = settings.playback.externalPlayers[ext];
|
||||
if (!internal && program != null && program.isNotEmpty) {
|
||||
// WebDAV 는 스트리밍 주소로 넘긴다 (아이디 · 비밀번호는 넣지 않음 - 55)
|
||||
if (external != null) {
|
||||
|
|
@ -1312,7 +1312,7 @@ class AppController extends ChangeNotifier {
|
|||
final siblings = isDav(videos.first)
|
||||
? [for (final e in await vList(vDirname(videos.first))) if (!e.isDir) e.path]
|
||||
: await services.storage.listFiles(p.dirname(videos.first));
|
||||
return buildPlaylist(videos.first, siblings, settings.playlistMode);
|
||||
return buildPlaylist(videos.first, siblings, settings.playback.playlistMode);
|
||||
}
|
||||
|
||||
/// 재생 중 고를 수 있는 외부 자막: 같은 폴더의 자막 + jj_mkv 안의 파일명_*.srt
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@ import 'package:path/path.dart' as p;
|
|||
|
||||
import '../core/reader_sources.dart' show defaultImageExtensions;
|
||||
import '../core/download_detect.dart';
|
||||
import '../core/playlist.dart';
|
||||
import 'settings/records.dart';
|
||||
import 'settings/settings_group.dart';
|
||||
import 'settings/playback_settings.dart';
|
||||
import 'settings/mkv_settings.dart';
|
||||
import 'settings/display_settings.dart';
|
||||
import 'settings/remote_settings.dart';
|
||||
|
|
@ -25,6 +25,7 @@ import 'settings/explorer_settings.dart';
|
|||
export 'settings/records.dart';
|
||||
export 'settings/settings_group.dart';
|
||||
export 'settings/settings_store.dart';
|
||||
export 'settings/playback_settings.dart';
|
||||
export 'settings/mkv_settings.dart';
|
||||
export 'settings/display_settings.dart';
|
||||
export 'settings/remote_settings.dart';
|
||||
|
|
@ -71,15 +72,11 @@ class AppSettings {
|
|||
|
||||
|
||||
|
||||
/// 탐색기에서 동영상을 열었을 때 (더블클릭 · 연결 프로그램): 'play' 바로 재생 / 'add' 편집 목록에 추가
|
||||
String openFileAction = 'play';
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// 프로그램이 켜져 있을 때 탐색기에서 연 동영상 재생: 'same' 켜져 있는 창에서 / 'new' 새 재생 창
|
||||
String openFileWindow = 'same';
|
||||
|
||||
|
||||
|
||||
|
|
@ -181,15 +178,11 @@ class AppSettings {
|
|||
bool recycleOnDelete = true;
|
||||
|
||||
|
||||
/// 61: 기본 자막 언어 (MKV 의 기본 자막 트랙 · 플레이어가 먼저 켜는 자막). '' = 화면 언어 따르기, 그 밖은 자막 언어 코드 (ko · ja …)
|
||||
String preferredSubtitleLanguage = '';
|
||||
|
||||
|
||||
/// 39: 켤 때 "모든 파일 접근" 안내를 한 번 보였는지 (그 뒤로는 파일 탐색기 안의 안내로)
|
||||
bool allFilesHintShown = false;
|
||||
|
||||
/// 내장 플레이어 자막 글자 크기 배율 (0.5 ~ 2.5, 기본 1)
|
||||
double subtitleScale = 1.0;
|
||||
|
||||
|
||||
|
||||
|
|
@ -232,11 +225,7 @@ class AppSettings {
|
|||
|
||||
|
||||
|
||||
/// 동영상 하나를 재생할 때 재생 목록 (기본: 같은 시리즈)
|
||||
PlaylistMode playlistMode = PlaylistMode.series;
|
||||
|
||||
/// 확장자별 재생 프로그램 (없으면 내장 플레이어): 'system' 또는 실행 파일 경로
|
||||
Map<String, String> externalPlayers = {};
|
||||
|
||||
|
||||
|
||||
|
|
@ -284,8 +273,11 @@ class AppSettings {
|
|||
/// MKV · 자막 만들기 (저장 위치 · 이동 버튼 · 인코딩 · AI 자막 · OpenSubtitles)
|
||||
final mkv = MkvSettings();
|
||||
|
||||
/// 재생 (동영상 열기 · 재생 목록 · 외부 플레이어 · 자막 크기 · 기본 자막 언어)
|
||||
final playback = PlaybackSettings();
|
||||
|
||||
/// 설정 분야들 (설정 A) - 저마다 자기 키를 읽고 쓴다. toJson · fromJson 은 이 목록을 돌며 합치기만 한다
|
||||
List<SettingsGroup> get groups => [explorer, network, tor, copy, aiImage, reader, download, browser, run, vault, tools, remote, display, mkv];
|
||||
List<SettingsGroup> get groups => [explorer, network, tor, copy, aiImage, reader, download, browser, run, vault, tools, remote, display, mkv, playback];
|
||||
|
||||
/// [plainSecrets]: 안전 저장소를 쓸 수 없을 때만 (예전 파일에 있던 비밀 값을 잃지 않게) 예전처럼 파일에 둔다
|
||||
Map<String, Object?> toJson({bool plainSecrets = false}) {
|
||||
|
|
@ -294,8 +286,6 @@ class AppSettings {
|
|||
...stripSecrets(extra),
|
||||
'folderBookmarks': [for (final b in folderBookmarks) b.toJson()],
|
||||
'cookieScopeV2': true,
|
||||
'openFileAction': openFileAction,
|
||||
'openFileWindow': openFileWindow,
|
||||
'robocopyLinksV1': true,
|
||||
'imageExts': imageExts,
|
||||
'cleanupPrechecked': cleanupPrechecked,
|
||||
|
|
@ -303,12 +293,8 @@ class AppSettings {
|
|||
'allowInnerToOuter': allowInnerToOuter,
|
||||
'rememberPasswords': rememberPasswords,
|
||||
'recycleOnDelete': recycleOnDelete,
|
||||
'preferredSubtitleLanguage': preferredSubtitleLanguage,
|
||||
// 116: 예전 판의 표시 ('allFilesHintShown') 는 권한이 없어진 것을 몰라 다시 띄우지 못했다 → 새 이름으로 한 번 더
|
||||
'allFilesHint2': allFilesHintShown,
|
||||
'subtitleScale': subtitleScale,
|
||||
'playlistMode': playlistMode.name,
|
||||
'externalPlayers': externalPlayers,
|
||||
};
|
||||
for (final g in groups) {
|
||||
g.write(j, plainSecrets: plainSecrets);
|
||||
|
|
@ -317,12 +303,8 @@ class AppSettings {
|
|||
}
|
||||
|
||||
factory AppSettings.fromJson(Map<String, dynamic> j) {
|
||||
T pick<T extends Enum>(List<T> values, Object? name, T fallback) =>
|
||||
values.firstWhere((v) => v.name == name, orElse: () => fallback);
|
||||
final s = AppSettings()
|
||||
..folderBookmarks = [for (final x in (j['folderBookmarks'] as List?) ?? const []) ?FolderBookmark.fromJson(x)]
|
||||
..openFileAction = j['openFileAction'] == 'add' ? 'add' : 'play'
|
||||
..openFileWindow = j['openFileWindow'] == 'new' ? 'new' : 'same'
|
||||
..imageExts = j['imageExts'] is List
|
||||
? [for (final x in j['imageExts'] as List) '$x'.toLowerCase()]
|
||||
: [...defaultImageExtensions]
|
||||
|
|
@ -333,11 +315,7 @@ class AppSettings {
|
|||
..allowInnerToOuter = j['allowInnerToOuter'] != false
|
||||
..rememberPasswords = j['rememberPasswords'] != false
|
||||
..recycleOnDelete = j['recycleOnDelete'] != false
|
||||
..preferredSubtitleLanguage = j['preferredSubtitleLanguage'] is String ? j['preferredSubtitleLanguage'] as String : ''
|
||||
..allFilesHintShown = j['allFilesHint2'] == true
|
||||
..subtitleScale = ((j['subtitleScale'] as num?)?.toDouble() ?? 1.0).clamp(0.5, 2.5)
|
||||
..playlistMode = pick(PlaylistMode.values, j['playlistMode'], PlaylistMode.series)
|
||||
..externalPlayers = ((j['externalPlayers'] as Map?) ?? const {}).cast<String, String>();
|
||||
..allFilesHintShown = j['allFilesHint2'] == true;
|
||||
// 분야를 먼저 읽는다 - 바뀐 기본값 알림 ([_migrated]) 이 분야의 값을 본다
|
||||
for (final g in s.groups) {
|
||||
g.read(j);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
import '../../core/playlist.dart';
|
||||
import 'settings_group.dart';
|
||||
|
||||
/// 약속 (설정 A): 환경 설정 > 재생 (동영상 열기 · 재생 목록 · 외부 플레이어 · 자막 크기 · 기본 자막 언어) - 자기 키 (이름 · 처음 값 · 읽기 · 쓰기) 를 스스로 갖는다.
|
||||
/// 설정 하나를 더할 때는 이 파일만 고친다. 저장 파일의 키 이름은 예전 그대로 (평평한 키)
|
||||
class PlaybackSettings implements SettingsGroup {
|
||||
/// 탐색기에서 동영상을 열었을 때 (더블클릭 · 연결 프로그램): 'play' 바로 재생 / 'add' 편집 목록에 추가
|
||||
String openFileAction = 'play';
|
||||
|
||||
/// 프로그램이 켜져 있을 때 탐색기에서 연 동영상 재생: 'same' 켜져 있는 창에서 / 'new' 새 재생 창
|
||||
String openFileWindow = 'same';
|
||||
|
||||
/// 61: 기본 자막 언어 (MKV 의 기본 자막 트랙 · 플레이어가 먼저 켜는 자막). '' = 화면 언어 따르기, 그 밖은 자막 언어 코드 (ko · ja …)
|
||||
String preferredSubtitleLanguage = '';
|
||||
|
||||
/// 내장 플레이어 자막 글자 크기 배율 (0.5 ~ 2.5, 기본 1)
|
||||
double subtitleScale = 1.0;
|
||||
|
||||
/// 동영상 하나를 재생할 때 재생 목록 (기본: 같은 시리즈)
|
||||
PlaylistMode playlistMode = PlaylistMode.series;
|
||||
|
||||
/// 확장자별 재생 프로그램 (없으면 내장 플레이어): 'system' 또는 실행 파일 경로
|
||||
Map<String, String> externalPlayers = {};
|
||||
|
||||
@override
|
||||
void write(Map<String, Object?> j, {required bool plainSecrets}) {
|
||||
j['openFileAction'] = openFileAction;
|
||||
j['openFileWindow'] = openFileWindow;
|
||||
j['playlistMode'] = playlistMode.name;
|
||||
j['externalPlayers'] = externalPlayers;
|
||||
j['subtitleScale'] = subtitleScale;
|
||||
j['preferredSubtitleLanguage'] = preferredSubtitleLanguage;
|
||||
}
|
||||
|
||||
@override
|
||||
void read(Map<String, dynamic> j) {
|
||||
openFileAction = j['openFileAction'] == 'add' ? 'add' : 'play';
|
||||
openFileWindow = j['openFileWindow'] == 'new' ? 'new' : 'same';
|
||||
preferredSubtitleLanguage = j['preferredSubtitleLanguage'] is String ? j['preferredSubtitleLanguage'] as String : '';
|
||||
subtitleScale = ((j['subtitleScale'] as num?)?.toDouble() ?? 1.0).clamp(0.5, 2.5);
|
||||
playlistMode = pickEnum(PlaylistMode.values, j['playlistMode'], PlaylistMode.series);
|
||||
externalPlayers = ((j['externalPlayers'] as Map?) ?? const {}).cast<String, String>();
|
||||
}
|
||||
}
|
||||
|
|
@ -367,7 +367,7 @@ Future<void> main(List<String> args) async {
|
|||
if (videos.isEmpty) return;
|
||||
// 어느 쪽이든 MKV 화면의 목록에는 들어간다
|
||||
final added = controller.addVideos(videos, allowOutputFolder: true);
|
||||
if (controller.settings.openFileAction == 'add') {
|
||||
if (controller.settings.playback.openFileAction == 'add') {
|
||||
await added;
|
||||
final first = controller.videos.where((v) => videos.any((f) => p.equals(f, v.path))).firstOrNull;
|
||||
if (first != null) controller.select(first);
|
||||
|
|
@ -444,7 +444,7 @@ Future<void> openFromOtherApp(
|
|||
if (ctx == null || !ctx.mounted) return;
|
||||
if (paths.isNotEmpty) {
|
||||
final added = c.addVideos(paths, allowOutputFolder: true);
|
||||
if (c.settings.openFileAction == 'add') {
|
||||
if (c.settings.playback.openFileAction == 'add') {
|
||||
await added;
|
||||
final first = c.videos.where((v) => paths.any((f) => p.equals(f, v.path))).firstOrNull;
|
||||
if (first != null) c.select(first);
|
||||
|
|
@ -535,9 +535,9 @@ void watchDnsFailure(GlobalKey<ScaffoldMessengerState> messengerKey, AppControll
|
|||
|
||||
/// 탐색기에서 연 동영상을 새 재생 창으로 띄울지 (재생 요청 + 설정 "새 창에서")
|
||||
bool wantsNewPlayerWindow(LaunchRequest r, AppSettings s) =>
|
||||
s.openFileWindow == 'new' &&
|
||||
s.playback.openFileWindow == 'new' &&
|
||||
r.files.any(isVideoFile) &&
|
||||
(r.action == LaunchAction.play || (r.action == LaunchAction.add && s.openFileAction == 'play'));
|
||||
(r.action == LaunchAction.play || (r.action == LaunchAction.add && s.playback.openFileAction == 'play'));
|
||||
|
||||
extension on String {
|
||||
String ifEmptyText(String other) => isEmpty ? other : this;
|
||||
|
|
|
|||
|
|
@ -405,8 +405,8 @@ class _PlayerPageState extends State<PlayerPage> {
|
|||
// 자막 글자 크기 (설정에 남는다)
|
||||
SubmenuButton(menuChildren: [
|
||||
for (final r in const [0.6, 0.8, 1.0, 1.2, 1.5, 2.0, 2.5])
|
||||
item('${(r * 100).round()}%', () => c.updateSettings((x) => x.subtitleScale = r),
|
||||
checked: (c.settings.subtitleScale - r).abs() < 0.01),
|
||||
item('${(r * 100).round()}%', () => c.updateSettings((x) => x.playback.subtitleScale = r),
|
||||
checked: (c.settings.playback.subtitleScale - r).abs() < 0.01),
|
||||
], child: Text(tr('자막 크기'))),
|
||||
if (s.audioTracks.length > 1)
|
||||
SubmenuButton(menuChildren: [
|
||||
|
|
|
|||
|
|
@ -42,8 +42,8 @@ class _MkvSettingsSectionState extends State<MkvSettingsSection> {
|
|||
title: Text(tr('기본 자막 언어')),
|
||||
subtitle: Text(tr('MKV 의 기본 자막 트랙 · 플레이어가 먼저 켜는 자막')),
|
||||
trailing: SubtitleLanguagePicker(
|
||||
value: s.preferredSubtitleLanguage,
|
||||
onChanged: (v) => c.updateSettings((x) => x.preferredSubtitleLanguage = v),
|
||||
value: s.playback.preferredSubtitleLanguage,
|
||||
onChanged: (v) => c.updateSettings((x) => x.playback.preferredSubtitleLanguage = v),
|
||||
),
|
||||
),
|
||||
SettingTile(
|
||||
|
|
@ -219,11 +219,11 @@ class _PlaySettingsSectionState extends State<PlaySettingsSection> {
|
|||
title: Text(tr('동영상 하나를 재생할 때')),
|
||||
subtitle: Text(tr('시리즈: file_001 · file_002, S01E01 · S01E02 처럼 번호만 다른 파일')),
|
||||
trailing: DropdownButton<PlaylistMode>(
|
||||
value: s.playlistMode,
|
||||
value: s.playback.playlistMode,
|
||||
items: [
|
||||
for (final m in PlaylistMode.values) DropdownMenuItem(value: m, child: Text(m.label)),
|
||||
],
|
||||
onChanged: (m) => c.updateSettings((x) => x.playlistMode = m!),
|
||||
onChanged: (m) => c.updateSettings((x) => x.playback.playlistMode = m!),
|
||||
),
|
||||
),
|
||||
SettingTile(
|
||||
|
|
@ -232,12 +232,12 @@ class _PlaySettingsSectionState extends State<PlaySettingsSection> {
|
|||
? tr('더블클릭 · 연결 프로그램으로 JJ_MKVMaker 를 골랐을 때 (오른쪽 클릭 메뉴는 그대로)')
|
||||
: tr('파일 앱의 "다음으로 열기" · 공유에서 JJ_MKVMaker 를 골랐을 때')),
|
||||
trailing: DropdownButton<String>(
|
||||
value: s.openFileAction,
|
||||
value: s.playback.openFileAction,
|
||||
items: [
|
||||
DropdownMenuItem(value: 'play', child: Text(tr('바로 재생 (기본)'))),
|
||||
DropdownMenuItem(value: 'add', child: Text(tr('편집 목록에 추가 (MKV 만들기 대상)'))),
|
||||
],
|
||||
onChanged: (v) => c.updateSettings((x) => x.openFileAction = v!),
|
||||
onChanged: (v) => c.updateSettings((x) => x.playback.openFileAction = v!),
|
||||
),
|
||||
),
|
||||
if (desk) ...[
|
||||
|
|
@ -245,12 +245,12 @@ class _PlaySettingsSectionState extends State<PlaySettingsSection> {
|
|||
title: Text(tr('탐색기에서 연 동영상을 재생할 창')),
|
||||
subtitle: Text(tr('프로그램이 이미 켜져 있을 때. 새 창은 재생만 하는 창이며 닫으면 그 창만 끝납니다')),
|
||||
trailing: DropdownButton<String>(
|
||||
value: s.openFileWindow,
|
||||
value: s.playback.openFileWindow,
|
||||
items: [
|
||||
DropdownMenuItem(value: 'same', child: Text(tr('켜져 있는 창에서 (기본)'))),
|
||||
DropdownMenuItem(value: 'new', child: Text(tr('새 창에서'))),
|
||||
],
|
||||
onChanged: (v) => c.updateSettings((x) => x.openFileWindow = v!),
|
||||
onChanged: (v) => c.updateSettings((x) => x.playback.openFileWindow = v!),
|
||||
),
|
||||
),
|
||||
ExternalPlayersTile(c: c),
|
||||
|
|
@ -316,13 +316,13 @@ class ExternalPlayersTile extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final map = c.settings.externalPlayers;
|
||||
final map = c.settings.playback.externalPlayers;
|
||||
final vlc = c.services.shell.vlcPath;
|
||||
Future<void> set(String ext, String? v) => c.updateSettings((x) {
|
||||
if (v == null || v.isEmpty) {
|
||||
x.externalPlayers.remove(ext);
|
||||
x.playback.externalPlayers.remove(ext);
|
||||
} else {
|
||||
x.externalPlayers[ext] = v;
|
||||
x.playback.externalPlayers[ext] = v;
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -373,7 +373,7 @@ void main() {
|
|||
File(p.join(root.path, '영상', '메모.txt')).writeAsStringSync('t');
|
||||
addTearDown(RemoteStreamBridge.close);
|
||||
final c = AppController(PlatformServices(mediaTool: ProcessMediaTool('x', 'y'), storage: DesktopStorageService()));
|
||||
c.settings.playlistMode = PlaylistMode.folder;
|
||||
c.settings.playback.playlistMode = PlaylistMode.folder;
|
||||
final plan = await c.preparePlayback(['ftp://f1/영상/1화.mkv']);
|
||||
expect(plan!.$1, ['ftp://f1/영상/1화.mkv', 'ftp://f1/영상/2화.mkv'], reason: '같은 폴더의 동영상만 차례로 (다음 화)');
|
||||
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ void main() {
|
|||
|
||||
test('기본 자막 언어 설정: 화면 언어 따르기 (처음 값) · 고른 언어가 화면 언어보다 먼저 · 저장', () async {
|
||||
addTearDown(() => preferredSubtitleSetting = '');
|
||||
expect(AppSettings().preferredSubtitleLanguage, '', reason: '처음 값은 화면 언어 따르기');
|
||||
expect(AppSettings().playback.preferredSubtitleLanguage, '', reason: '처음 값은 화면 언어 따르기');
|
||||
await i18n.apply('ja', save: false);
|
||||
preferredSubtitleSetting = 'ko'; // 화면은 일본어, 자막은 한국어
|
||||
expect(preferredDefaultLanguage, 'kor');
|
||||
|
|
@ -65,8 +65,8 @@ void main() {
|
|||
expect(preferredDefaultLanguage, 'vie');
|
||||
preferredSubtitleSetting = '';
|
||||
expect(preferredDefaultLanguage, 'jpn');
|
||||
final s = AppSettings()..preferredSubtitleLanguage = 'zh-Hans';
|
||||
expect(AppSettings.fromJson(s.toJson()).preferredSubtitleLanguage, 'zh-Hans');
|
||||
final s = AppSettings()..playback.preferredSubtitleLanguage = 'zh-Hans';
|
||||
expect(AppSettings.fromJson(s.toJson()).playback.preferredSubtitleLanguage, 'zh-Hans');
|
||||
});
|
||||
|
||||
test('Android 저장소 이름: 내장 · SD 카드는 앱 화면 언어로, USB 등은 기기 이름 그대로', () async {
|
||||
|
|
|
|||
|
|
@ -147,18 +147,18 @@ void main() {
|
|||
final play = LaunchRequest.parse(['--play', r'D:.mkv']);
|
||||
final sub = LaunchRequest.parse(['--subtitle', r'D:.mkv']);
|
||||
final s = AppSettings();
|
||||
expect([s.openFileAction, s.openFileWindow], ['play', 'same']);
|
||||
expect([s.playback.openFileAction, s.playback.openFileWindow], ['play', 'same']);
|
||||
expect(wantsNewPlayerWindow(open, s), isFalse); // 기본: 켜져 있는 창에서
|
||||
s.openFileWindow = 'new';
|
||||
s.playback.openFileWindow = 'new';
|
||||
expect(wantsNewPlayerWindow(open, s), isTrue);
|
||||
expect(wantsNewPlayerWindow(play, s), isTrue);
|
||||
expect(wantsNewPlayerWindow(sub, s), isFalse); // 자막 만들기는 원래 창
|
||||
expect(wantsNewPlayerWindow(LaunchRequest.parse(const []), s), isFalse);
|
||||
s.openFileAction = 'add';
|
||||
s.playback.openFileAction = 'add';
|
||||
expect(wantsNewPlayerWindow(open, s), isFalse); // 목록에 추가는 원래 창
|
||||
expect(wantsNewPlayerWindow(play, s), isTrue);
|
||||
final back = AppSettings.fromJson(s.toJson());
|
||||
expect([back.openFileAction, back.openFileWindow], ['add', 'new']);
|
||||
expect([back.playback.openFileAction, back.playback.openFileWindow], ['add', 'new']);
|
||||
});
|
||||
|
||||
test('Android 화면 방향: 기본 자동, 가로 · 세로 고정 저장, 예전 기본 (가로 고정) 은 한 번 자동으로', () {
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ void main() {
|
|||
|
||||
test('같은 폴더 동영상 목록 · 다리로 스트리밍 (Range · 건너뛰기) · 다음 파일 · 그 자막', () async {
|
||||
final c = AppController(PlatformServices(mediaTool: ProcessMediaTool('x', 'y'), storage: DesktopStorageService()));
|
||||
c.settings.playlistMode = PlaylistMode.folder;
|
||||
c.settings.playback.playlistMode = PlaylistMode.folder;
|
||||
final plan = await c.preparePlayback(['sftp://s1/영상/1화.mkv']);
|
||||
expect(plan!.$1, ['sftp://s1/영상/1화.mkv', 'sftp://s1/영상/2화.mkv'], reason: '같은 폴더의 동영상만 차례로');
|
||||
|
||||
|
|
|
|||
|
|
@ -16,12 +16,12 @@ void main() {
|
|||
setUp(() => c = AppController(PlatformServices(mediaTool: ProcessMediaTool('x', 'y'), storage: DesktopStorageService())));
|
||||
|
||||
test('자막 글자 크기: 설정에 남고 플레이어에 바로 반영', () async {
|
||||
await c.updateSettings((s) => s.subtitleScale = 1.5);
|
||||
await c.updateSettings((s) => s.playback.subtitleScale = 1.5);
|
||||
expect(playerSubtitleScale.value, 1.5);
|
||||
expect(AppSettings.fromJson(c.settings.toJson()).subtitleScale, 1.5);
|
||||
expect(AppSettings.fromJson({'subtitleScale': 9}).subtitleScale, 2.5);
|
||||
expect(AppSettings.fromJson({}).subtitleScale, 1.0);
|
||||
await c.updateSettings((s) => s.subtitleScale = 1.0);
|
||||
expect(AppSettings.fromJson(c.settings.toJson()).playback.subtitleScale, 1.5);
|
||||
expect(AppSettings.fromJson({'subtitleScale': 9}).playback.subtitleScale, 2.5);
|
||||
expect(AppSettings.fromJson({}).playback.subtitleScale, 1.0);
|
||||
await c.updateSettings((s) => s.playback.subtitleScale = 1.0);
|
||||
});
|
||||
|
||||
test('WebDAV 가 끼면 탐색기 복사 확인 창에 robocopy 가 아니라 실제 방법 (현재 방식)', () {
|
||||
|
|
|
|||
|
|
@ -323,7 +323,7 @@ void main() {
|
|||
});
|
||||
addTearDown(RemoteStreamBridge.close);
|
||||
final c = AppController(PlatformServices(mediaTool: ProcessMediaTool('x', 'y'), storage: DesktopStorageService()));
|
||||
c.settings.playlistMode = PlaylistMode.folder;
|
||||
c.settings.playback.playlistMode = PlaylistMode.folder;
|
||||
final plan = await c.preparePlayback(['smb://m1/영상/1화.mkv']);
|
||||
expect(plan!.$1, ['smb://m1/영상/1화.mkv', 'smb://m1/영상/2화.mkv'], reason: '같은 폴더의 동영상만 차례로 (다음 화)');
|
||||
|
||||
|
|
|
|||
|
|
@ -186,7 +186,7 @@ void main() {
|
|||
expect(await res.transform(const SystemEncoding().decoder).join(), 'v1');
|
||||
http.close();
|
||||
final c = AppController(PlatformServices(mediaTool: ProcessMediaTool('x', 'y'), storage: DesktopStorageService()));
|
||||
c.settings.playlistMode = PlaylistMode.folder;
|
||||
c.settings.playback.playlistMode = PlaylistMode.folder;
|
||||
final before = server.requests.where((r) => r.startsWith('GET')).length;
|
||||
final plan = await c.preparePlayback(['dav://$id/영상/1화.mkv']);
|
||||
expect(plan!.$1, ['dav://$id/영상/1화.mkv', 'dav://$id/영상/2화.mkv']);
|
||||
|
|
|
|||
Loading…
Reference in New Issue