Selaa lähdekoodia

Merge pull request #1182 from AppFlowy-IO/fix/switch_to_text_property

fix: display cell data after switching to text field
Nathan.fooo 2 vuotta sitten
vanhempi
commit
82182d7872

+ 5 - 8
frontend/app_flowy/lib/plugins/grid/presentation/widgets/cell/url_cell/url_cell.dart

@@ -97,7 +97,6 @@ class GridURLCell extends GridCellWidget {
 
 class _GridURLCellState extends GridCellState<GridURLCell> {
   final _popoverController = PopoverController();
-  GridURLCellController? _cellContext;
   late URLCellBloc _cellBloc;
 
   @override
@@ -132,6 +131,7 @@ class _GridURLCellState extends GridCellState<GridURLCell> {
             controller: _popoverController,
             constraints: BoxConstraints.loose(const Size(300, 160)),
             direction: PopoverDirection.bottomWithLeftAligned,
+            triggerActions: PopoverTriggerFlags.none,
             offset: const Offset(0, 20),
             child: SizedBox.expand(
               child: GestureDetector(
@@ -144,7 +144,8 @@ class _GridURLCellState extends GridCellState<GridURLCell> {
             ),
             popupBuilder: (BuildContext popoverContext) {
               return URLEditorPopover(
-                cellController: _cellContext!,
+                cellController: widget.cellControllerBuilder.build()
+                    as GridURLCellController,
               );
             },
             onClose: () {
@@ -166,17 +167,13 @@ class _GridURLCellState extends GridCellState<GridURLCell> {
     final uri = Uri.parse(url);
     if (url.isNotEmpty && await canLaunchUrl(uri)) {
       await launchUrl(uri);
-    } else {
-      _cellContext =
-          widget.cellControllerBuilder.build() as GridURLCellController;
-      widget.onCellEditing.value = true;
-      _popoverController.show();
     }
   }
 
   @override
   void requestBeginFocus() {
-    _openUrlOrEdit(_cellBloc.state.url);
+    widget.onCellEditing.value = true;
+    _popoverController.show();
   }
 
   @override

+ 8 - 1
frontend/rust-lib/flowy-grid/src/entities/cell_entities.rs

@@ -1,3 +1,4 @@
+use crate::entities::FieldType;
 use flowy_derive::ProtoBuf;
 use flowy_error::ErrorCode;
 use flowy_grid_data_model::parser::NotEmptyStr;
@@ -74,15 +75,20 @@ pub struct GridCellPB {
     #[pb(index = 1)]
     pub field_id: String,
 
+    // The data was encoded in field_type's data type
     #[pb(index = 2)]
     pub data: Vec<u8>,
+
+    #[pb(index = 3, one_of)]
+    pub field_type: Option<FieldType>,
 }
 
 impl GridCellPB {
-    pub fn new(field_id: &str, data: Vec<u8>) -> Self {
+    pub fn new(field_id: &str, field_type: FieldType, data: Vec<u8>) -> Self {
         Self {
             field_id: field_id.to_owned(),
             data,
+            field_type: Some(field_type),
         }
     }
 
@@ -90,6 +96,7 @@ impl GridCellPB {
         Self {
             field_id: field_id.to_owned(),
             data: vec![],
+            field_type: None,
         }
     }
 }

+ 59 - 6
frontend/rust-lib/flowy-grid/src/services/cell/cell_operation.rs

@@ -24,6 +24,13 @@ pub trait CellDisplayable<CD> {
         decoded_field_type: &FieldType,
         field_rev: &FieldRevision,
     ) -> FlowyResult<CellBytes>;
+
+    fn display_string(
+        &self,
+        cell_data: CellData<CD>,
+        decoded_field_type: &FieldType,
+        field_rev: &FieldRevision,
+    ) -> FlowyResult<String>;
 }
 
 // CD: Short for CellData. This type is the type return by apply_changeset function.
@@ -84,16 +91,16 @@ pub fn apply_cell_data_changeset<C: ToString, T: AsRef<FieldRevision>>(
 pub fn decode_any_cell_data<T: TryInto<AnyCellData, Error = FlowyError> + Debug>(
     data: T,
     field_rev: &FieldRevision,
-) -> CellBytes {
+) -> (FieldType, CellBytes) {
+    let to_field_type = field_rev.ty.into();
     match data.try_into() {
         Ok(any_cell_data) => {
             let AnyCellData { data, field_type } = any_cell_data;
-            let to_field_type = field_rev.ty.into();
             match try_decode_cell_data(data.into(), &field_type, &to_field_type, field_rev) {
-                Ok(cell_bytes) => cell_bytes,
+                Ok(cell_bytes) => (field_type, cell_bytes),
                 Err(e) => {
                     tracing::error!("Decode cell data failed, {:?}", e);
-                    CellBytes::default()
+                    (field_type, CellBytes::default())
                 }
             }
         }
@@ -101,12 +108,58 @@ pub fn decode_any_cell_data<T: TryInto<AnyCellData, Error = FlowyError> + Debug>
             // It's okay to ignore this error, because it's okay that the current cell can't
             // display the existing cell data. For example, the UI of the text cell will be blank if
             // the type of the data of cell is Number.
-            CellBytes::default()
+
+            (to_field_type, CellBytes::default())
+        }
+    }
+}
+
+pub fn decode_cell_data_to_string(
+    cell_data: CellData<String>,
+    from_field_type: &FieldType,
+    to_field_type: &FieldType,
+    field_rev: &FieldRevision,
+) -> FlowyResult<String> {
+    let cell_data = cell_data.try_into_inner()?;
+    let get_cell_display_str = || {
+        let field_type: FieldTypeRevision = to_field_type.into();
+        let result = match to_field_type {
+            FieldType::RichText => field_rev
+                .get_type_option::<RichTextTypeOptionPB>(field_type)?
+                .display_string(cell_data.into(), from_field_type, field_rev),
+            FieldType::Number => field_rev
+                .get_type_option::<NumberTypeOptionPB>(field_type)?
+                .display_string(cell_data.into(), from_field_type, field_rev),
+            FieldType::DateTime => field_rev
+                .get_type_option::<DateTypeOptionPB>(field_type)?
+                .display_string(cell_data.into(), from_field_type, field_rev),
+            FieldType::SingleSelect => field_rev
+                .get_type_option::<SingleSelectTypeOptionPB>(field_type)?
+                .display_string(cell_data.into(), from_field_type, field_rev),
+            FieldType::MultiSelect => field_rev
+                .get_type_option::<MultiSelectTypeOptionPB>(field_type)?
+                .display_string(cell_data.into(), from_field_type, field_rev),
+            FieldType::Checkbox => field_rev
+                .get_type_option::<CheckboxTypeOptionPB>(field_type)?
+                .display_string(cell_data.into(), from_field_type, field_rev),
+            FieldType::URL => field_rev
+                .get_type_option::<URLTypeOptionPB>(field_type)?
+                .display_string(cell_data.into(), from_field_type, field_rev),
+        };
+        Some(result)
+    };
+
+    match get_cell_display_str() {
+        Some(Ok(s)) => Ok(s),
+        Some(Err(err)) => {
+            tracing::error!("{:?}", err);
+            Ok("".to_owned())
         }
+        None => Ok("".to_owned()),
     }
 }
 
-/// Use the `to_field_type`'s TypeOption to parse the cell data into `from_field_type`'s data.
+/// Use the `to_field_type`'s TypeOption to parse the cell data into `from_field_type` type's data.
 ///
 /// Each `FieldType` has its corresponding `TypeOption` that implements the `CellDisplayable`
 /// and `CellDataOperation` traits.

+ 10 - 0
frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_type_option.rs

@@ -48,6 +48,16 @@ impl CellDisplayable<CheckboxCellData> for CheckboxTypeOptionPB {
         let cell_data = cell_data.try_into_inner()?;
         Ok(CellBytes::new(cell_data))
     }
+
+    fn display_string(
+        &self,
+        cell_data: CellData<CheckboxCellData>,
+        _decoded_field_type: &FieldType,
+        _field_rev: &FieldRevision,
+    ) -> FlowyResult<String> {
+        let cell_data = cell_data.try_into_inner()?;
+        Ok(cell_data.to_string())
+    }
 }
 
 impl CellDataOperation<CheckboxCellData, String> for CheckboxTypeOptionPB {

+ 11 - 0
frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_type_option.rs

@@ -127,6 +127,17 @@ impl CellDisplayable<DateTimestamp> for DateTypeOptionPB {
         let date_cell_data = self.today_desc_from_timestamp(timestamp);
         CellBytes::from(date_cell_data)
     }
+
+    fn display_string(
+        &self,
+        cell_data: CellData<DateTimestamp>,
+        _decoded_field_type: &FieldType,
+        _field_rev: &FieldRevision,
+    ) -> FlowyResult<String> {
+        let timestamp = cell_data.try_into_inner()?;
+        let date_cell_data = self.today_desc_from_timestamp(timestamp);
+        Ok(date_cell_data.date)
+    }
 }
 
 impl CellDataOperation<DateTimestamp, DateCellChangesetPB> for DateTypeOptionPB {

+ 28 - 7
frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option.rs

@@ -1,6 +1,6 @@
 use crate::entities::FieldType;
 use crate::impl_type_option;
-use crate::services::cell::{CellBytes, CellData, CellDataChangeset, CellDataOperation};
+use crate::services::cell::{CellBytes, CellData, CellDataChangeset, CellDataOperation, CellDisplayable};
 use crate::services::field::type_options::number_type_option::format::*;
 use crate::services::field::{BoxTypeOptionBuilder, NumberCellData, TypeOptionBuilder};
 use bytes::Bytes;
@@ -102,22 +102,43 @@ pub(crate) fn strip_currency_symbol<T: ToString>(s: T) -> String {
     s
 }
 
+impl CellDisplayable<String> for NumberTypeOptionPB {
+    fn display_data(
+        &self,
+        cell_data: CellData<String>,
+        _decoded_field_type: &FieldType,
+        _field_rev: &FieldRevision,
+    ) -> FlowyResult<CellBytes> {
+        let cell_data: String = cell_data.try_into_inner()?;
+        match self.format_cell_data(&cell_data) {
+            Ok(num) => Ok(CellBytes::new(num.to_string())),
+            Err(_) => Ok(CellBytes::default()),
+        }
+    }
+
+    fn display_string(
+        &self,
+        cell_data: CellData<String>,
+        _decoded_field_type: &FieldType,
+        _field_rev: &FieldRevision,
+    ) -> FlowyResult<String> {
+        let cell_data: String = cell_data.try_into_inner()?;
+        Ok(cell_data)
+    }
+}
+
 impl CellDataOperation<String, String> for NumberTypeOptionPB {
     fn decode_cell_data(
         &self,
         cell_data: CellData<String>,
         decoded_field_type: &FieldType,
-        _field_rev: &FieldRevision,
+        field_rev: &FieldRevision,
     ) -> FlowyResult<CellBytes> {
         if decoded_field_type.is_date() {
             return Ok(CellBytes::default());
         }
 
-        let cell_data: String = cell_data.try_into_inner()?;
-        match self.format_cell_data(&cell_data) {
-            Ok(num) => Ok(CellBytes::new(num.to_string())),
-            Err(_) => Ok(CellBytes::default()),
-        }
+        self.display_data(cell_data, decoded_field_type, field_rev)
     }
 
     fn apply_changeset(

+ 15 - 0
frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_option.rs

@@ -120,6 +120,21 @@ where
     ) -> FlowyResult<CellBytes> {
         CellBytes::from(self.selected_select_option(cell_data))
     }
+
+    fn display_string(
+        &self,
+        cell_data: CellData<SelectOptionIds>,
+        _decoded_field_type: &FieldType,
+        _field_rev: &FieldRevision,
+    ) -> FlowyResult<String> {
+        Ok(self
+            .selected_select_option(cell_data)
+            .select_options
+            .into_iter()
+            .map(|option| option.name)
+            .collect::<Vec<String>>()
+            .join(SELECTION_IDS_SEPARATOR))
+    }
 }
 
 pub fn select_option_operation(field_rev: &FieldRevision) -> FlowyResult<Box<dyn SelectOptionOperation>> {

+ 6 - 6
frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/text_tests.rs

@@ -17,10 +17,10 @@ mod tests {
             type_option
                 .decode_cell_data(1647251762.into(), &field_type, &field_rev)
                 .unwrap()
-                .parser::<DateCellDataParser>()
+                .parser::<TextCellDataParser>()
                 .unwrap()
-                .date,
-            "Mar 14,2022".to_owned()
+                .as_ref(),
+            "Mar 14,2022"
         );
     }
 
@@ -40,10 +40,10 @@ mod tests {
             type_option
                 .decode_cell_data(option_id.into(), &field_type, &field_rev)
                 .unwrap()
-                .parser::<SelectOptionCellDataParser>()
+                .parser::<TextCellDataParser>()
                 .unwrap()
-                .select_options,
-            vec![done_option],
+                .to_string(),
+            done_option.name,
         );
     }
 }

+ 29 - 3
frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/text_type_option.rs

@@ -1,8 +1,8 @@
 use crate::entities::FieldType;
 use crate::impl_type_option;
 use crate::services::cell::{
-    try_decode_cell_data, CellBytes, CellBytesParser, CellData, CellDataChangeset, CellDataOperation, CellDisplayable,
-    FromCellString,
+    decode_cell_data_to_string, CellBytes, CellBytesParser, CellData, CellDataChangeset, CellDataOperation,
+    CellDisplayable, FromCellString,
 };
 use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder};
 use bytes::Bytes;
@@ -44,6 +44,16 @@ impl CellDisplayable<String> for RichTextTypeOptionPB {
         let cell_str: String = cell_data.try_into_inner()?;
         Ok(CellBytes::new(cell_str))
     }
+
+    fn display_string(
+        &self,
+        cell_data: CellData<String>,
+        _decoded_field_type: &FieldType,
+        _field_rev: &FieldRevision,
+    ) -> FlowyResult<String> {
+        let cell_str: String = cell_data.try_into_inner()?;
+        Ok(cell_str)
+    }
 }
 
 impl CellDataOperation<String, String> for RichTextTypeOptionPB {
@@ -57,8 +67,10 @@ impl CellDataOperation<String, String> for RichTextTypeOptionPB {
             || decoded_field_type.is_single_select()
             || decoded_field_type.is_multi_select()
             || decoded_field_type.is_number()
+            || decoded_field_type.is_url()
         {
-            try_decode_cell_data(cell_data, decoded_field_type, decoded_field_type, field_rev)
+            let s = decode_cell_data_to_string(cell_data, decoded_field_type, decoded_field_type, field_rev);
+            Ok(CellBytes::new(s.unwrap_or_else(|_| "".to_owned())))
         } else {
             self.display_data(cell_data, decoded_field_type, field_rev)
         }
@@ -85,6 +97,14 @@ impl AsRef<str> for TextCellData {
     }
 }
 
+impl std::ops::Deref for TextCellData {
+    type Target = String;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
 impl FromCellString for TextCellData {
     fn from_cell_str(s: &str) -> FlowyResult<Self>
     where
@@ -94,6 +114,12 @@ impl FromCellString for TextCellData {
     }
 }
 
+impl ToString for TextCellData {
+    fn to_string(&self) -> String {
+        self.0.clone()
+    }
+}
+
 pub struct TextCellDataParser();
 impl CellBytesParser for TextCellDataParser {
     type Object = TextCellData;

+ 10 - 0
frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_type_option.rs

@@ -42,6 +42,16 @@ impl CellDisplayable<URLCellDataPB> for URLTypeOptionPB {
         let cell_data: URLCellDataPB = cell_data.try_into_inner()?;
         CellBytes::from(cell_data)
     }
+
+    fn display_string(
+        &self,
+        cell_data: CellData<URLCellDataPB>,
+        _decoded_field_type: &FieldType,
+        _field_rev: &FieldRevision,
+    ) -> FlowyResult<String> {
+        let cell_data: URLCellDataPB = cell_data.try_into_inner()?;
+        Ok(cell_data.content)
+    }
 }
 
 impl CellDataOperation<URLCellDataPB, String> for URLTypeOptionPB {

+ 7 - 3
frontend/rust-lib/flowy-grid/src/services/grid_editor.rs

@@ -435,14 +435,18 @@ impl GridRevisionEditor {
     }
 
     pub async fn get_cell(&self, params: &GridCellIdParams) -> Option<GridCellPB> {
-        let cell_bytes = self.get_cell_bytes(params).await?;
-        Some(GridCellPB::new(&params.field_id, cell_bytes.to_vec()))
+        let (field_type, cell_bytes) = self.decode_any_cell_data(params).await?;
+        Some(GridCellPB::new(&params.field_id, field_type, cell_bytes.to_vec()))
     }
 
     pub async fn get_cell_bytes(&self, params: &GridCellIdParams) -> Option<CellBytes> {
+        let (_, cell_data) = self.decode_any_cell_data(params).await?;
+        Some(cell_data)
+    }
+
+    async fn decode_any_cell_data(&self, params: &GridCellIdParams) -> Option<(FieldType, CellBytes)> {
         let field_rev = self.get_field_rev(&params.field_id).await?;
         let row_rev = self.block_manager.get_row_rev(&params.row_id).await.ok()??;
-
         let cell_rev = row_rev.cells.get(&params.field_id)?.clone();
         Some(decode_any_cell_data(cell_rev.data, &field_rev))
     }

+ 4 - 4
frontend/rust-lib/flowy-grid/src/services/group/controller.rs

@@ -205,7 +205,7 @@ where
 
             if let Some(cell_rev) = cell_rev {
                 let mut grouped_rows: Vec<GroupedRow> = vec![];
-                let cell_bytes = decode_any_cell_data(cell_rev.data, field_rev);
+                let cell_bytes = decode_any_cell_data(cell_rev.data, field_rev).1;
                 let cell_data = cell_bytes.parser::<P>()?;
                 for group in self.group_ctx.groups() {
                     if self.can_group(&group.filter_content, &cell_data) {
@@ -244,7 +244,7 @@ where
         field_rev: &FieldRevision,
     ) -> FlowyResult<Vec<GroupChangesetPB>> {
         if let Some(cell_rev) = row_rev.cells.get(&self.field_id) {
-            let cell_bytes = decode_any_cell_data(cell_rev.data.clone(), field_rev);
+            let cell_bytes = decode_any_cell_data(cell_rev.data.clone(), field_rev).1;
             let cell_data = cell_bytes.parser::<P>()?;
             let mut changesets = self.add_row_if_match(row_rev, &cell_data);
             let default_group_changeset = self.update_default_group(row_rev, &changesets);
@@ -265,7 +265,7 @@ where
     ) -> FlowyResult<Vec<GroupChangesetPB>> {
         // if the cell_rev is none, then the row must be crated from the default group.
         if let Some(cell_rev) = row_rev.cells.get(&self.field_id) {
-            let cell_bytes = decode_any_cell_data(cell_rev.data.clone(), field_rev);
+            let cell_bytes = decode_any_cell_data(cell_rev.data.clone(), field_rev).1;
             let cell_data = cell_bytes.parser::<P>()?;
             Ok(self.remove_row_if_match(row_rev, &cell_data))
         } else {
@@ -285,7 +285,7 @@ where
         };
 
         if let Some(cell_rev) = cell_rev {
-            let cell_bytes = decode_any_cell_data(cell_rev.data, context.field_rev);
+            let cell_bytes = decode_any_cell_data(cell_rev.data, context.field_rev).1;
             let cell_data = cell_bytes.parser::<P>()?;
             Ok(self.move_row(&cell_data, context))
         } else {