WIP X-plore P3 연결: 길게 누르기 [해시] · [폴더 속성], 빠른 보기 [16진] (검토 대기)
관리자 지시 (10/18): cd 의 도우미 (b6e4717, lib/ui/file_tools.dart) 를 탐색기에 연결.
- 길게 누르기 메뉴 (폴더 크기 계산 옆 - cd 가 넣을 격자 · 글 뷰어 항목과 떨어진 곳):
· 파일: [해시 (MD5 · SHA-256)] → showFileHash (진행 · 취소, 복사, 붙여 넣은 값과 비교)
· 폴더: [폴더 속성] → showFolderProperties (파일 · 폴더 수 · 크기 · 링크 · 만든 · 바뀐 때)
- 빠른 보기 (81) 창: [16진] → HexViewerPage (앞부분부터 나눠 읽기)
- 내 판단: 셋 다 이 기기의 파일만 (원격 WebDAV 는 해시 · 16진 · 속성이 파일을 다 받아야 해서 메뉴에서 뺌)
시험: explorer_test 에 연결 시험 (해시 "hello" 의 MD5 · SHA-256 값, sub 의 "파일 1개 · 폴더 0개", 빠른 보기 → 16진 화면) -
explorer · file_tools · quick_look 57 통과, analyze 문제 없음, l10n 빠짐 0. 캡처는 아직 (Windows 캡처 시험은 다음).
j (SMB 찾기) 는 이 브랜치에 88 (SMB) 이 없어 smb_find (묶음7_88 위) 에서 (관리자 지시).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
xplore_p3
parent
b6e47178e3
commit
fba28cb027
|
|
@ -71,6 +71,7 @@
|
||||||
"1/2 · AI 그림으로 다듬는 중": "1/2 · Refining with AI image",
|
"1/2 · AI 그림으로 다듬는 중": "1/2 · Refining with AI image",
|
||||||
"10초 뒤로 (←)": "Back 10 seconds (←)",
|
"10초 뒤로 (←)": "Back 10 seconds (←)",
|
||||||
"10초 앞으로 (→)": "Forward 10 seconds (→)",
|
"10초 앞으로 (→)": "Forward 10 seconds (→)",
|
||||||
|
"16진": "Hex",
|
||||||
"16진 보기 · {0}": "Hex view · {0}",
|
"16진 보기 · {0}": "Hex view · {0}",
|
||||||
"1배 (선명하게)": "1× (sharpen)",
|
"1배 (선명하게)": "1× (sharpen)",
|
||||||
"1분 안": "under 1 min",
|
"1분 안": "under 1 min",
|
||||||
|
|
@ -2413,6 +2414,7 @@
|
||||||
"폴더 복사 · 이동 방법": "Folder copy · move method",
|
"폴더 복사 · 이동 방법": "Folder copy · move method",
|
||||||
"폴더 삭제: {0} (안의 {1}개 포함)": "Folder deleted: {0} (including {1} inside)",
|
"폴더 삭제: {0} (안의 {1}개 포함)": "Folder deleted: {0} (including {1} inside)",
|
||||||
"폴더 선택": "Choose folder",
|
"폴더 선택": "Choose folder",
|
||||||
|
"폴더 속성": "Folder properties",
|
||||||
"폴더 속성 · {0}": "Folder properties · {0}",
|
"폴더 속성 · {0}": "Folder properties · {0}",
|
||||||
"폴더 수정": "Edit folder",
|
"폴더 수정": "Edit folder",
|
||||||
"폴더 안 파일 크기의 합을 목록에 보입니다. 큰 폴더 · NAS 는 읽는 데 오래 걸릴 수 있습니다. 길게 누르기 [폴더 크기 계산] 은 늘 됩니다": "Shows the total size of the files inside each folder. Large folders or a NAS can take a while to read. Long-press [Calculate folder size] always works",
|
"폴더 안 파일 크기의 합을 목록에 보입니다. 큰 폴더 · NAS 는 읽는 데 오래 걸릴 수 있습니다. 길게 누르기 [폴더 크기 계산] 은 늘 됩니다": "Shows the total size of the files inside each folder. Large folders or a NAS can take a while to read. Long-press [Calculate folder size] always works",
|
||||||
|
|
@ -2508,6 +2510,7 @@
|
||||||
"해상도 올리기 모델을 받아야 합니다. 어느 것을 받을까요?": "An upscaling model is needed. Which one should be downloaded?",
|
"해상도 올리기 모델을 받아야 합니다. 어느 것을 받을까요?": "An upscaling model is needed. Which one should be downloaded?",
|
||||||
"해상도를 올리지 못했습니다": "Couldn't upscale",
|
"해상도를 올리지 못했습니다": "Couldn't upscale",
|
||||||
"해상도를 올린 그림 저장 폴더": "Folder for upscaled images",
|
"해상도를 올린 그림 저장 폴더": "Folder for upscaled images",
|
||||||
|
"해시 (MD5 · SHA-256)": "Hash (MD5 · SHA-256)",
|
||||||
"해시 · {0}": "Hash · {0}",
|
"해시 · {0}": "Hash · {0}",
|
||||||
"해제": "Unset",
|
"해제": "Unset",
|
||||||
"허용": "Allow",
|
"허용": "Allow",
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,7 @@
|
||||||
"1/2 · AI 그림으로 다듬는 중": "1/2 · AI 画像で整え中",
|
"1/2 · AI 그림으로 다듬는 중": "1/2 · AI 画像で整え中",
|
||||||
"10초 뒤로 (←)": "10秒戻る(←)",
|
"10초 뒤로 (←)": "10秒戻る(←)",
|
||||||
"10초 앞으로 (→)": "10秒進む(→)",
|
"10초 앞으로 (→)": "10秒進む(→)",
|
||||||
|
"16진": "16進",
|
||||||
"16진 보기 · {0}": "16進表示 · {0}",
|
"16진 보기 · {0}": "16進表示 · {0}",
|
||||||
"1배 (선명하게)": "1倍 (くっきり)",
|
"1배 (선명하게)": "1倍 (くっきり)",
|
||||||
"1분 안": "1 分以内",
|
"1분 안": "1 分以内",
|
||||||
|
|
@ -2413,6 +2414,7 @@
|
||||||
"폴더 복사 · 이동 방법": "フォルダーのコピー · 移動方法",
|
"폴더 복사 · 이동 방법": "フォルダーのコピー · 移動方法",
|
||||||
"폴더 삭제: {0} (안의 {1}개 포함)": "フォルダーを削除: {0}(中の {1}個を含む)",
|
"폴더 삭제: {0} (안의 {1}개 포함)": "フォルダーを削除: {0}(中の {1}個を含む)",
|
||||||
"폴더 선택": "フォルダーを選択",
|
"폴더 선택": "フォルダーを選択",
|
||||||
|
"폴더 속성": "フォルダーのプロパティ",
|
||||||
"폴더 속성 · {0}": "フォルダーのプロパティ · {0}",
|
"폴더 속성 · {0}": "フォルダーのプロパティ · {0}",
|
||||||
"폴더 수정": "フォルダーを編集",
|
"폴더 수정": "フォルダーを編集",
|
||||||
"폴더 안 파일 크기의 합을 목록에 보입니다. 큰 폴더 · NAS 는 읽는 데 오래 걸릴 수 있습니다. 길게 누르기 [폴더 크기 계산] 은 늘 됩니다": "フォルダー内のファイルサイズの合計を一覧に表示します。大きなフォルダー・NAS は読み込みに時間がかかることがあります。長押しの [フォルダーサイズを計算] はいつでも使えます",
|
"폴더 안 파일 크기의 합을 목록에 보입니다. 큰 폴더 · NAS 는 읽는 데 오래 걸릴 수 있습니다. 길게 누르기 [폴더 크기 계산] 은 늘 됩니다": "フォルダー内のファイルサイズの合計を一覧に表示します。大きなフォルダー・NAS は読み込みに時間がかかることがあります。長押しの [フォルダーサイズを計算] はいつでも使えます",
|
||||||
|
|
@ -2508,6 +2510,7 @@
|
||||||
"해상도 올리기 모델을 받아야 합니다. 어느 것을 받을까요?": "解像度アップのモデルが必要です。どれをダウンロードしますか?",
|
"해상도 올리기 모델을 받아야 합니다. 어느 것을 받을까요?": "解像度アップのモデルが必要です。どれをダウンロードしますか?",
|
||||||
"해상도를 올리지 못했습니다": "高解像度化できませんでした",
|
"해상도를 올리지 못했습니다": "高解像度化できませんでした",
|
||||||
"해상도를 올린 그림 저장 폴더": "高解像度化した画像の保存フォルダー",
|
"해상도를 올린 그림 저장 폴더": "高解像度化した画像の保存フォルダー",
|
||||||
|
"해시 (MD5 · SHA-256)": "ハッシュ (MD5 · SHA-256)",
|
||||||
"해시 · {0}": "ハッシュ · {0}",
|
"해시 · {0}": "ハッシュ · {0}",
|
||||||
"해제": "解除",
|
"해제": "解除",
|
||||||
"허용": "許可",
|
"허용": "許可",
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,7 @@
|
||||||
"1/2 · AI 그림으로 다듬는 중": "1/2 · 正在用 AI 图片优化",
|
"1/2 · AI 그림으로 다듬는 중": "1/2 · 正在用 AI 图片优化",
|
||||||
"10초 뒤로 (←)": "后退 10 秒(←)",
|
"10초 뒤로 (←)": "后退 10 秒(←)",
|
||||||
"10초 앞으로 (→)": "前进 10 秒(→)",
|
"10초 앞으로 (→)": "前进 10 秒(→)",
|
||||||
|
"16진": "十六进制",
|
||||||
"16진 보기 · {0}": "十六进制查看 · {0}",
|
"16진 보기 · {0}": "十六进制查看 · {0}",
|
||||||
"1배 (선명하게)": "1倍 (锐化)",
|
"1배 (선명하게)": "1倍 (锐化)",
|
||||||
"1분 안": "1 分钟以内",
|
"1분 안": "1 分钟以内",
|
||||||
|
|
@ -2413,6 +2414,7 @@
|
||||||
"폴더 복사 · 이동 방법": "文件夹复制 · 移动方式",
|
"폴더 복사 · 이동 방법": "文件夹复制 · 移动方式",
|
||||||
"폴더 삭제: {0} (안의 {1}개 포함)": "已删除文件夹: {0}(含其中 {1} 个)",
|
"폴더 삭제: {0} (안의 {1}개 포함)": "已删除文件夹: {0}(含其中 {1} 个)",
|
||||||
"폴더 선택": "选择文件夹",
|
"폴더 선택": "选择文件夹",
|
||||||
|
"폴더 속성": "文件夹属性",
|
||||||
"폴더 속성 · {0}": "文件夹属性 · {0}",
|
"폴더 속성 · {0}": "文件夹属性 · {0}",
|
||||||
"폴더 수정": "编辑文件夹",
|
"폴더 수정": "编辑文件夹",
|
||||||
"폴더 안 파일 크기의 합을 목록에 보입니다. 큰 폴더 · NAS 는 읽는 데 오래 걸릴 수 있습니다. 길게 누르기 [폴더 크기 계산] 은 늘 됩니다": "在列表中显示文件夹内文件大小的总和。大型文件夹或 NAS 可能需要较长时间读取。长按 [计算文件夹大小] 始终可用",
|
"폴더 안 파일 크기의 합을 목록에 보입니다. 큰 폴더 · NAS 는 읽는 데 오래 걸릴 수 있습니다. 길게 누르기 [폴더 크기 계산] 은 늘 됩니다": "在列表中显示文件夹内文件大小的总和。大型文件夹或 NAS 可能需要较长时间读取。长按 [计算文件夹大小] 始终可用",
|
||||||
|
|
@ -2508,6 +2510,7 @@
|
||||||
"해상도 올리기 모델을 받아야 합니다. 어느 것을 받을까요?": "需要放大模型。要下载哪一个?",
|
"해상도 올리기 모델을 받아야 합니다. 어느 것을 받을까요?": "需要放大模型。要下载哪一个?",
|
||||||
"해상도를 올리지 못했습니다": "无法提高分辨率",
|
"해상도를 올리지 못했습니다": "无法提高分辨率",
|
||||||
"해상도를 올린 그림 저장 폴더": "提高分辨率后图片的保存文件夹",
|
"해상도를 올린 그림 저장 폴더": "提高分辨率后图片的保存文件夹",
|
||||||
|
"해시 (MD5 · SHA-256)": "哈希 (MD5 · SHA-256)",
|
||||||
"해시 · {0}": "哈希 · {0}",
|
"해시 · {0}": "哈希 · {0}",
|
||||||
"해제": "解除",
|
"해제": "解除",
|
||||||
"허용": "允许",
|
"허용": "允许",
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,7 @@ import '../l10n/tr.dart';
|
||||||
import 'explorer_bookmarks.dart';
|
import 'explorer_bookmarks.dart';
|
||||||
import 'explorer_search.dart';
|
import 'explorer_search.dart';
|
||||||
import 'quick_look.dart';
|
import 'quick_look.dart';
|
||||||
|
import 'file_tools.dart' show showFileHash, showFolderProperties;
|
||||||
import 'explorer_drag.dart';
|
import 'explorer_drag.dart';
|
||||||
import 'archive_ui.dart';
|
import 'archive_ui.dart';
|
||||||
import 'storage_page.dart';
|
import 'storage_page.dart';
|
||||||
|
|
@ -1605,6 +1606,9 @@ class _ExplorerPageState extends State<ExplorerPage> {
|
||||||
if (e.isDir) ('storage', Icons.pie_chart_outline, tr('저장 공간 분석')),
|
if (e.isDir) ('storage', Icons.pie_chart_outline, tr('저장 공간 분석')),
|
||||||
// 80: 이 폴더 크기를 지금 계산 (설정이 "안 함" 이어도)
|
// 80: 이 폴더 크기를 지금 계산 (설정이 "안 함" 이어도)
|
||||||
if (e.isDir) ('folderSize', Icons.data_usage, _sizes.busy(e.path) ? tr('폴더 크기 계산 멈추기') : tr('폴더 크기 계산')),
|
if (e.isDir) ('folderSize', Icons.data_usage, _sizes.busy(e.path) ? tr('폴더 크기 계산 멈추기') : tr('폴더 크기 계산')),
|
||||||
|
// X-plore P3: 폴더 속성 (안의 파일 · 폴더 수 · 크기 · 만든 · 바뀐 때) · 파일 해시 (MD5 · SHA-256) - 이 기기의 것만 (원격은 다 받아야 해서 뺌)
|
||||||
|
if (e.isDir && !dav) ('props', Icons.fact_check_outlined, tr('폴더 속성')),
|
||||||
|
if (!e.isDir && !dav) ('hash', Icons.tag, tr('해시 (MD5 · SHA-256)')),
|
||||||
if (e.isDir && dual) ('openOther', Icons.vertical_split_outlined, tr('다른 창에서 열기')),
|
if (e.isDir && dual) ('openOther', Icons.vertical_split_outlined, tr('다른 창에서 열기')),
|
||||||
if (e.isDir) ('playFolder', Icons.play_circle_outline, tr('이 폴더의 동영상 재생')),
|
if (e.isDir) ('playFolder', Icons.play_circle_outline, tr('이 폴더의 동영상 재생')),
|
||||||
if (video || audio) ('playInternal', Icons.play_circle_outline, tr('내장 플레이어로 재생')),
|
if (video || audio) ('playInternal', Icons.play_circle_outline, tr('내장 플레이어로 재생')),
|
||||||
|
|
@ -1705,6 +1709,10 @@ class _ExplorerPageState extends State<ExplorerPage> {
|
||||||
pane.focused = made;
|
pane.focused = made;
|
||||||
pane.changed();
|
pane.changed();
|
||||||
}
|
}
|
||||||
|
case 'props':
|
||||||
|
await showFolderProperties(context, e.path);
|
||||||
|
case 'hash':
|
||||||
|
await showFileHash(context, e.path);
|
||||||
case 'folderSize':
|
case 'folderSize':
|
||||||
if (_sizes.busy(e.path)) {
|
if (_sizes.busy(e.path)) {
|
||||||
_sizes.cancel(e.path);
|
_sizes.cancel(e.path);
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import '../core/models.dart';
|
||||||
import '../core/playlist.dart' show isAudioFile, isVideoFile;
|
import '../core/playlist.dart' show isAudioFile, isVideoFile;
|
||||||
import '../core/vfs.dart';
|
import '../core/vfs.dart';
|
||||||
import '../l10n/tr.dart';
|
import '../l10n/tr.dart';
|
||||||
|
import 'file_tools.dart' show HexViewerPage;
|
||||||
import 'theme.dart';
|
import 'theme.dart';
|
||||||
|
|
||||||
/// 81: 빠른 보기에서 글로 보는 확장자
|
/// 81: 빠른 보기에서 글로 보는 확장자
|
||||||
|
|
@ -209,6 +210,12 @@ class _QuickLookState extends State<QuickLook> {
|
||||||
]),
|
]),
|
||||||
),
|
),
|
||||||
actions: [
|
actions: [
|
||||||
|
// X-plore P3: 16진 보기 (이 기기의 파일만 - 앞부분부터 나눠 읽기)
|
||||||
|
if (!e.isDir && !isDav(e.path))
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Navigator.of(context).push(MaterialPageRoute<void>(builder: (_) => HexViewerPage(path: e.path))),
|
||||||
|
child: Text(tr('16진')),
|
||||||
|
),
|
||||||
TextButton(onPressed: () => Navigator.pop(context), child: Text(tr('닫기'))),
|
TextButton(onPressed: () => Navigator.pop(context), child: Text(tr('닫기'))),
|
||||||
FilledButton(
|
FilledButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ import 'package:jj_mkvmaker/services/platform_services.dart';
|
||||||
import 'package:jj_mkvmaker/core/file_ops.dart' show formatSize;
|
import 'package:jj_mkvmaker/core/file_ops.dart' show formatSize;
|
||||||
import 'package:jj_mkvmaker/ui/explorer_page.dart';
|
import 'package:jj_mkvmaker/ui/explorer_page.dart';
|
||||||
import 'package:jj_mkvmaker/ui/explorer_search.dart';
|
import 'package:jj_mkvmaker/ui/explorer_search.dart';
|
||||||
|
import 'package:jj_mkvmaker/ui/file_tools.dart' show HexViewerPage;
|
||||||
import 'package:jj_mkvmaker/ui/quick_look.dart';
|
import 'package:jj_mkvmaker/ui/quick_look.dart';
|
||||||
import 'package:jj_mkvmaker/ui/explorer_drag.dart';
|
import 'package:jj_mkvmaker/ui/explorer_drag.dart';
|
||||||
import 'package:jj_mkvmaker/ui/storage_page.dart';
|
import 'package:jj_mkvmaker/ui/storage_page.dart';
|
||||||
|
|
@ -160,6 +161,38 @@ void main() {
|
||||||
await tester.pump(const Duration(seconds: 2));
|
await tester.pump(const Duration(seconds: 2));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('X-plore P3: 길게 누르기 [해시] (MD5 · SHA-256) · 폴더 [폴더 속성] · 빠른 보기 [16진]', (tester) async {
|
||||||
|
await open(tester);
|
||||||
|
// 해시: doc.txt = "hello"
|
||||||
|
await tester.longPress(find.text('doc.txt'));
|
||||||
|
await calm(tester);
|
||||||
|
await act(tester, () => tester.tap(find.text('해시 (MD5 · SHA-256)')));
|
||||||
|
await settle(tester, () => find.textContaining('2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824').evaluate().isNotEmpty);
|
||||||
|
expect(find.textContaining('5d41402abc4b2a76b9719d911017c592'), findsOneWidget, reason: 'MD5');
|
||||||
|
await act(tester, () => tester.tap(find.text('닫기').last));
|
||||||
|
await calm(tester);
|
||||||
|
// 폴더 속성: sub 안에 inner.txt 하나
|
||||||
|
await tester.longPress(find.text('sub'));
|
||||||
|
await calm(tester);
|
||||||
|
await act(tester, () => tester.tap(find.text('폴더 속성')));
|
||||||
|
await settle(tester, () => find.text('파일 1개 · 폴더 0개').evaluate().isNotEmpty);
|
||||||
|
await act(tester, () => tester.tap(find.text('닫기').last));
|
||||||
|
await calm(tester);
|
||||||
|
// 빠른 보기 → [16진]
|
||||||
|
await tester.longPress(find.text('doc.txt'));
|
||||||
|
await calm(tester);
|
||||||
|
await act(tester, () => tester.tap(find.text('미리 보기')));
|
||||||
|
await settle(tester, () => find.text('16진').evaluate().isNotEmpty);
|
||||||
|
await act(tester, () => tester.tap(find.text('16진')));
|
||||||
|
await settle(tester, () => find.byType(HexViewerPage).evaluate().isNotEmpty);
|
||||||
|
expect(find.byType(HexViewerPage), findsOneWidget);
|
||||||
|
// 16진 보기가 앞부분을 다 읽어 파일을 놓을 때까지 (실제 시간) 기다린 뒤 닫는다 - 열린 파일이 남으면 시험 폴더를 못 지운다
|
||||||
|
await tester.runAsync(() => Future<void>.delayed(const Duration(milliseconds: 300)));
|
||||||
|
await tester.pump();
|
||||||
|
await act(tester, () => tester.pageBack());
|
||||||
|
await calm(tester);
|
||||||
|
});
|
||||||
|
|
||||||
testWidgets('X-plore b: 가운데 버튼 길게 누르기 = 짝 동작 - [복사] 길게 = 이동 창 · [삭제] 길게 = 영구 삭제 창', (tester) async {
|
testWidgets('X-plore b: 가운데 버튼 길게 누르기 = 짝 동작 - [복사] 길게 = 이동 창 · [삭제] 길게 = 영구 삭제 창', (tester) async {
|
||||||
await open(tester);
|
await open(tester);
|
||||||
await act(tester, () => tester.tap(find.text('doc.txt')));
|
await act(tester, () => tester.tap(find.text('doc.txt')));
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue