알림 시간을 시험 전용 길이 대신 주입으로: NoticeTiming (InheritedWidget, 없으면 appNoticeDuration 10초)
- lib/ui/notice.dart 의 noticeDurationForTest 를 지움 (lib 에 시험 전용 길이를 두지 않음 - 관리자 10/23)
- 탐색기 점검 시험은 MaterialApp 을 NoticeTiming 으로 감싼다. 약속 시험: 감싸면 그 시간, 없으면 10초
- 확인: 캡처 2회 90/90 같음 · 앞 판 (5303663) 과도 90/90 같음 → base7
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
modular
parent
53036633d3
commit
8c561a6133
|
|
@ -14,7 +14,7 @@ import 'package:jj_mkvmaker/platform/windows/process_media_tool.dart';
|
|||
import 'package:jj_mkvmaker/services/platform_services.dart';
|
||||
import 'package:jj_mkvmaker/ui/explorer/job_view.dart' show TransferJobView;
|
||||
import 'package:jj_mkvmaker/ui/explorer_page.dart';
|
||||
import 'package:jj_mkvmaker/ui/notice.dart' show appNoticeDuration, noticeDurationForTest;
|
||||
import 'package:jj_mkvmaker/ui/notice.dart' show NoticeTiming;
|
||||
import 'package:jj_mkvmaker/ui/theme.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
|
||||
|
|
@ -35,8 +35,6 @@ void main() {
|
|||
t.view.physicalSize = Size(w.toDouble(), h.toDouble());
|
||||
t.view.devicePixelRatio = 1;
|
||||
addTearDown(t.view.reset);
|
||||
noticeDurationForTest = const Duration(hours: 1);
|
||||
addTearDown(() => noticeDurationForTest = appNoticeDuration);
|
||||
await t.runAsync(() => i18n.apply('ko', save: false));
|
||||
useTestRecycleBin();
|
||||
// 캡처 비교가 흔들리지 않게 시험 폴더 이름 · 파일 시각을 고정 (관리자 지시 10/22) - 끝나면 지움
|
||||
|
|
@ -66,7 +64,11 @@ void main() {
|
|||
final shotKey = GlobalKey();
|
||||
await t.runAsync(() => t.pumpWidget(RepaintBoundary(
|
||||
key: shotKey,
|
||||
child: MaterialApp(theme: buildTheme(), debugShowCheckedModeBanner: false, home: ExplorerPage(device: device, c: c)),
|
||||
// 알림이 실제 시간으로 닫히지 않게 (정한 자리에서 noticeTimesOut 으로 닫는다)
|
||||
child: NoticeTiming(
|
||||
duration: const Duration(hours: 1),
|
||||
child: MaterialApp(theme: buildTheme(), debugShowCheckedModeBanner: false, home: ExplorerPage(device: device, c: c)),
|
||||
),
|
||||
)));
|
||||
Future<void> settle([int n = 12]) async {
|
||||
for (var i = 0; i < n; i++) {
|
||||
|
|
@ -100,8 +102,8 @@ void main() {
|
|||
}
|
||||
|
||||
// 복사 · 이동이 끝나 진행 패널이 다 내려갈 때까지 (실제 시간, 10초까지) - 캡처가 PC 빠르기에 따라 달라지지 않게
|
||||
// 알림은 실제 시간 10초 (appNoticeDuration) 로 닫히면 찍는 때와 겹쳐 장면이 실행마다 달라진다 (14 · 27) -
|
||||
// 이 시험은 저절로 닫히지 않게 두고, 정한 자리에서 "시간이 다 되어 닫힘" 으로 닫는다 (앱의 알림 시간은 그대로)
|
||||
// 알림은 실제 시간 10초 (앱의 값) 로 닫히면 찍는 때와 겹쳐 장면이 실행마다 달라진다 (14 · 27) -
|
||||
// 이 시험은 NoticeTiming 으로 저절로 닫히지 않게 두고, 정한 자리에서 "시간이 다 되어 닫힘" 으로 닫는다 (앱의 알림 시간은 그대로)
|
||||
Future<void> noticeTimesOut() async {
|
||||
t.state<ScaffoldMessengerState>(find.byType(ScaffoldMessenger).first).removeCurrentSnackBar();
|
||||
await settle(3);
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
|
|||
/// 단추가 있는 아래 알림 (SnackBar) 을 띄우는 곳은 이것 하나 (E4 U2, 관리자 승인 10/22).
|
||||
///
|
||||
/// 약속
|
||||
/// - [NoticeLife.timed] (기본): [noticeDuration] (앱은 [appNoticeDuration]) 뒤 저절로 닫힌다. 앱 전체 한 값이다.
|
||||
/// - [NoticeLife.timed] (기본): [appNoticeDuration] 뒤 저절로 닫힌다. 앱 전체 한 값이다 (화면을 찍는 시험만 [NoticeTiming] 으로 정함).
|
||||
/// (Flutter 3.29 부터 단추가 있는 SnackBar 는 기본으로 닫히지 않아, 끝 알림이 다음 일을 하는 내내 아래 줄을 가렸다 - 점검 U2)
|
||||
/// - [NoticeLife.untilClosed]: 사용자가 ✕ 를 누르거나 부르는 쪽이 돌려받은 것으로 닫을 때까지 둔다.
|
||||
/// 상태가 남는 중요한 안내 (248 DNS · 198 감지한 언어) 와, 부르는 쪽이 일이 끝나면 닫는 것 (다운로드 준비 · 시작 전 [취소]) 만.
|
||||
|
|
@ -12,13 +12,18 @@ import 'package:flutter/material.dart';
|
|||
/// - [messenger] 가 없으면 아무것도 하지 않고 null.
|
||||
const appNoticeDuration = Duration(seconds: 10);
|
||||
|
||||
/// [NoticeLife.timed] 알림이 저절로 닫히기까지. 앱은 늘 [appNoticeDuration] (U2 의 값 - 바꾸는 곳 없음).
|
||||
/// 화면을 찍는 시험만 [noticeDurationForTest] 로 정한다 (실제 시간 10초가 찍는 때와 겹쳐 장면이 실행마다 달라지지 않게)
|
||||
Duration get noticeDuration => _noticeDuration;
|
||||
Duration _noticeDuration = appNoticeDuration;
|
||||
/// [NoticeLife.timed] 알림이 저절로 닫히기까지를 아래 화면에 정해 준다. 없으면 [appNoticeDuration] (앱은 늘 없음 - U2 의 값).
|
||||
/// 화면을 찍는 시험이 MaterialApp 을 이것으로 감싸 정한다 (실제 시간 10초가 찍는 때와 겹쳐 장면이 실행마다 달라지지 않게)
|
||||
class NoticeTiming extends InheritedWidget {
|
||||
final Duration duration;
|
||||
const NoticeTiming({super.key, required this.duration, required super.child});
|
||||
|
||||
@visibleForTesting
|
||||
set noticeDurationForTest(Duration d) => _noticeDuration = d;
|
||||
/// [context] 위에서 정한 알림 시간 (없으면 [appNoticeDuration])
|
||||
static Duration of(BuildContext context) => context.getInheritedWidgetOfExactType<NoticeTiming>()?.duration ?? appNoticeDuration;
|
||||
|
||||
@override
|
||||
bool updateShouldNotify(NoticeTiming old) => duration != old.duration;
|
||||
}
|
||||
|
||||
enum NoticeLife { timed, untilClosed }
|
||||
|
||||
|
|
@ -38,7 +43,7 @@ ScaffoldFeatureController<SnackBar, SnackBarClosedReason>? showNotice(
|
|||
if (clearOthers) messenger.clearSnackBars();
|
||||
return messenger.showSnackBar(SnackBar(
|
||||
content: content ?? Text(text!),
|
||||
duration: life == NoticeLife.timed ? noticeDuration : const Duration(days: 1),
|
||||
duration: life == NoticeLife.timed ? NoticeTiming.of(messenger.context) : const Duration(days: 1),
|
||||
persist: life == NoticeLife.untilClosed,
|
||||
showCloseIcon: true,
|
||||
action: action == null ? null : SnackBarAction(label: action.$1, onPressed: action.$2),
|
||||
|
|
|
|||
|
|
@ -355,12 +355,12 @@ void main() {
|
|||
await tester.tap(find.text('실행 취소'));
|
||||
await tester.pumpAndSettle();
|
||||
expect(bm.tree.findByUrl('https://www.youtube.com/watch?v=abc'), isNotNull);
|
||||
await tester.tap(find.byTooltip('더 보기').last); // 실행 취소 알림은 noticeDuration (E4 U2) 뒤 저절로 사라진다
|
||||
await tester.tap(find.byTooltip('더 보기').last); // 실행 취소 알림은 appNoticeDuration (E4 U2) 뒤 저절로 사라진다
|
||||
await tester.pumpAndSettle();
|
||||
await tester.tap(find.text('삭제').last);
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text('실행 취소'), findsOneWidget);
|
||||
await tester.pump(noticeDuration + const Duration(seconds: 1));
|
||||
await tester.pump(appNoticeDuration + const Duration(seconds: 1));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text('실행 취소'), findsNothing);
|
||||
bm.undoRemove();
|
||||
|
|
|
|||
|
|
@ -11,20 +11,19 @@ void main() {
|
|||
messenger = key.currentState!;
|
||||
}
|
||||
|
||||
testWidgets('단추가 있어도 timed 는 noticeDuration 뒤 저절로 닫힘 (U2) · 앱 전체 한 값', (tester) async {
|
||||
testWidgets('단추가 있어도 timed 는 appNoticeDuration 뒤 저절로 닫힘 (U2) · 앱 전체 한 값', (tester) async {
|
||||
await open(tester);
|
||||
var pressed = 0;
|
||||
showNotice(messenger, text: '복사했습니다', action: ('폴더 열기', () => pressed++));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text('복사했습니다'), findsOneWidget);
|
||||
expect(find.byIcon(Icons.close), findsOneWidget, reason: '✕ 로 바로 닫기');
|
||||
await tester.pump(noticeDuration - const Duration(seconds: 1));
|
||||
await tester.pump(appNoticeDuration - const Duration(seconds: 1));
|
||||
expect(find.text('복사했습니다'), findsOneWidget, reason: '정해진 시간 전에는 남음');
|
||||
await tester.pump(const Duration(seconds: 2));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text('복사했습니다'), findsNothing);
|
||||
expect(pressed, 0);
|
||||
expect(noticeDuration, const Duration(seconds: 10));
|
||||
expect(appNoticeDuration, const Duration(seconds: 10), reason: '앱의 값 (U2) - 시험이 정하지 않으면 이것');
|
||||
});
|
||||
|
||||
|
|
@ -65,4 +64,19 @@ void main() {
|
|||
expect(find.text('되돌리기 알림'), findsOneWidget);
|
||||
expect(showNotice(null, text: 'x'), isNull);
|
||||
});
|
||||
|
||||
testWidgets('NoticeTiming: 감싼 화면의 timed 알림은 그 시간 뒤 닫힘 (없으면 appNoticeDuration)', (tester) async {
|
||||
final key = GlobalKey<ScaffoldMessengerState>();
|
||||
await tester.pumpWidget(NoticeTiming(
|
||||
duration: const Duration(seconds: 30),
|
||||
child: MaterialApp(scaffoldMessengerKey: key, home: const Scaffold(body: SizedBox()))));
|
||||
showNotice(key.currentState, text: '오래 남음', action: ('보기', () {}));
|
||||
await tester.pump();
|
||||
await tester.pump(const Duration(milliseconds: 500)); // 들어오는 움직임이 끝난 뒤부터 센다
|
||||
await tester.pump(appNoticeDuration + const Duration(seconds: 5));
|
||||
expect(find.text('오래 남음'), findsOneWidget, reason: '10초가 지나도 정한 30초 전에는 남음');
|
||||
await tester.pump(const Duration(seconds: 20));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text('오래 남음'), findsNothing);
|
||||
});
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue