파일 탐색기: 폰 한 창 · 한 번 누르면 실행 · 경로 이름 · 권한 · WebDAV 오류 안내 · 첫 화면 바로
근거: 감독 세션 지시 (폰 Z Fold6 · S10 Ultra 를 사용자처럼 써 본 결과) 1 · 5 · 6 · 10 · 11 · 12 · 14번.
감사 A-13 (지시와 반대였던 기본값) 되돌림 포함.
- 1: "모든 파일 접근" 권한이 없으면 목록 위에 이유 · 할 일 · [권한 허용 화면 열기] · [다시 확인].
듀얼 앱 (복제한 앱) 이면 그 사실과 원래 앱으로 여는 방법을 안내. [동영상 추가] 권한 화면에도.
허용하고 돌아오면 다시 확인해 목록을 새로 읽음.
- 5 · 14: 경로를 "SD 카드 › JJ_sdtest › jj_mkv" · "디바이스 저장공간 › Download" · "☁ ds1815 › 폴더" 로 (Android · WebDAV).
- 6: Rsync 창이 위아래면 버튼도 "위 → 아래 · 위 ← 아래 · 위 ⇄ 아래" (화살표도).
- 10 · 5: 기본값을 사용자 입장으로 - 창 배치 기본 '화면 크기 따라' (넓으면 두 창, 폰 세로는 한 창),
Android 는 한 번 누르면 바로 실행. 예전 기본값 (사용자가 고른 것 아님) 은 한 번 옮김, 고른 값은 그대로.
- 11: 창마다 따로 읽음 - WebDAV 서버를 기다리는 동안에도 이 기기 파일이 바로 보임 (읽는 중 막대).
- 12: 읽을 수 없으면 이유 (서버에 닿지 않음 → 같은 네트워크 · Tailscale, 비밀번호, 인증서, 권한, 없음) ·
[다시 시도] · [서버 설정 고치기].
- 감사 A-13: ZIP 은 기본 목록 보기 (사용자 지시 10-08 "zip 은 기본 목록 보기, 만화 보기는 설정에서"). 예전 기본 (만화) 은 한 번 끔.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
묶음3
parent
b39678f8f6
commit
fead23ce2f
|
|
@ -62,6 +62,7 @@
|
||||||
"API 키": "API key",
|
"API 키": "API key",
|
||||||
"API 키 (필수, 무료)": "API key (required, free)",
|
"API 키 (필수, 무료)": "API key (required, free)",
|
||||||
"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 가 막은 폴더 (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.",
|
||||||
"Android 설치 화면에서 [설치] 를 누르세요. 설정 · 받은 파일 · AI 모델은 그대로 남습니다.\n(처음이면 \"이 출처의 앱 설치 허용\" 을 켜야 할 수 있습니다)": "Press [Install] on the Android install screen. Settings, downloaded files and AI models stay as they are.\n(The first time, you may need to turn on \"Allow from this source\")",
|
"Android 설치 화면에서 [설치] 를 누르세요. 설정 · 받은 파일 · AI 모델은 그대로 남습니다.\n(처음이면 \"이 출처의 앱 설치 허용\" 을 켜야 할 수 있습니다)": "Press [Install] on the Android install screen. Settings, downloaded files and AI models stay as they are.\n(The first time, you may need to turn on \"Allow from this source\")",
|
||||||
|
|
@ -162,6 +163,7 @@
|
||||||
"ZIP · CBZ 를 만화로 보기": "Read ZIP · CBZ as comics",
|
"ZIP · CBZ 를 만화로 보기": "Read ZIP · CBZ as comics",
|
||||||
"ZIP 옆 새 폴더 \"{0}\" 로": "To a new folder \"{0}\" next to the ZIP",
|
"ZIP 옆 새 폴더 \"{0}\" 로": "To a new folder \"{0}\" next to the ZIP",
|
||||||
"ZIP 이 있는 폴더로": "To the ZIP's folder",
|
"ZIP 이 있는 폴더로": "To the ZIP's folder",
|
||||||
|
"[서버 설정 고치기] 에서 아이디 · 비밀번호를 확인하세요.": "Check the user name and password in [Edit server settings].",
|
||||||
"aria2 RPC 에 연결할 수 없습니다.": "Cannot connect to aria2 RPC.",
|
"aria2 RPC 에 연결할 수 없습니다.": "Cannot connect to aria2 RPC.",
|
||||||
"aria2 오류: {0}": "aria2 error: {0}",
|
"aria2 오류: {0}": "aria2 error: {0}",
|
||||||
"cookies.txt (Netscape 형식)": "cookies.txt (Netscape format)",
|
"cookies.txt (Netscape 형식)": "cookies.txt (Netscape format)",
|
||||||
|
|
@ -378,6 +380,7 @@
|
||||||
"누르면 일정 바꾸기": "Tap to change the schedule",
|
"누르면 일정 바꾸기": "Tap to change the schedule",
|
||||||
"다 받는 대로 MKV 만들기의 동영상 목록에 넣고, 다운로드 목록에서는 뺍니다 (다운로드 화면의 체크 상자와 같음)": "As soon as they finish, put them in the Make MKV video list and remove them from the download list (same as the checkbox on the download screen)",
|
"다 받는 대로 MKV 만들기의 동영상 목록에 넣고, 다운로드 목록에서는 뺍니다 (다운로드 화면의 체크 상자와 같음)": "As soon as they finish, put them in the Make MKV video list and remove them from the download list (same as the checkbox on the download screen)",
|
||||||
"다 받으면 MKV 만들기의 동영상 목록에 자동으로 넣고, 이 다운로드 목록에서는 뺍니다 (받은 파일은 그대로)": "When finished, automatically add to the Make MKV video list and remove from this download list (the downloaded file stays)",
|
"다 받으면 MKV 만들기의 동영상 목록에 자동으로 넣고, 이 다운로드 목록에서는 뺍니다 (받은 파일은 그대로)": "When finished, automatically add to the Make MKV video list and remove from this download list (the downloaded file stays)",
|
||||||
|
"다른 곳에서 지웠거나 옮겼을 수 있습니다. 위 폴더로 가 보세요.": "It may have been deleted or moved elsewhere. Try the parent folder.",
|
||||||
"다른 버전 ({0}) 을 쓰다가 v{1} 로 돌아왔습니다. 그 버전은 이 버전의 설정 일부를 모를 수 있습니다.\nv{1} 를 마지막으로 쓸 때 보관해 둔 설정 (동영상 목록 · 즐겨찾기 포함) 으로 되돌릴까요?": "You came back to v{1} after using another version ({0}). That version may not know some of this version's settings.\nRestore the settings kept when you last used v{1} (including the video list and bookmarks)?",
|
"다른 버전 ({0}) 을 쓰다가 v{1} 로 돌아왔습니다. 그 버전은 이 버전의 설정 일부를 모를 수 있습니다.\nv{1} 를 마지막으로 쓸 때 보관해 둔 설정 (동영상 목록 · 즐겨찾기 포함) 으로 되돌릴까요?": "You came back to v{1} after using another version ({0}). That version may not know some of this version's settings.\nRestore the settings kept when you last used v{1} (including the video list and bookmarks)?",
|
||||||
"다른 버전 고르기": "Choose another version",
|
"다른 버전 고르기": "Choose another version",
|
||||||
"다른 브라우저의 즐겨찾기 가져오기": "Import bookmarks from another browser",
|
"다른 브라우저의 즐겨찾기 가져오기": "Import bookmarks from another browser",
|
||||||
|
|
@ -396,6 +399,7 @@
|
||||||
"다시 만들기 대기로": "Back to waiting for remake",
|
"다시 만들기 대기로": "Back to waiting for remake",
|
||||||
"다시 설치": "Reinstall",
|
"다시 설치": "Reinstall",
|
||||||
"다시 세기": "Recount",
|
"다시 세기": "Recount",
|
||||||
|
"다시 시도": "Try again",
|
||||||
"다시 시작": "Restart",
|
"다시 시작": "Restart",
|
||||||
"다시 켤 때 동기화": "Sync on restart",
|
"다시 켤 때 동기화": "Sync on restart",
|
||||||
"다운로드": "Downloads",
|
"다운로드": "Downloads",
|
||||||
|
|
@ -641,6 +645,11 @@
|
||||||
"새로고침 (F5)": "Reload (F5)",
|
"새로고침 (F5)": "Reload (F5)",
|
||||||
"색 보정": "Color correction",
|
"색 보정": "Color correction",
|
||||||
"색온도": "Temperature",
|
"색온도": "Temperature",
|
||||||
|
"서버 설정 고치기": "Edit server settings",
|
||||||
|
"서버 인증서를 확인할 수 없습니다": "Cannot verify the server certificate",
|
||||||
|
"서버에 닿지 않습니다": "Cannot reach the server",
|
||||||
|
"서버에서 이 계정의 권한을 확인하세요.": "Check this account's permissions on the server.",
|
||||||
|
"서버와 같은 네트워크에 있거나 VPN (예: Tailscale) 이 켜져 있어야 합니다. 켠 뒤 [다시 시도] 를 누르세요.": "You need to be on the same network as the server or have a VPN (e.g. Tailscale) on. Turn it on, then tap [Try again].",
|
||||||
"선택": "Select",
|
"선택": "Select",
|
||||||
"선택 {0} / {1}개": "Selected {0} / {1}",
|
"선택 {0} / {1}개": "Selected {0} / {1}",
|
||||||
"선택 끝": "Done",
|
"선택 끝": "Done",
|
||||||
|
|
@ -731,6 +740,7 @@
|
||||||
"아래에 줄 추가": "Add line below",
|
"아래에 줄 추가": "Add line below",
|
||||||
"아이디": "User name",
|
"아이디": "User name",
|
||||||
"아이디 (선택)": "Username (optional)",
|
"아이디 (선택)": "Username (optional)",
|
||||||
|
"아이디 또는 비밀번호가 맞지 않습니다": "The user name or password is wrong",
|
||||||
"아이디·비밀번호는 환경 설정에서 넣을 수 있습니다 (선택, 하루 받기 횟수가 늘어남).": "You can enter the username · password in Settings (optional, raises the daily download limit).",
|
"아이디·비밀번호는 환경 설정에서 넣을 수 있습니다 (선택, 하루 받기 횟수가 늘어남).": "You can enter the username · password in Settings (optional, raises the daily download limit).",
|
||||||
"아이콘 · 목록 모양: X-plore (썸네일 · 두 줄) · Windows 탐색기 (컬러 아이콘 · 열) · Total Commander (촘촘한 목록 · [폴더])": "Icons · list look: X-plore (thumbnails · two lines) · Windows Explorer (color icons · columns) · Total Commander (dense list · [folders])",
|
"아이콘 · 목록 모양: X-plore (썸네일 · 두 줄) · Windows 탐색기 (컬러 아이콘 · 열) · Total Commander (촘촘한 목록 · [폴더])": "Icons · list look: X-plore (thumbnails · two lines) · Windows Explorer (color icons · columns) · Total Commander (dense list · [folders])",
|
||||||
"아직 만든 MKV · 자막이 없습니다: {0}": "No MKV · subtitles made yet: {0}",
|
"아직 만든 MKV · 자막이 없습니다: {0}": "No MKV · subtitles made yet: {0}",
|
||||||
|
|
@ -891,6 +901,8 @@
|
||||||
"이 폴더 선택": "Choose this folder",
|
"이 폴더 선택": "Choose this folder",
|
||||||
"이 폴더 전체": "This whole folder",
|
"이 폴더 전체": "This whole folder",
|
||||||
"이 폴더를 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 read this folder",
|
||||||
"이 폴더에 동영상이 없습니다.": "There are no videos in this folder.",
|
"이 폴더에 동영상이 없습니다.": "There are no videos in this folder.",
|
||||||
"이 폴더에 새 폴더": "New folder in this folder",
|
"이 폴더에 새 폴더": "New folder in this folder",
|
||||||
"이 폴더에 현재 페이지 추가": "Add the current page to this folder",
|
"이 폴더에 현재 페이지 추가": "Add the current page to this folder",
|
||||||
|
|
@ -942,6 +954,7 @@
|
||||||
"일반": "General",
|
"일반": "General",
|
||||||
"일본어": "Japanese",
|
"일본어": "Japanese",
|
||||||
"일시정지": "Pause",
|
"일시정지": "Pause",
|
||||||
|
"읽을 수 없습니다": "Cannot read",
|
||||||
"읽을 수 없음": "Cannot read",
|
"읽을 수 없음": "Cannot read",
|
||||||
"임시 파일 · 남은 조각 정리": "Clean temporary files · leftovers",
|
"임시 파일 · 남은 조각 정리": "Clean temporary files · leftovers",
|
||||||
"자동": "Auto",
|
"자동": "Auto",
|
||||||
|
|
@ -1096,6 +1109,7 @@
|
||||||
"지금 쓰는 버전: v{0}": "Current version: v{0}",
|
"지금 쓰는 버전: v{0}": "Current version: v{0}",
|
||||||
"지금 쓰는 버전: v{0} → 새 버전: v{1}": "Current version: v{0} → new version: v{1}",
|
"지금 쓰는 버전: v{0} → 새 버전: v{1}": "Current version: v{0} → new version: v{1}",
|
||||||
"지금: {0}": "Now: {0}",
|
"지금: {0}": "Now: {0}",
|
||||||
|
"지금은 듀얼 앱 (복제한 앱) 입니다. Android 가 듀얼 앱에는 이 권한을 주지 않을 수 있습니다. 허용 화면에서 켤 수 없으면 배지 없는 원래 JJ_MKVMaker 아이콘으로 여세요.": "This is the Dual App (cloned app). Android may not grant this permission to dual apps. If you can't turn it on, open the original JJ_MKVMaker icon without the badge.",
|
||||||
"지난 실행이 정상적으로 끝나지 않았습니다 (마지막 확인 {0}:{1}). 작업 기록에 남겨 두었습니다.": "The last run did not end normally (last check {0}:{1}). It has been noted in the job log.",
|
"지난 실행이 정상적으로 끝나지 않았습니다 (마지막 확인 {0}:{1}). 작업 기록에 남겨 두었습니다.": "The last run did not end normally (last check {0}:{1}). It has been noted in the job log.",
|
||||||
"지난 작업 기록": "Old job logs",
|
"지난 작업 기록": "Old job logs",
|
||||||
"지우기": "Delete",
|
"지우기": "Delete",
|
||||||
|
|
@ -1110,6 +1124,7 @@
|
||||||
"직접 지정": "Specify",
|
"직접 지정": "Specify",
|
||||||
"진행 중인 작업 없음": "No jobs in progress",
|
"진행 중인 작업 없음": "No jobs in progress",
|
||||||
"진행 중인 작업이 있습니다: {0}\n중지하고 끝낼까요?": "A job is in progress: {0}\nStop it and quit?",
|
"진행 중인 작업이 있습니다: {0}\n중지하고 끝낼까요?": "A job is in progress: {0}\nStop it and quit?",
|
||||||
|
"집 NAS 처럼 자체 서명 인증서면 [서버 설정 고치기] 에서 \"인증서 확인 안 함\" 을 켜세요.": "If it uses a self-signed certificate (like a home NAS), turn on \"Don't verify certificate\" in [Edit server settings].",
|
||||||
"창": "Panes",
|
"창": "Panes",
|
||||||
"창 · 작업 표시줄 · 트레이와 앱 안 왼쪽 위 버튼의 아이콘입니다 (실행 파일 · 바탕 화면 바로 가기 아이콘은 그대로)": "Icon of the window, taskbar, tray and the top-left button in the app (the program file and desktop shortcut icons stay the same)",
|
"창 · 작업 표시줄 · 트레이와 앱 안 왼쪽 위 버튼의 아이콘입니다 (실행 파일 · 바탕 화면 바로 가기 아이콘은 그대로)": "Icon of the window, taskbar, tray and the top-left button in the app (the program file and desktop shortcut icons stay the same)",
|
||||||
"창 배치": "Pane layout",
|
"창 배치": "Pane layout",
|
||||||
|
|
@ -1188,6 +1203,7 @@
|
||||||
"파일 확인 중…": "Checking files…",
|
"파일 확인 중…": "Checking files…",
|
||||||
"파일만 골랐을 때": "When only files are selected",
|
"파일만 골랐을 때": "When only files are selected",
|
||||||
"파일을 분석할 수 없습니다: {0}": "Cannot analyze the file: {0}",
|
"파일을 분석할 수 없습니다: {0}": "Cannot analyze the file: {0}",
|
||||||
|
"파일이 보이지 않습니다: \"모든 파일에 대한 접근\" 권한이 없습니다": "Files are not shown: \"All files access\" is not allowed",
|
||||||
"팝업 끄기": "Close pop-up",
|
"팝업 끄기": "Close pop-up",
|
||||||
"팝업 보기": "Pop-up view",
|
"팝업 보기": "Pop-up view",
|
||||||
"패키지 라이선스": "Package licenses",
|
"패키지 라이선스": "Package licenses",
|
||||||
|
|
@ -1217,6 +1233,8 @@
|
||||||
"폴더: {0}": "Folder: {0}",
|
"폴더: {0}": "Folder: {0}",
|
||||||
"폴더가 들어 있을 때": "When folders are included",
|
"폴더가 들어 있을 때": "When folders are included",
|
||||||
"폴더가 아닙니다: {0}": "Not a folder: {0}",
|
"폴더가 아닙니다: {0}": "Not a folder: {0}",
|
||||||
|
"폴더가 없습니다": "The folder does not exist",
|
||||||
|
"폴더는 보여도 그 안의 동영상 · 파일은 이 권한이 있어야 보입니다. 허용 화면에서 JJ_MKVMaker 를 켜고 돌아오세요.": "Folders are shown, but the videos and files inside need this permission. Turn on JJ_MKVMaker on the permission screen and come back.",
|
||||||
"폴더를 만들 수 없습니다: {0}": "Cannot create the folder: {0}",
|
"폴더를 만들 수 없습니다: {0}": "Cannot create the folder: {0}",
|
||||||
"폴더를 자기 자신 안으로 {0} 수 없습니다: {1}": "Cannot {0} a folder into itself: {1}",
|
"폴더를 자기 자신 안으로 {0} 수 없습니다: {1}": "Cannot {0} a folder into itself: {1}",
|
||||||
"폴더만 lsync 로 옮길 수 있습니다.": "Only folders can be moved to lsync.",
|
"폴더만 lsync 로 옮길 수 있습니다.": "Only folders can be moved to lsync.",
|
||||||
|
|
@ -1247,6 +1265,8 @@
|
||||||
"필수 프로그램이 모두 설치되어 있습니다.": "All required programs are installed.",
|
"필수 프로그램이 모두 설치되어 있습니다.": "All required programs are installed.",
|
||||||
"하위 폴더가 없습니다": "No subfolders",
|
"하위 폴더가 없습니다": "No subfolders",
|
||||||
"한 번: 바로 실행": "Single: open right away",
|
"한 번: 바로 실행": "Single: open right away",
|
||||||
|
"한 번: 바로 실행 (기본)": "Single tap: open (default)",
|
||||||
|
"한 번: 선택 · 두 번: 실행": "Single tap: select · double tap: open",
|
||||||
"한 번: 선택 · 두 번: 실행 (기본)": "Single: select · Double: open (default)",
|
"한 번: 선택 · 두 번: 실행 (기본)": "Single: select · Double: open (default)",
|
||||||
"한 번에": "All at once",
|
"한 번에": "All at once",
|
||||||
"한 쪽 맞추기": "Fit page",
|
"한 쪽 맞추기": "Fit page",
|
||||||
|
|
@ -1282,6 +1302,7 @@
|
||||||
"화면 작게": "Smaller",
|
"화면 작게": "Smaller",
|
||||||
"화면 크게": "Larger",
|
"화면 크게": "Larger",
|
||||||
"화면 크기": "Size",
|
"화면 크기": "Size",
|
||||||
|
"화면 크기 따라 (기본)": "By screen size (default)",
|
||||||
"화면이 있는 컴포넌트는 하나 이상 남아 있어야 합니다.": "At least one component with a screen must stay installed.",
|
"화면이 있는 컴포넌트는 하나 이상 남아 있어야 합니다.": "At least one component with a screen must stay installed.",
|
||||||
"화질": "Quality",
|
"화질": "Quality",
|
||||||
"확인": "OK",
|
"확인": "OK",
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,7 @@
|
||||||
"API 키": "API キー",
|
"API 키": "API キー",
|
||||||
"API 키 (필수, 무료)": "API キー(必須・無料)",
|
"API 키 (필수, 무료)": "API キー(必須・無料)",
|
||||||
"AV1 영상은 이 기기에서 다시 인코딩할 수 없습니다. 코덱을 \"원본 유지\" 로 바꿔 MKV 를 만드세요. (PC 판은 됩니다)": "AV1 動画はこの端末では再エンコードできません。コーデックを「元のまま」に変えて MKV を作成してください。(PC 版はできます)",
|
"AV1 영상은 이 기기에서 다시 인코딩할 수 없습니다. 코덱을 \"원본 유지\" 로 바꿔 MKV 를 만드세요. (PC 판은 됩니다)": "AV1 動画はこの端末では再エンコードできません。コーデックを「元のまま」に変えて MKV を作成してください。(PC 版はできます)",
|
||||||
|
"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 キー · パスワードは保存しないので再入力が必要です。",
|
||||||
"Android 설치 화면에서 [설치] 를 누르세요. 설정 · 받은 파일 · AI 모델은 그대로 남습니다.\n(처음이면 \"이 출처의 앱 설치 허용\" 을 켜야 할 수 있습니다)": "Android のインストール画面で[インストール]を押してください。設定・ダウンロードしたファイル・AI モデルはそのまま残ります。\n(初回は「この提供元のアプリを許可」をオンにする必要があるかもしれません)",
|
"Android 설치 화면에서 [설치] 를 누르세요. 설정 · 받은 파일 · AI 모델은 그대로 남습니다.\n(처음이면 \"이 출처의 앱 설치 허용\" 을 켜야 할 수 있습니다)": "Android のインストール画面で[インストール]を押してください。設定・ダウンロードしたファイル・AI モデルはそのまま残ります。\n(初回は「この提供元のアプリを許可」をオンにする必要があるかもしれません)",
|
||||||
|
|
@ -162,6 +163,7 @@
|
||||||
"ZIP · CBZ 를 만화로 보기": "ZIP・CBZ をマンガとして表示",
|
"ZIP · CBZ 를 만화로 보기": "ZIP・CBZ をマンガとして表示",
|
||||||
"ZIP 옆 새 폴더 \"{0}\" 로": "ZIP の隣の新しいフォルダー「{0}」へ",
|
"ZIP 옆 새 폴더 \"{0}\" 로": "ZIP の隣の新しいフォルダー「{0}」へ",
|
||||||
"ZIP 이 있는 폴더로": "ZIP のあるフォルダーへ",
|
"ZIP 이 있는 폴더로": "ZIP のあるフォルダーへ",
|
||||||
|
"[서버 설정 고치기] 에서 아이디 · 비밀번호를 확인하세요.": "[サーバー設定を修正] でユーザー名・パスワードを確認してください。",
|
||||||
"aria2 RPC 에 연결할 수 없습니다.": "aria2 RPC に接続できません。",
|
"aria2 RPC 에 연결할 수 없습니다.": "aria2 RPC に接続できません。",
|
||||||
"aria2 오류: {0}": "aria2 エラー: {0}",
|
"aria2 오류: {0}": "aria2 エラー: {0}",
|
||||||
"cookies.txt (Netscape 형식)": "cookies.txt(Netscape 形式)",
|
"cookies.txt (Netscape 형식)": "cookies.txt(Netscape 形式)",
|
||||||
|
|
@ -378,6 +380,7 @@
|
||||||
"누르면 일정 바꾸기": "タップで予定を変更",
|
"누르면 일정 바꾸기": "タップで予定を変更",
|
||||||
"다 받는 대로 MKV 만들기의 동영상 목록에 넣고, 다운로드 목록에서는 뺍니다 (다운로드 화면의 체크 상자와 같음)": "ダウンロードが終わり次第 MKV 作成の動画リストに入れ、ダウンロードリストからは外します(ダウンロード画面のチェックボックスと同じ)",
|
"다 받는 대로 MKV 만들기의 동영상 목록에 넣고, 다운로드 목록에서는 뺍니다 (다운로드 화면의 체크 상자와 같음)": "ダウンロードが終わり次第 MKV 作成の動画リストに入れ、ダウンロードリストからは外します(ダウンロード画面のチェックボックスと同じ)",
|
||||||
"다 받으면 MKV 만들기의 동영상 목록에 자동으로 넣고, 이 다운로드 목록에서는 뺍니다 (받은 파일은 그대로)": "ダウンロードが終わると MKV 作成の動画リストに自動で入れ、このダウンロードリストからは外します(ダウンロードしたファイルはそのまま)",
|
"다 받으면 MKV 만들기의 동영상 목록에 자동으로 넣고, 이 다운로드 목록에서는 뺍니다 (받은 파일은 그대로)": "ダウンロードが終わると MKV 作成の動画リストに自動で入れ、このダウンロードリストからは外します(ダウンロードしたファイルはそのまま)",
|
||||||
|
"다른 곳에서 지웠거나 옮겼을 수 있습니다. 위 폴더로 가 보세요.": "別の場所で削除・移動された可能性があります。上のフォルダーへ移動してみてください。",
|
||||||
"다른 버전 ({0}) 을 쓰다가 v{1} 로 돌아왔습니다. 그 버전은 이 버전의 설정 일부를 모를 수 있습니다.\nv{1} 를 마지막으로 쓸 때 보관해 둔 설정 (동영상 목록 · 즐겨찾기 포함) 으로 되돌릴까요?": "別のバージョン ({0}) を使ったあと v{1} に戻りました。そのバージョンはこのバージョンの設定の一部を知らない可能性があります。\nv{1} を最後に使ったときに保管した設定 (動画リスト · ブックマークを含む) に戻しますか?",
|
"다른 버전 ({0}) 을 쓰다가 v{1} 로 돌아왔습니다. 그 버전은 이 버전의 설정 일부를 모를 수 있습니다.\nv{1} 를 마지막으로 쓸 때 보관해 둔 설정 (동영상 목록 · 즐겨찾기 포함) 으로 되돌릴까요?": "別のバージョン ({0}) を使ったあと v{1} に戻りました。そのバージョンはこのバージョンの設定の一部を知らない可能性があります。\nv{1} を最後に使ったときに保管した設定 (動画リスト · ブックマークを含む) に戻しますか?",
|
||||||
"다른 버전 고르기": "別のバージョンを選ぶ",
|
"다른 버전 고르기": "別のバージョンを選ぶ",
|
||||||
"다른 브라우저의 즐겨찾기 가져오기": "他のブラウザーのブックマークを取り込む",
|
"다른 브라우저의 즐겨찾기 가져오기": "他のブラウザーのブックマークを取り込む",
|
||||||
|
|
@ -396,6 +399,7 @@
|
||||||
"다시 만들기 대기로": "作り直し待ちに戻す",
|
"다시 만들기 대기로": "作り直し待ちに戻す",
|
||||||
"다시 설치": "再インストール",
|
"다시 설치": "再インストール",
|
||||||
"다시 세기": "再カウント",
|
"다시 세기": "再カウント",
|
||||||
|
"다시 시도": "再試行",
|
||||||
"다시 시작": "再起動",
|
"다시 시작": "再起動",
|
||||||
"다시 켤 때 동기화": "再起動時の同期",
|
"다시 켤 때 동기화": "再起動時の同期",
|
||||||
"다운로드": "ダウンロード",
|
"다운로드": "ダウンロード",
|
||||||
|
|
@ -641,6 +645,11 @@
|
||||||
"새로고침 (F5)": "再読み込み(F5)",
|
"새로고침 (F5)": "再読み込み(F5)",
|
||||||
"색 보정": "カラー補正",
|
"색 보정": "カラー補正",
|
||||||
"색온도": "色温度",
|
"색온도": "色温度",
|
||||||
|
"서버 설정 고치기": "サーバー設定を修正",
|
||||||
|
"서버 인증서를 확인할 수 없습니다": "サーバー証明書を確認できません",
|
||||||
|
"서버에 닿지 않습니다": "サーバーに接続できません",
|
||||||
|
"서버에서 이 계정의 권한을 확인하세요.": "サーバーでこのアカウントの権限を確認してください。",
|
||||||
|
"서버와 같은 네트워크에 있거나 VPN (예: Tailscale) 이 켜져 있어야 합니다. 켠 뒤 [다시 시도] 를 누르세요.": "サーバーと同じネットワークにいるか、VPN (例: Tailscale) をオンにする必要があります。オンにしてから [再試行] を押してください。",
|
||||||
"선택": "選択",
|
"선택": "選択",
|
||||||
"선택 {0} / {1}개": "選択 {0} / {1}個",
|
"선택 {0} / {1}개": "選択 {0} / {1}個",
|
||||||
"선택 끝": "選択終了",
|
"선택 끝": "選択終了",
|
||||||
|
|
@ -731,6 +740,7 @@
|
||||||
"아래에 줄 추가": "下に行を追加",
|
"아래에 줄 추가": "下に行を追加",
|
||||||
"아이디": "ユーザー名",
|
"아이디": "ユーザー名",
|
||||||
"아이디 (선택)": "ユーザー名(任意)",
|
"아이디 (선택)": "ユーザー名(任意)",
|
||||||
|
"아이디 또는 비밀번호가 맞지 않습니다": "ユーザー名またはパスワードが正しくありません",
|
||||||
"아이디·비밀번호는 환경 설정에서 넣을 수 있습니다 (선택, 하루 받기 횟수가 늘어남).": "ユーザー名・パスワードは環境設定で入力できます(任意、1日のダウンロード回数が増えます)。",
|
"아이디·비밀번호는 환경 설정에서 넣을 수 있습니다 (선택, 하루 받기 횟수가 늘어남).": "ユーザー名・パスワードは環境設定で入力できます(任意、1日のダウンロード回数が増えます)。",
|
||||||
"아이콘 · 목록 모양: X-plore (썸네일 · 두 줄) · Windows 탐색기 (컬러 아이콘 · 열) · Total Commander (촘촘한 목록 · [폴더])": "アイコン · 一覧の見た目: X-plore (サムネイル · 2 行) · Windows エクスプローラー (カラーアイコン · 列) · Total Commander (詰めた一覧 · [フォルダー])",
|
"아이콘 · 목록 모양: X-plore (썸네일 · 두 줄) · Windows 탐색기 (컬러 아이콘 · 열) · Total Commander (촘촘한 목록 · [폴더])": "アイコン · 一覧の見た目: X-plore (サムネイル · 2 行) · Windows エクスプローラー (カラーアイコン · 列) · Total Commander (詰めた一覧 · [フォルダー])",
|
||||||
"아직 만든 MKV · 자막이 없습니다: {0}": "まだ作成した MKV・字幕がありません: {0}",
|
"아직 만든 MKV · 자막이 없습니다: {0}": "まだ作成した MKV・字幕がありません: {0}",
|
||||||
|
|
@ -891,6 +901,8 @@
|
||||||
"이 폴더 선택": "このフォルダーを選択",
|
"이 폴더 선택": "このフォルダーを選択",
|
||||||
"이 폴더 전체": "このフォルダー全体",
|
"이 폴더 전체": "このフォルダー全体",
|
||||||
"이 폴더를 rsync 원본 · 대상으로 고르기": "このフォルダーを rsync の元 · 対象に選ぶ",
|
"이 폴더를 rsync 원본 · 대상으로 고르기": "このフォルダーを rsync の元 · 対象に選ぶ",
|
||||||
|
"이 폴더를 볼 권한이 없습니다": "このフォルダーを表示する権限がありません",
|
||||||
|
"이 폴더를 읽을 권한이 없습니다": "このフォルダーを読む権限がありません",
|
||||||
"이 폴더에 동영상이 없습니다.": "このフォルダーに動画がありません。",
|
"이 폴더에 동영상이 없습니다.": "このフォルダーに動画がありません。",
|
||||||
"이 폴더에 새 폴더": "このフォルダーに新しいフォルダー",
|
"이 폴더에 새 폴더": "このフォルダーに新しいフォルダー",
|
||||||
"이 폴더에 현재 페이지 추가": "このフォルダーに現在のページを追加",
|
"이 폴더에 현재 페이지 추가": "このフォルダーに現在のページを追加",
|
||||||
|
|
@ -942,6 +954,7 @@
|
||||||
"일반": "一般",
|
"일반": "一般",
|
||||||
"일본어": "日本語",
|
"일본어": "日本語",
|
||||||
"일시정지": "一時停止",
|
"일시정지": "一時停止",
|
||||||
|
"읽을 수 없습니다": "読み込めません",
|
||||||
"읽을 수 없음": "読み取れません",
|
"읽을 수 없음": "読み取れません",
|
||||||
"임시 파일 · 남은 조각 정리": "一時ファイル・残った断片を整理",
|
"임시 파일 · 남은 조각 정리": "一時ファイル・残った断片を整理",
|
||||||
"자동": "自動",
|
"자동": "自動",
|
||||||
|
|
@ -1096,6 +1109,7 @@
|
||||||
"지금 쓰는 버전: v{0}": "使用中のバージョン: v{0}",
|
"지금 쓰는 버전: v{0}": "使用中のバージョン: v{0}",
|
||||||
"지금 쓰는 버전: v{0} → 새 버전: v{1}": "現在のバージョン: v{0} → 新しいバージョン: v{1}",
|
"지금 쓰는 버전: v{0} → 새 버전: v{1}": "現在のバージョン: v{0} → 新しいバージョン: v{1}",
|
||||||
"지금: {0}": "現在: {0}",
|
"지금: {0}": "現在: {0}",
|
||||||
|
"지금은 듀얼 앱 (복제한 앱) 입니다. Android 가 듀얼 앱에는 이 권한을 주지 않을 수 있습니다. 허용 화면에서 켤 수 없으면 배지 없는 원래 JJ_MKVMaker 아이콘으로 여세요.": "これはデュアルアプリ (複製したアプリ) です。Android はデュアルアプリにこの権限を与えない場合があります。許可画面でオンにできない場合は、バッジのない元の JJ_MKVMaker アイコンから開いてください。",
|
||||||
"지난 실행이 정상적으로 끝나지 않았습니다 (마지막 확인 {0}:{1}). 작업 기록에 남겨 두었습니다.": "前回の実行が正常に終了しませんでした(最終確認 {0}:{1})。作業記録に残しました。",
|
"지난 실행이 정상적으로 끝나지 않았습니다 (마지막 확인 {0}:{1}). 작업 기록에 남겨 두었습니다.": "前回の実行が正常に終了しませんでした(最終確認 {0}:{1})。作業記録に残しました。",
|
||||||
"지난 작업 기록": "過去の作業記録",
|
"지난 작업 기록": "過去の作業記録",
|
||||||
"지우기": "削除",
|
"지우기": "削除",
|
||||||
|
|
@ -1110,6 +1124,7 @@
|
||||||
"직접 지정": "直接指定",
|
"직접 지정": "直接指定",
|
||||||
"진행 중인 작업 없음": "進行中の作業なし",
|
"진행 중인 작업 없음": "進行中の作業なし",
|
||||||
"진행 중인 작업이 있습니다: {0}\n중지하고 끝낼까요?": "進行中の作業があります: {0}\n中止して終了しますか?",
|
"진행 중인 작업이 있습니다: {0}\n중지하고 끝낼까요?": "進行中の作業があります: {0}\n中止して終了しますか?",
|
||||||
|
"집 NAS 처럼 자체 서명 인증서면 [서버 설정 고치기] 에서 \"인증서 확인 안 함\" 을 켜세요.": "自宅 NAS のように自己署名証明書なら、[サーバー設定を修正] で「証明書を検証しない」をオンにしてください。",
|
||||||
"창": "ペイン",
|
"창": "ペイン",
|
||||||
"창 · 작업 표시줄 · 트레이와 앱 안 왼쪽 위 버튼의 아이콘입니다 (실행 파일 · 바탕 화면 바로 가기 아이콘은 그대로)": "ウィンドウ・タスクバー・トレイとアプリ内左上のボタンのアイコンです(実行ファイル・デスクトップのショートカットのアイコンはそのまま)",
|
"창 · 작업 표시줄 · 트레이와 앱 안 왼쪽 위 버튼의 아이콘입니다 (실행 파일 · 바탕 화면 바로 가기 아이콘은 그대로)": "ウィンドウ・タスクバー・トレイとアプリ内左上のボタンのアイコンです(実行ファイル・デスクトップのショートカットのアイコンはそのまま)",
|
||||||
"창 배치": "ペインの配置",
|
"창 배치": "ペインの配置",
|
||||||
|
|
@ -1188,6 +1203,7 @@
|
||||||
"파일 확인 중…": "ファイルを確認中…",
|
"파일 확인 중…": "ファイルを確認中…",
|
||||||
"파일만 골랐을 때": "ファイルだけを選んだとき",
|
"파일만 골랐을 때": "ファイルだけを選んだとき",
|
||||||
"파일을 분석할 수 없습니다: {0}": "ファイルを分析できません: {0}",
|
"파일을 분석할 수 없습니다: {0}": "ファイルを分析できません: {0}",
|
||||||
|
"파일이 보이지 않습니다: \"모든 파일에 대한 접근\" 권한이 없습니다": "ファイルが表示されません: 「すべてのファイルへのアクセス」権限がありません",
|
||||||
"팝업 끄기": "ポップアップを閉じる",
|
"팝업 끄기": "ポップアップを閉じる",
|
||||||
"팝업 보기": "ポップアップ表示",
|
"팝업 보기": "ポップアップ表示",
|
||||||
"패키지 라이선스": "パッケージのライセンス",
|
"패키지 라이선스": "パッケージのライセンス",
|
||||||
|
|
@ -1217,6 +1233,8 @@
|
||||||
"폴더: {0}": "フォルダー: {0}",
|
"폴더: {0}": "フォルダー: {0}",
|
||||||
"폴더가 들어 있을 때": "フォルダーを含むとき",
|
"폴더가 들어 있을 때": "フォルダーを含むとき",
|
||||||
"폴더가 아닙니다: {0}": "フォルダーではありません: {0}",
|
"폴더가 아닙니다: {0}": "フォルダーではありません: {0}",
|
||||||
|
"폴더가 없습니다": "フォルダーがありません",
|
||||||
|
"폴더는 보여도 그 안의 동영상 · 파일은 이 권한이 있어야 보입니다. 허용 화면에서 JJ_MKVMaker 를 켜고 돌아오세요.": "フォルダーは見えても、中の動画・ファイルはこの権限が必要です。許可画面で JJ_MKVMaker をオンにして戻ってください。",
|
||||||
"폴더를 만들 수 없습니다: {0}": "フォルダーを作成できません: {0}",
|
"폴더를 만들 수 없습니다: {0}": "フォルダーを作成できません: {0}",
|
||||||
"폴더를 자기 자신 안으로 {0} 수 없습니다: {1}": "フォルダーを自分自身の中へ{0}ことはできません: {1}",
|
"폴더를 자기 자신 안으로 {0} 수 없습니다: {1}": "フォルダーを自分自身の中へ{0}ことはできません: {1}",
|
||||||
"폴더만 lsync 로 옮길 수 있습니다.": "lsync へ移せるのはフォルダーだけです。",
|
"폴더만 lsync 로 옮길 수 있습니다.": "lsync へ移せるのはフォルダーだけです。",
|
||||||
|
|
@ -1247,6 +1265,8 @@
|
||||||
"필수 프로그램이 모두 설치되어 있습니다.": "必須プログラムはすべてインストールされています。",
|
"필수 프로그램이 모두 설치되어 있습니다.": "必須プログラムはすべてインストールされています。",
|
||||||
"하위 폴더가 없습니다": "サブフォルダーがありません",
|
"하위 폴더가 없습니다": "サブフォルダーがありません",
|
||||||
"한 번: 바로 실행": "1 回: すぐに開く",
|
"한 번: 바로 실행": "1 回: すぐに開く",
|
||||||
|
"한 번: 바로 실행 (기본)": "1 回: すぐに開く (既定)",
|
||||||
|
"한 번: 선택 · 두 번: 실행": "1 回: 選択・2 回: 開く",
|
||||||
"한 번: 선택 · 두 번: 실행 (기본)": "1 回: 選択 · 2 回: 開く (既定)",
|
"한 번: 선택 · 두 번: 실행 (기본)": "1 回: 選択 · 2 回: 開く (既定)",
|
||||||
"한 번에": "まとめて 1 回",
|
"한 번에": "まとめて 1 回",
|
||||||
"한 쪽 맞추기": "1 ページに合わせる",
|
"한 쪽 맞추기": "1 ページに合わせる",
|
||||||
|
|
@ -1282,6 +1302,7 @@
|
||||||
"화면 작게": "画面を小さく",
|
"화면 작게": "画面を小さく",
|
||||||
"화면 크게": "画面を大きく",
|
"화면 크게": "画面を大きく",
|
||||||
"화면 크기": "画面サイズ",
|
"화면 크기": "画面サイズ",
|
||||||
|
"화면 크기 따라 (기본)": "画面サイズに合わせる (既定)",
|
||||||
"화면이 있는 컴포넌트는 하나 이상 남아 있어야 합니다.": "画面のあるコンポーネントを少なくとも1つ残す必要があります。",
|
"화면이 있는 컴포넌트는 하나 이상 남아 있어야 합니다.": "画面のあるコンポーネントを少なくとも1つ残す必要があります。",
|
||||||
"화질": "画質",
|
"화질": "画質",
|
||||||
"확인": "OK",
|
"확인": "OK",
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,7 @@
|
||||||
"API 키": "API 密钥",
|
"API 키": "API 密钥",
|
||||||
"API 키 (필수, 무료)": "API 密钥(必填,免费)",
|
"API 키 (필수, 무료)": "API 密钥(必填,免费)",
|
||||||
"AV1 영상은 이 기기에서 다시 인코딩할 수 없습니다. 코덱을 \"원본 유지\" 로 바꿔 MKV 를 만드세요. (PC 판은 됩니다)": "此设备无法重新编码 AV1 视频。请将编解码器改为“保持原样”后制作 MKV。(PC 版可以)",
|
"AV1 영상은 이 기기에서 다시 인코딩할 수 없습니다. 코덱을 \"원본 유지\" 로 바꿔 MKV 를 만드세요. (PC 판은 됩니다)": "此设备无法重新编码 AV1 视频。请将编解码器改为“保持原样”后制作 MKV。(PC 版可以)",
|
||||||
|
"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 密钥 · 密码不会保存,需要重新输入。",
|
||||||
"Android 설치 화면에서 [설치] 를 누르세요. 설정 · 받은 파일 · AI 모델은 그대로 남습니다.\n(처음이면 \"이 출처의 앱 설치 허용\" 을 켜야 할 수 있습니다)": "请在 Android 安装界面点击[安装]。设置、已下载的文件和 AI 模型都会保留。\n(首次可能需要开启“允许安装此来源的应用”)",
|
"Android 설치 화면에서 [설치] 를 누르세요. 설정 · 받은 파일 · AI 모델은 그대로 남습니다.\n(처음이면 \"이 출처의 앱 설치 허용\" 을 켜야 할 수 있습니다)": "请在 Android 安装界面点击[安装]。设置、已下载的文件和 AI 模型都会保留。\n(首次可能需要开启“允许安装此来源的应用”)",
|
||||||
|
|
@ -162,6 +163,7 @@
|
||||||
"ZIP · CBZ 를 만화로 보기": "将 ZIP · CBZ 作为漫画阅读",
|
"ZIP · CBZ 를 만화로 보기": "将 ZIP · CBZ 作为漫画阅读",
|
||||||
"ZIP 옆 새 폴더 \"{0}\" 로": "到 ZIP 旁的新文件夹“{0}”",
|
"ZIP 옆 새 폴더 \"{0}\" 로": "到 ZIP 旁的新文件夹“{0}”",
|
||||||
"ZIP 이 있는 폴더로": "到 ZIP 所在文件夹",
|
"ZIP 이 있는 폴더로": "到 ZIP 所在文件夹",
|
||||||
|
"[서버 설정 고치기] 에서 아이디 · 비밀번호를 확인하세요.": "请在 [修改服务器设置] 中检查用户名和密码。",
|
||||||
"aria2 RPC 에 연결할 수 없습니다.": "无法连接到 aria2 RPC。",
|
"aria2 RPC 에 연결할 수 없습니다.": "无法连接到 aria2 RPC。",
|
||||||
"aria2 오류: {0}": "aria2 错误: {0}",
|
"aria2 오류: {0}": "aria2 错误: {0}",
|
||||||
"cookies.txt (Netscape 형식)": "cookies.txt(Netscape 格式)",
|
"cookies.txt (Netscape 형식)": "cookies.txt(Netscape 格式)",
|
||||||
|
|
@ -378,6 +380,7 @@
|
||||||
"누르면 일정 바꾸기": "点按以更改计划",
|
"누르면 일정 바꾸기": "点按以更改计划",
|
||||||
"다 받는 대로 MKV 만들기의 동영상 목록에 넣고, 다운로드 목록에서는 뺍니다 (다운로드 화면의 체크 상자와 같음)": "下载完成后立即放入制作 MKV 的视频列表,并从下载列表移除(与下载界面的复选框相同)",
|
"다 받는 대로 MKV 만들기의 동영상 목록에 넣고, 다운로드 목록에서는 뺍니다 (다운로드 화면의 체크 상자와 같음)": "下载完成后立即放入制作 MKV 的视频列表,并从下载列表移除(与下载界面的复选框相同)",
|
||||||
"다 받으면 MKV 만들기의 동영상 목록에 자동으로 넣고, 이 다운로드 목록에서는 뺍니다 (받은 파일은 그대로)": "下载完成后自动加入制作 MKV 的视频列表,并从此下载列表移除(已下载的文件保留)",
|
"다 받으면 MKV 만들기의 동영상 목록에 자동으로 넣고, 이 다운로드 목록에서는 뺍니다 (받은 파일은 그대로)": "下载完成后自动加入制作 MKV 的视频列表,并从此下载列表移除(已下载的文件保留)",
|
||||||
|
"다른 곳에서 지웠거나 옮겼을 수 있습니다. 위 폴더로 가 보세요.": "可能已在别处被删除或移动。请返回上级文件夹。",
|
||||||
"다른 버전 ({0}) 을 쓰다가 v{1} 로 돌아왔습니다. 그 버전은 이 버전의 설정 일부를 모를 수 있습니다.\nv{1} 를 마지막으로 쓸 때 보관해 둔 설정 (동영상 목록 · 즐겨찾기 포함) 으로 되돌릴까요?": "使用其他版本 ({0}) 后回到了 v{1}。该版本可能不认识此版本的部分设置。\n要恢复最后一次使用 v{1} 时保存的设置 (包括视频列表 · 书签) 吗?",
|
"다른 버전 ({0}) 을 쓰다가 v{1} 로 돌아왔습니다. 그 버전은 이 버전의 설정 일부를 모를 수 있습니다.\nv{1} 를 마지막으로 쓸 때 보관해 둔 설정 (동영상 목록 · 즐겨찾기 포함) 으로 되돌릴까요?": "使用其他版本 ({0}) 后回到了 v{1}。该版本可能不认识此版本的部分设置。\n要恢复最后一次使用 v{1} 时保存的设置 (包括视频列表 · 书签) 吗?",
|
||||||
"다른 버전 고르기": "选择其他版本",
|
"다른 버전 고르기": "选择其他版本",
|
||||||
"다른 브라우저의 즐겨찾기 가져오기": "导入其他浏览器的书签",
|
"다른 브라우저의 즐겨찾기 가져오기": "导入其他浏览器的书签",
|
||||||
|
|
@ -396,6 +399,7 @@
|
||||||
"다시 만들기 대기로": "改回等待重新制作",
|
"다시 만들기 대기로": "改回等待重新制作",
|
||||||
"다시 설치": "重新安装",
|
"다시 설치": "重新安装",
|
||||||
"다시 세기": "重新统计",
|
"다시 세기": "重新统计",
|
||||||
|
"다시 시도": "重试",
|
||||||
"다시 시작": "重新启动",
|
"다시 시작": "重新启动",
|
||||||
"다시 켤 때 동기화": "重新启动时同步",
|
"다시 켤 때 동기화": "重新启动时同步",
|
||||||
"다운로드": "下载",
|
"다운로드": "下载",
|
||||||
|
|
@ -641,6 +645,11 @@
|
||||||
"새로고침 (F5)": "刷新(F5)",
|
"새로고침 (F5)": "刷新(F5)",
|
||||||
"색 보정": "色彩校正",
|
"색 보정": "色彩校正",
|
||||||
"색온도": "色温",
|
"색온도": "色温",
|
||||||
|
"서버 설정 고치기": "修改服务器设置",
|
||||||
|
"서버 인증서를 확인할 수 없습니다": "无法验证服务器证书",
|
||||||
|
"서버에 닿지 않습니다": "无法连接服务器",
|
||||||
|
"서버에서 이 계정의 권한을 확인하세요.": "请在服务器上检查此账户的权限。",
|
||||||
|
"서버와 같은 네트워크에 있거나 VPN (예: Tailscale) 이 켜져 있어야 합니다. 켠 뒤 [다시 시도] 를 누르세요.": "需要与服务器在同一网络,或打开 VPN (如 Tailscale)。打开后点 [重试]。",
|
||||||
"선택": "选择",
|
"선택": "选择",
|
||||||
"선택 {0} / {1}개": "已选 {0} / {1} 个",
|
"선택 {0} / {1}개": "已选 {0} / {1} 个",
|
||||||
"선택 끝": "完成选择",
|
"선택 끝": "完成选择",
|
||||||
|
|
@ -731,6 +740,7 @@
|
||||||
"아래에 줄 추가": "在下方添加一行",
|
"아래에 줄 추가": "在下方添加一行",
|
||||||
"아이디": "用户名",
|
"아이디": "用户名",
|
||||||
"아이디 (선택)": "用户名(可选)",
|
"아이디 (선택)": "用户名(可选)",
|
||||||
|
"아이디 또는 비밀번호가 맞지 않습니다": "用户名或密码错误",
|
||||||
"아이디·비밀번호는 환경 설정에서 넣을 수 있습니다 (선택, 하루 받기 횟수가 늘어남).": "可在设置中填写用户名 · 密码(可选,可增加每日下载次数)。",
|
"아이디·비밀번호는 환경 설정에서 넣을 수 있습니다 (선택, 하루 받기 횟수가 늘어남).": "可在设置中填写用户名 · 密码(可选,可增加每日下载次数)。",
|
||||||
"아이콘 · 목록 모양: X-plore (썸네일 · 두 줄) · Windows 탐색기 (컬러 아이콘 · 열) · Total Commander (촘촘한 목록 · [폴더])": "图标 · 列表外观: X-plore (缩略图 · 两行) · Windows 资源管理器 (彩色图标 · 列) · Total Commander (紧凑列表 · [文件夹])",
|
"아이콘 · 목록 모양: X-plore (썸네일 · 두 줄) · Windows 탐색기 (컬러 아이콘 · 열) · Total Commander (촘촘한 목록 · [폴더])": "图标 · 列表外观: X-plore (缩略图 · 两行) · Windows 资源管理器 (彩色图标 · 列) · Total Commander (紧凑列表 · [文件夹])",
|
||||||
"아직 만든 MKV · 자막이 없습니다: {0}": "尚未制作 MKV · 字幕: {0}",
|
"아직 만든 MKV · 자막이 없습니다: {0}": "尚未制作 MKV · 字幕: {0}",
|
||||||
|
|
@ -891,6 +901,8 @@
|
||||||
"이 폴더 선택": "选择此文件夹",
|
"이 폴더 선택": "选择此文件夹",
|
||||||
"이 폴더 전체": "整个文件夹",
|
"이 폴더 전체": "整个文件夹",
|
||||||
"이 폴더를 rsync 원본 · 대상으로 고르기": "选择此文件夹作为 rsync 源 · 目标",
|
"이 폴더를 rsync 원본 · 대상으로 고르기": "选择此文件夹作为 rsync 源 · 目标",
|
||||||
|
"이 폴더를 볼 권한이 없습니다": "没有查看此文件夹的权限",
|
||||||
|
"이 폴더를 읽을 권한이 없습니다": "没有读取此文件夹的权限",
|
||||||
"이 폴더에 동영상이 없습니다.": "此文件夹中没有视频。",
|
"이 폴더에 동영상이 없습니다.": "此文件夹中没有视频。",
|
||||||
"이 폴더에 새 폴더": "在此文件夹中新建文件夹",
|
"이 폴더에 새 폴더": "在此文件夹中新建文件夹",
|
||||||
"이 폴더에 현재 페이지 추가": "将当前页面添加到此文件夹",
|
"이 폴더에 현재 페이지 추가": "将当前页面添加到此文件夹",
|
||||||
|
|
@ -942,6 +954,7 @@
|
||||||
"일반": "常规",
|
"일반": "常规",
|
||||||
"일본어": "日语",
|
"일본어": "日语",
|
||||||
"일시정지": "暂停",
|
"일시정지": "暂停",
|
||||||
|
"읽을 수 없습니다": "无法读取",
|
||||||
"읽을 수 없음": "无法读取",
|
"읽을 수 없음": "无法读取",
|
||||||
"임시 파일 · 남은 조각 정리": "清理临时文件 · 残留碎片",
|
"임시 파일 · 남은 조각 정리": "清理临时文件 · 残留碎片",
|
||||||
"자동": "自动",
|
"자동": "自动",
|
||||||
|
|
@ -1096,6 +1109,7 @@
|
||||||
"지금 쓰는 버전: v{0}": "当前版本: v{0}",
|
"지금 쓰는 버전: v{0}": "当前版本: v{0}",
|
||||||
"지금 쓰는 버전: v{0} → 새 버전: v{1}": "当前版本: v{0} → 新版本: v{1}",
|
"지금 쓰는 버전: v{0} → 새 버전: v{1}": "当前版本: v{0} → 新版本: v{1}",
|
||||||
"지금: {0}": "当前: {0}",
|
"지금: {0}": "当前: {0}",
|
||||||
|
"지금은 듀얼 앱 (복제한 앱) 입니다. Android 가 듀얼 앱에는 이 권한을 주지 않을 수 있습니다. 허용 화면에서 켤 수 없으면 배지 없는 원래 JJ_MKVMaker 아이콘으로 여세요.": "当前是双开应用 (复制的应用)。Android 可能不会给双开应用此权限。如果无法开启,请从没有徽标的原 JJ_MKVMaker 图标打开。",
|
||||||
"지난 실행이 정상적으로 끝나지 않았습니다 (마지막 확인 {0}:{1}). 작업 기록에 남겨 두었습니다.": "上次运行未正常结束(最后检查 {0}:{1})。已记录在任务记录中。",
|
"지난 실행이 정상적으로 끝나지 않았습니다 (마지막 확인 {0}:{1}). 작업 기록에 남겨 두었습니다.": "上次运行未正常结束(最后检查 {0}:{1})。已记录在任务记录中。",
|
||||||
"지난 작업 기록": "旧任务记录",
|
"지난 작업 기록": "旧任务记录",
|
||||||
"지우기": "删除",
|
"지우기": "删除",
|
||||||
|
|
@ -1110,6 +1124,7 @@
|
||||||
"직접 지정": "手动指定",
|
"직접 지정": "手动指定",
|
||||||
"진행 중인 작업 없음": "没有进行中的任务",
|
"진행 중인 작업 없음": "没有进行中的任务",
|
||||||
"진행 중인 작업이 있습니다: {0}\n중지하고 끝낼까요?": "有正在进行的任务: {0}\n要停止并退出吗?",
|
"진행 중인 작업이 있습니다: {0}\n중지하고 끝낼까요?": "有正在进行的任务: {0}\n要停止并退出吗?",
|
||||||
|
"집 NAS 처럼 자체 서명 인증서면 [서버 설정 고치기] 에서 \"인증서 확인 안 함\" 을 켜세요.": "如果是自签名证书 (如家用 NAS),请在 [修改服务器设置] 中开启“不验证证书”。",
|
||||||
"창": "窗格",
|
"창": "窗格",
|
||||||
"창 · 작업 표시줄 · 트레이와 앱 안 왼쪽 위 버튼의 아이콘입니다 (실행 파일 · 바탕 화면 바로 가기 아이콘은 그대로)": "窗口、任务栏、托盘以及应用内左上角按钮的图标(程序文件和桌面快捷方式的图标不变)",
|
"창 · 작업 표시줄 · 트레이와 앱 안 왼쪽 위 버튼의 아이콘입니다 (실행 파일 · 바탕 화면 바로 가기 아이콘은 그대로)": "窗口、任务栏、托盘以及应用内左上角按钮的图标(程序文件和桌面快捷方式的图标不变)",
|
||||||
"창 배치": "窗格布局",
|
"창 배치": "窗格布局",
|
||||||
|
|
@ -1188,6 +1203,7 @@
|
||||||
"파일 확인 중…": "正在检查文件…",
|
"파일 확인 중…": "正在检查文件…",
|
||||||
"파일만 골랐을 때": "只选择文件时",
|
"파일만 골랐을 때": "只选择文件时",
|
||||||
"파일을 분석할 수 없습니다: {0}": "无法分析文件: {0}",
|
"파일을 분석할 수 없습니다: {0}": "无法分析文件: {0}",
|
||||||
|
"파일이 보이지 않습니다: \"모든 파일에 대한 접근\" 권한이 없습니다": "文件不可见: 没有“所有文件访问”权限",
|
||||||
"팝업 끄기": "关闭弹出窗口",
|
"팝업 끄기": "关闭弹出窗口",
|
||||||
"팝업 보기": "弹出窗口观看",
|
"팝업 보기": "弹出窗口观看",
|
||||||
"패키지 라이선스": "软件包许可",
|
"패키지 라이선스": "软件包许可",
|
||||||
|
|
@ -1217,6 +1233,8 @@
|
||||||
"폴더: {0}": "文件夹: {0}",
|
"폴더: {0}": "文件夹: {0}",
|
||||||
"폴더가 들어 있을 때": "包含文件夹时",
|
"폴더가 들어 있을 때": "包含文件夹时",
|
||||||
"폴더가 아닙니다: {0}": "不是文件夹: {0}",
|
"폴더가 아닙니다: {0}": "不是文件夹: {0}",
|
||||||
|
"폴더가 없습니다": "文件夹不存在",
|
||||||
|
"폴더는 보여도 그 안의 동영상 · 파일은 이 권한이 있어야 보입니다. 허용 화면에서 JJ_MKVMaker 를 켜고 돌아오세요.": "虽然能看到文件夹,但其中的视频和文件需要此权限。请在权限界面开启 JJ_MKVMaker 后返回。",
|
||||||
"폴더를 만들 수 없습니다: {0}": "无法创建文件夹: {0}",
|
"폴더를 만들 수 없습니다: {0}": "无法创建文件夹: {0}",
|
||||||
"폴더를 자기 자신 안으로 {0} 수 없습니다: {1}": "不能将文件夹{0}到其自身内部: {1}",
|
"폴더를 자기 자신 안으로 {0} 수 없습니다: {1}": "不能将文件夹{0}到其自身内部: {1}",
|
||||||
"폴더만 lsync 로 옮길 수 있습니다.": "只有文件夹可以移到 lsync。",
|
"폴더만 lsync 로 옮길 수 있습니다.": "只有文件夹可以移到 lsync。",
|
||||||
|
|
@ -1247,6 +1265,8 @@
|
||||||
"필수 프로그램이 모두 설치되어 있습니다.": "所有必需程序均已安装。",
|
"필수 프로그램이 모두 설치되어 있습니다.": "所有必需程序均已安装。",
|
||||||
"하위 폴더가 없습니다": "没有子文件夹",
|
"하위 폴더가 없습니다": "没有子文件夹",
|
||||||
"한 번: 바로 실행": "单击: 立即打开",
|
"한 번: 바로 실행": "单击: 立即打开",
|
||||||
|
"한 번: 바로 실행 (기본)": "单击: 直接打开 (默认)",
|
||||||
|
"한 번: 선택 · 두 번: 실행": "单击: 选择 · 双击: 打开",
|
||||||
"한 번: 선택 · 두 번: 실행 (기본)": "单击: 选择 · 双击: 打开 (默认)",
|
"한 번: 선택 · 두 번: 실행 (기본)": "单击: 选择 · 双击: 打开 (默认)",
|
||||||
"한 번에": "一次执行",
|
"한 번에": "一次执行",
|
||||||
"한 쪽 맞추기": "适应整页",
|
"한 쪽 맞추기": "适应整页",
|
||||||
|
|
@ -1282,6 +1302,7 @@
|
||||||
"화면 작게": "缩小界面",
|
"화면 작게": "缩小界面",
|
||||||
"화면 크게": "放大界面",
|
"화면 크게": "放大界面",
|
||||||
"화면 크기": "画面大小",
|
"화면 크기": "画面大小",
|
||||||
|
"화면 크기 따라 (기본)": "按屏幕大小 (默认)",
|
||||||
"화면이 있는 컴포넌트는 하나 이상 남아 있어야 합니다.": "至少要保留一个带界面的组件。",
|
"화면이 있는 컴포넌트는 하나 이상 남아 있어야 합니다.": "至少要保留一个带界面的组件。",
|
||||||
"화질": "画质",
|
"화질": "画质",
|
||||||
"확인": "确定",
|
"확인": "确定",
|
||||||
|
|
|
||||||
|
|
@ -285,11 +285,11 @@ class AppSettings {
|
||||||
|
|
||||||
// ── 파일 탐색기 (X-plore 참고) ──
|
// ── 파일 탐색기 (X-plore 참고) ──
|
||||||
/// 창: 'dual' 두 창 (기본) · 'split' 왼쪽 폴더 트리 + 오른쪽 그 폴더의 파일 목록 · 'single' 한 창
|
/// 창: 'dual' 두 창 (기본) · 'split' 왼쪽 폴더 트리 + 오른쪽 그 폴더의 파일 목록 · 'single' 한 창
|
||||||
String explorerLayout = 'dual';
|
String explorerLayout = 'auto';
|
||||||
|
|
||||||
/// 누르기: 'select' 한 번 = 선택 · 두 번 = 열기 (기본) / 'open' 한 번 = 바로 열기.
|
/// 누르기: 'select' 한 번 = 선택 · 두 번 = 열기 (기본) / 'open' 한 번 = 바로 열기.
|
||||||
/// 길게 누르기 · 오른쪽 클릭은 늘 기능 메뉴.
|
/// 길게 누르기 · 오른쪽 클릭은 늘 기능 메뉴.
|
||||||
String explorerClick = 'select';
|
String explorerClick = Platform.isAndroid ? 'open' : 'select';
|
||||||
|
|
||||||
/// 모양: 'xplore' (기본) · 'windows' Windows 탐색기 · 'totalcmd' Total Commander
|
/// 모양: 'xplore' (기본) · 'windows' Windows 탐색기 · 'totalcmd' Total Commander
|
||||||
String explorerStyle = 'xplore';
|
String explorerStyle = 'xplore';
|
||||||
|
|
@ -356,8 +356,8 @@ class AppSettings {
|
||||||
/// 보기: 밝기 (-0.7 어둡게 ~ 0.7 밝게)
|
/// 보기: 밝기 (-0.7 어둡게 ~ 0.7 밝게)
|
||||||
double readerBrightness = 0;
|
double readerBrightness = 0;
|
||||||
|
|
||||||
/// ZIP · CBZ 를 두 번 누르면 안의 그림을 만화처럼 보기 (끄면 목록)
|
/// ZIP · CBZ 를 두 번 누르면 안의 그림을 만화처럼 보기 (끄면 목록). 기본은 목록 (사용자 지시)
|
||||||
bool zipComic = true;
|
bool zipComic = false;
|
||||||
|
|
||||||
/// WebDAV 서버 (파일 탐색기 · Rsync 화면 위쪽 "SD 카드" 옆 탭). 비밀번호는 이 설정 파일에만.
|
/// WebDAV 서버 (파일 탐색기 · Rsync 화면 위쪽 "SD 카드" 옆 탭). 비밀번호는 이 설정 파일에만.
|
||||||
List<DavServer> webdavServers = [];
|
List<DavServer> webdavServers = [];
|
||||||
|
|
@ -462,6 +462,8 @@ class AppSettings {
|
||||||
'webJavaScript': webJavaScript,
|
'webJavaScript': webJavaScript,
|
||||||
'explorerLayout': explorerLayout,
|
'explorerLayout': explorerLayout,
|
||||||
'explorerClick': explorerClick,
|
'explorerClick': explorerClick,
|
||||||
|
// 예전 기본값 (두 창 · 한 번 누르면 선택) 은 사용자가 고른 값이 아니므로 한 번 새 기본값으로 옮긴다
|
||||||
|
'explorerV2': true,
|
||||||
'explorerStyle': explorerStyle,
|
'explorerStyle': explorerStyle,
|
||||||
'explorerOrientation': explorerOrientation,
|
'explorerOrientation': explorerOrientation,
|
||||||
'explorerToolbar': explorerToolbar,
|
'explorerToolbar': explorerToolbar,
|
||||||
|
|
@ -481,6 +483,8 @@ class AppSettings {
|
||||||
'readerRtl': readerRtl,
|
'readerRtl': readerRtl,
|
||||||
'readerBrightness': readerBrightness,
|
'readerBrightness': readerBrightness,
|
||||||
'zipComic': zipComic,
|
'zipComic': zipComic,
|
||||||
|
// 예전 기본값 (만화 보기 켜짐) 은 지시와 반대였으므로 한 번 꺼진 상태 (목록) 로
|
||||||
|
'zipComicV2': true,
|
||||||
'webdavServers': [for (final x in webdavServers) x.toJson()],
|
'webdavServers': [for (final x in webdavServers) x.toJson()],
|
||||||
'rsyncOptions': rsyncOptions,
|
'rsyncOptions': rsyncOptions,
|
||||||
'robocopyOptions': robocopyOptions,
|
'robocopyOptions': robocopyOptions,
|
||||||
|
|
@ -572,8 +576,18 @@ class AppSettings {
|
||||||
..externalBrowser = j['externalBrowser'] as String? ?? 'system'
|
..externalBrowser = j['externalBrowser'] as String? ?? 'system'
|
||||||
..webTranslate = j['webTranslate'] as bool? ?? false
|
..webTranslate = j['webTranslate'] as bool? ?? false
|
||||||
..webJavaScript = j['webJavaScript'] as bool? ?? true
|
..webJavaScript = j['webJavaScript'] as bool? ?? true
|
||||||
..explorerLayout = const ['single', 'split'].contains(j['explorerLayout']) ? j['explorerLayout'] as String : 'dual'
|
// 'auto' = 넓은 화면은 두 창, 좁은 화면 (폰 세로) 은 한 창. 예전 기본 'dual' 은 한 번 'auto' 로
|
||||||
..explorerClick = j['explorerClick'] == 'open' ? 'open' : 'select'
|
..explorerLayout = const ['single', 'split', 'auto'].contains(j['explorerLayout'])
|
||||||
|
? j['explorerLayout'] as String
|
||||||
|
: j['explorerLayout'] == 'dual' && j['explorerV2'] == true
|
||||||
|
? 'dual'
|
||||||
|
: 'auto'
|
||||||
|
// Android 는 손가락으로 한 번 누르면 바로 실행이 기본. 예전 기본 'select' 는 Android 에서 한 번 'open' 으로
|
||||||
|
..explorerClick = j['explorerClick'] == 'open'
|
||||||
|
? 'open'
|
||||||
|
: j['explorerClick'] == 'select' && (j['explorerV2'] == true || !Platform.isAndroid)
|
||||||
|
? 'select'
|
||||||
|
: (Platform.isAndroid ? 'open' : 'select')
|
||||||
..explorerStyle = const ['windows', 'totalcmd'].contains(j['explorerStyle']) ? j['explorerStyle'] as String : 'xplore'
|
..explorerStyle = const ['windows', 'totalcmd'].contains(j['explorerStyle']) ? j['explorerStyle'] as String : 'xplore'
|
||||||
..explorerOrientation = const ['side', 'stacked'].contains(j['explorerOrientation'])
|
..explorerOrientation = const ['side', 'stacked'].contains(j['explorerOrientation'])
|
||||||
? j['explorerOrientation'] as String
|
? j['explorerOrientation'] as String
|
||||||
|
|
@ -600,7 +614,7 @@ class AppSettings {
|
||||||
..readerFit = j['readerFit'] == 'width' ? 'width' : 'page'
|
..readerFit = j['readerFit'] == 'width' ? 'width' : 'page'
|
||||||
..readerRtl = j['readerRtl'] as bool? ?? false
|
..readerRtl = j['readerRtl'] as bool? ?? false
|
||||||
..readerBrightness = ((j['readerBrightness'] as num?)?.toDouble() ?? 0).clamp(-0.7, 0.7)
|
..readerBrightness = ((j['readerBrightness'] as num?)?.toDouble() ?? 0).clamp(-0.7, 0.7)
|
||||||
..zipComic = j['zipComic'] as bool? ?? true
|
..zipComic = j['zipComic'] == true && j['zipComicV2'] == true
|
||||||
..webdavServers = [
|
..webdavServers = [
|
||||||
for (final x in (j['webdavServers'] as List?) ?? const [])
|
for (final x in (j['webdavServers'] as List?) ?? const [])
|
||||||
if (x is Map) DavServer.fromJson(x),
|
if (x is Map) DavServer.fromJson(x),
|
||||||
|
|
|
||||||
|
|
@ -61,9 +61,16 @@ class _FileBrowserState extends State<_FileBrowser> {
|
||||||
_start();
|
_start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 듀얼 앱 (복제한 앱): Android 가 "모든 파일 접근" 을 주지 않을 수 있어 안내를 따로
|
||||||
|
bool _dual = false;
|
||||||
|
|
||||||
Future<void> _start() async {
|
Future<void> _start() async {
|
||||||
_volumes = await AndroidAccess.volumes();
|
_volumes = await AndroidAccess.volumes();
|
||||||
final allowed = await AndroidAccess.hasAllFiles();
|
final allowed = await AndroidAccess.hasAllFiles();
|
||||||
|
try {
|
||||||
|
final root = await AndroidAccess.storageRoot();
|
||||||
|
_dual = root.contains('/emulated/') && !root.endsWith('/emulated/0');
|
||||||
|
} catch (_) {}
|
||||||
final first = [widget.initialDirectory, _lastDir, _volumes.first.$1].firstWhere(
|
final first = [widget.initialDirectory, _lastDir, _volumes.first.$1].firstWhere(
|
||||||
(d) => d != null && Directory(d).existsSync() && _volumeOf(d) != null,
|
(d) => d != null && Directory(d).existsSync() && _volumeOf(d) != null,
|
||||||
orElse: () => _volumes.first.$1)!;
|
orElse: () => _volumes.first.$1)!;
|
||||||
|
|
@ -285,6 +292,15 @@ class _FileBrowserState extends State<_FileBrowser> {
|
||||||
tr('동영상을 고르고, 동영상 옆 jj_mkv 폴더에 MKV 를 만들려면\n"모든 파일에 대한 접근" 권한이 필요합니다.'),
|
tr('동영상을 고르고, 동영상 옆 jj_mkv 폴더에 MKV 를 만들려면\n"모든 파일에 대한 접근" 권한이 필요합니다.'),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
|
if (_dual) ...[
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
Text(
|
||||||
|
tr('지금은 듀얼 앱 (복제한 앱) 입니다. Android 가 듀얼 앱에는 이 권한을 주지 않을 수 있습니다. '
|
||||||
|
'허용 화면에서 켤 수 없으면 배지 없는 원래 JJ_MKVMaker 아이콘으로 여세요.'),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: const TextStyle(color: JjColors.textDim),
|
||||||
|
),
|
||||||
|
],
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
FilledButton(onPressed: AndroidAccess.request, child: Text(tr('권한 허용 화면 열기'))),
|
FilledButton(onPressed: AndroidAccess.request, child: Text(tr('권한 허용 화면 열기'))),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
|
|
|
||||||
|
|
@ -212,6 +212,7 @@ class _ExplorerPageState extends State<ExplorerPage> {
|
||||||
for (final pane in _panes) {
|
for (final pane in _panes) {
|
||||||
pane.dispose();
|
pane.dispose();
|
||||||
}
|
}
|
||||||
|
if (_allFiles != null) _life.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -222,18 +223,183 @@ class _ExplorerPageState extends State<ExplorerPage> {
|
||||||
Future<void> _init() async {
|
Future<void> _init() async {
|
||||||
_local = await _loadVolumes();
|
_local = await _loadVolumes();
|
||||||
if (_local.isEmpty) _local = [(Platform.isWindows ? r'C:\' : '/', Platform.isWindows ? 'C:' : '/')];
|
if (_local.isEmpty) _local = [(Platform.isWindows ? r'C:\' : '/', Platform.isWindows ? 'C:' : '/')];
|
||||||
|
if (Platform.isAndroid) unawaited(_checkAccess());
|
||||||
final saved = widget.rsync ? c.settings.rsyncPaths : c.settings.explorerPaths;
|
final saved = widget.rsync ? c.settings.rsyncPaths : c.settings.explorerPaths;
|
||||||
|
// 창마다 따로 읽는다: 한 창이 WebDAV 서버를 기다려도 다른 창 (이 기기 파일) 은 바로 보이게
|
||||||
|
final wants = [
|
||||||
|
for (var i = 0; i < 2; i++) i < saved.length && _reachable(saved[i]) ? saved[i] : _local[0].$1,
|
||||||
|
];
|
||||||
for (var i = 0; i < 2; i++) {
|
for (var i = 0; i < 2; i++) {
|
||||||
final want = i < saved.length && _reachable(saved[i]) ? saved[i] : _local[0].$1;
|
_panes[i]
|
||||||
await _goTo(_panes[i], want, remember: false);
|
..root = _volumeOf(wants[i])
|
||||||
|
..current = wants[i]
|
||||||
|
..focused = wants[i];
|
||||||
}
|
}
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
setState(() => _ready = true);
|
setState(() => _ready = true);
|
||||||
for (final pane in _panes) {
|
for (var i = 0; i < 2; i++) {
|
||||||
_reveal(pane, pane.current); // 목록이 그려진 뒤에
|
final pane = _panes[i];
|
||||||
|
unawaited(_goTo(pane, wants[i], remember: false).then((_) => _reveal(pane, pane.current)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ───────── 권한 (Android) ─────────
|
||||||
|
|
||||||
|
/// "모든 파일에 대한 접근" 권한 (없으면 폴더만 보이고 파일은 안 보인다). null = 아직 모름
|
||||||
|
bool? _allFiles;
|
||||||
|
|
||||||
|
/// 듀얼 앱 (복제한 앱) 인지: 저장소가 /storage/emulated/0 이 아님
|
||||||
|
bool _dualApp = false;
|
||||||
|
|
||||||
|
late final AppLifecycleListener _life = AppLifecycleListener(onResume: () {
|
||||||
|
if (Platform.isAndroid && _allFiles == false) unawaited(_checkAccess(reload: true));
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<void> _checkAccess({bool reload = false}) async {
|
||||||
|
_life; // 다시 돌아오면 (권한 화면에서 허용하고 오면) 다시 확인
|
||||||
|
final ok = await AndroidAccess.hasAllFiles();
|
||||||
|
var dual = false;
|
||||||
|
try {
|
||||||
|
final root = await AndroidAccess.storageRoot();
|
||||||
|
dual = root.contains('/emulated/') && !root.endsWith('/emulated/0');
|
||||||
|
} catch (_) {}
|
||||||
|
if (!mounted) return;
|
||||||
|
final changed = ok != _allFiles;
|
||||||
|
setState(() {
|
||||||
|
_allFiles = ok;
|
||||||
|
_dualApp = dual;
|
||||||
|
});
|
||||||
|
if (reload && changed && ok) {
|
||||||
|
for (final pane in _panes) {
|
||||||
|
pane.cache.clear();
|
||||||
|
for (final d in pane.expanded.toList()) {
|
||||||
|
await _load(pane, d, force: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 권한이 없을 때 목록 위 안내 (이유 · 할 일 · 허용 화면 열기 · 다시 확인)
|
||||||
|
Widget? _accessNotice(_Pane pane) {
|
||||||
|
if (!Platform.isAndroid || _allFiles != false || isDav(pane.root)) return null;
|
||||||
|
return _notice(
|
||||||
|
icon: Icons.lock_outline,
|
||||||
|
title: tr('파일이 보이지 않습니다: "모든 파일에 대한 접근" 권한이 없습니다'),
|
||||||
|
body: _dualApp
|
||||||
|
? tr('지금은 듀얼 앱 (복제한 앱) 입니다. Android 가 듀얼 앱에는 이 권한을 주지 않을 수 있습니다. '
|
||||||
|
'허용 화면에서 켤 수 없으면 배지 없는 원래 JJ_MKVMaker 아이콘으로 여세요.')
|
||||||
|
: tr('폴더는 보여도 그 안의 동영상 · 파일은 이 권한이 있어야 보입니다. 허용 화면에서 JJ_MKVMaker 를 켜고 돌아오세요.'),
|
||||||
|
actions: [
|
||||||
|
FilledButton.tonal(onPressed: AndroidAccess.request, child: Text(tr('권한 허용 화면 열기'))),
|
||||||
|
TextButton(onPressed: () => _checkAccess(reload: true), child: Text(tr('허용했으면 다시 확인'))),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 목록 위 안내 상자
|
||||||
|
Widget _notice({required IconData icon, required String title, required String body, required List<Widget> actions}) =>
|
||||||
|
Container(
|
||||||
|
width: double.infinity,
|
||||||
|
margin: const EdgeInsets.fromLTRB(6, 6, 6, 0),
|
||||||
|
padding: const EdgeInsets.fromLTRB(12, 10, 12, 6),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.redAccent.withValues(alpha: 0.12),
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
border: Border.all(color: Colors.redAccent.withValues(alpha: 0.5)),
|
||||||
|
),
|
||||||
|
child: Column(crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [
|
||||||
|
Row(crossAxisAlignment: CrossAxisAlignment.start, children: [
|
||||||
|
Icon(icon, size: 18, color: Colors.redAccent),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
Expanded(child: Text(title, style: const TextStyle(fontWeight: FontWeight.w600))),
|
||||||
|
]),
|
||||||
|
const SizedBox(height: 4),
|
||||||
|
Text(body, style: const TextStyle(fontSize: 12, color: JjColors.textDim)),
|
||||||
|
Wrap(spacing: 8, children: actions),
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
|
||||||
|
// ───────── 읽을 수 없을 때 (12) ─────────
|
||||||
|
|
||||||
|
/// 오류 → (무엇이 문제인지, 무엇을 하면 되는지)
|
||||||
|
(String, String) _explain(String e, {required bool dav}) {
|
||||||
|
final s = e.toLowerCase();
|
||||||
|
if (dav && (s.contains('socketexception') || s.contains('connection refused') || s.contains('failed host lookup') ||
|
||||||
|
s.contains('network is unreachable') || s.contains('no route') || s.contains('timed out') ||
|
||||||
|
s.contains('timeoutexception') || s.contains('connection reset') || s.contains('connection closed'))) {
|
||||||
|
return (
|
||||||
|
tr('서버에 닿지 않습니다'),
|
||||||
|
tr('서버와 같은 네트워크에 있거나 VPN (예: Tailscale) 이 켜져 있어야 합니다. 켠 뒤 [다시 시도] 를 누르세요.'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (s.contains(' 401') || s.contains('status: 401') || s.contains('아이디 · 비밀번호')) {
|
||||||
|
return (tr('아이디 또는 비밀번호가 맞지 않습니다'), tr('[서버 설정 고치기] 에서 아이디 · 비밀번호를 확인하세요.'));
|
||||||
|
}
|
||||||
|
if (s.contains('handshake') || s.contains('certificate')) {
|
||||||
|
return (
|
||||||
|
tr('서버 인증서를 확인할 수 없습니다'),
|
||||||
|
tr('집 NAS 처럼 자체 서명 인증서면 [서버 설정 고치기] 에서 "인증서 확인 안 함" 을 켜세요.'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (s.contains(' 403') || s.contains('권한 없음')) return (tr('이 폴더를 볼 권한이 없습니다'), tr('서버에서 이 계정의 권한을 확인하세요.'));
|
||||||
|
if (s.contains(' 404') || s.contains('없는 경로')) return (tr('폴더가 없습니다'), tr('다른 곳에서 지웠거나 옮겼을 수 있습니다. 위 폴더로 가 보세요.'));
|
||||||
|
if (s.contains('permission denied') || s.contains('pathaccessexception') || s.contains('errno = 13')) {
|
||||||
|
return (
|
||||||
|
tr('이 폴더를 읽을 권한이 없습니다'),
|
||||||
|
Platform.isAndroid ? tr('Android 가 막은 폴더 (Android/data 등) 이거나 "모든 파일에 대한 접근" 권한이 없습니다.') : '',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return (tr('읽을 수 없습니다'), e);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget? _errorNotice(_Pane pane, String dir) {
|
||||||
|
final err = pane.errors[dir] ?? pane.errors[pane.root];
|
||||||
|
if (err == null) return null;
|
||||||
|
final where = pane.errors[dir] != null ? dir : pane.root;
|
||||||
|
final dav = isDav(where);
|
||||||
|
final (title, body) = _explain(err, dav: dav);
|
||||||
|
return _notice(
|
||||||
|
icon: dav ? Icons.cloud_off_outlined : Icons.error_outline,
|
||||||
|
title: '${_displayPath(where)}: $title',
|
||||||
|
body: body,
|
||||||
|
actions: [
|
||||||
|
FilledButton.tonal(
|
||||||
|
onPressed: () async {
|
||||||
|
pane.errors.remove(where);
|
||||||
|
pane.changed();
|
||||||
|
await _load(pane, where, force: true);
|
||||||
|
for (final d in pane.expanded.toList()) {
|
||||||
|
if (isSameOrInside(d, where) && d != where) await _load(pane, d, force: true);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: Text(tr('다시 시도')),
|
||||||
|
),
|
||||||
|
if (dav) TextButton(onPressed: () => _editDav(pane, pane.root), child: Text(tr('서버 설정 고치기'))),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 화면에 보일 경로 (5 · 14): Android 는 "SD 카드 › JJ_sdtest › jj_mkv", WebDAV 는 "☁ 서버 › 폴더", Windows 는 그대로
|
||||||
|
String _displayPath(String path) {
|
||||||
|
if (isDav(path)) {
|
||||||
|
final d = DavPath.parse(path);
|
||||||
|
final label = DavRegistry.server(d.server)?.label ?? 'WebDAV';
|
||||||
|
return ['☁ $label', ...d.rel.split('/').where((s) => s.isNotEmpty)].join(' › ');
|
||||||
|
}
|
||||||
|
if (!Platform.isAndroid) return path;
|
||||||
|
String? best;
|
||||||
|
var label = '';
|
||||||
|
for (final (v, l) in _local) {
|
||||||
|
if ((samePath(v, path) || p.isWithin(v, path)) && (best == null || v.length > best.length)) {
|
||||||
|
best = v;
|
||||||
|
label = l;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (best == null) return path;
|
||||||
|
final rest = p.relative(path, from: best);
|
||||||
|
return [label, if (rest != '.') ...p.split(rest)].join(' › ');
|
||||||
|
}
|
||||||
|
|
||||||
Future<List<(String, String)>> _loadVolumes() async {
|
Future<List<(String, String)>> _loadVolumes() async {
|
||||||
if (Platform.isWindows) return windowsDrives();
|
if (Platform.isWindows) return windowsDrives();
|
||||||
if (Platform.isAndroid) {
|
if (Platform.isAndroid) {
|
||||||
|
|
@ -362,7 +528,11 @@ class _ExplorerPageState extends State<ExplorerPage> {
|
||||||
bool get _split => !widget.rsync && c.settings.explorerLayout == 'split';
|
bool get _split => !widget.rsync && c.settings.explorerLayout == 'split';
|
||||||
|
|
||||||
/// 좌우 두 창 (Rsync 화면은 늘)
|
/// 좌우 두 창 (Rsync 화면은 늘)
|
||||||
bool get _dual => widget.rsync || c.settings.explorerLayout == 'dual';
|
bool get _dual =>
|
||||||
|
widget.rsync ||
|
||||||
|
c.settings.explorerLayout == 'dual' ||
|
||||||
|
// 자동: 넓으면 두 창, 좁은 화면 (폰 세로) 은 한 창 - 같은 목록이 반씩 잘려 두 번 보이지 않게
|
||||||
|
(c.settings.explorerLayout == 'auto' && !isCompact(context));
|
||||||
|
|
||||||
/// 한 번 누르면 선택 · 두 번 누르면 열기 (아니면 한 번에 바로 열기)
|
/// 한 번 누르면 선택 · 두 번 누르면 열기 (아니면 한 번에 바로 열기)
|
||||||
bool get _selectMode => c.settings.explorerClick != 'open';
|
bool get _selectMode => c.settings.explorerClick != 'open';
|
||||||
|
|
@ -1553,6 +1723,7 @@ class _ExplorerPageState extends State<ExplorerPage> {
|
||||||
width: 420,
|
width: 420,
|
||||||
child: Column(mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [
|
child: Column(mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [
|
||||||
group(tr('창'), layout, [
|
group(tr('창'), layout, [
|
||||||
|
('auto', tr('화면 크기 따라 (기본)')),
|
||||||
('dual', tr('두 창')),
|
('dual', tr('두 창')),
|
||||||
('split', tr('폴더 + 파일 목록')),
|
('split', tr('폴더 + 파일 목록')),
|
||||||
('single', tr('한 창')),
|
('single', tr('한 창')),
|
||||||
|
|
@ -1708,7 +1879,7 @@ class _ExplorerPageState extends State<ExplorerPage> {
|
||||||
Text(widget.rsync ? 'Rsync' : tr('파일 탐색기'), style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600)),
|
Text(widget.rsync ? 'Rsync' : tr('파일 탐색기'), style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600)),
|
||||||
const SizedBox(width: 12),
|
const SizedBox(width: 12),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Text(_ready ? vDisplay(_pane.current) : '',
|
child: Text(_ready ? _displayPath(_pane.current) : '',
|
||||||
maxLines: 1, overflow: TextOverflow.ellipsis, style: const TextStyle(color: JjColors.textDim)),
|
maxLines: 1, overflow: TextOverflow.ellipsis, style: const TextStyle(color: JjColors.textDim)),
|
||||||
),
|
),
|
||||||
PopupMenuButton<ExplorerButton>(
|
PopupMenuButton<ExplorerButton>(
|
||||||
|
|
@ -1839,6 +2010,10 @@ class _ExplorerPageState extends State<ExplorerPage> {
|
||||||
return _frame(i, [
|
return _frame(i, [
|
||||||
_paneHeader(pane),
|
_paneHeader(pane),
|
||||||
const Divider(height: 1),
|
const Divider(height: 1),
|
||||||
|
?_accessNotice(pane),
|
||||||
|
?_errorNotice(pane, pane.current),
|
||||||
|
// 읽는 중 (WebDAV 서버를 기다릴 때 등)
|
||||||
|
if (pane.loading.isNotEmpty) const LinearProgressIndicator(minHeight: 2),
|
||||||
if (look.columns && !foldersOnly) ExplorerColumnsHeader(style: look, markColumn: _selecting),
|
if (look.columns && !foldersOnly) ExplorerColumnsHeader(style: look, markColumn: _selecting),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ListView.builder(
|
child: ListView.builder(
|
||||||
|
|
@ -1867,9 +2042,11 @@ class _ExplorerPageState extends State<ExplorerPage> {
|
||||||
height: 40,
|
height: 40,
|
||||||
alignment: Alignment.centerLeft,
|
alignment: Alignment.centerLeft,
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||||
child: Text(dir, maxLines: 1, overflow: TextOverflow.ellipsis, style: const TextStyle(color: JjColors.textDim)),
|
child: Text(_displayPath(dir), maxLines: 1, overflow: TextOverflow.ellipsis, style: const TextStyle(color: JjColors.textDim)),
|
||||||
),
|
),
|
||||||
const Divider(height: 1),
|
const Divider(height: 1),
|
||||||
|
?_accessNotice(pane),
|
||||||
|
?_errorNotice(pane, dir),
|
||||||
if (look.columns) ExplorerColumnsHeader(style: look, markColumn: _selecting),
|
if (look.columns) ExplorerColumnsHeader(style: look, markColumn: _selecting),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: pane.loading.contains(dir)
|
child: pane.loading.contains(dir)
|
||||||
|
|
@ -2139,13 +2316,32 @@ class _Toolbar extends StatelessWidget {
|
||||||
const _Toolbar(
|
const _Toolbar(
|
||||||
{required this.buttons, required this.vertical, required this.onPressed, required this.enabled, required this.selected});
|
{required this.buttons, required this.vertical, required this.onPressed, required this.enabled, required this.selected});
|
||||||
|
|
||||||
|
/// 창이 위아래로 놓이면 (버튼 줄이 가로) "좌 → 우" 대신 "위 → 아래"
|
||||||
|
String _label(ExplorerButton b) => vertical
|
||||||
|
? b.label
|
||||||
|
: switch (b) {
|
||||||
|
ExplorerButton.toRight => '위 → 아래',
|
||||||
|
ExplorerButton.toLeft => '위 ← 아래',
|
||||||
|
ExplorerButton.both => '위 ⇄ 아래',
|
||||||
|
_ => b.label,
|
||||||
|
};
|
||||||
|
|
||||||
|
IconData _icon(ExplorerButton b) => vertical
|
||||||
|
? b.icon
|
||||||
|
: switch (b) {
|
||||||
|
ExplorerButton.toRight => Icons.arrow_downward,
|
||||||
|
ExplorerButton.toLeft => Icons.arrow_upward,
|
||||||
|
ExplorerButton.both => Icons.swap_vert,
|
||||||
|
_ => b.icon,
|
||||||
|
};
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
Widget btn(ExplorerButton b) {
|
Widget btn(ExplorerButton b) {
|
||||||
final on = enabled(b);
|
final on = enabled(b);
|
||||||
final sel = selected(b);
|
final sel = selected(b);
|
||||||
return Tooltip(
|
return Tooltip(
|
||||||
message: tr(b.label),
|
message: tr(_label(b)),
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: on ? () => onPressed(b) : null,
|
onTap: on ? () => onPressed(b) : null,
|
||||||
borderRadius: BorderRadius.circular(6),
|
borderRadius: BorderRadius.circular(6),
|
||||||
|
|
@ -2153,9 +2349,9 @@ class _Toolbar extends StatelessWidget {
|
||||||
width: 72,
|
width: 72,
|
||||||
height: 58,
|
height: 58,
|
||||||
child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [
|
child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [
|
||||||
Icon(b.icon, size: 22, color: !on ? JjColors.textDim.withValues(alpha: 0.4) : sel ? JjColors.accent : null),
|
Icon(_icon(b), size: 22, color: !on ? JjColors.textDim.withValues(alpha: 0.4) : sel ? JjColors.accent : null),
|
||||||
const SizedBox(height: 2),
|
const SizedBox(height: 2),
|
||||||
Text(tr(b.label),
|
Text(tr(_label(b)),
|
||||||
maxLines: 2,
|
maxLines: 2,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
|
|
|
||||||
|
|
@ -576,8 +576,9 @@ class _SettingsPageState extends State<SettingsPage> {
|
||||||
trailing: DropdownButton<String>(
|
trailing: DropdownButton<String>(
|
||||||
value: s.explorerClick,
|
value: s.explorerClick,
|
||||||
items: [
|
items: [
|
||||||
DropdownMenuItem(value: 'select', child: Text(tr('한 번: 선택 · 두 번: 실행 (기본)'))),
|
DropdownMenuItem(
|
||||||
DropdownMenuItem(value: 'open', child: Text(tr('한 번: 바로 실행'))),
|
value: 'select', child: Text(desk ? tr('한 번: 선택 · 두 번: 실행 (기본)') : tr('한 번: 선택 · 두 번: 실행'))),
|
||||||
|
DropdownMenuItem(value: 'open', child: Text(desk ? tr('한 번: 바로 실행') : tr('한 번: 바로 실행 (기본)'))),
|
||||||
],
|
],
|
||||||
onChanged: (v) => c.updateSettings((x) => x.explorerClick = v!),
|
onChanged: (v) => c.updateSettings((x) => x.explorerClick = v!),
|
||||||
),
|
),
|
||||||
|
|
@ -601,6 +602,7 @@ class _SettingsPageState extends State<SettingsPage> {
|
||||||
trailing: DropdownButton<String>(
|
trailing: DropdownButton<String>(
|
||||||
value: s.explorerLayout,
|
value: s.explorerLayout,
|
||||||
items: [
|
items: [
|
||||||
|
DropdownMenuItem(value: 'auto', child: Text(tr('화면 크기 따라 (기본)'))),
|
||||||
DropdownMenuItem(value: 'dual', child: Text(tr('두 창'))),
|
DropdownMenuItem(value: 'dual', child: Text(tr('두 창'))),
|
||||||
DropdownMenuItem(value: 'split', child: Text(tr('폴더 + 파일 목록'))),
|
DropdownMenuItem(value: 'split', child: Text(tr('폴더 + 파일 목록'))),
|
||||||
DropdownMenuItem(value: 'single', child: Text(tr('한 창'))),
|
DropdownMenuItem(value: 'single', child: Text(tr('한 창'))),
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue