From 0ea2da424fe54821ce66166d383ef91f2a6254e2 Mon Sep 17 00:00:00 2001 From: Mathias Mogensen <42929161+Xazin@users.noreply.github.com> Date: Fri, 1 Nov 2024 00:36:14 +0100 Subject: [PATCH] fix: reminder improvements (#6680) --- .../mobile_notifications_page.dart | 14 ++---- .../child_page_transaction_handler.dart | 15 ++---- .../editor_transaction_service.dart | 1 + .../mention_transaction_handler.dart | 23 +++++++++ .../workspace/application/view/view_ext.dart | 6 --- .../notifications/notification_dialog.dart | 49 +++++++++---------- .../widgets/notification_button.dart | 2 +- .../widgets/notification_item.dart | 23 --------- .../widgets/notification_view.dart | 3 -- 9 files changed, 55 insertions(+), 81 deletions(-) create mode 100644 frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/transaction_handler/mention_transaction_handler.dart diff --git a/frontend/appflowy_flutter/lib/mobile/presentation/notifications/mobile_notifications_page.dart b/frontend/appflowy_flutter/lib/mobile/presentation/notifications/mobile_notifications_page.dart index 64e3e8824d..a8055b8ba2 100644 --- a/frontend/appflowy_flutter/lib/mobile/presentation/notifications/mobile_notifications_page.dart +++ b/frontend/appflowy_flutter/lib/mobile/presentation/notifications/mobile_notifications_page.dart @@ -28,8 +28,8 @@ class MobileNotificationsScreen extends StatefulWidget { class _MobileNotificationsScreenState extends State with SingleTickerProviderStateMixin { - final ReminderBloc _reminderBloc = getIt(); - late final TabController _controller = TabController(length: 2, vsync: this); + final ReminderBloc reminderBloc = getIt(); + late final TabController controller = TabController(length: 2, vsync: this); @override Widget build(BuildContext context) { @@ -39,7 +39,7 @@ class _MobileNotificationsScreenState extends State create: (context) => UserProfileBloc()..add(const UserProfileEvent.started()), ), - BlocProvider.value(value: _reminderBloc), + BlocProvider.value(value: reminderBloc), BlocProvider( create: (_) => NotificationFilterBloc(), ), @@ -54,8 +54,8 @@ class _MobileNotificationsScreenState extends State _NotificationScreenContent( workspaceSetting: workspaceSetting, userProfile: userProfile, - controller: _controller, - reminderBloc: _reminderBloc, + controller: controller, + reminderBloc: reminderBloc, ), ); }, @@ -124,7 +124,6 @@ class _NotificationScreenContent extends StatelessWidget { reminderBloc: reminderBloc, views: sectionState.section.publicViews, onAction: _onAction, - onDelete: _onDelete, onReadChanged: _onReadChanged, actionBar: InboxActionBar( hasUnreads: state.hasUnreads, @@ -161,9 +160,6 @@ class _NotificationScreenContent extends StatelessWidget { ), ); - void _onDelete(ReminderPB reminder) => - reminderBloc.add(ReminderEvent.remove(reminderId: reminder.id)); - void _onReadChanged(ReminderPB reminder, bool isRead) => reminderBloc.add( ReminderEvent.update(ReminderUpdate(id: reminder.id, isRead: isRead)), ); diff --git a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/mention/child_page_transaction_handler.dart b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/mention/child_page_transaction_handler.dart index b2a47bae37..5c02837329 100644 --- a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/mention/child_page_transaction_handler.dart +++ b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/mention/child_page_transaction_handler.dart @@ -1,6 +1,5 @@ import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/plugins/document/presentation/editor_plugins/mention/mention_block.dart'; -import 'package:appflowy/plugins/document/presentation/editor_plugins/transaction_handler/editor_transaction_handler.dart'; import 'package:appflowy/plugins/trash/application/trash_service.dart'; import 'package:appflowy/shared/clipboard_state.dart'; import 'package:appflowy/workspace/application/view/view_service.dart'; @@ -12,20 +11,12 @@ import 'package:flowy_infra_ui/style_widget/snap_bar.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -/// The data used to handle transactions for mentions. -/// -/// [Node] is the block node. -/// [Map] is the data of the mention block. -/// [int] is the index of the mention block in the list of deltas (after transaction apply). -/// -typedef MentionBlockData = (Node, Map, int); +import '../transaction_handler/mention_transaction_handler.dart'; const _pasteIdentifier = 'child_page_transaction'; -class ChildPageTransactionHandler - extends EditorTransactionHandler { - ChildPageTransactionHandler() - : super(type: MentionBlockKeys.mention, livesInDelta: true); +class ChildPageTransactionHandler extends MentionTransactionHandler { + ChildPageTransactionHandler() : super(subType: MentionType.childPage.name); @override Future onTransaction( diff --git a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/transaction_handler/editor_transaction_service.dart b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/transaction_handler/editor_transaction_service.dart index 8fcbbcf91f..a82a6cba70 100644 --- a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/transaction_handler/editor_transaction_service.dart +++ b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/transaction_handler/editor_transaction_service.dart @@ -4,6 +4,7 @@ import 'package:appflowy/plugins/document/presentation/editor_notification.dart' import 'package:appflowy/plugins/document/presentation/editor_plugins/mention/child_page_transaction_handler.dart'; import 'package:appflowy/plugins/document/presentation/editor_plugins/sub_page/sub_page_transaction_handler.dart'; import 'package:appflowy/plugins/document/presentation/editor_plugins/transaction_handler/editor_transaction_handler.dart'; +import 'package:appflowy/plugins/document/presentation/editor_plugins/transaction_handler/mention_transaction_handler.dart'; import 'package:appflowy/shared/clipboard_state.dart'; import 'package:appflowy/shared/feature_flags.dart'; import 'package:appflowy_editor/appflowy_editor.dart'; diff --git a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/transaction_handler/mention_transaction_handler.dart b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/transaction_handler/mention_transaction_handler.dart new file mode 100644 index 0000000000..632561589e --- /dev/null +++ b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/transaction_handler/mention_transaction_handler.dart @@ -0,0 +1,23 @@ +import 'package:appflowy/plugins/document/presentation/editor_plugins/mention/mention_block.dart'; +import 'package:appflowy/plugins/document/presentation/editor_plugins/transaction_handler/editor_transaction_handler.dart'; +import 'package:appflowy_editor/appflowy_editor.dart'; + +/// The data used to handle transactions for mentions. +/// +/// [Node] is the block node. +/// [Map] is the data of the mention block. +/// [int] is the index of the mention block in the list of deltas (after transaction apply). +/// +typedef MentionBlockData = (Node, Map, int); + +abstract class MentionTransactionHandler + extends EditorTransactionHandler { + const MentionTransactionHandler({ + required this.subType, + }) + : super(type: MentionBlockKeys.mention, livesInDelta: true); + + final String subType; + + MentionType get mentionType => MentionType.fromString(subType); +} diff --git a/frontend/appflowy_flutter/lib/workspace/application/view/view_ext.dart b/frontend/appflowy_flutter/lib/workspace/application/view/view_ext.dart index dc7e5e97a9..3b3b369ccd 100644 --- a/frontend/appflowy_flutter/lib/workspace/application/view/view_ext.dart +++ b/frontend/appflowy_flutter/lib/workspace/application/view/view_ext.dart @@ -301,12 +301,6 @@ extension ViewLayoutExtension on ViewLayoutPB { _ => throw Exception('Unknown layout type'), }; - FlowySvgData mentionIcon({bool isChildPage = false}) => switch (this) { - ViewLayoutPB.Document => - isChildPage ? FlowySvgs.child_page_s : FlowySvgs.link_to_page_s, - _ => icon, - }; - bool get isDocumentView => switch (this) { ViewLayoutPB.Document => true, ViewLayoutPB.Chat || diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/notifications/notification_dialog.dart b/frontend/appflowy_flutter/lib/workspace/presentation/notifications/notification_dialog.dart index d0392efb55..0c22cd60d2 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/notifications/notification_dialog.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/notifications/notification_dialog.dart @@ -28,25 +28,25 @@ class NotificationDialog extends StatefulWidget { class _NotificationDialogState extends State with SingleTickerProviderStateMixin { - late final TabController _controller = TabController(length: 2, vsync: this); - final PopoverMutex _mutex = PopoverMutex(); - final ReminderBloc _reminderBloc = getIt(); + late final TabController controller = TabController(length: 2, vsync: this); + final PopoverMutex mutex = PopoverMutex(); + final ReminderBloc reminderBloc = getIt(); @override void initState() { super.initState(); // Get all the past and upcoming reminders - _reminderBloc.add(const ReminderEvent.started()); - _controller.addListener(_updateState); + reminderBloc.add(const ReminderEvent.started()); + controller.addListener(updateState); } - void _updateState() => setState(() {}); + void updateState() => setState(() {}); @override void dispose() { - _mutex.dispose(); - _controller.removeListener(_updateState); - _controller.dispose(); + mutex.dispose(); + controller.removeListener(updateState); + controller.dispose(); super.dispose(); } @@ -54,7 +54,7 @@ class _NotificationDialogState extends State Widget build(BuildContext context) { return MultiBlocProvider( providers: [ - BlocProvider.value(value: _reminderBloc), + BlocProvider.value(value: reminderBloc), BlocProvider( create: (_) => NotificationFilterBloc(), ), @@ -63,27 +63,26 @@ class _NotificationDialogState extends State builder: (context, filterState) => BlocBuilder( builder: (context, state) { - final reminders = state.reminders.sortByScheduledAt(); + final pastReminders = state.pastReminders.sortByScheduledAt(); final upcomingReminders = state.upcomingReminders.sortByScheduledAt(); - final hasUnreads = reminders.any((r) => !r.isRead); + final hasUnreads = pastReminders.any((r) => !r.isRead); return Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ const NotificationHubTitle(), - NotificationTabBar(tabController: _controller), + NotificationTabBar(tabController: controller), Expanded( child: TabBarView( - controller: _controller, + controller: controller, children: [ NotificationsView( - shownReminders: reminders, - reminderBloc: _reminderBloc, + shownReminders: pastReminders, + reminderBloc: reminderBloc, views: widget.views, - onDelete: _onDelete, - onAction: _onAction, + onAction: onAction, onReadChanged: _onReadChanged, actionBar: InboxActionBar( hasUnreads: hasUnreads, @@ -92,10 +91,10 @@ class _NotificationDialogState extends State ), NotificationsView( shownReminders: upcomingReminders, - reminderBloc: _reminderBloc, + reminderBloc: reminderBloc, views: widget.views, isUpcoming: true, - onAction: _onAction, + onAction: onAction, ), ], ), @@ -108,20 +107,16 @@ class _NotificationDialogState extends State ); } - void _onAction(ReminderPB reminder, int? path, ViewPB? view) { - _reminderBloc.add( + void onAction(ReminderPB reminder, int? path, ViewPB? view) { + reminderBloc.add( ReminderEvent.pressReminder(reminderId: reminder.id, path: path), ); widget.mutex.close(); } - void _onDelete(ReminderPB reminder) { - _reminderBloc.add(ReminderEvent.remove(reminderId: reminder.id)); - } - void _onReadChanged(ReminderPB reminder, bool isRead) { - _reminderBloc.add( + reminderBloc.add( ReminderEvent.update(ReminderUpdate(id: reminder.id, isRead: isRead)), ); } diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/notifications/widgets/notification_button.dart b/frontend/appflowy_flutter/lib/workspace/presentation/notifications/widgets/notification_button.dart index c6c216e409..6f29c8e2aa 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/notifications/widgets/notification_button.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/notifications/widgets/notification_button.dart @@ -48,7 +48,7 @@ class _NotificationButtonState extends State { builder: (notificationSettingsContext, notificationSettingsState) { return BlocBuilder( builder: (context, state) { - final hasUnreads = state.reminders.any((r) => !r.isRead); + final hasUnreads = state.pastReminders.any((r) => !r.isRead); return notificationSettingsState.isShowNotificationsIconEnabled ? FlowyTooltip( message: LocaleKeys.notificationHub_title.tr(), diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/notifications/widgets/notification_item.dart b/frontend/appflowy_flutter/lib/workspace/presentation/notifications/widgets/notification_item.dart index f85df0e6d1..849d8cd5c5 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/notifications/widgets/notification_item.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/notifications/widgets/notification_item.dart @@ -27,7 +27,6 @@ class NotificationItem extends StatefulWidget { this.includeTime = false, this.readOnly = false, this.onAction, - this.onDelete, this.onReadChanged, this.view, }); @@ -50,7 +49,6 @@ class NotificationItem extends StatefulWidget { final bool readOnly; final void Function(int? path)? onAction; - final VoidCallback? onDelete; final void Function(bool isRead)? onReadChanged; @override @@ -153,7 +151,6 @@ class _NotificationItemState extends State { UniversalPlatform.isMobile ? 16 : 14, color: AFThemeExtension.of(context).textColor, ), - // TODO(Xazin): Relative time FlowyText.regular( infoString, fontSize: @@ -191,7 +188,6 @@ class _NotificationItemState extends State { top: UniversalPlatform.isMobile ? 8 : 4, child: NotificationItemActions( isRead: widget.isRead, - onDelete: widget.onDelete, onReadChanged: widget.onReadChanged, ), ), @@ -247,12 +243,10 @@ class NotificationItemActions extends StatelessWidget { const NotificationItemActions({ super.key, required this.isRead, - this.onDelete, this.onReadChanged, }); final bool isRead; - final VoidCallback? onDelete; final void Function(bool isRead)? onReadChanged; @override @@ -292,23 +286,6 @@ class NotificationItemActions extends StatelessWidget { onPressed: () => onReadChanged?.call(true), ), ], - VerticalDivider( - width: 3, - thickness: 1, - indent: 2, - endIndent: 2, - color: UniversalPlatform.isMobile - ? Theme.of(context).colorScheme.outline - : Theme.of(context).dividerColor, - ), - FlowyIconButton( - height: size, - width: size, - tooltipText: LocaleKeys.reminderNotification_tooltipDelete.tr(), - icon: const FlowySvg(FlowySvgs.delete_s), - iconColorOnHover: Theme.of(context).colorScheme.onSurface, - onPressed: onDelete, - ), ], ), ), diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/notifications/widgets/notification_view.dart b/frontend/appflowy_flutter/lib/workspace/presentation/notifications/widgets/notification_view.dart index 645be8b055..0465256f60 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/notifications/widgets/notification_view.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/notifications/widgets/notification_view.dart @@ -26,7 +26,6 @@ class NotificationsView extends StatelessWidget { required this.views, this.isUpcoming = false, this.onAction, - this.onDelete, this.onReadChanged, this.actionBar, }); @@ -36,7 +35,6 @@ class NotificationsView extends StatelessWidget { final List views; final bool isUpcoming; final Function(ReminderPB reminder, int? path, ViewPB? view)? onAction; - final Function(ReminderPB reminder)? onDelete; final Function(ReminderPB reminder, bool isRead)? onReadChanged; final Widget? actionBar; @@ -87,7 +85,6 @@ class NotificationsView extends StatelessWidget { readOnly: isUpcoming, onReadChanged: (isRead) => onReadChanged?.call(reminder, isRead), - onDelete: () => onDelete?.call(reminder), onAction: (path) => onAction?.call(reminder, path, view), view: view, );