// ⏱️ 우리 학교 전용 "열품타" 공부 타이머 화면 (UI 전용). // 서버 통신/상태는 lib/function/study_timer_controller.dart가 담당한다. import 'package:flutter/material.dart'; import '../function/study_timer_controller.dart'; import '../theme/app_palette.dart'; import 'app_notice.dart'; import 'launchpad_transition.dart'; import 'study_ranking_screen.dart'; import 'title_pill.dart'; class StudyTimerScreen extends StatefulWidget { final String studentId; final String studentName; final int? grade; const StudyTimerScreen({ super.key, required this.studentId, required this.studentName, this.grade, }); @override State createState() => _StudyTimerScreenState(); } class _StudyTimerScreenState extends State { late final StudyTimerController _controller; @override void initState() { super.initState(); _controller = StudyTimerController( studentId: widget.studentId, studentName: widget.studentName, ); _controller.init(); } @override void dispose() { _controller.dispose(); super.dispose(); } String _formatHMS(int totalSeconds) { final h = totalSeconds ~/ 3600; final m = (totalSeconds % 3600) ~/ 60; final s = totalSeconds % 60; final hh = h.toString().padLeft(2, '0'); final mm = m.toString().padLeft(2, '0'); final ss = s.toString().padLeft(2, '0'); return '$hh:$mm:$ss'; } String _formatHM(int totalSeconds) { final h = totalSeconds ~/ 3600; final m = (totalSeconds % 3600) ~/ 60; if (h > 0) return '$h시간 $m분'; return '$m분'; } Future _toggle() async { final (success, message) = _controller.isRunning ? await _controller.stop() : await _controller.start(); if (!mounted) return; AppNotice.show( context, message, icon: success ? Icons.check_circle_rounded : Icons.error_outline_rounded, ); } void _openRanking() { if (widget.grade == null) { AppNotice.show(context, '학년 정보가 없어 랭킹을 볼 수 없어요.'); return; } pushLaunchpad( context, (context) => StudyRankingScreen( grade: widget.grade!, myStudentId: widget.studentId, ), ); } @override Widget build(BuildContext context) { return ListenableBuilder( listenable: _controller, builder: (context, _) { final bool isRunning = _controller.isRunning; return Scaffold( backgroundColor: AppPalette.mist, appBar: AppBar( backgroundColor: Colors.transparent, foregroundColor: AppPalette.ink, elevation: 0, centerTitle: true, title: const TitlePill('공부 타이머'), actions: [ IconButton( icon: const Icon(Icons.leaderboard_rounded), tooltip: '학년 랭킹', onPressed: _openRanking, ), ], ), body: _controller.isLoading ? const Center(child: CircularProgressIndicator()) : Center( child: SingleChildScrollView( padding: const EdgeInsets.all(24), child: Column( mainAxisSize: MainAxisSize.min, children: [ Text( isRunning ? '지금 공부 중이에요' : '공부를 시작해볼까요?', style: const TextStyle( fontSize: 15, color: Colors.grey, ), ), const SizedBox(height: 12), Text( _formatHMS(_controller.liveElapsedSeconds), style: const TextStyle( fontSize: 52, fontWeight: FontWeight.bold, color: AppPalette.ink, ), ), const SizedBox(height: 36), GestureDetector( onTap: _controller.isBusy ? null : _toggle, child: Container( width: 140, height: 140, decoration: BoxDecoration( shape: BoxShape.circle, color: isRunning ? Colors.red[400] : AppPalette.ink, boxShadow: [ BoxShadow( color: (isRunning ? Colors.red : AppPalette.ink) .withValues(alpha: 0.3), blurRadius: 20, offset: const Offset(0, 8), ), ], ), child: Center( child: _controller.isBusy ? const CircularProgressIndicator( color: Colors.white, ) : Column( mainAxisSize: MainAxisSize.min, children: [ Icon( isRunning ? Icons.stop_rounded : Icons.play_arrow_rounded, color: Colors.white, size: 36, ), Text( isRunning ? '공부 종료' : '공부 시작', style: const TextStyle( color: Colors.white, fontWeight: FontWeight.bold, ), ), ], ), ), ), ), const SizedBox(height: 40), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ _statBox( '오늘', _formatHM(_controller.todaySecondsLive), ), const SizedBox(width: 12), _statBox( '이번주', _formatHM(_controller.weekSecondsLive), ), const SizedBox(width: 12), _statBox( '전체', _formatHM(_controller.totalSecondsLive), ), ], ), ], ), ), ), ); }, ); } Widget _statBox(String label, String value) { return Container( width: 100, padding: const EdgeInsets.symmetric(vertical: 14), decoration: BoxDecoration( color: AppPalette.paper, borderRadius: BorderRadius.circular(16), border: Border.all(color: AppPalette.sage), ), child: Column( children: [ Text(label, style: TextStyle(color: Colors.grey[600], fontSize: 12)), const SizedBox(height: 4), Text( value, style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 15), ), ], ), ); } }