Android 폴더 고르기: [이 폴더 선택] 왼쪽에 [폴더 만들기] (지금 폴더 아래에 만들고 그 폴더로)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
main
RyuJongJin 2026-10-04 21:17:37 +09:00
parent 7c487c41cd
commit 4257b97305
4 changed files with 50 additions and 3 deletions

View File

@ -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",

View File

@ -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回押すと最初のボタンのフォルダーに移動します",

View File

@ -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}",
"폴란드어": "波兰语",
"표시 이름": "显示名称",
"표시 이름은 바로 고칠 수 있습니다. 동영상 줄을 세 번 누르면 첫 번째 버튼의 폴더로 옮깁니다": "显示名称可直接修改。连续点击视频行三次会移到第一个按钮的文件夹",

View File

@ -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<void> _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(() {