From 4257b973054f54c2ff1e294d13dde35d3f6e1c72 Mon Sep 17 00:00:00 2001 From: RyuJongJin <266630912+RyuJongJin@users.noreply.github.com> Date: Sun, 4 Oct 2026 21:17:37 +0900 Subject: [PATCH] =?UTF-8?q?Android=20=ED=8F=B4=EB=8D=94=20=EA=B3=A0?= =?UTF-8?q?=EB=A5=B4=EA=B8=B0:=20[=EC=9D=B4=20=ED=8F=B4=EB=8D=94=20?= =?UTF-8?q?=EC=84=A0=ED=83=9D]=20=EC=99=BC=EC=AA=BD=EC=97=90=20[=ED=8F=B4?= =?UTF-8?q?=EB=8D=94=20=EB=A7=8C=EB=93=A4=EA=B8=B0]=20(=EC=A7=80=EA=B8=88?= =?UTF-8?q?=20=ED=8F=B4=EB=8D=94=20=EC=95=84=EB=9E=98=EC=97=90=20=EB=A7=8C?= =?UTF-8?q?=EB=93=A4=EA=B3=A0=20=EA=B7=B8=20=ED=8F=B4=EB=8D=94=EB=A1=9C)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- assets/l10n/en.json | 5 +++++ assets/l10n/ja.json | 5 +++++ assets/l10n/zh-Hans.json | 5 +++++ lib/ui/android_file_browser.dart | 38 +++++++++++++++++++++++++++++--- 4 files changed, 50 insertions(+), 3 deletions(-) diff --git a/assets/l10n/en.json b/assets/l10n/en.json index a6aa752..31d5955 100644 --- a/assets/l10n/en.json +++ b/assets/l10n/en.json @@ -156,6 +156,7 @@ "{0} 번역 중 {1}%": "Translating {0} {1}%", "{0} 브라우저의 YouTube 로그인 쿠키 사용 (Chrome · Edge 는 브라우저를 닫아야 읽힐 수 있음)": "Use the YouTube sign-in cookies of the {0} browser (Chrome · Edge may need to be closed to be read)", "{0} 순으로 정렬{1}": "Sort by {0}{1}", + "{0} 아래에 만듭니다": "Created under {0}", "{0} 에서 받을 파일을 찾지 못했습니다": "Could not find a file to download from {0}", "{0} 인코더가 FFmpeg 에 없습니다.": "FFmpeg does not have the {0} encoder.", "{0} 추가": "Add {0}", @@ -591,6 +592,7 @@ "이미 동영상 목록에 있습니다 ({0}개).": "Already in the video list ({0}).", "이미 목록에 있는 동영상입니다 ({0}개).": "These videos are already in the list ({0}).", "이미 받는 중이거나 받을 수 없는 주소입니다.": "Already downloading or a URL that cannot be downloaded.", + "이미 있는 폴더입니다: {0}": "The folder already exists: {0}", "이미지 자막은 번역할 수 없습니다": "Image subtitles cannot be translated", "이미지 자막은 편집할 수 없습니다": "Image subtitles cannot be edited", "이전": "Previous", @@ -800,14 +802,17 @@ "포르투갈어": "Portuguese", "포함된 구성 요소와 라이선스 (THIRD_PARTY_NOTICES.txt)": "Included components and licenses (THIRD_PARTY_NOTICES.txt)", "폴더": "Folder", + "폴더 만들기": "New folder", "폴더 삭제: {0} (안의 {1}개 포함)": "Folder deleted: {0} (including {1} inside)", "폴더 선택": "Choose folder", "폴더 수정": "Edit folder", "폴더 열기": "Open folder", "폴더 이름": "Folder name", "폴더 이름 바꾸기 · 이동": "Rename · move folder", + "폴더 이름에 쓸 수 없는 글자가 있습니다 (\\ / : * ? \" < > |)": "The folder name has characters that cannot be used (\\ / : * ? \" < > |)", "폴더: {0}": "Folder: {0}", "폴더가 아닙니다: {0}": "Not a folder: {0}", + "폴더를 만들 수 없습니다: {0}": "Cannot create the folder: {0}", "폴란드어": "Polish", "표시 이름": "Display name", "표시 이름은 바로 고칠 수 있습니다. 동영상 줄을 세 번 누르면 첫 번째 버튼의 폴더로 옮깁니다": "You can edit display names right here. Pressing a video row three times moves it to the first button's folder", diff --git a/assets/l10n/ja.json b/assets/l10n/ja.json index f79e270..70e0cad 100644 --- a/assets/l10n/ja.json +++ b/assets/l10n/ja.json @@ -156,6 +156,7 @@ "{0} 번역 중 {1}%": "{0} を翻訳中 {1}%", "{0} 브라우저의 YouTube 로그인 쿠키 사용 (Chrome · Edge 는 브라우저를 닫아야 읽힐 수 있음)": "{0} ブラウザーの YouTube ログインクッキーを使う(Chrome・Edge はブラウザーを閉じないと読めないことがあります)", "{0} 순으로 정렬{1}": "{0} 順に並べ替え{1}", + "{0} 아래에 만듭니다": "{0} の下に作成します", "{0} 에서 받을 파일을 찾지 못했습니다": "{0} からダウンロードするファイルが見つかりませんでした", "{0} 인코더가 FFmpeg 에 없습니다.": "FFmpeg に {0} エンコーダーがありません。", "{0} 추가": "{0} を追加", @@ -591,6 +592,7 @@ "이미 동영상 목록에 있습니다 ({0}개).": "既に動画リストにあります({0}個)。", "이미 목록에 있는 동영상입니다 ({0}개).": "既にリストにある動画です({0}個)。", "이미 받는 중이거나 받을 수 없는 주소입니다.": "既にダウンロード中か、ダウンロードできない URL です。", + "이미 있는 폴더입니다: {0}": "既にあるフォルダーです: {0}", "이미지 자막은 번역할 수 없습니다": "画像字幕は翻訳できません", "이미지 자막은 편집할 수 없습니다": "画像字幕は編集できません", "이전": "前へ", @@ -800,14 +802,17 @@ "포르투갈어": "ポルトガル語", "포함된 구성 요소와 라이선스 (THIRD_PARTY_NOTICES.txt)": "含まれるコンポーネントとライセンス(THIRD_PARTY_NOTICES.txt)", "폴더": "フォルダー", + "폴더 만들기": "フォルダーを作成", "폴더 삭제: {0} (안의 {1}개 포함)": "フォルダーを削除: {0}(中の {1}個を含む)", "폴더 선택": "フォルダーを選択", "폴더 수정": "フォルダーを編集", "폴더 열기": "フォルダーを開く", "폴더 이름": "フォルダー名", "폴더 이름 바꾸기 · 이동": "フォルダー名の変更・移動", + "폴더 이름에 쓸 수 없는 글자가 있습니다 (\\ / : * ? \" < > |)": "フォルダー名に使えない文字があります(\\ / : * ? \" < > |)", "폴더: {0}": "フォルダー: {0}", "폴더가 아닙니다: {0}": "フォルダーではありません: {0}", + "폴더를 만들 수 없습니다: {0}": "フォルダーを作成できません: {0}", "폴란드어": "ポーランド語", "표시 이름": "表示名", "표시 이름은 바로 고칠 수 있습니다. 동영상 줄을 세 번 누르면 첫 번째 버튼의 폴더로 옮깁니다": "表示名はその場で変更できます。動画の行を 3回押すと最初のボタンのフォルダーに移動します", diff --git a/assets/l10n/zh-Hans.json b/assets/l10n/zh-Hans.json index c75649d..c398f80 100644 --- a/assets/l10n/zh-Hans.json +++ b/assets/l10n/zh-Hans.json @@ -156,6 +156,7 @@ "{0} 번역 중 {1}%": "正在翻译 {0} {1}%", "{0} 브라우저의 YouTube 로그인 쿠키 사용 (Chrome · Edge 는 브라우저를 닫아야 읽힐 수 있음)": "使用 {0} 浏览器的 YouTube 登录 Cookie(Chrome · Edge 可能需要关闭浏览器才能读取)", "{0} 순으로 정렬{1}": "按{0}排序{1}", + "{0} 아래에 만듭니다": "在 {0} 下创建", "{0} 에서 받을 파일을 찾지 못했습니다": "未在 {0} 找到要下载的文件", "{0} 인코더가 FFmpeg 에 없습니다.": "FFmpeg 中没有 {0} 编码器。", "{0} 추가": "添加 {0}", @@ -591,6 +592,7 @@ "이미 동영상 목록에 있습니다 ({0}개).": "已在视频列表中({0} 个)。", "이미 목록에 있는 동영상입니다 ({0}개).": "这些视频已在列表中({0} 个)。", "이미 받는 중이거나 받을 수 없는 주소입니다.": "已在下载中,或该地址无法下载。", + "이미 있는 폴더입니다: {0}": "文件夹已存在: {0}", "이미지 자막은 번역할 수 없습니다": "图像字幕无法翻译", "이미지 자막은 편집할 수 없습니다": "图像字幕无法编辑", "이전": "上一个", @@ -800,14 +802,17 @@ "포르투갈어": "葡萄牙语", "포함된 구성 요소와 라이선스 (THIRD_PARTY_NOTICES.txt)": "包含的组件与许可(THIRD_PARTY_NOTICES.txt)", "폴더": "文件夹", + "폴더 만들기": "新建文件夹", "폴더 삭제: {0} (안의 {1}개 포함)": "已删除文件夹: {0}(含其中 {1} 个)", "폴더 선택": "选择文件夹", "폴더 수정": "编辑文件夹", "폴더 열기": "打开文件夹", "폴더 이름": "文件夹名称", "폴더 이름 바꾸기 · 이동": "重命名 · 移动文件夹", + "폴더 이름에 쓸 수 없는 글자가 있습니다 (\\ / : * ? \" < > |)": "文件夹名称中有不能使用的字符(\\ / : * ? \" < > |)", "폴더: {0}": "文件夹: {0}", "폴더가 아닙니다: {0}": "不是文件夹: {0}", + "폴더를 만들 수 없습니다: {0}": "无法创建文件夹: {0}", "폴란드어": "波兰语", "표시 이름": "显示名称", "표시 이름은 바로 고칠 수 있습니다. 동영상 줄을 세 번 누르면 첫 번째 버튼의 폴더로 옮깁니다": "显示名称可直接修改。连续点击视频行三次会移到第一个按钮的文件夹", diff --git a/lib/ui/android_file_browser.dart b/lib/ui/android_file_browser.dart index 877ff27..5dc5f35 100644 --- a/lib/ui/android_file_browser.dart +++ b/lib/ui/android_file_browser.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:path/path.dart' as p; import '../platform/android/android_storage.dart'; +import 'bookmark_ui.dart' show askText; import 'theme.dart'; import '../l10n/tr.dart'; @@ -104,6 +105,30 @@ class _FileBrowserState extends State<_FileBrowser> { }); } + /// 폴더 만들기: 이름을 물어 [parent] 아래에 만들고 그 폴더로 들어간다 + Future _makeFolder(String parent) async { + final name = (await askText(context, tr('폴더 만들기'), tr('폴더 이름'), tr('새 폴더'), + help: trf('{0} 아래에 만듭니다', [parent]))) + ?.trim(); + if (name == null || name.isEmpty || !mounted) return; + final messenger = ScaffoldMessenger.of(context); + if (RegExp(r'[\\/:*?"<>|]').hasMatch(name) || name == '.' || name == '..') { + messenger.showSnackBar(SnackBar(content: Text(tr('폴더 이름에 쓸 수 없는 글자가 있습니다 (\\ / : * ? " < > |)')))); + return; + } + final path = p.join(parent, name); + try { + if (Directory(path).existsSync()) { + messenger.showSnackBar(SnackBar(content: Text(trf('이미 있는 폴더입니다: {0}', [name])))); + } else { + Directory(path).createSync(); + } + _open(path); + } catch (e) { + messenger.showSnackBar(SnackBar(content: Text(trf('폴더를 만들 수 없습니다: {0}', [e])))); + } + } + static String _size(int b) { if (b >= 1 << 30) return '${(b / (1 << 30)).toStringAsFixed(1)}GB'; if (b >= 1 << 20) return '${(b / (1 << 20)).toStringAsFixed(1)}MB'; @@ -126,7 +151,14 @@ class _FileBrowserState extends State<_FileBrowser> { appBar: AppBar( title: Text(widget.title), actions: [ - if (widget.folder) + if (widget.folder) ...[ + // 지금 보고 있는 폴더 아래에 새 폴더 (만든 뒤 그 폴더로 들어간다) + OutlinedButton.icon( + onPressed: dir == null ? null : () => _makeFolder(dir), + icon: const Icon(Icons.create_new_folder_outlined, size: 18), + label: Text(tr('폴더 만들기')), + ), + const SizedBox(width: 8), Padding( padding: const EdgeInsets.only(right: 8), child: FilledButton.icon( @@ -134,8 +166,8 @@ class _FileBrowserState extends State<_FileBrowser> { icon: const Icon(Icons.check, size: 18), label: Text(tr('이 폴더 선택')), ), - ) - else ...[ + ), + ] else ...[ if (_files.isNotEmpty) TextButton( onPressed: () => setState(() {