feat: API 인증 시스템 구현 및 로그인 화면 연동
- AuthService, AuthRemoteDataSource 구현 - JWT 토큰 관리 (SecureStorage 사용) - 로그인 화면 API 연동 및 에러 처리 - freezed 패키지로 Auth 관련 DTO 모델 생성 - 의존성 주입 설정 업데이트
This commit is contained in:
@@ -27,10 +27,7 @@ class _LoginViewRedesignState extends State<LoginViewRedesign>
|
||||
late AnimationController _slideController;
|
||||
late Animation<Offset> _slideAnimation;
|
||||
|
||||
final _usernameController = TextEditingController();
|
||||
final _passwordController = TextEditingController();
|
||||
bool _rememberMe = false;
|
||||
bool _isLoading = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -66,39 +63,23 @@ class _LoginViewRedesignState extends State<LoginViewRedesign>
|
||||
void dispose() {
|
||||
_fadeController.dispose();
|
||||
_slideController.dispose();
|
||||
_usernameController.dispose();
|
||||
_passwordController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Future<void> _handleLogin() async {
|
||||
if (_usernameController.text.isEmpty || _passwordController.text.isEmpty) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('사용자명과 비밀번호를 입력해주세요.'),
|
||||
backgroundColor: ShadcnTheme.destructive,
|
||||
),
|
||||
);
|
||||
return;
|
||||
final success = await widget.controller.login();
|
||||
if (success) {
|
||||
widget.onLoginSuccess();
|
||||
}
|
||||
|
||||
setState(() {
|
||||
_isLoading = true;
|
||||
});
|
||||
|
||||
// 실제 로그인 로직 (임시로 2초 대기)
|
||||
await Future.delayed(const Duration(seconds: 2));
|
||||
|
||||
setState(() {
|
||||
_isLoading = false;
|
||||
});
|
||||
|
||||
widget.onLoginSuccess();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
return ChangeNotifierProvider.value(
|
||||
value: widget.controller,
|
||||
child: Consumer<LoginController>(
|
||||
builder: (context, controller, _) {
|
||||
return Scaffold(
|
||||
backgroundColor: ShadcnTheme.background,
|
||||
body: SafeArea(
|
||||
child: Center(
|
||||
@@ -128,6 +109,8 @@ class _LoginViewRedesignState extends State<LoginViewRedesign>
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -190,6 +173,7 @@ class _LoginViewRedesignState extends State<LoginViewRedesign>
|
||||
}
|
||||
|
||||
Widget _buildLoginCard() {
|
||||
final controller = context.watch<LoginController>();
|
||||
return ShadcnCard(
|
||||
padding: const EdgeInsets.all(ShadcnTheme.spacing8),
|
||||
child: Column(
|
||||
@@ -210,7 +194,7 @@ class _LoginViewRedesignState extends State<LoginViewRedesign>
|
||||
ShadcnInput(
|
||||
label: '사용자명',
|
||||
placeholder: '사용자명을 입력하세요',
|
||||
controller: _usernameController,
|
||||
controller: controller.idController,
|
||||
prefixIcon: const Icon(Icons.person_outline),
|
||||
keyboardType: TextInputType.text,
|
||||
),
|
||||
@@ -220,7 +204,7 @@ class _LoginViewRedesignState extends State<LoginViewRedesign>
|
||||
ShadcnInput(
|
||||
label: '비밀번호',
|
||||
placeholder: '비밀번호를 입력하세요',
|
||||
controller: _passwordController,
|
||||
controller: controller.pwController,
|
||||
prefixIcon: const Icon(Icons.lock_outline),
|
||||
obscureText: true,
|
||||
keyboardType: TextInputType.visiblePassword,
|
||||
@@ -231,11 +215,9 @@ class _LoginViewRedesignState extends State<LoginViewRedesign>
|
||||
Row(
|
||||
children: [
|
||||
Checkbox(
|
||||
value: _rememberMe,
|
||||
value: controller.saveId,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
_rememberMe = value ?? false;
|
||||
});
|
||||
controller.setSaveId(value ?? false);
|
||||
},
|
||||
activeColor: ShadcnTheme.primary,
|
||||
),
|
||||
@@ -244,6 +226,38 @@ class _LoginViewRedesignState extends State<LoginViewRedesign>
|
||||
],
|
||||
),
|
||||
const SizedBox(height: ShadcnTheme.spacing8),
|
||||
|
||||
// 에러 메시지 표시
|
||||
if (controller.errorMessage != null)
|
||||
Container(
|
||||
padding: const EdgeInsets.all(ShadcnTheme.spacing3),
|
||||
margin: const EdgeInsets.only(bottom: ShadcnTheme.spacing4),
|
||||
decoration: BoxDecoration(
|
||||
color: ShadcnTheme.destructive.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(ShadcnTheme.borderRadius),
|
||||
border: Border.all(
|
||||
color: ShadcnTheme.destructive.withOpacity(0.3),
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.error_outline,
|
||||
size: 20,
|
||||
color: ShadcnTheme.destructive,
|
||||
),
|
||||
const SizedBox(width: ShadcnTheme.spacing2),
|
||||
Expanded(
|
||||
child: Text(
|
||||
controller.errorMessage!,
|
||||
style: ShadcnTheme.bodyMedium.copyWith(
|
||||
color: ShadcnTheme.destructive,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
// 로그인 버튼
|
||||
ShadcnButton(
|
||||
@@ -253,7 +267,7 @@ class _LoginViewRedesignState extends State<LoginViewRedesign>
|
||||
textColor: Colors.white,
|
||||
size: ShadcnButtonSize.large,
|
||||
fullWidth: true,
|
||||
loading: _isLoading,
|
||||
loading: controller.isLoading,
|
||||
),
|
||||
const SizedBox(height: ShadcnTheme.spacing4),
|
||||
|
||||
@@ -261,8 +275,8 @@ class _LoginViewRedesignState extends State<LoginViewRedesign>
|
||||
ShadcnButton(
|
||||
text: '테스트 로그인',
|
||||
onPressed: () {
|
||||
_usernameController.text = 'admin';
|
||||
_passwordController.text = 'password';
|
||||
controller.idController.text = 'admin@example.com';
|
||||
controller.pwController.text = 'admin123';
|
||||
_handleLogin();
|
||||
},
|
||||
variant: ShadcnButtonVariant.secondary,
|
||||
|
||||
Reference in New Issue
Block a user