Skip to content

Commit

Permalink
Require accepting tsandcs during profile setup
Browse files Browse the repository at this point in the history
  • Loading branch information
JElgar committed Oct 20, 2024
1 parent 8f5d460 commit 6edf7f4
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 45 deletions.
12 changes: 4 additions & 8 deletions lib/assets/components/inputs.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,11 @@ class CustomCheckboxFormField extends FormField<bool> {
Widget? title,
FormFieldSetter<bool>? onSaved,
ValueChanged<bool>? onChanged,
FormFieldValidator<bool>? validator,
String? errorText,
bool initialValue = false,
bool autovalidate = false,
}) : super(
onSaved: onSaved,
validator: validator,
initialValue: initialValue,
autovalidateMode: AutovalidateMode.disabled,
builder: (FormFieldState<bool> state) {
Expand Down Expand Up @@ -42,14 +41,11 @@ class CustomCheckboxFormField extends FormField<bool> {
Expanded(child: title!),
],
),
state.hasError
errorText != null
? Text(
state.errorText!,
errorText,
style:
Theme.of(context).textTheme.bodyLarge?.copyWith(
color: Theme.of(context).colorScheme.error,
fontSize: 12,
),
Theme.of(context).inputDecorationTheme.errorStyle,
)
: Container(),
],
Expand Down
35 changes: 21 additions & 14 deletions lib/themes.dart
Original file line number Diff line number Diff line change
Expand Up @@ -101,23 +101,25 @@ final secondaryFilledButtonStyle = TextButton.styleFrom(
foregroundColor: CustomColors.brandColor,
).merge(primaryTextButtonStyle);

final regularColorScheme = ColorScheme(
brightness: Brightness.light,
primary: CustomColors.brandColor,
// TODO This is does not quite work as white isn't very visible on orange
onPrimary: Colors.white,
secondary: const Color.fromRGBO(255, 220, 121, 1),
onSecondary: Colors.black,
// TODO What is this really?
surface: Colors.white,
onSurface: Colors.black,
error: const Color.fromRGBO(211, 0, 1, 1),
// TODO Really?
onError: Colors.white,
);

final regularTheme = ThemeData(
primaryColor: CustomColors.brandColor,
fontFamily: fontFamily,
colorScheme: ColorScheme(
brightness: Brightness.light,
primary: CustomColors.brandColor,
// TODO This is does not quite work as white isn't very visible on orange
onPrimary: Colors.white,
secondary: const Color.fromRGBO(255, 220, 121, 1),
onSecondary: Colors.black,
// TODO What is this really?
surface: Colors.white,
onSurface: Colors.black,
error: const Color.fromRGBO(211, 0, 1, 1),
// TODO Really?
onError: Colors.white,
),
colorScheme: regularColorScheme,
textTheme: textTheme,
buttonTheme: ButtonThemeData(
buttonColor: CustomColors.brandColor,
Expand Down Expand Up @@ -163,6 +165,11 @@ final regularTheme = ThemeData(
BorderSide(color: Color.fromRGBO(222, 224, 232, 1), width: 2.0),
),
hintStyle: textTheme.labelMedium,
errorStyle: TextStyle(
color: regularColorScheme.error,
fontStyle: FontStyle.italic,
fontSize: textTheme.bodyMedium?.fontSize,
),
),
);

Expand Down
22 changes: 20 additions & 2 deletions lib/ui/views/profile_setup/bloc/profile_setup_bloc.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:formz/formz.dart';
import 'package:nowu/services/user_service.dart';
import 'package:nowu/ui/views/profile_setup/model/tsAndCsAcceptInput.dart';

import './profile_setup_state.dart';
import '../model/name.dart';
Expand All @@ -15,6 +16,7 @@ class ProfileSetupBloc extends Cubit<ProfileSetupState> {
ProfileSetupState(
name: Name.pure(),
shouldSubscribeToNewsLetter: false,
tsAndCsAccepted: TsAndCsAcceptInput.pure(),
),
);

Expand All @@ -35,10 +37,26 @@ class ProfileSetupBloc extends Cubit<ProfileSetupState> {
);
}

void updateTsAndCsAccepted(bool value) {
emit(
state.copyWith(
tsAndCsAccepted: TsAndCsAcceptInput.dirty(value),
isValid: Formz.validate([state.tsAndCsAccepted]),
),
);
}

Future<void> submit() async {
final isValid = Formz.validate([state.name]);
final isValid = Formz.validate([state.name, state.tsAndCsAccepted]);
if (isValid == false) {
emit(state.copyWith(isValid: isValid));
emit(
state.copyWith(
isValid: isValid,
name: Name.dirty(state.name.value),
tsAndCsAccepted:
TsAndCsAcceptInput.dirty(state.tsAndCsAccepted.value),
),
);
return;
}

Expand Down
2 changes: 2 additions & 0 deletions lib/ui/views/profile_setup/bloc/profile_setup_state.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:formz/formz.dart';
import 'package:nowu/ui/views/profile_setup/model/tsAndCsAcceptInput.dart';

import '../model/name.dart';

Expand All @@ -12,5 +13,6 @@ class ProfileSetupState with _$ProfileSetupState {
@Default(false) bool isValid,
required Name name,
required bool shouldSubscribeToNewsLetter,
required TsAndCsAcceptInput tsAndCsAccepted,
}) = _ProfileSetupState;
}
19 changes: 19 additions & 0 deletions lib/ui/views/profile_setup/model/tsAndCsAcceptInput.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import 'package:formz/formz.dart';

enum TsAndCsValidationError { acceptRequired }

class TsAndCsAcceptInput extends FormzInput<bool, TsAndCsValidationError>
with FormzInputErrorCacheMixin {
TsAndCsAcceptInput.pure([super.value = false]) : super.pure();
TsAndCsAcceptInput.dirty([super.value = false]) : super.dirty();

@override
TsAndCsValidationError? validator(value) {
print('Validating field $value');
if (!value) {
return TsAndCsValidationError.acceptRequired;
}

return null;
}
}
54 changes: 33 additions & 21 deletions lib/ui/views/profile_setup/profile_setup_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import 'package:nowu/services/user_service.dart';
import 'package:nowu/themes.dart';
import 'package:nowu/ui/views/profile_setup/bloc/profile_setup_bloc.dart';
import 'package:nowu/ui/views/profile_setup/model/name.dart';
import 'package:nowu/ui/views/profile_setup/model/tsAndCsAcceptInput.dart';
import 'package:url_launcher/url_launcher.dart';

import 'bloc/profile_setup_state.dart';
Expand Down Expand Up @@ -219,32 +220,43 @@ class _NewsLetterSignup extends StatelessWidget {
}

class _AcceptTandCInput extends StatelessWidget {
String? _getErrorText(ProfileSetupState state) {
switch (state.tsAndCsAccepted.displayError) {
case null:
return null;
case TsAndCsValidationError.acceptRequired:
return 'You must accept our terms and conditions to use the app';
}
}

@override
Widget build(BuildContext context) {
return CustomCheckboxFormField(
title: RichText(
text: TextSpan(
style: Theme.of(context).textTheme.bodyLarge?.copyWith(
color: Colors.white,
),
children: [
const TextSpan(text: 'I agree to the user '),
TextSpan(
text: 'Terms & Conditions',
return BlocBuilder<ProfileSetupBloc, ProfileSetupState>(
builder: (context, state) {
return CustomCheckboxFormField(
title: RichText(
text: TextSpan(
style: Theme.of(context).textTheme.bodyLarge?.copyWith(
color: CustomColors.brandColor,
color: Colors.white,
),
recognizer: TapGestureRecognizer()
..onTap = () => launchUrl(
TERMS_AND_CONDITIONS_URI,
),
children: [
const TextSpan(text: 'I agree to the user '),
TextSpan(
text: 'Terms & Conditions',
style: Theme.of(context).textTheme.bodyLarge?.copyWith(
color: CustomColors.brandColor,
),
recognizer: TapGestureRecognizer()
..onTap = () => launchUrl(
TERMS_AND_CONDITIONS_URI,
),
),
],
),
],
),
),
validator: (value) {
if (!value!) return 'You must accept our terms and conditions';
return null;
),
onChanged: context.read<ProfileSetupBloc>().updateTsAndCsAccepted,
errorText: _getErrorText(state),
);
},
);
}
Expand Down

0 comments on commit 6edf7f4

Please sign in to comment.