Skip to content

Commit

Permalink
Merge pull request #81 from chornerman/feature/#8-integrate-reset-pas…
Browse files Browse the repository at this point in the history
…sword-screen

[#8] Integrate Reset Password screen
  • Loading branch information
chornerman committed Dec 27, 2022
2 parents 7e21c5d + 208d1a4 commit a1a30e2
Show file tree
Hide file tree
Showing 21 changed files with 312 additions and 33 deletions.
1 change: 1 addition & 0 deletions assets/color/colors.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="chinese_black">#15151A</color>
<color name="raisin_black">#252525</color>
</resources>
File renamed without changes
File renamed without changes
5 changes: 5 additions & 0 deletions assets/images/ic_notification.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,8 @@
"loginInvalidEmailPassword": "Invalid email or password",
"resetPasswordDescription": "Enter your email to receive instructions for resetting your password.",
"resetPasswordReset": "Reset",
"resetPasswordSuccessTitle": "Check your email.",
"resetPasswordSuccessDescription": "We’ve email you instructions to reset your password.",
"resetPasswordInvalidEmail": "Invalid email",
"homeToday": "Today"
}
3 changes: 3 additions & 0 deletions lib/l10n/app_th.arb
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,8 @@
"loginInvalidEmailPassword": "อีเมลล์หรือรหัสผ่านไม่ถูกต้อง",
"resetPasswordDescription": "กรุณากรอกอีเมลล์เพื่อรับคำแนะนำในการรีเซ็ตรหัสผ่าน",
"resetPasswordReset": "รีเซ็ต",
"resetPasswordSuccessTitle": "ตรวจสอบอีเมลล์ของคุณ",
"resetPasswordSuccessDescription": "เราได้ส่งขั้นตอนการรีเซ็ตรหัสผ่านให้คุณทางอีเมลล์แล้ว",
"resetPasswordInvalidEmail": "อีเมลล์ไม่ถูกต้อง",
"homeToday": "วันนี้"
}
21 changes: 13 additions & 8 deletions lib/page/home/home_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import 'package:survey/page/home/widget/home_surveys_page_view_widget.dart';
import 'package:survey/usecase/get_cached_surveys_use_case.dart';
import 'package:survey/usecase/get_surveys_use_case.dart';
import 'package:survey/usecase/get_user_use_case.dart';
import 'package:survey/widget/loading_indicator_widget.dart';

final homeViewModelProvider =
StateNotifierProvider.autoDispose<HomeViewModel, HomeState>((ref) {
Expand Down Expand Up @@ -116,16 +117,20 @@ class _HomePageState extends ConsumerState<HomePage> {
child: ListView(),
),
SafeArea(
child: HomeHeaderWidget(
currentDate:
ref.read(homeViewModelProvider.notifier).getCurrentDate(),
userAvatarUrl: ref.watch(_userStreamProvider).value?.avatarUrl,
child: Column(
children: [
HomeHeaderWidget(
currentDate: ref
.read(homeViewModelProvider.notifier)
.getCurrentDate(),
userAvatarUrl:
ref.watch(_userStreamProvider).value?.avatarUrl,
),
if (shouldShowLoading)
LoadingIndicatorWidget(shouldIgnoreOtherGestures: false)
],
),
),
if (shouldShowLoading)
const Center(
child: CircularProgressIndicator(color: Colors.white),
)
],
),
),
Expand Down
2 changes: 1 addition & 1 deletion lib/page/home/widget/home_surveys_item_widget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class HomeSurveysItemWidget extends StatelessWidget {
Padding(
padding: const EdgeInsets.only(left: Dimens.space20),
child: ElevatedButton(
child: Assets.images.icArrowRight.svg(),
child: Assets.images.icArrowNext.svg(),
style: ElevatedButton.styleFrom(
elevation: 0,
shape: const CircleBorder(),
Expand Down
4 changes: 2 additions & 2 deletions lib/page/login/login_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import 'package:survey/page/login/login_view_model.dart';
import 'package:survey/page/login/widget/login_text_input_forgot_password_widget.dart';
import 'package:survey/resource/dimens.dart';
import 'package:survey/usecase/login_use_case.dart';
import 'package:survey/widget/circular_progress_bar_widget.dart';
import 'package:survey/widget/loading_indicator_widget.dart';
import 'package:survey/widget/onboarding_background_widget.dart';
import 'package:survey/widget/rounded_button_widget.dart';
import 'package:survey/widget/text_input_widget.dart';
Expand Down Expand Up @@ -96,7 +96,7 @@ class _LoginPageState extends ConsumerState<LoginPage> {
),
),
ref.watch(loginViewModelProvider).maybeWhen(
loading: () => const CircularProgressBarWidget(),
loading: () => const LoadingIndicatorWidget(),
orElse: () => const SizedBox(),
)
],
Expand Down
2 changes: 1 addition & 1 deletion lib/page/login/login_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ class LoginState with _$LoginState {

const factory LoginState.apiError(String errorMessage) = _Error;

const factory LoginState.invalidInputsError() = _InvalidInputError;
const factory LoginState.invalidInputsError() = _InvalidInputsError;
}
90 changes: 87 additions & 3 deletions lib/page/resetpassword/reset_password_page.dart
Original file line number Diff line number Diff line change
@@ -1,17 +1,51 @@
import 'package:another_flushbar/flushbar.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:survey/constants.dart';
import 'package:survey/di/di.dart';
import 'package:survey/gen/assets.gen.dart';
import 'package:survey/gen/colors.gen.dart';
import 'package:survey/page/resetpassword/reset_password_state.dart';
import 'package:survey/page/resetpassword/reset_password_view_model.dart';
import 'package:survey/resource/dimens.dart';
import 'package:survey/usecase/reset_password_use_case.dart';
import 'package:survey/widget/app_bar_back_button_widget.dart';
import 'package:survey/widget/loading_indicator_widget.dart';
import 'package:survey/widget/onboarding_background_widget.dart';
import 'package:survey/widget/rounded_button_widget.dart';
import 'package:survey/widget/text_input_widget.dart';

class ResetPasswordPage extends StatelessWidget {
const ResetPasswordPage({Key? key}) : super(key: key);
final resetPasswordViewModelProvider = StateNotifierProvider.autoDispose<
ResetPasswordViewModel, ResetPasswordState>((ref) {
return ResetPasswordViewModel(getIt.get<ResetPasswordUseCase>());
});

class ResetPasswordPage extends ConsumerStatefulWidget {
const ResetPasswordPage({super.key});

@override
_ResetPasswordPageState createState() => _ResetPasswordPageState();
}

class _ResetPasswordPageState extends ConsumerState<ResetPasswordPage> {
final _emailController = TextEditingController();

@override
Widget build(BuildContext context) {
ref.listen<ResetPasswordState>(resetPasswordViewModelProvider, (
ResetPasswordState? previousState,
ResetPasswordState newState,
) {
newState.maybeWhen(
success: () => _showResetPasswordSuccessFlushbar(),
apiError: (errorMessage) => _showError(errorMessage),
invalidInputError: () =>
_showError(AppLocalizations.of(context)!.resetPasswordInvalidEmail),
orElse: () {},
);
});

return Scaffold(
resizeToAvoidBottomInset: false,
body: Stack(
Expand Down Expand Up @@ -39,13 +73,17 @@ class ResetPasswordPage extends StatelessWidget {
const SizedBox(height: Dimens.space96),
TextInputWidget(
hintText: AppLocalizations.of(context)!.email,
controller: _emailController,
),
const SizedBox(height: Dimens.space20),
RoundedButtonWidget(
buttonText:
AppLocalizations.of(context)!.resetPasswordReset,
onPressed: () {
// TODO: Call reset password use case
_hideKeyboard();
ref
.read(resetPasswordViewModelProvider.notifier)
.resetPassword(_emailController.text);
},
),
],
Expand All @@ -56,8 +94,54 @@ class ResetPasswordPage extends StatelessWidget {
padding: EdgeInsets.only(top: Dimens.space24, left: Dimens.space22),
child: AppBarBackButtonWidget(),
),
ref.watch(resetPasswordViewModelProvider).maybeWhen(
loading: () => const LoadingIndicatorWidget(),
orElse: () => const SizedBox(),
)
],
),
);
}

void _showResetPasswordSuccessFlushbar() {
Flushbar(
flushbarPosition: FlushbarPosition.TOP,
flushbarStyle: FlushbarStyle.GROUNDED,
duration: Duration(seconds: Constants.snackBarDurationInSecond),
backgroundColor: ColorName.raisinBlack,
titleText: Text(
AppLocalizations.of(context)!.resetPasswordSuccessTitle,
style: Theme.of(context).textTheme.bodyText2?.copyWith(
fontWeight: FontWeight.w800,
),
),
messageText: Text(
AppLocalizations.of(context)!.resetPasswordSuccessDescription,
style: Theme.of(context).textTheme.subtitle1?.copyWith(
fontWeight: FontWeight.w400,
),
),
icon: Assets.images.icNotification.svg(),
).show(context);
}

void _showError(String errorMessage) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
duration: const Duration(seconds: Constants.snackBarDurationInSecond),
content: Text(errorMessage),
));
}

void _hideKeyboard() {
FocusScopeNode currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus && currentFocus.focusedChild != null) {
FocusManager.instance.primaryFocus?.unfocus();
}
}

@override
void dispose() {
_emailController.dispose();
super.dispose();
}
}
16 changes: 16 additions & 0 deletions lib/page/resetpassword/reset_password_state.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import 'package:freezed_annotation/freezed_annotation.dart';

part 'reset_password_state.freezed.dart';

@freezed
class ResetPasswordState with _$ResetPasswordState {
const factory ResetPasswordState.init() = _Init;

const factory ResetPasswordState.loading() = _Loading;

const factory ResetPasswordState.success() = _Success;

const factory ResetPasswordState.apiError(String errorMessage) = _Error;

const factory ResetPasswordState.invalidInputError() = _InvalidInputError;
}
27 changes: 27 additions & 0 deletions lib/page/resetpassword/reset_password_view_model.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import 'package:email_validator/email_validator.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:survey/page/resetpassword/reset_password_state.dart';
import 'package:survey/usecase/base/base_use_case.dart';
import 'package:survey/usecase/reset_password_use_case.dart';

class ResetPasswordViewModel extends StateNotifier<ResetPasswordState> {
final ResetPasswordUseCase _resetPasswordUseCase;

ResetPasswordViewModel(this._resetPasswordUseCase)
: super(const ResetPasswordState.init());

void resetPassword(String email) async {
state = const ResetPasswordState.loading();
if (EmailValidator.validate(email)) {
Result<void> result = await _resetPasswordUseCase.call(email);
if (result is Success) {
state = const ResetPasswordState.success();
} else {
state =
ResetPasswordState.apiError((result as Failed).getErrorMessage());
}
} else {
state = const ResetPasswordState.invalidInputError();
}
}
}
2 changes: 2 additions & 0 deletions lib/resource/dimens.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ class Dimens {
static const double roundedButtonBorderRadius = 10;
static const double roundedButtonHeight = 56;

static const double circularProgressBarBackgroundSize = 56;

static const double homeSurveysIndicatorsSize = 8;
static const double homeSurveysNextButtonSize = 56;
static const double homeUserAvatarSize = 36;
Expand Down
2 changes: 1 addition & 1 deletion lib/widget/app_bar_back_button_widget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class AppBarBackButtonWidget extends StatelessWidget {
Widget build(BuildContext context) {
return SafeArea(
child: IconButton(
icon: Assets.images.icBackArrow.svg(),
icon: Assets.images.icArrowBack.svg(),
padding: EdgeInsets.zero,
constraints: BoxConstraints(),
onPressed: () => _appNavigator.navigateBack(context),
Expand Down
17 changes: 0 additions & 17 deletions lib/widget/circular_progress_bar_widget.dart

This file was deleted.

39 changes: 39 additions & 0 deletions lib/widget/loading_indicator_widget.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import 'package:flutter/material.dart';
import 'package:loading_indicator/loading_indicator.dart';
import 'package:survey/resource/dimens.dart';

class LoadingIndicatorWidget extends StatelessWidget {
final bool shouldIgnoreOtherGestures;

const LoadingIndicatorWidget({
Key? key,
this.shouldIgnoreOtherGestures = true,
}) : super(key: key);

@override
Widget build(BuildContext context) {
return shouldIgnoreOtherGestures
? Container(
width: double.infinity,
height: double.infinity,
color: Colors.transparent,
child: _buildLoadingIndicator(),
)
: _buildLoadingIndicator();
}

Widget _buildLoadingIndicator() {
return Center(
child: Container(
padding: EdgeInsets.all(Dimens.space12),
width: Dimens.circularProgressBarBackgroundSize,
height: Dimens.circularProgressBarBackgroundSize,
color: Colors.black54,
child: LoadingIndicator(
indicatorType: Indicator.lineSpinFadeLoader,
colors: const [Colors.white],
),
),
);
}
}
14 changes: 14 additions & 0 deletions pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "5.2.0"
another_flushbar:
dependency: "direct main"
description:
name: another_flushbar
url: "https://pub.dartlang.org"
source: hosted
version: "1.12.29"
args:
dependency: transitive
description:
Expand Down Expand Up @@ -413,6 +420,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.1"
loading_indicator:
dependency: "direct main"
description:
name: loading_indicator
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.0"
logging:
dependency: transitive
description:
Expand Down
2 changes: 2 additions & 0 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ environment:
sdk: ">=2.17.0 <3.0.0"

dependencies:
another_flushbar: ^1.12.29
dio: ^4.0.6
email_validator: ^2.1.17
equatable: ^2.0.5
Expand All @@ -39,6 +40,7 @@ dependencies:
intl: ^0.17.0
japx: ^2.0.4
json_annotation: ^4.6.0
loading_indicator: ^3.1.0
page_view_dot_indicator: ^2.0.1
retrofit: ^3.0.1+1
rxdart: ^0.27.7
Expand Down
Loading

0 comments on commit a1a30e2

Please sign in to comment.