Skip to content

Commit

Permalink
adjust login button and layout and login function (#29)
Browse files Browse the repository at this point in the history
  • Loading branch information
Ida631 authored Nov 5, 2024
1 parent af03f1b commit 4f1d09b
Show file tree
Hide file tree
Showing 9 changed files with 436 additions and 189 deletions.
4 changes: 4 additions & 0 deletions domain/lib/usecases/auth_usecase.dart
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,8 @@ class AuthUseCase {
Future<String> resetPassword(String token, String newPassword) async {
return await repository.resetPassword(token, newPassword);
}

confirmPasswordReset(String email, String newPassword, String confirmationCode) {}


}
15 changes: 7 additions & 8 deletions lib/generated/intl/messages_all.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@

import 'dart:async';

import 'package:flutter/foundation.dart';
import 'package:intl/intl.dart';
import 'package:intl/message_lookup_by_library.dart';
import 'package:intl/src/intl_helpers.dart';
Expand All @@ -22,9 +21,9 @@ import 'messages_zh_HK.dart' as messages_zh_hk;

typedef Future<dynamic> LibraryLoader();
Map<String, LibraryLoader> _deferredLibraries = {
'en': () => new SynchronousFuture(null),
'zh': () => new SynchronousFuture(null),
'zh_HK': () => new SynchronousFuture(null),
'en': () => new Future.value(null),
'zh': () => new Future.value(null),
'zh_HK': () => new Future.value(null),
};

MessageLookupByLibrary? _findExact(String localeName) {
Expand All @@ -41,18 +40,18 @@ MessageLookupByLibrary? _findExact(String localeName) {
}

/// User programs should call this before using [localeName] for messages.
Future<bool> initializeMessages(String localeName) {
Future<bool> initializeMessages(String localeName) async {
var availableLocale = Intl.verifiedLocale(
localeName, (locale) => _deferredLibraries[locale] != null,
onFailure: (_) => null);
if (availableLocale == null) {
return new SynchronousFuture(false);
return new Future.value(false);
}
var lib = _deferredLibraries[availableLocale];
lib == null ? new SynchronousFuture(false) : lib();
await (lib == null ? new Future.value(false) : lib());
initializeInternalMessageLookup(() => new CompositeMessageLookup());
messageLookup.addLocale(availableLocale, _findGeneratedMessagesFor);
return new SynchronousFuture(true);
return new Future.value(true);
}

bool _messagesExistFor(String locale) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,42 @@ import 'package:flutter/material.dart';
class ForgetPasswordViewModel extends ChangeNotifier {
bool isLoading = false;
String errorMessage = '';
AuthUseCase authUseCase;
bool isPasswordResetting = false;

final AuthUseCase authUseCase;

ForgetPasswordViewModel({required this.authUseCase});

Future<void> forgetPassword(String email) async {
isLoading = true;
_setLoadingState(true);
errorMessage = '';
notifyListeners();

try {
await authUseCase.forgetPassword(email);
isLoading = false;
isPasswordResetting = true; // Move to the confirm reset stage
} catch (error) {
errorMessage = error.toString();
} finally {
_setLoadingState(false);
}
}

Future<void> confirmPasswordReset(String email, String newPassword, String confirmationCode) async {
_setLoadingState(true);
errorMessage = '';

try {
await authUseCase.confirmPasswordReset(email, newPassword, confirmationCode);
isPasswordResetting = false; // Reset process completed
} catch (error) {
errorMessage = error.toString();
isLoading = false;
} finally {
_setLoadingState(false);
}
}

void _setLoadingState(bool value) {
isLoading = value;
notifyListeners();
}
}
8 changes: 8 additions & 0 deletions lib/presentation/settings/viewModels/login_view_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@ class LoginViewModel extends ChangeNotifier {
String? _errorMessage;
String? get errorMessage => _errorMessage;

bool _isButtonEnabled = false;
bool get isButtonEnabled => _isButtonEnabled;

void updateButtonState(String username, String password) {
_isButtonEnabled = username.isNotEmpty && password.isNotEmpty;
notifyListeners();
}

Future<String?> login(String username, String password) async {
_isLoading = true;
_errorMessage = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,8 @@ class ResetPasswordViewModel extends ChangeNotifier {
ResetPasswordViewModel({required this.authUseCase});

Future<void> verifyToken(String token) async {
isLoading = true;
_setLoadingState(true);
errorMessage = '';
notifyListeners();

try {
await authUseCase.resetPasswordVerify(token);
Expand All @@ -21,15 +20,13 @@ class ResetPasswordViewModel extends ChangeNotifier {
isTokenValid = false;
errorMessage = 'Invalid or expired token';
} finally {
isLoading = false;
notifyListeners();
_setLoadingState(false);
}
}

Future<String?> resetPassword(String token, String newPassword) async {
isLoading = true;
_setLoadingState(true);
errorMessage = '';
notifyListeners();

try {
await authUseCase.resetPassword(token, newPassword);
Expand All @@ -38,8 +35,12 @@ class ResetPasswordViewModel extends ChangeNotifier {
errorMessage = 'Failed to reset password. Please try again.';
return null;
} finally {
isLoading = false;
notifyListeners();
_setLoadingState(false);
}
}

void _setLoadingState(bool value) {
isLoading = value;
notifyListeners();
}
}
184 changes: 136 additions & 48 deletions lib/presentation/settings/views/forget_password_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ class ForgetPasswordPage extends StatefulWidget {

class _ForgetPasswordPageState extends State<ForgetPasswordPage> {
final _emailController = TextEditingController();
final _newPasswordController = TextEditingController();
final _confirmationCodeController = TextEditingController();
final _formKey = GlobalKey<FormState>();

@override
Expand All @@ -19,8 +21,7 @@ class _ForgetPasswordPageState extends State<ForgetPasswordPage> {
child: Scaffold(
appBar: AppBar(
title: Text("Forget Password"),
backgroundColor:
Colors.grey[800], // Customize the AppBar color as needed
backgroundColor: Color(0xFF33424E), // Customize the AppBar color as needed
),
body: Consumer<ForgetPasswordViewModel>(
builder: (context, viewModel, child) {
Expand All @@ -29,55 +30,140 @@ class _ForgetPasswordPageState extends State<ForgetPasswordPage> {
child: Form(
key: _formKey,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// Email Input Field
TextFormField(
controller: _emailController,
decoration: InputDecoration(
labelText: "Email",
hintText: "Input Email",
border: UnderlineInputBorder(),
SizedBox(height: 10),

// If password reset flow has started, show confirmation form
if (viewModel.isPasswordResetting) ...[
// New Password Input
TextFormField(
controller: _newPasswordController,
decoration: InputDecoration(
labelText: "New Password",
hintText: "Input New Password",
border: UnderlineInputBorder(),
),
obscureText: true,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter your new password';
}
return null;
},
),
SizedBox(height: 20),

// Confirmation Code Input
TextFormField(
controller: _confirmationCodeController,
decoration: InputDecoration(
labelText: "Confirmation Code",
hintText: "Input Code",
border: UnderlineInputBorder(),
),
keyboardType: TextInputType.number,
validator: (value) {
if (value == null || value.length != 6) {
return 'The confirmation code is invalid';
}
return null;
},
),
SizedBox(height: 20),

// Confirm Button
MaterialButton(
onPressed: viewModel.isLoading
? null
: () async {
if (_formKey.currentState!.validate()) {
await viewModel.confirmPasswordReset(
_emailController.text,
_newPasswordController.text,
_confirmationCodeController.text,
);
if (viewModel.errorMessage.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Password reset successful.'),
),
);
Navigator.pop(context);
}
}
},
height: 45,
minWidth: double.infinity,
color: Color.fromRGBO(150, 150, 150, 1),
disabledColor: Color.fromRGBO(150, 150, 150, 0.5),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(6),
),
child: viewModel.isLoading
? CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
)
: Text(
"Confirm",
style: TextStyle(color: Colors.white, fontSize: 16),
),
),
] else ...[
// Email Input Field
TextFormField(
controller: _emailController,
decoration: InputDecoration(
labelText: "Email",
hintText: "Input Email",
border: UnderlineInputBorder(),
),
keyboardType: TextInputType.emailAddress,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter your email';
}
if (!RegExp(r'^[^@]+@[^@]+\.[^@]+').hasMatch(value)) {
return 'Please enter a valid email';
}
return null;
},
),
keyboardType: TextInputType.emailAddress,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter your email';
}
if (!RegExp(r'^[^@]+@[^@]+\.[^@]+').hasMatch(value)) {
return 'Please enter a valid email';
}
return null;
},
),
SizedBox(height: 20),
SizedBox(height: 20),

// Reset Password Button
ElevatedButton(
onPressed: viewModel.isLoading
? null
: () async {
if (_formKey.currentState!.validate()) {
await viewModel
.forgetPassword(_emailController.text);
if (viewModel.errorMessage.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content:
Text('Password reset email sent.')),
);
Navigator.pop(
context); // Go back after successful reset
}
}
},
child: viewModel.isLoading
? CircularProgressIndicator(
valueColor:
AlwaysStoppedAnimation<Color>(Colors.white),
)
: Text("Reset Password"),
),
// Reset Password Button
MaterialButton(
onPressed: viewModel.isLoading
? null
: () async {
if (_formKey.currentState!.validate()) {
await viewModel.forgetPassword(_emailController.text);
if (viewModel.errorMessage.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Password reset email sent.'),
),
);
}
}
},
height: 45,
minWidth: double.infinity,
color: Color.fromRGBO(150, 150, 150, 1),
disabledColor: Color.fromRGBO(150, 150, 150, 0.5),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(6),
),
child: viewModel.isLoading
? CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
)
: Text(
"Reset Password",
style: TextStyle(color: Colors.white, fontSize: 16),
),
),
],

// Error Message
if (viewModel.errorMessage.isNotEmpty)
Expand All @@ -101,6 +187,8 @@ class _ForgetPasswordPageState extends State<ForgetPasswordPage> {
@override
void dispose() {
_emailController.dispose();
_newPasswordController.dispose();
_confirmationCodeController.dispose();
super.dispose();
}
}
Loading

0 comments on commit 4f1d09b

Please sign in to comment.