From 64e5a80d1f078b9ef569d34a874e6d24dd067e9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damian=20Moli=C5=84ski?= <47773413+damian-molinski@users.noreply.github.com> Date: Wed, 31 Jul 2024 12:02:49 +0200 Subject: [PATCH] refactor: text_filed widgets page independent (#648) * refactor: change widgets folders from voices_[name] to just [name] to be consistent * refactor: Introduce VoicesTextField which is page independent and LoginXTextField which are tied to LoginBloc * fix: voices_x_text_field child widget reference --- .../scenarios/robots/login_robot.dart | 9 ++- .../pages/login/login_email_text_filed.dart | 29 +++++++++ .../lib/pages/login/login_form.dart | 7 ++- .../login/login_password_text_field.dart | 29 +++++++++ .../actions/connecting_status.dart | 0 .../actions/finish_account_button.dart | 0 .../actions/get_started_button.dart | 0 .../actions/notifications_indicator.dart | 0 .../actions/role_picker.dart | 0 .../actions/search_button.dart | 0 .../actions/unlock_button.dart | 0 .../actions/user_profile_button.dart | 0 .../actions/voices_app_bar_actions.dart | 0 .../voices_app_bar.dart | 2 +- .../voices_drawer.dart | 0 catalyst_voices/lib/widgets/email_input.dart | 38 ------------ .../lib/widgets/password_input.dart | 46 --------------- .../text_field/voices_email_text_field.dart | 33 +++++++++++ .../voices_password_text_field.dart | 35 +++++++++++ .../widgets/text_field/voices_text_field.dart | 59 +++++++++++++++++++ catalyst_voices/lib/widgets/widgets.dart | 5 +- .../examples/voices_navigation_example.dart | 6 +- 22 files changed, 202 insertions(+), 96 deletions(-) create mode 100644 catalyst_voices/lib/pages/login/login_email_text_filed.dart create mode 100644 catalyst_voices/lib/pages/login/login_password_text_field.dart rename catalyst_voices/lib/widgets/{voices_app_bar => app_bar}/actions/connecting_status.dart (100%) rename catalyst_voices/lib/widgets/{voices_app_bar => app_bar}/actions/finish_account_button.dart (100%) rename catalyst_voices/lib/widgets/{voices_app_bar => app_bar}/actions/get_started_button.dart (100%) rename catalyst_voices/lib/widgets/{voices_app_bar => app_bar}/actions/notifications_indicator.dart (100%) rename catalyst_voices/lib/widgets/{voices_app_bar => app_bar}/actions/role_picker.dart (100%) rename catalyst_voices/lib/widgets/{voices_app_bar => app_bar}/actions/search_button.dart (100%) rename catalyst_voices/lib/widgets/{voices_app_bar => app_bar}/actions/unlock_button.dart (100%) rename catalyst_voices/lib/widgets/{voices_app_bar => app_bar}/actions/user_profile_button.dart (100%) rename catalyst_voices/lib/widgets/{voices_app_bar => app_bar}/actions/voices_app_bar_actions.dart (100%) rename catalyst_voices/lib/widgets/{voices_app_bar => app_bar}/voices_app_bar.dart (97%) rename catalyst_voices/lib/widgets/{voices_drawer => drawer}/voices_drawer.dart (100%) delete mode 100644 catalyst_voices/lib/widgets/email_input.dart delete mode 100644 catalyst_voices/lib/widgets/password_input.dart create mode 100644 catalyst_voices/lib/widgets/text_field/voices_email_text_field.dart create mode 100644 catalyst_voices/lib/widgets/text_field/voices_password_text_field.dart create mode 100644 catalyst_voices/lib/widgets/text_field/voices_text_field.dart diff --git a/catalyst_voices/integration_test/scenarios/robots/login_robot.dart b/catalyst_voices/integration_test/scenarios/robots/login_robot.dart index b3c60e6d0b..4adc148806 100644 --- a/catalyst_voices/integration_test/scenarios/robots/login_robot.dart +++ b/catalyst_voices/integration_test/scenarios/robots/login_robot.dart @@ -1,5 +1,6 @@ import 'package:catalyst_voices/pages/login/login.dart'; -import 'package:catalyst_voices/widgets/widgets.dart'; +import 'package:catalyst_voices/pages/login/login_email_text_filed.dart'; +import 'package:catalyst_voices/pages/login/login_password_text_field.dart'; import 'package:flutter_test/flutter_test.dart'; final class LoginRobot { @@ -16,14 +17,16 @@ final class LoginRobot { } Future enterEmail(String email) async { - final emailTextField = find.byKey(EmailInput.emailInputKey); + final emailTextField = find.byKey(LoginEmailTextFiled.emailInputKey); expect(emailTextField, findsOneWidget); await widgetTester.enterText(emailTextField, email); await widgetTester.pump(); } Future enterPassword(String password) async { - final passwordTextField = find.byKey(PasswordInput.passwordInputKey); + final passwordTextField = find.byKey( + LoginPasswordTextField.passwordInputKey, + ); expect(passwordTextField, findsOneWidget); await widgetTester.enterText(passwordTextField, password); await widgetTester.pump(); diff --git a/catalyst_voices/lib/pages/login/login_email_text_filed.dart b/catalyst_voices/lib/pages/login/login_email_text_filed.dart new file mode 100644 index 0000000000..770d8ac3ad --- /dev/null +++ b/catalyst_voices/lib/pages/login/login_email_text_filed.dart @@ -0,0 +1,29 @@ +import 'package:catalyst_voices/widgets/widgets.dart'; +import 'package:catalyst_voices_blocs/catalyst_voices_blocs.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +final class LoginEmailTextFiled extends StatelessWidget { + static const emailInputKey = Key('EmailInput'); + + const LoginEmailTextFiled({ + super.key, + }); + + @override + Widget build(BuildContext context) { + return BlocBuilder( + buildWhen: (previous, current) => previous.email != current.email, + builder: (context, state) { + return VoicesEmailTextField( + key: emailInputKey, + onChanged: (email) => _onEmailChanged(context, email), + ); + }, + ); + } + + void _onEmailChanged(BuildContext context, String email) { + context.read().add(LoginEmailChanged(email)); + } +} diff --git a/catalyst_voices/lib/pages/login/login_form.dart b/catalyst_voices/lib/pages/login/login_form.dart index a7d125a898..9c49875402 100644 --- a/catalyst_voices/lib/pages/login/login_form.dart +++ b/catalyst_voices/lib/pages/login/login_form.dart @@ -1,5 +1,6 @@ import 'package:catalyst_voices/pages/login/login.dart'; -import 'package:catalyst_voices/widgets/widgets.dart'; +import 'package:catalyst_voices/pages/login/login_email_text_filed.dart'; +import 'package:catalyst_voices/pages/login/login_password_text_field.dart'; import 'package:catalyst_voices_blocs/catalyst_voices_blocs.dart'; import 'package:catalyst_voices_localization/catalyst_voices_localization.dart'; import 'package:flutter/material.dart'; @@ -51,9 +52,9 @@ final class LoginForm extends StatelessWidget { ), ), const SizedBox(height: 30), - const EmailInput(), + const LoginEmailTextFiled(), const SizedBox(height: 20), - const PasswordInput(), + const LoginPasswordTextField(), const SizedBox(height: 20), const SizedBox( width: double.infinity, diff --git a/catalyst_voices/lib/pages/login/login_password_text_field.dart b/catalyst_voices/lib/pages/login/login_password_text_field.dart new file mode 100644 index 0000000000..aa165e2d10 --- /dev/null +++ b/catalyst_voices/lib/pages/login/login_password_text_field.dart @@ -0,0 +1,29 @@ +import 'package:catalyst_voices/widgets/widgets.dart'; +import 'package:catalyst_voices_blocs/catalyst_voices_blocs.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +final class LoginPasswordTextField extends StatelessWidget { + static const passwordInputKey = Key('PasswordInput'); + + const LoginPasswordTextField({ + super.key, + }); + + @override + Widget build(BuildContext context) { + return BlocBuilder( + buildWhen: (previous, current) => previous.password != current.password, + builder: (context, state) { + return VoicesPasswordTextField( + key: passwordInputKey, + onChanged: (password) => _onPasswordChanged(context, password), + ); + }, + ); + } + + void _onPasswordChanged(BuildContext context, String password) { + context.read().add(LoginPasswordChanged(password)); + } +} diff --git a/catalyst_voices/lib/widgets/voices_app_bar/actions/connecting_status.dart b/catalyst_voices/lib/widgets/app_bar/actions/connecting_status.dart similarity index 100% rename from catalyst_voices/lib/widgets/voices_app_bar/actions/connecting_status.dart rename to catalyst_voices/lib/widgets/app_bar/actions/connecting_status.dart diff --git a/catalyst_voices/lib/widgets/voices_app_bar/actions/finish_account_button.dart b/catalyst_voices/lib/widgets/app_bar/actions/finish_account_button.dart similarity index 100% rename from catalyst_voices/lib/widgets/voices_app_bar/actions/finish_account_button.dart rename to catalyst_voices/lib/widgets/app_bar/actions/finish_account_button.dart diff --git a/catalyst_voices/lib/widgets/voices_app_bar/actions/get_started_button.dart b/catalyst_voices/lib/widgets/app_bar/actions/get_started_button.dart similarity index 100% rename from catalyst_voices/lib/widgets/voices_app_bar/actions/get_started_button.dart rename to catalyst_voices/lib/widgets/app_bar/actions/get_started_button.dart diff --git a/catalyst_voices/lib/widgets/voices_app_bar/actions/notifications_indicator.dart b/catalyst_voices/lib/widgets/app_bar/actions/notifications_indicator.dart similarity index 100% rename from catalyst_voices/lib/widgets/voices_app_bar/actions/notifications_indicator.dart rename to catalyst_voices/lib/widgets/app_bar/actions/notifications_indicator.dart diff --git a/catalyst_voices/lib/widgets/voices_app_bar/actions/role_picker.dart b/catalyst_voices/lib/widgets/app_bar/actions/role_picker.dart similarity index 100% rename from catalyst_voices/lib/widgets/voices_app_bar/actions/role_picker.dart rename to catalyst_voices/lib/widgets/app_bar/actions/role_picker.dart diff --git a/catalyst_voices/lib/widgets/voices_app_bar/actions/search_button.dart b/catalyst_voices/lib/widgets/app_bar/actions/search_button.dart similarity index 100% rename from catalyst_voices/lib/widgets/voices_app_bar/actions/search_button.dart rename to catalyst_voices/lib/widgets/app_bar/actions/search_button.dart diff --git a/catalyst_voices/lib/widgets/voices_app_bar/actions/unlock_button.dart b/catalyst_voices/lib/widgets/app_bar/actions/unlock_button.dart similarity index 100% rename from catalyst_voices/lib/widgets/voices_app_bar/actions/unlock_button.dart rename to catalyst_voices/lib/widgets/app_bar/actions/unlock_button.dart diff --git a/catalyst_voices/lib/widgets/voices_app_bar/actions/user_profile_button.dart b/catalyst_voices/lib/widgets/app_bar/actions/user_profile_button.dart similarity index 100% rename from catalyst_voices/lib/widgets/voices_app_bar/actions/user_profile_button.dart rename to catalyst_voices/lib/widgets/app_bar/actions/user_profile_button.dart diff --git a/catalyst_voices/lib/widgets/voices_app_bar/actions/voices_app_bar_actions.dart b/catalyst_voices/lib/widgets/app_bar/actions/voices_app_bar_actions.dart similarity index 100% rename from catalyst_voices/lib/widgets/voices_app_bar/actions/voices_app_bar_actions.dart rename to catalyst_voices/lib/widgets/app_bar/actions/voices_app_bar_actions.dart diff --git a/catalyst_voices/lib/widgets/voices_app_bar/voices_app_bar.dart b/catalyst_voices/lib/widgets/app_bar/voices_app_bar.dart similarity index 97% rename from catalyst_voices/lib/widgets/voices_app_bar/voices_app_bar.dart rename to catalyst_voices/lib/widgets/app_bar/voices_app_bar.dart index 6f3edc3df8..7b6dbd1b16 100644 --- a/catalyst_voices/lib/widgets/voices_app_bar/voices_app_bar.dart +++ b/catalyst_voices/lib/widgets/app_bar/voices_app_bar.dart @@ -1,4 +1,4 @@ -import 'package:catalyst_voices/widgets/voices_app_bar/actions/voices_app_bar_actions.dart'; +import 'package:catalyst_voices/widgets/app_bar/actions/voices_app_bar_actions.dart'; import 'package:catalyst_voices_assets/catalyst_voices_assets.dart'; import 'package:catalyst_voices_brands/catalyst_voices_brands.dart'; import 'package:catalyst_voices_shared/catalyst_voices_shared.dart'; diff --git a/catalyst_voices/lib/widgets/voices_drawer/voices_drawer.dart b/catalyst_voices/lib/widgets/drawer/voices_drawer.dart similarity index 100% rename from catalyst_voices/lib/widgets/voices_drawer/voices_drawer.dart rename to catalyst_voices/lib/widgets/drawer/voices_drawer.dart diff --git a/catalyst_voices/lib/widgets/email_input.dart b/catalyst_voices/lib/widgets/email_input.dart deleted file mode 100644 index 7f47dc773f..0000000000 --- a/catalyst_voices/lib/widgets/email_input.dart +++ /dev/null @@ -1,38 +0,0 @@ -import 'package:catalyst_voices_blocs/catalyst_voices_blocs.dart'; -import 'package:catalyst_voices_localization/catalyst_voices_localization.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; - -final class EmailInput extends StatelessWidget { - static const emailInputKey = Key('EmailInput'); - - const EmailInput({super.key}); - - @override - Widget build(BuildContext context) { - final l10n = context.l10n; - return BlocBuilder( - buildWhen: (previous, current) => previous.email != current.email, - builder: (context, state) { - return TextField( - key: emailInputKey, - keyboardType: TextInputType.emailAddress, - textInputAction: TextInputAction.next, - onChanged: (email) => context.read().add( - LoginEmailChanged(email), - ), - decoration: InputDecoration( - filled: true, - labelText: l10n.emailLabelText, - hintText: l10n.emailHintText, - errorText: l10n.emailErrorText, - border: const OutlineInputBorder(), - ), - style: const TextStyle( - fontWeight: FontWeight.w500, - ), - ); - }, - ); - } -} diff --git a/catalyst_voices/lib/widgets/password_input.dart b/catalyst_voices/lib/widgets/password_input.dart deleted file mode 100644 index 0b9a526de9..0000000000 --- a/catalyst_voices/lib/widgets/password_input.dart +++ /dev/null @@ -1,46 +0,0 @@ -import 'package:catalyst_voices_blocs/catalyst_voices_blocs.dart'; -import 'package:catalyst_voices_localization/catalyst_voices_localization.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; - -final class PasswordInput extends StatelessWidget { - static const passwordInputKey = Key('PasswordInput'); - - const PasswordInput({ - super.key, - }); - - @override - Widget build(BuildContext context) { - final l10n = context.l10n; - return BlocBuilder( - buildWhen: (previous, current) => previous.password != current.password, - builder: (context, state) { - return TextField( - key: passwordInputKey, - keyboardType: TextInputType.multiline, - obscureText: true, - textInputAction: TextInputAction.done, - onChanged: (password) => _onPasswordChanged(context, password), - decoration: InputDecoration( - filled: true, - errorMaxLines: 2, - labelText: l10n.passwordLabelText, - hintText: l10n.passwordHintText, - errorText: l10n.passwordErrorText, - border: const OutlineInputBorder(), - ), - style: const TextStyle( - fontWeight: FontWeight.w500, - ), - ); - }, - ); - } - - void _onPasswordChanged(BuildContext context, String password) { - return context.read().add( - LoginPasswordChanged(password), - ); - } -} diff --git a/catalyst_voices/lib/widgets/text_field/voices_email_text_field.dart b/catalyst_voices/lib/widgets/text_field/voices_email_text_field.dart new file mode 100644 index 0000000000..d4c98d03fd --- /dev/null +++ b/catalyst_voices/lib/widgets/text_field/voices_email_text_field.dart @@ -0,0 +1,33 @@ +import 'package:catalyst_voices/widgets/text_field/voices_text_field.dart'; +import 'package:catalyst_voices_localization/catalyst_voices_localization.dart'; +import 'package:flutter/material.dart'; + +final class VoicesEmailTextField extends StatelessWidget { + /// Emits new value when widget input changes + final ValueChanged? onChanged; + + const VoicesEmailTextField({ + super.key, + this.onChanged, + }); + + @override + Widget build(BuildContext context) { + final l10n = context.l10n; + return VoicesTextField( + keyboardType: TextInputType.emailAddress, + textInputAction: TextInputAction.next, + onChanged: onChanged, + decoration: InputDecoration( + filled: true, + labelText: l10n.emailLabelText, + hintText: l10n.emailHintText, + errorText: l10n.emailErrorText, + border: const OutlineInputBorder(), + ), + style: const TextStyle( + fontWeight: FontWeight.w500, + ), + ); + } +} diff --git a/catalyst_voices/lib/widgets/text_field/voices_password_text_field.dart b/catalyst_voices/lib/widgets/text_field/voices_password_text_field.dart new file mode 100644 index 0000000000..61a81284c9 --- /dev/null +++ b/catalyst_voices/lib/widgets/text_field/voices_password_text_field.dart @@ -0,0 +1,35 @@ +import 'package:catalyst_voices/widgets/text_field/voices_text_field.dart'; +import 'package:catalyst_voices_localization/catalyst_voices_localization.dart'; +import 'package:flutter/material.dart'; + +final class VoicesPasswordTextField extends StatelessWidget { + /// Emits new value when widget input changes + final ValueChanged? onChanged; + + const VoicesPasswordTextField({ + super.key, + this.onChanged, + }); + + @override + Widget build(BuildContext context) { + final l10n = context.l10n; + return VoicesTextField( + keyboardType: TextInputType.multiline, + obscureText: true, + textInputAction: TextInputAction.done, + onChanged: onChanged, + decoration: InputDecoration( + filled: true, + errorMaxLines: 2, + labelText: l10n.passwordLabelText, + hintText: l10n.passwordHintText, + errorText: l10n.passwordErrorText, + border: const OutlineInputBorder(), + ), + style: const TextStyle( + fontWeight: FontWeight.w500, + ), + ); + } +} diff --git a/catalyst_voices/lib/widgets/text_field/voices_text_field.dart b/catalyst_voices/lib/widgets/text_field/voices_text_field.dart new file mode 100644 index 0000000000..feef7154e3 --- /dev/null +++ b/catalyst_voices/lib/widgets/text_field/voices_text_field.dart @@ -0,0 +1,59 @@ +import 'package:flutter/material.dart'; + +/// Base Voices TextField widget +class VoicesTextField extends StatelessWidget { + /// [TextField.controller] + final TextEditingController? controller; + + /// [TextField.focusNode] + final FocusNode? focusNode; + + /// [TextField.decoration] + final InputDecoration? decoration; + + /// [TextField.keyboardType] + final TextInputType? keyboardType; + + /// [TextField.textInputAction] + final TextInputAction? textInputAction; + + /// [TextField.textCapitalization] + final TextCapitalization textCapitalization; + + /// [TextField.style] + final TextStyle? style; + + /// [TextField.obscureText] + final bool obscureText; + + /// [TextField.onChanged] + final ValueChanged? onChanged; + + const VoicesTextField({ + super.key, + this.controller, + this.focusNode, + this.decoration = const InputDecoration(), + this.keyboardType, + this.textInputAction, + this.textCapitalization = TextCapitalization.none, + this.style, + this.obscureText = false, + this.onChanged, + }); + + @override + Widget build(BuildContext context) { + return TextField( + controller: controller, + focusNode: focusNode, + decoration: decoration, + keyboardType: keyboardType, + textInputAction: textInputAction, + textCapitalization: textCapitalization, + style: style, + obscureText: obscureText, + onChanged: onChanged, + ); + } +} diff --git a/catalyst_voices/lib/widgets/widgets.dart b/catalyst_voices/lib/widgets/widgets.dart index 2151fa5c6b..6400f957d1 100644 --- a/catalyst_voices/lib/widgets/widgets.dart +++ b/catalyst_voices/lib/widgets/widgets.dart @@ -1,2 +1,3 @@ -export 'email_input.dart'; -export 'password_input.dart'; +export 'text_field/voices_email_text_field.dart'; +export 'text_field/voices_password_text_field.dart'; +export 'text_field/voices_text_field.dart'; diff --git a/catalyst_voices/uikit_example/lib/examples/voices_navigation_example.dart b/catalyst_voices/uikit_example/lib/examples/voices_navigation_example.dart index 5f0d71b86d..41c819393d 100644 --- a/catalyst_voices/uikit_example/lib/examples/voices_navigation_example.dart +++ b/catalyst_voices/uikit_example/lib/examples/voices_navigation_example.dart @@ -1,8 +1,8 @@ +import 'package:catalyst_voices/widgets/app_bar/actions/voices_app_bar_actions.dart'; +import 'package:catalyst_voices/widgets/app_bar/voices_app_bar.dart'; +import 'package:catalyst_voices/widgets/drawer/voices_drawer.dart'; import 'package:catalyst_voices/widgets/menu/voices_expandable_list_tile.dart'; import 'package:catalyst_voices/widgets/menu/voices_list_tile.dart'; -import 'package:catalyst_voices/widgets/voices_app_bar/actions/voices_app_bar_actions.dart'; -import 'package:catalyst_voices/widgets/voices_app_bar/voices_app_bar.dart'; -import 'package:catalyst_voices/widgets/voices_drawer/voices_drawer.dart'; import 'package:catalyst_voices_assets/catalyst_voices_assets.dart'; import 'package:flutter/material.dart';