From 83ca1690591e80a8fa8217b8c2841fccfa4c3f65 Mon Sep 17 00:00:00 2001 From: llsajjad Date: Sat, 9 Aug 2025 17:25:19 +0330 Subject: [PATCH] changed logoRepository to authRepository --- lib/core/config/dependencies.dart | 2 +- lib/view_models/auth_view_model.dart | 47 ++++++++++-- lib/view_models/login_view_model.dart | 42 ----------- lib/views/login/pages/login_desktop_page.dart | 70 +++++++++--------- lib/views/login/pages/login_mobile_page.dart | 71 +++++++++---------- lib/views/login/pages/login_tablet_page.dart | 70 +++++++++--------- 6 files changed, 138 insertions(+), 164 deletions(-) delete mode 100644 lib/view_models/login_view_model.dart diff --git a/lib/core/config/dependencies.dart b/lib/core/config/dependencies.dart index 47949cb..b6fb3cc 100644 --- a/lib/core/config/dependencies.dart +++ b/lib/core/config/dependencies.dart @@ -32,7 +32,7 @@ List get repositories { List get viewModels { return [ - Provider( + ChangeNotifierProvider( create: (context) => AuthViewModel(authRepository: context.read()), ), ]; diff --git a/lib/view_models/auth_view_model.dart b/lib/view_models/auth_view_model.dart index 40492ac..0b2ba07 100644 --- a/lib/view_models/auth_view_model.dart +++ b/lib/view_models/auth_view_model.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; - import '../core/utils/result.dart'; import '../data/models/user_model.dart'; import '../data/repositories/auth_repository.dart'; @@ -8,8 +7,25 @@ class AuthViewModel with ChangeNotifier { final AuthRepository _authRepository; AuthViewModel({required AuthRepository authRepository}) - : _authRepository = authRepository; + : _authRepository = authRepository { + usernameController.addListener(_onTextChanged); + passwordController.addListener(_onTextChanged); + usernameFocus.addListener(_onTextChanged); + passwordFocus.addListener(_onTextChanged); + } + final TextEditingController usernameController = TextEditingController(); + final TextEditingController passwordController = TextEditingController(); + final FocusNode usernameFocus = FocusNode(); + final FocusNode passwordFocus = FocusNode(); + + bool _obscurePassword = true; + bool get obscurePassword => _obscurePassword; + bool get isLoginEnabled => + usernameController.text.isNotEmpty && + passwordController.text.isNotEmpty; + + // Auth state bool _isLoading = false; String? _errorMessage; UserModel? _loggedInUser; @@ -18,25 +34,44 @@ class AuthViewModel with ChangeNotifier { String? get errorMessage => _errorMessage; UserModel? get loggedInUser => _loggedInUser; - Future login(String email, String password) async { + void togglePasswordVisibility() { + _obscurePassword = !_obscurePassword; + notifyListeners(); + } + + void _onTextChanged() { + notifyListeners(); + } + + Future login() async { _isLoading = true; _errorMessage = null; notifyListeners(); - final result = await _authRepository.login(email, password); + final result = await _authRepository.login( + usernameController.text.trim(), + passwordController.text.trim(), + ); switch (result) { case Ok(): _loggedInUser = result.value; - // موفقیت‌آمیز break; case Error(): _errorMessage = result.error.toString(); - // خطا break; } _isLoading = false; notifyListeners(); } + + @override + void dispose() { + usernameController.dispose(); + passwordController.dispose(); + usernameFocus.dispose(); + passwordFocus.dispose(); + super.dispose(); + } } diff --git a/lib/view_models/login_view_model.dart b/lib/view_models/login_view_model.dart deleted file mode 100644 index 340539d..0000000 --- a/lib/view_models/login_view_model.dart +++ /dev/null @@ -1,42 +0,0 @@ -// lib/view_models/login_view_model.dart -import 'package:flutter/material.dart'; - -class LoginViewModel with ChangeNotifier { - final TextEditingController usernameController = TextEditingController(); - final TextEditingController passwordController = TextEditingController(); - - final FocusNode usernameFocus = FocusNode(); - final FocusNode passwordFocus = FocusNode(); - - bool _obscurePassword = true; - - LoginViewModel() { - usernameController.addListener(_onTextChanged); - passwordController.addListener(_onTextChanged); - usernameFocus.addListener(_onTextChanged); - passwordFocus.addListener(_onTextChanged); - } - - bool get obscurePassword => _obscurePassword; - bool get isLoginEnabled => - usernameController.text.isNotEmpty && - passwordController.text.isNotEmpty; - - void togglePasswordVisibility() { - _obscurePassword = !_obscurePassword; - notifyListeners(); - } - - void _onTextChanged() { - notifyListeners(); - } - - @override - void dispose() { - usernameController.dispose(); - passwordController.dispose(); - usernameFocus.dispose(); - passwordFocus.dispose(); - super.dispose(); - } -} diff --git a/lib/views/login/pages/login_desktop_page.dart b/lib/views/login/pages/login_desktop_page.dart index f9bf5ed..c706ab0 100644 --- a/lib/views/login/pages/login_desktop_page.dart +++ b/lib/views/login/pages/login_desktop_page.dart @@ -1,36 +1,17 @@ -// lib/views/login_desktop_screen.dart import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; import 'package:tm_app/core/routes/app_routes.dart'; import 'package:tm_app/core/theme/colors.dart'; import '../../../core/constants/assets.dart'; import '../../../core/constants/strings.dart'; import '../../../core/utils/size_config.dart'; -import '../../../view_models/login_view_model.dart'; +import '../../../view_models/auth_view_model.dart'; import '../widgets/widgets.dart'; -class LoginDesktopPage extends StatefulWidget { +class LoginDesktopPage extends StatelessWidget { const LoginDesktopPage({super.key}); - @override - State createState() => _LoginDesktopPageState(); -} - -class _LoginDesktopPageState extends State { - late final LoginViewModel _viewModel; - - @override - void initState() { - super.initState(); - _viewModel = LoginViewModel(); - } - - @override - void dispose() { - _viewModel.dispose(); - super.dispose(); - } - @override Widget build(BuildContext context) { SizeConfig.init(context); @@ -41,9 +22,8 @@ class _LoginDesktopPageState extends State { padding: EdgeInsets.symmetric(horizontal: 24.0.w()), child: SizedBox( width: 526, - child: ListenableBuilder( - listenable: _viewModel, - builder: (context, _) { + child: Consumer( + builder: (context, viewModel, _) { return Column( mainAxisSize: MainAxisSize.min, children: [ @@ -53,8 +33,8 @@ class _LoginDesktopPageState extends State { SizedBox(height: 32.0.h()), LoginTextField( - controller: _viewModel.usernameController, - focusNode: _viewModel.usernameFocus, + controller: viewModel.usernameController, + focusNode: viewModel.usernameFocus, label: AppStrings.usernameLabel, iconPath: AssetsManager.userIcon, fieldHeight: 60.0.h(), @@ -64,26 +44,40 @@ class _LoginDesktopPageState extends State { SizedBox(height: 16.0.h()), LoginTextField( - controller: _viewModel.passwordController, - focusNode: _viewModel.passwordFocus, + controller: viewModel.passwordController, + focusNode: viewModel.passwordFocus, label: AppStrings.passwordLabel, iconPath: AssetsManager.passwordIcon, prefixIconPadding: 4.0.w(), isPassword: true, - obscureText: _viewModel.obscurePassword, + obscureText: viewModel.obscurePassword, fieldHeight: 60.0.h(), - onToggleVisibility: _viewModel.togglePasswordVisibility, + onToggleVisibility: viewModel.togglePasswordVisibility, borderRedus: 4.0.w(), ), SizedBox(height: 32.0.h()), - BaseButton( - isEnabled: _viewModel.isLoginEnabled, - onPressed: - _viewModel.isLoginEnabled - ? () => HomeRouteData().go(context) - : null, - ), + if (viewModel.isLoading) + const CircularProgressIndicator() + else + BaseButton( + isEnabled: viewModel.isLoginEnabled, + onPressed: + viewModel.isLoginEnabled + ? () async { + await viewModel.login(); + if (viewModel.loggedInUser != null) { + HomeRouteData().go(context); + } else if (viewModel.errorMessage != null) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(viewModel.errorMessage!), + ), + ); + } + } + : null, + ), ], ); }, diff --git a/lib/views/login/pages/login_mobile_page.dart b/lib/views/login/pages/login_mobile_page.dart index 2f1ac24..9912c6d 100644 --- a/lib/views/login/pages/login_mobile_page.dart +++ b/lib/views/login/pages/login_mobile_page.dart @@ -1,36 +1,17 @@ -// lib/views/login_screen.dart import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; import 'package:tm_app/core/routes/app_routes.dart'; import 'package:tm_app/core/theme/colors.dart'; import '../../../core/constants/assets.dart'; import '../../../core/constants/strings.dart'; import '../../../core/utils/size_config.dart'; +import '../../../view_models/auth_view_model.dart'; import '../widgets/widgets.dart'; -import '../../../view_models/login_view_model.dart'; -class LoginMobilePage extends StatefulWidget { +class LoginMobilePage extends StatelessWidget { const LoginMobilePage({super.key}); - @override - State createState() => _LoginMobilePageState(); -} - -class _LoginMobilePageState extends State { - late final LoginViewModel _viewModel; - - @override - void initState() { - super.initState(); - _viewModel = LoginViewModel(); - } - - @override - void dispose() { - _viewModel.dispose(); - super.dispose(); - } - @override Widget build(BuildContext context) { SizeConfig.init(context); @@ -40,9 +21,8 @@ class _LoginMobilePageState extends State { body: Center( child: SingleChildScrollView( padding: EdgeInsets.symmetric(horizontal: 24.0.w()), - child: ListenableBuilder( - listenable: _viewModel, - builder: (context, _) { + child: Consumer( + builder: (context, viewModel, _) { return Column( mainAxisSize: MainAxisSize.min, children: [ @@ -52,32 +32,45 @@ class _LoginMobilePageState extends State { SizedBox(height: 32.0.h()), LoginTextField( - controller: _viewModel.usernameController, - focusNode: _viewModel.usernameFocus, + controller: viewModel.usernameController, + focusNode: viewModel.usernameFocus, label: AppStrings.usernameLabel, iconPath: AssetsManager.userIcon, ), SizedBox(height: 16.0.h()), LoginTextField( - controller: _viewModel.passwordController, - focusNode: _viewModel.passwordFocus, + controller: viewModel.passwordController, + focusNode: viewModel.passwordFocus, label: AppStrings.passwordLabel, iconPath: AssetsManager.passwordIcon, isPassword: true, - obscureText: _viewModel.obscurePassword, - onToggleVisibility: _viewModel.togglePasswordVisibility, + obscureText: viewModel.obscurePassword, + onToggleVisibility: viewModel.togglePasswordVisibility, ), SizedBox(height: 32.0.h()), - BaseButton( - isEnabled: _viewModel.isLoginEnabled, - onPressed: _viewModel.isLoginEnabled - ? () { - HomeRouteData().go(context); - } - : null, - ), + if (viewModel.isLoading) + const CircularProgressIndicator() + else + BaseButton( + isEnabled: viewModel.isLoginEnabled, + onPressed: + viewModel.isLoginEnabled + ? () async { + await viewModel.login(); + if (viewModel.loggedInUser != null) { + HomeRouteData().go(context); + } else if (viewModel.errorMessage != null) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(viewModel.errorMessage!), + ), + ); + } + } + : null, + ), ], ); }, diff --git a/lib/views/login/pages/login_tablet_page.dart b/lib/views/login/pages/login_tablet_page.dart index 64a36aa..d054420 100644 --- a/lib/views/login/pages/login_tablet_page.dart +++ b/lib/views/login/pages/login_tablet_page.dart @@ -1,36 +1,17 @@ -// lib/views/login_tablet_screen.dart import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; import 'package:tm_app/core/routes/app_routes.dart'; import 'package:tm_app/core/theme/colors.dart'; import '../../../core/constants/assets.dart'; import '../../../core/constants/strings.dart'; import '../../../core/utils/size_config.dart'; -import '../../../view_models/login_view_model.dart'; +import '../../../view_models/auth_view_model.dart'; import '../widgets/widgets.dart'; -class LoginTabletPage extends StatefulWidget { +class LoginTabletPage extends StatelessWidget { const LoginTabletPage({super.key}); - @override - State createState() => _LoginTabletPageState(); -} - -class _LoginTabletPageState extends State { - late final LoginViewModel _viewModel; - - @override - void initState() { - super.initState(); - _viewModel = LoginViewModel(); - } - - @override - void dispose() { - _viewModel.dispose(); - super.dispose(); - } - @override Widget build(BuildContext context) { SizeConfig.init(context); @@ -41,9 +22,8 @@ class _LoginTabletPageState extends State { padding: EdgeInsets.symmetric(horizontal: 24.0.w()), child: SizedBox( width: 526, - child: ListenableBuilder( - listenable: _viewModel, - builder: (context, _) { + child: Consumer( + builder: (context, viewModel, _) { return Column( mainAxisSize: MainAxisSize.min, children: [ @@ -53,8 +33,8 @@ class _LoginTabletPageState extends State { SizedBox(height: 32.0.h()), LoginTextField( - controller: _viewModel.usernameController, - focusNode: _viewModel.usernameFocus, + controller: viewModel.usernameController, + focusNode: viewModel.usernameFocus, label: AppStrings.usernameLabel, iconPath: AssetsManager.userIcon, fieldHeight: 60.0.h(), @@ -64,26 +44,40 @@ class _LoginTabletPageState extends State { SizedBox(height: 16.0.h()), LoginTextField( - controller: _viewModel.passwordController, - focusNode: _viewModel.passwordFocus, + controller: viewModel.passwordController, + focusNode: viewModel.passwordFocus, label: AppStrings.passwordLabel, iconPath: AssetsManager.passwordIcon, prefixIconPadding: 4.0.w(), isPassword: true, - obscureText: _viewModel.obscurePassword, + obscureText: viewModel.obscurePassword, fieldHeight: 60.0.h(), - onToggleVisibility: _viewModel.togglePasswordVisibility, + onToggleVisibility: viewModel.togglePasswordVisibility, borderRedus: 4.0.w(), ), SizedBox(height: 32.0.h()), - BaseButton( - isEnabled: _viewModel.isLoginEnabled, - onPressed: - _viewModel.isLoginEnabled - ? () => HomeRouteData().go(context) - : null, - ), + if (viewModel.isLoading) + const CircularProgressIndicator() + else + BaseButton( + isEnabled: viewModel.isLoginEnabled, + onPressed: + viewModel.isLoginEnabled + ? () async { + await viewModel.login(); + if (viewModel.loggedInUser != null) { + HomeRouteData().go(context); + } else if (viewModel.errorMessage != null) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(viewModel.errorMessage!), + ), + ); + } + } + : null, + ), ], ); },