changed logoRepository to authRepository

This commit is contained in:
llsajjad
2025-08-09 17:25:19 +03:30
parent e468ec9c43
commit 83ca169059
6 changed files with 138 additions and 164 deletions
+1 -1
View File
@@ -32,7 +32,7 @@ List<SingleChildWidget> get repositories {
List<SingleChildWidget> get viewModels { List<SingleChildWidget> get viewModels {
return [ return [
Provider( ChangeNotifierProvider(
create: (context) => AuthViewModel(authRepository: context.read()), create: (context) => AuthViewModel(authRepository: context.read()),
), ),
]; ];
+41 -6
View File
@@ -1,5 +1,4 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../core/utils/result.dart'; import '../core/utils/result.dart';
import '../data/models/user_model.dart'; import '../data/models/user_model.dart';
import '../data/repositories/auth_repository.dart'; import '../data/repositories/auth_repository.dart';
@@ -8,8 +7,25 @@ class AuthViewModel with ChangeNotifier {
final AuthRepository _authRepository; final AuthRepository _authRepository;
AuthViewModel({required 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; bool _isLoading = false;
String? _errorMessage; String? _errorMessage;
UserModel? _loggedInUser; UserModel? _loggedInUser;
@@ -18,25 +34,44 @@ class AuthViewModel with ChangeNotifier {
String? get errorMessage => _errorMessage; String? get errorMessage => _errorMessage;
UserModel? get loggedInUser => _loggedInUser; UserModel? get loggedInUser => _loggedInUser;
Future<void> login(String email, String password) async { void togglePasswordVisibility() {
_obscurePassword = !_obscurePassword;
notifyListeners();
}
void _onTextChanged() {
notifyListeners();
}
Future<void> login() async {
_isLoading = true; _isLoading = true;
_errorMessage = null; _errorMessage = null;
notifyListeners(); notifyListeners();
final result = await _authRepository.login(email, password); final result = await _authRepository.login(
usernameController.text.trim(),
passwordController.text.trim(),
);
switch (result) { switch (result) {
case Ok<UserModel>(): case Ok<UserModel>():
_loggedInUser = result.value; _loggedInUser = result.value;
// موفقیت‌آمیز
break; break;
case Error<UserModel>(): case Error<UserModel>():
_errorMessage = result.error.toString(); _errorMessage = result.error.toString();
// خطا
break; break;
} }
_isLoading = false; _isLoading = false;
notifyListeners(); notifyListeners();
} }
@override
void dispose() {
usernameController.dispose();
passwordController.dispose();
usernameFocus.dispose();
passwordFocus.dispose();
super.dispose();
}
} }
-42
View File
@@ -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();
}
}
+32 -38
View File
@@ -1,36 +1,17 @@
// lib/views/login_desktop_screen.dart
import 'package:flutter/material.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/routes/app_routes.dart';
import 'package:tm_app/core/theme/colors.dart'; import 'package:tm_app/core/theme/colors.dart';
import '../../../core/constants/assets.dart'; import '../../../core/constants/assets.dart';
import '../../../core/constants/strings.dart'; import '../../../core/constants/strings.dart';
import '../../../core/utils/size_config.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'; import '../widgets/widgets.dart';
class LoginDesktopPage extends StatefulWidget { class LoginDesktopPage extends StatelessWidget {
const LoginDesktopPage({super.key}); const LoginDesktopPage({super.key});
@override
State<LoginDesktopPage> createState() => _LoginDesktopPageState();
}
class _LoginDesktopPageState extends State<LoginDesktopPage> {
late final LoginViewModel _viewModel;
@override
void initState() {
super.initState();
_viewModel = LoginViewModel();
}
@override
void dispose() {
_viewModel.dispose();
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
SizeConfig.init(context); SizeConfig.init(context);
@@ -41,9 +22,8 @@ class _LoginDesktopPageState extends State<LoginDesktopPage> {
padding: EdgeInsets.symmetric(horizontal: 24.0.w()), padding: EdgeInsets.symmetric(horizontal: 24.0.w()),
child: SizedBox( child: SizedBox(
width: 526, width: 526,
child: ListenableBuilder( child: Consumer<AuthViewModel>(
listenable: _viewModel, builder: (context, viewModel, _) {
builder: (context, _) {
return Column( return Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
@@ -53,8 +33,8 @@ class _LoginDesktopPageState extends State<LoginDesktopPage> {
SizedBox(height: 32.0.h()), SizedBox(height: 32.0.h()),
LoginTextField( LoginTextField(
controller: _viewModel.usernameController, controller: viewModel.usernameController,
focusNode: _viewModel.usernameFocus, focusNode: viewModel.usernameFocus,
label: AppStrings.usernameLabel, label: AppStrings.usernameLabel,
iconPath: AssetsManager.userIcon, iconPath: AssetsManager.userIcon,
fieldHeight: 60.0.h(), fieldHeight: 60.0.h(),
@@ -64,26 +44,40 @@ class _LoginDesktopPageState extends State<LoginDesktopPage> {
SizedBox(height: 16.0.h()), SizedBox(height: 16.0.h()),
LoginTextField( LoginTextField(
controller: _viewModel.passwordController, controller: viewModel.passwordController,
focusNode: _viewModel.passwordFocus, focusNode: viewModel.passwordFocus,
label: AppStrings.passwordLabel, label: AppStrings.passwordLabel,
iconPath: AssetsManager.passwordIcon, iconPath: AssetsManager.passwordIcon,
prefixIconPadding: 4.0.w(), prefixIconPadding: 4.0.w(),
isPassword: true, isPassword: true,
obscureText: _viewModel.obscurePassword, obscureText: viewModel.obscurePassword,
fieldHeight: 60.0.h(), fieldHeight: 60.0.h(),
onToggleVisibility: _viewModel.togglePasswordVisibility, onToggleVisibility: viewModel.togglePasswordVisibility,
borderRedus: 4.0.w(), borderRedus: 4.0.w(),
), ),
SizedBox(height: 32.0.h()), SizedBox(height: 32.0.h()),
BaseButton( if (viewModel.isLoading)
isEnabled: _viewModel.isLoginEnabled, const CircularProgressIndicator()
onPressed: else
_viewModel.isLoginEnabled BaseButton(
? () => HomeRouteData().go(context) isEnabled: viewModel.isLoginEnabled,
: null, 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,
),
], ],
); );
}, },
+32 -39
View File
@@ -1,36 +1,17 @@
// lib/views/login_screen.dart
import 'package:flutter/material.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/routes/app_routes.dart';
import 'package:tm_app/core/theme/colors.dart'; import 'package:tm_app/core/theme/colors.dart';
import '../../../core/constants/assets.dart'; import '../../../core/constants/assets.dart';
import '../../../core/constants/strings.dart'; import '../../../core/constants/strings.dart';
import '../../../core/utils/size_config.dart'; import '../../../core/utils/size_config.dart';
import '../../../view_models/auth_view_model.dart';
import '../widgets/widgets.dart'; import '../widgets/widgets.dart';
import '../../../view_models/login_view_model.dart';
class LoginMobilePage extends StatefulWidget { class LoginMobilePage extends StatelessWidget {
const LoginMobilePage({super.key}); const LoginMobilePage({super.key});
@override
State<LoginMobilePage> createState() => _LoginMobilePageState();
}
class _LoginMobilePageState extends State<LoginMobilePage> {
late final LoginViewModel _viewModel;
@override
void initState() {
super.initState();
_viewModel = LoginViewModel();
}
@override
void dispose() {
_viewModel.dispose();
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
SizeConfig.init(context); SizeConfig.init(context);
@@ -40,9 +21,8 @@ class _LoginMobilePageState extends State<LoginMobilePage> {
body: Center( body: Center(
child: SingleChildScrollView( child: SingleChildScrollView(
padding: EdgeInsets.symmetric(horizontal: 24.0.w()), padding: EdgeInsets.symmetric(horizontal: 24.0.w()),
child: ListenableBuilder( child: Consumer<AuthViewModel>(
listenable: _viewModel, builder: (context, viewModel, _) {
builder: (context, _) {
return Column( return Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
@@ -52,32 +32,45 @@ class _LoginMobilePageState extends State<LoginMobilePage> {
SizedBox(height: 32.0.h()), SizedBox(height: 32.0.h()),
LoginTextField( LoginTextField(
controller: _viewModel.usernameController, controller: viewModel.usernameController,
focusNode: _viewModel.usernameFocus, focusNode: viewModel.usernameFocus,
label: AppStrings.usernameLabel, label: AppStrings.usernameLabel,
iconPath: AssetsManager.userIcon, iconPath: AssetsManager.userIcon,
), ),
SizedBox(height: 16.0.h()), SizedBox(height: 16.0.h()),
LoginTextField( LoginTextField(
controller: _viewModel.passwordController, controller: viewModel.passwordController,
focusNode: _viewModel.passwordFocus, focusNode: viewModel.passwordFocus,
label: AppStrings.passwordLabel, label: AppStrings.passwordLabel,
iconPath: AssetsManager.passwordIcon, iconPath: AssetsManager.passwordIcon,
isPassword: true, isPassword: true,
obscureText: _viewModel.obscurePassword, obscureText: viewModel.obscurePassword,
onToggleVisibility: _viewModel.togglePasswordVisibility, onToggleVisibility: viewModel.togglePasswordVisibility,
), ),
SizedBox(height: 32.0.h()), SizedBox(height: 32.0.h()),
BaseButton( if (viewModel.isLoading)
isEnabled: _viewModel.isLoginEnabled, const CircularProgressIndicator()
onPressed: _viewModel.isLoginEnabled else
? () { BaseButton(
HomeRouteData().go(context); isEnabled: viewModel.isLoginEnabled,
} onPressed:
: null, 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,
),
], ],
); );
}, },
+32 -38
View File
@@ -1,36 +1,17 @@
// lib/views/login_tablet_screen.dart
import 'package:flutter/material.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/routes/app_routes.dart';
import 'package:tm_app/core/theme/colors.dart'; import 'package:tm_app/core/theme/colors.dart';
import '../../../core/constants/assets.dart'; import '../../../core/constants/assets.dart';
import '../../../core/constants/strings.dart'; import '../../../core/constants/strings.dart';
import '../../../core/utils/size_config.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'; import '../widgets/widgets.dart';
class LoginTabletPage extends StatefulWidget { class LoginTabletPage extends StatelessWidget {
const LoginTabletPage({super.key}); const LoginTabletPage({super.key});
@override
State<LoginTabletPage> createState() => _LoginTabletPageState();
}
class _LoginTabletPageState extends State<LoginTabletPage> {
late final LoginViewModel _viewModel;
@override
void initState() {
super.initState();
_viewModel = LoginViewModel();
}
@override
void dispose() {
_viewModel.dispose();
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
SizeConfig.init(context); SizeConfig.init(context);
@@ -41,9 +22,8 @@ class _LoginTabletPageState extends State<LoginTabletPage> {
padding: EdgeInsets.symmetric(horizontal: 24.0.w()), padding: EdgeInsets.symmetric(horizontal: 24.0.w()),
child: SizedBox( child: SizedBox(
width: 526, width: 526,
child: ListenableBuilder( child: Consumer<AuthViewModel>(
listenable: _viewModel, builder: (context, viewModel, _) {
builder: (context, _) {
return Column( return Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
@@ -53,8 +33,8 @@ class _LoginTabletPageState extends State<LoginTabletPage> {
SizedBox(height: 32.0.h()), SizedBox(height: 32.0.h()),
LoginTextField( LoginTextField(
controller: _viewModel.usernameController, controller: viewModel.usernameController,
focusNode: _viewModel.usernameFocus, focusNode: viewModel.usernameFocus,
label: AppStrings.usernameLabel, label: AppStrings.usernameLabel,
iconPath: AssetsManager.userIcon, iconPath: AssetsManager.userIcon,
fieldHeight: 60.0.h(), fieldHeight: 60.0.h(),
@@ -64,26 +44,40 @@ class _LoginTabletPageState extends State<LoginTabletPage> {
SizedBox(height: 16.0.h()), SizedBox(height: 16.0.h()),
LoginTextField( LoginTextField(
controller: _viewModel.passwordController, controller: viewModel.passwordController,
focusNode: _viewModel.passwordFocus, focusNode: viewModel.passwordFocus,
label: AppStrings.passwordLabel, label: AppStrings.passwordLabel,
iconPath: AssetsManager.passwordIcon, iconPath: AssetsManager.passwordIcon,
prefixIconPadding: 4.0.w(), prefixIconPadding: 4.0.w(),
isPassword: true, isPassword: true,
obscureText: _viewModel.obscurePassword, obscureText: viewModel.obscurePassword,
fieldHeight: 60.0.h(), fieldHeight: 60.0.h(),
onToggleVisibility: _viewModel.togglePasswordVisibility, onToggleVisibility: viewModel.togglePasswordVisibility,
borderRedus: 4.0.w(), borderRedus: 4.0.w(),
), ),
SizedBox(height: 32.0.h()), SizedBox(height: 32.0.h()),
BaseButton( if (viewModel.isLoading)
isEnabled: _viewModel.isLoginEnabled, const CircularProgressIndicator()
onPressed: else
_viewModel.isLoginEnabled BaseButton(
? () => HomeRouteData().go(context) isEnabled: viewModel.isLoginEnabled,
: null, 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,
),
], ],
); );
}, },