appflowy 3 роки тому
батько
коміт
afc563d781

+ 1 - 1
frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/context_builder.dart

@@ -2,7 +2,7 @@ part of 'cell_service.dart';
 
 typedef GridCellContext = _GridCellContext<Cell, String>;
 typedef GridSelectOptionCellContext = _GridCellContext<SelectOptionCellData, String>;
-typedef GridDateCellContext = _GridCellContext<DateCellData, DateCellPersistenceData>;
+typedef GridDateCellContext = _GridCellContext<DateCellData, DateCalData>;
 
 class GridCellContextBuilder {
   final GridCellCache _cellCache;

+ 8 - 5
frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/data_persistence.dart

@@ -31,23 +31,26 @@ class CellDataPersistence implements _GridCellDataPersistence<String> {
 }
 
 @freezed
-class DateCellPersistenceData with _$DateCellPersistenceData {
-  const factory DateCellPersistenceData({required DateTime date, String? time}) = _DateCellPersistenceData;
+class DateCalData with _$DateCalData {
+  const factory DateCalData({required DateTime date, String? time}) = _DateCellPersistenceData;
 }
 
-class DateCellDataPersistence implements _GridCellDataPersistence<DateCellPersistenceData> {
+class DateCellDataPersistence implements _GridCellDataPersistence<DateCalData> {
   final GridCell gridCell;
   DateCellDataPersistence({
     required this.gridCell,
   });
 
   @override
-  Future<Option<FlowyError>> save(DateCellPersistenceData data) {
+  Future<Option<FlowyError>> save(DateCalData data) {
     var payload = DateChangesetPayload.create()..cellIdentifier = _cellIdentifier(gridCell);
 
     final date = (data.date.millisecondsSinceEpoch ~/ 1000).toString();
     payload.date = date;
-    payload.time = data.time ?? "";
+
+    if (data.time != null) {
+      payload.time = data.time!;
+    }
 
     return GridEventUpdateDateCell(payload).send().then((result) {
       return result.fold(

+ 38 - 20
frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart

@@ -9,7 +9,7 @@ import 'dart:async';
 import 'cell_service/cell_service.dart';
 import 'package:dartz/dartz.dart';
 import 'package:protobuf/protobuf.dart';
-// import 'package:fixnum/fixnum.dart' as $fixnum;
+import 'package:fixnum/fixnum.dart' as $fixnum;
 part 'date_cal_bloc.freezed.dart';
 
 class DateCalBloc extends Bloc<DateCalEvent, DateCalState> {
@@ -34,7 +34,11 @@ class DateCalBloc extends Bloc<DateCalEvent, DateCalState> {
           setFocusedDay: (focusedDay) {
             emit(state.copyWith(focusedDay: focusedDay));
           },
-          didReceiveCellUpdate: (value) {},
+          didReceiveCellUpdate: (DateCellData cellData) {
+            final dateData = dateDataFromCellData(cellData);
+            final time = dateData.foldRight("", (dateData, previous) => dateData.time);
+            emit(state.copyWith(dateData: dateData, time: time));
+          },
           setIncludeTime: (includeTime) async {
             await _updateTypeOption(emit, includeTime: includeTime);
           },
@@ -53,11 +57,8 @@ class DateCalBloc extends Bloc<DateCalEvent, DateCalState> {
   }
 
   Future<void> _updateDateData(Emitter<DateCalState> emit, {DateTime? date, String? time}) {
-    final DateCellPersistenceData newDateData = state.dateData.fold(
-      () {
-        var newDateData = DateCellPersistenceData(date: date ?? DateTime.now());
-        return newDateData.copyWith(time: time);
-      },
+    final DateCalData newDateData = state.dateData.fold(
+      () => DateCalData(date: date ?? DateTime.now(), time: time),
       (dateData) {
         var newDateData = dateData;
         if (date != null && !isSameDay(newDateData.date, date)) {
@@ -74,7 +75,7 @@ class DateCalBloc extends Bloc<DateCalEvent, DateCalState> {
     return _saveDateData(emit, newDateData);
   }
 
-  Future<void> _saveDateData(Emitter<DateCalState> emit, DateCellPersistenceData newDateData) async {
+  Future<void> _saveDateData(Emitter<DateCalState> emit, DateCalData newDateData) async {
     if (state.dateData == Some(newDateData)) {
       return;
     }
@@ -173,31 +174,48 @@ class DateCalState with _$DateCalState {
     required DateTypeOption dateTypeOption,
     required CalendarFormat format,
     required DateTime focusedDay,
-    required String time,
     required Option<String> timeFormatError,
-    required Option<DateCellPersistenceData> dateData,
+    required Option<DateCalData> dateData,
+    required String? time,
   }) = _DateCalState;
 
   factory DateCalState.initial(
     DateTypeOption dateTypeOption,
     DateCellData? cellData,
   ) {
-    Option<DateCellPersistenceData> dateData = none();
-    final time = cellData?.time ?? "";
-    if (cellData != null) {
-      // final timestamp = $fixnum.Int64.parseInt(cellData.timestamp).toInt();
-      final timestamp = cellData.timestamp * 1000;
-      final selectedDay = DateTime.fromMillisecondsSinceEpoch(timestamp.toInt());
-      dateData = Some(DateCellPersistenceData(date: selectedDay, time: time));
-    }
-
+    Option<DateCalData> dateData = dateDataFromCellData(cellData);
+    final time = dateData.foldRight("", (dateData, previous) => dateData.time);
     return DateCalState(
       dateTypeOption: dateTypeOption,
       format: CalendarFormat.month,
       focusedDay: DateTime.now(),
-      dateData: dateData,
       time: time,
+      dateData: dateData,
       timeFormatError: none(),
     );
   }
 }
+
+Option<DateCalData> dateDataFromCellData(DateCellData? cellData) {
+  String? time = timeFromCellData(cellData);
+  Option<DateCalData> dateData = none();
+  if (cellData != null) {
+    final timestamp = cellData.timestamp * 1000;
+    final date = DateTime.fromMillisecondsSinceEpoch(timestamp.toInt());
+    dateData = Some(DateCalData(date: date, time: time));
+  }
+  return dateData;
+}
+
+$fixnum.Int64 timestampFromDateTime(DateTime dateTime) {
+  final timestamp = (dateTime.millisecondsSinceEpoch ~/ 1000);
+  return $fixnum.Int64(timestamp);
+}
+
+String? timeFromCellData(DateCellData? cellData) {
+  String? time;
+  if (cellData?.hasTime() ?? false) {
+    time = cellData?.time;
+  }
+  return time;
+}

+ 5 - 1
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/calendar.dart

@@ -254,7 +254,11 @@ class _TimeTextFieldState extends State<_TimeTextField> {
   @override
   Widget build(BuildContext context) {
     final theme = context.watch<AppTheme>();
-    return BlocBuilder<DateCalBloc, DateCalState>(
+    return BlocConsumer<DateCalBloc, DateCalState>(
+      listener: (context, state) {
+        _controller.text = state.time ?? "";
+      },
+      listenWhen: (p, c) => p.time != c.time,
       builder: (context, state) {
         if (state.dateTypeOption.includeTime) {
           return Padding(

+ 1 - 1
frontend/rust-lib/flowy-grid/src/event_handler.rs

@@ -289,7 +289,7 @@ pub(crate) async fn get_date_cell_data_handler(
         Some(field_meta) => {
             let cell_meta = editor.get_cell_meta(&params.row_id, &params.field_id).await?;
             let type_option = DateTypeOption::from(&field_meta);
-            let date_cell_data = type_option.date_cell_data(&cell_meta)?;
+            let date_cell_data = type_option.make_date_cell_data(&cell_meta)?;
             data_result(date_cell_data)
         }
     }

+ 23 - 31
frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs

@@ -5,14 +5,12 @@ use crate::services::row::{CellContentChangeset, CellDataOperation, DecodedCellD
 use bytes::Bytes;
 use chrono::format::strftime::StrftimeItems;
 use chrono::NaiveDateTime;
-use diesel::types::Time;
 use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
 use flowy_error::{internal_error, ErrorCode, FlowyError, FlowyResult};
 use flowy_grid_data_model::entities::{
     CellChangeset, CellMeta, FieldMeta, FieldType, TypeOptionDataDeserializer, TypeOptionDataEntry,
 };
 use serde::{Deserialize, Serialize};
-use std::ops::Add;
 use std::str::FromStr;
 use strum_macros::EnumIter;
 
@@ -79,7 +77,7 @@ impl DateTypeOption {
         }
     }
 
-    pub fn date_cell_data(&self, cell_meta: &Option<CellMeta>) -> FlowyResult<DateCellData> {
+    pub fn make_date_cell_data(&self, cell_meta: &Option<CellMeta>) -> FlowyResult<DateCellData> {
         if cell_meta.is_none() {
             return Ok(DateCellData::default());
         }
@@ -112,27 +110,28 @@ impl DateTypeOption {
         utc: &chrono::DateTime<chrono::Utc>,
         time: &Option<String>,
     ) -> FlowyResult<i64> {
-        let mut date_str = format!(
-            "{}",
-            utc.format_with_items(StrftimeItems::new(self.date_format.format_str()))
-        );
-
         if let Some(time_str) = time.as_ref() {
             if !time_str.is_empty() {
-                date_str = date_str.add(&time_str);
-            }
-        }
-        let fmt = self.date_fmt(time);
-        match NaiveDateTime::parse_from_str(&date_str, &fmt) {
-            Ok(native) => {
-                let utc = self.utc_date_time_from_native(native);
-                Ok(utc.timestamp())
-            }
-            Err(_e) => {
-                let msg = format!("Parse {} with format: {} failed", date_str, fmt);
-                Err(FlowyError::new(ErrorCode::InvalidDateTimeFormat, &msg))
+                let date_str = format!(
+                    "{}{}",
+                    utc.format_with_items(StrftimeItems::new(self.date_format.format_str())),
+                    &time_str
+                );
+
+                return match NaiveDateTime::parse_from_str(&date_str, &self.date_fmt(time)) {
+                    Ok(native) => {
+                        let utc = self.utc_date_time_from_native(native);
+                        Ok(utc.timestamp())
+                    }
+                    Err(_e) => {
+                        let msg = format!("Parse {} failed", date_str);
+                        Err(FlowyError::new(ErrorCode::InvalidDateTimeFormat, &msg))
+                    }
+                };
             }
         }
+
+        return Ok(utc.timestamp());
     }
 }
 
@@ -170,7 +169,7 @@ impl CellDataOperation for DateTypeOption {
                     let timestamp = self.timestamp_from_utc_with_time(&utc, &time)?;
                     DateCellDataSerde::new(timestamp, time, &self.time_format)
                 }
-                _ => DateCellDataSerde::from_timestamp(date_timestamp, &self.time_format),
+                _ => DateCellDataSerde::from_timestamp(date_timestamp, Some(default_time_str(&self.time_format))),
             },
         };
 
@@ -312,11 +311,8 @@ impl DateCellDataSerde {
         }
     }
 
-    fn from_timestamp(timestamp: i64, time_format: &TimeFormat) -> Self {
-        Self {
-            timestamp,
-            time: Some(default_time_str(time_format)),
-        }
+    pub(crate) fn from_timestamp(timestamp: i64, time: Option<String>) -> Self {
+        Self { timestamp, time }
     }
 
     fn to_string(self) -> String {
@@ -614,11 +610,7 @@ mod tests {
     }
 
     fn data(s: i64) -> String {
-        let json = serde_json::to_string(&DateCellDataSerde {
-            timestamp: s,
-            time: None,
-        })
-        .unwrap();
+        let json = serde_json::to_string(&DateCellDataSerde::from_timestamp(s, None)).unwrap();
         TypeOptionCellData::new(&json, FieldType::DateTime).json()
     }
 }

+ 2 - 1
frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option.rs

@@ -78,7 +78,8 @@ mod tests {
 
         // date
         let date_time_field_meta = FieldBuilder::from_field_type(&FieldType::DateTime).build();
-        let data = TypeOptionCellData::new("1647251762", FieldType::DateTime).json();
+        let json = serde_json::to_string(&DateCellDataSerde::from_timestamp(1647251762, None)).unwrap();
+        let data = TypeOptionCellData::new(&json, FieldType::DateTime).json();
         assert_eq!(
             type_option.decode_cell_data(data, &date_time_field_meta).content,
             "Mar 14,2022".to_owned()

+ 19 - 8
frontend/rust-lib/flowy-grid/tests/grid/grid_test.rs

@@ -2,8 +2,8 @@ use crate::grid::script::EditorScript::*;
 use crate::grid::script::*;
 use chrono::NaiveDateTime;
 use flowy_grid::services::field::{
-    MultiSelectTypeOption, SelectOption, SelectOptionCellContentChangeset, SingleSelectTypeOption,
-    SELECTION_IDS_SEPARATOR,
+    DateCellContentChangeset, MultiSelectTypeOption, SelectOption, SelectOptionCellContentChangeset,
+    SingleSelectTypeOption, SELECTION_IDS_SEPARATOR,
 };
 use flowy_grid::services::row::{decode_cell_data, CreateRowMetaBuilder};
 use flowy_grid_data_model::entities::{
@@ -240,7 +240,9 @@ async fn grid_row_add_cells_test() {
                 builder.add_cell(&field.id, "18,443".to_owned()).unwrap();
             }
             FieldType::DateTime => {
-                builder.add_cell(&field.id, "1647251762".to_owned()).unwrap();
+                builder
+                    .add_cell(&field.id, make_date_cell_string("1647251762"))
+                    .unwrap();
             }
             FieldType::SingleSelect => {
                 let type_option = SingleSelectTypeOption::from(field);
@@ -278,10 +280,11 @@ async fn grid_row_add_date_cell_test() {
             date_field = Some(field.clone());
             NaiveDateTime::from_timestamp(123, 0);
             // The data should not be empty
-            assert!(builder.add_cell(&field.id, "".to_owned()).is_err());
-
-            assert!(builder.add_cell(&field.id, "123".to_owned()).is_ok());
-            assert!(builder.add_cell(&field.id, format!("{}", timestamp)).is_ok());
+            assert!(builder.add_cell(&field.id, "".to_string()).is_err());
+            assert!(builder.add_cell(&field.id, make_date_cell_string("123")).is_ok());
+            assert!(builder
+                .add_cell(&field.id, make_date_cell_string(&timestamp.to_string()))
+                .is_ok());
         }
     }
     let context = builder.build();
@@ -315,7 +318,7 @@ async fn grid_cell_update() {
                 let data = match field_meta.field_type {
                     FieldType::RichText => "".to_string(),
                     FieldType::Number => "123".to_string(),
-                    FieldType::DateTime => "123".to_string(),
+                    FieldType::DateTime => make_date_cell_string("123"),
                     FieldType::SingleSelect => {
                         let type_option = SingleSelectTypeOption::from(field_meta);
                         SelectOptionCellContentChangeset::from_insert(&type_option.options.first().unwrap().id).to_str()
@@ -363,3 +366,11 @@ async fn grid_cell_update() {
 
     test.run_scripts(scripts).await;
 }
+
+fn make_date_cell_string(s: &str) -> String {
+    serde_json::to_string(&DateCellContentChangeset {
+        date: Some(s.to_string()),
+        time: None,
+    })
+    .unwrap()
+}