import 'package:flutter/material.dart'; import 'package:superport/screens/common/theme_shadcn.dart'; import 'package:superport/screens/common/components/shadcn_components.dart'; import 'package:superport/screens/login/controllers/login_controller.dart'; import 'dart:math' as math; /// shadcn/ui 스타일로 재설계된 로그인 화면 class LoginViewRedesign extends StatefulWidget { final LoginController controller; final VoidCallback onLoginSuccess; const LoginViewRedesign({ Key? key, required this.controller, required this.onLoginSuccess, }) : super(key: key); @override State createState() => _LoginViewRedesignState(); } class _LoginViewRedesignState extends State with TickerProviderStateMixin { late AnimationController _fadeController; late Animation _fadeAnimation; late AnimationController _slideController; late Animation _slideAnimation; @override void initState() { super.initState(); _setupAnimations(); } void _setupAnimations() { _fadeController = AnimationController( duration: const Duration(milliseconds: 1000), vsync: this, ); _fadeAnimation = Tween(begin: 0.0, end: 1.0).animate( CurvedAnimation(parent: _fadeController, curve: Curves.easeInOut), ); _slideController = AnimationController( duration: const Duration(milliseconds: 800), vsync: this, ); _slideAnimation = Tween( begin: const Offset(0, 0.3), end: Offset.zero, ).animate( CurvedAnimation(parent: _slideController, curve: Curves.easeOutCubic), ); _fadeController.forward(); _slideController.forward(); } @override void dispose() { _fadeController.dispose(); _slideController.dispose(); super.dispose(); } Future _handleLogin() async { final success = await widget.controller.login(); if (success) { widget.onLoginSuccess(); } } @override Widget build(BuildContext context) { return ListenableBuilder( listenable: widget.controller, builder: (context, _) { return Scaffold( backgroundColor: ShadcnTheme.background, body: SafeArea( child: Center( child: SingleChildScrollView( physics: const BouncingScrollPhysics(), child: Padding( padding: const EdgeInsets.all(ShadcnTheme.spacing6), child: ConstrainedBox( constraints: const BoxConstraints(maxWidth: 400), child: FadeTransition( opacity: _fadeAnimation, child: SlideTransition( position: _slideAnimation, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ _buildHeader(), const SizedBox(height: ShadcnTheme.spacing12), _buildLoginCard(), const SizedBox(height: ShadcnTheme.spacing8), _buildFooter(), ], ), ), ), ), ), ), ), ), ); }, ); } Widget _buildHeader() { return Column( children: [ // 로고 및 애니메이션 Container( padding: const EdgeInsets.all(ShadcnTheme.spacing4), decoration: BoxDecoration( shape: BoxShape.circle, gradient: LinearGradient( colors: [ ShadcnTheme.gradient1, ShadcnTheme.gradient2, ShadcnTheme.gradient3, ], begin: Alignment.topLeft, end: Alignment.bottomRight, ), boxShadow: [ BoxShadow( color: ShadcnTheme.gradient1.withValues(alpha: 0.3), blurRadius: 20, offset: const Offset(0, 10), ), ], ), child: AnimatedBuilder( animation: _fadeController, builder: (context, child) { return Transform.rotate( angle: _fadeController.value * 2 * math.pi * 0.1, child: Icon( Icons.directions_boat, size: 48, color: ShadcnTheme.primaryForeground, ), ); }, ), ), const SizedBox(height: ShadcnTheme.spacing6), // 앱 이름 Text( 'supERPort', style: ShadcnTheme.headingH1.copyWith( foreground: Paint() ..shader = LinearGradient( colors: [ShadcnTheme.gradient1, ShadcnTheme.gradient2], ).createShader(const Rect.fromLTWH(0, 0, 200, 70)), ), ), const SizedBox(height: ShadcnTheme.spacing2), Text('스마트 ERP 시스템', style: ShadcnTheme.bodyMuted), ], ); } Widget _buildLoginCard() { final controller = widget.controller; return ShadcnCard( padding: const EdgeInsets.all(ShadcnTheme.spacing8), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // 로그인 헤더 Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('로그인', style: ShadcnTheme.headingH3), const SizedBox(height: ShadcnTheme.spacing1), Text('계정 정보를 입력하여 로그인하세요.', style: ShadcnTheme.bodyMuted), ], ), const SizedBox(height: ShadcnTheme.spacing8), // 아이디/이메일 입력 ShadcnInput( label: '아이디/이메일', placeholder: '아이디 또는 이메일을 입력하세요', controller: controller.idController, prefixIcon: const Icon(Icons.person_outline), keyboardType: TextInputType.text, ), const SizedBox(height: ShadcnTheme.spacing4), // 비밀번호 입력 ShadcnInput( label: '비밀번호', placeholder: '비밀번호를 입력하세요', controller: controller.pwController, prefixIcon: const Icon(Icons.lock_outline), obscureText: true, keyboardType: TextInputType.visiblePassword, ), const SizedBox(height: ShadcnTheme.spacing4), // 아이디 저장 체크박스 Row( children: [ Checkbox( value: controller.saveId, onChanged: (value) { controller.setSaveId(value ?? false); }, activeColor: ShadcnTheme.primary, ), const SizedBox(width: ShadcnTheme.spacing2), Text('아이디 저장', style: ShadcnTheme.bodyMedium), ], ), 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.withValues(alpha: 0.1), borderRadius: BorderRadius.circular(ShadcnTheme.radiusMd), border: Border.all( color: ShadcnTheme.destructive.withValues(alpha: 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( text: '로그인', onPressed: _handleLogin, variant: ShadcnButtonVariant.primary, textColor: Colors.white, size: ShadcnButtonSize.large, fullWidth: true, loading: controller.isLoading, ), const SizedBox(height: ShadcnTheme.spacing4), // 테스트 로그인 버튼 ShadcnButton( text: '테스트 로그인', onPressed: () async { // 테스트 계정 정보 자동 입력 widget.controller.idController.text = 'admin@superport.kr'; widget.controller.pwController.text = 'admin123!'; // 실제 로그인 프로세스 실행 await _handleLogin(); }, variant: ShadcnButtonVariant.secondary, size: ShadcnButtonSize.medium, fullWidth: true, ), ], ), ); } Widget _buildFooter() { return Column( children: [ // 기능 소개 Container( padding: const EdgeInsets.all(ShadcnTheme.spacing4), decoration: BoxDecoration( color: ShadcnTheme.muted, borderRadius: BorderRadius.circular(ShadcnTheme.radiusLg), border: Border.all(color: Colors.black), ), child: Row( children: [ Container( padding: const EdgeInsets.all(ShadcnTheme.spacing2), decoration: BoxDecoration( color: ShadcnTheme.info.withValues(alpha: 0.1), borderRadius: BorderRadius.circular(ShadcnTheme.radiusMd), ), child: Icon( Icons.info_outline, size: 16, color: ShadcnTheme.info, ), ), const SizedBox(width: ShadcnTheme.spacing3), Expanded( child: Text( '장비 관리, 회사 관리, 사용자 관리 등\n포트 운영에 필요한 모든 기능을 제공합니다.', style: ShadcnTheme.bodySmall, ), ), ], ), ), const SizedBox(height: ShadcnTheme.spacing6), // 저작권 정보 Text( 'Copyright 2025 NatureBridgeAI. All rights reserved.', style: ShadcnTheme.bodySmall.copyWith( color: ShadcnTheme.foreground.withValues(alpha: 0.7), fontWeight: FontWeight.w500, ), ), ], ); } }