Files
fanuzu/app/lib/features/quest/widgets/time_attack_countdown.dart
T

58 lines
1.7 KiB
Dart

import 'dart:async';
import 'package:flutter/widgets.dart';
import '../../../core/data/server_clock.dart';
/// 타임어택 남은 시간 — 초마다 다시 그린다. 마감은 서버 값(`quests.activeTo`)이라
/// 화면을 다시 열어도 처음부터 세지 않는다. 기준은 [ServerClock] 이다. 마감이 지나면
/// [builder] 가 null 을 받고 타이머를 멈춘다.
///
/// 표시용이다. 참여 수락/거부는 서버 시각으로 다시 판정한다(`fn-quest-timeattack`).
class TimeAttackCountdown extends StatefulWidget {
const TimeAttackCountdown({
super.key,
required this.endsAt,
required this.builder,
});
final DateTime endsAt;
final Widget Function(BuildContext context, Duration? left) builder;
@override
State<TimeAttackCountdown> createState() => _TimeAttackCountdownState();
}
class _TimeAttackCountdownState extends State<TimeAttackCountdown> {
late final Timer _timer;
@override
void initState() {
super.initState();
_timer = Timer.periodic(const Duration(seconds: 1), (_) => setState(() {}));
}
@override
void dispose() {
_timer.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
final left = widget.endsAt.difference(ServerClock.now());
final closed = left.isNegative || left == Duration.zero;
if (closed) _timer.cancel();
return widget.builder(context, closed ? null : left);
}
}
/// `H:MM:SS`(1시간 이상) 또는 `MM:SS`.
String formatLeft(Duration left) {
String two(int n) => n.toString().padLeft(2, '0');
final h = left.inHours;
final m = two(left.inMinutes % 60);
final s = two(left.inSeconds % 60);
return h > 0 ? '$h:$m:$s' : '$m:$s';
}