128 lines
5.6 KiB
Dart
128 lines
5.6 KiB
Dart
import 'dart:io';
|
|
import 'dart:typed_data';
|
|
import 'dart:ui' as ui;
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter/rendering.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:integration_test/integration_test.dart';
|
|
import 'package:jj_mkvmaker/app/app_controller.dart';
|
|
import 'package:jj_mkvmaker/ui/app_actions.dart';
|
|
import 'package:jj_mkvmaker/app/subtitle_editor_controller.dart';
|
|
import 'package:jj_mkvmaker/core/app_manager.dart';
|
|
import 'package:jj_mkvmaker/core/dlna.dart';
|
|
import 'package:jj_mkvmaker/core/languages.dart';
|
|
import 'package:jj_mkvmaker/core/models.dart';
|
|
import 'package:jj_mkvmaker/core/srt.dart';
|
|
import 'package:jj_mkvmaker/platform/windows/desktop_storage_service.dart';
|
|
import 'package:jj_mkvmaker/platform/windows/process_media_tool.dart';
|
|
import 'package:jj_mkvmaker/services/platform_services.dart';
|
|
import 'package:jj_mkvmaker/ui/app_manager_page.dart';
|
|
import 'package:jj_mkvmaker/ui/dlna_page.dart';
|
|
import 'package:jj_mkvmaker/ui/subtitle_editor_page.dart';
|
|
import 'package:jj_mkvmaker/ui/theme.dart';
|
|
import 'package:jj_mkvmaker/ui/tor_page.dart';
|
|
import 'package:path/path.dart' as p;
|
|
|
|
/// ⑦ 밝은 화면 (관리자 지시 10/21): 캡처가 없던 화면 (DLNA · 앱 관리자 · Tor · 자막 편집) 을 PNG 로 (JJ_SHOT_DIR, JJ_SHOT_THEME=light).
|
|
/// 기기 · 네트워크 대신 가짜를 쓰고, 설정은 메모리에만
|
|
class _Apps implements AppManagerBackend {
|
|
@override
|
|
Future<List<InstalledApp>> list() async => [
|
|
for (final (i, n) in ['카메라', 'Chrome', 'JJ_MKVMaker', '메모'].indexed)
|
|
InstalledApp(
|
|
package: 'com.x.$i',
|
|
label: n,
|
|
version: '1.$i',
|
|
apk: '',
|
|
installed: DateTime(2026, 1, i + 1),
|
|
updated: DateTime(2026, 2, i + 1),
|
|
size: (i + 1) * 12000000,
|
|
system: i == 0,
|
|
splits: 0),
|
|
];
|
|
@override
|
|
Future<Uint8List?> icon(String package) async => null;
|
|
@override
|
|
Future<bool> details(String package) async => true;
|
|
@override
|
|
Future<bool> uninstall(String package) async => true;
|
|
@override
|
|
Future<String> backupDir() async => Directory.systemTemp.path;
|
|
}
|
|
|
|
void main() {
|
|
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
|
if (Platform.environment['JJ_SHOT_THEME'] == 'light') JjColors.use(Brightness.light);
|
|
|
|
testWidgets('캡처 없던 화면 그림', (t) async {
|
|
final out = Platform.environment['JJ_SHOT_DIR'] ?? p.join(Directory.systemTemp.path, 'jj_shots_misc');
|
|
Directory(out).createSync(recursive: true);
|
|
final c = AppController(PlatformServices(mediaTool: ProcessMediaTool('x', 'y'), storage: DesktopStorageService()));
|
|
c.settings
|
|
..tor.noticeSeen = true
|
|
..display.components = [...c.settings.display.components, 'tor'];
|
|
final key = GlobalKey();
|
|
|
|
Future<void> shot(String name, Size size, Widget home, {Future<void> Function()? then}) async {
|
|
t.view.physicalSize = size;
|
|
t.view.devicePixelRatio = 1;
|
|
await t.runAsync(() => t.pumpWidget(MaterialApp(
|
|
key: UniqueKey(),
|
|
theme: buildTheme(),
|
|
debugShowCheckedModeBanner: false,
|
|
builder: (_, child) => AppScope(controller: c, child: RepaintBoundary(key: key, child: child!)),
|
|
home: home,
|
|
)));
|
|
for (var i = 0; i < 15; i++) {
|
|
await t.runAsync(() => Future<void>.delayed(const Duration(milliseconds: 100)));
|
|
await t.pump(const Duration(milliseconds: 50));
|
|
}
|
|
if (then != null) {
|
|
await then();
|
|
for (var i = 0; i < 10; i++) {
|
|
await t.runAsync(() => Future<void>.delayed(const Duration(milliseconds: 100)));
|
|
await t.pump(const Duration(milliseconds: 50));
|
|
}
|
|
}
|
|
final boundary = key.currentContext!.findRenderObject()! as RenderRepaintBoundary;
|
|
final image = await t.runAsync(() => boundary.toImage());
|
|
final bytes = await t.runAsync(() => image!.toByteData(format: ui.ImageByteFormat.png));
|
|
File(p.join(out, 'misc_$name.png')).writeAsBytesSync(bytes!.buffer.asUint8List());
|
|
await t.pumpWidget(const SizedBox());
|
|
}
|
|
|
|
const nas = DlnaServer('집 NAS', 'http://192.168.0.5/d.xml', 'http://192.168.0.5/ctl');
|
|
Widget dlna() => DlnaPage(
|
|
c: c,
|
|
discover: () async => [nas],
|
|
browse: (s, id, start) async => (
|
|
entries: [
|
|
const DlnaEntry('v', '동영상', isContainer: true, childCount: 2),
|
|
const DlnaEntry('x', '여행.mp4', upnpClass: 'object.item.videoItem'),
|
|
],
|
|
total: 2
|
|
),
|
|
);
|
|
await shot('dlna_servers', const Size(960, 600), dlna());
|
|
await shot('dlna_folder', const Size(960, 600), dlna(), then: () => t.tap(find.text('집 NAS')));
|
|
await shot('apps_412', const Size(412, 800), AppManagerPage(backend: _Apps()));
|
|
await shot('tor_960', const Size(960, 600), TorPage(
|
|
c: c,
|
|
startTor: () async {},
|
|
missingFeatures: () async => const [],
|
|
applyProxy: () async => true,
|
|
onLeft: () async {},
|
|
viewBuilder: (_, _) => const ColoredBox(color: Colors.white),
|
|
));
|
|
final v = VideoItem(r'D:\m\영화.mkv');
|
|
final s = SubtitleEntry.external(path: r'D:\m\영화.ko.srt', language: languageOf('ko'));
|
|
v.subtitles.add(s);
|
|
final editor = SubtitleEditorController(
|
|
parseSrt('1\n00:00:01,000 --> 00:00:03,000\n첫째\n\n2\n00:00:05,000 --> 00:00:07,000\n둘째\n\n3\n00:00:09,000 --> 00:00:11,000\n셋째\n'),
|
|
saveCharset: 'UTF-8');
|
|
await shot('subtitle_960', const Size(960, 600), SubtitleEditorPage(app: c, video: v, entry: s, editor: editor));
|
|
t.view.reset();
|
|
});
|
|
}
|