137 lines
4.6 KiB
Dart
137 lines
4.6 KiB
Dart
import 'dart:async';
|
|
import 'dart:io';
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:path/path.dart' as p;
|
|
|
|
import 'app/app_controller.dart';
|
|
import 'app/download_manager.dart';
|
|
import 'app/settings.dart';
|
|
import 'core/playlist.dart';
|
|
import 'platform/windows/single_instance.dart';
|
|
import 'services/platform_services.dart';
|
|
import 'ui/ai_dialog.dart';
|
|
import 'ui/downloads_page.dart';
|
|
import 'ui/home_page.dart';
|
|
import 'ui/player_page.dart';
|
|
import 'ui/setup_dialog.dart';
|
|
import 'ui/update_dialog.dart';
|
|
import 'ui/theme.dart';
|
|
|
|
Future<void> main(List<String> args) async {
|
|
WidgetsFlutterBinding.ensureInitialized();
|
|
|
|
// 이미 실행 중이면 인수(탐색기에서 고른 파일)를 넘기고 끝낸다
|
|
final instance = SingleInstance();
|
|
if (!await instance.claim(LaunchRequest.parse(args), waitForExit: args.contains('--restart'))) {
|
|
exit(0);
|
|
}
|
|
|
|
final services = PlatformServices.create();
|
|
final controller = AppController(services, settingsStore: SettingsStore());
|
|
await controller.init();
|
|
|
|
final downloads = DownloadManager(
|
|
backends: services.createDownloadBackends?.call(() => controller.settings) ?? const [],
|
|
settings: () => controller.settings,
|
|
);
|
|
final navigatorKey = GlobalKey<NavigatorState>();
|
|
final messengerKey = GlobalKey<ScaffoldMessengerState>();
|
|
|
|
/// 종료 요청 (창 X · 트레이 종료 · 종료 버튼): 다운로드 중이면 확인
|
|
Future<bool> confirmQuit() async {
|
|
final ctx = navigatorKey.currentContext;
|
|
if (ctx != null && !await confirmExit(ctx, downloads)) return false;
|
|
await downloads.shutdown();
|
|
return true;
|
|
}
|
|
|
|
await services.shell.init(
|
|
hotkey: controller.settings.showHotkey,
|
|
minimizeToTray: () => controller.settings.minimizeToTray,
|
|
onCloseRequested: confirmQuit,
|
|
onDownloadsRequested: () => navigatorKey.currentState
|
|
?.push(MaterialPageRoute<void>(builder: (_) => DownloadsPage(d: downloads))),
|
|
);
|
|
|
|
// 클립보드로 추가된 다운로드 알림 · 트레이 글
|
|
downloads.onAdded.listen((t) => messengerKey.currentState
|
|
?.showSnackBar(SnackBar(content: Text('다운로드 추가: ${t.source}'))));
|
|
downloads.addListener(() {
|
|
final n = downloads.downloadingCount;
|
|
services.shell.setTooltip(n > 0 ? 'JJ_MKVMaker - 다운로드 $n개' : 'JJ_MKVMaker');
|
|
});
|
|
unawaited(downloads.startClipboardWatch());
|
|
|
|
// 탐색기 메뉴 · 두 번째 실행에서 온 요청 처리
|
|
instance.listen((req) async {
|
|
await services.shell.show();
|
|
final ctx = navigatorKey.currentContext;
|
|
if (ctx == null || req.files.isEmpty) return;
|
|
if (!ctx.mounted) return;
|
|
switch (req.action) {
|
|
case LaunchAction.play:
|
|
await playFiles(ctx, controller, req.files);
|
|
case LaunchAction.subtitle:
|
|
await controller.addVideos(req.files.where(isVideoFile).toList());
|
|
final targets = controller.videos
|
|
.where((v) => req.files.any((f) => p.equals(f, v.path)))
|
|
.toList();
|
|
if (targets.isNotEmpty && ctx.mounted) {
|
|
controller.select(targets.first);
|
|
await showAiDialog(ctx, controller, targets.first, targets: targets);
|
|
}
|
|
case LaunchAction.add:
|
|
await controller.addVideos(req.files.where(isVideoFile).toList());
|
|
}
|
|
});
|
|
|
|
controller.confirmQuit = confirmQuit;
|
|
|
|
// 처음 화면이 뜬 뒤: 필수 프로그램 점검 (없으면 물어보고 설치) → 새 버전 확인 (하루 한 번)
|
|
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
|
final ctx = navigatorKey.currentContext;
|
|
if (ctx == null) return;
|
|
await checkRequiredTools(ctx, services.shell);
|
|
final ctx2 = navigatorKey.currentContext;
|
|
if (ctx2 != null && ctx2.mounted) await checkForUpdate(ctx2, controller);
|
|
});
|
|
|
|
runApp(JjCapCutApp(
|
|
controller: controller,
|
|
downloads: downloads,
|
|
navigatorKey: navigatorKey,
|
|
messengerKey: messengerKey,
|
|
onExit: () async {
|
|
if (await confirmQuit()) await services.shell.quit();
|
|
},
|
|
));
|
|
}
|
|
|
|
class JjCapCutApp extends StatelessWidget {
|
|
final AppController controller;
|
|
final DownloadManager? downloads;
|
|
final GlobalKey<NavigatorState>? navigatorKey;
|
|
final GlobalKey<ScaffoldMessengerState>? messengerKey;
|
|
final VoidCallback? onExit;
|
|
|
|
const JjCapCutApp({
|
|
super.key,
|
|
required this.controller,
|
|
this.downloads,
|
|
this.navigatorKey,
|
|
this.messengerKey,
|
|
this.onExit,
|
|
});
|
|
|
|
@override
|
|
Widget build(BuildContext context) => MaterialApp(
|
|
title: 'JJ_MKVMaker',
|
|
debugShowCheckedModeBanner: false,
|
|
theme: buildTheme(),
|
|
navigatorKey: navigatorKey,
|
|
scaffoldMessengerKey: messengerKey,
|
|
home: HomePage(c: controller, downloads: downloads, onExit: onExit),
|
|
);
|
|
}
|