154 lines
6.2 KiB
Dart
154 lines
6.2 KiB
Dart
import 'package:flutter/material.dart';
|
|
|
|
import '../app/app_controller.dart';
|
|
import '../platform/windows/cef_runtime.dart';
|
|
import 'theme.dart';
|
|
import '../l10n/tr.dart';
|
|
|
|
/// 환경 설정에서 "Chrome (내장)" 을 골랐을 때: 엔진이 없으면 내려받고, 설정을 바꾼 뒤 다시 시작을 권한다.
|
|
/// 끝까지 진행했으면 true (설정이 'chrome' 으로 바뀜).
|
|
Future<bool> chooseChromeEngine(BuildContext context, AppController c) async {
|
|
if (!CefRuntime.installed) {
|
|
final ok = await showDialog<bool>(
|
|
context: context,
|
|
builder: (ctx) => AlertDialog(
|
|
scrollable: true,
|
|
title: Text(tr('내장 Chrome 엔진 내려받기')),
|
|
content: SizedBox(
|
|
width: 460,
|
|
child: Text(
|
|
trf('Chrome 엔진 (CEF {0}) 을 공식 배포처에서 내려받습니다.\n' '· 받을 크기: 약 {1}MB (설치 후 약 390MB)\n' '· 설치 위치: 프로그램 폴더의 Lib\\cef\n' '· 설치한 뒤 프로그램을 다시 시작하면 앱 안 브라우저가 Chrome 엔진으로 바뀝니다.\n\n' '참고: Google 은 이런 내장 브라우저의 로그인을 막을 수 있습니다. ' 'YouTube 로그인이 필요하면 Edge 엔진을 쓰세요 (언제든 다시 바꿀 수 있습니다).', [CefRuntime.version, CefRuntime.approxDownloadMb]),
|
|
style: TextStyle(fontSize: 13),
|
|
),
|
|
),
|
|
actions: [
|
|
TextButton(onPressed: () => Navigator.pop(ctx, false), child: Text(tr('취소'))),
|
|
FilledButton(onPressed: () => Navigator.pop(ctx, true), child: Text(tr('내려받기'))),
|
|
],
|
|
),
|
|
);
|
|
if (ok != true || !context.mounted) return false;
|
|
final installed = await showDialog<bool>(
|
|
context: context,
|
|
barrierDismissible: false,
|
|
builder: (_) => _InstallProgress(c: c),
|
|
);
|
|
if (installed != true || !context.mounted) return false;
|
|
}
|
|
await c.updateSettings((s) => s.browserEngine = 'chrome');
|
|
if (!context.mounted) return true;
|
|
if (!CefRuntime.readyThisRun) {
|
|
final restart = await showDialog<bool>(
|
|
context: context,
|
|
builder: (ctx) => AlertDialog(
|
|
scrollable: true,
|
|
title: Text(tr('다시 시작')),
|
|
content: Text(tr('Chrome 엔진은 프로그램을 다시 시작하면 쓸 수 있습니다. 지금 다시 시작할까요?')),
|
|
actions: [
|
|
TextButton(onPressed: () => Navigator.pop(ctx, false), child: Text(tr('나중에'))),
|
|
FilledButton(onPressed: () => Navigator.pop(ctx, true), child: Text(tr('다시 시작'))),
|
|
],
|
|
),
|
|
);
|
|
if (restart == true) await c.services.shell.restart();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
class _InstallProgress extends StatefulWidget {
|
|
final AppController c;
|
|
const _InstallProgress({required this.c});
|
|
|
|
@override
|
|
State<_InstallProgress> createState() => _InstallProgressState();
|
|
}
|
|
|
|
class _InstallProgressState extends State<_InstallProgress> {
|
|
double _p = 0;
|
|
String _stage = tr('준비 중');
|
|
String? _error;
|
|
bool _cancel = false;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_run();
|
|
}
|
|
|
|
Future<void> _run() async {
|
|
widget.c.note(trf('내장 Chrome 엔진 내려받기 시작: {0}', [CefRuntime.downloadUri]));
|
|
try {
|
|
await CefRuntime.install(
|
|
onProgress: (p, stage) {
|
|
if (mounted) {
|
|
setState(() {
|
|
_p = p;
|
|
_stage = stage;
|
|
});
|
|
}
|
|
},
|
|
isCancelled: () => _cancel,
|
|
);
|
|
widget.c.note(trf('내장 Chrome 엔진 설치 완료 ({0}MB): {1}', [CefRuntime.installedMb(), CefRuntime.dir]));
|
|
if (mounted) Navigator.pop(context, true);
|
|
} catch (e) {
|
|
widget.c.note(trf('내장 Chrome 엔진 설치 실패: {0}', [e]));
|
|
if (mounted) setState(() => _error = '$e');
|
|
}
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) => AlertDialog(
|
|
scrollable: true,
|
|
title: Text(tr('내장 Chrome 엔진')),
|
|
content: SizedBox(
|
|
width: 420,
|
|
child: Column(mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [
|
|
if (_error == null) ...[
|
|
Text('$_stage ${(_p * 100).round()}%'),
|
|
const SizedBox(height: 8),
|
|
LinearProgressIndicator(value: _p <= 0 ? null : _p),
|
|
] else
|
|
Text(trf('설치하지 못했습니다.\n{0}', [_error]), style: const TextStyle(color: JjColors.danger)),
|
|
]),
|
|
),
|
|
actions: [
|
|
if (_error == null)
|
|
TextButton(onPressed: () => setState(() => _cancel = true), child: Text(tr('취소')))
|
|
else
|
|
TextButton(onPressed: () => Navigator.pop(context, false), child: Text(tr('닫기'))),
|
|
],
|
|
);
|
|
}
|
|
|
|
/// 207: 관리자 권한으로 실행 중에 내장 Chrome 엔진을 쓰겠다고 할 때 - 위험을 알리고 확인을 받은 뒤에만 설정을 켠다
|
|
Future<bool> confirmCefWhenElevated(BuildContext context, AppController c) async {
|
|
final ok = await showDialog<bool>(
|
|
context: context,
|
|
builder: (ctx) => AlertDialog(
|
|
scrollable: true,
|
|
title: Text(tr('관리자 권한일 때도 Chrome 엔진 쓰기')),
|
|
content: SizedBox(
|
|
width: 480,
|
|
child: Text(tr('이 프로그램이 관리자 권한으로 실행 중입니다. 권장하지 않습니다.\n\n'
|
|
'· 내장 Chrome 엔진은 샌드박스 (웹 페이지를 가두는 보호) 가 꺼져 있어, 웹 페이지가 관리자 권한 프로세스 안에서 돕니다. '
|
|
'페이지의 취약점이 곧 이 PC 의 관리자 권한이 될 수 있습니다.\n'
|
|
'· Edge 엔진은 이 영향이 없습니다.\n'
|
|
'· 관리자 권한 없이 프로그램을 실행하면 이 설정 없이도 Chrome 엔진을 쓸 수 있습니다.')),
|
|
),
|
|
actions: [
|
|
TextButton(onPressed: () => Navigator.pop(ctx, false), child: Text(tr('취소'))),
|
|
FilledButton(
|
|
style: FilledButton.styleFrom(backgroundColor: JjColors.danger),
|
|
onPressed: () => Navigator.pop(ctx, true),
|
|
child: Text(tr('그래도 쓰기')),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
if (ok != true) return false;
|
|
await c.updateSettings((x) => x.cefWhenElevated = true);
|
|
c.note(tr('관리자 권한일 때도 Chrome 엔진 쓰기를 켰습니다 (권장하지 않음).'));
|
|
return true;
|
|
}
|