WIP 85 파일 탐색기 진행 패널 숨기기 · 작은 표시 · Android 알림 진행률 · 끝나면 [폴더 열기] (검토 대기)

- 관리자 지시 (F14): 복사 진행 패널을 숨길 수 있게 (Android 는 알림줄에 진행), 끝나면 [폴더 열기].
- 패널 오른쪽 위 [숨기기] → 오른쪽 아래 작은 표시 "복사 · 이동 n개 · 45%" (누르면 다시 펼침). 숨김은 설정으로 기억 (처음 값: 보임).
  관리자 판단: 숨겨도 묻는 창 (확인 · 같은 이름) 과 실패 알림은 늘 뜬다 (패널과 따로). 멈춘 (실패한) 것이 있으면 작은 표시가
  빨갛게 "복사 · 이동 멈춤 - 눌러서 보기".
- Android 작업 알림: "복사 · 이동 n개 · 45%" (CopyCenter.activeProgress), 다운로드가 없으면 진행 막대도 복사 · 이동 진행률.
- 끝난 알림에 [폴더 열기] - 앱 탐색기에서 넣은 폴더로 (그 폴더를 보는 창, 없으면 지금 창).
- 시험: keep_alive_test (복사 진행률 글 · 막대 · 다운로드가 먼저), explorer_test 85 ([폴더 열기] · [숨기기] → 작은 표시 → 다시).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
묶음6
RyuJongJin 2026-10-17 13:36:59 +09:00
parent 5cdf57d7ff
commit 53a1b47a2c
9 changed files with 158 additions and 9 deletions

View File

@ -1209,7 +1209,10 @@
"복사 · rsync 목록으로 옮겼습니다.": "Moved to the copy · rsync list.",
"복사 · 동기화가 중간에 끊겨 남은 임시 파일입니다 (.jjpart). 완성된 파일이 아니므로 지워도 됩니다. 같은 파일을 다시 복사하면 새로 만듭니다.": "Temporary files left behind when a copy or sync was interrupted (.jjpart). They are not complete files, so you can delete them. Copying the same file again creates it anew.",
"복사 · 이동 {0}개": "{0} copy · move",
"복사 · 이동 {0}개 · {1}%": "Copy · move: {0} · {1}%",
"복사 · 이동 {0}개가 아직 끝나지 않았습니다. 끝내면 멈추고, 복사하던 파일은 완성되지 않은 채로 남지 않게 지웁니다.": "{0} copy/move tasks have not finished. Exiting stops them, and the file being copied is removed so no incomplete file is left.",
"복사 · 이동 끝": "Copy · move finished",
"복사 · 이동 멈춤 - 눌러서 보기": "Copy · move stopped - tap to see",
"복사 · 이동 중입니다": "Copying · moving in progress",
"복사 · 이동: 받는 쪽 파일이 더 새것이면 건너뜁니다 (예전에는 예전 원본으로 덮어쓰고, 이동이면 원본도 지웠습니다). 건너뛴 파일은 원본에 남고 끝 알림에 그 수가 나옵니다. 되돌리기: 환경 설정 > 파일 탐색기 (또는 Rsync) > 받는 쪽이 더 새것이면 건너뛰기": "Copy · move: files are skipped when the receiving side is newer (before, the older source overwrote them, and a move also deleted the source). Skipped files stay in the source and their number appears in the finish notice. To change back: Settings > File explorer (or Rsync) > Skip when the receiving side is newer",
"복사 · 이동은 두 창에서 씁니다 (창 배치 > 두 창).": "Copy · move works with two panes (Pane layout > Two panes).",
@ -1377,6 +1380,7 @@
"수정 · 이동": "Edit · move",
"수정한 날짜": "Date modified",
"숨겨도 위쪽 ⋮ 메뉴에서 창 배치 · 버튼 구성을 바꿀 수 있습니다.": "Even when hidden, you can change the pane layout · buttons from the ⋮ menu at the top.",
"숨기기": "Hide",
"숨긴 항목 (. 으로 시작) 보이기": "Show hidden items (starting with .)",
"숨긴 항목 숨기기": "Hide hidden items",
"숨김": "Hidden",
@ -2115,6 +2119,7 @@
"직접 지정 (기본)": "Manual (default)",
"진행 중인 작업 없음": "No jobs in progress",
"진행 중인 작업이 있습니다: {0}\n중지하고 끝낼까요?": "A job is in progress: {0}\nStop it and quit?",
"진행 패널 보기": "Show progress panel",
"집 NAS 처럼 자체 서명 인증서면 [서버 설정 고치기] 에서 \"인증서 확인 안 함\" 을 켜세요.": "If it uses a self-signed certificate (like a home NAS), turn on \"Don't verify certificate\" in [Edit server settings].",
"짧을수록 빨리 맞추지만 배터리를 더 씁니다.": "Shorter means faster syncing but more battery use.",
"차례 기다림": "Waiting in queue",

View File

@ -1209,7 +1209,10 @@
"복사 · rsync 목록으로 옮겼습니다.": "コピー · rsync の一覧へ移しました。",
"복사 · 동기화가 중간에 끊겨 남은 임시 파일입니다 (.jjpart). 완성된 파일이 아니므로 지워도 됩니다. 같은 파일을 다시 복사하면 새로 만듭니다.": "コピー・同期が途中で中断されて残った一時ファイルです (.jjpart)。完成したファイルではないので削除しても構いません。同じファイルをもう一度コピーすると新しく作ります。",
"복사 · 이동 {0}개": "コピー・移動 {0} 件",
"복사 · 이동 {0}개 · {1}%": "コピー・移動 {0} 件 · {1}%",
"복사 · 이동 {0}개가 아직 끝나지 않았습니다. 끝내면 멈추고, 복사하던 파일은 완성되지 않은 채로 남지 않게 지웁니다.": "コピー・移動 {0} 件がまだ終わっていません。終了すると止まり、コピー中のファイルは未完成のまま残らないよう削除します。",
"복사 · 이동 끝": "コピー・移動 完了",
"복사 · 이동 멈춤 - 눌러서 보기": "コピー・移動が停止 - タップして表示",
"복사 · 이동 중입니다": "コピー・移動中です",
"복사 · 이동: 받는 쪽 파일이 더 새것이면 건너뜁니다 (예전에는 예전 원본으로 덮어쓰고, 이동이면 원본도 지웠습니다). 건너뛴 파일은 원본에 남고 끝 알림에 그 수가 나옵니다. 되돌리기: 환경 설정 > 파일 탐색기 (또는 Rsync) > 받는 쪽이 더 새것이면 건너뛰기": "コピー · 移動: 受け取る側のファイルが新しければスキップします (以前は古い元で上書きし、移動なら元も削除していました)。スキップしたファイルは元に残り、終了の通知にその数が出ます。戻すには: 環境設定 > ファイルエクスプローラー (または Rsync) > 受け取る側が新しければスキップ",
"복사 · 이동은 두 창에서 씁니다 (창 배치 > 두 창).": "コピー · 移動は 2 ペインで使います (ペインの配置 > 2 ペイン)。",
@ -1377,6 +1380,7 @@
"수정 · 이동": "編集・移動",
"수정한 날짜": "更新日時",
"숨겨도 위쪽 ⋮ 메뉴에서 창 배치 · 버튼 구성을 바꿀 수 있습니다.": "非表示にしても、上の ⋮ メニューからペインの配置 · ボタン構成を変えられます。",
"숨기기": "隠す",
"숨긴 항목 (. 으로 시작) 보이기": "隠し項目 (. で始まる) を表示",
"숨긴 항목 숨기기": "隠し項目を隠す",
"숨김": "非表示",
@ -2115,6 +2119,7 @@
"직접 지정 (기본)": "手動指定 (既定)",
"진행 중인 작업 없음": "進行中の作業なし",
"진행 중인 작업이 있습니다: {0}\n중지하고 끝낼까요?": "進行中の作業があります: {0}\n中止して終了しますか?",
"진행 패널 보기": "進行パネルを表示",
"집 NAS 처럼 자체 서명 인증서면 [서버 설정 고치기] 에서 \"인증서 확인 안 함\" 을 켜세요.": "自宅 NAS のように自己署名証明書なら、[サーバー設定を修正] で「証明書を検証しない」をオンにしてください。",
"짧을수록 빨리 맞추지만 배터리를 더 씁니다.": "短いほど早く同期しますが、バッテリーをより使います。",
"차례 기다림": "順番待ち",

View File

@ -1209,7 +1209,10 @@
"복사 · rsync 목록으로 옮겼습니다.": "已移到 复制 · rsync 列表。",
"복사 · 동기화가 중간에 끊겨 남은 임시 파일입니다 (.jjpart). 완성된 파일이 아니므로 지워도 됩니다. 같은 파일을 다시 복사하면 새로 만듭니다.": "这是复制 · 同步中途中断后留下的临时文件 (.jjpart)。它们不是完整的文件,可以删除。再次复制同一文件会重新创建。",
"복사 · 이동 {0}개": "复制 · 移动 {0} 个",
"복사 · 이동 {0}개 · {1}%": "复制 · 移动 {0} 个 · {1}%",
"복사 · 이동 {0}개가 아직 끝나지 않았습니다. 끝내면 멈추고, 복사하던 파일은 완성되지 않은 채로 남지 않게 지웁니다.": "{0} 个复制 · 移动尚未完成。退出会停止它们,并删除正在复制的文件,以免留下不完整的文件。",
"복사 · 이동 끝": "复制 · 移动 已完成",
"복사 · 이동 멈춤 - 눌러서 보기": "复制 · 移动已停止 - 点按查看",
"복사 · 이동 중입니다": "正在复制 · 移动",
"복사 · 이동: 받는 쪽 파일이 더 새것이면 건너뜁니다 (예전에는 예전 원본으로 덮어쓰고, 이동이면 원본도 지웠습니다). 건너뛴 파일은 원본에 남고 끝 알림에 그 수가 나옵니다. 되돌리기: 환경 설정 > 파일 탐색기 (또는 Rsync) > 받는 쪽이 더 새것이면 건너뛰기": "复制 · 移动:接收端文件较新时跳过(以前会用旧的源文件覆盖,移动时还会删除源)。跳过的文件留在源中,完成通知中会显示数量。恢复:设置 > 文件浏览器(或 Rsync)> 接收端较新时跳过",
"복사 · 이동은 두 창에서 씁니다 (창 배치 > 두 창).": "复制 · 移动需在双窗格中使用 (窗格布局 > 双窗格)。",
@ -1377,6 +1380,7 @@
"수정 · 이동": "编辑 · 移动",
"수정한 날짜": "修改日期",
"숨겨도 위쪽 ⋮ 메뉴에서 창 배치 · 버튼 구성을 바꿀 수 있습니다.": "即使隐藏,也可以在顶部 ⋮ 菜单中更改窗格布局 · 按钮配置。",
"숨기기": "隐藏",
"숨긴 항목 (. 으로 시작) 보이기": "显示隐藏项目 (以 . 开头)",
"숨긴 항목 숨기기": "隐藏隐藏项目",
"숨김": "隐藏",
@ -2115,6 +2119,7 @@
"직접 지정 (기본)": "手动指定 (默认)",
"진행 중인 작업 없음": "没有进行中的任务",
"진행 중인 작업이 있습니다: {0}\n중지하고 끝낼까요?": "有正在进行的任务: {0}\n要停止并退出吗?",
"진행 패널 보기": "显示进度面板",
"집 NAS 처럼 자체 서명 인증서면 [서버 설정 고치기] 에서 \"인증서 확인 안 함\" 을 켜세요.": "如果是自签名证书 (如家用 NAS),请在 [修改服务器设置] 中开启“不验证证书”。",
"짧을수록 빨리 맞추지만 배터리를 더 씁니다.": "间隔越短同步越快,但更耗电。",
"차례 기다림": "排队等待",

View File

@ -35,6 +35,13 @@ class CopyCenter extends ChangeNotifier {
/// 지금 도는 복사 · 이동 수 (끝낼 때 확인 · Android 작업 알림에)
int get activeCount => jobs.values.where((j) => !j.finished).length;
/// 85: 지금 도는 복사 · 이동 전체의 진행률 (0~1, 도는 것이 없거나 아직 세는 중이면 null) - Android 알림 · 숨긴 패널의 작은 표시
double? get activeProgress {
final run = [for (final j in jobs.values) if (!j.finished) j];
if (run.isEmpty || run.any((j) => j.counting)) return null;
return run.fold<double>(0, (a, j) => a + j.overall) / run.length;
}
/// 이미 만들어진 것 (없으면 null - 새로 만들지 않음)
static CopyCenter? peekOf(AppController c) => _instance != null && _instance!.c == c ? _instance : null;
bool get anyRunning => jobs.values.any((j) => !j.finished);

View File

@ -425,6 +425,9 @@ class AppSettings {
/// 82: 창 사이 끌어 놓기 - 'ask' 묻기 (처음 값, 관리자 판단) · 'copy' 복사 · 'move' 이동
String explorerDropAction = 'ask';
/// 85: 탐색기의 복사 · 이동 진행 패널을 숨김 (아래 작은 표시만). 처음 값: 보임
bool explorerProgressHidden = false;
bool explorerShowHidden = false;
// ── 복사 · 이동 (파일 탐색기) · rsync · lsync (Rsync 화면) ──
@ -745,6 +748,7 @@ class AppSettings {
'explorerSortDesc': explorerSortDesc,
'explorerFolderSize': explorerFolderSize,
'explorerDropAction': explorerDropAction,
'explorerProgressHidden': explorerProgressHidden,
'explorerSortPerFolder': explorerSortPerFolder,
'explorerFolderSorts': explorerFolderSorts,
'explorerShowHidden': explorerShowHidden,
@ -962,6 +966,7 @@ class AppSettings {
..explorerSortDesc = j['explorerSortDesc'] as bool? ?? false
..explorerFolderSize = const ['sort', 'always', 'off'].contains(j['explorerFolderSize']) ? j['explorerFolderSize'] as String : 'sort'
..explorerSortPerFolder = j['explorerSortPerFolder'] == true
..explorerProgressHidden = j['explorerProgressHidden'] == true
..explorerDropAction = const ['ask', 'copy', 'move'].contains(j['explorerDropAction']) ? j['explorerDropAction'] as String : 'ask'
..explorerFolderSorts = {
if (j['explorerFolderSorts'] is Map)

View File

@ -95,9 +95,12 @@ class AndroidKeepAlive {
_ai = store?..addListener(_changed);
}
final ai = [AiJobs.instance.statusLine, store?.statusLine].nonNulls.join(' · ').trim();
var (text, progress) =
status(c.currentJob, c.busy, running, downloads.overallProgress,
syncs: syncs, syncing: live?.anyRunning ?? false, copies: copying, stopped: live?.problems.length ?? 0);
var (text, progress) = status(c.currentJob, c.busy, running, downloads.overallProgress,
syncs: syncs,
syncing: live?.anyRunning ?? false,
copies: copying,
copyProgress: copies?.activeProgress,
stopped: live?.problems.length ?? 0);
if (ai.isNotEmpty) {
// 진행 알림에 남은 장 수와 예상 시간 (발열 · 배터리 때문에 쉬어 가지는 않는다 - 사용자 결정)
text = text == null ? ai : '$ai · $text';
@ -124,18 +127,25 @@ class AndroidKeepAlive {
/// 알림 글과 진행률 (0~100, 모르면 -1). 진행 중인 일이 없으면 글이 null.
/// [syncs] 백그라운드로 지켜보는 실시간 동기화 수 ([syncing] 지금 맞추는 중)
static (String?, int) status(String? job, bool busy, int downloads, double? downloadProgress,
{int syncs = 0, bool syncing = false, int copies = 0, int stopped = 0}) {
{int syncs = 0, bool syncing = false, int copies = 0, double? copyProgress, int stopped = 0}) {
final parts = [
// 68: 원본을 읽지 못해 멈춘 동기화 (화면을 보지 않아도 알 수 있게 맨 앞에)
if (stopped > 0) trf('⚠ 동기화 멈춤 {0}개 · 원본 확인 필요', [stopped]),
if (busy) job ?? tr('작업 중'),
if (copies > 0) trf('복사 · 이동 {0}개', [copies]),
// 85: 복사 · 이동 진행률도 알림에 (탐색기의 진행 패널을 숨겨도 보이게)
if (copies > 0)
copyProgress == null ? trf('복사 · 이동 {0}개', [copies]) : trf('복사 · 이동 {0}개 · {1}%', [copies, (copyProgress * 100).round()]),
if (downloads > 0) trf('다운로드 {0}개{1}', [downloads, downloadProgress == null ? '' : ' · ${(downloadProgress * 100).round()}%']),
if (syncs > 0) syncing ? trf('동기화 {0}개 · 맞추는 중', [syncs]) : trf('동기화 {0}개 지켜보는 중', [syncs]),
];
if (parts.isEmpty) return (null, -1);
// 진행률 막대는 다운로드만 있을 때 (작업 진행률은 동영상마다 따로라 하나로 합치기 어렵다)
final p = !busy && downloadProgress != null ? (downloadProgress * 100).round().clamp(0, 100) : -1;
// 진행률 막대는 다운로드만 있을 때 (작업 진행률은 동영상마다 따로라 하나로 합치기 어렵다).
// 85: 다운로드가 없으면 복사 · 이동 진행률
final p = !busy && downloadProgress != null
? (downloadProgress * 100).round().clamp(0, 100)
: !busy && downloads == 0 && copyProgress != null
? (copyProgress * 100).round().clamp(0, 100)
: -1;
return (parts.join(' · '), p);
}
}

View File

@ -2320,7 +2320,7 @@ class _ExplorerPageState extends State<ExplorerPage> {
}
x.changed();
}
_snack(error is FileOpCancelled
final doneText = error is FileOpCancelled
? tr('취소했습니다.')
: error != null
? trf('끝나지 못했습니다: {0}', [error])
@ -2331,7 +2331,23 @@ class _ExplorerPageState extends State<ExplorerPage> {
if (!move && job.keptNewer > 0) trf('받는 쪽이 더 새것 {0}개 건너뜀', [job.keptNewer]),
if (job.skipped.isNotEmpty) trf('같은 이름이라 건너뜀: {0}', [_namesOf(job.skipped)]),
if (skippedHere.isNotEmpty) trf('이미 이 폴더에 있어 건너뜀: {0}', [_namesOf(skippedHere)]),
].join(' · '));
].join(' · ');
// 85: 끝나면 [폴더 열기] - 앱 탐색기에서 넣은 폴더로 (그 폴더를 보고 있는 창, 없으면 지금 창)
if (error == null && mounted) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(doneText),
action: SnackBarAction(
label: tr('폴더 열기'),
onPressed: () {
final show = _panes.where((x) => samePath(x.current, dest)).firstOrNull ?? _pane;
setState(() => _active = _panes.indexOf(show));
unawaited(_goTo(show, dest, fresh: true));
},
),
));
} else {
_snack(doneText);
}
// 82: 끌어 놓기의 이동 되돌리기 (끝난 알림 바로 뒤에 - 진행 막대가 내려가기를 기다리지 않게)
if (error == null && mounted) onFinished?.call(job);
// 다 되면 진행 막대가 잠깐 100% 를 보인 뒤 내려간다
@ -2624,6 +2640,58 @@ class _ExplorerPageState extends State<ExplorerPage> {
/// 아래에서 올라오는 진행 막대 (위: 전체 항목 중 · 아래: 지금 폴더의 파일 중)
Widget _transferPanel() {
final jobs = _jobs;
// 85: 숨겼으면 오른쪽 아래 작은 표시 "복사 · 이동 n개 · 45%" (누르면 다시 펼침)
if (jobs.isNotEmpty && c.settings.explorerProgressHidden) {
return Align(
alignment: Alignment.bottomRight,
child: Padding(
padding: const EdgeInsets.only(bottom: 8),
child: ListenableBuilder(
listenable: Listenable.merge(jobs),
builder: (context, _) {
final run = [for (final j in jobs) if (!j.finished) j];
// 관리자 판단: 숨겨도 멈춘 (실패한) 것은 분명히 - 빨간 표시 (끝난 알림 · 묻는 창은 숨김과 상관없이 늘 뜬다)
final failed = jobs.any((j) => j.finished && j.error != null && j.error is! FileOpCancelled);
final pct = run.isEmpty || run.any((j) => j.counting)
? null
: (run.fold<double>(0, (a, j) => a + j.overall) / run.length * 100).round();
return Material(
elevation: 6,
color: failed ? JjColors.danger.withValues(alpha: 0.25) : JjColors.panelHigh,
borderRadius: BorderRadius.circular(18),
child: InkWell(
borderRadius: BorderRadius.circular(18),
onTap: () => c.updateSettings((x) => x.explorerProgressHidden = false),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
child: Row(mainAxisSize: MainAxisSize.min, children: [
SizedBox(
width: 14,
height: 14,
child: CircularProgressIndicator(strokeWidth: 2, value: run.isEmpty ? 1 : (pct == null ? null : pct / 100)),
),
const SizedBox(width: 8),
Text(
failed
? tr('복사 · 이동 멈춤 - 눌러서 보기')
: run.isEmpty
? tr('복사 · 이동 끝')
: pct == null
? trf('복사 · 이동 {0}개', [run.length])
: trf('복사 · 이동 {0}개 · {1}%', [run.length, pct]),
style: const TextStyle(fontSize: 12.5),
),
const SizedBox(width: 4),
Tooltip(message: tr('진행 패널 보기'), child: const Icon(Icons.expand_less, size: 18)),
]),
),
),
);
},
),
),
);
}
return AnimatedSlide(
offset: jobs.isEmpty ? const Offset(0, 1.2) : Offset.zero,
duration: const Duration(milliseconds: 250),
@ -2641,6 +2709,19 @@ class _ExplorerPageState extends State<ExplorerPage> {
constraints: BoxConstraints(maxHeight: MediaQuery.sizeOf(context).height * 0.45),
child: SingleChildScrollView(
child: Column(mainAxisSize: MainAxisSize.min, children: [
// 85: 숨기기 (아래 작은 표시로) - 다른 파일을 보면서 기다릴 수 있게. Android 는 알림줄에도 진행률
Align(
alignment: Alignment.centerRight,
child: SizedBox(
height: 28,
child: TextButton.icon(
style: TextButton.styleFrom(visualDensity: VisualDensity.compact),
onPressed: () => c.updateSettings((x) => x.explorerProgressHidden = true),
icon: const Icon(Icons.expand_more, size: 18),
label: Text(tr('숨기기'), style: const TextStyle(fontSize: 12)),
),
),
),
for (final (k, job) in jobs.indexed) ...[
if (k > 0) const Divider(height: 18),
ListenableBuilder(listenable: job, builder: (context, _) => _jobView(job)),

View File

@ -1102,6 +1102,32 @@ void main() {
});
});
testWidgets('85: 진행 패널 [숨기기] → 아래 작은 표시 (누르면 다시) · 끝난 알림의 [폴더 열기]', (tester) async {
await open(tester);
await act(tester, () => tester.tap(find.text('doc.txt')));
await settle(tester, () => false, rounds: 15);
await act(tester, () => tester.tap(find.text('복사').first));
await calm(tester);
await act(tester, () => tester.tap(find.widgetWithText(FilledButton, '복사')));
await settle(tester, () => File(p.join(right, 'doc.txt')).existsSync() && find.text('폴더 열기').evaluate().isNotEmpty);
expect(find.text('폴더 열기'), findsOneWidget, reason: '끝난 알림에 [폴더 열기]');
// 패널은 끝난 뒤 잠깐 남는다 - [숨기기]
expect(find.text('숨기기'), findsOneWidget);
await act(tester, () => tester.tap(find.text('숨기기')));
await calm(tester);
expect(c.settings.explorerProgressHidden, isTrue, reason: '숨김은 기억');
expect(find.text('숨기기'), findsNothing);
expect(find.text('복사 · 이동 끝'), findsOneWidget, reason: '아래 작은 표시');
// (아래 알림이 잠깐 작은 표시를 덮는다 - 알림을 닫고 누름)
ScaffoldMessenger.of(tester.element(find.byType(ExplorerPage))).clearSnackBars();
await calm(tester);
await act(tester, () => tester.tap(find.text('복사 · 이동 끝')));
await calm(tester);
expect(c.settings.explorerProgressHidden, isFalse, reason: '누르면 다시 펼침');
ScaffoldMessenger.of(tester.element(find.byType(ExplorerPage))).clearSnackBars();
await calm(tester);
});
testWidgets('81: Space 로 빠른 보기 (글 파일 앞부분) · 필터에 치는 중에는 그냥 빈칸 · TC 는 F3', (tester) async {
c.settings.explorerStyle = 'windows';
await open(tester);

View File

@ -14,5 +14,10 @@ void main() {
// 백그라운드로 실행: 실시간 동기화를 지켜보는 동안에도
expect(AndroidKeepAlive.status(null, false, 0, null, syncs: 2), ('동기화 2개 지켜보는 중', -1));
expect(AndroidKeepAlive.status('MKV 만들기', true, 0, null, syncs: 1, syncing: true), ('MKV 만들기 · 동기화 1개 · 맞추는 중', -1));
// 85: 복사 · 이동 진행률 - 다운로드가 없으면 막대도
expect(AndroidKeepAlive.status(null, false, 0, null, copies: 1, copyProgress: 0.4), ('복사 · 이동 1개 · 40%', 40));
expect(AndroidKeepAlive.status(null, false, 0, null, copies: 2), ('복사 · 이동 2개', -1), reason: '세는 중 (모름)');
expect(AndroidKeepAlive.status(null, false, 1, 0.5, copies: 1, copyProgress: 0.1), ('복사 · 이동 1개 · 10% · 다운로드 1개 · 50%', 50),
reason: '막대는 다운로드가 먼저');
});
}