전체 점검에서 고침: 다시 켜면 전에 만든 자막 (jj_mkv) 다시 연결, Android 16 태블릿에서 화면 방향 고정 동작, 목록 머리글 한 줄, '이 기기에서' 띄어쓰기
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>main
parent
52deef4118
commit
98122539e7
|
|
@ -17,6 +17,10 @@
|
|||
android:name="${applicationName}"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:requestLegacyExternalStorage="true">
|
||||
<!-- Android 16: 큰 화면 (태블릿) 에서도 환경 설정 > 화면 방향 (가로 고정 · 세로 고정) 을 따르게 -->
|
||||
<property
|
||||
android:name="android.window.PROPERTY_COMPAT_ALLOW_RESTRICTED_RESIZABILITY"
|
||||
android:value="true" />
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
" · 다시 시작해야 Chrome 으로 바뀝니다": " · Restart to switch to Chrome",
|
||||
" · 대기 {0}": " · {0} waiting",
|
||||
" · 대기 {0}개": " · {0} waiting",
|
||||
" · 전에 만든 자막 {0}개 (jj_mkv)": " · {0} subtitles made earlier (jj_mkv)",
|
||||
" → MKV 만들기": " → Make MKV",
|
||||
" ⚠ 사용할 수 없는 코덱: {0}": " ⚠ Unavailable codec: {0}",
|
||||
" ⚠ 표현할 수 없는 글자 {0}개": " ⚠ {0} characters cannot be represented",
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
" · 다시 시작해야 Chrome 으로 바뀝니다": " · 再起動すると Chrome に切り替わります",
|
||||
" · 대기 {0}": " · 待機 {0}",
|
||||
" · 대기 {0}개": " · 待機 {0}個",
|
||||
" · 전에 만든 자막 {0}개 (jj_mkv)": " · 以前作成した字幕 {0}個(jj_mkv)",
|
||||
" → MKV 만들기": " → MKV 作成",
|
||||
" ⚠ 사용할 수 없는 코덱: {0}": " ⚠ 使用できないコーデック: {0}",
|
||||
" ⚠ 표현할 수 없는 글자 {0}개": " ⚠ 表現できない文字 {0}個",
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
" · 다시 시작해야 Chrome 으로 바뀝니다": " · 重新启动后切换到 Chrome",
|
||||
" · 대기 {0}": " · 等待 {0}",
|
||||
" · 대기 {0}개": " · 等待 {0} 个",
|
||||
" · 전에 만든 자막 {0}개 (jj_mkv)": " · 之前制作的字幕 {0} 个(jj_mkv)",
|
||||
" → MKV 만들기": " → 制作 MKV",
|
||||
" ⚠ 사용할 수 없는 코덱: {0}": " ⚠ 不可用的编解码器: {0}",
|
||||
" ⚠ 표현할 수 없는 글자 {0}개": " ⚠ {0} 个字符无法表示",
|
||||
|
|
|
|||
|
|
@ -340,9 +340,26 @@ class AppController extends ChangeNotifier {
|
|||
for (final d in siblings) {
|
||||
await _addExternal(v, d.path, d.language);
|
||||
}
|
||||
// 전에 만든 자막 (jj_mkv 의 파일명_ko.srt 등: AI 자막 · 번역 · 인터넷 자막) 도 다시 연결
|
||||
// (앱을 다시 켜거나 목록에 다시 넣어도 MKV 에 빠지지 않게). 음성인식 원본 파일명_AI.srt 는 언어별 파일과 같아서 뺀다.
|
||||
var made = 0;
|
||||
final out = outputDirFor(v.path);
|
||||
if (!p.equals(out, v.directory)) {
|
||||
List<String> files = const [];
|
||||
try {
|
||||
files = await services.storage.listFiles(out);
|
||||
} catch (_) {}
|
||||
for (final d in findSiblingSubtitles(v.path, files)) {
|
||||
if (d.isAi || d.language == undetermined) continue;
|
||||
if (v.subtitles.any((s) => s.path != null && p.equals(s.path!, d.path))) continue;
|
||||
await _addExternal(v, d.path, d.language);
|
||||
made++;
|
||||
}
|
||||
}
|
||||
final embeddedCount =
|
||||
v.subtitles.where((s) => s.kind == SubtitleKind.embedded).length;
|
||||
_log(trf('추가: {0} (내장 자막 {1}개, 같은 폴더 자막 {2}개)', [v.fileName, embeddedCount, siblings.length]));
|
||||
_log(trf('추가: {0} (내장 자막 {1}개, 같은 폴더 자막 {2}개)', [v.fileName, embeddedCount, siblings.length]) +
|
||||
(made > 0 ? trf(' · 전에 만든 자막 {0}개 (jj_mkv)', [made]) : ''));
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -454,15 +454,19 @@ class _VideoList extends StatelessWidget {
|
|||
Expanded(
|
||||
child: InkWell(
|
||||
onTap: c.videos.isEmpty ? null : c.toggleAllChecked,
|
||||
// 좁으면 글자를 줄여서 한 줄에 다 보이게
|
||||
child: FittedBox(
|
||||
fit: BoxFit.scaleDown,
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
c.checked.isEmpty
|
||||
? trf('동영상 {0}개 · 전체 선택', [c.videos.length])
|
||||
: trf('선택 {0} / {1}개', [c.checked.length, c.videos.length]),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(color: JjColors.textDim, fontSize: 12)),
|
||||
),
|
||||
),
|
||||
),
|
||||
// 정렬: 같은 것을 다시 누르면 반대 순서
|
||||
_sortButton('name', Icons.sort_by_alpha, tr('파일 이름')),
|
||||
_sortButton('date', Icons.calendar_month, tr('날짜')),
|
||||
|
|
|
|||
|
|
@ -62,6 +62,20 @@ void main() {
|
|||
expect(c.selected, busy);
|
||||
});
|
||||
|
||||
test('목록에 다시 넣으면 (앱을 다시 켜도) 전에 만든 자막 (jj_mkv 의 파일명_ko.srt 등) 이 다시 붙는다', () async {
|
||||
final c = _controller();
|
||||
final video = make('강의.mp4').path;
|
||||
make(p.join('jj_mkv', '강의_AI.srt'));
|
||||
make(p.join('jj_mkv', '강의_ko.srt'));
|
||||
make(p.join('jj_mkv', '강의_en.srt'));
|
||||
make(p.join('jj_mkv', '다른영상_ko.srt'));
|
||||
make('강의.ja.srt'); // 같은 폴더 자막
|
||||
await c.addVideos([video]);
|
||||
final v = c.videos.single;
|
||||
expect([for (final s in v.subtitles) p.basename(s.path!)]..sort(), ['강의.ja.srt', '강의_en.srt', '강의_ko.srt']);
|
||||
expect(v.subtitles.firstWhere((s) => s.path!.endsWith('_ko.srt')).language.code, 'ko');
|
||||
});
|
||||
|
||||
test('이동 폴더를 안 정했으면 옮기지 않는다', () async {
|
||||
final c = _controller();
|
||||
final a = VideoItem(make('a.mp4').path);
|
||||
|
|
|
|||
Loading…
Reference in New Issue