Skip to content

Commit

Permalink
form: move files, restructure
Browse files Browse the repository at this point in the history
  • Loading branch information
marfavi committed Feb 6, 2024
1 parent 0dc69df commit 32286a2
Show file tree
Hide file tree
Showing 22 changed files with 47 additions and 53 deletions.
3 changes: 0 additions & 3 deletions lib/core/validator/email_is_valid.dart

This file was deleted.

9 changes: 7 additions & 2 deletions lib/features/login/presentation/pages/login_page_email.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import 'package:coffeecard/core/strings.dart';
import 'package:coffeecard/core/validator/email_is_valid.dart';
import 'package:coffeecard/core/widgets/fast_slide_transition.dart';
import 'package:coffeecard/features/login/presentation/pages/login_page_base.dart';
import 'package:coffeecard/features/login/presentation/pages/login_page_passcode.dart';
Expand All @@ -8,6 +7,12 @@ import 'package:coffeecard/features/login/presentation/widgets/login_email_text_
import 'package:coffeecard/features/register/presentation/pages/register_flow.dart';
import 'package:flutter/material.dart';

// FIXME: Duplicate code.
// Rewrite the LoginPageEmail widget to use the Form widget,
// such that we can use input validators.
final _isValidEmail =
RegExp(r'^[^@ \t\r\n]+@[^@ \t\r\n]+\.[^@ \t\r\n]{2,}').hasMatch;

class LoginPageEmail extends StatefulWidget {
const LoginPageEmail({this.transitionDuration = Duration.zero});

Expand Down Expand Up @@ -50,7 +55,7 @@ class _LoginPageEmailState extends State<LoginPageEmail>
void _validateEmail(BuildContext context, String email) {
if (email.isEmpty) {
error = Strings.loginEnterEmailError;
} else if (!emailIsValid(email)) {
} else if (!_isValidEmail(email)) {
error = Strings.loginInvalidEmailError;
} else {
final _ =
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import 'package:coffeecard/core/ignore_value.dart';
import 'package:coffeecard/core/strings.dart';
import 'package:coffeecard/core/validator/input_validator.dart';
import 'package:coffeecard/core/widgets/components/dialog.dart';
import 'package:coffeecard/core/widgets/components/loading_overlay.dart';
import 'package:coffeecard/features/form/presentation/widgets/form.dart';
import 'package:coffeecard/features/login/data/datasources/account_remote_data_source.dart';
import 'package:coffeecard/features/shared/form.dart';
import 'package:coffeecard/service_locator.dart';
import 'package:flutter/material.dart';
import 'package:fpdart/fpdart.dart';
Expand Down Expand Up @@ -34,7 +33,7 @@ class ForgotPasscodeForm extends StatelessWidget {
return emailExistsResult.fold(
(error) => const Left(Strings.emailValidationError),
(emailExists) => emailExists
? const Right(null)
? const Right(unit)
: const Left(Strings.forgotPasscodeNoAccountExists),
);
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import 'package:coffeecard/core/strings.dart';
import 'package:coffeecard/core/validator/input_validator.dart';
import 'package:coffeecard/features/form/presentation/widgets/form.dart';
import 'package:coffeecard/features/login/data/datasources/account_remote_data_source.dart';
import 'package:coffeecard/features/shared/form.dart';
import 'package:coffeecard/service_locator.dart';
import 'package:flutter/material.dart';
import 'package:fpdart/fpdart.dart';
Expand Down Expand Up @@ -30,7 +29,7 @@ class RegisterEmailForm extends StatelessWidget {
(l) => const Left(Strings.emailValidationError),
(r) => r
? Left(Strings.registerEmailInUse(text))
: const Right(null),
: const Right(unit),
);
},
),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import 'package:coffeecard/core/ignore_value.dart';
import 'package:coffeecard/core/strings.dart';
import 'package:coffeecard/core/validator/input_validator.dart';
import 'package:coffeecard/core/widgets/components/dialog.dart';
import 'package:coffeecard/core/widgets/components/helpers/unordered_list_builder.dart';
import 'package:coffeecard/core/widgets/components/loading_overlay.dart';
import 'package:coffeecard/features/form/presentation/widgets/form.dart';
import 'package:coffeecard/features/register/presentation/cubit/register_cubit.dart';
import 'package:coffeecard/features/shared/form.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:gap/gap.dart';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import 'package:coffeecard/core/strings.dart';
import 'package:coffeecard/core/validator/input_validator.dart';
import 'package:coffeecard/features/form/presentation/widgets/form.dart';
import 'package:coffeecard/features/shared/form.dart';
import 'package:flutter/material.dart';

class RegisterPasscodeForm extends StatelessWidget {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import 'package:coffeecard/core/strings.dart';
import 'package:coffeecard/core/validator/input_validator.dart';
import 'package:coffeecard/features/form/presentation/widgets/form.dart';
import 'package:coffeecard/features/shared/form.dart';
import 'package:flutter/material.dart';

class RegisterPasscodeRepeatForm extends StatelessWidget {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import 'package:coffeecard/core/strings.dart';
import 'package:coffeecard/core/validator/input_validator.dart';
import 'package:coffeecard/features/form/presentation/widgets/form.dart';
import 'package:coffeecard/features/login/data/datasources/account_remote_data_source.dart';
import 'package:coffeecard/features/shared/form.dart';
import 'package:coffeecard/service_locator.dart';
import 'package:flutter/material.dart';
import 'package:fpdart/fpdart.dart';
Expand Down Expand Up @@ -37,7 +36,7 @@ class ChangeEmailForm extends StatelessWidget {
(l) => const Left(Strings.emailValidationError),
(r) => r
? Left(Strings.registerEmailInUse(text))
: const Right(null),
: const Right(unit),
);
},
),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import 'package:coffeecard/core/strings.dart';
import 'package:coffeecard/core/validator/input_validator.dart';
import 'package:coffeecard/features/form/presentation/widgets/form.dart';
import 'package:coffeecard/features/shared/form.dart';
import 'package:coffeecard/features/user/presentation/cubit/user_cubit.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import 'package:coffeecard/core/strings.dart';
import 'package:coffeecard/core/validator/input_validator.dart';
import 'package:coffeecard/core/widgets/fast_slide_transition.dart';
import 'package:coffeecard/features/form/presentation/widgets/form.dart';
import 'package:coffeecard/features/settings/presentation/widgets/forms/change_passcode_repeat_form.dart';
import 'package:coffeecard/features/shared/form.dart';
import 'package:flutter/material.dart';

class ChangePasscodeForm extends StatelessWidget {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import 'package:coffeecard/core/strings.dart';
import 'package:coffeecard/core/validator/input_validator.dart';
import 'package:coffeecard/core/widgets/fast_slide_transition.dart';
import 'package:coffeecard/features/form/presentation/widgets/form.dart';
import 'package:coffeecard/features/shared/form.dart';
import 'package:coffeecard/features/user/presentation/cubit/user_cubit.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
Expand Down
1 change: 1 addition & 0 deletions lib/features/shared/form.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export 'package:coffeecard/src/shared/form/form.dart';
3 changes: 1 addition & 2 deletions lib/features/voucher/presentation/widgets/voucher_form.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import 'package:coffeecard/core/strings.dart';
import 'package:coffeecard/core/validator/input_validator.dart';
import 'package:coffeecard/features/form/presentation/widgets/form.dart';
import 'package:coffeecard/features/shared/form.dart';
import 'package:coffeecard/features/voucher/presentation/cubit/voucher_cubit.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import 'package:bloc/bloc.dart';
import 'package:coffeecard/core/debouncing.dart';
import 'package:coffeecard/core/validator/input_validator.dart';
import 'package:coffeecard/features/shared/form.dart';
import 'package:equatable/equatable.dart';
import 'package:fpdart/fpdart.dart';

Expand All @@ -25,7 +24,7 @@ class FormBloc extends Bloc<FormEvent, FormState> {
state.copyWith(
loading: false,
canSubmit: false,
error: either,
validationStatus: either,
shouldDisplayError: validator.forceErrorMessage ? true : null,
),
);
Expand All @@ -37,7 +36,7 @@ class FormBloc extends Bloc<FormEvent, FormState> {
loading: false,
text: text,
canSubmit: true,
error: const Right(null),
validationStatus: const Right(unit),
),
);
},
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -6,37 +6,37 @@ class FormState extends Equatable {
this.text = '',
this.canSubmit = false,
this.shouldDisplayError = false,
this.error = const Right(null),
this.validationStatus = const Right(unit),
});

final bool loading;
final String text;
final bool canSubmit;
final bool shouldDisplayError;
final ErrorEither error;
final Either<String, Unit> validationStatus;

@override
List<Object?> get props => [
loading,
text,
canSubmit,
shouldDisplayError,
error,
validationStatus,
];

FormState copyWith({
bool? loading,
String? text,
bool? canSubmit,
bool? shouldDisplayError,
ErrorEither? error,
Either<String, Unit>? validationStatus,
}) {
return FormState(
loading: loading ?? this.loading,
text: text ?? this.text,
canSubmit: canSubmit ?? this.canSubmit,
shouldDisplayError: shouldDisplayError ?? this.shouldDisplayError,
error: error ?? this.error,
validationStatus: validationStatus ?? this.validationStatus,
);
}
}
4 changes: 4 additions & 0 deletions lib/src/shared/form/form.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export 'bloc/debouncing.dart';
export 'bloc/form_bloc.dart';
export 'input_validator/input_validator.dart';
export 'widgets/form.dart';
Original file line number Diff line number Diff line change
@@ -1,21 +1,17 @@
import 'dart:async';

import 'package:coffeecard/core/validator/email_is_valid.dart';
import 'package:fpdart/fpdart.dart';

part 'input_validator_helpers.dart';

/// Either an input error message (String) or a valid input (void).
typedef ErrorEither = Either<String, void>;

/// A content validator for `AppForm`s.
/// A content validator for [FormBase] widgets.
///
/// Example:
/// ```dart
/// class ExampleForm extends StatelessWidget {
/// @override
/// Widget build(BuildContext context) {
/// return AppForm(
/// return FormBase(
/// inputValidators: [
/// InputValidator.bool(
/// validate: (input) => input.length == 4,
Expand Down Expand Up @@ -54,14 +50,14 @@ class InputValidator {
}) : this(
validate: (String input) async {
final validInput = await validate(input);
return validInput ? const Right(null) : Left(errorMessage);
return validInput ? const Right(unit) : Left(errorMessage);
},
forceErrorMessage: forceErrorMessage,
);

/// The input validator. Either returns an
/// error message (left) or success (right).
final FutureOr<ErrorEither> Function(String input) validate;
final FutureOr<Either<String, Unit>> Function(String input) validate;

/// If failing this input validator should show an error message,
/// even if the user has not pressed submit yet.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class InputValidators {

static InputValidator validEmail({required String errorMessage}) {
return InputValidator.bool(
validate: emailIsValid,
validate: RegExp(r'^[^@ \t\r\n]+@[^@ \t\r\n]+\.[^@ \t\r\n]{2,}').hasMatch,
errorMessage: errorMessage,
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import 'package:coffeecard/core/strings.dart';
import 'package:coffeecard/core/styles/app_colors.dart';
import 'package:coffeecard/core/validator/input_validator.dart';
import 'package:coffeecard/core/widgets/components/rounded_button.dart';
import 'package:coffeecard/core/widgets/components/section_title.dart';
import 'package:coffeecard/features/form/presentation/bloc/form_bloc.dart';
import 'package:coffeecard/features/shared/form.dart';
import 'package:flutter/material.dart' hide FormState;
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
Expand Down Expand Up @@ -79,7 +78,6 @@ class FormBase extends StatelessWidget {
listenWhen: (_, current) => autoSubmitValidInput && current.canSubmit,
listener: (_, state) => onSubmit(state.text),
builder: (context, state) {
final bloc = context.read<FormBloc>();
return Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.stretch,
Expand All @@ -93,12 +91,16 @@ class FormBase extends StatelessWidget {
inputValidators: inputValidators,
onChanged: (input) {
if (!state.loading) {
bloc.add(FormValidateRequested());
context.read<FormBloc>().add(FormValidateRequested());
}
bloc.add(FormValidateStarted(input: input));
context
.read<FormBloc>()
.add(FormValidateStarted(input: input));
},
onEditingComplete: () {
bloc.add(FormToggleErrorDisplay(displayError: true));
context
.read<FormBloc>()
.add(FormToggleErrorDisplay(displayError: true));
if (state.canSubmit) {
onSubmit(state.text);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ class _FormTextFieldState extends State<_FormTextField> {
Widget build(BuildContext context) {
return BlocBuilder<FormBloc, FormState>(
builder: (context, state) {
final maybeError = state.error.fold((l) => l, (r) => null);
final maybeError = state.validationStatus.fold((l) => l, (r) => null);

return Container(
margin: const EdgeInsets.only(bottom: 12),
Expand Down

0 comments on commit 32286a2

Please sign in to comment.