50 Android 가 막은 폴더 (Android/data · obb): 빈 폴더가 아니라 "이 폴더는 Android 가 막아 볼 수 없습니다" · [위 폴더로]
- Android 11 부터 이런 폴더는 오류 없이 빈 목록으로 읽힌다 - 막힌 것이라고 알리고 그 앱의 내보내기 · 공유를 안내 - 다시 해도 같으므로 [다시 시도] 대신 [위 폴더로] - 시험: file_error_test (경로 판별 · 안내 글) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>묶음3
parent
de967d190a
commit
c25a754035
|
|
@ -102,6 +102,7 @@
|
||||||
"API 키 (필수, 무료)": "API key (required, free)",
|
"API 키 (필수, 무료)": "API key (required, free)",
|
||||||
"API 키 또는 아이디:비밀번호 (선택)": "API key or user:password (optional)",
|
"API 키 또는 아이디:비밀번호 (선택)": "API key or user:password (optional)",
|
||||||
"AV1 영상은 이 기기에서 다시 인코딩할 수 없습니다. 코덱을 \"원본 유지\" 로 바꿔 MKV 를 만드세요. (PC 판은 됩니다)": "AV1 video cannot be re-encoded on this device. Change the codec to \"Keep original\" to make the MKV. (The PC version can.)",
|
"AV1 영상은 이 기기에서 다시 인코딩할 수 없습니다. 코덱을 \"원본 유지\" 로 바꿔 MKV 를 만드세요. (PC 판은 됩니다)": "AV1 video cannot be re-encoded on this device. Change the codec to \"Keep original\" to make the MKV. (The PC version can.)",
|
||||||
|
"Android 11 부터 다른 앱의 데이터 폴더 (Android/data · Android/obb) 는 어떤 파일 앱도 열 수 없습니다. 그 앱 안의 내보내기 · 공유로 파일을 꺼내세요.": "Since Android 11, no file app can open other apps' data folders (Android/data · Android/obb). Use export or share inside that app to get the files.",
|
||||||
"Android 가 막은 폴더 (Android/data 등) 이거나 \"모든 파일에 대한 접근\" 권한이 없습니다.": "This folder is blocked by Android (such as Android/data), or \"All files access\" is not allowed.",
|
"Android 가 막은 폴더 (Android/data 등) 이거나 \"모든 파일에 대한 접근\" 권한이 없습니다.": "This folder is blocked by Android (such as Android/data), or \"All files access\" is not allowed.",
|
||||||
"Android 는 rsync 를 내려받을 수 없습니다. 직접 지정하세요.": "rsync cannot be downloaded on Android. Specify it yourself.",
|
"Android 는 rsync 를 내려받을 수 없습니다. 직접 지정하세요.": "rsync cannot be downloaded on Android. Specify it yourself.",
|
||||||
"Android 는 버전이 낮은 앱을 지금 앱 위에 설치하지 못합니다. 그래서:\n1. v{0} 설치 파일과 지금 설정 (동영상 목록 · 즐겨찾기 포함) 을 Download/JJ_MKVMaker 에 저장합니다.\n2. 이 앱을 지웁니다 (Android 확인 창).\n3. 파일 앱에서 Download/JJ_MKVMaker 의 APK 를 눌러 설치합니다.\n4. 이 기능이 있는 버전이면 시작할 때 저장해 둔 설정을 되살릴지 묻습니다. 더 예전 버전은 설정을 다시 해야 합니다.\n※ 자막 API 키 · 비밀번호는 저장하지 않으므로 다시 넣어야 합니다.": "Android cannot install a lower version over the current app. So:\n1. Save the v{0} install file and the current settings (including the video list and bookmarks) to Download/JJ_MKVMaker.\n2. Uninstall this app (Android confirmation).\n3. Tap the APK in Download/JJ_MKVMaker in a file manager to install it.\n4. Versions with this feature ask at startup whether to restore the saved settings. Older versions need to be set up again.\n* Subtitle API keys and passwords are not saved, so enter them again.",
|
"Android 는 버전이 낮은 앱을 지금 앱 위에 설치하지 못합니다. 그래서:\n1. v{0} 설치 파일과 지금 설정 (동영상 목록 · 즐겨찾기 포함) 을 Download/JJ_MKVMaker 에 저장합니다.\n2. 이 앱을 지웁니다 (Android 확인 창).\n3. 파일 앱에서 Download/JJ_MKVMaker 의 APK 를 눌러 설치합니다.\n4. 이 기능이 있는 버전이면 시작할 때 저장해 둔 설정을 되살릴지 묻습니다. 더 예전 버전은 설정을 다시 해야 합니다.\n※ 자막 API 키 · 비밀번호는 저장하지 않으므로 다시 넣어야 합니다.": "Android cannot install a lower version over the current app. So:\n1. Save the v{0} install file and the current settings (including the video list and bookmarks) to Download/JJ_MKVMaker.\n2. Uninstall this app (Android confirmation).\n3. Tap the APK in Download/JJ_MKVMaker in a file manager to install it.\n4. Versions with this feature ask at startup whether to restore the saved settings. Older versions need to be set up again.\n* Subtitle API keys and passwords are not saved, so enter them again.",
|
||||||
|
|
@ -1270,6 +1271,7 @@
|
||||||
"웹 페이지 자동 번역": "Translate web pages automatically",
|
"웹 페이지 자동 번역": "Translate web pages automatically",
|
||||||
"웹 페이지를 번역하지 못했습니다: {0}": "Could not translate the web page: {0}",
|
"웹 페이지를 번역하지 못했습니다: {0}": "Could not translate the web page: {0}",
|
||||||
"위 폴더": "Parent folder",
|
"위 폴더": "Parent folder",
|
||||||
|
"위 폴더로": "Go up",
|
||||||
"위로": "Up",
|
"위로": "Up",
|
||||||
"위아래": "Top and bottom",
|
"위아래": "Top and bottom",
|
||||||
"위아래 ⇅": "Stacked ⇅",
|
"위아래 ⇅": "Stacked ⇅",
|
||||||
|
|
@ -1331,6 +1333,7 @@
|
||||||
"이 폴더 선택": "Choose this folder",
|
"이 폴더 선택": "Choose this folder",
|
||||||
"이 폴더 쌍은 기억한 옵션을 씁니다 (환경 설정이 아니라 모니터링 > 복사 · rsync 에서 고칩니다)": "This folder pair uses its remembered options (edit them in Monitoring > Copy · rsync, not in settings)",
|
"이 폴더 쌍은 기억한 옵션을 씁니다 (환경 설정이 아니라 모니터링 > 복사 · rsync 에서 고칩니다)": "This folder pair uses its remembered options (edit them in Monitoring > Copy · rsync, not in settings)",
|
||||||
"이 폴더 전체": "This whole folder",
|
"이 폴더 전체": "This whole folder",
|
||||||
|
"이 폴더는 Android 가 막아 볼 수 없습니다": "Android blocks this folder, so it cannot be viewed",
|
||||||
"이 폴더를 rsync 원본 · 대상으로 고르기": "Choose this folder as rsync source · target",
|
"이 폴더를 rsync 원본 · 대상으로 고르기": "Choose this folder as rsync source · target",
|
||||||
"이 폴더를 볼 권한이 없습니다": "No permission to view this folder",
|
"이 폴더를 볼 권한이 없습니다": "No permission to view this folder",
|
||||||
"이 폴더를 읽을 권한이 없습니다": "No permission to read this folder",
|
"이 폴더를 읽을 권한이 없습니다": "No permission to read this folder",
|
||||||
|
|
|
||||||
|
|
@ -102,6 +102,7 @@
|
||||||
"API 키 (필수, 무료)": "API キー(必須・無料)",
|
"API 키 (필수, 무료)": "API キー(必須・無料)",
|
||||||
"API 키 또는 아이디:비밀번호 (선택)": "API キーまたは ID:パスワード (任意)",
|
"API 키 또는 아이디:비밀번호 (선택)": "API キーまたは ID:パスワード (任意)",
|
||||||
"AV1 영상은 이 기기에서 다시 인코딩할 수 없습니다. 코덱을 \"원본 유지\" 로 바꿔 MKV 를 만드세요. (PC 판은 됩니다)": "AV1 動画はこの端末では再エンコードできません。コーデックを「元のまま」に変えて MKV を作成してください。(PC 版はできます)",
|
"AV1 영상은 이 기기에서 다시 인코딩할 수 없습니다. 코덱을 \"원본 유지\" 로 바꿔 MKV 를 만드세요. (PC 판은 됩니다)": "AV1 動画はこの端末では再エンコードできません。コーデックを「元のまま」に変えて MKV を作成してください。(PC 版はできます)",
|
||||||
|
"Android 11 부터 다른 앱의 데이터 폴더 (Android/data · Android/obb) 는 어떤 파일 앱도 열 수 없습니다. 그 앱 안의 내보내기 · 공유로 파일을 꺼내세요.": "Android 11 以降、他のアプリのデータフォルダー (Android/data・Android/obb) はどのファイルアプリでも開けません。そのアプリ内のエクスポート・共有でファイルを取り出してください。",
|
||||||
"Android 가 막은 폴더 (Android/data 등) 이거나 \"모든 파일에 대한 접근\" 권한이 없습니다.": "Android が制限しているフォルダー (Android/data など) か、「すべてのファイルへのアクセス」権限がありません。",
|
"Android 가 막은 폴더 (Android/data 등) 이거나 \"모든 파일에 대한 접근\" 권한이 없습니다.": "Android が制限しているフォルダー (Android/data など) か、「すべてのファイルへのアクセス」権限がありません。",
|
||||||
"Android 는 rsync 를 내려받을 수 없습니다. 직접 지정하세요.": "Android では rsync をダウンロードできません。直接指定してください。",
|
"Android 는 rsync 를 내려받을 수 없습니다. 직접 지정하세요.": "Android では rsync をダウンロードできません。直接指定してください。",
|
||||||
"Android 는 버전이 낮은 앱을 지금 앱 위에 설치하지 못합니다. 그래서:\n1. v{0} 설치 파일과 지금 설정 (동영상 목록 · 즐겨찾기 포함) 을 Download/JJ_MKVMaker 에 저장합니다.\n2. 이 앱을 지웁니다 (Android 확인 창).\n3. 파일 앱에서 Download/JJ_MKVMaker 의 APK 를 눌러 설치합니다.\n4. 이 기능이 있는 버전이면 시작할 때 저장해 둔 설정을 되살릴지 묻습니다. 더 예전 버전은 설정을 다시 해야 합니다.\n※ 자막 API 키 · 비밀번호는 저장하지 않으므로 다시 넣어야 합니다.": "Android はバージョンの低いアプリを今のアプリの上にインストールできません。そこで:\n1. v{0} のインストールファイルと今の設定 (動画リスト · ブックマークを含む) を Download/JJ_MKVMaker に保存します。\n2. このアプリを削除します (Android の確認画面)。\n3. ファイルアプリで Download/JJ_MKVMaker の APK をタップしてインストールします。\n4. この機能があるバージョンなら起動時に保存した設定を復元するか尋ねます。それより古いバージョンは設定し直す必要があります。\n※ 字幕 API キー · パスワードは保存しないので再入力が必要です。",
|
"Android 는 버전이 낮은 앱을 지금 앱 위에 설치하지 못합니다. 그래서:\n1. v{0} 설치 파일과 지금 설정 (동영상 목록 · 즐겨찾기 포함) 을 Download/JJ_MKVMaker 에 저장합니다.\n2. 이 앱을 지웁니다 (Android 확인 창).\n3. 파일 앱에서 Download/JJ_MKVMaker 의 APK 를 눌러 설치합니다.\n4. 이 기능이 있는 버전이면 시작할 때 저장해 둔 설정을 되살릴지 묻습니다. 더 예전 버전은 설정을 다시 해야 합니다.\n※ 자막 API 키 · 비밀번호는 저장하지 않으므로 다시 넣어야 합니다.": "Android はバージョンの低いアプリを今のアプリの上にインストールできません。そこで:\n1. v{0} のインストールファイルと今の設定 (動画リスト · ブックマークを含む) を Download/JJ_MKVMaker に保存します。\n2. このアプリを削除します (Android の確認画面)。\n3. ファイルアプリで Download/JJ_MKVMaker の APK をタップしてインストールします。\n4. この機能があるバージョンなら起動時に保存した設定を復元するか尋ねます。それより古いバージョンは設定し直す必要があります。\n※ 字幕 API キー · パスワードは保存しないので再入力が必要です。",
|
||||||
|
|
@ -1270,6 +1271,7 @@
|
||||||
"웹 페이지 자동 번역": "ウェブページを自動翻訳",
|
"웹 페이지 자동 번역": "ウェブページを自動翻訳",
|
||||||
"웹 페이지를 번역하지 못했습니다: {0}": "ウェブページを翻訳できませんでした: {0}",
|
"웹 페이지를 번역하지 못했습니다: {0}": "ウェブページを翻訳できませんでした: {0}",
|
||||||
"위 폴더": "上のフォルダー",
|
"위 폴더": "上のフォルダー",
|
||||||
|
"위 폴더로": "上のフォルダーへ",
|
||||||
"위로": "上へ",
|
"위로": "上へ",
|
||||||
"위아래": "上下",
|
"위아래": "上下",
|
||||||
"위아래 ⇅": "上下 ⇅",
|
"위아래 ⇅": "上下 ⇅",
|
||||||
|
|
@ -1331,6 +1333,7 @@
|
||||||
"이 폴더 선택": "このフォルダーを選択",
|
"이 폴더 선택": "このフォルダーを選択",
|
||||||
"이 폴더 쌍은 기억한 옵션을 씁니다 (환경 설정이 아니라 모니터링 > 복사 · rsync 에서 고칩니다)": "このフォルダーの組は記憶したオプションを使います (環境設定ではなくモニタリング > コピー・rsync で変更します)",
|
"이 폴더 쌍은 기억한 옵션을 씁니다 (환경 설정이 아니라 모니터링 > 복사 · rsync 에서 고칩니다)": "このフォルダーの組は記憶したオプションを使います (環境設定ではなくモニタリング > コピー・rsync で変更します)",
|
||||||
"이 폴더 전체": "このフォルダー全体",
|
"이 폴더 전체": "このフォルダー全体",
|
||||||
|
"이 폴더는 Android 가 막아 볼 수 없습니다": "このフォルダーは Android によってブロックされているため表示できません",
|
||||||
"이 폴더를 rsync 원본 · 대상으로 고르기": "このフォルダーを rsync の元 · 対象に選ぶ",
|
"이 폴더를 rsync 원본 · 대상으로 고르기": "このフォルダーを rsync の元 · 対象に選ぶ",
|
||||||
"이 폴더를 볼 권한이 없습니다": "このフォルダーを表示する権限がありません",
|
"이 폴더를 볼 권한이 없습니다": "このフォルダーを表示する権限がありません",
|
||||||
"이 폴더를 읽을 권한이 없습니다": "このフォルダーを読む権限がありません",
|
"이 폴더를 읽을 권한이 없습니다": "このフォルダーを読む権限がありません",
|
||||||
|
|
|
||||||
|
|
@ -102,6 +102,7 @@
|
||||||
"API 키 (필수, 무료)": "API 密钥(必填,免费)",
|
"API 키 (필수, 무료)": "API 密钥(必填,免费)",
|
||||||
"API 키 또는 아이디:비밀번호 (선택)": "API 密钥或 用户名:密码 (可选)",
|
"API 키 또는 아이디:비밀번호 (선택)": "API 密钥或 用户名:密码 (可选)",
|
||||||
"AV1 영상은 이 기기에서 다시 인코딩할 수 없습니다. 코덱을 \"원본 유지\" 로 바꿔 MKV 를 만드세요. (PC 판은 됩니다)": "此设备无法重新编码 AV1 视频。请将编解码器改为“保持原样”后制作 MKV。(PC 版可以)",
|
"AV1 영상은 이 기기에서 다시 인코딩할 수 없습니다. 코덱을 \"원본 유지\" 로 바꿔 MKV 를 만드세요. (PC 판은 됩니다)": "此设备无法重新编码 AV1 视频。请将编解码器改为“保持原样”后制作 MKV。(PC 版可以)",
|
||||||
|
"Android 11 부터 다른 앱의 데이터 폴더 (Android/data · Android/obb) 는 어떤 파일 앱도 열 수 없습니다. 그 앱 안의 내보내기 · 공유로 파일을 꺼내세요.": "从 Android 11 起,任何文件应用都无法打开其他应用的数据文件夹 (Android/data · Android/obb)。请在该应用内使用导出或分享取出文件。",
|
||||||
"Android 가 막은 폴더 (Android/data 등) 이거나 \"모든 파일에 대한 접근\" 권한이 없습니다.": "这是 Android 限制的文件夹 (如 Android/data),或没有“所有文件访问”权限。",
|
"Android 가 막은 폴더 (Android/data 등) 이거나 \"모든 파일에 대한 접근\" 권한이 없습니다.": "这是 Android 限制的文件夹 (如 Android/data),或没有“所有文件访问”权限。",
|
||||||
"Android 는 rsync 를 내려받을 수 없습니다. 직접 지정하세요.": "Android 无法下载 rsync,请自行指定。",
|
"Android 는 rsync 를 내려받을 수 없습니다. 직접 지정하세요.": "Android 无法下载 rsync,请自行指定。",
|
||||||
"Android 는 버전이 낮은 앱을 지금 앱 위에 설치하지 못합니다. 그래서:\n1. v{0} 설치 파일과 지금 설정 (동영상 목록 · 즐겨찾기 포함) 을 Download/JJ_MKVMaker 에 저장합니다.\n2. 이 앱을 지웁니다 (Android 확인 창).\n3. 파일 앱에서 Download/JJ_MKVMaker 의 APK 를 눌러 설치합니다.\n4. 이 기능이 있는 버전이면 시작할 때 저장해 둔 설정을 되살릴지 묻습니다. 더 예전 버전은 설정을 다시 해야 합니다.\n※ 자막 API 키 · 비밀번호는 저장하지 않으므로 다시 넣어야 합니다.": "Android 无法在当前应用上安装版本更低的应用。因此:\n1. 将 v{0} 安装文件和当前设置 (包括视频列表 · 书签) 保存到 Download/JJ_MKVMaker。\n2. 卸载此应用 (Android 确认窗口)。\n3. 在文件应用中点按 Download/JJ_MKVMaker 中的 APK 进行安装。\n4. 带有此功能的版本会在启动时询问是否恢复保存的设置。更早的版本需要重新设置。\n※ 字幕 API 密钥 · 密码不会保存,需要重新输入。",
|
"Android 는 버전이 낮은 앱을 지금 앱 위에 설치하지 못합니다. 그래서:\n1. v{0} 설치 파일과 지금 설정 (동영상 목록 · 즐겨찾기 포함) 을 Download/JJ_MKVMaker 에 저장합니다.\n2. 이 앱을 지웁니다 (Android 확인 창).\n3. 파일 앱에서 Download/JJ_MKVMaker 의 APK 를 눌러 설치합니다.\n4. 이 기능이 있는 버전이면 시작할 때 저장해 둔 설정을 되살릴지 묻습니다. 더 예전 버전은 설정을 다시 해야 합니다.\n※ 자막 API 키 · 비밀번호는 저장하지 않으므로 다시 넣어야 합니다.": "Android 无法在当前应用上安装版本更低的应用。因此:\n1. 将 v{0} 安装文件和当前设置 (包括视频列表 · 书签) 保存到 Download/JJ_MKVMaker。\n2. 卸载此应用 (Android 确认窗口)。\n3. 在文件应用中点按 Download/JJ_MKVMaker 中的 APK 进行安装。\n4. 带有此功能的版本会在启动时询问是否恢复保存的设置。更早的版本需要重新设置。\n※ 字幕 API 密钥 · 密码不会保存,需要重新输入。",
|
||||||
|
|
@ -1270,6 +1271,7 @@
|
||||||
"웹 페이지 자동 번역": "自动翻译网页",
|
"웹 페이지 자동 번역": "自动翻译网页",
|
||||||
"웹 페이지를 번역하지 못했습니다: {0}": "无法翻译网页: {0}",
|
"웹 페이지를 번역하지 못했습니다: {0}": "无法翻译网页: {0}",
|
||||||
"위 폴더": "上级文件夹",
|
"위 폴더": "上级文件夹",
|
||||||
|
"위 폴더로": "返回上级文件夹",
|
||||||
"위로": "向上",
|
"위로": "向上",
|
||||||
"위아래": "上下",
|
"위아래": "上下",
|
||||||
"위아래 ⇅": "上下 ⇅",
|
"위아래 ⇅": "上下 ⇅",
|
||||||
|
|
@ -1331,6 +1333,7 @@
|
||||||
"이 폴더 선택": "选择此文件夹",
|
"이 폴더 선택": "选择此文件夹",
|
||||||
"이 폴더 쌍은 기억한 옵션을 씁니다 (환경 설정이 아니라 모니터링 > 복사 · rsync 에서 고칩니다)": "此文件夹组合使用记住的选项 (请在 监视 > 复制 · rsync 中修改,而非设置)",
|
"이 폴더 쌍은 기억한 옵션을 씁니다 (환경 설정이 아니라 모니터링 > 복사 · rsync 에서 고칩니다)": "此文件夹组合使用记住的选项 (请在 监视 > 复制 · rsync 中修改,而非设置)",
|
||||||
"이 폴더 전체": "整个文件夹",
|
"이 폴더 전체": "整个文件夹",
|
||||||
|
"이 폴더는 Android 가 막아 볼 수 없습니다": "此文件夹被 Android 阻止,无法查看",
|
||||||
"이 폴더를 rsync 원본 · 대상으로 고르기": "选择此文件夹作为 rsync 源 · 目标",
|
"이 폴더를 rsync 원본 · 대상으로 고르기": "选择此文件夹作为 rsync 源 · 目标",
|
||||||
"이 폴더를 볼 권한이 없습니다": "没有查看此文件夹的权限",
|
"이 폴더를 볼 권한이 없습니다": "没有查看此文件夹的权限",
|
||||||
"이 폴더를 읽을 권한이 없습니다": "没有读取此文件夹的权限",
|
"이 폴더를 읽을 권한이 없습니다": "没有读取此文件夹的权限",
|
||||||
|
|
|
||||||
|
|
@ -473,6 +473,23 @@ class _ExplorerPageState extends State<ExplorerPage> {
|
||||||
final server = dav ? DavRegistry.server(DavPath.parse(where).server) : null;
|
final server = dav ? DavRegistry.server(DavPath.parse(where).server) : null;
|
||||||
final (title, body) = explainFileError(err, dav: dav, noPassword: server != null && server.password.isEmpty);
|
final (title, body) = explainFileError(err, dav: dav, noPassword: server != null && server.password.isEmpty);
|
||||||
final locked = isLockedError(err);
|
final locked = isLockedError(err);
|
||||||
|
// 50: 막힌 폴더는 다시 해도 같으니 [다시 시도] 없이 [위 폴더로]
|
||||||
|
if (err == androidRestrictedError) {
|
||||||
|
return _notice(
|
||||||
|
icon: Icons.lock_outline,
|
||||||
|
title: '${_displayPath(where)}: $title',
|
||||||
|
body: body,
|
||||||
|
actions: [
|
||||||
|
FilledButton.tonal(
|
||||||
|
onPressed: () {
|
||||||
|
pane.errors.remove(where);
|
||||||
|
_goTo(pane, vDirname(where));
|
||||||
|
},
|
||||||
|
child: Text(tr('위 폴더로')),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
return _notice(
|
return _notice(
|
||||||
icon: dav ? Icons.cloud_off_outlined : Icons.error_outline,
|
icon: dav ? Icons.cloud_off_outlined : Icons.error_outline,
|
||||||
title: '${_displayPath(where)}: $title',
|
title: '${_displayPath(where)}: $title',
|
||||||
|
|
@ -584,10 +601,15 @@ class _ExplorerPageState extends State<ExplorerPage> {
|
||||||
try {
|
try {
|
||||||
final list = await listEntries(dir, showHidden: c.settings.explorerShowHidden);
|
final list = await listEntries(dir, showHidden: c.settings.explorerShowHidden);
|
||||||
pane.cache[dir] = _sorted(list);
|
pane.cache[dir] = _sorted(list);
|
||||||
|
// 50: Android 가 막은 폴더는 비어 보인다 (오류 없이) - 비어 있는 것이 아니라 막힌 것이라고 알린다
|
||||||
|
if (list.isEmpty && isAndroidRestricted(dir)) {
|
||||||
|
pane.errors[dir] = androidRestrictedError;
|
||||||
|
} else {
|
||||||
pane.errors.remove(dir);
|
pane.errors.remove(dir);
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
pane.cache[dir] = const [];
|
pane.cache[dir] = const [];
|
||||||
pane.errors[dir] = '$e';
|
pane.errors[dir] = isAndroidRestricted(dir) ? androidRestrictedError : '$e';
|
||||||
} finally {
|
} finally {
|
||||||
pane.loading.remove(dir);
|
pane.loading.remove(dir);
|
||||||
pane.changed();
|
pane.changed();
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,21 @@ import '../l10n/tr.dart';
|
||||||
|
|
||||||
/// 파일 · WebDAV 오류를 사람이 읽을 말로 (제목, 할 일). 원문 예외는 알아볼 수 없을 때만 그대로.
|
/// 파일 · WebDAV 오류를 사람이 읽을 말로 (제목, 할 일). 원문 예외는 알아볼 수 없을 때만 그대로.
|
||||||
/// 파일 탐색기 · 폴더 고르기 · 그 밖에 WebDAV 를 읽는 화면이 함께 쓴다 (12 · 134).
|
/// 파일 탐색기 · 폴더 고르기 · 그 밖에 WebDAV 를 읽는 화면이 함께 쓴다 (12 · 134).
|
||||||
|
/// 50: Android 가 막은 폴더 (Android/data · obb) 표시 (파일 탐색기가 오류 자리에 넣는다)
|
||||||
|
const androidRestrictedError = 'ANDROID_RESTRICTED_FOLDER';
|
||||||
|
|
||||||
|
/// 50: Android 11 부터 어떤 파일 앱도 다른 앱의 데이터 폴더 (Android/data · Android/obb) 를 볼 수 없다
|
||||||
|
bool isAndroidRestricted(String path, {bool? android}) =>
|
||||||
|
(android ?? Platform.isAndroid) && RegExp(r'/Android/(data|obb)(/|$)', caseSensitive: false).hasMatch(path);
|
||||||
|
|
||||||
(String, String) explainFileError(String e, {required bool dav, bool noPassword = false}) {
|
(String, String) explainFileError(String e, {required bool dav, bool noPassword = false}) {
|
||||||
|
if (e == androidRestrictedError) {
|
||||||
|
return (
|
||||||
|
tr('이 폴더는 Android 가 막아 볼 수 없습니다'),
|
||||||
|
tr('Android 11 부터 다른 앱의 데이터 폴더 (Android/data · Android/obb) 는 어떤 파일 앱도 열 수 없습니다. '
|
||||||
|
'그 앱 안의 내보내기 · 공유로 파일을 꺼내세요.'),
|
||||||
|
);
|
||||||
|
}
|
||||||
// 128 · 133: 마스터 비밀번호를 기다리는 중 (고장이 아님)
|
// 128 · 133: 마스터 비밀번호를 기다리는 중 (고장이 아님)
|
||||||
if (isLockedError(e)) {
|
if (isLockedError(e)) {
|
||||||
return (tr('마스터 비밀번호가 필요합니다'), tr('이 서버의 저장된 비밀번호를 쓰려면 마스터 비밀번호를 넣으세요.'));
|
return (tr('마스터 비밀번호가 필요합니다'), tr('이 서버의 저장된 비밀번호를 쓰려면 마스터 비밀번호를 넣으세요.'));
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:jj_mkvmaker/ui/file_error.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
test('50: Android 가 막은 폴더 (Android/data · obb) 알아보기', () {
|
||||||
|
for (final p in [
|
||||||
|
'/storage/emulated/0/Android/data',
|
||||||
|
'/storage/emulated/0/Android/data/com.example.app',
|
||||||
|
'/storage/emulated/0/Android/obb/',
|
||||||
|
'/storage/1234-ABCD/Android/data/x',
|
||||||
|
]) {
|
||||||
|
expect(isAndroidRestricted(p, android: true), isTrue, reason: p);
|
||||||
|
}
|
||||||
|
for (final p in [
|
||||||
|
'/storage/emulated/0/Android',
|
||||||
|
'/storage/emulated/0/Android/media',
|
||||||
|
'/storage/emulated/0/Download/Android/datas',
|
||||||
|
'/storage/emulated/0/Movies',
|
||||||
|
]) {
|
||||||
|
expect(isAndroidRestricted(p, android: true), isFalse, reason: p);
|
||||||
|
}
|
||||||
|
// Windows 등은 해당 없음
|
||||||
|
expect(isAndroidRestricted('/storage/emulated/0/Android/data', android: false), isFalse);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('50: 막힌 폴더는 "이 폴더는 Android 가 막아 볼 수 없습니다" 와 할 일', () {
|
||||||
|
final (title, body) = explainFileError(androidRestrictedError, dav: false);
|
||||||
|
expect(title, '이 폴더는 Android 가 막아 볼 수 없습니다');
|
||||||
|
expect(body, contains('내보내기'));
|
||||||
|
});
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue