mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2025-11-17 19:07:30 +00:00
fix: reminder improvements (#6680)
This commit is contained in:
parent
07e34609e7
commit
0ea2da424f
@ -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)),
|
||||||
);
|
);
|
||||||
|
|||||||
@ -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(
|
||||||
|
|||||||
@ -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';
|
||||||
|
|||||||
@ -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);
|
||||||
|
}
|
||||||
@ -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 ||
|
||||||
|
|||||||
@ -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)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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(),
|
||||||
|
|||||||
@ -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,
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -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,
|
||||||
);
|
);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user