import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import '../app/app_controller.dart'; import '../app/download_manager.dart'; import '../app/copy_center.dart'; import '../app/live_sync.dart'; import '../services/downloader.dart' show DownloadState; import '../l10n/tr.dart'; /// 끝내기 전에: 복사 · 이동이 돌고 있으면 묻는다 (멈추면 그 파일은 만들다 만 .jjpart 로 남지 않게 지운다). 끝내도 되면 true Future confirmStopCopies(BuildContext context, AppController c) async { final n = CopyCenter.peekOf(c)?.activeCount ?? 0; if (n == 0) return true; final go = await showDialog( context: context, builder: (ctx) => AlertDialog( scrollable: true, title: Text(tr('복사 · 이동 중입니다')), content: Text(trf('복사 · 이동 {0}개가 아직 끝나지 않았습니다. 끝내면 멈추고, 복사하던 파일은 완성되지 않은 채로 남지 않게 지웁니다.', [n])), actions: [ TextButton(onPressed: () => Navigator.pop(ctx, false), child: Text(tr('취소'))), FilledButton(onPressed: () => Navigator.pop(ctx, true), child: Text(tr('끝내기'))), ], ), ); if (go == true) { for (final j in CopyCenter.peekOf(c)!.jobs.values) { if (!j.finished) j.cancel(); } } return go == true; } /// Android 첫 화면에서 ← 로 앱을 끝낼 때: "백그라운드로 실행" 이 꺼져 있고 작업 (MKV · AI 자막 · 다운로드 · 실시간 동기화) 이 /// 돌고 있으면 그냥 끝내지 않고 묻는다 (멈추면 작업이 사라지므로). 백그라운드로 실행이 켜져 있으면 앱은 뒤로 가고 작업은 계속된다. class ExitGuard extends StatelessWidget { final AppController c; final DownloadManager? downloads; final Widget child; const ExitGuard({super.key, required this.c, this.downloads, required this.child}); static const _ch = MethodChannel('jj_mkvmaker/android'); /// 돌고 있는 작업 (글로) List _running() { final live = LiveSync.instance; final dl = downloads?.tasks.where((t) => t.state == DownloadState.downloading || t.state == DownloadState.queued).length ?? 0; final copies = CopyCenter.peekOf(c)?.activeCount ?? 0; return [ if (c.busy) c.currentJob ?? tr('MKV · AI 작업'), if (copies > 0) trf('복사 · 이동 {0}개', [copies]), if (dl > 0) trf('다운로드 {0}개', [dl]), if (live != null && live.watching.isNotEmpty) trf('실시간 동기화 {0}쌍', [live.watching.length]), ]; } bool get _guard => c.services.platform.isAndroid && !c.settings.run.inBackground && _running().isNotEmpty; @override Widget build(BuildContext context) => ListenableBuilder( listenable: c, builder: (context, _) => PopScope( canPop: !_guard, onPopInvokedWithResult: (didPop, _) async { if (didPop) return; final running = _running(); final pick = await showDialog( context: context, builder: (ctx) => AlertDialog( scrollable: true, title: Text(tr('작업이 진행 중입니다')), content: Column(mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ for (final r in running) Text('• $r'), const SizedBox(height: 10), Text(tr('"백그라운드로 실행" 이 꺼져 있어 앱을 끝내면 작업이 멈춥니다.')), ]), actions: [ TextButton(onPressed: () => Navigator.pop(ctx), child: Text(tr('취소'))), TextButton(onPressed: () => Navigator.pop(ctx, 'exit'), child: Text(tr('끝내기 (작업 멈춤)'))), FilledButton(onPressed: () => Navigator.pop(ctx, 'back'), child: Text(tr('뒤로 보내고 계속'))), ], ), ); if (pick == 'back') { try { await _ch.invokeMethod('moveToBack'); } catch (_) {} } else if (pick == 'exit') { await SystemNavigator.pop(); } }, child: child, ), ); }