From 6877607c5e03cd9c25d90f1bf0419bae82d786f3 Mon Sep 17 00:00:00 2001 From: Richard Shiue <71320345+richardshiue@users.noreply.github.com> Date: Fri, 24 Feb 2023 16:59:14 +0800 Subject: [PATCH] chore: calendar plugin backend database data (#1884) * chore: implement CalendarBloc * chore: enable save and read the calendar setting * style: more precise variable name * chore: backend calendar settings * chore: protobuf for layout settings * chore: update test * chore: Enumerate the LayoutTypePB enum type to get the supported layout types * fix: deserialize object type is not the same as serialize object type * chore: add set/get calendar settings event * ci: fix wanrings --------- Co-authored-by: nathan Co-authored-by: vedon --- .../calendar/application/calendar_bloc.dart | 159 ++++++++++++++++++ .../application/calendar_data_controller.dart | 115 +++++++++++++ .../application/calendar_listener.dart | 65 +++++++ .../database_view_revision_pad.rs | 27 +++ .../src/entities/calendar_entities.rs | 85 ++++++++++ .../flowy-database/src/entities/mod.rs | 2 + .../src/entities/setting_entities.rs | 40 ++--- .../flowy-database/src/event_handler.rs | 20 +++ .../rust-lib/flowy-database/src/event_map.rs | 11 +- .../flowy-database/src/notification.rs | 2 + .../src/services/database_view/editor.rs | 22 ++- .../src/services/database_view/trait_impl.rs | 23 ++- shared-lib/database-model/src/view_rev.rs | 29 +++- 13 files changed, 568 insertions(+), 32 deletions(-) create mode 100644 frontend/app_flowy/lib/plugins/calendar/application/calendar_bloc.dart create mode 100644 frontend/app_flowy/lib/plugins/calendar/application/calendar_data_controller.dart create mode 100644 frontend/app_flowy/lib/plugins/calendar/application/calendar_listener.dart create mode 100644 frontend/rust-lib/flowy-database/src/entities/calendar_entities.rs diff --git a/frontend/app_flowy/lib/plugins/calendar/application/calendar_bloc.dart b/frontend/app_flowy/lib/plugins/calendar/application/calendar_bloc.dart new file mode 100644 index 0000000000..d546a09348 --- /dev/null +++ b/frontend/app_flowy/lib/plugins/calendar/application/calendar_bloc.dart @@ -0,0 +1,159 @@ +import 'package:app_flowy/plugins/grid/application/field/field_controller.dart'; +import 'package:app_flowy/plugins/grid/application/row/row_cache.dart'; +import 'package:appflowy_backend/log.dart'; +import 'package:appflowy_backend/protobuf/flowy-error/protobuf.dart'; +import 'package:appflowy_backend/protobuf/flowy-folder/protobuf.dart'; +import 'package:appflowy_backend/protobuf/flowy-database/protobuf.dart'; +import 'package:calendar_view/calendar_view.dart'; +import 'package:dartz/dartz.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; + +import 'calendar_data_controller.dart'; + +part 'calendar_bloc.freezed.dart'; + +class CalendarBloc extends Bloc { + final CalendarDataController _databaseDataController; + final EventController calendarEventsController = EventController(); + + GridFieldController get fieldController => + _databaseDataController.fieldController; + String get databaseId => _databaseDataController.databaseId; + + CalendarBloc({required ViewPB view}) + : _databaseDataController = CalendarDataController(view: view), + super(CalendarState.initial(view.id)) { + on( + (event, emit) async { + await event.when( + initial: () async { + _startListening(); + await _openDatabase(emit); + }, + didReceiveCalendarSettings: (CalendarSettingsPB settings) { + emit(state.copyWith(settings: Some(settings))); + }, + didReceiveDatabaseUpdate: (DatabasePB database) { + emit(state.copyWith(database: Some(database))); + }, + didReceiveError: (FlowyError error) { + emit(state.copyWith(noneOrError: Some(error))); + }, + ); + }, + ); + } + + Future _openDatabase(Emitter emit) async { + final result = await _databaseDataController.openDatabase(); + result.fold( + (database) => emit( + state.copyWith(loadingState: DatabaseLoadingState.finish(left(unit))), + ), + (err) => emit( + state.copyWith(loadingState: DatabaseLoadingState.finish(right(err))), + ), + ); + } + + GridRowCache? getRowCache(String blockId) { + return _databaseDataController.rowCache; + } + + void _startListening() { + _databaseDataController.addListener( + onDatabaseChanged: (database) { + if (!isClosed) return; + + add(CalendarEvent.didReceiveDatabaseUpdate(database)); + }, + onSettingsChanged: (CalendarSettingsPB settings) { + if (isClosed) return; + add(CalendarEvent.didReceiveCalendarSettings(settings)); + }, + onArrangeWithNewField: (field) { + if (isClosed) return; + _initializeEvents(field); + // add(CalendarEvent.) + }, + onError: (err) { + Log.error(err); + }, + ); + } + + void _initializeEvents(FieldPB dateField) { + calendarEventsController.removeWhere((element) => true); + + const events = >[]; + + // final List> events = rows.map((row) { + // final event = CalendarEventData( + // title: "", + // date: row -> dateField -> value, + // event: row, + // ); + + // return event; + // }).toList(); + + calendarEventsController.addAll(events); + } +} + +@freezed +class CalendarEvent with _$CalendarEvent { + const factory CalendarEvent.initial() = _InitialCalendar; + const factory CalendarEvent.didReceiveCalendarSettings( + CalendarSettingsPB settings) = _DidReceiveCalendarSettings; + const factory CalendarEvent.didReceiveError(FlowyError error) = + _DidReceiveError; + const factory CalendarEvent.didReceiveDatabaseUpdate(DatabasePB database) = + _DidReceiveDatabaseUpdate; +} + +@freezed +class CalendarState with _$CalendarState { + const factory CalendarState({ + required String databaseId, + required Option database, + required Option dateField, + required Option> unscheduledRows, + required Option settings, + required DatabaseLoadingState loadingState, + required Option noneOrError, + }) = _CalendarState; + + factory CalendarState.initial(String databaseId) => CalendarState( + database: none(), + databaseId: databaseId, + dateField: none(), + unscheduledRows: none(), + settings: none(), + noneOrError: none(), + loadingState: const _Loading(), + ); +} + +@freezed +class DatabaseLoadingState with _$DatabaseLoadingState { + const factory DatabaseLoadingState.loading() = _Loading; + const factory DatabaseLoadingState.finish( + Either successOrFail) = _Finish; +} + +class CalendarEditingRow { + RowPB row; + int? index; + + CalendarEditingRow({ + required this.row, + required this.index, + }); +} + +class CalendarData { + final RowInfo rowInfo; + CalendarData(this.rowInfo); +} diff --git a/frontend/app_flowy/lib/plugins/calendar/application/calendar_data_controller.dart b/frontend/app_flowy/lib/plugins/calendar/application/calendar_data_controller.dart new file mode 100644 index 0000000000..bf69611d51 --- /dev/null +++ b/frontend/app_flowy/lib/plugins/calendar/application/calendar_data_controller.dart @@ -0,0 +1,115 @@ +import 'dart:async'; +import 'dart:collection'; + +import 'package:app_flowy/plugins/grid/application/view/grid_view_cache.dart'; +import 'package:app_flowy/plugins/grid/application/field/field_controller.dart'; +import 'package:app_flowy/plugins/grid/application/grid_service.dart'; +import 'package:app_flowy/plugins/grid/application/row/row_cache.dart'; +import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart'; +import 'package:appflowy_backend/protobuf/flowy-folder/protobuf.dart'; +import 'package:appflowy_backend/protobuf/flowy-database/protobuf.dart'; +import 'package:dartz/dartz.dart'; + +import 'calendar_listener.dart'; + +typedef OnFieldsChanged = void Function(UnmodifiableListView); +typedef OnDatabaseChanged = void Function(DatabasePB); +typedef OnSettingsChanged = void Function(CalendarSettingsPB); +typedef OnArrangeWithNewField = void Function(FieldPB); + +typedef OnRowsChanged = void Function(List, RowsChangedReason); +typedef OnError = void Function(FlowyError); + +class CalendarDataController { + final String databaseId; + final DatabaseFFIService _databaseFFIService; + final GridFieldController fieldController; + final CalendarListener _listener; + late DatabaseViewCache _viewCache; + + OnFieldsChanged? _onFieldsChanged; + OnDatabaseChanged? _onDatabaseChanged; + OnRowsChanged? _onRowsChanged; + OnSettingsChanged? _onSettingsChanged; + OnArrangeWithNewField? _onArrangeWithNewField; + OnError? _onError; + + List get rowInfos => _viewCache.rowInfos; + GridRowCache get rowCache => _viewCache.rowCache; + + CalendarDataController({required ViewPB view}) + : databaseId = view.id, + _listener = CalendarListener(view.id), + _databaseFFIService = DatabaseFFIService(viewId: view.id), + fieldController = GridFieldController(databaseId: view.id) { + _viewCache = DatabaseViewCache( + databaseId: view.id, + fieldController: fieldController, + ); + _viewCache.addListener(onRowsChanged: (reason) { + _onRowsChanged?.call(rowInfos, reason); + }); + } + + void addListener({ + required OnDatabaseChanged onDatabaseChanged, + OnFieldsChanged? onFieldsChanged, + OnRowsChanged? onRowsChanged, + required OnSettingsChanged? onSettingsChanged, + required OnArrangeWithNewField? onArrangeWithNewField, + required OnError? onError, + }) { + _onDatabaseChanged = onDatabaseChanged; + _onFieldsChanged = onFieldsChanged; + _onRowsChanged = onRowsChanged; + _onSettingsChanged = onSettingsChanged; + _onArrangeWithNewField = onArrangeWithNewField; + _onError = onError; + + fieldController.addListener(onFields: (fields) { + _onFieldsChanged?.call(UnmodifiableListView(fields)); + }); + + _listener.start( + onCalendarSettingsChanged: (result) { + result.fold( + (settings) => _onSettingsChanged?.call(settings), + (e) => _onError?.call(e), + ); + }, + onArrangeWithNewField: (result) { + result.fold( + (settings) => _onArrangeWithNewField?.call(settings), + (e) => _onError?.call(e), + ); + }, + ); + } + + Future> openDatabase() async { + final result = await _databaseFFIService.openGrid(); + return result.fold( + (database) async { + _onDatabaseChanged?.call(database); + return fieldController + .loadFields(fieldIds: database.fields) + .then((result) { + return result.fold( + (l) => Future(() async { + _viewCache.rowCache.initializeRows(database.rows); + return left(l); + }), + (err) => right(err), + ); + }); + }, + (err) => right(err), + ); + } + + Future dispose() async { + await _viewCache.dispose(); + await _databaseFFIService.closeGrid(); + await fieldController.dispose(); + } +} diff --git a/frontend/app_flowy/lib/plugins/calendar/application/calendar_listener.dart b/frontend/app_flowy/lib/plugins/calendar/application/calendar_listener.dart new file mode 100644 index 0000000000..4b2230ce1e --- /dev/null +++ b/frontend/app_flowy/lib/plugins/calendar/application/calendar_listener.dart @@ -0,0 +1,65 @@ +import 'dart:typed_data'; + +import 'package:app_flowy/core/grid_notification.dart'; +import 'package:flowy_infra/notifier.dart'; +import 'package:appflowy_backend/protobuf/flowy-error/protobuf.dart'; +import 'package:appflowy_backend/protobuf/flowy-database/protobuf.dart'; +import 'package:dartz/dartz.dart'; + +typedef CalendarSettingsValue = Either; +typedef ArrangeWithNewField = Either; + +class CalendarListener { + final String viewId; + PublishNotifier? _calendarSettingsNotifier = + PublishNotifier(); + PublishNotifier? _arrangeWithNewFieldNotifier = + PublishNotifier(); + DatabaseNotificationListener? _listener; + CalendarListener(this.viewId); + + void start({ + required void Function(CalendarSettingsValue) onCalendarSettingsChanged, + required void Function(ArrangeWithNewField) onArrangeWithNewField, + }) { + _calendarSettingsNotifier?.addPublishListener(onCalendarSettingsChanged); + _arrangeWithNewFieldNotifier?.addPublishListener(onArrangeWithNewField); + _listener = DatabaseNotificationListener( + objectId: viewId, + handler: _handler, + ); + } + + void _handler( + DatabaseNotification ty, + Either result, + ) { + switch (ty) { + case DatabaseNotification.DidUpdateCalendarSettings: + result.fold( + (payload) => _calendarSettingsNotifier?.value = + left(CalendarSettingsPB.fromBuffer(payload)), + (error) => _calendarSettingsNotifier?.value = right(error), + ); + break; + case DatabaseNotification.DidArrangeCalendarWithNewField: + result.fold( + (payload) => _arrangeWithNewFieldNotifier?.value = + left(FieldPB.fromBuffer(payload)), + (error) => _arrangeWithNewFieldNotifier?.value = right(error), + ); + break; + default: + break; + } + } + + Future stop() async { + await _listener?.stop(); + _calendarSettingsNotifier?.dispose(); + _calendarSettingsNotifier = null; + + _arrangeWithNewFieldNotifier?.dispose(); + _arrangeWithNewFieldNotifier = null; + } +} diff --git a/frontend/rust-lib/flowy-client-sync/src/client_database/database_view_revision_pad.rs b/frontend/rust-lib/flowy-client-sync/src/client_database/database_view_revision_pad.rs index 4ce588189e..adf3579067 100644 --- a/frontend/rust-lib/flowy-client-sync/src/client_database/database_view_revision_pad.rs +++ b/frontend/rust-lib/flowy-client-sync/src/client_database/database_view_revision_pad.rs @@ -294,6 +294,33 @@ impl DatabaseViewRevisionPad { }) } + /// Returns the settings for the given layout. If it's not exists then will return the + /// default settings for the given layout. + /// Each [database view](https://appflowy.gitbook.io/docs/essential-documentation/contribute-to-appflowy/architecture/frontend/database-view) has its own settings. + pub fn get_layout_setting(&self, layout: &LayoutRevision) -> Option + where + T: serde::de::DeserializeOwned, + { + let settings_str = self.view.layout_settings.get(layout)?; + serde_json::from_str::(settings_str).ok() + } + + /// updates the settings for the given layout type + pub fn update_layout_setting( + &mut self, + layout: &LayoutRevision, + settings: &T, + ) -> SyncResult> + where + T: serde::Serialize, + { + let settings_str = serde_json::to_string(settings).map_err(internal_sync_error)?; + self.modify(|view| { + view.layout_settings.insert(layout.clone(), settings_str); + Ok(Some(())) + }) + } + pub fn json_str(&self) -> SyncResult { make_grid_view_rev_json_str(&self.view) } diff --git a/frontend/rust-lib/flowy-database/src/entities/calendar_entities.rs b/frontend/rust-lib/flowy-database/src/entities/calendar_entities.rs new file mode 100644 index 0000000000..97b41acda0 --- /dev/null +++ b/frontend/rust-lib/flowy-database/src/entities/calendar_entities.rs @@ -0,0 +1,85 @@ +use crate::entities::parser::NotEmptyStr; +use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; +use flowy_error::ErrorCode; +use serde::{Deserialize, Serialize}; +use serde_repr::{Deserialize_repr, Serialize_repr}; +use std::convert::TryInto; + +#[derive(Debug, Clone, Eq, PartialEq, Default, ProtoBuf)] +pub struct CalendarSettingsPB { + #[pb(index = 1)] + pub view_id: String, + + #[pb(index = 2)] + pub layout_ty: CalendarLayout, + + #[pb(index = 3)] + pub first_day_of_week: i32, + + #[pb(index = 4)] + pub show_weekends: bool, + + #[pb(index = 5)] + pub show_week_numbers: bool, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct CalendarSettingsParams { + pub(crate) view_id: String, + layout_ty: CalendarLayout, + first_day_of_week: i32, + show_weekends: bool, + show_week_numbers: bool, +} + +const DEFAULT_FIRST_DAY_OF_WEEK: i32 = 0; +const DEFAULT_SHOW_WEEKENDS: bool = true; +const DEFAULT_SHOW_WEEK_NUMBERS: bool = true; + +impl CalendarSettingsParams { + pub fn default_with(view_id: String) -> Self { + CalendarSettingsParams { + view_id: view_id.to_string(), + layout_ty: CalendarLayout::default(), + first_day_of_week: DEFAULT_FIRST_DAY_OF_WEEK, + show_weekends: DEFAULT_SHOW_WEEKENDS, + show_week_numbers: DEFAULT_SHOW_WEEK_NUMBERS, + } + } +} + +impl TryInto for CalendarSettingsPB { + type Error = ErrorCode; + + fn try_into(self) -> Result { + let view_id = NotEmptyStr::parse(self.view_id).map_err(|_| ErrorCode::ViewIdInvalid)?; + Ok(CalendarSettingsParams { + view_id: view_id.0, + layout_ty: self.layout_ty, + first_day_of_week: self.first_day_of_week, + show_weekends: self.show_weekends, + show_week_numbers: self.show_week_numbers, + }) + } +} + +impl std::convert::From for CalendarSettingsPB { + fn from(params: CalendarSettingsParams) -> Self { + CalendarSettingsPB { + view_id: params.view_id, + layout_ty: params.layout_ty, + first_day_of_week: params.first_day_of_week, + show_weekends: params.show_weekends, + show_week_numbers: params.show_week_numbers, + } + } +} + +#[derive(Debug, Clone, Eq, PartialEq, Default, ProtoBuf_Enum, Serialize_repr, Deserialize_repr)] +#[repr(u8)] +pub enum CalendarLayout { + #[default] + MonthLayout = 0, + WeekLayout = 1, + DayLayout = 2, +} diff --git a/frontend/rust-lib/flowy-database/src/entities/mod.rs b/frontend/rust-lib/flowy-database/src/entities/mod.rs index 9f83360346..a8e1d90a4f 100644 --- a/frontend/rust-lib/flowy-database/src/entities/mod.rs +++ b/frontend/rust-lib/flowy-database/src/entities/mod.rs @@ -1,3 +1,4 @@ +mod calendar_entities; mod cell_entities; mod field_entities; pub mod filter_entities; @@ -9,6 +10,7 @@ pub mod setting_entities; mod sort_entities; mod view_entities; +pub use calendar_entities::*; pub use cell_entities::*; pub use field_entities::*; pub use filter_entities::*; diff --git a/frontend/rust-lib/flowy-database/src/entities/setting_entities.rs b/frontend/rust-lib/flowy-database/src/entities/setting_entities.rs index 36cbbfeb82..d1ac252113 100644 --- a/frontend/rust-lib/flowy-database/src/entities/setting_entities.rs +++ b/frontend/rust-lib/flowy-database/src/entities/setting_entities.rs @@ -1,25 +1,24 @@ use crate::entities::parser::NotEmptyStr; use crate::entities::{ - AlterFilterParams, AlterFilterPayloadPB, AlterSortParams, AlterSortPayloadPB, DeleteFilterParams, - DeleteFilterPayloadPB, DeleteGroupParams, DeleteGroupPayloadPB, DeleteSortParams, - DeleteSortPayloadPB, InsertGroupParams, InsertGroupPayloadPB, RepeatedFilterPB, + AlterFilterParams, AlterFilterPayloadPB, AlterSortParams, AlterSortPayloadPB, CalendarSettingsPB, + DeleteFilterParams, DeleteFilterPayloadPB, DeleteGroupParams, DeleteGroupPayloadPB, + DeleteSortParams, DeleteSortPayloadPB, InsertGroupParams, InsertGroupPayloadPB, RepeatedFilterPB, RepeatedGroupConfigurationPB, RepeatedSortPB, }; use database_model::LayoutRevision; use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; use flowy_error::ErrorCode; use std::convert::TryInto; -use strum::IntoEnumIterator; use strum_macros::EnumIter; /// [DatabaseViewSettingPB] defines the setting options for the grid. Such as the filter, group, and sort. #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)] pub struct DatabaseViewSettingPB { #[pb(index = 1)] - pub support_layouts: Vec, + pub current_layout: LayoutTypePB, #[pb(index = 2)] - pub current_layout: LayoutTypePB, + pub layout_setting: LayoutSettingPB, #[pb(index = 3)] pub filters: RepeatedFilterPB, @@ -31,23 +30,6 @@ pub struct DatabaseViewSettingPB { pub sorts: RepeatedSortPB, } -#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)] -pub struct ViewLayoutPB { - #[pb(index = 1)] - ty: LayoutTypePB, -} - -impl ViewLayoutPB { - pub fn all() -> Vec { - let mut layouts = vec![]; - for layout_ty in LayoutTypePB::iter() { - layouts.push(ViewLayoutPB { ty: layout_ty }) - } - - layouts - } -} - #[derive(Debug, Clone, PartialEq, Eq, ProtoBuf_Enum, EnumIter)] #[repr(u8)] pub enum LayoutTypePB { @@ -176,3 +158,15 @@ impl DatabaseSettingChangesetParams { self.insert_filter.is_some() || self.delete_filter.is_some() } } + +#[derive(Debug, Eq, PartialEq, Default, ProtoBuf, Clone)] +pub struct LayoutSettingPB { + #[pb(index = 1, one_of)] + pub calendar: Option, +} + +impl LayoutSettingPB { + pub fn new() -> Self { + Self::default() + } +} diff --git a/frontend/rust-lib/flowy-database/src/event_handler.rs b/frontend/rust-lib/flowy-database/src/event_handler.rs index 94f0bd8c36..588064b31e 100644 --- a/frontend/rust-lib/flowy-database/src/event_handler.rs +++ b/frontend/rust-lib/flowy-database/src/event_handler.rs @@ -560,3 +560,23 @@ pub(crate) async fn move_group_row_handler( editor.move_group_row(params).await?; Ok(()) } + +#[tracing::instrument(level = "debug", skip(data, manager), err)] +pub(crate) async fn set_calendar_setting_handler( + data: AFPluginData, + manager: AFPluginState>, +) -> FlowyResult<()> { + let params: CalendarSettingsParams = data.into_inner().try_into()?; + let _ = manager.get_database_editor(params.view_id.as_ref()).await?; + todo!("nathan: depends on the main branch refactoring") +} + +#[tracing::instrument(level = "debug", skip(data, manager), err)] +pub(crate) async fn get_calendar_setting_handler( + data: AFPluginData, + manager: AFPluginState>, +) -> FlowyResult<()> { + let view_id = data.into_inner().value; + let _ = manager.get_database_editor(view_id.as_ref()).await?; + todo!("nathan: depends on the main branch refactoring") +} diff --git a/frontend/rust-lib/flowy-database/src/event_map.rs b/frontend/rust-lib/flowy-database/src/event_map.rs index 8c485974e8..c504b7cf63 100644 --- a/frontend/rust-lib/flowy-database/src/event_map.rs +++ b/frontend/rust-lib/flowy-database/src/event_map.rs @@ -47,7 +47,10 @@ pub fn init(database_manager: Arc) -> AFPlugin { .event(DatabaseEvent::CreateBoardCard, create_board_card_handler) .event(DatabaseEvent::MoveGroup, move_group_handler) .event(DatabaseEvent::MoveGroupRow, move_group_row_handler) - .event(DatabaseEvent::GetGroup, get_groups_handler); + .event(DatabaseEvent::GetGroup, get_groups_handler) + // Calendar + .event(DatabaseEvent::SetCalenderSetting, set_calendar_setting_handler) + .event(DatabaseEvent::GetCalendarSetting, get_calendar_setting_handler); plugin } @@ -229,4 +232,10 @@ pub enum DatabaseEvent { #[event(input = "MoveGroupRowPayloadPB")] GroupByField = 113, + + #[event(input = "CalendarSettingsPB")] + SetCalenderSetting = 114, + + #[event()] + GetCalendarSetting = 115, } diff --git a/frontend/rust-lib/flowy-database/src/notification.rs b/frontend/rust-lib/flowy-database/src/notification.rs index b4f56ba14e..ffbba67ff2 100644 --- a/frontend/rust-lib/flowy-database/src/notification.rs +++ b/frontend/rust-lib/flowy-database/src/notification.rs @@ -31,6 +31,8 @@ pub enum DatabaseNotification { DidReorderSingleRow = 66, /// Trigger when the settings of the database are changed DidUpdateSettings = 70, + DidUpdateCalendarSettings = 80, + DidArrangeCalendarWithNewField = 81, } impl std::default::Default for DatabaseNotification { diff --git a/frontend/rust-lib/flowy-database/src/services/database_view/editor.rs b/frontend/rust-lib/flowy-database/src/services/database_view/editor.rs index 02c388ed9a..cf62aaaf0c 100644 --- a/frontend/rust-lib/flowy-database/src/services/database_view/editor.rs +++ b/frontend/rust-lib/flowy-database/src/services/database_view/editor.rs @@ -635,6 +635,26 @@ impl DatabaseViewRevisionEditor { Ok(()) } + /// Returns the current calendar settings + pub async fn get_calendar_settings(&self) -> FlowyResult { + let settings = self + .pad + .read() + .await + .get_layout_setting(&LayoutRevision::Calendar) + .unwrap_or_else(|| CalendarSettingsParams::default_with(self.view_id.to_string())); + Ok(settings) + } + + /// Update the calendar settings and send the notification to refresh the UI + pub async fn update_calendar_settings(&self, params: CalendarSettingsParams) -> FlowyResult<()> { + // Maybe it needs no send notification to refresh the UI + self + .modify(|pad| Ok(pad.update_layout_setting(&LayoutRevision::Calendar, ¶ms)?)) + .await?; + Ok(()) + } + #[tracing::instrument(level = "trace", skip_all, err)] pub async fn did_update_view_field_type_option( &self, @@ -878,7 +898,7 @@ async fn new_group_controller( .await } -/// Returns a [GroupController] +/// Returns a [GroupController] /// async fn new_group_controller_with_field_rev( user_id: String, diff --git a/frontend/rust-lib/flowy-database/src/services/database_view/trait_impl.rs b/frontend/rust-lib/flowy-database/src/services/database_view/trait_impl.rs index 5608626d68..31723c5959 100644 --- a/frontend/rust-lib/flowy-database/src/services/database_view/trait_impl.rs +++ b/frontend/rust-lib/flowy-database/src/services/database_view/trait_impl.rs @@ -1,4 +1,4 @@ -use crate::entities::{DatabaseViewSettingPB, LayoutTypePB, ViewLayoutPB}; +use crate::entities::{CalendarSettingsParams, DatabaseViewSettingPB, LayoutSettingPB}; use crate::services::database_view::{get_cells_for_field, DatabaseViewEditorDelegate}; use crate::services::field::RowSingleCellData; use crate::services::filter::{FilterController, FilterDelegate, FilterType}; @@ -7,8 +7,8 @@ use crate::services::row::DatabaseBlockRowRevision; use crate::services::sort::{SortDelegate, SortType}; use bytes::Bytes; use database_model::{ - FieldRevision, FieldTypeRevision, FilterRevision, GroupConfigurationRevision, RowRevision, - SortRevision, + FieldRevision, FieldTypeRevision, FilterRevision, GroupConfigurationRevision, LayoutRevision, + RowRevision, SortRevision, }; use flowy_client_sync::client_database::{DatabaseViewRevisionPad, GridViewRevisionChangeset}; use flowy_client_sync::make_operations_from_revisions; @@ -146,13 +146,24 @@ pub fn make_grid_setting( view_pad: &DatabaseViewRevisionPad, field_revs: &[Arc], ) -> DatabaseViewSettingPB { - let layout_type: LayoutTypePB = view_pad.layout.clone().into(); + let layout_type: LayoutRevision = view_pad.layout.clone(); + let mut layout_settings = LayoutSettingPB::new(); + match layout_type { + LayoutRevision::Grid => {}, + LayoutRevision::Board => {}, + LayoutRevision::Calendar => { + layout_settings.calendar = view_pad + .get_layout_setting::(&layout_type) + .map(|params| params.into()); + }, + } + let filters = view_pad.get_all_filters(field_revs); let group_configurations = view_pad.get_groups_by_field_revs(field_revs); let sorts = view_pad.get_all_sorts(field_revs); DatabaseViewSettingPB { - support_layouts: ViewLayoutPB::all(), - current_layout: layout_type, + current_layout: layout_type.into(), + layout_setting: layout_settings, filters: filters.into(), sorts: sorts.into(), group_configurations: group_configurations.into(), diff --git a/shared-lib/database-model/src/view_rev.rs b/shared-lib/database-model/src/view_rev.rs index b30f5c1644..3010ef8f50 100644 --- a/shared-lib/database-model/src/view_rev.rs +++ b/shared-lib/database-model/src/view_rev.rs @@ -1,4 +1,5 @@ use crate::{FilterConfiguration, GroupConfiguration, SortConfiguration}; +use indexmap::IndexMap; use nanoid::nanoid; use serde::{Deserialize, Serialize}; use serde_repr::*; @@ -38,6 +39,9 @@ pub struct DatabaseViewRevision { pub layout: LayoutRevision, + #[serde(default)] + pub layout_settings: LayoutSettings, + #[serde(default)] pub filters: FilterConfiguration, @@ -54,6 +58,7 @@ impl DatabaseViewRevision { view_id, database_id, layout, + layout_settings: Default::default(), filters: Default::default(), groups: Default::default(), sorts: Default::default(), @@ -65,6 +70,27 @@ impl DatabaseViewRevision { } } +#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(transparent)] +pub struct LayoutSettings { + #[serde(with = "indexmap::serde_seq")] + inner: IndexMap, +} + +impl std::ops::Deref for LayoutSettings { + type Target = IndexMap; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl std::ops::DerefMut for LayoutSettings { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inner + } +} + #[derive(Debug, Clone, Default, Serialize, Deserialize)] pub struct RowOrderRevision { pub row_id: String, @@ -80,6 +106,7 @@ mod tests { view_id: "1".to_string(), database_id: "1".to_string(), layout: Default::default(), + layout_settings: Default::default(), filters: Default::default(), groups: Default::default(), sorts: Default::default(), @@ -87,7 +114,7 @@ mod tests { let s = serde_json::to_string(&grid_view_revision).unwrap(); assert_eq!( s, - r#"{"view_id":"1","grid_id":"1","layout":0,"filters":[],"groups":[],"sorts":[]}"# + r#"{"view_id":"1","grid_id":"1","layout":0,"layout_settings":[],"filters":[],"groups":[],"sorts":[]}"# ); } }