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 : }
|