chore: add more logs in reminder bloc (#5860)

* chore: add more logs in reminder bloc

* Revert "chore: add more logs in reminder bloc"

This reverts commit 9d0bb8fb29.

* chore: add more logs in reminder bloc

* fix: unable to view reminders on Desktop

* fix: force refresh reminders

* chore: fix flutter analyze

* feat: support database reminder on Mobile

* chore: remove referenced database padding
This commit is contained in:
Lucas.Xu
2024-08-08 13:35:22 +08:00
committed by GitHub
parent a523b8ff90
commit 7769034467
17 changed files with 216 additions and 104 deletions

View File

@ -5,6 +5,7 @@ import 'package:appflowy/user/application/reminder/reminder_extension.dart';
import 'package:appflowy/workspace/application/settings/date_time/date_format_ext.dart'; import 'package:appflowy/workspace/application/settings/date_time/date_format_ext.dart';
import 'package:appflowy/workspace/application/settings/date_time/time_format_ext.dart'; import 'package:appflowy/workspace/application/settings/date_time/time_format_ext.dart';
import 'package:appflowy/workspace/application/view/prelude.dart'; import 'package:appflowy/workspace/application/view/prelude.dart';
import 'package:appflowy/workspace/application/view/view_ext.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart'; import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
import 'package:appflowy_editor/appflowy_editor.dart'; import 'package:appflowy_editor/appflowy_editor.dart';
@ -23,16 +24,20 @@ class NotificationReminderBloc
await event.when( await event.when(
initial: (reminder, dateFormat, timeFormat) async { initial: (reminder, dateFormat, timeFormat) async {
this.reminder = reminder; this.reminder = reminder;
this.dateFormat = dateFormat;
this.timeFormat = timeFormat;
add(const NotificationReminderEvent.reset());
},
reset: () async {
final createdAt = await _getCreatedAt( final createdAt = await _getCreatedAt(
reminder, reminder,
dateFormat, dateFormat,
timeFormat, timeFormat,
); );
final view = await _getView(reminder); final view = await _getView(reminder);
final node = await _getContent(reminder);
if (view == null || node == null) { if (view == null) {
emit( emit(
NotificationReminderState( NotificationReminderState(
createdAt: createdAt, createdAt: createdAt,
@ -41,7 +46,13 @@ class NotificationReminderBloc
status: NotificationReminderStatus.error, status: NotificationReminderStatus.error,
), ),
); );
} else { }
final layout = view!.layout;
if (layout.isDocumentView) {
final node = await _getContent(reminder);
if (node != null) {
emit( emit(
NotificationReminderState( NotificationReminderState(
createdAt: createdAt, createdAt: createdAt,
@ -53,13 +64,25 @@ class NotificationReminderBloc
), ),
); );
} }
} else if (layout.isDatabaseView) {
emit(
NotificationReminderState(
createdAt: createdAt,
pageTitle: view.name,
view: view,
reminderContent: reminder.message,
status: NotificationReminderStatus.loaded,
),
);
}
}, },
reset: () {},
); );
}); });
} }
late final ReminderPB reminder; late final ReminderPB reminder;
late final UserDateFormatPB dateFormat;
late final UserTimeFormatPB timeFormat;
Future<String> _getCreatedAt( Future<String> _getCreatedAt(
ReminderPB reminder, ReminderPB reminder,

View File

@ -46,10 +46,18 @@ class _MobileViewPageState extends State<MobileViewPage> {
// control the app bar opacity when in immersive mode // control the app bar opacity when in immersive mode
final ValueNotifier<double> _appBarOpacity = ValueNotifier(1.0); final ValueNotifier<double> _appBarOpacity = ValueNotifier(1.0);
@override
void initState() {
super.initState();
getIt<ReminderBloc>().add(const ReminderEvent.started());
}
@override @override
void dispose() { void dispose() {
_appBarOpacity.dispose(); _appBarOpacity.dispose();
_scrollNotificationObserver = null; _scrollNotificationObserver = null;
super.dispose(); super.dispose();
} }
@ -78,8 +86,7 @@ class _MobileViewPageState extends State<MobileViewPage> {
ViewBloc(view: view)..add(const ViewEvent.initial()), ViewBloc(view: view)..add(const ViewEvent.initial()),
), ),
BlocProvider.value( BlocProvider.value(
value: getIt<ReminderBloc>() value: getIt<ReminderBloc>(),
..add(const ReminderEvent.started()),
), ),
if (view.layout.isDocumentView) if (view.layout.isDocumentView)
BlocProvider( BlocProvider(

View File

@ -99,6 +99,7 @@ class _MobileHomePageState extends State<MobileHomePage> {
super.initState(); super.initState();
getIt<MenuSharedState>().addLatestViewListener(_onLatestViewChange); getIt<MenuSharedState>().addLatestViewListener(_onLatestViewChange);
getIt<ReminderBloc>().add(const ReminderEvent.started());
} }
@override @override

View File

@ -6,6 +6,8 @@ import 'package:appflowy/mobile/presentation/notifications/widgets/color.dart';
import 'package:appflowy/plugins/document/presentation/editor_configuration.dart'; import 'package:appflowy/plugins/document/presentation/editor_configuration.dart';
import 'package:appflowy/plugins/document/presentation/editor_style.dart'; import 'package:appflowy/plugins/document/presentation/editor_style.dart';
import 'package:appflowy/user/application/reminder/reminder_extension.dart'; import 'package:appflowy/user/application/reminder/reminder_extension.dart';
import 'package:appflowy/workspace/application/view/view_ext.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart'; import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
import 'package:appflowy_editor/appflowy_editor.dart'; import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
@ -76,7 +78,7 @@ class UnreadRedDot extends StatelessWidget {
} }
} }
class NotificationContent extends StatelessWidget { class NotificationContent extends StatefulWidget {
const NotificationContent({ const NotificationContent({
super.key, super.key,
required this.reminder, required this.reminder,
@ -84,10 +86,29 @@ class NotificationContent extends StatelessWidget {
final ReminderPB reminder; final ReminderPB reminder;
@override
State<NotificationContent> createState() => _NotificationContentState();
}
class _NotificationContentState extends State<NotificationContent> {
@override
void didUpdateWidget(covariant NotificationContent oldWidget) {
super.didUpdateWidget(oldWidget);
context.read<NotificationReminderBloc>().add(
const NotificationReminderEvent.reset(),
);
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocBuilder<NotificationReminderBloc, NotificationReminderState>( return BlocBuilder<NotificationReminderBloc, NotificationReminderState>(
builder: (context, state) { builder: (context, state) {
final view = state.view;
if (view == null) {
return const SizedBox.shrink();
}
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
@ -105,15 +126,7 @@ class NotificationContent extends StatelessWidget {
// content // content
Padding( Padding(
padding: const EdgeInsets.only(right: 16.0), padding: const EdgeInsets.only(right: 16.0),
child: IntrinsicHeight( child: _buildContent(view, nodes: state.nodes),
child: BlocProvider(
create: (context) => DocumentPageStyleBloc(view: state.view!),
child: NotificationDocumentContent(
reminder: reminder,
nodes: state.nodes,
),
),
),
), ),
], ],
); );
@ -121,6 +134,33 @@ class NotificationContent extends StatelessWidget {
); );
} }
Widget _buildContent(ViewPB view, {List<Node>? nodes}) {
if (view.layout.isDocumentView && nodes != null) {
return IntrinsicHeight(
child: BlocProvider(
create: (context) => DocumentPageStyleBloc(view: view),
child: NotificationDocumentContent(
reminder: widget.reminder,
nodes: nodes,
),
),
);
} else if (view.layout.isDatabaseView) {
final opacity = widget.reminder.type == ReminderType.past ? 0.3 : 1.0;
return Opacity(
opacity: opacity,
child: FlowyText(
widget.reminder.message,
fontSize: 14,
figmaLineHeight: 22,
color: context.notificationItemTextColor,
),
);
}
return const SizedBox.shrink();
}
Widget _buildHeader() { Widget _buildHeader() {
return FlowyText.semibold( return FlowyText.semibold(
LocaleKeys.settings_notifications_titles_reminder.tr(), LocaleKeys.settings_notifications_titles_reminder.tr(),

View File

@ -8,6 +8,7 @@ import 'package:appflowy/plugins/database/application/row/row_cache.dart';
import 'package:appflowy/plugins/database/application/row/row_controller.dart'; import 'package:appflowy/plugins/database/application/row/row_controller.dart';
import 'package:appflowy/plugins/database/board/application/board_bloc.dart'; import 'package:appflowy/plugins/database/board/application/board_bloc.dart';
import 'package:appflowy/plugins/database/grid/presentation/layout/sizes.dart'; import 'package:appflowy/plugins/database/grid/presentation/layout/sizes.dart';
import 'package:appflowy/plugins/database/tab_bar/tab_bar_view.dart';
import 'package:appflowy/plugins/database/widgets/cell/card_cell_builder.dart'; import 'package:appflowy/plugins/database/widgets/cell/card_cell_builder.dart';
import 'package:appflowy/plugins/database/widgets/cell/card_cell_skeleton/text_card_cell.dart'; import 'package:appflowy/plugins/database/widgets/cell/card_cell_skeleton/text_card_cell.dart';
import 'package:appflowy/plugins/database/widgets/row/row_detail.dart'; import 'package:appflowy/plugins/database/widgets/row/row_detail.dart';
@ -64,7 +65,10 @@ class HiddenGroupsColumn extends StatelessWidget {
height: 50, height: 50,
child: Padding( child: Padding(
padding: EdgeInsets.only( padding: EdgeInsets.only(
left: 80 + margin.left, left: margin.left +
context
.read<DatabasePluginWidgetBuilderSize>()
.horizontalPadding,
right: margin.right + 4, right: margin.right + 4,
), ),
child: Row( child: Row(

View File

@ -1,5 +1,3 @@
import 'package:flutter/material.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart'; import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart'; import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart';
@ -20,12 +18,12 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/size.dart'; import 'package:flowy_infra/size.dart';
import 'package:flowy_infra/theme_extension.dart'; import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import '../../application/row/row_controller.dart'; import '../../application/row/row_controller.dart';
import '../../widgets/row/row_detail.dart'; import '../../widgets/row/row_detail.dart';
import 'calendar_day.dart'; import 'calendar_day.dart';
import 'layout/sizes.dart'; import 'layout/sizes.dart';
import 'toolbar/calendar_setting_bar.dart'; import 'toolbar/calendar_setting_bar.dart';
@ -185,11 +183,17 @@ class _CalendarPageState extends State<CalendarPage> {
return LayoutBuilder( return LayoutBuilder(
// must specify MonthView width for useAvailableVerticalSpace to work properly // must specify MonthView width for useAvailableVerticalSpace to work properly
builder: (context, constraints) { builder: (context, constraints) {
return Padding( EdgeInsets padding = PlatformExtension.isMobile
padding: PlatformExtension.isMobile
? CalendarSize.contentInsetsMobile ? CalendarSize.contentInsetsMobile
: CalendarSize.contentInsets + : CalendarSize.contentInsets +
const EdgeInsets.symmetric(horizontal: 40), const EdgeInsets.symmetric(horizontal: 40);
final double horizontalPadding =
context.read<DatabasePluginWidgetBuilderSize>().horizontalPadding;
if (horizontalPadding == 0) {
padding = padding.copyWith(left: 0, right: 0);
}
return Padding(
padding: padding,
child: ScrollConfiguration( child: ScrollConfiguration(
behavior: behavior:
ScrollConfiguration.of(context).copyWith(scrollbars: false), ScrollConfiguration.of(context).copyWith(scrollbars: false),

View File

@ -1,9 +1,8 @@
import 'package:flutter/material.dart';
import 'package:appflowy/plugins/database/grid/application/calculations/calculations_bloc.dart'; import 'package:appflowy/plugins/database/grid/application/calculations/calculations_bloc.dart';
import 'package:appflowy/plugins/database/grid/application/grid_bloc.dart'; import 'package:appflowy/plugins/database/grid/application/grid_bloc.dart';
import 'package:appflowy/plugins/database/grid/presentation/layout/sizes.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/calculations/calculate_cell.dart'; import 'package:appflowy/plugins/database/grid/presentation/widgets/calculations/calculate_cell.dart';
import 'package:appflowy/plugins/database/tab_bar/tab_bar_view.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
class GridCalculationsRow extends StatelessWidget { class GridCalculationsRow extends StatelessWidget {
@ -27,9 +26,12 @@ class GridCalculationsRow extends StatelessWidget {
)..add(const CalculationsEvent.started()), )..add(const CalculationsEvent.started()),
child: BlocBuilder<CalculationsBloc, CalculationsState>( child: BlocBuilder<CalculationsBloc, CalculationsState>(
builder: (context, state) { builder: (context, state) {
final padding =
context.read<DatabasePluginWidgetBuilderSize>().horizontalPadding;
return Padding( return Padding(
padding: padding: includeDefaultInsets
includeDefaultInsets ? GridSize.contentInsets : EdgeInsets.zero, ? EdgeInsets.symmetric(horizontal: padding)
: EdgeInsets.zero,
child: Row( child: Row(
children: [ children: [
...state.fields.map( ...state.fields.map(

View File

@ -1,13 +1,13 @@
import 'package:flutter/material.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart'; import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/database/grid/application/grid_bloc.dart'; import 'package:appflowy/plugins/database/grid/application/grid_bloc.dart';
import 'package:appflowy/plugins/database/grid/presentation/layout/sizes.dart'; import 'package:appflowy/plugins/database/grid/presentation/layout/sizes.dart';
import 'package:appflowy/plugins/database/tab_bar/tab_bar_view.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/theme_extension.dart'; import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra_ui/style_widget/button.dart'; import 'package:flowy_infra_ui/style_widget/button.dart';
import 'package:flowy_infra_ui/style_widget/text.dart'; import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
class GridAddRowButton extends StatelessWidget { class GridAddRowButton extends StatelessWidget {
@ -41,8 +41,11 @@ class GridRowBottomBar extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final padding =
context.read<DatabasePluginWidgetBuilderSize>().horizontalPadding;
return Container( return Container(
padding: GridSize.footerContentInsets + const EdgeInsets.only(left: 40), padding: GridSize.footerContentInsets.copyWith(left: 0) +
EdgeInsets.only(left: padding),
height: GridSize.footerHeight, height: GridSize.footerHeight,
child: const GridAddRowButton(), child: const GridAddRowButton(),
); );

View File

@ -98,7 +98,7 @@ class _RowLeadingState extends State<_RowLeading> {
return AppFlowyPopover( return AppFlowyPopover(
controller: popoverController, controller: popoverController,
triggerActions: PopoverTriggerFlags.none, triggerActions: PopoverTriggerFlags.none,
constraints: BoxConstraints.loose(const Size(176, 200)), constraints: BoxConstraints.loose(const Size(200, 200)),
direction: PopoverDirection.rightWithCenterAligned, direction: PopoverDirection.rightWithCenterAligned,
margin: const EdgeInsets.symmetric(horizontal: 6, vertical: 8), margin: const EdgeInsets.symmetric(horizontal: 6, vertical: 8),
popupBuilder: (_) { popupBuilder: (_) {

View File

@ -56,7 +56,8 @@ class _DatabaseViewWidgetState extends State<DatabaseViewWidget> {
shrinkWrap: widget.shrinkWrap, shrinkWrap: widget.shrinkWrap,
context: PluginContext(), context: PluginContext(),
data: { data: {
kDatabasePluginWidgetBuilderHorizontalPadding: 40.0, kDatabasePluginWidgetBuilderHorizontalPadding:
view.layout == ViewLayoutPB.Grid ? 40.0 : 0.0,
}, },
), ),
); );

View File

@ -1,5 +1,4 @@
import 'package:appflowy/workspace/application/settings/appearance/base_appearance.dart'; import 'package:appflowy/workspace/application/settings/appearance/base_appearance.dart';
import 'package:appflowy_backend/log.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
@ -38,11 +37,7 @@ TextStyle getGoogleFontSafely(
letterSpacing: letterSpacing, letterSpacing: letterSpacing,
height: lineHeight, height: lineHeight,
); );
} catch (e) { } catch (_) {}
Log.error(
'Font family $fontFamily is not available, using default font family instead',
);
}
} }
return TextStyle( return TextStyle(

View File

@ -24,6 +24,8 @@ part 'reminder_bloc.freezed.dart';
class ReminderBloc extends Bloc<ReminderEvent, ReminderState> { class ReminderBloc extends Bloc<ReminderEvent, ReminderState> {
ReminderBloc() : super(ReminderState()) { ReminderBloc() : super(ReminderState()) {
Log.info('ReminderBloc created');
_actionBloc = getIt<ActionNavigationBloc>(); _actionBloc = getIt<ActionNavigationBloc>();
_reminderService = const ReminderService(); _reminderService = const ReminderService();
timer = _periodicCheck(); timer = _periodicCheck();
@ -40,36 +42,58 @@ class ReminderBloc extends Bloc<ReminderEvent, ReminderState> {
(event, emit) async { (event, emit) async {
await event.when( await event.when(
started: () async { started: () async {
final remindersOrFailure = await _reminderService.fetchReminders(); Log.info('Start fetching reminders');
remindersOrFailure.fold( final result = await _reminderService.fetchReminders();
(reminders) => emit(state.copyWith(reminders: reminders)),
(error) => Log.error(error), result.fold(
(reminders) {
Log.info('Fetched reminders on startup: ${reminders.length}');
emit(state.copyWith(reminders: reminders));
},
(error) => Log.error('Failed to fetch reminders: $error'),
); );
}, },
remove: (reminderId) async { remove: (reminderId) async {
final unitOrFailure = final result = await _reminderService.removeReminder(
await _reminderService.removeReminder(reminderId: reminderId); reminderId: reminderId,
);
unitOrFailure.fold( result.fold(
(_) { (_) {
Log.info('Removed reminder: $reminderId');
final reminders = [...state.reminders]; final reminders = [...state.reminders];
reminders.removeWhere((e) => e.id == reminderId); reminders.removeWhere((e) => e.id == reminderId);
emit(state.copyWith(reminders: reminders)); emit(state.copyWith(reminders: reminders));
}, },
(error) => Log.error(error), (error) => Log.error(
'Failed to remove reminder($reminderId): $error',
),
); );
}, },
add: (reminder) async { add: (reminder) async {
final unitOrFailure = // check the timestamp in the reminder
await _reminderService.addReminder(reminder: reminder); if (reminder.createdAt == null) {
reminder.freeze();
reminder = reminder.rebuild((update) {
update.meta[ReminderMetaKeys.createdAt] =
DateTime.now().millisecondsSinceEpoch.toString();
});
}
return unitOrFailure.fold( final result = await _reminderService.addReminder(
reminder: reminder,
);
return result.fold(
(_) { (_) {
Log.info('Added reminder: ${reminder.id}');
Log.info('Before adding reminder: ${state.reminders.length}');
final reminders = [...state.reminders, reminder]; final reminders = [...state.reminders, reminder];
Log.info('After adding reminder: ${reminders.length}');
emit(state.copyWith(reminders: reminders)); emit(state.copyWith(reminders: reminders));
}, },
(error) => Log.error(error), (error) => Log.error('Failed to add reminder: $error'),
); );
}, },
addById: (reminderId, objectId, scheduledAt, meta) async => add( addById: (reminderId, objectId, scheduledAt, meta) async => add(
@ -86,8 +110,9 @@ class ReminderBloc extends Bloc<ReminderEvent, ReminderState> {
), ),
), ),
update: (updateObject) async { update: (updateObject) async {
final reminder = state.reminders final reminder = state.reminders.firstWhereOrNull(
.firstWhereOrNull((r) => r.id == updateObject.id); (r) => r.id == updateObject.id,
);
if (reminder == null) { if (reminder == null) {
return; return;
@ -98,15 +123,20 @@ class ReminderBloc extends Bloc<ReminderEvent, ReminderState> {
reminder: newReminder, reminder: newReminder,
); );
Log.info('Updating reminder: ${reminder.id}');
failureOrUnit.fold( failureOrUnit.fold(
(_) { (_) {
Log.info('Updated reminder: ${reminder.id}');
final index = final index =
state.reminders.indexWhere((r) => r.id == reminder.id); state.reminders.indexWhere((r) => r.id == reminder.id);
final reminders = [...state.reminders]; final reminders = [...state.reminders];
reminders.replaceRange(index, index + 1, [newReminder]); reminders.replaceRange(index, index + 1, [newReminder]);
emit(state.copyWith(reminders: reminders)); emit(state.copyWith(reminders: reminders));
}, },
(error) => Log.error(error), (error) => Log.error(
'Failed to update reminder(${reminder.id}): $error',
),
); );
}, },
pressReminder: (reminderId, path, view) { pressReminder: (reminderId, path, view) {
@ -157,6 +187,9 @@ class ReminderBloc extends Bloc<ReminderEvent, ReminderState> {
}, },
markAsRead: (reminderIds) async { markAsRead: (reminderIds) async {
final reminders = await _onMarkAsRead(reminderIds: reminderIds); final reminders = await _onMarkAsRead(reminderIds: reminderIds);
Log.info('Marked reminders as read: $reminderIds');
emit( emit(
state.copyWith( state.copyWith(
reminders: reminders, reminders: reminders,
@ -168,6 +201,9 @@ class ReminderBloc extends Bloc<ReminderEvent, ReminderState> {
isArchived: true, isArchived: true,
reminderIds: reminderIds, reminderIds: reminderIds,
); );
Log.info('Archived reminders: $reminderIds');
emit( emit(
state.copyWith( state.copyWith(
reminders: reminders, reminders: reminders,
@ -176,6 +212,9 @@ class ReminderBloc extends Bloc<ReminderEvent, ReminderState> {
}, },
markAllRead: () async { markAllRead: () async {
final reminders = await _onMarkAsRead(); final reminders = await _onMarkAsRead();
Log.info('Marked all reminders as read');
emit( emit(
state.copyWith( state.copyWith(
reminders: reminders, reminders: reminders,
@ -184,6 +223,9 @@ class ReminderBloc extends Bloc<ReminderEvent, ReminderState> {
}, },
archiveAll: () async { archiveAll: () async {
final reminders = await _onArchived(isArchived: true); final reminders = await _onArchived(isArchived: true);
Log.info('Archived all reminders');
emit( emit(
state.copyWith( state.copyWith(
reminders: reminders, reminders: reminders,
@ -199,11 +241,14 @@ class ReminderBloc extends Bloc<ReminderEvent, ReminderState> {
); );
}, },
refresh: () async { refresh: () async {
final remindersOrFailure = await _reminderService.fetchReminders(); final result = await _reminderService.fetchReminders();
remindersOrFailure.fold( result.fold(
(reminders) => emit(state.copyWith(reminders: reminders)), (reminders) {
(error) => emit(state), Log.info('Fetched reminders on refresh: ${reminders.length}');
emit(state.copyWith(reminders: reminders));
},
(error) => Log.error('Failed to fetch reminders: $error'),
); );
}, },
); );

View File

@ -71,8 +71,7 @@ class DesktopHomeScreen extends StatelessWidget {
key: ValueKey(userProfile.id), key: ValueKey(userProfile.id),
providers: [ providers: [
BlocProvider.value( BlocProvider.value(
value: getIt<ReminderBloc>() value: getIt<ReminderBloc>(),
..add(const ReminderEvent.started()),
), ),
BlocProvider<TabsBloc>.value(value: getIt<TabsBloc>()), BlocProvider<TabsBloc>.value(value: getIt<TabsBloc>()),
BlocProvider<HomeBloc>( BlocProvider<HomeBloc>(

View File

@ -1,5 +1,3 @@
import 'package:flutter/material.dart';
import 'package:appflowy/startup/startup.dart'; import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/user/application/notification_filter/notification_filter_bloc.dart'; import 'package:appflowy/user/application/notification_filter/notification_filter_bloc.dart';
import 'package:appflowy/user/application/reminder/reminder_bloc.dart'; import 'package:appflowy/user/application/reminder/reminder_bloc.dart';
@ -11,6 +9,7 @@ import 'package:appflowy/workspace/presentation/notifications/widgets/notificati
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-user/reminder.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-user/reminder.pb.dart';
import 'package:appflowy_popover/appflowy_popover.dart'; import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
class NotificationDialog extends StatefulWidget { class NotificationDialog extends StatefulWidget {
@ -64,12 +63,10 @@ class _NotificationDialogState extends State<NotificationDialog>
builder: (context, filterState) => builder: (context, filterState) =>
BlocBuilder<ReminderBloc, ReminderState>( BlocBuilder<ReminderBloc, ReminderState>(
builder: (context, state) { builder: (context, state) {
final List<ReminderPB> pastReminders = state.pastReminders final reminders = state.reminders.sortByScheduledAt();
.where((r) => filterState.showUnreadsOnly ? !r.isRead : true) final upcomingReminders =
.sortByScheduledAt();
final List<ReminderPB> upcomingReminders =
state.upcomingReminders.sortByScheduledAt(); state.upcomingReminders.sortByScheduledAt();
final hasUnreads = reminders.any((r) => !r.isRead);
return Column( return Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
@ -82,14 +79,14 @@ class _NotificationDialogState extends State<NotificationDialog>
controller: _controller, controller: _controller,
children: [ children: [
NotificationsView( NotificationsView(
shownReminders: pastReminders, shownReminders: reminders,
reminderBloc: _reminderBloc, reminderBloc: _reminderBloc,
views: widget.views, views: widget.views,
onDelete: _onDelete, onDelete: _onDelete,
onAction: _onAction, onAction: _onAction,
onReadChanged: _onReadChanged, onReadChanged: _onReadChanged,
actionBar: InboxActionBar( actionBar: InboxActionBar(
hasUnreads: state.hasUnreads, hasUnreads: hasUnreads,
showUnreadsOnly: filterState.showUnreadsOnly, showUnreadsOnly: filterState.showUnreadsOnly,
), ),
), ),

View File

@ -1,5 +1,3 @@
import 'package:flutter/material.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart'; import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/startup/startup.dart'; import 'package:appflowy/startup/startup.dart';
@ -11,6 +9,7 @@ import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/theme_extension.dart'; import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
class NotificationButton extends StatefulWidget { class NotificationButton extends StatefulWidget {
@ -23,6 +22,12 @@ class NotificationButton extends StatefulWidget {
class _NotificationButtonState extends State<NotificationButton> { class _NotificationButtonState extends State<NotificationButton> {
final mutex = PopoverMutex(); final mutex = PopoverMutex();
@override
void initState() {
super.initState();
getIt<ReminderBloc>().add(const ReminderEvent.started());
}
@override @override
void dispose() { void dispose() {
mutex.dispose(); mutex.dispose();
@ -56,8 +61,10 @@ class _NotificationButtonState extends State<NotificationButton> {
child: FlowyButton( child: FlowyButton(
useIntrinsicWidth: true, useIntrinsicWidth: true,
margin: EdgeInsets.zero, margin: EdgeInsets.zero,
text: text: _buildNotificationIcon(
_buildNotificationIcon(context, state.hasUnreads), context,
state.hasUnreads,
),
), ),
), ),
), ),

View File

@ -1,10 +1,10 @@
import 'package:appflowy/generated/flowy_svgs.g.dart'; import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/document/presentation/editor_configuration.dart'; import 'package:appflowy/mobile/presentation/notifications/widgets/widgets.dart';
import 'package:appflowy/plugins/document/presentation/editor_style.dart';
import 'package:appflowy/workspace/application/settings/appearance/appearance_cubit.dart'; import 'package:appflowy/workspace/application/settings/appearance/appearance_cubit.dart';
import 'package:appflowy/workspace/application/settings/date_time/date_format_ext.dart'; import 'package:appflowy/workspace/application/settings/date_time/date_format_ext.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
import 'package:appflowy_editor/appflowy_editor.dart'; import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:appflowy_popover/appflowy_popover.dart'; import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
@ -18,7 +18,7 @@ import 'package:provider/provider.dart';
class NotificationItem extends StatefulWidget { class NotificationItem extends StatefulWidget {
const NotificationItem({ const NotificationItem({
super.key, super.key,
required this.reminderId, required this.reminder,
required this.title, required this.title,
required this.scheduled, required this.scheduled,
required this.body, required this.body,
@ -32,7 +32,7 @@ class NotificationItem extends StatefulWidget {
this.view, this.view,
}); });
final String reminderId; final ReminderPB reminder;
final String title; final String title;
final Int64 scheduled; final Int64 scheduled;
final String body; final String body;
@ -169,6 +169,7 @@ class _NotificationItemState extends State<NotificationItem> {
), ),
child: _NotificationContent( child: _NotificationContent(
block: widget.block, block: widget.block,
reminder: widget.reminder,
body: widget.body, body: widget.body,
), ),
), ),
@ -214,10 +215,12 @@ class _NotificationItemState extends State<NotificationItem> {
class _NotificationContent extends StatelessWidget { class _NotificationContent extends StatelessWidget {
const _NotificationContent({ const _NotificationContent({
required this.body, required this.body,
required this.reminder,
required this.block, required this.block,
}); });
final String body; final String body;
final ReminderPB reminder;
final Future<Node?>? block; final Future<Node?>? block;
@override @override
@ -229,29 +232,10 @@ class _NotificationContent extends StatelessWidget {
return FlowyText.regular(body, maxLines: 4); return FlowyText.regular(body, maxLines: 4);
} }
final editorState = EditorState( return IntrinsicHeight(
document: Document(root: snapshot.data!), child: NotificationDocumentContent(
); nodes: [snapshot.data!],
reminder: reminder,
final styleCustomizer = EditorStyleCustomizer(
context: context,
padding: EdgeInsets.zero,
);
return Transform.scale(
scale: .9,
alignment: Alignment.centerLeft,
child: AppFlowyEditor(
editorState: editorState,
editorStyle: styleCustomizer.style(),
editable: false,
shrinkWrap: true,
blockComponentBuilders: getEditorBuilderMap(
context: context,
editorState: editorState,
styleCustomizer: styleCustomizer,
editable: false,
),
), ),
); );
}, },

View File

@ -76,7 +76,7 @@ class NotificationsView extends StatelessWidget {
final view = views.findView(reminder.objectId); final view = views.findView(reminder.objectId);
return NotificationItem( return NotificationItem(
reminderId: reminder.id, reminder: reminder,
key: ValueKey(reminder.id), key: ValueKey(reminder.id),
title: reminder.title, title: reminder.title,
scheduled: reminder.scheduledAt, scheduled: reminder.scheduledAt,