mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2025-04-24 06:37:14 -04:00
fix: add error text under text field
This commit is contained in:
parent
2e295e6891
commit
caf8ff974f
4 changed files with 102 additions and 54 deletions
|
@ -2,6 +2,8 @@ import 'package:appflowy/generated/locale_keys.g.dart';
|
|||
import 'package:appflowy/user/application/sign_in_bloc.dart';
|
||||
import 'package:appflowy/user/presentation/screens/sign_in_screen/widgets/continue_with/continue_with_email.dart';
|
||||
import 'package:appflowy/user/presentation/screens/sign_in_screen/widgets/continue_with/continue_with_magic_link_or_passcode_page.dart';
|
||||
import 'package:appflowy/user/presentation/screens/sign_in_screen/widgets/continue_with/continue_with_password.dart';
|
||||
import 'package:appflowy/user/presentation/screens/sign_in_screen/widgets/continue_with/continue_with_password_page.dart';
|
||||
import 'package:appflowy/workspace/presentation/widgets/dialogs.dart';
|
||||
import 'package:appflowy_ui/appflowy_ui.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
|
@ -57,14 +59,13 @@ class _ContinueWithEmailAndPasswordState
|
|||
controller.text,
|
||||
),
|
||||
),
|
||||
// Hide password sign in until we implement the reset password / forgot password
|
||||
// VSpace(theme.spacing.l),
|
||||
// ContinueWithPassword(
|
||||
// onTap: () => _pushContinueWithPasswordPage(
|
||||
// context,
|
||||
// controller.text,
|
||||
// ),
|
||||
// ),
|
||||
VSpace(theme.spacing.l),
|
||||
ContinueWithPassword(
|
||||
onTap: () => _pushContinueWithPasswordPage(
|
||||
context,
|
||||
controller.text,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
@ -106,28 +107,31 @@ class _ContinueWithEmailAndPasswordState
|
|||
);
|
||||
}
|
||||
|
||||
// void _pushContinueWithPasswordPage(
|
||||
// BuildContext context,
|
||||
// String email,
|
||||
// ) {
|
||||
// final signInBloc = context.read<SignInBloc>();
|
||||
// Navigator.push(
|
||||
// context,
|
||||
// MaterialPageRoute(
|
||||
// builder: (context) => ContinueWithPasswordPage(
|
||||
// email: email,
|
||||
// backToLogin: () => Navigator.pop(context),
|
||||
// onEnterPassword: (password) => signInBloc.add(
|
||||
// SignInEvent.signInWithEmailAndPassword(
|
||||
// email: email,
|
||||
// password: password,
|
||||
// ),
|
||||
// ),
|
||||
// onForgotPassword: () {
|
||||
// // todo: implement forgot password
|
||||
// },
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
void _pushContinueWithPasswordPage(
|
||||
BuildContext context,
|
||||
String email,
|
||||
) {
|
||||
final signInBloc = context.read<SignInBloc>();
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => BlocProvider.value(
|
||||
value: signInBloc,
|
||||
child: ContinueWithPasswordPage(
|
||||
email: email,
|
||||
backToLogin: () => Navigator.pop(context),
|
||||
onEnterPassword: (password) => signInBloc.add(
|
||||
SignInEvent.signInWithEmailAndPassword(
|
||||
email: email,
|
||||
password: password,
|
||||
),
|
||||
),
|
||||
onForgotPassword: () {
|
||||
// todo: implement forgot password
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
import 'package:appflowy/user/application/sign_in_bloc.dart';
|
||||
import 'package:appflowy/user/presentation/screens/sign_in_screen/widgets/logo/logo.dart';
|
||||
import 'package:appflowy_ui/appflowy_ui.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flowy_infra_ui/widget/spacing.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
class ContinueWithPasswordPage extends StatefulWidget {
|
||||
const ContinueWithPasswordPage({
|
||||
|
@ -25,6 +27,7 @@ class ContinueWithPasswordPage extends StatefulWidget {
|
|||
|
||||
class _ContinueWithPasswordPageState extends State<ContinueWithPasswordPage> {
|
||||
final passwordController = TextEditingController();
|
||||
final inputPasswordKey = GlobalKey<AFTextFieldState>();
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
|
@ -38,18 +41,30 @@ class _ContinueWithPasswordPageState extends State<ContinueWithPasswordPage> {
|
|||
body: Center(
|
||||
child: SizedBox(
|
||||
width: 320,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
// Logo and title
|
||||
..._buildLogoAndTitle(),
|
||||
child: BlocListener<SignInBloc, SignInState>(
|
||||
listener: (context, state) {
|
||||
if (state.passwordError != null) {
|
||||
inputPasswordKey.currentState?.syncError(
|
||||
hasError: true,
|
||||
errorText: 'Incorrect password. Please try again.',
|
||||
);
|
||||
} else {
|
||||
inputPasswordKey.currentState?.syncError();
|
||||
}
|
||||
},
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
// Logo and title
|
||||
..._buildLogoAndTitle(),
|
||||
|
||||
// Password input and buttons
|
||||
..._buildPasswordSection(),
|
||||
// Password input and buttons
|
||||
..._buildPasswordSection(),
|
||||
|
||||
// Back to login
|
||||
..._buildBackToLogin(),
|
||||
],
|
||||
// Back to login
|
||||
..._buildBackToLogin(),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -100,25 +115,33 @@ class _ContinueWithPasswordPageState extends State<ContinueWithPasswordPage> {
|
|||
return [
|
||||
// Password input
|
||||
AFTextField(
|
||||
key: inputPasswordKey,
|
||||
controller: passwordController,
|
||||
hintText: 'Enter password',
|
||||
autoFocus: true,
|
||||
onSubmitted: widget.onEnterPassword,
|
||||
),
|
||||
// todo: ask designer to provide the spacing
|
||||
VSpace(12),
|
||||
VSpace(8),
|
||||
|
||||
// todo: forgot password is not implemented yet
|
||||
// Forgot password button
|
||||
// AFGhostTextButton(
|
||||
// text: 'Forget password?',
|
||||
// size: AFButtonSize.s,
|
||||
// onTap: widget.onForgotPassword,
|
||||
// textColor: (context, isHovering, disabled) {
|
||||
// return theme.textColorScheme.theme;
|
||||
// },
|
||||
// ),
|
||||
VSpace(12),
|
||||
Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: AFGhostTextButton(
|
||||
text: 'Forget password?',
|
||||
size: AFButtonSize.s,
|
||||
padding: EdgeInsets.zero,
|
||||
onTap: widget.onForgotPassword,
|
||||
textColor: (context, isHovering, disabled) {
|
||||
final theme = AppFlowyTheme.of(context);
|
||||
if (isHovering) {
|
||||
return theme.fillColorScheme.themeThickHover;
|
||||
}
|
||||
return theme.textColorScheme.theme;
|
||||
},
|
||||
),
|
||||
),
|
||||
VSpace(20),
|
||||
|
||||
// Continue button
|
||||
AFFilledTextButton.primary(
|
||||
|
@ -137,8 +160,12 @@ class _ContinueWithPasswordPageState extends State<ContinueWithPasswordPage> {
|
|||
text: 'Back to Login',
|
||||
size: AFButtonSize.s,
|
||||
onTap: widget.backToLogin,
|
||||
padding: EdgeInsets.zero,
|
||||
textColor: (context, isHovering, disabled) {
|
||||
final theme = AppFlowyTheme.of(context);
|
||||
if (isHovering) {
|
||||
return theme.fillColorScheme.themeThickHover;
|
||||
}
|
||||
return theme.textColorScheme.theme;
|
||||
},
|
||||
),
|
||||
|
|
|
@ -101,6 +101,7 @@ class _DesktopThirdPartySignInState extends State<_DesktopThirdPartySignIn> {
|
|||
VSpace(theme.spacing.l),
|
||||
AFGhostTextButton(
|
||||
text: 'More options',
|
||||
padding: EdgeInsets.zero,
|
||||
textColor: (context, isHovering, disabled) {
|
||||
if (isHovering) {
|
||||
return theme.fillColorScheme.themeThickHover;
|
||||
|
|
|
@ -5,6 +5,10 @@ typedef AFTextFieldValidator = (bool result, String errorText) Function(
|
|||
TextEditingController controller,
|
||||
);
|
||||
|
||||
abstract class AFTextFieldState extends State<AFTextField> {
|
||||
void syncError({bool hasError = false, String errorText = ''}) {}
|
||||
}
|
||||
|
||||
class AFTextField extends StatefulWidget {
|
||||
const AFTextField({
|
||||
super.key,
|
||||
|
@ -52,7 +56,7 @@ class AFTextField extends StatefulWidget {
|
|||
State<AFTextField> createState() => _AFTextFieldState();
|
||||
}
|
||||
|
||||
class _AFTextFieldState extends State<AFTextField> {
|
||||
class _AFTextFieldState extends AFTextFieldState {
|
||||
late final TextEditingController effectiveController;
|
||||
|
||||
bool hasError = false;
|
||||
|
@ -148,6 +152,7 @@ class _AFTextFieldState extends State<AFTextField> {
|
|||
|
||||
if (hasError && errorText.isNotEmpty) {
|
||||
child = Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
child,
|
||||
SizedBox(height: theme.spacing.xs),
|
||||
|
@ -174,4 +179,15 @@ class _AFTextFieldState extends State<AFTextField> {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void syncError({
|
||||
bool hasError = false,
|
||||
String errorText = '',
|
||||
}) {
|
||||
setState(() {
|
||||
this.hasError = hasError;
|
||||
this.errorText = errorText;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue