학생 참여 유도를 위해 공부 시작/종료 타이머와 학년별(오늘/이번주/전체) 랭킹 화면을 대시보드에 추가. 로그인 응답에 학년 정보를 포함시켜 세션 저장/복원 전체 경로에 전달되도록 함. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
116 lines
3.4 KiB
Dart
116 lines
3.4 KiB
Dart
// 🚪 앱 진입점. Firebase/백그라운드 감시 서비스 초기화 후 로그인 화면으로 시작한다.
|
|
// 실제 화면 구현은 lib/screens/ 폴더, 공통 설정은 lib/config.dart 참고.
|
|
import 'dart:io';
|
|
import 'package:flutter/foundation.dart' show kIsWeb;
|
|
import 'package:flutter/material.dart';
|
|
import 'package:firebase_core/firebase_core.dart';
|
|
import 'firebase_options.dart';
|
|
import 'config.dart';
|
|
import 'function/session_store.dart';
|
|
import 'pocket_watch_service.dart';
|
|
import 'theme/app_palette.dart';
|
|
import 'ui/login_screen.dart';
|
|
import 'ui/main_dashboard.dart';
|
|
|
|
void main() async {
|
|
WidgetsFlutterBinding.ensureInitialized();
|
|
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
|
|
await printFCMToken();
|
|
if (!kIsWeb && Platform.isAndroid) {
|
|
await initializePocketWatchService();
|
|
}
|
|
runApp(const SchoolAttendanceApp());
|
|
}
|
|
|
|
// 🌊 스크롤이 끝에 닿을 때 나오는 파란색 오버스크롤 글로우 효과를 없앤다.
|
|
class _NoGlowScrollBehavior extends MaterialScrollBehavior {
|
|
@override
|
|
Widget buildOverscrollIndicator(
|
|
BuildContext context,
|
|
Widget child,
|
|
ScrollableDetails details,
|
|
) {
|
|
return child;
|
|
}
|
|
}
|
|
|
|
class SchoolAttendanceApp extends StatelessWidget {
|
|
const SchoolAttendanceApp({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return MaterialApp(
|
|
debugShowCheckedModeBanner: false,
|
|
title: '$schoolName 학생 도우미',
|
|
scrollBehavior: _NoGlowScrollBehavior(),
|
|
theme: ThemeData(
|
|
useMaterial3: true,
|
|
scaffoldBackgroundColor: AppPalette.mist,
|
|
colorScheme:
|
|
ColorScheme.fromSeed(
|
|
seedColor: AppPalette.ink,
|
|
brightness: Brightness.light,
|
|
).copyWith(
|
|
primary: AppPalette.ink,
|
|
onPrimary: AppPalette.paper,
|
|
secondary: AppPalette.ink,
|
|
onSecondary: AppPalette.paper,
|
|
surface: AppPalette.paper,
|
|
onSurface: AppPalette.ink,
|
|
),
|
|
),
|
|
home: const _StartupGate(), // 🚪 저장된 로그인이 있으면 대시보드로, 없으면 로그인 화면으로.
|
|
);
|
|
}
|
|
}
|
|
|
|
/// 🔐 "로그인 유지" 진입점. 기기에 저장된 세션이 있는지 확인하는 동안 잠깐 로딩을 보여주고,
|
|
/// 있으면 로그인 화면 없이 바로 대시보드로, 없으면 로그인 화면으로 보낸다.
|
|
class _StartupGate extends StatefulWidget {
|
|
const _StartupGate();
|
|
|
|
@override
|
|
State<_StartupGate> createState() => _StartupGateState();
|
|
}
|
|
|
|
class _StartupGateState extends State<_StartupGate> {
|
|
SavedSession? _session;
|
|
bool _checked = false;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_checkSession();
|
|
}
|
|
|
|
Future<void> _checkSession() async {
|
|
final session = await SessionStore.load();
|
|
if (!mounted) return;
|
|
setState(() {
|
|
_session = session;
|
|
_checked = true;
|
|
});
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
if (!_checked) {
|
|
return Scaffold(
|
|
backgroundColor: AppPalette.mist,
|
|
body: const Center(child: CircularProgressIndicator()),
|
|
);
|
|
}
|
|
final session = _session;
|
|
if (session != null) {
|
|
return MainDashboard(
|
|
userId: session.userId,
|
|
userName: session.userName,
|
|
role: session.role,
|
|
isDeviceMatched: session.isDeviceMatched,
|
|
grade: session.grade,
|
|
);
|
|
}
|
|
return const LoginScreen();
|
|
}
|
|
}
|