E10 · 50 보충: 로컬 폴더를 읽지 못하면 빈 폴더로 보이지 않게 ("읽을 수 없습니다 · 이유" 와 [다시 시도])
- listEntries 가 Directory.list 의 오류를 버려 권한 없는 폴더 · 빠진 USB · 없는 폴더가 빈 폴더로 보였다. 하나도 읽지 못했으면 그 오류를 던지고, 일부를 읽은 뒤의 오류는 읽은 것까지 보여 준다 - 부르는 다른 곳: [폴더 재생] 은 이유 알림, [MKV 목록에 추가] 는 읽지 못한 폴더를 건너뛰고 알림, 그림 보기는 고른 그림만 - 시험: 빈 폴더 · 없는 폴더 · C:\System Volume Information (권한 없음) - 탐색기에 "이 폴더를 읽을 권한이 없습니다" 와 [다시 시도] Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>묶음3
parent
c25a754035
commit
ba332f9f84
|
|
@ -1400,6 +1400,8 @@
|
|||
"일시정지": "Pause",
|
||||
"읽기 전용 매체입니다": "Read-only media",
|
||||
"읽을 수 없습니다": "Cannot read",
|
||||
"읽을 수 없습니다: {0}": "Cannot read: {0}",
|
||||
"읽을 수 없어 건너뛴 폴더: {0}": "Skipped folders that could not be read: {0}",
|
||||
"읽을 수 없음": "Cannot read",
|
||||
"읽지 못한 원래 파일은 지우지 않고 아래에 보관했습니다:": "The original file that could not be read was not deleted; it is kept here:",
|
||||
"읽지 못한 폴더 {0}개 (권한 · 연결 문제) - 그 안은 찾지 못했습니다": "{0} unreadable folders (permission or connection problem) - not searched inside",
|
||||
|
|
|
|||
|
|
@ -1400,6 +1400,8 @@
|
|||
"일시정지": "一時停止",
|
||||
"읽기 전용 매체입니다": "読み取り専用メディアです",
|
||||
"읽을 수 없습니다": "読み込めません",
|
||||
"읽을 수 없습니다: {0}": "読み込めません: {0}",
|
||||
"읽을 수 없어 건너뛴 폴더: {0}": "読み込めずスキップしたフォルダー: {0}",
|
||||
"읽을 수 없음": "読み取れません",
|
||||
"읽지 못한 원래 파일은 지우지 않고 아래에 보관했습니다:": "読めなかった元のファイルは削除せず、ここに保管しました:",
|
||||
"읽지 못한 폴더 {0}개 (권한 · 연결 문제) - 그 안은 찾지 못했습니다": "読めなかったフォルダー {0} 個 (権限・接続の問題) - その中は探せませんでした",
|
||||
|
|
|
|||
|
|
@ -1400,6 +1400,8 @@
|
|||
"일시정지": "暂停",
|
||||
"읽기 전용 매체입니다": "只读介质",
|
||||
"읽을 수 없습니다": "无法读取",
|
||||
"읽을 수 없습니다: {0}": "无法读取: {0}",
|
||||
"읽을 수 없어 건너뛴 폴더: {0}": "无法读取而跳过的文件夹: {0}",
|
||||
"읽을 수 없음": "无法读取",
|
||||
"읽지 못한 원래 파일은 지우지 않고 아래에 보관했습니다:": "无法读取的原文件没有删除,保存在这里:",
|
||||
"읽지 못한 폴더 {0}개 (권한 · 연결 문제) - 그 안은 찾지 못했습니다": "{0} 个无法读取的文件夹 (权限 · 连接问题) - 未在其中查找",
|
||||
|
|
|
|||
|
|
@ -57,7 +57,10 @@ Future<List<FileEntry>> listEntries(String dir, {bool showHidden = false}) async
|
|||
];
|
||||
}
|
||||
final out = <FileEntry>[];
|
||||
await for (final e in Directory(dir).list(followLinks: false).handleError((_) {})) {
|
||||
// E10: 폴더를 읽지 못하면 (권한 없음 · 빠진 USB 등) 빈 폴더로 보이지 않게 던진다 (화면이 "읽을 수 없습니다: 이유" 와 [다시 시도]).
|
||||
// 일부를 읽은 뒤의 오류는 읽은 것까지 보여 준다
|
||||
Object? failed;
|
||||
await for (final e in Directory(dir).list(followLinks: false).handleError((Object err) => failed ??= err)) {
|
||||
try {
|
||||
final st = await e.stat();
|
||||
final isDir = st.type == FileSystemEntityType.directory;
|
||||
|
|
@ -66,6 +69,7 @@ Future<List<FileEntry>> listEntries(String dir, {bool showHidden = false}) async
|
|||
out.add(entry);
|
||||
} catch (_) {}
|
||||
}
|
||||
if (failed != null && out.isEmpty) throw failed!;
|
||||
return out;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -909,7 +909,13 @@ class _ExplorerPageState extends State<ExplorerPage> {
|
|||
/// 그림 보기: 같은 폴더의 그림을 지금 정렬 순서대로 넘겨 본다
|
||||
Future<void> _viewImages(String path, _Pane? pane) async {
|
||||
final dir = vDirname(path);
|
||||
final list = pane?.cache[dir] ?? _sorted(await listEntries(dir, showHidden: c.settings.explorerShowHidden));
|
||||
// 폴더를 읽지 못하면 (E10: 이제 오류로 알림) 고른 그림 하나만
|
||||
List<FileEntry> list;
|
||||
try {
|
||||
list = pane?.cache[dir] ?? _sorted(await listEntries(dir, showHidden: c.settings.explorerShowHidden));
|
||||
} catch (_) {
|
||||
list = const [];
|
||||
}
|
||||
final images = [
|
||||
for (final e in list)
|
||||
if (!e.isDir && c.settings.imageExts.contains(extOf(e.path))) e.path,
|
||||
|
|
@ -1252,7 +1258,13 @@ class _ExplorerPageState extends State<ExplorerPage> {
|
|||
}
|
||||
|
||||
Future<void> _playFolder(String dir) async {
|
||||
final list = (await listEntries(dir)).where((e) => !e.isDir && isVideoFile(e.path)).map((e) => e.path).toList();
|
||||
final List<String> list;
|
||||
try {
|
||||
list = (await listEntries(dir)).where((e) => !e.isDir && isVideoFile(e.path)).map((e) => e.path).toList();
|
||||
} catch (e) {
|
||||
_snack(trf('읽을 수 없습니다: {0}', [explainFileError('$e', dav: isDav(dir)).$1]));
|
||||
return;
|
||||
}
|
||||
if (list.isEmpty) {
|
||||
_snack(tr('이 폴더에 동영상이 없습니다.'));
|
||||
return;
|
||||
|
|
@ -1267,15 +1279,21 @@ class _ExplorerPageState extends State<ExplorerPage> {
|
|||
return;
|
||||
}
|
||||
final videos = <String>[];
|
||||
final unreadable = <String>[];
|
||||
for (final x in paths) {
|
||||
if (vIsDirSync(x)) {
|
||||
try {
|
||||
videos.addAll((await listEntries(x)).where((e) => !e.isDir && isVideoFile(e.path)).map((e) => e.path));
|
||||
} catch (_) {
|
||||
unreadable.add(vBasename(x)); // 읽지 못한 폴더는 건너뛰고 알린다
|
||||
}
|
||||
} else if (isVideoFile(x)) {
|
||||
videos.add(x);
|
||||
}
|
||||
}
|
||||
if (unreadable.isNotEmpty) _snack(trf('읽을 수 없어 건너뛴 폴더: {0}', [unreadable.take(3).join(', ')]));
|
||||
if (videos.isEmpty) {
|
||||
_snack(tr('추가할 동영상이 없습니다.'));
|
||||
if (unreadable.isEmpty) _snack(tr('추가할 동영상이 없습니다.'));
|
||||
return;
|
||||
}
|
||||
await c.addVideos(videos, allowOutputFolder: true);
|
||||
|
|
|
|||
|
|
@ -243,6 +243,20 @@ void main() {
|
|||
expect(find.text('앞 화면'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('E10: 권한 없는 폴더는 빈 폴더가 아니라 "읽을 수 없음 · 이유" 와 [다시 시도]', (tester) async {
|
||||
const locked = r'C:\System Volume Information';
|
||||
if (!Platform.isWindows || !Directory(locked).existsSync()) return;
|
||||
c.settings.explorerPaths = [locked, right];
|
||||
ExplorerPage.debugVolumes = () => [(r'C:\', 'C:'), (p.rootPrefix(tmp.path), p.rootPrefix(tmp.path).substring(0, 2))];
|
||||
tester.view.physicalSize = const Size(1600, 900);
|
||||
tester.view.devicePixelRatio = 1;
|
||||
addTearDown(tester.view.reset);
|
||||
await tester.runAsync(() => tester.pumpWidget(MaterialApp(home: ExplorerPage(c: c))));
|
||||
await settle(tester, () => find.textContaining('이 폴더를 읽을 권한이 없습니다').evaluate().isNotEmpty);
|
||||
expect(find.textContaining('이 폴더를 읽을 권한이 없습니다'), findsOneWidget);
|
||||
expect(find.text('다시 시도'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('48: 건너뛰기를 고르면 그대로 두고 건너뛴 것을 알린다', (tester) async {
|
||||
await startCopy(tester);
|
||||
await tester.tap(find.text('건너뛰기'));
|
||||
|
|
|
|||
|
|
@ -200,4 +200,13 @@ void main() {
|
|||
expect(File(p.join(b.path, 'k')).readAsStringSync(), 'file');
|
||||
});
|
||||
});
|
||||
|
||||
test('E10: 폴더를 읽지 못하면 빈 목록이 아니라 오류 (권한 없음 · 없는 폴더) · 빈 폴더는 그대로 빈 목록', () async {
|
||||
final empty = Directory(p.join(tmp.path, 'empty'))..createSync();
|
||||
expect(await listEntries(empty.path), isEmpty);
|
||||
await expectLater(listEntries(p.join(tmp.path, 'gone')), throwsA(isA<FileSystemException>()));
|
||||
if (Platform.isWindows && Directory(r'C:\System Volume Information').existsSync()) {
|
||||
await expectLater(listEntries(r'C:\System Volume Information'), throwsA(isA<FileSystemException>()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue