diff --git a/lib/ui/home_page.dart b/lib/ui/home_page.dart index b87b4a3..3606edc 100644 --- a/lib/ui/home_page.dart +++ b/lib/ui/home_page.dart @@ -103,7 +103,7 @@ class HomePage extends StatelessWidget { ), const Divider(height: 1), // 249: DNS 서버에 닿지 않는 동안 작업 기록 위에 (아래 안내를 놓쳐도 MKV 화면에서 보고 바꿀 수 있게) - Padding(padding: const EdgeInsets.symmetric(horizontal: 12), child: DnsFailureLine(c: c)), + Padding(padding: const EdgeInsets.symmetric(horizontal: 12), child: DnsFailureLine(c: c, compact: isCompact(context))), if (c.settings.showLog) SizedBox( // 화면이 낮은 기기 (휴대폰 가로) 에서 목록 · 자세히 보기를 가리지 않도록 화면 높이에 맞춘다. diff --git a/lib/ui/network_settings.dart b/lib/ui/network_settings.dart index 0bea1ac..289b060 100644 --- a/lib/ui/network_settings.dart +++ b/lib/ui/network_settings.dart @@ -19,7 +19,11 @@ import 'tor_page.dart' show showTorNotice; /// 서버가 다시 답하거나 DNS 설정을 바꾸면 사라진다. class DnsFailureLine extends StatelessWidget { final AppController c; - const DnsFailureLine({super.key, required this.c}); + + /// 266: 좁은 화면 (폰 세로) - 한 줄 (글은 줄임, 길게 누르면 전체 · 버튼은 같은 줄). 두 줄이면 위의 세부 정보 칸이 줄어 + /// [AI 자막 만들기] · [인터넷 자막 찾기] 가 칸 밖으로 밀렸다 + final bool compact; + const DnsFailureLine({super.key, required this.c, this.compact = false}); @override Widget build(BuildContext context) => ValueListenableBuilder( @@ -27,12 +31,33 @@ class DnsFailureLine extends StatelessWidget { builder: (context, f, _) { if (f == null) return const SizedBox.shrink(); String two(int x) => x.toString().padLeft(2, '0'); + final text = trf('DNS 서버 ({0}) 에 닿지 않음 ({1}부터)', [f.server, '${two(f.at.hour)}:${two(f.at.minute)}']); + if (compact) { + return SizedBox( + height: 36, + child: Row(children: [ + const Icon(Icons.warning_amber_rounded, size: 16, color: Colors.orange), + const SizedBox(width: 6), + Expanded( + child: Tooltip( + message: text, + child: Text(text, maxLines: 1, overflow: TextOverflow.ellipsis, style: const TextStyle(fontSize: 12, color: Colors.orange)), + ), + ), + TextButton( + style: TextButton.styleFrom( + visualDensity: VisualDensity.compact, padding: const EdgeInsets.symmetric(horizontal: 8), minimumSize: const Size(0, 36)), + onPressed: () => c.updateSettings((x) => x.dnsMode = 'system'), + child: Text(tr('시스템 DNS 로 바꾸기'), style: const TextStyle(fontSize: 13)), + ), + ]), + ); + } return Padding( padding: const EdgeInsets.symmetric(vertical: 4), child: Wrap(spacing: 8, crossAxisAlignment: WrapCrossAlignment.center, children: [ const Icon(Icons.warning_amber_rounded, size: 18, color: Colors.orange), - Text(trf('DNS 서버 ({0}) 에 닿지 않음 ({1}부터)', [f.server, '${two(f.at.hour)}:${two(f.at.minute)}']), - style: const TextStyle(fontSize: 12, color: Colors.orange)), + Text(text, style: const TextStyle(fontSize: 12, color: Colors.orange)), TextButton( onPressed: () => c.updateSettings((x) => x.dnsMode = 'system'), child: Text(tr('시스템 DNS 로 바꾸기')), diff --git a/test/mkv_portrait_detail_test.dart b/test/mkv_portrait_detail_test.dart index 32bbeaa..c77bb65 100644 --- a/test/mkv_portrait_detail_test.dart +++ b/test/mkv_portrait_detail_test.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:jj_mkvmaker/app/app_controller.dart'; +import 'package:jj_mkvmaker/app/net_guard.dart'; import 'package:jj_mkvmaker/app/settings.dart'; import 'package:jj_mkvmaker/core/models.dart'; import 'package:jj_mkvmaker/platform/windows/desktop_storage_service.dart'; @@ -10,8 +11,8 @@ import 'package:jj_mkvmaker/ui/home_page.dart'; /// 261: 폰 세로 (노트 10+ 412×869) 의 MKV 세부 정보 - "감지한 언어" 줄이 생겨도 [AI 자막 만들기] 가 밀려 가려지지 않는다 void main() { - for (final detected in [false, true]) { - testWidgets('261: 폰 세로 · 작업 기록 켬 · 감지한 언어 ${detected ? '있음' : '없음'} - [AI 자막 만들기] 가 스크롤 없이 보인다', (tester) async { + for (final (detected, dns) in [(false, false), (true, false), (true, true)]) { + testWidgets('261 · 266: 폰 세로 · 작업 기록 켬 · 감지한 언어 ${detected ? '있음' : '없음'}${dns ? ' · DNS 닿지 않음 줄' : ''} - [AI 자막 만들기] 가 스크롤 없이 보인다', (tester) async { tester.view.physicalSize = const Size(412, 869); tester.view.devicePixelRatio = 1; addTearDown(tester.view.reset); @@ -27,6 +28,11 @@ void main() { c.videos.add(VideoItem('D:/v/아주 긴 이름의 동영상 파일 $i.mp4')); } c.selected = c.videos.first..aiDetected = detected ? 'en' : null; + // 266: DNS 가 닿지 않는 동안 작업 기록 위의 줄 (936 노트 10+ 에서 두 줄이 되어 버튼을 밀어냄) + if (dns) { + NetGuard.instance.failure.value = DnsFailure('192.0.2.1', '답이 없습니다', DateTime(2026, 10, 12, 8, 42)); + addTearDown(() => NetGuard.instance.failure.value = null); + } await tester.pumpWidget(MaterialApp(home: HomePage(c: c))); await tester.pump(); expect(tester.takeException(), isNull); @@ -36,6 +42,12 @@ void main() { final view = tester.getRect(find.ancestor(of: ai, matching: find.byType(Scrollable)).first); final button = tester.getRect(ai); expect(button.bottom, lessThanOrEqualTo(view.bottom), reason: '버튼 $button · 세부 정보 칸 $view'); + if (dns) { + // 한 줄 · 버튼도 그 줄에 + final line = tester.getRect(find.text('DNS 서버 (192.0.2.1) 에 닿지 않음 (08:42부터)')); + final sys = tester.getRect(find.text('시스템 DNS 로 바꾸기')); + expect((sys.center.dy - line.center.dy).abs(), lessThan(4), reason: '버튼이 같은 줄'); + } }); } }