WIP 84 파일 탐색기 정렬: 열 머리를 누르면 그 기준 · 다시 누르면 거꾸로, 설정 "정렬을 폴더마다 기억" (검토 대기)
- 관리자 지시 (F13): 열 머리를 누르면 그 기준으로 정렬, 폴더마다 정렬을 기억 (선택). - Windows 탐색기 · Total Commander 모양의 열 머리 (이름 · 날짜 · 유형/확장자 · 크기) 를 누르면 그 기준 (오름차순), 같은 열을 다시 누르면 거꾸로. 지금 정렬 열은 강조색 + ▲ ▼. (X-plore 모양은 열이 없어 예전처럼 [정렬 기준]) - 설정 "정렬을 폴더마다 기억" (처음: 끔 - 예전처럼 모든 폴더가 같은 정렬). 켜면 열 머리 · [정렬 기준] 이 지금 창의 폴더에만 쓰고 (정렬 창에 "이 폴더에만: …"), 기억하지 않은 폴더는 전체 정렬. 300개까지 (오래된 것부터 지움). 틀린 값은 비움. - 80 의 자동 폴더 크기 · 크기가 나온 뒤 다시 줄 세우기도 그 폴더의 정렬을 따른다. - 시험: explorer_test 84 (열 머리 · 거꾸로 · ▼, 폴더마다 · 저장 · 틀린 값). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>묶음6
parent
a15f6c25af
commit
1b988cd84c
|
|
@ -431,6 +431,7 @@
|
||||||
"{0} 새로 {1} · 덮어씀 {2}": "{0} new {1} · overwrite {2}",
|
"{0} 새로 {1} · 덮어씀 {2}": "{0} new {1} · overwrite {2}",
|
||||||
"{0} 새로 {1} · 바뀜 {2}": "{0} new {1} · changed {2}",
|
"{0} 새로 {1} · 바뀜 {2}": "{0} new {1} · changed {2}",
|
||||||
"{0} 설치": "Install {0}",
|
"{0} 설치": "Install {0}",
|
||||||
|
"{0} 순으로 정렬": "Sort by {0}",
|
||||||
"{0} 순으로 정렬{1}": "Sort by {0}{1}",
|
"{0} 순으로 정렬{1}": "Sort by {0}{1}",
|
||||||
"{0} 아래에 만듭니다": "Created under {0}",
|
"{0} 아래에 만듭니다": "Created under {0}",
|
||||||
"{0} 안의 파일": "Files in {0}",
|
"{0} 안의 파일": "Files in {0}",
|
||||||
|
|
@ -771,6 +772,8 @@
|
||||||
"노르웨이어": "Norwegian",
|
"노르웨이어": "Norwegian",
|
||||||
"누르고 있으면 조정 전": "Hold to see before",
|
"누르고 있으면 조정 전": "Hold to see before",
|
||||||
"누르기": "Tap",
|
"누르기": "Tap",
|
||||||
|
"누르면 내림차순": "Click for descending",
|
||||||
|
"누르면 오름차순": "Click for ascending",
|
||||||
"누르면 일정 바꾸기": "Tap to change the schedule",
|
"누르면 일정 바꾸기": "Tap to change the schedule",
|
||||||
"늘 건너뛰기": "Always skip",
|
"늘 건너뛰기": "Always skip",
|
||||||
"늘 계산": "Always calculate",
|
"늘 계산": "Always calculate",
|
||||||
|
|
@ -1736,6 +1739,7 @@
|
||||||
"이 폴더에 새 폴더": "New folder in this folder",
|
"이 폴더에 새 폴더": "New folder in this folder",
|
||||||
"이 폴더에 현재 페이지 추가": "Add the current page to this folder",
|
"이 폴더에 현재 페이지 추가": "Add the current page to this folder",
|
||||||
"이 폴더에는 고를 파일이 없습니다": "There are no files to choose in this folder",
|
"이 폴더에는 고를 파일이 없습니다": "There are no files to choose in this folder",
|
||||||
|
"이 폴더에만: {0}": "This folder only: {0}",
|
||||||
"이 폴더의 동영상 재생": "Play videos in this folder",
|
"이 폴더의 동영상 재생": "Play videos in this folder",
|
||||||
"이 프로그램이 관리자 권한으로 실행 중입니다. 권장하지 않습니다.\n\n· 내장 Chrome 엔진은 샌드박스 (웹 페이지를 가두는 보호) 가 꺼져 있어, 웹 페이지가 관리자 권한 프로세스 안에서 돕니다. 페이지의 취약점이 곧 이 PC 의 관리자 권한이 될 수 있습니다.\n· Edge 엔진은 이 영향이 없습니다.\n· 관리자 권한 없이 프로그램을 실행하면 이 설정 없이도 Chrome 엔진을 쓸 수 있습니다.": "This app is running as administrator. This is not recommended.\n\n· The built-in Chrome engine has its sandbox (the protection that confines web pages) turned off, so web pages run inside an administrator process. A flaw in a page could become administrator access to this PC.\n· The Edge engine is not affected.\n· If you run the app without administrator rights, you can use the Chrome engine without this setting.",
|
"이 프로그램이 관리자 권한으로 실행 중입니다. 권장하지 않습니다.\n\n· 내장 Chrome 엔진은 샌드박스 (웹 페이지를 가두는 보호) 가 꺼져 있어, 웹 페이지가 관리자 권한 프로세스 안에서 돕니다. 페이지의 취약점이 곧 이 PC 의 관리자 권한이 될 수 있습니다.\n· Edge 엔진은 이 영향이 없습니다.\n· 관리자 권한 없이 프로그램을 실행하면 이 설정 없이도 Chrome 엔진을 쓸 수 있습니다.": "This app is running as administrator. This is not recommended.\n\n· The built-in Chrome engine has its sandbox (the protection that confines web pages) turned off, so web pages run inside an administrator process. A flaw in a page could become administrator access to this PC.\n· The Edge engine is not affected.\n· If you run the app without administrator rights, you can use the Chrome engine without this setting.",
|
||||||
"이 형식을 여는 앱이 없습니다. 길게 누르거나 오른쪽 클릭 → [내장 플레이어로 재생] 으로 들어 보세요.": "No app opens this format. Long-press or right-click → [Play in built-in player] to try it.",
|
"이 형식을 여는 앱이 없습니다. 길게 누르거나 오른쪽 클릭 → [내장 플레이어로 재생] 으로 들어 보세요.": "No app opens this format. Long-press or right-click → [Play in built-in player] to try it.",
|
||||||
|
|
@ -1950,6 +1954,7 @@
|
||||||
"전체 화면 (F)": "Full screen (F)",
|
"전체 화면 (F)": "Full screen (F)",
|
||||||
"점검": "Check",
|
"점검": "Check",
|
||||||
"정렬 기준": "Sort by",
|
"정렬 기준": "Sort by",
|
||||||
|
"정렬을 폴더마다 기억": "Remember sort per folder",
|
||||||
"정리": "Clean up",
|
"정리": "Clean up",
|
||||||
"정리 ({0})": "Clean up ({0})",
|
"정리 ({0})": "Clean up ({0})",
|
||||||
"정리 창에서 미리 체크할 것": "Pre-checked in the cleanup window",
|
"정리 창에서 미리 체크할 것": "Pre-checked in the cleanup window",
|
||||||
|
|
@ -2166,6 +2171,7 @@
|
||||||
"켜면 Tor 공식 배포처에서 Tor Expert Bundle {0} (tor {1}) 을 내려받습니다 (약 {2}MB, SHA-256 확인). 끄면 지웁니다.": "Turning it on downloads Tor Expert Bundle {0} (tor {1}) from the official Tor distribution (about {2} MB, SHA-256 verified). Turning it off deletes it.",
|
"켜면 Tor 공식 배포처에서 Tor Expert Bundle {0} (tor {1}) 을 내려받습니다 (약 {2}MB, SHA-256 확인). 끄면 지웁니다.": "Turning it on downloads Tor Expert Bundle {0} (tor {1}) from the official Tor distribution (about {2} MB, SHA-256 verified). Turning it off deletes it.",
|
||||||
"켜면 두 번 눌렀을 때 안의 그림을 바로 넘겨 봅니다. 끄면 목록 (골라서 풀기) 을 엽니다.": "When on, double-tapping shows the images inside right away. When off, opens the file list (extract selected).",
|
"켜면 두 번 눌렀을 때 안의 그림을 바로 넘겨 봅니다. 끄면 목록 (골라서 풀기) 을 엽니다.": "When on, double-tapping shows the images inside right away. When off, opens the file list (extract selected).",
|
||||||
"켜면 변환기를 내려받아 설치합니다 (약 420MB). 끄면 지웁니다.": "Turning it on downloads and installs a converter (about 420MB). Turning it off deletes it.",
|
"켜면 변환기를 내려받아 설치합니다 (약 420MB). 끄면 지웁니다.": "Turning it on downloads and installs a converter (about 420MB). Turning it off deletes it.",
|
||||||
|
"켜면 열 머리 · 정렬 기준에서 바꾼 정렬이 그 폴더에만 쓰입니다. 끄면 모든 폴더가 같은 정렬입니다": "When on, a sort changed from a column header or Sort by applies to that folder only. When off, all folders share one sort",
|
||||||
"켜면 휴지통으로 보내 되살릴 수 있습니다 (Shift+Delete 는 영구 삭제). 끄면 늘 영구 삭제로 묻습니다. 네트워크 드라이브 · USB 메모리는 휴지통이 없어 늘 영구 삭제입니다": "When on, items go to the Recycle Bin and can be restored (Shift+Delete deletes permanently). When off, it always asks to delete permanently. Network drives and USB memory have no Recycle Bin, so deletion there is always permanent",
|
"켜면 휴지통으로 보내 되살릴 수 있습니다 (Shift+Delete 는 영구 삭제). 끄면 늘 영구 삭제로 묻습니다. 네트워크 드라이브 · USB 메모리는 휴지통이 없어 늘 영구 삭제입니다": "When on, items go to the Recycle Bin and can be restored (Shift+Delete deletes permanently). When off, it always asks to delete permanently. Network drives and USB memory have no Recycle Bin, so deletion there is always permanent",
|
||||||
"켜져 있는 창에서 (기본)": "In the open window (default)",
|
"켜져 있는 창에서 (기본)": "In the open window (default)",
|
||||||
"코덱": "Codec",
|
"코덱": "Codec",
|
||||||
|
|
|
||||||
|
|
@ -431,6 +431,7 @@
|
||||||
"{0} 새로 {1} · 덮어씀 {2}": "{0} 新規 {1} · 上書き {2}",
|
"{0} 새로 {1} · 덮어씀 {2}": "{0} 新規 {1} · 上書き {2}",
|
||||||
"{0} 새로 {1} · 바뀜 {2}": "{0} 新規 {1}・変更 {2}",
|
"{0} 새로 {1} · 바뀜 {2}": "{0} 新規 {1}・変更 {2}",
|
||||||
"{0} 설치": "{0} のインストール",
|
"{0} 설치": "{0} のインストール",
|
||||||
|
"{0} 순으로 정렬": "{0} 順に並べ替え",
|
||||||
"{0} 순으로 정렬{1}": "{0} 順に並べ替え{1}",
|
"{0} 순으로 정렬{1}": "{0} 順に並べ替え{1}",
|
||||||
"{0} 아래에 만듭니다": "{0} の下に作成します",
|
"{0} 아래에 만듭니다": "{0} の下に作成します",
|
||||||
"{0} 안의 파일": "{0} 内のファイル",
|
"{0} 안의 파일": "{0} 内のファイル",
|
||||||
|
|
@ -771,6 +772,8 @@
|
||||||
"노르웨이어": "ノルウェー語",
|
"노르웨이어": "ノルウェー語",
|
||||||
"누르고 있으면 조정 전": "押している間は調整前",
|
"누르고 있으면 조정 전": "押している間は調整前",
|
||||||
"누르기": "タップ",
|
"누르기": "タップ",
|
||||||
|
"누르면 내림차순": "クリックで降順",
|
||||||
|
"누르면 오름차순": "クリックで昇順",
|
||||||
"누르면 일정 바꾸기": "タップで予定を変更",
|
"누르면 일정 바꾸기": "タップで予定を変更",
|
||||||
"늘 건너뛰기": "常にスキップ",
|
"늘 건너뛰기": "常にスキップ",
|
||||||
"늘 계산": "常に計算",
|
"늘 계산": "常に計算",
|
||||||
|
|
@ -1736,6 +1739,7 @@
|
||||||
"이 폴더에 새 폴더": "このフォルダーに新しいフォルダー",
|
"이 폴더에 새 폴더": "このフォルダーに新しいフォルダー",
|
||||||
"이 폴더에 현재 페이지 추가": "このフォルダーに現在のページを追加",
|
"이 폴더에 현재 페이지 추가": "このフォルダーに現在のページを追加",
|
||||||
"이 폴더에는 고를 파일이 없습니다": "このフォルダーには選べるファイルがありません",
|
"이 폴더에는 고를 파일이 없습니다": "このフォルダーには選べるファイルがありません",
|
||||||
|
"이 폴더에만: {0}": "このフォルダーだけ: {0}",
|
||||||
"이 폴더의 동영상 재생": "このフォルダーの動画を再生",
|
"이 폴더의 동영상 재생": "このフォルダーの動画を再生",
|
||||||
"이 프로그램이 관리자 권한으로 실행 중입니다. 권장하지 않습니다.\n\n· 내장 Chrome 엔진은 샌드박스 (웹 페이지를 가두는 보호) 가 꺼져 있어, 웹 페이지가 관리자 권한 프로세스 안에서 돕니다. 페이지의 취약점이 곧 이 PC 의 관리자 권한이 될 수 있습니다.\n· Edge 엔진은 이 영향이 없습니다.\n· 관리자 권한 없이 프로그램을 실행하면 이 설정 없이도 Chrome 엔진을 쓸 수 있습니다.": "このアプリは管理者権限で実行されています。おすすめしません。\n\n· 内蔵 Chrome エンジンはサンドボックス (Web ページを閉じ込める保護) がオフのため、Web ページが管理者権限のプロセス内で動きます。ページの脆弱性がそのままこの PC の管理者権限になるおそれがあります。\n· Edge エンジンにはこの影響がありません。\n· 管理者権限なしでアプリを実行すれば、この設定なしで Chrome エンジンを使えます。",
|
"이 프로그램이 관리자 권한으로 실행 중입니다. 권장하지 않습니다.\n\n· 내장 Chrome 엔진은 샌드박스 (웹 페이지를 가두는 보호) 가 꺼져 있어, 웹 페이지가 관리자 권한 프로세스 안에서 돕니다. 페이지의 취약점이 곧 이 PC 의 관리자 권한이 될 수 있습니다.\n· Edge 엔진은 이 영향이 없습니다.\n· 관리자 권한 없이 프로그램을 실행하면 이 설정 없이도 Chrome 엔진을 쓸 수 있습니다.": "このアプリは管理者権限で実行されています。おすすめしません。\n\n· 内蔵 Chrome エンジンはサンドボックス (Web ページを閉じ込める保護) がオフのため、Web ページが管理者権限のプロセス内で動きます。ページの脆弱性がそのままこの PC の管理者権限になるおそれがあります。\n· Edge エンジンにはこの影響がありません。\n· 管理者権限なしでアプリを実行すれば、この設定なしで Chrome エンジンを使えます。",
|
||||||
"이 형식을 여는 앱이 없습니다. 길게 누르거나 오른쪽 클릭 → [내장 플레이어로 재생] 으로 들어 보세요.": "この形式を開くアプリがありません。長押しまたは右クリック → [内蔵プレーヤーで再生] で試してください。",
|
"이 형식을 여는 앱이 없습니다. 길게 누르거나 오른쪽 클릭 → [내장 플레이어로 재생] 으로 들어 보세요.": "この形式を開くアプリがありません。長押しまたは右クリック → [内蔵プレーヤーで再生] で試してください。",
|
||||||
|
|
@ -1950,6 +1954,7 @@
|
||||||
"전체 화면 (F)": "全画面(F)",
|
"전체 화면 (F)": "全画面(F)",
|
||||||
"점검": "点検",
|
"점검": "点検",
|
||||||
"정렬 기준": "並べ替え",
|
"정렬 기준": "並べ替え",
|
||||||
|
"정렬을 폴더마다 기억": "フォルダーごとに並べ替えを記憶",
|
||||||
"정리": "整理",
|
"정리": "整理",
|
||||||
"정리 ({0})": "整理({0})",
|
"정리 ({0})": "整理({0})",
|
||||||
"정리 창에서 미리 체크할 것": "整理ウィンドウで事前にチェックするもの",
|
"정리 창에서 미리 체크할 것": "整理ウィンドウで事前にチェックするもの",
|
||||||
|
|
@ -2166,6 +2171,7 @@
|
||||||
"켜면 Tor 공식 배포처에서 Tor Expert Bundle {0} (tor {1}) 을 내려받습니다 (약 {2}MB, SHA-256 확인). 끄면 지웁니다.": "オンにすると Tor 公式配布元から Tor Expert Bundle {0} (tor {1}) をダウンロードします (約 {2}MB、SHA-256 確認)。オフにすると削除します。",
|
"켜면 Tor 공식 배포처에서 Tor Expert Bundle {0} (tor {1}) 을 내려받습니다 (약 {2}MB, SHA-256 확인). 끄면 지웁니다.": "オンにすると Tor 公式配布元から Tor Expert Bundle {0} (tor {1}) をダウンロードします (約 {2}MB、SHA-256 確認)。オフにすると削除します。",
|
||||||
"켜면 두 번 눌렀을 때 안의 그림을 바로 넘겨 봅니다. 끄면 목록 (골라서 풀기) 을 엽니다.": "オンにするとダブルタップで中の画像をすぐめくって表示します。オフにすると一覧 (選んで展開) を開きます。",
|
"켜면 두 번 눌렀을 때 안의 그림을 바로 넘겨 봅니다. 끄면 목록 (골라서 풀기) 을 엽니다.": "オンにするとダブルタップで中の画像をすぐめくって表示します。オフにすると一覧 (選んで展開) を開きます。",
|
||||||
"켜면 변환기를 내려받아 설치합니다 (약 420MB). 끄면 지웁니다.": "オンにすると変換ツールをダウンロードしてインストールします (約 420MB)。オフにすると削除します。",
|
"켜면 변환기를 내려받아 설치합니다 (약 420MB). 끄면 지웁니다.": "オンにすると変換ツールをダウンロードしてインストールします (約 420MB)。オフにすると削除します。",
|
||||||
|
"켜면 열 머리 · 정렬 기준에서 바꾼 정렬이 그 폴더에만 쓰입니다. 끄면 모든 폴더가 같은 정렬입니다": "オンにすると、列見出し・並べ替えで変えた並べ替えはそのフォルダーだけに使われます。オフではすべてのフォルダーが同じ並べ替えです",
|
||||||
"켜면 휴지통으로 보내 되살릴 수 있습니다 (Shift+Delete 는 영구 삭제). 끄면 늘 영구 삭제로 묻습니다. 네트워크 드라이브 · USB 메모리는 휴지통이 없어 늘 영구 삭제입니다": "オンにするとごみ箱に移動し、元に戻せます (Shift+Delete は完全に削除)。オフにすると常に完全に削除として確認します。ネットワークドライブ・USB メモリにはごみ箱がないため常に完全に削除です",
|
"켜면 휴지통으로 보내 되살릴 수 있습니다 (Shift+Delete 는 영구 삭제). 끄면 늘 영구 삭제로 묻습니다. 네트워크 드라이브 · USB 메모리는 휴지통이 없어 늘 영구 삭제입니다": "オンにするとごみ箱に移動し、元に戻せます (Shift+Delete は完全に削除)。オフにすると常に完全に削除として確認します。ネットワークドライブ・USB メモリにはごみ箱がないため常に完全に削除です",
|
||||||
"켜져 있는 창에서 (기본)": "開いているウィンドウで(既定)",
|
"켜져 있는 창에서 (기본)": "開いているウィンドウで(既定)",
|
||||||
"코덱": "コーデック",
|
"코덱": "コーデック",
|
||||||
|
|
|
||||||
|
|
@ -431,6 +431,7 @@
|
||||||
"{0} 새로 {1} · 덮어씀 {2}": "{0} 新增 {1} · 覆盖 {2}",
|
"{0} 새로 {1} · 덮어씀 {2}": "{0} 新增 {1} · 覆盖 {2}",
|
||||||
"{0} 새로 {1} · 바뀜 {2}": "{0} 新增 {1} · 更改 {2}",
|
"{0} 새로 {1} · 바뀜 {2}": "{0} 新增 {1} · 更改 {2}",
|
||||||
"{0} 설치": "安装 {0}",
|
"{0} 설치": "安装 {0}",
|
||||||
|
"{0} 순으로 정렬": "按{0}排序",
|
||||||
"{0} 순으로 정렬{1}": "按{0}排序{1}",
|
"{0} 순으로 정렬{1}": "按{0}排序{1}",
|
||||||
"{0} 아래에 만듭니다": "在 {0} 下创建",
|
"{0} 아래에 만듭니다": "在 {0} 下创建",
|
||||||
"{0} 안의 파일": "{0} 中的文件",
|
"{0} 안의 파일": "{0} 中的文件",
|
||||||
|
|
@ -771,6 +772,8 @@
|
||||||
"노르웨이어": "挪威语",
|
"노르웨이어": "挪威语",
|
||||||
"누르고 있으면 조정 전": "按住查看调整前",
|
"누르고 있으면 조정 전": "按住查看调整前",
|
||||||
"누르기": "点按",
|
"누르기": "点按",
|
||||||
|
"누르면 내림차순": "点击改为降序",
|
||||||
|
"누르면 오름차순": "点击改为升序",
|
||||||
"누르면 일정 바꾸기": "点按以更改计划",
|
"누르면 일정 바꾸기": "点按以更改计划",
|
||||||
"늘 건너뛰기": "总是跳过",
|
"늘 건너뛰기": "总是跳过",
|
||||||
"늘 계산": "始终计算",
|
"늘 계산": "始终计算",
|
||||||
|
|
@ -1736,6 +1739,7 @@
|
||||||
"이 폴더에 새 폴더": "在此文件夹中新建文件夹",
|
"이 폴더에 새 폴더": "在此文件夹中新建文件夹",
|
||||||
"이 폴더에 현재 페이지 추가": "将当前页面添加到此文件夹",
|
"이 폴더에 현재 페이지 추가": "将当前页面添加到此文件夹",
|
||||||
"이 폴더에는 고를 파일이 없습니다": "此文件夹中没有可选择的文件",
|
"이 폴더에는 고를 파일이 없습니다": "此文件夹中没有可选择的文件",
|
||||||
|
"이 폴더에만: {0}": "仅此文件夹: {0}",
|
||||||
"이 폴더의 동영상 재생": "播放此文件夹中的视频",
|
"이 폴더의 동영상 재생": "播放此文件夹中的视频",
|
||||||
"이 프로그램이 관리자 권한으로 실행 중입니다. 권장하지 않습니다.\n\n· 내장 Chrome 엔진은 샌드박스 (웹 페이지를 가두는 보호) 가 꺼져 있어, 웹 페이지가 관리자 권한 프로세스 안에서 돕니다. 페이지의 취약점이 곧 이 PC 의 관리자 권한이 될 수 있습니다.\n· Edge 엔진은 이 영향이 없습니다.\n· 관리자 권한 없이 프로그램을 실행하면 이 설정 없이도 Chrome 엔진을 쓸 수 있습니다.": "本应用正以管理员权限运行,不推荐这样做。\n\n· 内置 Chrome 引擎的沙盒(限制网页的保护)已关闭,网页会在管理员权限进程中运行。网页中的漏洞可能直接变成此电脑的管理员权限。\n· Edge 引擎不受此影响。\n· 不以管理员权限运行本应用时,无需此设置即可使用 Chrome 引擎。",
|
"이 프로그램이 관리자 권한으로 실행 중입니다. 권장하지 않습니다.\n\n· 내장 Chrome 엔진은 샌드박스 (웹 페이지를 가두는 보호) 가 꺼져 있어, 웹 페이지가 관리자 권한 프로세스 안에서 돕니다. 페이지의 취약점이 곧 이 PC 의 관리자 권한이 될 수 있습니다.\n· Edge 엔진은 이 영향이 없습니다.\n· 관리자 권한 없이 프로그램을 실행하면 이 설정 없이도 Chrome 엔진을 쓸 수 있습니다.": "本应用正以管理员权限运行,不推荐这样做。\n\n· 内置 Chrome 引擎的沙盒(限制网页的保护)已关闭,网页会在管理员权限进程中运行。网页中的漏洞可能直接变成此电脑的管理员权限。\n· Edge 引擎不受此影响。\n· 不以管理员权限运行本应用时,无需此设置即可使用 Chrome 引擎。",
|
||||||
"이 형식을 여는 앱이 없습니다. 길게 누르거나 오른쪽 클릭 → [내장 플레이어로 재생] 으로 들어 보세요.": "没有可打开此格式的应用。请长按或右键 → [用内置播放器播放] 试试。",
|
"이 형식을 여는 앱이 없습니다. 길게 누르거나 오른쪽 클릭 → [내장 플레이어로 재생] 으로 들어 보세요.": "没有可打开此格式的应用。请长按或右键 → [用内置播放器播放] 试试。",
|
||||||
|
|
@ -1950,6 +1954,7 @@
|
||||||
"전체 화면 (F)": "全屏(F)",
|
"전체 화면 (F)": "全屏(F)",
|
||||||
"점검": "检查",
|
"점검": "检查",
|
||||||
"정렬 기준": "排序方式",
|
"정렬 기준": "排序方式",
|
||||||
|
"정렬을 폴더마다 기억": "按文件夹记住排序",
|
||||||
"정리": "清理",
|
"정리": "清理",
|
||||||
"정리 ({0})": "清理({0})",
|
"정리 ({0})": "清理({0})",
|
||||||
"정리 창에서 미리 체크할 것": "清理窗口中预先勾选的项目",
|
"정리 창에서 미리 체크할 것": "清理窗口中预先勾选的项目",
|
||||||
|
|
@ -2166,6 +2171,7 @@
|
||||||
"켜면 Tor 공식 배포처에서 Tor Expert Bundle {0} (tor {1}) 을 내려받습니다 (약 {2}MB, SHA-256 확인). 끄면 지웁니다.": "开启后从 Tor 官方发布处下载 Tor Expert Bundle {0} (tor {1}) (约 {2}MB,校验 SHA-256)。关闭时删除。",
|
"켜면 Tor 공식 배포처에서 Tor Expert Bundle {0} (tor {1}) 을 내려받습니다 (약 {2}MB, SHA-256 확인). 끄면 지웁니다.": "开启后从 Tor 官方发布处下载 Tor Expert Bundle {0} (tor {1}) (约 {2}MB,校验 SHA-256)。关闭时删除。",
|
||||||
"켜면 두 번 눌렀을 때 안의 그림을 바로 넘겨 봅니다. 끄면 목록 (골라서 풀기) 을 엽니다.": "开启后双击会直接翻看其中的图片;关闭则打开文件列表 (选择解压)。",
|
"켜면 두 번 눌렀을 때 안의 그림을 바로 넘겨 봅니다. 끄면 목록 (골라서 풀기) 을 엽니다.": "开启后双击会直接翻看其中的图片;关闭则打开文件列表 (选择解压)。",
|
||||||
"켜면 변환기를 내려받아 설치합니다 (약 420MB). 끄면 지웁니다.": "开启时会下载并安装转换器 (约 420MB)。关闭时会删除。",
|
"켜면 변환기를 내려받아 설치합니다 (약 420MB). 끄면 지웁니다.": "开启时会下载并安装转换器 (约 420MB)。关闭时会删除。",
|
||||||
|
"켜면 열 머리 · 정렬 기준에서 바꾼 정렬이 그 폴더에만 쓰입니다. 끄면 모든 폴더가 같은 정렬입니다": "开启后,通过列标题或排序方式更改的排序只用于该文件夹。关闭时所有文件夹使用同一排序",
|
||||||
"켜면 휴지통으로 보내 되살릴 수 있습니다 (Shift+Delete 는 영구 삭제). 끄면 늘 영구 삭제로 묻습니다. 네트워크 드라이브 · USB 메모리는 휴지통이 없어 늘 영구 삭제입니다": "开启后移到回收站,可以恢复 (Shift+Delete 为永久删除)。关闭后始终按永久删除询问。网络驱动器 · U 盘没有回收站,始终永久删除",
|
"켜면 휴지통으로 보내 되살릴 수 있습니다 (Shift+Delete 는 영구 삭제). 끄면 늘 영구 삭제로 묻습니다. 네트워크 드라이브 · USB 메모리는 휴지통이 없어 늘 영구 삭제입니다": "开启后移到回收站,可以恢复 (Shift+Delete 为永久删除)。关闭后始终按永久删除询问。网络驱动器 · U 盘没有回收站,始终永久删除",
|
||||||
"켜져 있는 창에서 (기본)": "在已打开的窗口中(默认)",
|
"켜져 있는 창에서 (기본)": "在已打开的窗口中(默认)",
|
||||||
"코덱": "编解码器",
|
"코덱": "编解码器",
|
||||||
|
|
|
||||||
|
|
@ -414,6 +414,12 @@ class AppSettings {
|
||||||
String explorerSort = 'name';
|
String explorerSort = 'name';
|
||||||
bool explorerSortDesc = false;
|
bool explorerSortDesc = false;
|
||||||
|
|
||||||
|
/// 84: 정렬을 폴더마다 기억 (처음: 끔 - 모든 폴더가 같은 정렬). 켜면 열 머리 · 정렬 창이 지금 폴더에만 쓰고 [explorerFolderSorts] 에 둔다
|
||||||
|
bool explorerSortPerFolder = false;
|
||||||
|
|
||||||
|
/// 84: 폴더 → "기준|desc" (예: "size|1"). 오래된 것부터 지워 300개까지
|
||||||
|
Map<String, String> explorerFolderSorts = {};
|
||||||
|
|
||||||
/// 80: 폴더 크기 계산 - 'sort' 크기순 정렬일 때만 (처음 값) · 'always' 늘 · 'off' 안 함 (길게 누르기 [폴더 크기 계산] 은 늘 됨)
|
/// 80: 폴더 크기 계산 - 'sort' 크기순 정렬일 때만 (처음 값) · 'always' 늘 · 'off' 안 함 (길게 누르기 [폴더 크기 계산] 은 늘 됨)
|
||||||
String explorerFolderSize = 'sort';
|
String explorerFolderSize = 'sort';
|
||||||
bool explorerShowHidden = false;
|
bool explorerShowHidden = false;
|
||||||
|
|
@ -735,6 +741,8 @@ class AppSettings {
|
||||||
'explorerSort': explorerSort,
|
'explorerSort': explorerSort,
|
||||||
'explorerSortDesc': explorerSortDesc,
|
'explorerSortDesc': explorerSortDesc,
|
||||||
'explorerFolderSize': explorerFolderSize,
|
'explorerFolderSize': explorerFolderSize,
|
||||||
|
'explorerSortPerFolder': explorerSortPerFolder,
|
||||||
|
'explorerFolderSorts': explorerFolderSorts,
|
||||||
'explorerShowHidden': explorerShowHidden,
|
'explorerShowHidden': explorerShowHidden,
|
||||||
'explorerPaths': explorerPaths,
|
'explorerPaths': explorerPaths,
|
||||||
'copyMethodFile': copyMethodFile,
|
'copyMethodFile': copyMethodFile,
|
||||||
|
|
@ -949,6 +957,12 @@ class AppSettings {
|
||||||
..explorerSort = const ['date', 'size', 'type'].contains(j['explorerSort']) ? j['explorerSort'] as String : 'name'
|
..explorerSort = const ['date', 'size', 'type'].contains(j['explorerSort']) ? j['explorerSort'] as String : 'name'
|
||||||
..explorerSortDesc = j['explorerSortDesc'] as bool? ?? false
|
..explorerSortDesc = j['explorerSortDesc'] as bool? ?? false
|
||||||
..explorerFolderSize = const ['sort', 'always', 'off'].contains(j['explorerFolderSize']) ? j['explorerFolderSize'] as String : 'sort'
|
..explorerFolderSize = const ['sort', 'always', 'off'].contains(j['explorerFolderSize']) ? j['explorerFolderSize'] as String : 'sort'
|
||||||
|
..explorerSortPerFolder = j['explorerSortPerFolder'] == true
|
||||||
|
..explorerFolderSorts = {
|
||||||
|
if (j['explorerFolderSorts'] is Map)
|
||||||
|
for (final e in (j['explorerFolderSorts'] as Map).entries)
|
||||||
|
if (e.key is String && e.value is String) e.key as String: e.value as String,
|
||||||
|
}
|
||||||
..explorerShowHidden = j['explorerShowHidden'] as bool? ?? false
|
..explorerShowHidden = j['explorerShowHidden'] as bool? ?? false
|
||||||
..explorerPaths = [for (final x in (j['explorerPaths'] as List?) ?? const []) '$x']
|
..explorerPaths = [for (final x in (j['explorerPaths'] as List?) ?? const []) '$x']
|
||||||
..copyMethodFile = _method(j['copyMethodFile'])
|
..copyMethodFile = _method(j['copyMethodFile'])
|
||||||
|
|
|
||||||
|
|
@ -115,13 +115,46 @@ class ExplorerColumnsHeader extends StatelessWidget {
|
||||||
|
|
||||||
/// 선택 모드: 줄 끝의 선택 동그라미 칸만큼 비운다
|
/// 선택 모드: 줄 끝의 선택 동그라미 칸만큼 비운다
|
||||||
final bool markColumn;
|
final bool markColumn;
|
||||||
const ExplorerColumnsHeader({super.key, required this.style, this.markColumn = false});
|
|
||||||
|
/// 84: 지금 정렬 ('name' · 'date' · 'size' · 'type') · 거꾸로 - 그 열에 ▲ ▼
|
||||||
|
final String? sortBy;
|
||||||
|
final bool sortDesc;
|
||||||
|
|
||||||
|
/// 84: 열 머리를 누르면 (같은 열을 다시 누르면 거꾸로 - 부르는 쪽이 정한다)
|
||||||
|
final void Function(String by)? onSort;
|
||||||
|
const ExplorerColumnsHeader(
|
||||||
|
{super.key, required this.style, this.markColumn = false, this.sortBy, this.sortDesc = false, this.onSort});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
const st = TextStyle(fontSize: 11.5, color: JjColors.textDim);
|
const st = TextStyle(fontSize: 11.5, color: JjColors.textDim);
|
||||||
Widget cell(String t, int flex, {TextAlign align = TextAlign.start}) =>
|
Widget cell(String t, int flex, {TextAlign align = TextAlign.start, String? by}) {
|
||||||
Expanded(flex: flex, child: Text(t, style: st, textAlign: align, maxLines: 1, overflow: TextOverflow.clip));
|
final on = by != null && by == sortBy;
|
||||||
|
final label = Row(
|
||||||
|
mainAxisAlignment: align == TextAlign.end ? MainAxisAlignment.end : MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Flexible(
|
||||||
|
child: Text(t,
|
||||||
|
style: on ? st.copyWith(color: JjColors.accent, fontWeight: FontWeight.w600) : st,
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.clip),
|
||||||
|
),
|
||||||
|
if (on) Icon(sortDesc ? Icons.arrow_drop_down : Icons.arrow_drop_up, size: 16, color: JjColors.accent),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
return Expanded(
|
||||||
|
flex: flex,
|
||||||
|
child: by == null || onSort == null
|
||||||
|
? label
|
||||||
|
: Tooltip(
|
||||||
|
message: on
|
||||||
|
? (sortDesc ? tr('누르면 오름차순') : tr('누르면 내림차순'))
|
||||||
|
: trf('{0} 순으로 정렬', [t]),
|
||||||
|
child: InkWell(onTap: () => onSort!(by), child: SizedBox(height: 24, child: Align(alignment: Alignment.centerLeft, child: label))),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
height: 24,
|
height: 24,
|
||||||
padding: EdgeInsets.only(left: 10, right: markColumn ? 40 : 4),
|
padding: EdgeInsets.only(left: 10, right: markColumn ? 40 : 4),
|
||||||
|
|
@ -129,17 +162,17 @@ class ExplorerColumnsHeader extends StatelessWidget {
|
||||||
child: Row(
|
child: Row(
|
||||||
children: style == ExplorerStyle.windows
|
children: style == ExplorerStyle.windows
|
||||||
? [
|
? [
|
||||||
cell(tr('이름'), 6),
|
cell(tr('이름'), 6, by: 'name'),
|
||||||
cell(tr('수정한 날짜'), 3),
|
cell(tr('수정한 날짜'), 3, by: 'date'),
|
||||||
cell(tr('유형'), 2),
|
cell(tr('유형'), 2, by: 'type'),
|
||||||
cell(tr('크기'), 2, align: TextAlign.end),
|
cell(tr('크기'), 2, align: TextAlign.end, by: 'size'),
|
||||||
]
|
]
|
||||||
: [
|
: [
|
||||||
cell(tr('이름'), 6),
|
cell(tr('이름'), 6, by: 'name'),
|
||||||
cell(tr('확장자'), 1),
|
cell(tr('확장자'), 1, by: 'type'),
|
||||||
cell(tr('크기'), 2, align: TextAlign.end),
|
cell(tr('크기'), 2, align: TextAlign.end, by: 'size'),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
cell(tr('날짜'), 3),
|
cell(tr('날짜'), 3, by: 'date'),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -324,11 +324,9 @@ class _ExplorerPageState extends State<ExplorerPage> {
|
||||||
/// 80: 폴더 크기가 나오면 - 크기순이면 다시 줄 세우고 화면 갱신
|
/// 80: 폴더 크기가 나오면 - 크기순이면 다시 줄 세우고 화면 갱신
|
||||||
void _onSizes() {
|
void _onSizes() {
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
if (c.settings.explorerSort == 'size') {
|
|
||||||
for (final pane in _panes) {
|
for (final pane in _panes) {
|
||||||
for (final k in pane.cache.keys.toList()) {
|
for (final k in pane.cache.keys.toList()) {
|
||||||
pane.cache[k] = _sorted(pane.cache[k]!);
|
if (_sortOf(k).$1 == 'size') pane.cache[k] = _sorted(pane.cache[k]!, k);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setState(() {});
|
setState(() {});
|
||||||
|
|
@ -341,7 +339,7 @@ class _ExplorerPageState extends State<ExplorerPage> {
|
||||||
if (s != null) return s.label;
|
if (s != null) return s.label;
|
||||||
if (_sizes.busy(e.path)) return '…';
|
if (_sizes.busy(e.path)) return '…';
|
||||||
final mode = c.settings.explorerFolderSize;
|
final mode = c.settings.explorerFolderSize;
|
||||||
if ((mode == 'always' || (mode == 'sort' && c.settings.explorerSort == 'size')) && samePath(vDirname(e.path), pane.current)) {
|
if ((mode == 'always' || (mode == 'sort' && _sortOf(pane.current).$1 == 'size')) && samePath(vDirname(e.path), pane.current)) {
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
if (mounted) _sizes.request(e.path);
|
if (mounted) _sizes.request(e.path);
|
||||||
});
|
});
|
||||||
|
|
@ -765,7 +763,7 @@ class _ExplorerPageState extends State<ExplorerPage> {
|
||||||
pane.changed();
|
pane.changed();
|
||||||
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, dir);
|
||||||
// 50: Android 가 막은 폴더는 비어 보인다 (오류 없이) - 비어 있는 것이 아니라 막힌 것이라고 알린다
|
// 50: Android 가 막은 폴더는 비어 보인다 (오류 없이) - 비어 있는 것이 아니라 막힌 것이라고 알린다
|
||||||
if (list.isEmpty && isAndroidRestricted(dir)) {
|
if (list.isEmpty && isAndroidRestricted(dir)) {
|
||||||
pane.errors[dir] = androidRestrictedError;
|
pane.errors[dir] = androidRestrictedError;
|
||||||
|
|
@ -796,9 +794,54 @@ class _ExplorerPageState extends State<ExplorerPage> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
List<FileEntry> _sorted(List<FileEntry> list) {
|
/// [dir] 의 목록을 정렬. 84: "폴더마다 기억" 이 켜져 있으면 그 폴더의 정렬 (없으면 전체 정렬)
|
||||||
final by = SortBy.values.firstWhere((s) => s.name == c.settings.explorerSort, orElse: () => SortBy.name);
|
List<FileEntry> _sorted(List<FileEntry> list, String dir) {
|
||||||
return sortEntries(list, by, descending: c.settings.explorerSortDesc, dirSize: (d) => _sizes.of(d.path)?.bytes);
|
final (sortBy, desc) = _sortOf(dir);
|
||||||
|
final by = SortBy.values.firstWhere((s) => s.name == sortBy, orElse: () => SortBy.name);
|
||||||
|
return sortEntries(list, by, descending: desc, dirSize: (d) => _sizes.of(d.path)?.bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
static String _sortKey(String dir) => isDav(dir) ? vNorm(dir) : (Platform.isWindows ? dir.toLowerCase() : dir);
|
||||||
|
|
||||||
|
/// 84: [dir] 의 정렬 (기준, 거꾸로)
|
||||||
|
(String, bool) _sortOf(String dir) {
|
||||||
|
final s = c.settings;
|
||||||
|
if (s.explorerSortPerFolder) {
|
||||||
|
final v = s.explorerFolderSorts[_sortKey(dir)];
|
||||||
|
if (v != null && v.contains('|')) return (v.split('|').first, v.endsWith('|1'));
|
||||||
|
}
|
||||||
|
return (s.explorerSort, s.explorerSortDesc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 84: 정렬을 바꾼다 - "폴더마다 기억" 이면 [dir] 에만, 아니면 전체. 모든 창의 목록을 다시 줄 세운다
|
||||||
|
Future<void> _setSort(String dir, String by, bool desc) async {
|
||||||
|
await c.updateSettings((x) {
|
||||||
|
if (x.explorerSortPerFolder) {
|
||||||
|
final m = Map<String, String>.of(x.explorerFolderSorts)..remove(_sortKey(dir));
|
||||||
|
m[_sortKey(dir)] = '$by|${desc ? 1 : 0}';
|
||||||
|
while (m.length > 300) {
|
||||||
|
m.remove(m.keys.first);
|
||||||
|
}
|
||||||
|
x.explorerFolderSorts = m;
|
||||||
|
} else {
|
||||||
|
x
|
||||||
|
..explorerSort = by
|
||||||
|
..explorerSortDesc = desc;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
for (final pane in _panes) {
|
||||||
|
for (final k in pane.cache.keys.toList()) {
|
||||||
|
pane.cache[k] = _sorted(pane.cache[k]!, k);
|
||||||
|
}
|
||||||
|
pane.changed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 84: 열 머리를 누름 - 같은 열이면 거꾸로, 다른 열이면 그 열로 (오름차순)
|
||||||
|
Future<void> _sortByColumn(_Pane pane, String by) async {
|
||||||
|
setState(() => _active = _panes.indexOf(pane));
|
||||||
|
final (now, desc) = _sortOf(pane.current);
|
||||||
|
await _setSort(pane.current, by, now == by ? !desc : false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 그 폴더로: 저장 장치부터 그 폴더까지 펼치고 지금 폴더로 정한다
|
/// 그 폴더로: 저장 장치부터 그 폴더까지 펼치고 지금 폴더로 정한다
|
||||||
|
|
@ -1210,7 +1253,7 @@ class _ExplorerPageState extends State<ExplorerPage> {
|
||||||
// 폴더를 읽지 못하면 (E10: 이제 오류로 알림) 고른 그림 하나만
|
// 폴더를 읽지 못하면 (E10: 이제 오류로 알림) 고른 그림 하나만
|
||||||
List<FileEntry> list;
|
List<FileEntry> list;
|
||||||
try {
|
try {
|
||||||
list = pane?.cache[dir] ?? _sorted(await listEntries(dir, showHidden: c.settings.explorerShowHidden));
|
list = pane?.cache[dir] ?? _sorted(await listEntries(dir, showHidden: c.settings.explorerShowHidden), dir);
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
list = const [];
|
list = const [];
|
||||||
}
|
}
|
||||||
|
|
@ -2846,9 +2889,9 @@ class _ExplorerPageState extends State<ExplorerPage> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _sortDialog() async {
|
Future<void> _sortDialog() async {
|
||||||
final s = c.settings;
|
// 84: "폴더마다 기억" 이면 지금 창의 폴더 정렬
|
||||||
var by = s.explorerSort;
|
final dir = _pane.current;
|
||||||
var desc = s.explorerSortDesc;
|
var (by, desc) = _sortOf(dir);
|
||||||
final ok = await showDialog<bool>(
|
final ok = await showDialog<bool>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (ctx) => StatefulBuilder(
|
builder: (ctx) => StatefulBuilder(
|
||||||
|
|
@ -2866,6 +2909,8 @@ class _ExplorerPageState extends State<ExplorerPage> {
|
||||||
ChoiceChip(label: Text(label), selected: by == v, onSelected: (_) => set(() => by = v)),
|
ChoiceChip(label: Text(label), selected: by == v, onSelected: (_) => set(() => by = v)),
|
||||||
]),
|
]),
|
||||||
SwitchListTile(value: desc, title: Text(tr('거꾸로')), onChanged: (x) => set(() => desc = x)),
|
SwitchListTile(value: desc, title: Text(tr('거꾸로')), onChanged: (x) => set(() => desc = x)),
|
||||||
|
if (c.settings.explorerSortPerFolder)
|
||||||
|
Text(trf('이 폴더에만: {0}', [_displayPath(dir)]), style: const TextStyle(fontSize: 12, color: JjColors.textDim)),
|
||||||
]),
|
]),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(onPressed: () => Navigator.pop(ctx, false), child: Text(tr('취소'))),
|
TextButton(onPressed: () => Navigator.pop(ctx, false), child: Text(tr('취소'))),
|
||||||
|
|
@ -2875,15 +2920,7 @@ class _ExplorerPageState extends State<ExplorerPage> {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
if (ok != true) return;
|
if (ok != true) return;
|
||||||
await c.updateSettings((x) => x
|
await _setSort(dir, by, desc);
|
||||||
..explorerSort = by
|
|
||||||
..explorerSortDesc = desc);
|
|
||||||
for (final pane in _panes) {
|
|
||||||
for (final k in pane.cache.keys.toList()) {
|
|
||||||
pane.cache[k] = _sorted(pane.cache[k]!);
|
|
||||||
}
|
|
||||||
pane.changed();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 73: 즐겨찾기 - 이 창으로 가기, Rsync 화면이면 짝 (왼쪽 · 오른쪽) 을 한 번에
|
/// 73: 즐겨찾기 - 이 창으로 가기, Rsync 화면이면 짝 (왼쪽 · 오른쪽) 을 한 번에
|
||||||
|
|
@ -3437,7 +3474,14 @@ class _ExplorerPageState extends State<ExplorerPage> {
|
||||||
_filterBar(pane, rows.where((r) => !r.isRoot && isSameOrInside(r.entry.path, pane.current) && !samePath(r.entry.path, pane.current) && quickFilterMatch(vBasename(r.entry.path), pane.filter)).length),
|
_filterBar(pane, rows.where((r) => !r.isRoot && isSameOrInside(r.entry.path, pane.current) && !samePath(r.entry.path, pane.current) && quickFilterMatch(vBasename(r.entry.path), pane.filter)).length),
|
||||||
// 38: 안내가 길어도 목록을 덮지 않게 (창 높이의 35% 까지, 넘치면 넘겨 봄)
|
// 38: 안내가 길어도 목록을 덮지 않게 (창 높이의 35% 까지, 넘치면 넘겨 봄)
|
||||||
?_noticeArea([_accessNotice(pane), _errorNotice(pane, pane.current), _partialNotice(pane, pane.current)], box.maxHeight),
|
?_noticeArea([_accessNotice(pane), _errorNotice(pane, pane.current), _partialNotice(pane, pane.current)], box.maxHeight),
|
||||||
if (look.columns && !foldersOnly) ExplorerColumnsHeader(style: look, markColumn: _selecting),
|
if (look.columns && !foldersOnly)
|
||||||
|
ExplorerColumnsHeader(
|
||||||
|
style: look,
|
||||||
|
markColumn: _selecting,
|
||||||
|
sortBy: _sortOf(pane.current).$1,
|
||||||
|
sortDesc: _sortOf(pane.current).$2,
|
||||||
|
onSort: (by) => _sortByColumn(pane, by),
|
||||||
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Stack(children: [
|
child: Stack(children: [
|
||||||
ListView.builder(
|
ListView.builder(
|
||||||
|
|
@ -3489,7 +3533,14 @@ class _ExplorerPageState extends State<ExplorerPage> {
|
||||||
const Divider(height: 1),
|
const Divider(height: 1),
|
||||||
if (pane.filterOpen) _filterBar(pane, shown.length),
|
if (pane.filterOpen) _filterBar(pane, shown.length),
|
||||||
?_noticeArea([_accessNotice(pane), _errorNotice(pane, dir), _partialNotice(pane, dir)], box.maxHeight),
|
?_noticeArea([_accessNotice(pane), _errorNotice(pane, dir), _partialNotice(pane, dir)], box.maxHeight),
|
||||||
if (look.columns) ExplorerColumnsHeader(style: look, markColumn: _selecting),
|
if (look.columns)
|
||||||
|
ExplorerColumnsHeader(
|
||||||
|
style: look,
|
||||||
|
markColumn: _selecting,
|
||||||
|
sortBy: _sortOf(dir).$1,
|
||||||
|
sortDesc: _sortOf(dir).$2,
|
||||||
|
onSort: (by) => _sortByColumn(pane, by),
|
||||||
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
// 180: 다시 읽는 동안은 앞의 목록을 그대로 (빙글이로 바꾸면 목록이 새로 만들어져 스크롤이 맨 위로 간다)
|
// 180: 다시 읽는 동안은 앞의 목록을 그대로 (빙글이로 바꾸면 목록이 새로 만들어져 스크롤이 맨 위로 간다)
|
||||||
child: pane.loading.contains(dir) && !pane.cache.containsKey(dir)
|
child: pane.loading.contains(dir) && !pane.cache.containsKey(dir)
|
||||||
|
|
|
||||||
|
|
@ -767,6 +767,15 @@ class _SettingsPageState extends State<SettingsPage> {
|
||||||
onChanged: (v) => c.updateSettings((x) => x.explorerClick = v!),
|
onChanged: (v) => c.updateSettings((x) => x.explorerClick = v!),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
// 84: 정렬을 폴더마다 기억 (처음: 끔)
|
||||||
|
SettingTile(
|
||||||
|
title: Text(tr('정렬을 폴더마다 기억')),
|
||||||
|
subtitle: Text(tr('켜면 열 머리 · 정렬 기준에서 바꾼 정렬이 그 폴더에만 쓰입니다. 끄면 모든 폴더가 같은 정렬입니다')),
|
||||||
|
trailing: Switch(
|
||||||
|
value: s.explorerSortPerFolder,
|
||||||
|
onChanged: (v) => c.updateSettings((x) => x.explorerSortPerFolder = v),
|
||||||
|
),
|
||||||
|
),
|
||||||
// 80: 폴더 크기 (필요할 때 계산하고 이번 실행 동안 기억)
|
// 80: 폴더 크기 (필요할 때 계산하고 이번 실행 동안 기억)
|
||||||
SettingTile(
|
SettingTile(
|
||||||
title: Text(tr('폴더 크기')),
|
title: Text(tr('폴더 크기')),
|
||||||
|
|
|
||||||
|
|
@ -964,6 +964,40 @@ void main() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('84: 열 머리를 누르면 그 기준으로 · 다시 누르면 거꾸로 (처음: 모든 폴더 같은 정렬)', (tester) async {
|
||||||
|
File(p.join(left, 'a_big.txt')).writeAsStringSync('x' * 50);
|
||||||
|
c.settings.explorerStyle = 'windows';
|
||||||
|
await open(tester);
|
||||||
|
double y(String name) => tester.getTopLeft(find.text(name).first).dy;
|
||||||
|
expect(y('a_big.txt'), lessThan(y('doc.txt')), reason: '처음: 이름순');
|
||||||
|
await act(tester, () => tester.tap(find.text('크기').first));
|
||||||
|
await calm(tester);
|
||||||
|
expect((c.settings.explorerSort, c.settings.explorerSortDesc), ('size', false));
|
||||||
|
expect(y('doc.txt'), lessThan(y('a_big.txt')), reason: '크기 오름차순: doc.txt (5) 가 먼저');
|
||||||
|
await act(tester, () => tester.tap(find.text('크기').first));
|
||||||
|
await calm(tester);
|
||||||
|
expect(c.settings.explorerSortDesc, isTrue, reason: '같은 열을 다시 누르면 거꾸로');
|
||||||
|
// (거꾸로면 트리에 펼쳐진 위 폴더 (Temp 등) 의 차례도 바뀌어 시험 폴더가 화면 밖으로 갈 수 있어 줄 위치는 보지 않는다)
|
||||||
|
expect(find.byIcon(Icons.arrow_drop_down), findsWidgets, reason: '지금 정렬 열에 ▼');
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('84: "정렬을 폴더마다 기억" 을 켜면 그 폴더에만 (전체 정렬 · 다른 창은 그대로)', (tester) async {
|
||||||
|
c.settings
|
||||||
|
..explorerStyle = 'totalcmd'
|
||||||
|
..explorerSortPerFolder = true;
|
||||||
|
await open(tester);
|
||||||
|
// 왼쪽 창에서 날짜 열
|
||||||
|
await act(tester, () => tester.tap(find.text('날짜').first));
|
||||||
|
await calm(tester);
|
||||||
|
expect(c.settings.explorerSort, 'name', reason: '전체 정렬은 그대로');
|
||||||
|
expect(c.settings.explorerFolderSorts.values, contains('date|0'));
|
||||||
|
expect(c.settings.explorerFolderSorts.length, 1);
|
||||||
|
// 저장 · 읽기
|
||||||
|
expect(AppSettings.fromJson(c.settings.toJson()).explorerFolderSorts, c.settings.explorerFolderSorts);
|
||||||
|
expect(AppSettings.fromJson(c.settings.toJson()).explorerSortPerFolder, isTrue);
|
||||||
|
expect(AppSettings.fromJson({'explorerFolderSorts': 'broken'}).explorerFolderSorts, isEmpty, reason: '틀린 값은 비움');
|
||||||
|
});
|
||||||
|
|
||||||
testWidgets('80: 크기순 정렬이면 폴더 크기를 계산해 보이고, "안 함" 이어도 길게 누르기 [폴더 크기 계산]', (tester) async {
|
testWidgets('80: 크기순 정렬이면 폴더 크기를 계산해 보이고, "안 함" 이어도 길게 누르기 [폴더 크기 계산]', (tester) async {
|
||||||
File(p.join(left, 'sub', 'big.bin')).writeAsBytesSync(List.filled(3000, 1));
|
File(p.join(left, 'sub', 'big.bin')).writeAsBytesSync(List.filled(3000, 1));
|
||||||
c.settings
|
c.settings
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue