51 MKV 목록: 동영상 줄을 길게 누르면 오른쪽 클릭과 같은 메뉴 · "목록에서 빼기 (파일은 그대로)"

- 터치 화면에서 길게 누르면 누른 자리에 메뉴 (그 줄 선택, 짧은 진동). 한 번 · 두 번 · 세 번 누르기는 그대로
- 메뉴의 "삭제 (목록에서 제거)" 를 "목록에서 빼기 (파일은 그대로)" 로 - 파일이 지워진다고 오해하지 않게
- AI 자막 만들기 · 인터넷 자막 찾기는 쓸 수 있을 때 (오른쪽 클릭 메뉴와 같은 조건) 나온다
- 시험: 길게 누르기 → 선택 · 메뉴, 한 번 누르기는 메뉴 없음

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
묶음3
RyuJongJin 2026-10-09 21:01:23 +09:00
parent ba332f9f84
commit 6a90ae5706
5 changed files with 38 additions and 5 deletions

View File

@ -780,6 +780,7 @@
"목록 · 영상 옆 · 영상 위에 나오는 광고 영역을 감춥니다": "Hides ad areas in lists · next to · on top of videos", "목록 · 영상 옆 · 영상 위에 나오는 광고 영역을 감춥니다": "Hides ad areas in lists · next to · on top of videos",
"목록 보기": "View list", "목록 보기": "View list",
"목록에서 빼기": "Remove from list", "목록에서 빼기": "Remove from list",
"목록에서 빼기 (파일은 그대로)": "Remove from list (file is kept)",
"목록에서 제거": "Remove from list", "목록에서 제거": "Remove from list",
"목록에서 지우기 (파일은 그대로)": "Remove from list (files stay)", "목록에서 지우기 (파일은 그대로)": "Remove from list (files stay)",
"목록을 모두 비울까요?": "Clear the whole list?", "목록을 모두 비울까요?": "Clear the whole list?",

View File

@ -780,6 +780,7 @@
"목록 · 영상 옆 · 영상 위에 나오는 광고 영역을 감춥니다": "リスト・動画の横・動画の上に出る広告エリアを隠します", "목록 · 영상 옆 · 영상 위에 나오는 광고 영역을 감춥니다": "リスト・動画の横・動画の上に出る広告エリアを隠します",
"목록 보기": "リストを見る", "목록 보기": "リストを見る",
"목록에서 빼기": "リストから外す", "목록에서 빼기": "リストから外す",
"목록에서 빼기 (파일은 그대로)": "リストから外す (ファイルはそのまま)",
"목록에서 제거": "リストから削除", "목록에서 제거": "リストから削除",
"목록에서 지우기 (파일은 그대로)": "リストから削除 (ファイルはそのまま)", "목록에서 지우기 (파일은 그대로)": "リストから削除 (ファイルはそのまま)",
"목록을 모두 비울까요?": "一覧をすべて空にしますか?", "목록을 모두 비울까요?": "一覧をすべて空にしますか?",

View File

@ -780,6 +780,7 @@
"목록 · 영상 옆 · 영상 위에 나오는 광고 영역을 감춥니다": "隐藏列表 · 视频旁 · 视频上方出现的广告区域", "목록 · 영상 옆 · 영상 위에 나오는 광고 영역을 감춥니다": "隐藏列表 · 视频旁 · 视频上方出现的广告区域",
"목록 보기": "查看列表", "목록 보기": "查看列表",
"목록에서 빼기": "从列表中移除", "목록에서 빼기": "从列表中移除",
"목록에서 빼기 (파일은 그대로)": "从列表中移除 (保留文件)",
"목록에서 제거": "从列表中移除", "목록에서 제거": "从列表中移除",
"목록에서 지우기 (파일은 그대로)": "从列表中删除 (文件保留)", "목록에서 지우기 (파일은 그대로)": "从列表中删除 (文件保留)",
"목록을 모두 비울까요?": "清空整个列表吗?", "목록을 모두 비울까요?": "清空整个列表吗?",

View File

@ -2,6 +2,7 @@ import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart' show HapticFeedback;
import '../app/app_controller.dart'; import '../app/app_controller.dart';
import '../app/bookmarks_controller.dart'; import '../app/bookmarks_controller.dart';
@ -686,7 +687,7 @@ class _VideoTile extends StatelessWidget {
item('search', Icons.travel_explore, tr('인터넷 자막 찾기'), enabled: !busy), item('search', Icons.travel_explore, tr('인터넷 자막 찾기'), enabled: !busy),
item('subtitle', Icons.subtitles_outlined, tr('자막 파일 추가'), enabled: !busy), item('subtitle', Icons.subtitles_outlined, tr('자막 파일 추가'), enabled: !busy),
const PopupMenuDivider(), const PopupMenuDivider(),
item('remove', Icons.close, tr('삭제 (목록에서 제거)'), enabled: !busy), item('remove', Icons.close, tr('목록에서 빼기 (파일은 그대로)'), enabled: !busy),
], ],
); );
if (pick == null || !context.mounted) return; if (pick == null || !context.mounted) return;
@ -734,7 +735,13 @@ class _VideoTile extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final isSel = c.selected == v; final isSel = c.selected == v;
final subs = v.subtitles.where((s) => s.enabled).length; final subs = v.subtitles.where((s) => s.enabled).length;
return InkWell( // 51: 터치 화면에서는 길게 누르면 오른쪽 클릭과 같은 메뉴 (누른 자리에)
return GestureDetector(
onLongPressStart: (d) {
HapticFeedback.selectionClick();
_menu(context, d.globalPosition);
},
child: InkWell(
// 한 번: 보기 · 두 번: 재생 · 세 번 이상: 이동 폴더로 옮기기 // 한 번: 보기 · 두 번: 재생 · 세 번 이상: 이동 폴더로 옮기기
onTap: () => _tapped(context), onTap: () => _tapped(context),
// 오른쪽 클릭: 이 동영상으로 할 수 있는 일 // 오른쪽 클릭: 이 동영상으로 할 수 있는 일
@ -805,7 +812,7 @@ class _VideoTile extends StatelessWidget {
], ],
), ),
), ),
); ));
} }
} }

View File

@ -106,7 +106,7 @@ void main() {
await tester.tapAt(tester.getCenter(find.text('둘째.mp4').first), buttons: kSecondaryButton); await tester.tapAt(tester.getCenter(find.text('둘째.mp4').first), buttons: kSecondaryButton);
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect(c.selected, c.videos[1]); expect(c.selected, c.videos[1]);
for (final label in ['대상 폴더 열기', '자막 파일 추가', '삭제 (목록에서 제거)']) { for (final label in ['대상 폴더 열기', '자막 파일 추가', '목록에서 빼기 (파일은 그대로)']) {
expect(find.text(label), findsWidgets, reason: label); expect(find.text(label), findsWidgets, reason: label);
} }
await tester.tap(find.text('대상 폴더 열기')); await tester.tap(find.text('대상 폴더 열기'));
@ -116,11 +116,34 @@ void main() {
// 삭제 // 삭제
await tester.tapAt(tester.getCenter(find.text('둘째.mp4').first), buttons: kSecondaryButton); await tester.tapAt(tester.getCenter(find.text('둘째.mp4').first), buttons: kSecondaryButton);
await tester.pumpAndSettle(); await tester.pumpAndSettle();
await tester.tap(find.text('삭제 (목록에서 제거)')); await tester.tap(find.text('목록에서 빼기 (파일은 그대로)'));
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect([for (final v in c.videos) v.fileName], ['첫째.mp4']); expect([for (final v in c.videos) v.fileName], ['첫째.mp4']);
}); });
testWidgets('51: 터치 화면 - 동영상 줄을 길게 누르면 오른쪽 클릭과 같은 메뉴 (그 줄이 선택됨)', (tester) async {
tester.view.physicalSize = const Size(1500, 900);
tester.view.devicePixelRatio = 1;
addTearDown(tester.view.reset);
final c = AppController(PlatformServices(mediaTool: ProcessMediaTool('x', 'y'), storage: DesktopStorageService()));
c.videos.addAll([VideoItem(r'D:\v\첫째.mp4'), VideoItem(r'D:\v\둘째.mp4')]);
c.selected = c.videos.first;
await tester.pumpWidget(MaterialApp(home: HomePage(c: c)));
await tester.longPress(find.text('둘째.mp4').first);
await tester.pumpAndSettle();
expect(c.selected, c.videos[1]);
for (final label in ['대상 폴더 열기', '자막 파일 추가', '목록에서 빼기 (파일은 그대로)']) {
expect(find.text(label), findsWidgets, reason: label);
}
// 한 번 누르기는 그대로 (메뉴 없이 보기)
await tester.tapAt(const Offset(5, 5));
await tester.pumpAndSettle();
await tester.tap(find.text('첫째.mp4').first);
await tester.pump(const Duration(milliseconds: 600));
expect(c.selected, c.videos.first);
expect(find.text('대상 폴더 열기'), findsNothing);
});
testWidgets('MKV 화면 위쪽 막대: 창이 좁아도 넘치지 않고 설정 · 종료 버튼이 창 안에 있다', (tester) async { testWidgets('MKV 화면 위쪽 막대: 창이 좁아도 넘치지 않고 설정 · 종료 버튼이 창 안에 있다', (tester) async {
addTearDown(tester.view.reset); addTearDown(tester.view.reset);
final dir = Directory.systemTemp.createTempSync('jj_bar_'); final dir = Directory.systemTemp.createTempSync('jj_bar_');