fix: reminder improvements (#6680)

This commit is contained in:
Mathias Mogensen 2024-11-01 00:36:14 +01:00 committed by GitHub
parent 07e34609e7
commit 0ea2da424f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 55 additions and 81 deletions

View File

@ -28,8 +28,8 @@ class MobileNotificationsScreen extends StatefulWidget {
class _MobileNotificationsScreenState extends State<MobileNotificationsScreen> class _MobileNotificationsScreenState extends State<MobileNotificationsScreen>
with SingleTickerProviderStateMixin { with SingleTickerProviderStateMixin {
final ReminderBloc _reminderBloc = getIt<ReminderBloc>(); final ReminderBloc reminderBloc = getIt<ReminderBloc>();
late final TabController _controller = TabController(length: 2, vsync: this); late final TabController controller = TabController(length: 2, vsync: this);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -39,7 +39,7 @@ class _MobileNotificationsScreenState extends State<MobileNotificationsScreen>
create: (context) => create: (context) =>
UserProfileBloc()..add(const UserProfileEvent.started()), UserProfileBloc()..add(const UserProfileEvent.started()),
), ),
BlocProvider<ReminderBloc>.value(value: _reminderBloc), BlocProvider<ReminderBloc>.value(value: reminderBloc),
BlocProvider<NotificationFilterBloc>( BlocProvider<NotificationFilterBloc>(
create: (_) => NotificationFilterBloc(), create: (_) => NotificationFilterBloc(),
), ),
@ -54,8 +54,8 @@ class _MobileNotificationsScreenState extends State<MobileNotificationsScreen>
_NotificationScreenContent( _NotificationScreenContent(
workspaceSetting: workspaceSetting, workspaceSetting: workspaceSetting,
userProfile: userProfile, userProfile: userProfile,
controller: _controller, controller: controller,
reminderBloc: _reminderBloc, reminderBloc: reminderBloc,
), ),
); );
}, },
@ -124,7 +124,6 @@ class _NotificationScreenContent extends StatelessWidget {
reminderBloc: reminderBloc, reminderBloc: reminderBloc,
views: sectionState.section.publicViews, views: sectionState.section.publicViews,
onAction: _onAction, onAction: _onAction,
onDelete: _onDelete,
onReadChanged: _onReadChanged, onReadChanged: _onReadChanged,
actionBar: InboxActionBar( actionBar: InboxActionBar(
hasUnreads: state.hasUnreads, 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( void _onReadChanged(ReminderPB reminder, bool isRead) => reminderBloc.add(
ReminderEvent.update(ReminderUpdate(id: reminder.id, isRead: isRead)), ReminderEvent.update(ReminderUpdate(id: reminder.id, isRead: isRead)),
); );

View File

@ -1,6 +1,5 @@
import 'package:appflowy/generated/locale_keys.g.dart'; 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/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/plugins/trash/application/trash_service.dart';
import 'package:appflowy/shared/clipboard_state.dart'; import 'package:appflowy/shared/clipboard_state.dart';
import 'package:appflowy/workspace/application/view/view_service.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:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
/// The data used to handle transactions for mentions. import '../transaction_handler/mention_transaction_handler.dart';
///
/// [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<String, dynamic>, int);
const _pasteIdentifier = 'child_page_transaction'; const _pasteIdentifier = 'child_page_transaction';
class ChildPageTransactionHandler class ChildPageTransactionHandler extends MentionTransactionHandler {
extends EditorTransactionHandler<MentionBlockData> { ChildPageTransactionHandler() : super(subType: MentionType.childPage.name);
ChildPageTransactionHandler()
: super(type: MentionBlockKeys.mention, livesInDelta: true);
@override @override
Future<void> onTransaction( Future<void> onTransaction(

View File

@ -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/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/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/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/clipboard_state.dart';
import 'package:appflowy/shared/feature_flags.dart'; import 'package:appflowy/shared/feature_flags.dart';
import 'package:appflowy_editor/appflowy_editor.dart'; import 'package:appflowy_editor/appflowy_editor.dart';

View File

@ -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<String, dynamic>, int);
abstract class MentionTransactionHandler
extends EditorTransactionHandler<MentionBlockData> {
const MentionTransactionHandler({
required this.subType,
})
: super(type: MentionBlockKeys.mention, livesInDelta: true);
final String subType;
MentionType get mentionType => MentionType.fromString(subType);
}

View File

@ -301,12 +301,6 @@ extension ViewLayoutExtension on ViewLayoutPB {
_ => throw Exception('Unknown layout type'), _ => 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) { bool get isDocumentView => switch (this) {
ViewLayoutPB.Document => true, ViewLayoutPB.Document => true,
ViewLayoutPB.Chat || ViewLayoutPB.Chat ||

View File

@ -28,25 +28,25 @@ class NotificationDialog extends StatefulWidget {
class _NotificationDialogState extends State<NotificationDialog> class _NotificationDialogState extends State<NotificationDialog>
with SingleTickerProviderStateMixin { with SingleTickerProviderStateMixin {
late final TabController _controller = TabController(length: 2, vsync: this); late final TabController controller = TabController(length: 2, vsync: this);
final PopoverMutex _mutex = PopoverMutex(); final PopoverMutex mutex = PopoverMutex();
final ReminderBloc _reminderBloc = getIt<ReminderBloc>(); final ReminderBloc reminderBloc = getIt<ReminderBloc>();
@override @override
void initState() { void initState() {
super.initState(); super.initState();
// Get all the past and upcoming reminders // Get all the past and upcoming reminders
_reminderBloc.add(const ReminderEvent.started()); reminderBloc.add(const ReminderEvent.started());
_controller.addListener(_updateState); controller.addListener(updateState);
} }
void _updateState() => setState(() {}); void updateState() => setState(() {});
@override @override
void dispose() { void dispose() {
_mutex.dispose(); mutex.dispose();
_controller.removeListener(_updateState); controller.removeListener(updateState);
_controller.dispose(); controller.dispose();
super.dispose(); super.dispose();
} }
@ -54,7 +54,7 @@ class _NotificationDialogState extends State<NotificationDialog>
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MultiBlocProvider( return MultiBlocProvider(
providers: [ providers: [
BlocProvider<ReminderBloc>.value(value: _reminderBloc), BlocProvider<ReminderBloc>.value(value: reminderBloc),
BlocProvider<NotificationFilterBloc>( BlocProvider<NotificationFilterBloc>(
create: (_) => NotificationFilterBloc(), create: (_) => NotificationFilterBloc(),
), ),
@ -63,27 +63,26 @@ class _NotificationDialogState extends State<NotificationDialog>
builder: (context, filterState) => builder: (context, filterState) =>
BlocBuilder<ReminderBloc, ReminderState>( BlocBuilder<ReminderBloc, ReminderState>(
builder: (context, state) { builder: (context, state) {
final reminders = state.reminders.sortByScheduledAt(); final pastReminders = state.pastReminders.sortByScheduledAt();
final upcomingReminders = final upcomingReminders =
state.upcomingReminders.sortByScheduledAt(); state.upcomingReminders.sortByScheduledAt();
final hasUnreads = reminders.any((r) => !r.isRead); final hasUnreads = pastReminders.any((r) => !r.isRead);
return Column( return Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
const NotificationHubTitle(), const NotificationHubTitle(),
NotificationTabBar(tabController: _controller), NotificationTabBar(tabController: controller),
Expanded( Expanded(
child: TabBarView( child: TabBarView(
controller: _controller, controller: controller,
children: [ children: [
NotificationsView( NotificationsView(
shownReminders: reminders, shownReminders: pastReminders,
reminderBloc: _reminderBloc, reminderBloc: reminderBloc,
views: widget.views, views: widget.views,
onDelete: _onDelete, onAction: onAction,
onAction: _onAction,
onReadChanged: _onReadChanged, onReadChanged: _onReadChanged,
actionBar: InboxActionBar( actionBar: InboxActionBar(
hasUnreads: hasUnreads, hasUnreads: hasUnreads,
@ -92,10 +91,10 @@ class _NotificationDialogState extends State<NotificationDialog>
), ),
NotificationsView( NotificationsView(
shownReminders: upcomingReminders, shownReminders: upcomingReminders,
reminderBloc: _reminderBloc, reminderBloc: reminderBloc,
views: widget.views, views: widget.views,
isUpcoming: true, isUpcoming: true,
onAction: _onAction, onAction: onAction,
), ),
], ],
), ),
@ -108,20 +107,16 @@ class _NotificationDialogState extends State<NotificationDialog>
); );
} }
void _onAction(ReminderPB reminder, int? path, ViewPB? view) { void onAction(ReminderPB reminder, int? path, ViewPB? view) {
_reminderBloc.add( reminderBloc.add(
ReminderEvent.pressReminder(reminderId: reminder.id, path: path), ReminderEvent.pressReminder(reminderId: reminder.id, path: path),
); );
widget.mutex.close(); widget.mutex.close();
} }
void _onDelete(ReminderPB reminder) {
_reminderBloc.add(ReminderEvent.remove(reminderId: reminder.id));
}
void _onReadChanged(ReminderPB reminder, bool isRead) { void _onReadChanged(ReminderPB reminder, bool isRead) {
_reminderBloc.add( reminderBloc.add(
ReminderEvent.update(ReminderUpdate(id: reminder.id, isRead: isRead)), ReminderEvent.update(ReminderUpdate(id: reminder.id, isRead: isRead)),
); );
} }

View File

@ -48,7 +48,7 @@ class _NotificationButtonState extends State<NotificationButton> {
builder: (notificationSettingsContext, notificationSettingsState) { builder: (notificationSettingsContext, notificationSettingsState) {
return BlocBuilder<ReminderBloc, ReminderState>( return BlocBuilder<ReminderBloc, ReminderState>(
builder: (context, state) { builder: (context, state) {
final hasUnreads = state.reminders.any((r) => !r.isRead); final hasUnreads = state.pastReminders.any((r) => !r.isRead);
return notificationSettingsState.isShowNotificationsIconEnabled return notificationSettingsState.isShowNotificationsIconEnabled
? FlowyTooltip( ? FlowyTooltip(
message: LocaleKeys.notificationHub_title.tr(), message: LocaleKeys.notificationHub_title.tr(),

View File

@ -27,7 +27,6 @@ class NotificationItem extends StatefulWidget {
this.includeTime = false, this.includeTime = false,
this.readOnly = false, this.readOnly = false,
this.onAction, this.onAction,
this.onDelete,
this.onReadChanged, this.onReadChanged,
this.view, this.view,
}); });
@ -50,7 +49,6 @@ class NotificationItem extends StatefulWidget {
final bool readOnly; final bool readOnly;
final void Function(int? path)? onAction; final void Function(int? path)? onAction;
final VoidCallback? onDelete;
final void Function(bool isRead)? onReadChanged; final void Function(bool isRead)? onReadChanged;
@override @override
@ -153,7 +151,6 @@ class _NotificationItemState extends State<NotificationItem> {
UniversalPlatform.isMobile ? 16 : 14, UniversalPlatform.isMobile ? 16 : 14,
color: AFThemeExtension.of(context).textColor, color: AFThemeExtension.of(context).textColor,
), ),
// TODO(Xazin): Relative time
FlowyText.regular( FlowyText.regular(
infoString, infoString,
fontSize: fontSize:
@ -191,7 +188,6 @@ class _NotificationItemState extends State<NotificationItem> {
top: UniversalPlatform.isMobile ? 8 : 4, top: UniversalPlatform.isMobile ? 8 : 4,
child: NotificationItemActions( child: NotificationItemActions(
isRead: widget.isRead, isRead: widget.isRead,
onDelete: widget.onDelete,
onReadChanged: widget.onReadChanged, onReadChanged: widget.onReadChanged,
), ),
), ),
@ -247,12 +243,10 @@ class NotificationItemActions extends StatelessWidget {
const NotificationItemActions({ const NotificationItemActions({
super.key, super.key,
required this.isRead, required this.isRead,
this.onDelete,
this.onReadChanged, this.onReadChanged,
}); });
final bool isRead; final bool isRead;
final VoidCallback? onDelete;
final void Function(bool isRead)? onReadChanged; final void Function(bool isRead)? onReadChanged;
@override @override
@ -292,23 +286,6 @@ class NotificationItemActions extends StatelessWidget {
onPressed: () => onReadChanged?.call(true), 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,
),
], ],
), ),
), ),

View File

@ -26,7 +26,6 @@ class NotificationsView extends StatelessWidget {
required this.views, required this.views,
this.isUpcoming = false, this.isUpcoming = false,
this.onAction, this.onAction,
this.onDelete,
this.onReadChanged, this.onReadChanged,
this.actionBar, this.actionBar,
}); });
@ -36,7 +35,6 @@ class NotificationsView extends StatelessWidget {
final List<ViewPB> views; final List<ViewPB> views;
final bool isUpcoming; final bool isUpcoming;
final Function(ReminderPB reminder, int? path, ViewPB? view)? onAction; final Function(ReminderPB reminder, int? path, ViewPB? view)? onAction;
final Function(ReminderPB reminder)? onDelete;
final Function(ReminderPB reminder, bool isRead)? onReadChanged; final Function(ReminderPB reminder, bool isRead)? onReadChanged;
final Widget? actionBar; final Widget? actionBar;
@ -87,7 +85,6 @@ class NotificationsView extends StatelessWidget {
readOnly: isUpcoming, readOnly: isUpcoming,
onReadChanged: (isRead) => onReadChanged: (isRead) =>
onReadChanged?.call(reminder, isRead), onReadChanged?.call(reminder, isRead),
onDelete: () => onDelete?.call(reminder),
onAction: (path) => onAction?.call(reminder, path, view), onAction: (path) => onAction?.call(reminder, path, view),
view: view, view: view,
); );