feat: improve reminder color in notification page (#5855)

* feat: improve reminder color

* fix: notification page doesn't update when switching workspace
This commit is contained in:
Lucas.Xu 2024-08-01 20:21:25 +08:00 committed by GitHub
parent 9fbba5fb60
commit b9fd3701cd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 121 additions and 39 deletions

View File

@ -1,7 +1,5 @@
import 'dart:io'; import 'dart:io';
import 'package:flutter/material.dart';
import 'package:appflowy/mobile/presentation/home/mobile_home_page_header.dart'; import 'package:appflowy/mobile/presentation/home/mobile_home_page_header.dart';
import 'package:appflowy/mobile/presentation/home/tab/mobile_space_tab.dart'; import 'package:appflowy/mobile/presentation/home/tab/mobile_space_tab.dart';
import 'package:appflowy/mobile/presentation/home/tab/space_order_bloc.dart'; import 'package:appflowy/mobile/presentation/home/tab/space_order_bloc.dart';
@ -18,6 +16,8 @@ import 'package:appflowy_backend/dispatch/dispatch.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-folder/workspace.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-folder/workspace.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:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@ -74,6 +74,9 @@ class MobileHomeScreen extends StatelessWidget {
} }
} }
final PropertyValueNotifier<UserWorkspacePB?> mCurrentWorkspace =
PropertyValueNotifier<UserWorkspacePB?>(null);
class MobileHomePage extends StatefulWidget { class MobileHomePage extends StatefulWidget {
const MobileHomePage({ const MobileHomePage({
super.key, super.key,
@ -122,7 +125,10 @@ class _MobileHomePageState extends State<MobileHomePage> {
buildWhen: (previous, current) => buildWhen: (previous, current) =>
previous.currentWorkspace?.workspaceId != previous.currentWorkspace?.workspaceId !=
current.currentWorkspace?.workspaceId, current.currentWorkspace?.workspaceId,
listener: (context, state) => getIt<CachedRecentService>().reset(), listener: (context, state) {
getIt<CachedRecentService>().reset();
mCurrentWorkspace.value = state.currentWorkspace;
},
builder: (context, state) { builder: (context, state) {
if (state.currentWorkspace == null) { if (state.currentWorkspace == null) {
return const SizedBox.shrink(); return const SizedBox.shrink();

View File

@ -1,4 +1,3 @@
import 'package:appflowy/mobile/application/user_profile/user_profile_bloc.dart';
import 'package:appflowy/mobile/presentation/notifications/mobile_notifications_multiple_select_page.dart'; import 'package:appflowy/mobile/presentation/notifications/mobile_notifications_multiple_select_page.dart';
import 'package:appflowy/mobile/presentation/notifications/widgets/widgets.dart'; import 'package:appflowy/mobile/presentation/notifications/widgets/widgets.dart';
import 'package:appflowy/mobile/presentation/presentation.dart'; import 'package:appflowy/mobile/presentation/presentation.dart';
@ -28,20 +27,26 @@ class _MobileNotificationsScreenV2State
@override @override
bool get wantKeepAlive => true; bool get wantKeepAlive => true;
@override
void initState() {
super.initState();
mCurrentWorkspace.addListener(_onRefresh);
}
@override
void dispose() {
mCurrentWorkspace.removeListener(_onRefresh);
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
super.build(context); super.build(context);
return MultiBlocProvider( return BlocProvider<ReminderBloc>.value(
providers: [ value: getIt<ReminderBloc>(),
BlocProvider<UserProfileBloc>(
create: (context) => UserProfileBloc()
..add(
const UserProfileEvent.started(),
),
),
BlocProvider<ReminderBloc>.value(value: getIt<ReminderBloc>()),
],
child: ValueListenableBuilder( child: ValueListenableBuilder(
valueListenable: bottomNavigationBarType, valueListenable: bottomNavigationBarType,
builder: (_, value, __) { builder: (_, value, __) {
@ -55,6 +60,10 @@ class _MobileNotificationsScreenV2State
), ),
); );
} }
void _onRefresh() {
getIt<ReminderBloc>().add(const ReminderEvent.refresh());
}
} }
class MobileNotificationsTab extends StatefulWidget { class MobileNotificationsTab extends StatefulWidget {

View File

@ -5,6 +5,7 @@ import 'package:appflowy/mobile/application/page_style/document_page_style_bloc.
import 'package:appflowy/mobile/presentation/notifications/widgets/color.dart'; 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_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';
@ -107,7 +108,10 @@ class NotificationContent extends StatelessWidget {
child: IntrinsicHeight( child: IntrinsicHeight(
child: BlocProvider( child: BlocProvider(
create: (context) => DocumentPageStyleBloc(view: state.view!), create: (context) => DocumentPageStyleBloc(view: state.view!),
child: NotificationDocumentContent(nodes: state.nodes), child: NotificationDocumentContent(
reminder: reminder,
nodes: state.nodes,
),
), ),
), ),
), ),
@ -176,9 +180,11 @@ class NotificationEllipse extends StatelessWidget {
class NotificationDocumentContent extends StatelessWidget { class NotificationDocumentContent extends StatelessWidget {
const NotificationDocumentContent({ const NotificationDocumentContent({
super.key, super.key,
required this.reminder,
required this.nodes, required this.nodes,
}); });
final ReminderPB reminder;
final List<Node> nodes; final List<Node> nodes;
@override @override
@ -222,6 +228,8 @@ class NotificationDocumentContent extends StatelessWidget {
); );
return IgnorePointer( return IgnorePointer(
child: Opacity(
opacity: reminder.type == ReminderType.past ? 0.3 : 1,
child: AppFlowyEditor( child: AppFlowyEditor(
editorState: editorState, editorState: editorState,
editorStyle: editorStyle, editorStyle: editorStyle,
@ -232,6 +240,7 @@ class NotificationDocumentContent extends StatelessWidget {
shrinkWrap: true, shrinkWrap: true,
blockComponentBuilders: blockBuilders, blockComponentBuilders: blockBuilders,
), ),
),
); );
} }
} }

View File

@ -189,10 +189,7 @@ Map<String, BlockComponentBuilder> getEditorBuilderMap({
), ),
), ),
CalloutBlockKeys.type: CalloutBlockComponentBuilder( CalloutBlockKeys.type: CalloutBlockComponentBuilder(
configuration: configuration.copyWith( configuration: configuration.copyWith(),
textStyle: (_) => styleCustomizer.calloutBlockStyleBuilder(),
placeholderTextStyle: (_) => styleCustomizer.calloutBlockStyleBuilder(),
),
defaultColor: calloutBGColor, defaultColor: calloutBGColor,
), ),
DividerBlockKeys.type: DividerBlockComponentBuilder( DividerBlockKeys.type: DividerBlockComponentBuilder(

View File

@ -516,6 +516,10 @@ Color? buildEditorCustomizedColor(
Node node, Node node,
String colorString, String colorString,
) { ) {
if (!context.mounted) {
return null;
}
// the color string is from FlowyTint. // the color string is from FlowyTint.
final tintColor = FlowyTint.values.firstWhereOrNull( final tintColor = FlowyTint.values.firstWhereOrNull(
(e) => e.id == colorString, (e) => e.id == colorString,

View File

@ -186,7 +186,7 @@ class _CalloutBlockComponentWidgetState
// the emoji picker button for the note // the emoji picker button for the note
Padding( Padding(
padding: const EdgeInsets.only( padding: const EdgeInsets.only(
top: 8.0, top: 6.0,
left: 4.0, left: 4.0,
right: 4.0, right: 4.0,
), ),

View File

@ -163,11 +163,14 @@ class _MentionDateBlockState extends State<MentionDateBlock> {
_updateReminder(reminderOption, reminder), _updateReminder(reminderOption, reminder),
); );
final color = reminder?.isAck == true Color? color;
? Theme.of(context).isLightMode if (reminder != null) {
if (reminder.type == ReminderType.today) {
color = Theme.of(context).isLightMode
? const Color(0xFFFE0299) ? const Color(0xFFFE0299)
: Theme.of(context).colorScheme.error : Theme.of(context).colorScheme.error;
: null; }
}
final textStyle = widget.textStyle?.copyWith( final textStyle = widget.textStyle?.copyWith(
color: color, color: color,
leadingDistribution: TextLeadingDistribution.even, leadingDistribution: TextLeadingDistribution.even,
@ -364,6 +367,7 @@ class _MentionDateBlockState extends State<MentionDateBlock> {
ReminderUpdate( ReminderUpdate(
id: widget.reminderId!, id: widget.reminderId!,
scheduledAt: reminderOption.fromDate(parsedDate!), scheduledAt: reminderOption.fromDate(parsedDate!),
date: parsedDate!,
), ),
), ),
); );

View File

@ -185,12 +185,24 @@ class EditorStyleCustomizer {
} }
TextStyle calloutBlockStyleBuilder() { TextStyle calloutBlockStyleBuilder() {
if (PlatformExtension.isMobile) {
final afThemeExtension = AFThemeExtension.of(context);
final pageStyle = context.read<DocumentPageStyleBloc>().state;
final fontSize = pageStyle.fontLayout.fontSize;
final fontFamily = pageStyle.fontFamily ?? defaultFontFamily;
final baseTextStyle = this.baseTextStyle(fontFamily);
return baseTextStyle.copyWith(
fontSize: fontSize,
color: afThemeExtension.onBackground,
);
} else {
final fontSize = context.read<DocumentAppearanceCubit>().state.fontSize; final fontSize = context.read<DocumentAppearanceCubit>().state.fontSize;
return baseTextStyle(null).copyWith( return baseTextStyle(null).copyWith(
fontSize: fontSize, fontSize: fontSize,
height: 1.5, height: 1.5,
); );
} }
}
TextStyle outlineBlockPlaceholderStyleBuilder() { TextStyle outlineBlockPlaceholderStyleBuilder() {
final fontSize = context.read<DocumentAppearanceCubit>().state.fontSize; final fontSize = context.read<DocumentAppearanceCubit>().state.fontSize;

View File

@ -95,7 +95,7 @@ class ReminderBloc extends Bloc<ReminderEvent, ReminderState> {
final newReminder = updateObject.merge(a: reminder); final newReminder = updateObject.merge(a: reminder);
final failureOrUnit = await _reminderService.updateReminder( final failureOrUnit = await _reminderService.updateReminder(
reminder: updateObject.merge(a: reminder), reminder: newReminder,
); );
failureOrUnit.fold( failureOrUnit.fold(
@ -402,6 +402,7 @@ class ReminderUpdate {
this.scheduledAt, this.scheduledAt,
this.includeTime, this.includeTime,
this.isArchived, this.isArchived,
this.date,
}); });
final String id; final String id;
@ -410,6 +411,7 @@ class ReminderUpdate {
final DateTime? scheduledAt; final DateTime? scheduledAt;
final bool? includeTime; final bool? includeTime;
final bool? isArchived; final bool? isArchived;
final DateTime? date;
ReminderPB merge({required ReminderPB a}) { ReminderPB merge({required ReminderPB a}) {
final isAcknowledged = isAck == null && scheduledAt != null final isAcknowledged = isAck == null && scheduledAt != null
@ -425,6 +427,10 @@ class ReminderUpdate {
meta[ReminderMetaKeys.isArchived] = isArchived.toString(); meta[ReminderMetaKeys.isArchived] = isArchived.toString();
} }
if (date != a.date && date != null) {
meta[ReminderMetaKeys.date] = date!.millisecondsSinceEpoch.toString();
}
return ReminderPB( return ReminderPB(
id: a.id, id: a.id,
objectId: a.objectId, objectId: a.objectId,

View File

@ -6,6 +6,13 @@ class ReminderMetaKeys {
static String rowId = "row_id"; static String rowId = "row_id";
static String createdAt = "created_at"; static String createdAt = "created_at";
static String isArchived = "is_archived"; static String isArchived = "is_archived";
static String date = "date";
}
enum ReminderType {
past,
today,
other,
} }
extension ReminderExtension on ReminderPB { extension ReminderExtension on ReminderPB {
@ -28,4 +35,32 @@ extension ReminderExtension on ReminderPB {
final t = meta[ReminderMetaKeys.isArchived]; final t = meta[ReminderMetaKeys.isArchived];
return t != null ? t == true.toString() : false; return t != null ? t == true.toString() : false;
} }
DateTime? get date {
final t = meta[ReminderMetaKeys.date];
return t != null ? DateTime.fromMillisecondsSinceEpoch(int.parse(t)) : null;
}
ReminderType get type {
final date = this.date?.millisecondsSinceEpoch;
if (date == null) {
return ReminderType.other;
}
final now = DateTime.now().millisecondsSinceEpoch;
if (date < now) {
return ReminderType.past;
}
final difference = date - now;
const oneDayInMilliseconds = 24 * 60 * 60 * 1000;
if (difference < oneDayInMilliseconds) {
return ReminderType.today;
}
return ReminderType.other;
}
} }