폰 가로 브라우저 · 다운로드 주소 칸: 모자라면 위 막대 두 줄 (201 · 200)
- 버그 (기기 확인 지적): 가로 폰에서 주소 칸이 너무 좁거나 보이지 않던 것 - AppTopBar 가 가운데 폭을 재고 minMiddleWidth (브라우저 380 · 다운로드 420) 보다 좁으면 두 줄로 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>fix_mkv
parent
487d955a99
commit
c9c4f031b5
|
|
@ -25,20 +25,44 @@ bool isCompact(BuildContext context) => MediaQuery.sizeOf(context).width < compa
|
|||
|
||||
/// 모든 화면의 위쪽 막대: [nav] [middle (남는 너비)] [actions].
|
||||
/// 좁은 화면에서는 두 줄 - 위: [nav] … [actions], 아래: [middle] 이 한 줄을 다 쓴다.
|
||||
class AppTopBar extends StatelessWidget {
|
||||
/// [minMiddleWidth] (201): 한 줄일 때 middle 이 이보다 좁아지면 (폰 가로처럼 넓지만 버튼이 폭을 다 차지할 때) 두 줄로.
|
||||
/// 브라우저 주소 칸처럼 middle 이 꼭 보여야 하는 화면이 준다 (0 이면 폭만으로 정함)
|
||||
class AppTopBar extends StatefulWidget {
|
||||
final Widget nav;
|
||||
final Widget middle;
|
||||
final Widget actions;
|
||||
const AppTopBar({super.key, required this.nav, required this.middle, required this.actions});
|
||||
final double minMiddleWidth;
|
||||
const AppTopBar({super.key, required this.nav, required this.middle, required this.actions, this.minMiddleWidth = 0});
|
||||
|
||||
@override
|
||||
State<AppTopBar> createState() => _AppTopBarState();
|
||||
}
|
||||
|
||||
class _AppTopBarState extends State<AppTopBar> {
|
||||
final _mid = GlobalKey();
|
||||
|
||||
/// 한 줄에서 middle 이 모자랐던 화면 폭 - 이 폭 이하이면 두 줄
|
||||
double? _twoRowsAtOrBelow;
|
||||
|
||||
void _check(double width) {
|
||||
if (!mounted || widget.minMiddleWidth <= 0) return;
|
||||
final box = _mid.currentContext?.findRenderObject() as RenderBox?;
|
||||
if (box == null || !box.hasSize) return;
|
||||
if (box.size.width < widget.minMiddleWidth) setState(() => _twoRowsAtOrBelow = width);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (!isCompact(context)) {
|
||||
final nav = widget.nav, middle = widget.middle, actions = widget.actions;
|
||||
final width = MediaQuery.sizeOf(context).width;
|
||||
final narrow = _twoRowsAtOrBelow != null && width <= _twoRowsAtOrBelow!;
|
||||
if (!isCompact(context) && !narrow) {
|
||||
if (widget.minMiddleWidth > 0) WidgetsBinding.instance.addPostFrameCallback((_) => _check(width));
|
||||
return Container(
|
||||
height: appBarHeight,
|
||||
color: JjColors.panel,
|
||||
padding: const EdgeInsets.only(left: 8, right: appBarRightPadding),
|
||||
child: Row(children: [nav, const SizedBox(width: 8), Expanded(child: middle), actions]),
|
||||
child: Row(children: [nav, const SizedBox(width: 8), Expanded(child: KeyedSubtree(key: _mid, child: middle)), actions]),
|
||||
);
|
||||
}
|
||||
return Container(
|
||||
|
|
|
|||
|
|
@ -591,7 +591,9 @@ class _BrowserPageState extends State<BrowserPage> with RouteAware {
|
|||
);
|
||||
// 주소 칸이 좁아지면 (폰 세로 · 태블릿 세로 · 폰 가로 100%) 자주 안 쓰는 버튼은 ⋮ 메뉴로 - 주소가 "http" 만 보이거나
|
||||
// 아예 사라지던 것. 버튼을 없애지는 않는다.
|
||||
// 201: 폰 가로처럼 넓어도 버튼이 폭을 다 차지하면 주소 칸이 사라졌다 - 그때는 두 줄 (아래 줄을 주소 칸이 다 씀)
|
||||
return AppTopBar(
|
||||
minMiddleWidth: 380,
|
||||
nav: const AppNavButtons(onBrowserPage: true),
|
||||
actions: AppActions(c: widget.c),
|
||||
middle: LayoutBuilder(builder: (context, box) {
|
||||
|
|
|
|||
|
|
@ -88,7 +88,9 @@ class _DownloadsPageState extends State<DownloadsPage> {
|
|||
body: SwipeNav(
|
||||
current: 'downloads',
|
||||
child: Column(children: [
|
||||
// 200: 폰 가로에서 버튼이 폭을 다 차지해 주소 칸이 눌려 주소가 보이지 않았다 - 모자라면 두 줄 (아래 줄을 주소 칸이 다 씀)
|
||||
AppTopBar(
|
||||
minMiddleWidth: 420,
|
||||
nav: const AppNavButtons(onDownloadsPage: true),
|
||||
actions: const AppActions(),
|
||||
middle: Row(children: [
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:jj_mkvmaker/ui/app_actions.dart';
|
||||
|
||||
/// 201: 넓은 화면 (폰 가로) 이어도 버튼이 폭을 다 차지해 가운데 (브라우저 주소 칸) 가 모자라면 두 줄로
|
||||
void main() {
|
||||
Widget bar({double minMiddle = 0}) => MaterialApp(
|
||||
home: Scaffold(
|
||||
body: Column(children: [
|
||||
AppTopBar(
|
||||
minMiddleWidth: minMiddle,
|
||||
nav: const SizedBox(width: 420, height: 40),
|
||||
actions: const SizedBox(width: 360, height: 40),
|
||||
middle: const SizedBox(key: ValueKey('mid'), height: 36, child: Text('주소')),
|
||||
),
|
||||
]),
|
||||
),
|
||||
);
|
||||
|
||||
testWidgets('201: 가운데가 최소 폭보다 좁아지면 두 줄 (아래 줄을 가운데가 다 씀)', (tester) async {
|
||||
tester.view.physicalSize = const Size(900, 400); // 폰 가로 (compactWidth 720 보다 넓음)
|
||||
tester.view.devicePixelRatio = 1;
|
||||
addTearDown(tester.view.reset);
|
||||
await tester.pumpWidget(bar(minMiddle: 380));
|
||||
await tester.pump();
|
||||
await tester.pump();
|
||||
expect(tester.getSize(find.byKey(const ValueKey('mid'))).width, greaterThan(800));
|
||||
// 넓은 화면에서는 한 줄 그대로
|
||||
tester.view.physicalSize = const Size(1600, 900);
|
||||
await tester.pump();
|
||||
await tester.pump();
|
||||
expect(tester.getSize(find.byKey(const ValueKey('mid'))).width, lessThan(900));
|
||||
expect(tester.getSize(find.byKey(const ValueKey('mid'))).width, greaterThanOrEqualTo(380));
|
||||
});
|
||||
|
||||
testWidgets('201: 최소 폭을 주지 않은 화면은 예전처럼 (폭만으로 정함)', (tester) async {
|
||||
tester.view.physicalSize = const Size(900, 400);
|
||||
tester.view.devicePixelRatio = 1;
|
||||
addTearDown(tester.view.reset);
|
||||
await tester.pumpWidget(bar());
|
||||
await tester.pump();
|
||||
await tester.pump();
|
||||
expect(tester.getSize(find.byKey(const ValueKey('mid'))).width, lessThan(380));
|
||||
});
|
||||
}
|
||||
Loading…
Reference in New Issue