Merge branch 'smb_find' into next
# Conflicts: # assets/l10n/en.json # assets/l10n/ja.json # assets/l10n/zh-Hans.jsonhint_fix
commit
8d6f288fab
|
|
@ -480,6 +480,7 @@
|
|||
"{0} (동영상 {1})": "{0} (videos: {1})",
|
||||
"{0} - {1} (약 {2}MB)": "{0} - {1} (about {2}MB)",
|
||||
"{0} / {1} 읽음": "{0} / {1} read",
|
||||
"{0} / {1} 확인": "{0} / {1} checked",
|
||||
"{0} / {1}장": "{0} / {1} images",
|
||||
"{0} · {1}{2} (메인 화면 상단에서 변경)": "{0} · {1}{2} (change at the top of the main screen)",
|
||||
"{0} · {1}배 · {2}": "{0} · {1}× · {2}",
|
||||
|
|
@ -645,6 +646,8 @@
|
|||
"강할수록 많이 다듬지만 원본과 달라질 수 있습니다": "Stronger refines more but may drift from the original",
|
||||
"같습니다 ✔": "Match ✔",
|
||||
"같은 네트워크에서만 열 수 있습니다": "Can only be opened from the same network",
|
||||
"같은 망에서 찾기": "Find on this network",
|
||||
"같은 망의 SMB 서버": "SMB servers on this network",
|
||||
"같은 시리즈 (번호만 다른 파일)": "Same series (files that differ only by number)",
|
||||
"같은 이름을 덮어쓴 파일 {0}개는 되돌리지 않습니다.": "{0} files that replaced a file with the same name won't be undone.",
|
||||
"같은 이름의 파일이 있어 폴더를 만들 수 없습니다: {0}": "Can't create the folder because a file with the same name exists: {0}",
|
||||
|
|
@ -1944,6 +1947,7 @@
|
|||
"이 기기 (SD1.5 + LCM)": "This device (SD1.5 + LCM)",
|
||||
"이 기기 ({0})": "This device ({0})",
|
||||
"이 기기 메모리 {0}GB 기준:": "For this device's {0}GB of memory:",
|
||||
"이 기기가 연결된 망 (Wi-Fi · 유선) 의 기기들에 SMB (445) 연결만 해 보고 바로 닫습니다. 아무것도 보내지 않습니다.": "Tries an SMB (445) connection to devices on the network this device is on (Wi-Fi · wired) and closes it right away. Nothing is sent.",
|
||||
"이 기기에는 원문이 아니라 되돌릴 수 없는 해시만 남습니다.": "Only an irreversible hash is stored on this device, not the password itself.",
|
||||
"이 기기에서 한 장 약 {0} (지난번 걸린 시간 기준)": "About {0} per image on this device (based on last time)",
|
||||
"이 기기에서 한 장 약 {0} · 모두 약 {1} (지난번 걸린 시간 기준)": "About {0} per image, {1} in total on this device (based on last time)",
|
||||
|
|
@ -2420,6 +2424,7 @@
|
|||
"찾은 자막이 없습니다. 제목을 영어 원제로 바꾸거나 언어를 추가해 보세요.": "No subtitles found. Try the original English title or add languages.",
|
||||
"찾을 글": "Find",
|
||||
"찾을 수 없습니다 (이미 지워졌거나 옮겨졌습니다)": "Not found (already deleted or moved)",
|
||||
"찾지 못했습니다. NAS 가 켜져 있고 같은 망에 있는지 확인하거나, 주소를 직접 넣으세요.": "Nothing found. Check that the NAS is on and on the same network, or enter the address yourself.",
|
||||
"채도": "Saturation",
|
||||
"채우기 (가운데 잘라냄)": "Fill (crop the center)",
|
||||
"처리 장치": "Processor",
|
||||
|
|
|
|||
|
|
@ -480,6 +480,7 @@
|
|||
"{0} (동영상 {1})": "{0} (動画 {1})",
|
||||
"{0} - {1} (약 {2}MB)": "{0} - {1}(約 {2}MB)",
|
||||
"{0} / {1} 읽음": "{0} / {1} 読み込み済み",
|
||||
"{0} / {1} 확인": "{0} / {1} 確認",
|
||||
"{0} / {1}장": "{0} / {1} 枚",
|
||||
"{0} · {1}{2} (메인 화면 상단에서 변경)": "{0} · {1}{2}(メイン画面の上部で変更)",
|
||||
"{0} · {1}배 · {2}": "{0}・{1} 倍・{2}",
|
||||
|
|
@ -645,6 +646,8 @@
|
|||
"강할수록 많이 다듬지만 원본과 달라질 수 있습니다": "強いほど大きく整えますが、元と違ってくることがあります",
|
||||
"같습니다 ✔": "一致します ✔",
|
||||
"같은 네트워크에서만 열 수 있습니다": "同じネットワークからのみ開けます",
|
||||
"같은 망에서 찾기": "同じネットワークで探す",
|
||||
"같은 망의 SMB 서버": "同じネットワークの SMB サーバー",
|
||||
"같은 시리즈 (번호만 다른 파일)": "同じシリーズ(番号だけ違うファイル)",
|
||||
"같은 이름을 덮어쓴 파일 {0}개는 되돌리지 않습니다.": "同じ名前を上書きしたファイル {0} 件は元に戻しません。",
|
||||
"같은 이름의 파일이 있어 폴더를 만들 수 없습니다: {0}": "同じ名前のファイルがあるためフォルダーを作成できません: {0}",
|
||||
|
|
@ -1944,6 +1947,7 @@
|
|||
"이 기기 (SD1.5 + LCM)": "この端末 (SD1.5 + LCM)",
|
||||
"이 기기 ({0})": "この端末 ({0})",
|
||||
"이 기기 메모리 {0}GB 기준:": "この端末のメモリ {0}GB の場合:",
|
||||
"이 기기가 연결된 망 (Wi-Fi · 유선) 의 기기들에 SMB (445) 연결만 해 보고 바로 닫습니다. 아무것도 보내지 않습니다.": "この端末が接続しているネットワーク (Wi-Fi · 有線) の機器に SMB (445) で接続だけ試し、すぐに閉じます。何も送りません。",
|
||||
"이 기기에는 원문이 아니라 되돌릴 수 없는 해시만 남습니다.": "この端末にはパスワード自体ではなく、元に戻せないハッシュだけが残ります。",
|
||||
"이 기기에서 한 장 약 {0} (지난번 걸린 시간 기준)": "この端末で 1 枚約 {0} (前回の所要時間から)",
|
||||
"이 기기에서 한 장 약 {0} · 모두 약 {1} (지난번 걸린 시간 기준)": "この端末で 1 枚約 {0}・全部で約 {1} (前回の所要時間から)",
|
||||
|
|
@ -2420,6 +2424,7 @@
|
|||
"찾은 자막이 없습니다. 제목을 영어 원제로 바꾸거나 언어를 추가해 보세요.": "字幕が見つかりませんでした。タイトルを英語の原題に変えるか、言語を追加してみてください。",
|
||||
"찾을 글": "検索する文字",
|
||||
"찾을 수 없습니다 (이미 지워졌거나 옮겨졌습니다)": "見つかりません (すでに削除または移動されました)",
|
||||
"찾지 못했습니다. NAS 가 켜져 있고 같은 망에 있는지 확인하거나, 주소를 직접 넣으세요.": "見つかりませんでした。NAS の電源が入っていて同じネットワークにあるか確認するか、アドレスを直接入力してください。",
|
||||
"채도": "彩度",
|
||||
"채우기 (가운데 잘라냄)": "フィル(中央を切り抜き)",
|
||||
"처리 장치": "処理装置",
|
||||
|
|
|
|||
|
|
@ -480,6 +480,7 @@
|
|||
"{0} (동영상 {1})": "{0}(视频 {1})",
|
||||
"{0} - {1} (약 {2}MB)": "{0} - {1}(约 {2}MB)",
|
||||
"{0} / {1} 읽음": "已读取 {0} / {1}",
|
||||
"{0} / {1} 확인": "已检查 {0} / {1}",
|
||||
"{0} / {1}장": "{0} / {1} 张",
|
||||
"{0} · {1}{2} (메인 화면 상단에서 변경)": "{0} · {1}{2}(在主界面顶部更改)",
|
||||
"{0} · {1}배 · {2}": "{0} · {1} 倍 · {2}",
|
||||
|
|
@ -645,6 +646,8 @@
|
|||
"강할수록 많이 다듬지만 원본과 달라질 수 있습니다": "越强优化越多,但可能与原图不同",
|
||||
"같습니다 ✔": "相同 ✔",
|
||||
"같은 네트워크에서만 열 수 있습니다": "只能在同一网络中打开",
|
||||
"같은 망에서 찾기": "在同一网络中查找",
|
||||
"같은 망의 SMB 서버": "同一网络中的 SMB 服务器",
|
||||
"같은 시리즈 (번호만 다른 파일)": "同一系列(仅编号不同的文件)",
|
||||
"같은 이름을 덮어쓴 파일 {0}개는 되돌리지 않습니다.": "{0} 个覆盖了同名文件的文件不会撤销。",
|
||||
"같은 이름의 파일이 있어 폴더를 만들 수 없습니다: {0}": "存在同名文件,无法创建文件夹: {0}",
|
||||
|
|
@ -1944,6 +1947,7 @@
|
|||
"이 기기 (SD1.5 + LCM)": "本设备 (SD1.5 + LCM)",
|
||||
"이 기기 ({0})": "本设备 ({0})",
|
||||
"이 기기 메모리 {0}GB 기준:": "按本设备内存 {0}GB:",
|
||||
"이 기기가 연결된 망 (Wi-Fi · 유선) 의 기기들에 SMB (445) 연결만 해 보고 바로 닫습니다. 아무것도 보내지 않습니다.": "仅尝试与本设备所在网络 (Wi-Fi · 有线) 中的设备建立 SMB (445) 连接并立即关闭。不会发送任何内容。",
|
||||
"이 기기에는 원문이 아니라 되돌릴 수 없는 해시만 남습니다.": "本设备只保存无法还原的哈希值,而不是密码本身。",
|
||||
"이 기기에서 한 장 약 {0} (지난번 걸린 시간 기준)": "本设备每张约 {0} (按上次耗时)",
|
||||
"이 기기에서 한 장 약 {0} · 모두 약 {1} (지난번 걸린 시간 기준)": "本设备每张约 {0} · 共约 {1} (按上次耗时)",
|
||||
|
|
@ -2420,6 +2424,7 @@
|
|||
"찾은 자막이 없습니다. 제목을 영어 원제로 바꾸거나 언어를 추가해 보세요.": "未找到字幕。请尝试改用英文原名或添加语言。",
|
||||
"찾을 글": "查找",
|
||||
"찾을 수 없습니다 (이미 지워졌거나 옮겨졌습니다)": "找不到 (已被删除或移动)",
|
||||
"찾지 못했습니다. NAS 가 켜져 있고 같은 망에 있는지 확인하거나, 주소를 직접 넣으세요.": "未找到。请确认 NAS 已开启且在同一网络中,或直接输入地址。",
|
||||
"채도": "饱和度",
|
||||
"채우기 (가운데 잘라냄)": "填充(裁切中间)",
|
||||
"처리 장치": "处理器",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../app/app_controller.dart';
|
||||
import '../core/lan_scan.dart';
|
||||
import '../core/secret_gate.dart';
|
||||
import '../core/smb.dart';
|
||||
import '../l10n/tr.dart';
|
||||
|
|
@ -188,6 +189,22 @@ Future<SmbServer?> editSmbServer(BuildContext context, AppController c, {SmbServ
|
|||
),
|
||||
),
|
||||
]),
|
||||
// X-plore j: 같은 망 (Wi-Fi · 유선) 에서 SMB 서버 찾기 - 누를 때만 훑는다
|
||||
Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: TextButton.icon(
|
||||
icon: const Icon(Icons.radar, size: 18),
|
||||
label: Text(tr('같은 망에서 찾기')),
|
||||
onPressed: () async {
|
||||
final h = await pickLanSmbServer(ctx);
|
||||
if (h == null) return;
|
||||
set(() {
|
||||
host.text = h.name ?? h.address;
|
||||
if (name.text.trim().isEmpty && h.name != null) name.text = h.name!.split('.').first;
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
TextField(
|
||||
controller: share,
|
||||
decoration: InputDecoration(labelText: tr('공유 이름'), helperText: tr('예: video · home (\\\\서버\\공유 의 공유)')),
|
||||
|
|
@ -247,3 +264,77 @@ Future<SmbServer?> editSmbServer(BuildContext context, AppController c, {SmbServ
|
|||
]);
|
||||
return saved;
|
||||
}
|
||||
|
||||
|
||||
/// 시험: 찾는 함수 (null 이면 실제로 훑는다)
|
||||
@visibleForTesting
|
||||
Future<List<LanHost>> Function({bool Function()? cancelled, void Function(int done, int total)? onProgress})? debugFindSmbServers;
|
||||
|
||||
/// X-plore j: 같은 망의 SMB 서버를 찾아 고르는 창 (진행 · 취소). 이 기기의 사설망 (/24) 의 445 포트에 연결만 해 보고 바로 닫는다 (보내는 것 없음)
|
||||
/// [find]: 시험에서 바꿔 끼움 (실제 망을 훑지 않게)
|
||||
Future<LanHost?> pickLanSmbServer(BuildContext context) async {
|
||||
final find = debugFindSmbServers ?? findSmbServers;
|
||||
var cancelled = false;
|
||||
var done = 0, total = 0;
|
||||
List<LanHost>? found;
|
||||
Object? error;
|
||||
final picked = await showDialog<LanHost>(
|
||||
context: context,
|
||||
builder: (ctx) => StatefulBuilder(builder: (ctx, set) {
|
||||
if (found == null && error == null && total == 0) {
|
||||
total = -1;
|
||||
find(
|
||||
cancelled: () => cancelled,
|
||||
onProgress: (d, t) {
|
||||
if (ctx.mounted) set(() => (done, total) = (d, t));
|
||||
},
|
||||
).then((r) {
|
||||
if (ctx.mounted) set(() => found = r);
|
||||
}, onError: (Object e) {
|
||||
if (ctx.mounted) set(() => error = e);
|
||||
});
|
||||
}
|
||||
final list = found;
|
||||
return AlertDialog(
|
||||
scrollable: true,
|
||||
title: Text(tr('같은 망의 SMB 서버')),
|
||||
content: SizedBox(
|
||||
width: 460,
|
||||
child: Column(mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [
|
||||
Text(tr('이 기기가 연결된 망 (Wi-Fi · 유선) 의 기기들에 SMB (445) 연결만 해 보고 바로 닫습니다. 아무것도 보내지 않습니다.'),
|
||||
style: const TextStyle(fontSize: 12, color: JjColors.textDim)),
|
||||
const SizedBox(height: 10),
|
||||
if (list == null && error == null) ...[
|
||||
LinearProgressIndicator(value: total > 0 ? done / total : null),
|
||||
const SizedBox(height: 4),
|
||||
Text(total > 0 ? trf('{0} / {1} 확인', [done, total]) : tr('준비하는 중'), style: const TextStyle(fontSize: 12)),
|
||||
],
|
||||
if (error != null) Text('$error', style: const TextStyle(color: JjColors.danger)),
|
||||
if (list != null && list.isEmpty) Text(tr('찾지 못했습니다. NAS 가 켜져 있고 같은 망에 있는지 확인하거나, 주소를 직접 넣으세요.')),
|
||||
if (list != null)
|
||||
for (final h in list)
|
||||
ListTile(
|
||||
dense: true,
|
||||
contentPadding: EdgeInsets.zero,
|
||||
leading: const Icon(Icons.dns_outlined),
|
||||
title: Text(h.name ?? h.address),
|
||||
subtitle: h.name == null ? null : Text(h.address),
|
||||
onTap: () => Navigator.pop(ctx, h),
|
||||
),
|
||||
]),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
cancelled = true;
|
||||
Navigator.pop(ctx);
|
||||
},
|
||||
child: Text(list == null && error == null ? tr('취소') : tr('닫기')),
|
||||
),
|
||||
],
|
||||
);
|
||||
}),
|
||||
);
|
||||
cancelled = true;
|
||||
return picked;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,50 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:jj_mkvmaker/app/app_controller.dart';
|
||||
import 'package:jj_mkvmaker/core/lan_scan.dart';
|
||||
import 'package:jj_mkvmaker/platform/windows/desktop_storage_service.dart';
|
||||
import 'package:jj_mkvmaker/platform/windows/process_media_tool.dart';
|
||||
import 'package:jj_mkvmaker/services/platform_services.dart';
|
||||
import 'package:jj_mkvmaker/ui/smb_settings.dart';
|
||||
|
||||
/// X-plore j: [SMB 서버 추가] 창의 [같은 망에서 찾기] - 진행 · 찾은 서버를 고르면 주소 (이름) 칸을 채움. 시험은 실제 망을 훑지 않는다 (가짜 찾기)
|
||||
void main() {
|
||||
tearDown(() => debugFindSmbServers = null);
|
||||
|
||||
testWidgets('찾기 → 고르면 주소 · 이름 칸 채움, 못 찾으면 안내', (tester) async {
|
||||
tester.view.physicalSize = const Size(1000, 1200);
|
||||
tester.view.devicePixelRatio = 1;
|
||||
addTearDown(tester.view.reset);
|
||||
var calls = 0;
|
||||
var result = const [LanHost('192.168.0.9', 'nas.local'), LanHost('192.168.0.20', null)];
|
||||
debugFindSmbServers = ({cancelled, onProgress}) async {
|
||||
calls++;
|
||||
onProgress?.call(254, 254);
|
||||
return result;
|
||||
};
|
||||
final c = AppController(PlatformServices(mediaTool: ProcessMediaTool('x', 'y'), storage: DesktopStorageService()));
|
||||
final key = GlobalKey<NavigatorState>();
|
||||
await tester.pumpWidget(MaterialApp(navigatorKey: key, home: const Scaffold()));
|
||||
editSmbServer(key.currentContext!, c);
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text('SMB 서버 추가'), findsOneWidget);
|
||||
await tester.tap(find.text('같은 망에서 찾기'));
|
||||
await tester.pumpAndSettle();
|
||||
expect(calls, 1);
|
||||
expect(find.text('같은 망의 SMB 서버'), findsOneWidget);
|
||||
expect(find.text('nas.local'), findsOneWidget);
|
||||
expect(find.text('192.168.0.20'), findsOneWidget, reason: '이름을 모르면 주소');
|
||||
await tester.tap(find.text('nas.local'));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.widgetWithText(TextField, 'nas.local'), findsOneWidget, reason: '서버 주소 칸');
|
||||
expect(find.widgetWithText(TextField, 'nas'), findsOneWidget, reason: '이름 칸 (비어 있었으면)');
|
||||
// 못 찾음
|
||||
result = const [];
|
||||
await tester.tap(find.text('같은 망에서 찾기'));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.textContaining('찾지 못했습니다'), findsOneWidget);
|
||||
await tester.tap(find.text('닫기'));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text('SMB 서버 추가'), findsOneWidget, reason: '추가 창은 그대로');
|
||||
});
|
||||
}
|
||||
Loading…
Reference in New Issue