merged login and home

This commit is contained in:
amirrezaghabeli
2025-08-03 09:44:43 +03:30
parent 24e14b325a
commit 7aa082c6c8
40 changed files with 979 additions and 49 deletions
+74 -46
View File
@@ -1,8 +1,13 @@
// lib/views/login_screen.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../view_models/auth_view_model.dart';
import '../core/constants/assets.dart';
import '../core/constants/texts.dart';
import '../size_config.dart';
import '../views/widget/login_button.dart';
import '../views/widget/login_logo.dart';
import '../views/widget/login_textfield.dart';
import '../views/widget/login_title.dart';
class LoginScreen extends StatefulWidget {
const LoginScreen({super.key});
@@ -12,58 +17,81 @@ class LoginScreen extends StatefulWidget {
}
class _LoginScreenState extends State<LoginScreen> {
final _emailController = TextEditingController();
final _usernameController = TextEditingController();
final _passwordController = TextEditingController();
final _usernameFocus = FocusNode();
final _passwordFocus = FocusNode();
bool _obscurePassword = true;
bool get _isLoginEnabled =>
_usernameController.text.isNotEmpty &&
_passwordController.text.isNotEmpty;
@override
void initState() {
super.initState();
_usernameController.addListener(_updateState);
_passwordController.addListener(_updateState);
_usernameFocus.addListener(_updateState);
_passwordFocus.addListener(_updateState);
}
@override
void dispose() {
_usernameController.dispose();
_passwordController.dispose();
_usernameFocus.dispose();
_passwordFocus.dispose();
super.dispose();
}
void _updateState() => setState(() {});
void _togglePasswordVisibility() =>
setState(() => _obscurePassword = !_obscurePassword);
@override
Widget build(BuildContext context) {
final authViewModel = Provider.of<AuthViewModel>(context);
return Scaffold(
appBar: AppBar(title: const Text('Login')),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
TextField(
controller: _emailController,
decoration: const InputDecoration(labelText: 'Email'),
),
TextField(
controller: _passwordController,
decoration: const InputDecoration(labelText: 'Password'),
obscureText: true,
),
const SizedBox(height: 20),
if (authViewModel.isLoading)
const CircularProgressIndicator()
else
ElevatedButton(
onPressed: () {
authViewModel.login(
_emailController.text,
_passwordController.text,
);
},
child: const Text('Login'),
backgroundColor: Colors.white,
body: Center(
child: SingleChildScrollView(
padding: EdgeInsets.symmetric(horizontal: 24.0.w()),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const LoginLogo(),
SizedBox(height: 32.0.h()),
const LoginTitle(),
SizedBox(height: 32.0.h()),
LoginTextField(
controller: _usernameController,
focusNode: _usernameFocus,
label: TextManager.usernameLabel,
iconPath: AssetsManager.userIcon,
),
if (authViewModel.errorMessage != null)
Padding(
padding: const EdgeInsets.only(top: 20),
child: Text(
authViewModel.errorMessage!,
style: const TextStyle(color: Colors.red),
),
SizedBox(height: 16.0.h()),
LoginTextField(
controller: _passwordController,
focusNode: _passwordFocus,
label: TextManager.passwordLabel,
iconPath: AssetsManager.passwordIcon,
isPassword: true,
obscureText: _obscurePassword,
onToggleVisibility: _togglePasswordVisibility,
),
if (authViewModel.loggedInUser != null)
Padding(
padding: const EdgeInsets.only(top: 20),
child: Text(
'Welcome, ${authViewModel.loggedInUser!.name}!',
style: const TextStyle(color: Colors.green),
),
SizedBox(height: 32.0.h()),
LoginButton(
isEnabled: _isLoginEnabled,
onPressed: _isLoginEnabled ? () {} : null,
),
],
],
),
),
),
);
+38
View File
@@ -0,0 +1,38 @@
import 'package:flutter/material.dart';
import '../../core/constants/colors.dart';
import '../../core/constants/texts.dart';
import '../../size_config.dart';
class LoginButton extends StatelessWidget {
final bool isEnabled;
final VoidCallback? onPressed;
const LoginButton({
super.key,
required this.isEnabled,
required this.onPressed,
});
@override
Widget build(BuildContext context) {
return SizedBox(
width: double.infinity,
height: 55.0.h(),
child: ElevatedButton(
onPressed: onPressed,
style: ElevatedButton.styleFrom(
backgroundColor: isEnabled ? ColorManager.mainBlue : Colors.grey[300],
foregroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(28.0.w()),
),
),
child: Text(
TextManager.loginButton,
style: TextStyle(fontSize: 16.0.sp(), fontWeight: FontWeight.bold),
),
),
);
}
}
+13
View File
@@ -0,0 +1,13 @@
import 'package:flutter/material.dart';
import '../../core/constants/assets.dart';
import '../../size_config.dart';
class LoginLogo extends StatelessWidget {
const LoginLogo({super.key});
@override
Widget build(BuildContext context) {
return Image.asset(AssetsManager.logo, width: 190.0.w(), height: 88.0.h());
}
}
+75
View File
@@ -0,0 +1,75 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import '../../core/constants/assets.dart';
import '../../core/constants/colors.dart';
import '../../size_config.dart';
class LoginTextField extends StatelessWidget {
final TextEditingController controller;
final FocusNode focusNode;
final String label;
final String iconPath;
final bool isPassword;
final bool obscureText;
final VoidCallback? onToggleVisibility;
const LoginTextField({
super.key,
required this.controller,
required this.focusNode,
required this.label,
required this.iconPath,
this.isPassword = false,
this.obscureText = false,
this.onToggleVisibility,
});
@override
Widget build(BuildContext context) {
return TextField(
controller: controller,
focusNode: focusNode,
obscureText: isPassword ? obscureText : false,
decoration: InputDecoration(
labelText: label,
prefixIcon: Padding(
padding: EdgeInsets.all(12.0.w()),
child: SvgPicture.asset(
iconPath,
width: 24.0.w(),
height: 24.0.h(),
colorFilter: ColorFilter.mode(
focusNode.hasFocus ? Colors.black87 : Colors.grey,
BlendMode.srcIn,
),
),
),
suffixIcon:
isPassword
? IconButton(
onPressed: onToggleVisibility,
icon: SvgPicture.asset(
obscureText
? AssetsManager.passwordVisibility
: AssetsManager.passwordVisibilityOff,
width: 24.0.w(),
height: 24.0.h(),
colorFilter: ColorFilter.mode(
focusNode.hasFocus ? Colors.black87 : Colors.grey,
BlendMode.srcIn,
),
),
)
: null,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12.0.w()),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: ColorManager.borderBlue),
borderRadius: BorderRadius.circular(12.0.w()),
),
),
);
}
}
+30
View File
@@ -0,0 +1,30 @@
import 'package:flutter/material.dart';
import '../../core/constants/texts.dart';
import '../../size_config.dart';
class LoginTitle extends StatelessWidget {
const LoginTitle({super.key});
@override
Widget build(BuildContext context) {
return Column(
children: [
Text(
TextManager.signInTitle,
style: TextStyle(fontSize: 28.0.sp(), fontWeight: FontWeight.w700),
),
SizedBox(height: 8.0.h()),
Text(
TextManager.signInSubtitle,
style: TextStyle(
fontSize: 14.0.sp(),
fontWeight: FontWeight.w400,
color: Colors.grey,
),
textAlign: TextAlign.center,
),
],
);
}
}