mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
refactor: checkbox field type (#4682)
This commit is contained in:
parent
a6c6aa819c
commit
334aedd6c6
@ -1,6 +1,7 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:appflowy/plugins/database/application/cell/cell_controller_builder.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
@ -86,7 +87,6 @@ class CheckboxCellState with _$CheckboxCellState {
|
||||
}
|
||||
}
|
||||
|
||||
bool _isSelected(String? cellData) {
|
||||
// The backend use "Yes" and "No" to represent the checkbox cell data.
|
||||
return cellData == "Yes";
|
||||
bool _isSelected(CheckboxCellDataPB? cellData) {
|
||||
return cellData != null && cellData.isChecked;
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ import 'cell_data_loader.dart';
|
||||
import 'cell_data_persistence.dart';
|
||||
|
||||
typedef TextCellController = CellController<String, String>;
|
||||
typedef CheckboxCellController = CellController<String, String>;
|
||||
typedef CheckboxCellController = CellController<CheckboxCellDataPB, String>;
|
||||
typedef NumberCellController = CellController<String, String>;
|
||||
typedef SelectOptionCellController
|
||||
= CellController<SelectOptionCellDataPB, String>;
|
||||
@ -24,13 +24,13 @@ CellController makeCellController(
|
||||
final fieldType = fieldController.getField(cellContext.fieldId)!.fieldType;
|
||||
switch (fieldType) {
|
||||
case FieldType.Checkbox:
|
||||
return TextCellController(
|
||||
return CheckboxCellController(
|
||||
viewId: viewId,
|
||||
fieldController: fieldController,
|
||||
cellContext: cellContext,
|
||||
rowCache: rowCache,
|
||||
cellDataLoader: CellDataLoader(
|
||||
parser: StringCellDataParser(),
|
||||
parser: CheckboxCellDataParser(),
|
||||
),
|
||||
cellDataPersistence: TextCellDataPersistence(),
|
||||
);
|
||||
|
@ -66,6 +66,16 @@ class StringCellDataParser implements CellDataParser<String> {
|
||||
}
|
||||
}
|
||||
|
||||
class CheckboxCellDataParser implements CellDataParser<CheckboxCellDataPB> {
|
||||
@override
|
||||
CheckboxCellDataPB? parserData(List<int> data) {
|
||||
if (data.isEmpty) {
|
||||
return null;
|
||||
}
|
||||
return CheckboxCellDataPB.fromBuffer(data);
|
||||
}
|
||||
}
|
||||
|
||||
class NumberCellDataParser implements CellDataParser<String> {
|
||||
@override
|
||||
String? parserData(List<int> data) {
|
||||
|
@ -1,5 +1,6 @@
|
||||
import {
|
||||
CellPB,
|
||||
CheckboxCellDataPB,
|
||||
ChecklistCellDataPB,
|
||||
DateCellDataPB,
|
||||
FieldType,
|
||||
@ -28,7 +29,7 @@ export interface NumberCell extends Cell {
|
||||
|
||||
export interface CheckboxCell extends Cell {
|
||||
fieldType: FieldType.Checkbox;
|
||||
data: 'Yes' | 'No';
|
||||
data: boolean;
|
||||
}
|
||||
|
||||
export interface UrlCell extends Cell {
|
||||
@ -99,6 +100,10 @@ export type UndeterminedCell =
|
||||
| UrlCell
|
||||
| ChecklistCell;
|
||||
|
||||
const pbToCheckboxCellData = (pb: CheckboxCellDataPB): boolean => (
|
||||
pb.is_checked
|
||||
);
|
||||
|
||||
const pbToDateTimeCellData = (pb: DateCellDataPB): DateTimeCellData => ({
|
||||
date: pb.date,
|
||||
time: pb.time,
|
||||
@ -136,8 +141,9 @@ function bytesToCellData(bytes: Uint8Array, fieldType: FieldType) {
|
||||
switch (fieldType) {
|
||||
case FieldType.RichText:
|
||||
case FieldType.Number:
|
||||
case FieldType.Checkbox:
|
||||
return new TextDecoder().decode(bytes);
|
||||
case FieldType.Checkbox:
|
||||
return pbToCheckboxCellData(CheckboxCellDataPB.deserialize(bytes));
|
||||
case FieldType.DateTime:
|
||||
return pbToDateTimeCellData(DateCellDataPB.deserialize(bytes));
|
||||
case FieldType.LastEditedTime:
|
||||
|
@ -98,7 +98,7 @@ function pbToSelectTypeOption(pb: SingleSelectTypeOptionPB | MultiSelectTypeOpti
|
||||
|
||||
function pbToCheckboxTypeOption(pb: CheckboxTypeOptionPB): CheckboxTypeOption {
|
||||
return {
|
||||
isSelected: pb.is_selected,
|
||||
isSelected: pb.dummy_field,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@ export const CheckboxCell: FC<{
|
||||
cell: CheckboxCellType;
|
||||
}> = ({ field, cell }) => {
|
||||
const viewId = useViewId();
|
||||
const checked = cell.data === 'Yes';
|
||||
const checked = cell.data;
|
||||
|
||||
const handleClick = useCallback(() => {
|
||||
void cellService.updateCell(viewId, cell.rowId, field.id, !checked ? 'Yes' : 'No');
|
||||
|
@ -5,7 +5,7 @@ use bytes::Bytes;
|
||||
use event_integration::event_builder::EventBuilder;
|
||||
use event_integration::EventIntegrationTest;
|
||||
use flowy_database2::entities::{
|
||||
CellChangesetPB, CellIdPB, ChecklistCellDataChangesetPB, DatabaseLayoutPB,
|
||||
CellChangesetPB, CellIdPB, CheckboxCellDataPB, ChecklistCellDataChangesetPB, DatabaseLayoutPB,
|
||||
DatabaseSettingChangesetPB, DatabaseViewIdPB, DateChangesetPB, FieldType, OrderObjectPositionPB,
|
||||
SelectOptionCellDataPB, UpdateRowMetaChangesetPB,
|
||||
};
|
||||
@ -476,8 +476,8 @@ async fn update_checkbox_cell_event_test() {
|
||||
assert!(error.is_none());
|
||||
|
||||
let cell = test.get_cell(&grid_view.id, &row_id, &field_id).await;
|
||||
let output = String::from_utf8(cell.data).unwrap();
|
||||
assert_eq!(output, "Yes");
|
||||
let output = CheckboxCellDataPB::try_from(Bytes::from(cell.data)).unwrap();
|
||||
assert!(output.is_checked);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,24 +1,33 @@
|
||||
use crate::services::field::CheckboxTypeOption;
|
||||
use flowy_derive::ProtoBuf;
|
||||
|
||||
#[derive(Default, Debug, Clone, ProtoBuf)]
|
||||
pub struct CheckboxCellDataPB {
|
||||
#[pb(index = 1)]
|
||||
pub is_checked: bool,
|
||||
}
|
||||
|
||||
impl CheckboxCellDataPB {
|
||||
pub fn new(is_checked: bool) -> Self {
|
||||
Self { is_checked }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, ProtoBuf)]
|
||||
pub struct CheckboxTypeOptionPB {
|
||||
/// unused
|
||||
#[pb(index = 1)]
|
||||
pub is_selected: bool,
|
||||
pub dummy_field: bool,
|
||||
}
|
||||
|
||||
impl From<CheckboxTypeOption> for CheckboxTypeOptionPB {
|
||||
fn from(data: CheckboxTypeOption) -> Self {
|
||||
Self {
|
||||
is_selected: data.is_selected,
|
||||
}
|
||||
fn from(_type_option: CheckboxTypeOption) -> Self {
|
||||
Self { dummy_field: false }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CheckboxTypeOptionPB> for CheckboxTypeOption {
|
||||
fn from(data: CheckboxTypeOptionPB) -> Self {
|
||||
Self {
|
||||
is_selected: data.is_selected,
|
||||
}
|
||||
fn from(_type_option: CheckboxTypeOptionPB) -> Self {
|
||||
Self()
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ use collab_database::rows::{get_field_type_from_cell, Cell, Cells};
|
||||
|
||||
use flowy_error::{ErrorCode, FlowyError, FlowyResult};
|
||||
|
||||
use crate::entities::FieldType;
|
||||
use crate::entities::{CheckboxCellDataPB, FieldType};
|
||||
use crate::services::cell::{CellCache, CellProtobufBlob};
|
||||
use crate::services::field::checklist_type_option::ChecklistCellChangeset;
|
||||
use crate::services::field::*;
|
||||
@ -203,8 +203,8 @@ pub fn insert_url_cell(url: String, field: &Field) -> Cell {
|
||||
apply_cell_changeset(url, None, field, None).unwrap()
|
||||
}
|
||||
|
||||
pub fn insert_checkbox_cell(is_check: bool, field: &Field) -> Cell {
|
||||
let s = if is_check {
|
||||
pub fn insert_checkbox_cell(is_checked: bool, field: &Field) -> Cell {
|
||||
let s = if is_checked {
|
||||
CHECK.to_string()
|
||||
} else {
|
||||
UNCHECK.to_string()
|
||||
@ -343,8 +343,8 @@ impl<'a> CellBuilder<'a> {
|
||||
}
|
||||
},
|
||||
FieldType::Checkbox => {
|
||||
if let Ok(value) = CheckboxCellData::from_cell_str(&cell_str) {
|
||||
cells.insert(field_id, insert_checkbox_cell(value.into_inner(), field));
|
||||
if let Ok(value) = CheckboxCellDataPB::from_cell_str(&cell_str) {
|
||||
cells.insert(field_id, insert_checkbox_cell(value.is_checked, field));
|
||||
}
|
||||
},
|
||||
FieldType::URL => {
|
||||
@ -399,13 +399,13 @@ impl<'a> CellBuilder<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert_checkbox_cell(&mut self, field_id: &str, is_check: bool) {
|
||||
pub fn insert_checkbox_cell(&mut self, field_id: &str, is_checked: bool) {
|
||||
match self.field_maps.get(&field_id.to_owned()) {
|
||||
None => tracing::warn!("Can't find the checkbox field with id: {}", field_id),
|
||||
Some(field) => {
|
||||
self
|
||||
.cells
|
||||
.insert(field_id.to_owned(), insert_checkbox_cell(is_check, field));
|
||||
.insert(field_id.to_owned(), insert_checkbox_cell(is_checked, field));
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -1,20 +1,17 @@
|
||||
use crate::entities::{CheckboxFilterConditionPB, CheckboxFilterPB};
|
||||
use crate::services::field::CheckboxCellData;
|
||||
use crate::entities::{CheckboxCellDataPB, CheckboxFilterConditionPB, CheckboxFilterPB};
|
||||
|
||||
impl CheckboxFilterPB {
|
||||
pub fn is_visible(&self, cell_data: &CheckboxCellData) -> bool {
|
||||
let is_check = cell_data.is_check();
|
||||
pub fn is_visible(&self, cell_data: &CheckboxCellDataPB) -> bool {
|
||||
match self.condition {
|
||||
CheckboxFilterConditionPB::IsChecked => is_check,
|
||||
CheckboxFilterConditionPB::IsUnChecked => !is_check,
|
||||
CheckboxFilterConditionPB::IsChecked => cell_data.is_checked,
|
||||
CheckboxFilterConditionPB::IsUnChecked => !cell_data.is_checked,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::entities::{CheckboxFilterConditionPB, CheckboxFilterPB};
|
||||
use crate::services::field::CheckboxCellData;
|
||||
use crate::entities::{CheckboxCellDataPB, CheckboxFilterConditionPB, CheckboxFilterPB};
|
||||
use std::str::FromStr;
|
||||
|
||||
#[test]
|
||||
@ -27,8 +24,9 @@ mod tests {
|
||||
("yes", true),
|
||||
("false", false),
|
||||
("no", false),
|
||||
("", false),
|
||||
] {
|
||||
let data = CheckboxCellData::from_str(value).unwrap();
|
||||
let data = CheckboxCellDataPB::from_str(value).unwrap();
|
||||
assert_eq!(checkbox_filter.is_visible(&data), visible);
|
||||
}
|
||||
}
|
||||
@ -43,8 +41,9 @@ mod tests {
|
||||
("no", true),
|
||||
("true", false),
|
||||
("yes", false),
|
||||
("", true),
|
||||
] {
|
||||
let data = CheckboxCellData::from_str(value).unwrap();
|
||||
let data = CheckboxCellDataPB::from_str(value).unwrap();
|
||||
assert_eq!(checkbox_filter.is_visible(&data), visible);
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
mod tests {
|
||||
use collab_database::fields::Field;
|
||||
|
||||
use crate::entities::CheckboxCellDataPB;
|
||||
use crate::entities::FieldType;
|
||||
use crate::services::cell::CellDataDecoder;
|
||||
use crate::services::cell::FromCellString;
|
||||
@ -27,9 +28,9 @@ mod tests {
|
||||
assert_checkbox(&type_option, "NO", UNCHECK, &field_type, &field_rev);
|
||||
assert_checkbox(&type_option, "0", UNCHECK, &field_type, &field_rev);
|
||||
|
||||
// the checkout value will be empty if the value is letters or empty string
|
||||
assert_checkbox(&type_option, "abc", "", &field_type, &field_rev);
|
||||
assert_checkbox(&type_option, "", "", &field_type, &field_rev);
|
||||
// the checkout value will be uncheck as well if the value is letters or empty string
|
||||
assert_checkbox(&type_option, "abc", UNCHECK, &field_type, &field_rev);
|
||||
assert_checkbox(&type_option, "", UNCHECK, &field_type, &field_rev);
|
||||
}
|
||||
|
||||
fn assert_checkbox(
|
||||
@ -42,7 +43,7 @@ mod tests {
|
||||
assert_eq!(
|
||||
type_option
|
||||
.decode_cell(
|
||||
&CheckboxCellData::from_cell_str(input_str).unwrap().into(),
|
||||
&CheckboxCellDataPB::from_cell_str(input_str).unwrap().into(),
|
||||
field_type,
|
||||
field
|
||||
)
|
||||
|
@ -1,30 +1,27 @@
|
||||
use std::cmp::Ordering;
|
||||
use std::str::FromStr;
|
||||
|
||||
use collab::core::any_map::AnyMapExtension;
|
||||
use collab_database::fields::{Field, TypeOptionData, TypeOptionDataBuilder};
|
||||
use collab_database::rows::Cell;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use flowy_error::FlowyResult;
|
||||
|
||||
use crate::entities::{CheckboxFilterPB, FieldType};
|
||||
use crate::entities::{CheckboxCellDataPB, CheckboxFilterPB, FieldType};
|
||||
use crate::services::cell::{CellDataChangeset, CellDataDecoder};
|
||||
use crate::services::field::{
|
||||
CheckboxCellData, TypeOption, TypeOptionCellDataCompare, TypeOptionCellDataFilter,
|
||||
TypeOptionCellDataSerde, TypeOptionTransform,
|
||||
TypeOption, TypeOptionCellDataCompare, TypeOptionCellDataFilter, TypeOptionCellDataSerde,
|
||||
TypeOptionTransform,
|
||||
};
|
||||
use crate::services::sort::SortCondition;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||
pub struct CheckboxTypeOption {
|
||||
pub is_selected: bool,
|
||||
}
|
||||
pub struct CheckboxTypeOption();
|
||||
|
||||
impl TypeOption for CheckboxTypeOption {
|
||||
type CellData = CheckboxCellData;
|
||||
type CellData = CheckboxCellDataPB;
|
||||
type CellChangeset = CheckboxCellChangeset;
|
||||
type CellProtobufType = CheckboxCellData;
|
||||
type CellProtobufType = CheckboxCellDataPB;
|
||||
type CellFilter = CheckboxFilterPB;
|
||||
}
|
||||
|
||||
@ -47,7 +44,7 @@ impl TypeOptionTransform for CheckboxTypeOption {
|
||||
_field: &Field,
|
||||
) -> Option<<Self as TypeOption>::CellData> {
|
||||
if transformed_field_type.is_text() {
|
||||
Some(CheckboxCellData::from(cell))
|
||||
Some(CheckboxCellDataPB::from(cell))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -55,17 +52,14 @@ impl TypeOptionTransform for CheckboxTypeOption {
|
||||
}
|
||||
|
||||
impl From<TypeOptionData> for CheckboxTypeOption {
|
||||
fn from(data: TypeOptionData) -> Self {
|
||||
let is_selected = data.get_bool_value("is_selected").unwrap_or(false);
|
||||
CheckboxTypeOption { is_selected }
|
||||
fn from(_data: TypeOptionData) -> Self {
|
||||
Self()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CheckboxTypeOption> for TypeOptionData {
|
||||
fn from(data: CheckboxTypeOption) -> Self {
|
||||
TypeOptionDataBuilder::new()
|
||||
.insert_bool_value("is_selected", data.is_selected)
|
||||
.build()
|
||||
fn from(_data: CheckboxTypeOption) -> Self {
|
||||
TypeOptionDataBuilder::new().build()
|
||||
}
|
||||
}
|
||||
|
||||
@ -78,7 +72,7 @@ impl TypeOptionCellDataSerde for CheckboxTypeOption {
|
||||
}
|
||||
|
||||
fn parse_cell(&self, cell: &Cell) -> FlowyResult<<Self as TypeOption>::CellData> {
|
||||
Ok(CheckboxCellData::from(cell))
|
||||
Ok(CheckboxCellDataPB::from(cell))
|
||||
}
|
||||
}
|
||||
|
||||
@ -105,7 +99,7 @@ impl CellDataDecoder for CheckboxTypeOption {
|
||||
|
||||
fn numeric_cell(&self, cell: &Cell) -> Option<f64> {
|
||||
let cell_data = self.parse_cell(cell).ok()?;
|
||||
if cell_data.is_check() {
|
||||
if cell_data.is_checked {
|
||||
Some(1.0)
|
||||
} else {
|
||||
Some(0.0)
|
||||
@ -121,7 +115,7 @@ impl CellDataChangeset for CheckboxTypeOption {
|
||||
changeset: <Self as TypeOption>::CellChangeset,
|
||||
_cell: Option<Cell>,
|
||||
) -> FlowyResult<(Cell, <Self as TypeOption>::CellData)> {
|
||||
let checkbox_cell_data = CheckboxCellData::from_str(&changeset)?;
|
||||
let checkbox_cell_data = CheckboxCellDataPB::from_str(&changeset)?;
|
||||
Ok((checkbox_cell_data.clone().into(), checkbox_cell_data))
|
||||
}
|
||||
}
|
||||
@ -147,7 +141,7 @@ impl TypeOptionCellDataCompare for CheckboxTypeOption {
|
||||
other_cell_data: &<Self as TypeOption>::CellData,
|
||||
sort_condition: SortCondition,
|
||||
) -> Ordering {
|
||||
let order = cell_data.is_check().cmp(&other_cell_data.is_check());
|
||||
let order = cell_data.is_checked.cmp(&other_cell_data.is_checked);
|
||||
sort_condition.evaluate_order(order)
|
||||
}
|
||||
|
||||
@ -164,10 +158,10 @@ impl TypeOptionCellDataCompare for CheckboxTypeOption {
|
||||
sort_condition: SortCondition,
|
||||
) -> Ordering {
|
||||
match (cell_data, other_cell_data) {
|
||||
(None, Some(right_cell_data)) if right_cell_data.is_check() => {
|
||||
(None, Some(right_cell_data)) if right_cell_data.is_checked => {
|
||||
sort_condition.evaluate_order(Ordering::Less)
|
||||
},
|
||||
(Some(left_cell_data), None) if left_cell_data.is_check() => {
|
||||
(Some(left_cell_data), None) if left_cell_data.is_checked => {
|
||||
sort_condition.evaluate_order(Ordering::Greater)
|
||||
},
|
||||
_ => Ordering::Equal,
|
||||
|
@ -3,93 +3,53 @@ use std::str::FromStr;
|
||||
use bytes::Bytes;
|
||||
use collab::core::any_map::AnyMapExtension;
|
||||
use collab_database::rows::{new_cell_builder, Cell};
|
||||
use protobuf::ProtobufError;
|
||||
|
||||
use flowy_error::{FlowyError, FlowyResult};
|
||||
|
||||
use crate::entities::FieldType;
|
||||
use crate::entities::{CheckboxCellDataPB, FieldType};
|
||||
use crate::services::cell::{CellProtobufBlobParser, DecodedCellData, FromCellString};
|
||||
use crate::services::field::{TypeOptionCellData, CELL_DATA};
|
||||
|
||||
pub const CHECK: &str = "Yes";
|
||||
pub const UNCHECK: &str = "No";
|
||||
|
||||
#[derive(Default, Debug, Clone)]
|
||||
pub struct CheckboxCellData(pub String);
|
||||
|
||||
impl CheckboxCellData {
|
||||
pub fn into_inner(self) -> bool {
|
||||
self.is_check()
|
||||
}
|
||||
|
||||
pub fn is_check(&self) -> bool {
|
||||
self.0 == CHECK
|
||||
}
|
||||
|
||||
pub fn is_uncheck(&self) -> bool {
|
||||
self.0 == UNCHECK
|
||||
}
|
||||
}
|
||||
|
||||
impl TypeOptionCellData for CheckboxCellData {
|
||||
impl TypeOptionCellData for CheckboxCellDataPB {
|
||||
fn is_cell_empty(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8]> for CheckboxCellData {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
self.0.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Cell> for CheckboxCellData {
|
||||
impl From<&Cell> for CheckboxCellDataPB {
|
||||
fn from(cell: &Cell) -> Self {
|
||||
let value = cell.get_str_value(CELL_DATA).unwrap_or_default();
|
||||
CheckboxCellData::from_cell_str(&value).unwrap_or_default()
|
||||
CheckboxCellDataPB::from_cell_str(&value).unwrap_or_default()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CheckboxCellData> for Cell {
|
||||
fn from(data: CheckboxCellData) -> Self {
|
||||
impl From<CheckboxCellDataPB> for Cell {
|
||||
fn from(data: CheckboxCellDataPB) -> Self {
|
||||
new_cell_builder(FieldType::Checkbox)
|
||||
.insert_str_value(CELL_DATA, data.to_string())
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for CheckboxCellData {
|
||||
impl FromStr for CheckboxCellDataPB {
|
||||
type Err = FlowyError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let lower_case_str: &str = &s.to_lowercase();
|
||||
let val = match lower_case_str {
|
||||
"1" => Some(true),
|
||||
"true" => Some(true),
|
||||
"yes" => Some(true),
|
||||
"0" => Some(false),
|
||||
"false" => Some(false),
|
||||
"no" => Some(false),
|
||||
_ => None,
|
||||
let is_checked = match lower_case_str {
|
||||
"1" | "true" | "yes" => true,
|
||||
"0" | "false" | "no" => false,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
match val {
|
||||
Some(true) => Ok(Self(CHECK.to_string())),
|
||||
Some(false) => Ok(Self(UNCHECK.to_string())),
|
||||
None => Ok(Self("".to_string())),
|
||||
}
|
||||
Ok(Self::new(is_checked))
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::TryFrom<CheckboxCellData> for Bytes {
|
||||
type Error = ProtobufError;
|
||||
|
||||
fn try_from(value: CheckboxCellData) -> Result<Self, Self::Error> {
|
||||
Ok(Bytes::from(value.0))
|
||||
}
|
||||
}
|
||||
|
||||
impl FromCellString for CheckboxCellData {
|
||||
impl FromCellString for CheckboxCellDataPB {
|
||||
fn from_cell_str(s: &str) -> FlowyResult<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
@ -98,27 +58,29 @@ impl FromCellString for CheckboxCellData {
|
||||
}
|
||||
}
|
||||
|
||||
impl ToString for CheckboxCellData {
|
||||
impl ToString for CheckboxCellDataPB {
|
||||
fn to_string(&self) -> String {
|
||||
self.0.clone()
|
||||
if self.is_checked {
|
||||
CHECK.to_string()
|
||||
} else {
|
||||
UNCHECK.to_string()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DecodedCellData for CheckboxCellData {
|
||||
type Object = CheckboxCellData;
|
||||
impl DecodedCellData for CheckboxCellDataPB {
|
||||
type Object = CheckboxCellDataPB;
|
||||
|
||||
fn is_empty(&self) -> bool {
|
||||
self.0.is_empty()
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CheckboxCellDataParser();
|
||||
impl CellProtobufBlobParser for CheckboxCellDataParser {
|
||||
type Object = CheckboxCellData;
|
||||
type Object = CheckboxCellDataPB;
|
||||
|
||||
fn parser(bytes: &Bytes) -> FlowyResult<Self::Object> {
|
||||
match String::from_utf8(bytes.to_vec()) {
|
||||
Ok(s) => CheckboxCellData::from_cell_str(&s),
|
||||
Err(_) => Ok(CheckboxCellData("".to_string())),
|
||||
}
|
||||
CheckboxCellDataPB::try_from(bytes.as_ref()).or_else(|_| Ok(CheckboxCellDataPB::default()))
|
||||
}
|
||||
}
|
||||
|
@ -190,7 +190,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn multi_select_transform_with_checkbox_type_option_test() {
|
||||
let checkbox_type_option = CheckboxTypeOption { is_selected: false };
|
||||
let checkbox_type_option = CheckboxTypeOption();
|
||||
let mut multi_select = MultiSelectTypeOption::default();
|
||||
multi_select.transform_type_option(FieldType::Checkbox, checkbox_type_option.clone().into());
|
||||
debug_assert_eq!(multi_select.options.len(), 2);
|
||||
|
@ -5,15 +5,15 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use flowy_error::{internal_error, ErrorCode, FlowyResult};
|
||||
|
||||
use crate::entities::{FieldType, SelectOptionCellDataPB};
|
||||
use crate::entities::{CheckboxCellDataPB, FieldType, SelectOptionCellDataPB};
|
||||
use crate::services::cell::{
|
||||
CellDataDecoder, CellProtobufBlobParser, DecodedCellData, FromCellChangeset, ToCellChangeset,
|
||||
};
|
||||
use crate::services::field::selection_type_option::type_option_transform::SelectOptionTypeOptionTransformHelper;
|
||||
use crate::services::field::{
|
||||
make_selected_options, CheckboxCellData, MultiSelectTypeOption, SelectOption,
|
||||
SelectOptionCellData, SelectOptionColor, SelectOptionIds, SingleSelectTypeOption, TypeOption,
|
||||
TypeOptionCellDataSerde, TypeOptionTransform, SELECTION_IDS_SEPARATOR,
|
||||
make_selected_options, MultiSelectTypeOption, SelectOption, SelectOptionCellData,
|
||||
SelectOptionColor, SelectOptionIds, SingleSelectTypeOption, TypeOption, TypeOptionCellDataSerde,
|
||||
TypeOptionTransform, SELECTION_IDS_SEPARATOR,
|
||||
};
|
||||
|
||||
/// Defines the shared actions used by SingleSelect or Multi-Select.
|
||||
@ -104,7 +104,7 @@ where
|
||||
None
|
||||
},
|
||||
FieldType::Checkbox => {
|
||||
let cell_content = CheckboxCellData::from(cell).to_string();
|
||||
let cell_content = CheckboxCellDataPB::from(cell).to_string();
|
||||
let mut transformed_ids = Vec::new();
|
||||
let options = self.options();
|
||||
if let Some(option) = options.iter().find(|option| option.name == cell_content) {
|
||||
|
@ -47,7 +47,7 @@ impl GroupCustomize for CheckboxGroupController {
|
||||
content: &str,
|
||||
cell_data: &<Self::GroupTypeOption as TypeOption>::CellData,
|
||||
) -> bool {
|
||||
if cell_data.is_check() {
|
||||
if cell_data.is_checked {
|
||||
content == CHECK
|
||||
} else {
|
||||
content == UNCHECK
|
||||
@ -64,7 +64,7 @@ impl GroupCustomize for CheckboxGroupController {
|
||||
let mut changeset = GroupRowsNotificationPB::new(group.id.clone());
|
||||
let is_not_contained = !group.contains_row(&row_detail.row.id);
|
||||
if group.id == CHECK {
|
||||
if cell_data.is_uncheck() {
|
||||
if !cell_data.is_checked {
|
||||
// Remove the row if the group.id is CHECK but the cell_data is UNCHECK
|
||||
changeset
|
||||
.deleted_rows
|
||||
@ -82,7 +82,7 @@ impl GroupCustomize for CheckboxGroupController {
|
||||
}
|
||||
|
||||
if group.id == UNCHECK {
|
||||
if cell_data.is_check() {
|
||||
if cell_data.is_checked {
|
||||
// Remove the row if the group.id is UNCHECK but the cell_data is CHECK
|
||||
changeset
|
||||
.deleted_rows
|
||||
@ -154,8 +154,8 @@ impl GroupController for CheckboxGroupController {
|
||||
match self.context.get_group(group_id) {
|
||||
None => tracing::warn!("Can not find the group: {}", group_id),
|
||||
Some((_, group)) => {
|
||||
let is_check = group.id == CHECK;
|
||||
let cell = insert_checkbox_cell(is_check, field);
|
||||
let is_checked = group.id == CHECK;
|
||||
let cell = insert_checkbox_cell(is_checked, field);
|
||||
cells.insert(field.id.clone(), cell);
|
||||
},
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user