sign_up_screen.dart 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. import 'package:app_flowy/startup/startup.dart';
  2. import 'package:app_flowy/user/application/sign_up_bloc.dart';
  3. import 'package:app_flowy/user/presentation/router.dart';
  4. import 'package:app_flowy/user/presentation/widgets/background.dart';
  5. import 'package:easy_localization/easy_localization.dart';
  6. import 'package:flowy_infra/size.dart';
  7. import 'package:flowy_infra/text_style.dart';
  8. import 'package:flowy_infra_ui/widget/rounded_button.dart';
  9. import 'package:flowy_infra_ui/widget/rounded_input_field.dart';
  10. import 'package:flowy_infra_ui/widget/spacing.dart';
  11. import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
  12. import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart' show UserProfilePB;
  13. import 'package:flowy_infra_ui/style_widget/snap_bar.dart';
  14. import 'package:flutter/material.dart';
  15. import 'package:flutter_bloc/flutter_bloc.dart';
  16. import 'package:dartz/dartz.dart';
  17. import 'package:flowy_infra/image.dart';
  18. import 'package:app_flowy/generated/locale_keys.g.dart';
  19. import 'package:textstyle_extensions/textstyle_extensions.dart';
  20. class SignUpScreen extends StatelessWidget {
  21. final AuthRouter router;
  22. const SignUpScreen({Key? key, required this.router}) : super(key: key);
  23. @override
  24. Widget build(BuildContext context) {
  25. return BlocProvider(
  26. create: (context) => getIt<SignUpBloc>(),
  27. child: BlocListener<SignUpBloc, SignUpState>(
  28. listener: (context, state) {
  29. state.successOrFail.fold(
  30. () => {},
  31. (result) => _handleSuccessOrFail(context, result),
  32. );
  33. },
  34. child: const Scaffold(body: SignUpForm()),
  35. ),
  36. );
  37. }
  38. void _handleSuccessOrFail(
  39. BuildContext context, Either<UserProfilePB, FlowyError> result) {
  40. result.fold(
  41. (user) => router.pushWelcomeScreen(context, user),
  42. (error) => showSnapBar(context, error.msg),
  43. );
  44. }
  45. }
  46. class SignUpForm extends StatelessWidget {
  47. const SignUpForm({
  48. Key? key,
  49. }) : super(key: key);
  50. @override
  51. Widget build(BuildContext context) {
  52. return Align(
  53. alignment: Alignment.center,
  54. child: AuthFormContainer(
  55. children: [
  56. FlowyLogoTitle(
  57. title: LocaleKeys.signUp_title.tr(),
  58. logoSize: const Size(60, 60),
  59. ),
  60. const VSpace(30),
  61. const EmailTextField(),
  62. const PasswordTextField(),
  63. const RepeatPasswordTextField(),
  64. const VSpace(30),
  65. const SignUpButton(),
  66. const VSpace(10),
  67. const SignUpPrompt(),
  68. if (context.read<SignUpBloc>().state.isSubmitting) ...[
  69. const SizedBox(height: 8),
  70. const LinearProgressIndicator(value: null),
  71. ]
  72. ],
  73. ),
  74. );
  75. }
  76. }
  77. class SignUpPrompt extends StatelessWidget {
  78. const SignUpPrompt({
  79. Key? key,
  80. }) : super(key: key);
  81. @override
  82. Widget build(BuildContext context) {
  83. return Row(
  84. mainAxisAlignment: MainAxisAlignment.center,
  85. children: [
  86. Text(
  87. LocaleKeys.signUp_alreadyHaveAnAccount.tr(),
  88. style: TextStyle(color: Theme.of(context).hintColor, fontSize: 12),
  89. ),
  90. TextButton(
  91. style: TextButton.styleFrom(textStyle: TextStyles.body1),
  92. onPressed: () => Navigator.pop(context),
  93. child: Text(LocaleKeys.signIn_buttonText.tr(),
  94. style: TextStyle(color: Theme.of(context).colorScheme.primary)),
  95. ),
  96. ],
  97. );
  98. }
  99. }
  100. class SignUpButton extends StatelessWidget {
  101. const SignUpButton({
  102. Key? key,
  103. }) : super(key: key);
  104. @override
  105. Widget build(BuildContext context) {
  106. return RoundedTextButton(
  107. title: LocaleKeys.signUp_getStartedText.tr(),
  108. height: 48,
  109. onPressed: () {
  110. context
  111. .read<SignUpBloc>()
  112. .add(const SignUpEvent.signUpWithUserEmailAndPassword());
  113. },
  114. );
  115. }
  116. }
  117. class PasswordTextField extends StatelessWidget {
  118. const PasswordTextField({
  119. Key? key,
  120. }) : super(key: key);
  121. @override
  122. Widget build(BuildContext context) {
  123. return BlocBuilder<SignUpBloc, SignUpState>(
  124. buildWhen: (previous, current) =>
  125. previous.passwordError != current.passwordError,
  126. builder: (context, state) {
  127. return RoundedInputField(
  128. obscureText: true,
  129. obscureIcon: svgWidget("home/hide"),
  130. obscureHideIcon: svgWidget("home/show"),
  131. style: TextStyles.body1.size(FontSizes.s14),
  132. hintText: LocaleKeys.signUp_passwordHint.tr(),
  133. normalBorderColor: Theme.of(context).colorScheme.outline,
  134. errorBorderColor: Theme.of(context).colorScheme.error,
  135. cursorColor: Theme.of(context).colorScheme.primary,
  136. errorText: context
  137. .read<SignUpBloc>()
  138. .state
  139. .passwordError
  140. .fold(() => "", (error) => error),
  141. onChanged: (value) => context
  142. .read<SignUpBloc>()
  143. .add(SignUpEvent.passwordChanged(value)),
  144. );
  145. },
  146. );
  147. }
  148. }
  149. class RepeatPasswordTextField extends StatelessWidget {
  150. const RepeatPasswordTextField({
  151. Key? key,
  152. }) : super(key: key);
  153. @override
  154. Widget build(BuildContext context) {
  155. return BlocBuilder<SignUpBloc, SignUpState>(
  156. buildWhen: (previous, current) =>
  157. previous.repeatPasswordError != current.repeatPasswordError,
  158. builder: (context, state) {
  159. return RoundedInputField(
  160. obscureText: true,
  161. obscureIcon: svgWidget("home/hide"),
  162. obscureHideIcon: svgWidget("home/show"),
  163. style: TextStyles.body1.size(FontSizes.s14),
  164. hintText: LocaleKeys.signUp_repeatPasswordHint.tr(),
  165. normalBorderColor: Theme.of(context).colorScheme.outline,
  166. errorBorderColor: Theme.of(context).colorScheme.error,
  167. cursorColor: Theme.of(context).colorScheme.primary,
  168. errorText: context
  169. .read<SignUpBloc>()
  170. .state
  171. .repeatPasswordError
  172. .fold(() => "", (error) => error),
  173. onChanged: (value) => context
  174. .read<SignUpBloc>()
  175. .add(SignUpEvent.repeatPasswordChanged(value)),
  176. );
  177. },
  178. );
  179. }
  180. }
  181. class EmailTextField extends StatelessWidget {
  182. const EmailTextField({
  183. Key? key,
  184. }) : super(key: key);
  185. @override
  186. Widget build(BuildContext context) {
  187. return BlocBuilder<SignUpBloc, SignUpState>(
  188. buildWhen: (previous, current) =>
  189. previous.emailError != current.emailError,
  190. builder: (context, state) {
  191. return RoundedInputField(
  192. hintText: LocaleKeys.signUp_emailHint.tr(),
  193. style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
  194. normalBorderColor: Theme.of(context).colorScheme.outline,
  195. errorBorderColor: Theme.of(context).colorScheme.error,
  196. cursorColor: Theme.of(context).colorScheme.primary,
  197. errorText: context
  198. .read<SignUpBloc>()
  199. .state
  200. .emailError
  201. .fold(() => "", (error) => error),
  202. onChanged: (value) =>
  203. context.read<SignUpBloc>().add(SignUpEvent.emailChanged(value)),
  204. );
  205. },
  206. );
  207. }
  208. }