Files
school-attendance/lib/main_client_app.dart
T
sihooandClaude Sonnet 5 7495ece0c8 대시보드 배너/타이틀 중앙정렬 + 타일 UI 편집(드래그 이동/크기조절) + 로그인 유지 기능 추가
- 이름/부제, "스마트 관리 시스템 메뉴" 제목을 중앙 정렬
- 타일을 1x1~4x4 크기로 자유 배치할 수 있는 편집 모드 추가 (6x4 캔버스, 삼성 One UI 위젯 편집 방식)
- 타일 배치는 계정별로 서버에 저장/복원 (dashboard_layout_controller.dart)
- 설정 화면(톱니바퀴 아이콘) > "UI 편집" 진입점 추가
- shared_preferences로 로그인 유지 기능 추가 (비밀번호는 저장하지 않음)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-07 22:18:16 +09:00

102 lines
3.0 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 SchoolAttendanceApp extends StatelessWidget {
const SchoolAttendanceApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: '$schoolName 학생 도우미',
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,
);
}
return const LoginScreen();
}
}