mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
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:
parent
9fbba5fb60
commit
b9fd3701cd
@ -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();
|
||||||
|
@ -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 {
|
||||||
|
@ -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,15 +228,18 @@ class NotificationDocumentContent extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return IgnorePointer(
|
return IgnorePointer(
|
||||||
child: AppFlowyEditor(
|
child: Opacity(
|
||||||
editorState: editorState,
|
opacity: reminder.type == ReminderType.past ? 0.3 : 1,
|
||||||
editorStyle: editorStyle,
|
child: AppFlowyEditor(
|
||||||
disableSelectionService: true,
|
editorState: editorState,
|
||||||
disableKeyboardService: true,
|
editorStyle: editorStyle,
|
||||||
disableScrollService: true,
|
disableSelectionService: true,
|
||||||
editable: false,
|
disableKeyboardService: true,
|
||||||
shrinkWrap: true,
|
disableScrollService: true,
|
||||||
blockComponentBuilders: blockBuilders,
|
editable: false,
|
||||||
|
shrinkWrap: true,
|
||||||
|
blockComponentBuilders: blockBuilders,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -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(
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
),
|
),
|
||||||
|
@ -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!,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -185,11 +185,23 @@ class EditorStyleCustomizer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TextStyle calloutBlockStyleBuilder() {
|
TextStyle calloutBlockStyleBuilder() {
|
||||||
final fontSize = context.read<DocumentAppearanceCubit>().state.fontSize;
|
if (PlatformExtension.isMobile) {
|
||||||
return baseTextStyle(null).copyWith(
|
final afThemeExtension = AFThemeExtension.of(context);
|
||||||
fontSize: fontSize,
|
final pageStyle = context.read<DocumentPageStyleBloc>().state;
|
||||||
height: 1.5,
|
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;
|
||||||
|
return baseTextStyle(null).copyWith(
|
||||||
|
fontSize: fontSize,
|
||||||
|
height: 1.5,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TextStyle outlineBlockPlaceholderStyleBuilder() {
|
TextStyle outlineBlockPlaceholderStyleBuilder() {
|
||||||
|
@ -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,
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user