chitfund/luckychit/lib/features/auth/views/login_screen.dart

150 lines
5.5 KiB
Dart

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import '../../../core/services/auth_service.dart';
import '../../../core/utils/snackbar_util.dart';
import '../../../core/design_system/app_components/auth_shell.dart';
import '../../../core/design_system/app_components/app_card.dart';
import '../../../core/design_system/app_spacing.dart';
import '../../../core/design_system/app_text.dart';
import '../../../l10n/l10n_x.dart';
import 'signup_screen.dart';
class LoginScreen extends StatefulWidget {
const LoginScreen({super.key});
@override
State<LoginScreen> createState() => _LoginScreenState();
}
class _LoginScreenState extends State<LoginScreen> {
final _formKey = GlobalKey<FormState>();
final _mobileController = TextEditingController();
final _passwordController = TextEditingController();
final _authService = Get.find<AuthService>();
bool _isPasswordVisible = false;
@override
void dispose() {
_mobileController.dispose();
_passwordController.dispose();
super.dispose();
}
Future<void> _handleLogin() async {
if (_formKey.currentState!.validate()) {
final success = await _authService.login(
_mobileController.text.trim(),
_passwordController.text,
);
if (!success && mounted) {
final l = context.l10n;
SnackbarUtil.showError(
l.loginInvalidCredentials,
title: l.loginFailedTitle,
);
}
}
}
@override
Widget build(BuildContext context) {
final l = context.l10n;
final scheme = Theme.of(context).colorScheme;
return Scaffold(
body: AuthShell(
child: SingleChildScrollView(
child: AppCard(
padding: AppSpacing.all(AppSpacing.lg),
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisSize: MainAxisSize.min,
children: [
Semantics(
label: '${l.appDisplayName} logo',
child: Icon(
Icons.account_balance_wallet_rounded,
size: 56.w,
color: scheme.primary,
),
),
SizedBox(height: 16.h),
Text(l.appDisplayName, style: AppText.headline(context), textAlign: TextAlign.center),
SizedBox(height: 6.h),
Text(
l.authLoginTagline,
style: AppText.bodyMuted(context),
textAlign: TextAlign.center,
),
SizedBox(height: 24.h),
TextFormField(
controller: _mobileController,
keyboardType: TextInputType.phone,
textInputAction: TextInputAction.next,
decoration: InputDecoration(
labelText: l.labelMobileNumber,
prefixIcon: const Icon(Icons.phone_rounded),
),
validator: (value) {
if (value == null || value.isEmpty) return l.validatorEnterMobile;
if (value.length != 10) return l.validatorMobileTenDigits;
return null;
},
),
SizedBox(height: 14.h),
TextFormField(
controller: _passwordController,
obscureText: !_isPasswordVisible,
textInputAction: TextInputAction.done,
decoration: InputDecoration(
labelText: l.labelPassword,
prefixIcon: const Icon(Icons.lock_rounded),
suffixIcon: IconButton(
tooltip: _isPasswordVisible ? l.tooltipHidePassword : l.tooltipShowPassword,
icon: Icon(_isPasswordVisible ? Icons.visibility : Icons.visibility_off),
onPressed: () => setState(() => _isPasswordVisible = !_isPasswordVisible),
),
),
validator: (value) {
if (value == null || value.isEmpty) return l.validatorEnterPasswordAuth;
if (value.length < 6) return l.validatorPasswordMinSixAuth;
return null;
},
),
SizedBox(height: 20.h),
Obx(() {
final busy = _authService.isLoading.value;
return FilledButton(
onPressed: busy ? null : _handleLogin,
child: busy
? SizedBox(
height: 18.h,
width: 18.w,
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation<Color>(scheme.onPrimary),
),
)
: Text(l.signInButton),
);
}),
SizedBox(height: 10.h),
OutlinedButton(
onPressed: () => Get.to(() => const SignupScreen()),
child: Text(l.createAccountButton),
),
],
),
),
),
),
),
);
}
}