feat: add loading dialog

This commit is contained in:
LucasXu0 2025-04-10 11:03:49 +08:00
parent 0344afddf4
commit 41c2a4c9b0
8 changed files with 105 additions and 61 deletions

View file

@ -276,10 +276,11 @@ class _InviteMemberPageState extends State<_InviteMemberPage> {
void _inviteMember(BuildContext context) {
final email = emailController.text;
if (!isEmail(email)) {
return showToastNotification(
showToastNotification(
type: ToastificationType.error,
message: LocaleKeys.settings_appearance_members_emailInvalidError.tr(),
);
return;
}
context
.read<WorkspaceMemberBloc>()

View file

@ -104,9 +104,10 @@ Future<void> downloadMediaFile(
await afLaunchUrlString(file.url);
} else {
if (userProfile == null) {
return showToastNotification(
showToastNotification(
message: LocaleKeys.grid_media_downloadFailedToken.tr(),
);
return;
}
final uri = Uri.parse(file.url);

View file

@ -2,8 +2,6 @@ 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';
@ -59,13 +57,14 @@ class _ContinueWithEmailAndPasswordState
controller.text,
),
),
VSpace(theme.spacing.l),
ContinueWithPassword(
onTap: () => _pushContinueWithPasswordPage(
context,
controller.text,
),
),
// Hide password sign in until we implement the reset password / forgot password
// VSpace(theme.spacing.l),
// ContinueWithPassword(
// onTap: () => _pushContinueWithPasswordPage(
// context,
// controller.text,
// ),
// ),
],
);
}
@ -75,10 +74,11 @@ class _ContinueWithEmailAndPasswordState
String email,
) {
if (!isEmail(email)) {
return showToastNotification(
showToastNotification(
message: LocaleKeys.signIn_invalidEmail.tr(),
type: ToastificationType.error,
);
return;
}
final signInBloc = context.read<SignInBloc>();
@ -89,13 +89,16 @@ class _ContinueWithEmailAndPasswordState
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ContinueWithMagicLinkOrPasscodePage(
email: email,
backToLogin: () => Navigator.pop(context),
onEnterPasscode: (passcode) => signInBloc.add(
SignInEvent.signInWithPasscode(
email: email,
passcode: passcode,
builder: (context) => BlocProvider.value(
value: signInBloc,
child: ContinueWithMagicLinkOrPasscodePage(
email: email,
backToLogin: () => Navigator.pop(context),
onEnterPasscode: (passcode) => signInBloc.add(
SignInEvent.signInWithPasscode(
email: email,
passcode: passcode,
),
),
),
),
@ -103,28 +106,28 @@ 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) => ContinueWithPasswordPage(
// email: email,
// backToLogin: () => Navigator.pop(context),
// onEnterPassword: (password) => signInBloc.add(
// SignInEvent.signInWithEmailAndPassword(
// email: email,
// password: password,
// ),
// ),
// onForgotPassword: () {
// // todo: implement forgot password
// },
// ),
// ),
// );
// }
}

View file

@ -1,7 +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/workspace/presentation/widgets/dialogs.dart';
import 'package:appflowy_ui/appflowy_ui.dart';
import 'package:flowy_infra_ui/widget/spacing.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class ContinueWithMagicLinkOrPasscodePage extends StatefulWidget {
const ContinueWithMagicLinkOrPasscodePage({
@ -26,6 +29,8 @@ class _ContinueWithMagicLinkOrPasscodePageState
bool isEnteringPasscode = false;
ToastificationItem? toastificationItem;
@override
void dispose() {
passcodeController.dispose();
@ -35,22 +40,31 @@ class _ContinueWithMagicLinkOrPasscodePageState
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: SizedBox(
width: 320,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// Logo, title and description
..._buildLogoTitleAndDescription(),
return BlocListener<SignInBloc, SignInState>(
listener: (context, state) {
if (state.isSubmitting) {
_showLoadingDialog();
} else {
_dismissLoadingDialog();
}
},
child: Scaffold(
body: Center(
child: SizedBox(
width: 320,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// Logo, title and description
..._buildLogoTitleAndDescription(),
// Enter code manually
..._buildEnterCodeManually(),
// Enter code manually
..._buildEnterCodeManually(),
// Back to login
..._buildBackToLogin(),
],
// Back to login
..._buildBackToLogin(),
],
),
),
),
),
@ -91,7 +105,7 @@ class _ContinueWithMagicLinkOrPasscodePageState
// continue to login
AFFilledTextButton.primary(
text: 'Continue to sign up',
text: 'Continue to sign in',
onTap: () => widget.onEnterPasscode(passcodeController.text),
size: AFButtonSize.l,
alignment: Alignment.center,
@ -109,6 +123,9 @@ class _ContinueWithMagicLinkOrPasscodePageState
onTap: widget.backToLogin,
textColor: (context, isHovering, disabled) {
final theme = AppFlowyTheme.of(context);
if (isHovering) {
return theme.fillColorScheme.themeThickHover;
}
return theme.textColorScheme.theme;
},
),
@ -150,4 +167,19 @@ class _ContinueWithMagicLinkOrPasscodePageState
spacing,
];
}
void _showLoadingDialog() {
_dismissLoadingDialog();
toastificationItem = showToastNotification(
message: 'Signing in...',
);
}
void _dismissLoadingDialog() {
final toastificationItem = this.toastificationItem;
if (toastificationItem != null) {
toastification.dismiss(toastificationItem);
}
}
}

View file

@ -64,10 +64,11 @@ class _SignInWithMagicLinkButtonsState
void _sendMagicLink(BuildContext context, String email) {
if (!isEmail(email)) {
return showToastNotification(
showToastNotification(
message: LocaleKeys.signIn_invalidEmail.tr(),
type: ToastificationType.error,
);
return;
}
context

View file

@ -104,6 +104,9 @@ class _DesktopThirdPartySignInState extends State<_DesktopThirdPartySignIn> {
AFGhostTextButton(
text: 'More options',
textColor: (context, isHovering, disabled) {
if (isHovering) {
return theme.fillColorScheme.themeThickHover;
}
return theme.textColorScheme.theme;
},
onTap: () {

View file

@ -188,6 +188,9 @@ class SidebarPlanBloc extends Bloc<SidebarPlanEvent, SidebarPlanState> {
UserEventGetWorkspaceUsage(payload).send().then((result) {
result.onSuccess(
(usage) {
if (isClosed) {
return;
}
add(SidebarPlanEvent.updateWorkspaceUsage(usage));
},
);

View file

@ -362,7 +362,7 @@ class OkCancelButton extends StatelessWidget {
}
}
void showToastNotification({
ToastificationItem showToastNotification({
String? message,
TextSpan? richMessage,
String? description,
@ -374,7 +374,7 @@ void showToastNotification({
(message == null) != (richMessage == null),
"Exactly one of message or richMessage must be non-null.",
);
toastification.showCustom(
return toastification.showCustom(
alignment: Alignment.bottomCenter,
autoCloseDuration: const Duration(milliseconds: 3000),
callbacks: callbacks ?? const ToastificationCallbacks(),