WIP MKV 화면 ②③ 보충 (15 확인 · 관리자 판단): [›] 뒤 바탕 · 폰 세로 빈 작업 기록은 한 줄 높이 (검토 대기)

② [›] · [‹] 를 짧은 흐림 (20) + 바탕색 칸 + 단추 바탕 (panelHigh) 위에 - 폭 412 에서 잘린 세 번째 버튼 글자가
   [›] 뒤로 비쳐 보였다 (관리자 지시).
③ 관리자 1차 판단: 폰 세로 (좁은 화면) 에서 작업 기록이 비었으면 칸을 안내 한 줄 높이 (40) 로,
   기록이 생기면 예전 높이 (140 까지). 정보는 숨기지 않고 빈 자리만 없앤다. 넓은 화면 · 인코딩 줄은 그대로.
- 시험: 비었을 때 40 → 기록이 생기면 140, 넓은 화면은 140.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
묶음6
RyuJongJin 2026-10-17 10:50:01 +09:00
parent 31a06c74ed
commit e39068cc9f
3 changed files with 52 additions and 25 deletions

View File

@ -99,7 +99,12 @@ class HomePage extends StatelessWidget {
SizedBox( SizedBox(
// 화면이 낮은 기기 (휴대폰 가로) 에서 목록 · 자세히 보기를 가리지 않도록 화면 높이에 맞춘다. // 화면이 낮은 기기 (휴대폰 가로) 에서 목록 · 자세히 보기를 가리지 않도록 화면 높이에 맞춘다.
// 256: 폰 가로 (높이 500 미만) 는 더 작게 - 목록이 한 줄만 보였다 // 256: 폰 가로 (높이 500 미만) 는 더 작게 - 목록이 한 줄만 보였다
height: MediaQuery.sizeOf(context).height < 500 ? 52 : (MediaQuery.sizeOf(context).height * 0.22).clamp(80.0, 140.0), // 관리자 판단 (10/17, 15 지적): 폰 세로에서 기록이 비었으면 안내 한 줄 높이만 (빈 자리만 없앰), 기록이 생기면 예전 높이
height: isCompact(context) && c.logs.isEmpty
? _LogPanel.emptyHeight
: MediaQuery.sizeOf(context).height < 500
? 52
: (MediaQuery.sizeOf(context).height * 0.22).clamp(80.0, 140.0),
child: _LogPanel( child: _LogPanel(
logs: c.logs, logs: c.logs,
onClose: () => c.updateSettings((s) => s.showLog = false), onClose: () => c.updateSettings((s) => s.showLog = false),
@ -1415,6 +1420,9 @@ class _LogPanel extends StatelessWidget {
final VoidCallback onClose; final VoidCallback onClose;
const _LogPanel({required this.logs, required this.onClose}); const _LogPanel({required this.logs, required this.onClose});
/// 폰 세로에서 기록이 비었을 때의 높이 (안내 한 줄)
static const emptyHeight = 40.0;
@override @override
Widget build(BuildContext context) => Container( Widget build(BuildContext context) => Container(
color: JjColors.bg, color: JjColors.bg,
@ -1423,9 +1431,9 @@ class _LogPanel extends StatelessWidget {
if (logs.isEmpty) if (logs.isEmpty)
Positioned.fill( Positioned.fill(
child: Padding( child: Padding(
padding: const EdgeInsets.fromLTRB(16, 10, 44, 8), padding: const EdgeInsets.fromLTRB(16, 12, 44, 0),
child: Text(tr('작업 기록이 아직 없습니다. MKV 만들기 · 자막 · 다운로드를 하면 여기에 차례로 남습니다.'), child: Text(tr('작업 기록이 아직 없습니다. MKV 만들기 · 자막 · 다운로드를 하면 여기에 차례로 남습니다.'),
style: const TextStyle(fontSize: 12, color: JjColors.textDim)), maxLines: 1, overflow: TextOverflow.ellipsis, style: const TextStyle(fontSize: 12, color: JjColors.textDim)),
), ),
), ),
Positioned.fill( Positioned.fill(

View File

@ -53,34 +53,37 @@ class _ScrollMoreState extends State<ScrollMore> {
_scroll.animateTo(to, duration: const Duration(milliseconds: 220), curve: Curves.easeOut); _scroll.animateTo(to, duration: const Duration(milliseconds: 220), curve: Curves.easeOut);
} }
/// 끝의 [›] · [‹]: 짧은 흐림 + 바탕을 깐 단추 (15 지적: 잘린 버튼 글자가 [›] 뒤로 비쳐 보였다)
Widget _edge(bool right) { Widget _edge(bool right) {
final bg = widget.background ?? Theme.of(context).scaffoldBackgroundColor; final bg = widget.background ?? Theme.of(context).scaffoldBackgroundColor;
final fade = Container(
width: 20,
decoration: BoxDecoration(
gradient: LinearGradient(
begin: right ? Alignment.centerLeft : Alignment.centerRight,
end: right ? Alignment.centerRight : Alignment.centerLeft,
colors: [bg.withValues(alpha: 0), bg],
),
),
);
final button = ColoredBox(
color: bg,
child: Center(
child: IconButton(
tooltip: right ? tr('버튼 더 보기') : tr('앞의 버튼 보기'),
visualDensity: VisualDensity.compact,
style: IconButton.styleFrom(backgroundColor: JjColors.panelHigh),
icon: Icon(right ? Icons.chevron_right : Icons.chevron_left, color: JjColors.accent),
onPressed: () => _jump(right ? 1 : -1),
),
),
);
return Positioned( return Positioned(
top: 0, top: 0,
bottom: 0, bottom: 0,
left: right ? null : 0, left: right ? null : 0,
right: right ? 0 : null, right: right ? 0 : null,
child: DecoratedBox( child: Row(mainAxisSize: MainAxisSize.min, children: right ? [fade, button] : [button, fade]),
decoration: BoxDecoration(
gradient: LinearGradient(
begin: right ? Alignment.centerLeft : Alignment.centerRight,
end: right ? Alignment.centerRight : Alignment.centerLeft,
colors: [bg.withValues(alpha: 0), bg.withValues(alpha: 0.95), bg],
stops: const [0, 0.45, 1],
),
),
child: Padding(
padding: EdgeInsets.only(left: right ? 18 : 0, right: right ? 0 : 18),
child: Center(
child: IconButton(
tooltip: right ? tr('버튼 더 보기') : tr('앞의 버튼 보기'),
visualDensity: VisualDensity.compact,
icon: Icon(right ? Icons.chevron_right : Icons.chevron_left, color: JjColors.accent),
onPressed: () => _jump(right ? 1 : -1),
),
),
),
),
); );
} }

View File

@ -98,10 +98,26 @@ void main() {
expect(find.byTooltip('앞의 버튼 보기'), findsOneWidget); expect(find.byTooltip('앞의 버튼 보기'), findsOneWidget);
}); });
testWidgets('작업 기록이 비었으면 무엇이 들어오는 칸인지 적는다', (tester) async { /// 작업 기록 칸 (✕ 가 든 SizedBox) 의 높이
double logHeight(WidgetTester tester) =>
tester.getSize(find.ancestor(of: find.byTooltip('작업 기록 숨기기'), matching: find.byType(SizedBox)).first).height;
testWidgets('작업 기록이 비었으면 무엇이 들어오는 칸인지 적고, 폰 세로는 한 줄 높이 - 기록이 생기면 예전 높이', (tester) async {
final c = make(3); final c = make(3);
c.logs.clear(); c.logs.clear();
await show(tester, c, const Size(412, 869)); await show(tester, c, const Size(412, 869));
expect(find.textContaining('작업 기록이 아직 없습니다'), findsOneWidget); expect(find.textContaining('작업 기록이 아직 없습니다'), findsOneWidget);
expect(logHeight(tester), 40, reason: '관리자 판단: 빈 자리만 없앤다');
c.note('MKV 만들기 시작');
await tester.pump();
expect(logHeight(tester), 140);
expect(find.textContaining('작업 기록이 아직 없습니다'), findsNothing);
});
testWidgets('넓은 화면은 기록이 비어도 예전 높이 (폰 세로만 바꿈)', (tester) async {
final c = make(3);
c.logs.clear();
await show(tester, c, const Size(1280, 800));
expect(logHeight(tester), 140);
}); });
} }