JJ_MKVMaker/lib/platform/windows/window_memory.dart

91 lines
3.0 KiB
Dart

import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:flutter/painting.dart';
import 'package:screen_retriever/screen_retriever.dart';
import 'package:window_manager/window_manager.dart';
/// 창 위치 · 크기 · 최대화 여부를 기억했다가 다음에 같은 자리에서 연다.
///
/// [key] 별로 따로 기억한다 ('main' = 원래 창, 'second' = 탐색기에서 연 새 창).
/// 전체 화면 · 팝업 보기 · 최소화 상태에서는 저장하지 않는다 (그 전의 보통 크기를 유지).
class WindowMemory with WindowListener {
final String file;
final String key;
Timer? _debounce;
/// 팝업 보기처럼 창 크기를 잠깐 바꾸는 동안 true 로 두면 저장하지 않는다
bool Function()? paused;
WindowMemory(this.file, this.key);
Map<String, dynamic> _readAll() {
try {
return jsonDecode(File(file).readAsStringSync()) as Map<String, dynamic>;
} catch (_) {
return {};
}
}
/// 저장된 자리로 옮기고, 이후 움직이거나 크기를 바꾸면 자동 저장
Future<void> restoreAndWatch() async {
try {
final m = _readAll()[key];
if (m is Map) {
final r = Rect.fromLTWH((m['x'] as num).toDouble(), (m['y'] as num).toDouble(),
(m['w'] as num).toDouble(), (m['h'] as num).toDouble());
// 모니터를 뺐거나 해상도가 바뀌어 화면 밖이면 옮기지 않는다
if (r.width >= 400 && r.height >= 300 && await _visible(r)) {
await windowManager.setBounds(r);
if (m['max'] == true) await windowManager.maximize();
}
}
} catch (_) {}
windowManager.addListener(this);
}
static Future<bool> _visible(Rect r) async {
for (final d in await screenRetriever.getAllDisplays()) {
final area = (d.visiblePosition ?? Offset.zero) & (d.visibleSize ?? d.size);
final hit = area.intersect(r);
if (hit.width >= 200 && hit.height >= 100) return true;
}
return false;
}
Future<void> save() async {
try {
if (paused?.call() ?? false) return;
if (await windowManager.isFullScreen() || await windowManager.isMinimized()) return;
if (!await windowManager.isVisible()) return;
final max = await windowManager.isMaximized();
final all = _readAll();
final old = all[key];
if (max && old is Map) {
// 최대화: 보통 크기는 그대로 두고 표시만
all[key] = {...old, 'max': true};
} else {
final b = await windowManager.getBounds();
all[key] = {'x': b.left, 'y': b.top, 'w': b.width, 'h': b.height, 'max': max};
}
final tmp = File('$file.$pid.tmp')..writeAsStringSync(jsonEncode(all), flush: true);
tmp.renameSync(file);
} catch (_) {}
}
void _later() {
_debounce?.cancel();
_debounce = Timer(const Duration(milliseconds: 500), save);
}
@override
void onWindowMoved() => _later();
@override
void onWindowResized() => _later();
@override
void onWindowMaximize() => _later();
@override
void onWindowUnmaximize() => _later();
}