LCOV - code coverage report
Current view: top level - lib/screens/auth - login_screen.dart Coverage Total Hit
Test: lcov.info Lines: 59.4 % 69 41
Test Date: 2025-08-12 03:21:51 Functions: - 0 0

            Line data    Source code
       1              : import 'package:flutter/material.dart';
       2              : import 'package:provider/provider.dart';
       3              : import '../../services/auth_service.dart';
       4              : import 'register_screen.dart';
       5              : import 'forgot_password_screen.dart';
       6              : 
       7              : class LoginScreen extends StatefulWidget {
       8           48 :   const LoginScreen({super.key});
       9              : 
      10            1 :   @override
      11            1 :   State<LoginScreen> createState() => _LoginScreenState();
      12              : }
      13              : 
      14              : class _LoginScreenState extends State<LoginScreen> {
      15              :   final _formKey = GlobalKey<FormState>();
      16              :   final _usernameController = TextEditingController();
      17              :   final _passwordController = TextEditingController();
      18              :   bool _isPasswordVisible = false;
      19              :   bool _rememberMe = false;
      20              : 
      21            1 :   @override
      22              :   void dispose() {
      23            2 :     _usernameController.dispose();
      24            2 :     _passwordController.dispose();
      25            1 :     super.dispose();
      26              :   }
      27              : 
      28              :   // 로그인 처리 함수
      29            0 :   Future<void> _login() async {
      30            0 :     if (_formKey.currentState!.validate()) {
      31            0 :       final authService = Provider.of<AuthService>(context, listen: false);
      32            0 :       final success = await authService.login(
      33            0 :         _usernameController.text.trim(),
      34            0 :         _passwordController.text,
      35              :       );
      36              : 
      37            0 :       if (success && mounted) {
      38              :         // 로그인 성공 시 홈 화면으로 이동
      39            0 :         Navigator.of(context).pushNamedAndRemoveUntil('/', (route) => false);
      40            0 :       } else if (!success && mounted) {
      41              :         // 로그인 실패 시 스낵바 표시
      42            0 :         ScaffoldMessenger.of(context).showSnackBar(
      43              :           const SnackBar(
      44              :             content: Text('로그인에 실패했습니다. 아이디와 비밀번호를 확인해주세요.'),
      45              :             backgroundColor: Colors.red,
      46              :           ),
      47              :         );
      48              :       }
      49              :     }
      50              :   }
      51              : 
      52            1 :   @override
      53              :   Widget build(BuildContext context) {
      54            1 :     final authService = Provider.of<AuthService>(context);
      55              : 
      56            1 :     return Scaffold(
      57            1 :       body: SafeArea(
      58            1 :         child: Center(
      59            1 :           child: SingleChildScrollView(
      60              :             padding: const EdgeInsets.all(24.0),
      61            1 :             child: Form(
      62            1 :               key: _formKey,
      63            1 :               child: Column(
      64              :                 mainAxisAlignment: MainAxisAlignment.center,
      65              :                 crossAxisAlignment: CrossAxisAlignment.stretch,
      66            1 :                 children: [
      67              :                   // 로고 이미지
      68            1 :                   Column(
      69            1 :                     children: [
      70            1 :                       Image.asset(
      71              :                         'assets/images/logo.png',
      72              :                         width: 120,
      73              :                         height: 120,
      74              :                       ),
      75              :                       const SizedBox(height: 16),
      76              :                       const Text(
      77              :                         '레인보우 - 볼링 클럽 매니저',
      78              :                         textAlign: TextAlign.center,
      79              :                         style: TextStyle(
      80              :                           fontSize: 24,
      81              :                           fontWeight: FontWeight.bold,
      82              :                           color: Colors.blue,
      83              :                         ),
      84              :                       ),
      85              :                     ],
      86              :                   ),
      87              :                   const SizedBox(height: 48),
      88              : 
      89              :                   // 사용자명(아이디) 입력 필드
      90            1 :                   TextFormField(
      91            1 :                     controller: _usernameController,
      92              :                     decoration: const InputDecoration(
      93              :                       labelText: '아이디',
      94              :                       prefixIcon: Icon(Icons.person),
      95              :                       border: OutlineInputBorder(),
      96              :                     ),
      97            0 :                     validator: (value) {
      98            0 :                       if (value == null || value.isEmpty) {
      99              :                         return '아이디를 입력해주세요';
     100              :                       }
     101              :                       return null;
     102              :                     },
     103              :                   ),
     104              :                   const SizedBox(height: 16),
     105              : 
     106              :                   // 비밀번호 입력 필드
     107            1 :                   TextFormField(
     108            1 :                     controller: _passwordController,
     109            1 :                     obscureText: !_isPasswordVisible,
     110            1 :                     decoration: InputDecoration(
     111              :                       labelText: '비밀번호',
     112              :                       prefixIcon: const Icon(Icons.lock),
     113              :                       border: const OutlineInputBorder(),
     114            1 :                       suffixIcon: IconButton(
     115            1 :                         icon: Icon(
     116            1 :                           _isPasswordVisible ? Icons.visibility : Icons.visibility_off,
     117              :                         ),
     118            0 :                         onPressed: () {
     119            0 :                           setState(() {
     120            0 :                             _isPasswordVisible = !_isPasswordVisible;
     121              :                           });
     122              :                         },
     123              :                       ),
     124              :                     ),
     125            0 :                     validator: (value) {
     126            0 :                       if (value == null || value.isEmpty) {
     127              :                         return '비밀번호를 입력해주세요';
     128              :                       }
     129              :                       return null;
     130              :                     },
     131              :                   ),
     132              :                   const SizedBox(height: 8),
     133              : 
     134              :                   // 로그인 상태 유지 체크박스
     135            1 :                   Row(
     136            1 :                     children: [
     137            1 :                       Checkbox(
     138            1 :                         value: _rememberMe,
     139            0 :                         onChanged: (value) {
     140            0 :                           setState(() {
     141            0 :                             _rememberMe = value ?? false;
     142              :                           });
     143              :                         },
     144              :                       ),
     145              :                       const Text('로그인 상태 유지'),
     146              :                       const Spacer(),
     147            1 :                       TextButton(
     148            0 :                         onPressed: () {
     149            0 :                           Navigator.push(
     150              :                             context,
     151            0 :                             MaterialPageRoute(
     152            0 :                               builder: (context) => const ForgotPasswordScreen(),
     153              :                             ),
     154              :                           );
     155              :                         },
     156              :                         child: const Text('비밀번호 찾기'),
     157              :                       ),
     158              :                     ],
     159              :                   ),
     160              :                   const SizedBox(height: 24),
     161              : 
     162              :                   // 로그인 버튼
     163            1 :                   ElevatedButton(
     164            2 :                     onPressed: authService.isLoading ? null : _login,
     165            1 :                     style: ElevatedButton.styleFrom(
     166              :                       padding: const EdgeInsets.symmetric(vertical: 16),
     167              :                       backgroundColor: Colors.blue,
     168              :                       foregroundColor: Colors.white,
     169              :                     ),
     170            1 :                     child: authService.isLoading
     171              :                         ? const SizedBox(
     172              :                             width: 20,
     173              :                             height: 20,
     174              :                             child: CircularProgressIndicator(
     175              :                               strokeWidth: 2,
     176              :                               color: Colors.white,
     177              :                             ),
     178              :                           )
     179              :                         : const Text(
     180              :                             '로그인',
     181              :                             style: TextStyle(fontSize: 16),
     182              :                           ),
     183              :                   ),
     184              :                   const SizedBox(height: 16),
     185              : 
     186              :                   // 회원가입 링크
     187            1 :                   Row(
     188              :                     mainAxisAlignment: MainAxisAlignment.center,
     189            1 :                     children: [
     190              :                       const Text('계정이 없으신가요?'),
     191            1 :                       TextButton(
     192            0 :                         onPressed: () {
     193            0 :                           Navigator.push(
     194              :                             context,
     195            0 :                             MaterialPageRoute(
     196            0 :                               builder: (context) => const RegisterScreen(),
     197              :                             ),
     198              :                           );
     199              :                         },
     200              :                         child: const Text('회원가입'),
     201              :                       ),
     202              :                     ],
     203              :                   ),
     204              :                 ],
     205              :               ),
     206              :             ),
     207              :           ),
     208              :         ),
     209              :       ),
     210              :     );
     211              :   }
     212              : }
        

Generated by: LCOV version 2.3.1-1