Skip to content

Commit 4626c18

Browse files
authored
fix: revamp desktop notification center (#7607)
* fix: revamp desktop notification center * fix: complete the red dot * fix: remove context from showToastNotification * fix: date picker not updated after enable time * fix: path erro with ActionArgumentKeys.path
1 parent 5b2853c commit 4626c18

35 files changed

Lines changed: 1169 additions & 366 deletions

frontend/appflowy_flutter/lib/mobile/application/notification/notification_reminder_bloc.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ class NotificationReminderBloc
4343
createdAt: createdAt,
4444
pageTitle: '',
4545
reminderContent: '',
46+
isLocked: false,
4647
status: NotificationReminderStatus.error,
4748
),
4849
);
@@ -57,6 +58,7 @@ class NotificationReminderBloc
5758
NotificationReminderState(
5859
createdAt: createdAt,
5960
pageTitle: view.nameOrDefault,
61+
isLocked: view.isLocked,
6062
view: view,
6163
reminderContent: node.delta?.toPlainText() ?? '',
6264
nodes: [node],
@@ -70,6 +72,7 @@ class NotificationReminderBloc
7072
NotificationReminderState(
7173
createdAt: createdAt,
7274
pageTitle: view.nameOrDefault,
75+
isLocked: view.isLocked,
7376
view: view,
7477
reminderContent: reminder.message,
7578
status: NotificationReminderStatus.loaded,
@@ -203,6 +206,7 @@ class NotificationReminderState with _$NotificationReminderState {
203206
required String createdAt,
204207
required String pageTitle,
205208
required String reminderContent,
209+
required bool isLocked,
206210
@Default(NotificationReminderStatus.initial)
207211
NotificationReminderStatus status,
208212
@Default([]) List<Node> nodes,
@@ -215,5 +219,6 @@ class NotificationReminderState with _$NotificationReminderState {
215219
createdAt: '',
216220
pageTitle: '',
217221
reminderContent: '',
222+
isLocked: false,
218223
);
219224
}

frontend/appflowy_flutter/lib/mobile/presentation/notifications/mobile_notifications_screen.dart

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,14 @@ import 'package:appflowy/mobile/presentation/notifications/widgets/widgets.dart'
33
import 'package:appflowy/mobile/presentation/presentation.dart';
44
import 'package:appflowy/startup/startup.dart';
55
import 'package:appflowy/user/application/reminder/reminder_bloc.dart';
6+
import 'package:appflowy/workspace/presentation/notifications/widgets/notification_tab_bar.dart';
67
import 'package:appflowy_editor/appflowy_editor.dart';
78
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
89
import 'package:flutter/material.dart';
910
import 'package:flutter_bloc/flutter_bloc.dart';
1011

12+
import 'widgets/tab_bar.dart';
13+
1114
final PropertyValueNotifier<List<String>> mSelectedNotificationIds =
1215
PropertyValueNotifier([]);
1316

@@ -76,9 +79,9 @@ class _MobileNotificationsTabState extends State<MobileNotificationsTab>
7679
late TabController tabController;
7780

7881
final tabs = [
79-
MobileNotificationTabType.inbox,
80-
MobileNotificationTabType.unread,
81-
MobileNotificationTabType.archive,
82+
NotificationTabType.inbox,
83+
NotificationTabType.unread,
84+
NotificationTabType.archive,
8285
];
8386

8487
@override

frontend/appflowy_flutter/lib/mobile/presentation/notifications/widgets/empty.dart

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import 'package:appflowy/generated/flowy_svgs.g.dart';
22
import 'package:appflowy/generated/locale_keys.g.dart';
3-
import 'package:appflowy/mobile/presentation/notifications/widgets/widgets.dart';
3+
import 'package:appflowy/workspace/presentation/notifications/widgets/notification_tab_bar.dart';
44
import 'package:easy_localization/easy_localization.dart';
55
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
66
import 'package:flutter/material.dart';
@@ -11,24 +11,24 @@ class EmptyNotification extends StatelessWidget {
1111
required this.type,
1212
});
1313

14-
final MobileNotificationTabType type;
14+
final NotificationTabType type;
1515

1616
@override
1717
Widget build(BuildContext context) {
1818
final title = switch (type) {
19-
MobileNotificationTabType.inbox =>
19+
NotificationTabType.inbox =>
2020
LocaleKeys.settings_notifications_emptyInbox_title.tr(),
21-
MobileNotificationTabType.archive =>
21+
NotificationTabType.archive =>
2222
LocaleKeys.settings_notifications_emptyArchived_title.tr(),
23-
MobileNotificationTabType.unread =>
23+
NotificationTabType.unread =>
2424
LocaleKeys.settings_notifications_emptyUnread_title.tr(),
2525
};
2626
final desc = switch (type) {
27-
MobileNotificationTabType.inbox =>
27+
NotificationTabType.inbox =>
2828
LocaleKeys.settings_notifications_emptyInbox_description.tr(),
29-
MobileNotificationTabType.archive =>
29+
NotificationTabType.archive =>
3030
LocaleKeys.settings_notifications_emptyArchived_description.tr(),
31-
MobileNotificationTabType.unread =>
31+
NotificationTabType.unread =>
3232
LocaleKeys.settings_notifications_emptyUnread_description.tr(),
3333
};
3434
return Column(

frontend/appflowy_flutter/lib/mobile/presentation/notifications/widgets/notification_item.dart

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import 'package:appflowy/mobile/presentation/base/animated_gesture.dart';
44
import 'package:appflowy/mobile/presentation/notifications/widgets/widgets.dart';
55
import 'package:appflowy/user/application/reminder/reminder_bloc.dart';
66
import 'package:appflowy/workspace/application/settings/appearance/appearance_cubit.dart';
7+
import 'package:appflowy/workspace/presentation/notifications/widgets/notification_tab_bar.dart';
78
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
89
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
910
import 'package:flutter/foundation.dart';
@@ -18,7 +19,7 @@ class NotificationItem extends StatelessWidget {
1819
required this.reminder,
1920
});
2021

21-
final MobileNotificationTabType tabType;
22+
final NotificationTabType tabType;
2223
final ReminderPB reminder;
2324

2425
@override
@@ -93,7 +94,7 @@ class _InnerNotificationItem extends StatelessWidget {
9394
required this.tabType,
9495
});
9596

96-
final MobileNotificationTabType tabType;
97+
final NotificationTabType tabType;
9798
final ReminderPB reminder;
9899

99100
@override
@@ -121,22 +122,22 @@ class _SlidableNotificationItem extends StatelessWidget {
121122
required this.child,
122123
});
123124

124-
final MobileNotificationTabType tabType;
125+
final NotificationTabType tabType;
125126
final ReminderPB reminder;
126127
final Widget child;
127128

128129
@override
129130
Widget build(BuildContext context) {
130131
final List<NotificationPaneActionType> actions = switch (tabType) {
131-
MobileNotificationTabType.inbox => [
132+
NotificationTabType.inbox => [
132133
NotificationPaneActionType.more,
133134
if (!reminder.isRead) NotificationPaneActionType.markAsRead,
134135
],
135-
MobileNotificationTabType.unread => [
136+
NotificationTabType.unread => [
136137
NotificationPaneActionType.more,
137138
NotificationPaneActionType.markAsRead,
138139
],
139-
MobileNotificationTabType.archive => [
140+
NotificationTabType.archive => [
140141
if (kDebugMode) NotificationPaneActionType.unArchive,
141142
],
142143
};

frontend/appflowy_flutter/lib/mobile/presentation/notifications/widgets/shared.dart

Lines changed: 78 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,36 @@ class NotificationIcon extends StatelessWidget {
2828

2929
@override
3030
Widget build(BuildContext context) {
31-
return const FlowySvg(
32-
FlowySvgs.m_notification_reminder_s,
33-
size: Size.square(_kNotificationIconHeight),
34-
blendMode: null,
31+
return SizedBox(
32+
width: 42,
33+
height: 36,
34+
child: Stack(
35+
children: [
36+
const FlowySvg(
37+
FlowySvgs.m_notification_reminder_s,
38+
size: Size.square(32),
39+
blendMode: null,
40+
),
41+
Align(
42+
alignment: Alignment.bottomRight,
43+
child: Container(
44+
width: 20,
45+
height: 20,
46+
decoration: BoxDecoration(
47+
shape: BoxShape.circle,
48+
color: Theme.of(context).cardColor,
49+
),
50+
child: Center(
51+
child: FlowyText(
52+
'@',
53+
fontSize: 12,
54+
figmaLineHeight: 14,
55+
),
56+
),
57+
),
58+
),
59+
],
60+
),
3561
);
3662
}
3763
}
@@ -114,16 +140,10 @@ class _NotificationContentState extends State<NotificationContent> {
114140
crossAxisAlignment: CrossAxisAlignment.start,
115141
mainAxisSize: MainAxisSize.min,
116142
children: [
117-
// title
118-
_buildHeader(),
119-
120-
// time & page name
121-
_buildTimeAndPageName(
122-
context,
123-
state.createdAt,
124-
state.pageTitle,
125-
),
126-
143+
// title & time
144+
_buildHeader(state.createdAt, !widget.reminder.isRead),
145+
// page name
146+
_buildPageName(context, state.isLocked, state.pageTitle),
127147
// content
128148
Padding(
129149
padding: const EdgeInsets.only(right: 16.0),
@@ -162,40 +182,65 @@ class _NotificationContentState extends State<NotificationContent> {
162182
return const SizedBox.shrink();
163183
}
164184

165-
Widget _buildHeader() {
166-
return FlowyText.semibold(
167-
LocaleKeys.settings_notifications_titles_reminder.tr(),
168-
fontSize: 14,
169-
figmaLineHeight: 20,
185+
Widget _buildHeader(String createAt, bool unread) {
186+
return SizedBox(
187+
height: 22,
188+
child: Row(
189+
children: [
190+
FlowyText.semibold(
191+
LocaleKeys.settings_notifications_titles_reminder.tr(),
192+
fontSize: 14,
193+
figmaLineHeight: 20,
194+
),
195+
Spacer(),
196+
if (createAt.isNotEmpty)
197+
FlowyText.regular(
198+
createAt,
199+
fontSize: 12,
200+
figmaLineHeight: 18,
201+
color: context.notificationItemTextColor,
202+
),
203+
if (unread) ...[
204+
HSpace(4),
205+
const UnreadRedDot(),
206+
],
207+
],
208+
),
170209
);
171210
}
172211

173-
Widget _buildTimeAndPageName(
212+
Widget _buildPageName(
174213
BuildContext context,
175-
String createdAt,
214+
bool isLocked,
176215
String pageTitle,
177216
) {
178217
return Opacity(
179218
opacity: 0.5,
180-
child: Row(
181-
children: [
182-
// the legacy reminder doesn't contain the timestamp, so we don't show it
183-
if (createdAt.isNotEmpty) ...[
219+
child: SizedBox(
220+
height: 18,
221+
child: Row(
222+
children: [
223+
/// TODO: need to be replaced after reminder support more types
184224
FlowyText.regular(
185-
createdAt,
225+
LocaleKeys.notificationHub_mentionedYou.tr(),
186226
fontSize: 12,
187227
figmaLineHeight: 18,
188228
color: context.notificationItemTextColor,
189229
),
190230
const NotificationEllipse(),
231+
if (isLocked)
232+
Padding(
233+
padding: EdgeInsets.only(right: 5),
234+
child: FlowySvg(FlowySvgs.notification_lock_s),
235+
),
236+
FlowyText.regular(
237+
pageTitle,
238+
fontSize: 12,
239+
figmaLineHeight: 18,
240+
color: context.notificationItemTextColor,
241+
),
191242
],
192-
FlowyText.regular(
193-
pageTitle,
194-
fontSize: 12,
195-
figmaLineHeight: 18,
196-
color: context.notificationItemTextColor,
197-
),
198-
],
243+
),
199244
),
200245
);
201246
}

frontend/appflowy_flutter/lib/mobile/presentation/notifications/widgets/slide_actions.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@ import 'package:appflowy/generated/flowy_svgs.g.dart';
22
import 'package:appflowy/generated/locale_keys.g.dart';
33
import 'package:appflowy/mobile/application/notification/notification_reminder_bloc.dart';
44
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart';
5-
import 'package:appflowy/mobile/presentation/notifications/widgets/widgets.dart';
65
import 'package:appflowy/mobile/presentation/page_item/mobile_slide_action_button.dart';
76
import 'package:appflowy/mobile/presentation/presentation.dart';
87
import 'package:appflowy/mobile/presentation/widgets/widgets.dart';
98
import 'package:appflowy/user/application/reminder/reminder_bloc.dart';
109
import 'package:appflowy/user/application/reminder/reminder_extension.dart';
10+
import 'package:appflowy/workspace/presentation/notifications/widgets/notification_tab_bar.dart';
1111
import 'package:appflowy/workspace/presentation/widgets/dialogs.dart';
1212
import 'package:easy_localization/easy_localization.dart';
1313
import 'package:flutter/material.dart';
@@ -21,7 +21,7 @@ enum NotificationPaneActionType {
2121

2222
MobileSlideActionButton actionButton(
2323
BuildContext context, {
24-
required MobileNotificationTabType tabType,
24+
required NotificationTabType tabType,
2525
}) {
2626
switch (this) {
2727
case NotificationPaneActionType.markAsRead:

frontend/appflowy_flutter/lib/mobile/presentation/notifications/widgets/tab.dart

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import 'package:appflowy/mobile/presentation/notifications/widgets/widgets.dart'
33
import 'package:appflowy/shared/list_extension.dart';
44
import 'package:appflowy/user/application/reminder/reminder_bloc.dart';
55
import 'package:appflowy/user/application/reminder/reminder_extension.dart';
6+
import 'package:appflowy/workspace/presentation/notifications/widgets/notification_tab_bar.dart';
67
import 'package:appflowy/workspace/presentation/widgets/dialogs.dart';
78
import 'package:appflowy_backend/appflowy_backend.dart';
89
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
@@ -17,7 +18,7 @@ class NotificationTab extends StatefulWidget {
1718
required this.tabType,
1819
});
1920

20-
final MobileNotificationTabType tabType;
21+
final NotificationTabType tabType;
2122

2223
@override
2324
State<NotificationTab> createState() => _NotificationTabState();
@@ -81,17 +82,17 @@ class _NotificationTabState extends State<NotificationTab>
8182

8283
List<ReminderPB> _filterReminders(List<ReminderPB> reminders) {
8384
switch (widget.tabType) {
84-
case MobileNotificationTabType.inbox:
85+
case NotificationTabType.inbox:
8586
return reminders.reversed
8687
.where((reminder) => !reminder.isArchived)
8788
.toList()
8889
.unique((reminder) => reminder.id);
89-
case MobileNotificationTabType.archive:
90+
case NotificationTabType.archive:
9091
return reminders.reversed
9192
.where((reminder) => reminder.isArchived)
9293
.toList()
9394
.unique((reminder) => reminder.id);
94-
case MobileNotificationTabType.unread:
95+
case NotificationTabType.unread:
9596
return reminders.reversed
9697
.where((reminder) => !reminder.isRead)
9798
.toList()

0 commit comments

Comments
 (0)