import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:jj_mkvmaker/ui/floating_actions.dart'; /// W 공용 위젯 약속 (FloatingActions): 좁거나 낮은 화면은 내용 안 단추 줄 (떠 있지 않음), 넓으면 오른쪽 아래에 떠 있고 /// 내용 아래를 단추 높이만큼 비움 · 첫 단추가 맨 아래. 위젯 하나에 대해 한 번만 둔다 (설계 7-2) void main() { Widget fab(String n) => FloatingActionButton.extended(heroTag: null, onPressed: () {}, icon: const Icon(Icons.drive_file_move_outline), label: Text(n)); Future<(Widget?, double)> show(WidgetTester t, {required bool inline, Size size = const Size(960, 600), double scale = 1}) async { t.view.physicalSize = size; t.view.devicePixelRatio = 1; addTearDown(t.view.reset); Widget? gotRow; var gotGap = -1.0; await t.pumpWidget(MaterialApp( home: MediaQuery( data: MediaQueryData(size: size, textScaler: TextScaler.linear(scale)), child: Scaffold( body: FloatingActions( inline: inline, buttons: [fab('이동'), fab('NAS')], content: (row, gap) { gotRow = row; gotGap = gap; return ListView(children: [const SizedBox(height: 100, child: Text('내용')), ?row]); }, ), ), ), )); return (gotRow, gotGap); } testWidgets('넓으면 떠 있음: 내용 아래를 단추 높이만큼 비우고, 첫 단추가 맨 아래', (t) async { final (row, gap) = await show(t, inline: false); expect(row, isNull); expect(gap, 16 + 2 * floatingActionRow + 16); expect(t.getRect(find.text('이동')).top, greaterThan(t.getRect(find.text('NAS')).top), reason: '첫 단추가 아래'); expect(t.getRect(find.text('이동')).bottom, greaterThan(600 - 60), reason: '오른쪽 아래'); }); testWidgets('좁거나 낮으면 내용 안 단추 줄 (떠 있지 않음) · 아래 여백 24', (t) async { final (row, gap) = await show(t, inline: true, size: const Size(412, 900)); expect(row, isNotNull); expect(gap, 24); expect(find.byType(Positioned), findsNothing); expect(t.takeException(), isNull); }); testWidgets('floatingInline: 좁음 · 높이 500 미만 · 글자 배율로 나눈 높이 (F7 - 960×600 · 1.6 배)', (t) async { late BuildContext ctx; for (final (size, scale, compact, want) in [ (const Size(960, 800), 1.0, false, false), (const Size(960, 800), 1.0, true, true), (const Size(900, 412), 1.0, false, true), (const Size(960, 600), 1.6, false, true), ]) { await t.pumpWidget(MediaQuery( data: MediaQueryData(size: size, textScaler: TextScaler.linear(scale)), child: Builder(builder: (c) { ctx = c; return const SizedBox(); }))); expect(floatingInline(ctx, compact: compact), want, reason: '$size × $scale compact=$compact'); } }); }