mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
chore: check time format & add time format test
This commit is contained in:
@ -9,7 +9,7 @@ import 'dart:async';
|
|||||||
import 'cell_service/cell_service.dart';
|
import 'cell_service/cell_service.dart';
|
||||||
import 'package:dartz/dartz.dart';
|
import 'package:dartz/dartz.dart';
|
||||||
import 'package:protobuf/protobuf.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';
|
part 'date_cal_bloc.freezed.dart';
|
||||||
|
|
||||||
class DateCalBloc extends Bloc<DateCalEvent, DateCalState> {
|
class DateCalBloc extends Bloc<DateCalEvent, DateCalState> {
|
||||||
@ -163,9 +163,10 @@ class DateCalState with _$DateCalState {
|
|||||||
Option<DateCellPersistenceData> dateData = none();
|
Option<DateCellPersistenceData> dateData = none();
|
||||||
final time = cellData?.time ?? "";
|
final time = cellData?.time ?? "";
|
||||||
if (cellData != null) {
|
if (cellData != null) {
|
||||||
final timestamp = $fixnum.Int64.parseInt(cellData.date).toInt();
|
// final timestamp = $fixnum.Int64.parseInt(cellData.timestamp).toInt();
|
||||||
final selectedDay = DateTime.fromMillisecondsSinceEpoch(timestamp * 1000);
|
final timestamp = cellData.timestamp * 1000;
|
||||||
dateData = Some(DateCellPersistenceData(date: selectedDay));
|
final selectedDay = DateTime.fromMillisecondsSinceEpoch(timestamp.toInt());
|
||||||
|
dateData = Some(DateCellPersistenceData(date: selectedDay, time: time));
|
||||||
}
|
}
|
||||||
|
|
||||||
return DateCalState(
|
return DateCalState(
|
||||||
|
@ -127,7 +127,7 @@ class _CellCalendarWidget extends StatelessWidget {
|
|||||||
if (state.dateTypeOption.includeTime) {
|
if (state.dateTypeOption.includeTime) {
|
||||||
children.addAll([
|
children.addAll([
|
||||||
_TimeTextField(
|
_TimeTextField(
|
||||||
time: "",
|
text: state.time,
|
||||||
errorText: state.inputTimeError.fold(() => "", (error) => error.toString()),
|
errorText: state.inputTimeError.fold(() => "", (error) => error.toString()),
|
||||||
onEditingComplete: (text) {
|
onEditingComplete: (text) {
|
||||||
context.read<DateCalBloc>().add(DateCalEvent.setTime(text));
|
context.read<DateCalBloc>().add(DateCalEvent.setTime(text));
|
||||||
@ -247,11 +247,11 @@ class _IncludeTimeButton extends StatelessWidget {
|
|||||||
|
|
||||||
class _TimeTextField extends StatefulWidget {
|
class _TimeTextField extends StatefulWidget {
|
||||||
final String errorText;
|
final String errorText;
|
||||||
final String time;
|
final String text;
|
||||||
final void Function(String) onEditingComplete;
|
final void Function(String) onEditingComplete;
|
||||||
const _TimeTextField({
|
const _TimeTextField({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.time,
|
required this.text,
|
||||||
required this.errorText,
|
required this.errorText,
|
||||||
required this.onEditingComplete,
|
required this.onEditingComplete,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
@ -267,7 +267,7 @@ class _TimeTextFieldState extends State<_TimeTextField> {
|
|||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
_focusNode = FocusNode();
|
_focusNode = FocusNode();
|
||||||
_controller = TextEditingController(text: widget.time);
|
_controller = TextEditingController(text: widget.text);
|
||||||
_focusNode.addListener(() {
|
_focusNode.addListener(() {
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
widget.onEditingComplete(_controller.text);
|
widget.onEditingComplete(_controller.text);
|
||||||
|
@ -60,6 +60,12 @@ class _RoundedInputFieldState extends State<RoundedInputField> {
|
|||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
obscuteText = widget.obscureText;
|
obscuteText = widget.obscureText;
|
||||||
|
if (widget.controller != null) {
|
||||||
|
inputText = widget.controller!.text;
|
||||||
|
} else {
|
||||||
|
inputText = widget.initialValue ?? "";
|
||||||
|
}
|
||||||
|
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
import 'dart:core' as $core;
|
import 'dart:core' as $core;
|
||||||
|
|
||||||
|
import 'package:fixnum/fixnum.dart' as $fixnum;
|
||||||
import 'package:protobuf/protobuf.dart' as $pb;
|
import 'package:protobuf/protobuf.dart' as $pb;
|
||||||
|
|
||||||
import 'cell_entities.pb.dart' as $0;
|
import 'cell_entities.pb.dart' as $0;
|
||||||
@ -94,6 +95,7 @@ class DateCellData extends $pb.GeneratedMessage {
|
|||||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'DateCellData', createEmptyInstance: create)
|
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'DateCellData', createEmptyInstance: create)
|
||||||
..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'date')
|
..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'date')
|
||||||
..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'time')
|
..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'time')
|
||||||
|
..aInt64(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'timestamp')
|
||||||
..hasRequiredFields = false
|
..hasRequiredFields = false
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -101,6 +103,7 @@ class DateCellData extends $pb.GeneratedMessage {
|
|||||||
factory DateCellData({
|
factory DateCellData({
|
||||||
$core.String? date,
|
$core.String? date,
|
||||||
$core.String? time,
|
$core.String? time,
|
||||||
|
$fixnum.Int64? timestamp,
|
||||||
}) {
|
}) {
|
||||||
final _result = create();
|
final _result = create();
|
||||||
if (date != null) {
|
if (date != null) {
|
||||||
@ -109,6 +112,9 @@ class DateCellData extends $pb.GeneratedMessage {
|
|||||||
if (time != null) {
|
if (time != null) {
|
||||||
_result.time = time;
|
_result.time = time;
|
||||||
}
|
}
|
||||||
|
if (timestamp != null) {
|
||||||
|
_result.timestamp = timestamp;
|
||||||
|
}
|
||||||
return _result;
|
return _result;
|
||||||
}
|
}
|
||||||
factory DateCellData.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
|
factory DateCellData.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
|
||||||
@ -149,6 +155,15 @@ class DateCellData extends $pb.GeneratedMessage {
|
|||||||
$core.bool hasTime() => $_has(1);
|
$core.bool hasTime() => $_has(1);
|
||||||
@$pb.TagNumber(2)
|
@$pb.TagNumber(2)
|
||||||
void clearTime() => clearField(2);
|
void clearTime() => clearField(2);
|
||||||
|
|
||||||
|
@$pb.TagNumber(3)
|
||||||
|
$fixnum.Int64 get timestamp => $_getI64(2);
|
||||||
|
@$pb.TagNumber(3)
|
||||||
|
set timestamp($fixnum.Int64 v) { $_setInt64(2, v); }
|
||||||
|
@$pb.TagNumber(3)
|
||||||
|
$core.bool hasTimestamp() => $_has(2);
|
||||||
|
@$pb.TagNumber(3)
|
||||||
|
void clearTimestamp() => clearField(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
enum DateChangesetPayload_OneOfDate {
|
enum DateChangesetPayload_OneOfDate {
|
||||||
|
@ -50,11 +50,12 @@ const DateCellData$json = const {
|
|||||||
'2': const [
|
'2': const [
|
||||||
const {'1': 'date', '3': 1, '4': 1, '5': 9, '10': 'date'},
|
const {'1': 'date', '3': 1, '4': 1, '5': 9, '10': 'date'},
|
||||||
const {'1': 'time', '3': 2, '4': 1, '5': 9, '10': 'time'},
|
const {'1': 'time', '3': 2, '4': 1, '5': 9, '10': 'time'},
|
||||||
|
const {'1': 'timestamp', '3': 3, '4': 1, '5': 3, '10': 'timestamp'},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Descriptor for `DateCellData`. Decode as a `google.protobuf.DescriptorProto`.
|
/// Descriptor for `DateCellData`. Decode as a `google.protobuf.DescriptorProto`.
|
||||||
final $typed_data.Uint8List dateCellDataDescriptor = $convert.base64Decode('CgxEYXRlQ2VsbERhdGESEgoEZGF0ZRgBIAEoCVIEZGF0ZRISCgR0aW1lGAIgASgJUgR0aW1l');
|
final $typed_data.Uint8List dateCellDataDescriptor = $convert.base64Decode('CgxEYXRlQ2VsbERhdGESEgoEZGF0ZRgBIAEoCVIEZGF0ZRISCgR0aW1lGAIgASgJUgR0aW1lEhwKCXRpbWVzdGFtcBgDIAEoA1IJdGltZXN0YW1w');
|
||||||
@$core.Deprecated('Use dateChangesetPayloadDescriptor instead')
|
@$core.Deprecated('Use dateChangesetPayloadDescriptor instead')
|
||||||
const DateChangesetPayload$json = const {
|
const DateChangesetPayload$json = const {
|
||||||
'1': 'DateChangesetPayload',
|
'1': 'DateChangesetPayload',
|
||||||
|
@ -242,6 +242,7 @@ pub struct DateCellData {
|
|||||||
// message fields
|
// message fields
|
||||||
pub date: ::std::string::String,
|
pub date: ::std::string::String,
|
||||||
pub time: ::std::string::String,
|
pub time: ::std::string::String,
|
||||||
|
pub timestamp: i64,
|
||||||
// special fields
|
// special fields
|
||||||
pub unknown_fields: ::protobuf::UnknownFields,
|
pub unknown_fields: ::protobuf::UnknownFields,
|
||||||
pub cached_size: ::protobuf::CachedSize,
|
pub cached_size: ::protobuf::CachedSize,
|
||||||
@ -309,6 +310,21 @@ impl DateCellData {
|
|||||||
pub fn take_time(&mut self) -> ::std::string::String {
|
pub fn take_time(&mut self) -> ::std::string::String {
|
||||||
::std::mem::replace(&mut self.time, ::std::string::String::new())
|
::std::mem::replace(&mut self.time, ::std::string::String::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// int64 timestamp = 3;
|
||||||
|
|
||||||
|
|
||||||
|
pub fn get_timestamp(&self) -> i64 {
|
||||||
|
self.timestamp
|
||||||
|
}
|
||||||
|
pub fn clear_timestamp(&mut self) {
|
||||||
|
self.timestamp = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Param is passed by value, moved
|
||||||
|
pub fn set_timestamp(&mut self, v: i64) {
|
||||||
|
self.timestamp = v;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::protobuf::Message for DateCellData {
|
impl ::protobuf::Message for DateCellData {
|
||||||
@ -326,6 +342,13 @@ impl ::protobuf::Message for DateCellData {
|
|||||||
2 => {
|
2 => {
|
||||||
::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.time)?;
|
::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.time)?;
|
||||||
},
|
},
|
||||||
|
3 => {
|
||||||
|
if wire_type != ::protobuf::wire_format::WireTypeVarint {
|
||||||
|
return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
|
||||||
|
}
|
||||||
|
let tmp = is.read_int64()?;
|
||||||
|
self.timestamp = tmp;
|
||||||
|
},
|
||||||
_ => {
|
_ => {
|
||||||
::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
|
::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
|
||||||
},
|
},
|
||||||
@ -344,6 +367,9 @@ impl ::protobuf::Message for DateCellData {
|
|||||||
if !self.time.is_empty() {
|
if !self.time.is_empty() {
|
||||||
my_size += ::protobuf::rt::string_size(2, &self.time);
|
my_size += ::protobuf::rt::string_size(2, &self.time);
|
||||||
}
|
}
|
||||||
|
if self.timestamp != 0 {
|
||||||
|
my_size += ::protobuf::rt::value_size(3, self.timestamp, ::protobuf::wire_format::WireTypeVarint);
|
||||||
|
}
|
||||||
my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
|
my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
|
||||||
self.cached_size.set(my_size);
|
self.cached_size.set(my_size);
|
||||||
my_size
|
my_size
|
||||||
@ -356,6 +382,9 @@ impl ::protobuf::Message for DateCellData {
|
|||||||
if !self.time.is_empty() {
|
if !self.time.is_empty() {
|
||||||
os.write_string(2, &self.time)?;
|
os.write_string(2, &self.time)?;
|
||||||
}
|
}
|
||||||
|
if self.timestamp != 0 {
|
||||||
|
os.write_int64(3, self.timestamp)?;
|
||||||
|
}
|
||||||
os.write_unknown_fields(self.get_unknown_fields())?;
|
os.write_unknown_fields(self.get_unknown_fields())?;
|
||||||
::std::result::Result::Ok(())
|
::std::result::Result::Ok(())
|
||||||
}
|
}
|
||||||
@ -404,6 +433,11 @@ impl ::protobuf::Message for DateCellData {
|
|||||||
|m: &DateCellData| { &m.time },
|
|m: &DateCellData| { &m.time },
|
||||||
|m: &mut DateCellData| { &mut m.time },
|
|m: &mut DateCellData| { &mut m.time },
|
||||||
));
|
));
|
||||||
|
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeInt64>(
|
||||||
|
"timestamp",
|
||||||
|
|m: &DateCellData| { &m.timestamp },
|
||||||
|
|m: &mut DateCellData| { &mut m.timestamp },
|
||||||
|
));
|
||||||
::protobuf::reflect::MessageDescriptor::new_pb_name::<DateCellData>(
|
::protobuf::reflect::MessageDescriptor::new_pb_name::<DateCellData>(
|
||||||
"DateCellData",
|
"DateCellData",
|
||||||
fields,
|
fields,
|
||||||
@ -422,6 +456,7 @@ impl ::protobuf::Clear for DateCellData {
|
|||||||
fn clear(&mut self) {
|
fn clear(&mut self) {
|
||||||
self.date.clear();
|
self.date.clear();
|
||||||
self.time.clear();
|
self.time.clear();
|
||||||
|
self.timestamp = 0;
|
||||||
self.unknown_fields.clear();
|
self.unknown_fields.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -886,15 +921,16 @@ static file_descriptor_proto_data: &'static [u8] = b"\
|
|||||||
ateTypeOption\x12,\n\x0bdate_format\x18\x01\x20\x01(\x0e2\x0b.DateFormat\
|
ateTypeOption\x12,\n\x0bdate_format\x18\x01\x20\x01(\x0e2\x0b.DateFormat\
|
||||||
R\ndateFormat\x12,\n\x0btime_format\x18\x02\x20\x01(\x0e2\x0b.TimeFormat\
|
R\ndateFormat\x12,\n\x0btime_format\x18\x02\x20\x01(\x0e2\x0b.TimeFormat\
|
||||||
R\ntimeFormat\x12!\n\x0cinclude_time\x18\x03\x20\x01(\x08R\x0bincludeTim\
|
R\ntimeFormat\x12!\n\x0cinclude_time\x18\x03\x20\x01(\x08R\x0bincludeTim\
|
||||||
e\"6\n\x0cDateCellData\x12\x12\n\x04date\x18\x01\x20\x01(\tR\x04date\x12\
|
e\"T\n\x0cDateCellData\x12\x12\n\x04date\x18\x01\x20\x01(\tR\x04date\x12\
|
||||||
\x12\n\x04time\x18\x02\x20\x01(\tR\x04time\"\xa1\x01\n\x14DateChangesetP\
|
\x12\n\x04time\x18\x02\x20\x01(\tR\x04time\x12\x1c\n\ttimestamp\x18\x03\
|
||||||
ayload\x12?\n\x0fcell_identifier\x18\x01\x20\x01(\x0b2\x16.CellIdentifie\
|
\x20\x01(\x03R\ttimestamp\"\xa1\x01\n\x14DateChangesetPayload\x12?\n\x0f\
|
||||||
rPayloadR\x0ecellIdentifier\x12\x14\n\x04date\x18\x02\x20\x01(\tH\0R\x04\
|
cell_identifier\x18\x01\x20\x01(\x0b2\x16.CellIdentifierPayloadR\x0ecell\
|
||||||
date\x12\x14\n\x04time\x18\x03\x20\x01(\tH\x01R\x04timeB\r\n\x0bone_of_d\
|
Identifier\x12\x14\n\x04date\x18\x02\x20\x01(\tH\0R\x04date\x12\x14\n\
|
||||||
ateB\r\n\x0bone_of_time*6\n\nDateFormat\x12\t\n\x05Local\x10\0\x12\x06\n\
|
\x04time\x18\x03\x20\x01(\tH\x01R\x04timeB\r\n\x0bone_of_dateB\r\n\x0bon\
|
||||||
\x02US\x10\x01\x12\x07\n\x03ISO\x10\x02\x12\x0c\n\x08Friendly\x10\x03*0\
|
e_of_time*6\n\nDateFormat\x12\t\n\x05Local\x10\0\x12\x06\n\x02US\x10\x01\
|
||||||
\n\nTimeFormat\x12\x0e\n\nTwelveHour\x10\0\x12\x12\n\x0eTwentyFourHour\
|
\x12\x07\n\x03ISO\x10\x02\x12\x0c\n\x08Friendly\x10\x03*0\n\nTimeFormat\
|
||||||
\x10\x01b\x06proto3\
|
\x12\x0e\n\nTwelveHour\x10\0\x12\x12\n\x0eTwentyFourHour\x10\x01b\x06pro\
|
||||||
|
to3\
|
||||||
";
|
";
|
||||||
|
|
||||||
static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;
|
static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;
|
||||||
|
@ -9,6 +9,7 @@ message DateTypeOption {
|
|||||||
message DateCellData {
|
message DateCellData {
|
||||||
string date = 1;
|
string date = 1;
|
||||||
string time = 2;
|
string time = 2;
|
||||||
|
int64 timestamp = 3;
|
||||||
}
|
}
|
||||||
message DateChangesetPayload {
|
message DateChangesetPayload {
|
||||||
CellIdentifierPayload cell_identifier = 1;
|
CellIdentifierPayload cell_identifier = 1;
|
||||||
|
@ -6,7 +6,7 @@ use bytes::Bytes;
|
|||||||
use chrono::format::strftime::StrftimeItems;
|
use chrono::format::strftime::StrftimeItems;
|
||||||
use chrono::NaiveDateTime;
|
use chrono::NaiveDateTime;
|
||||||
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
|
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
|
||||||
use flowy_error::{ErrorCode, FlowyError, FlowyResult};
|
use flowy_error::{internal_error, ErrorCode, FlowyError, FlowyResult};
|
||||||
use flowy_grid_data_model::entities::{
|
use flowy_grid_data_model::entities::{
|
||||||
CellChangeset, CellMeta, FieldMeta, FieldType, TypeOptionDataDeserializer, TypeOptionDataEntry,
|
CellChangeset, CellMeta, FieldMeta, FieldType, TypeOptionDataDeserializer, TypeOptionDataEntry,
|
||||||
};
|
};
|
||||||
@ -30,12 +30,12 @@ pub struct DateTypeOption {
|
|||||||
impl_type_option!(DateTypeOption, FieldType::DateTime);
|
impl_type_option!(DateTypeOption, FieldType::DateTime);
|
||||||
|
|
||||||
impl DateTypeOption {
|
impl DateTypeOption {
|
||||||
#[allow(dead_code)]
|
|
||||||
fn today_desc_from_timestamp(&self, timestamp: i64) -> String {
|
fn today_desc_from_timestamp(&self, timestamp: i64) -> String {
|
||||||
let native = chrono::NaiveDateTime::from_timestamp(timestamp, 0);
|
let native = chrono::NaiveDateTime::from_timestamp(timestamp, 0);
|
||||||
self.today_desc_from_native(native)
|
self.today_desc_from_native(native)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
fn today_desc_from_str(&self, s: String) -> String {
|
fn today_desc_from_str(&self, s: String) -> String {
|
||||||
match NaiveDateTime::parse_from_str(&s, &self.fmt_str()) {
|
match NaiveDateTime::parse_from_str(&s, &self.fmt_str()) {
|
||||||
Ok(native) => self.today_desc_from_native(native),
|
Ok(native) => self.today_desc_from_native(native),
|
||||||
@ -89,25 +89,47 @@ impl DateTypeOption {
|
|||||||
return Ok(DateCellData::default());
|
return Ok(DateCellData::default());
|
||||||
}
|
}
|
||||||
|
|
||||||
let data: DateCellData = serde_json::from_str(&result.unwrap().data)?;
|
let serde_cell_data = DateCellDataSerde::from_str(&result.unwrap().data)?;
|
||||||
Ok(data)
|
let time = serde_cell_data.time;
|
||||||
|
let timestamp = serde_cell_data.timestamp;
|
||||||
|
let date = self.decode_cell_data_from_timestamp(serde_cell_data.timestamp).content;
|
||||||
|
|
||||||
|
return Ok(DateCellData { date, time, timestamp });
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decode_cell_data_from_timestamp(&self, timestamp: i64) -> DecodedCellData {
|
||||||
|
if timestamp == 0 {
|
||||||
|
return DecodedCellData::default();
|
||||||
|
}
|
||||||
|
|
||||||
|
let cell_content = self.today_desc_from_timestamp(timestamp);
|
||||||
|
return DecodedCellData::new(timestamp.to_string(), cell_content);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn timestamp_from_utc_with_time(&self, utc: &chrono::DateTime<chrono::Utc>, time: &str) -> FlowyResult<i64> {
|
||||||
|
let mut date_str = format!(
|
||||||
|
"{}",
|
||||||
|
utc.format_with_items(StrftimeItems::new(self.date_format.format_str()))
|
||||||
|
);
|
||||||
|
date_str = date_str.add(&time);
|
||||||
|
self.timestamp_from_str(&date_str)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CellDataOperation for DateTypeOption {
|
impl CellDataOperation for DateTypeOption {
|
||||||
fn decode_cell_data(&self, data: String, _field_meta: &FieldMeta) -> DecodedCellData {
|
fn decode_cell_data(&self, data: String, _field_meta: &FieldMeta) -> DecodedCellData {
|
||||||
if let Ok(type_option_cell_data) = TypeOptionCellData::from_str(&data) {
|
if let Ok(type_option_cell_data) = TypeOptionCellData::from_str(&data) {
|
||||||
|
// Return default data if the type_option_cell_data is not FieldType::DateTime.
|
||||||
|
// It happens when switching from one field to another.
|
||||||
|
// For example:
|
||||||
|
// FieldType::RichText -> FieldType::DateTime, it will display empty content on the screen.
|
||||||
if !type_option_cell_data.is_date() {
|
if !type_option_cell_data.is_date() {
|
||||||
return DecodedCellData::default();
|
return DecodedCellData::default();
|
||||||
}
|
}
|
||||||
|
return match DateCellDataSerde::from_str(&type_option_cell_data.data) {
|
||||||
let cell_data = type_option_cell_data.data;
|
Ok(serde_cell_data) => self.decode_cell_data_from_timestamp(serde_cell_data.timestamp),
|
||||||
if let Ok(timestamp) = cell_data.parse::<i64>() {
|
Err(_) => DecodedCellData::default(),
|
||||||
return DecodedCellData::new(format!("{}", timestamp), self.today_desc_from_timestamp(timestamp));
|
};
|
||||||
}
|
|
||||||
|
|
||||||
let cell_content = self.today_desc_from_str(cell_data.clone());
|
|
||||||
return DecodedCellData::new(cell_data, cell_content);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DecodedCellData::default()
|
DecodedCellData::default()
|
||||||
@ -119,26 +141,20 @@ impl CellDataOperation for DateTypeOption {
|
|||||||
_cell_meta: Option<CellMeta>,
|
_cell_meta: Option<CellMeta>,
|
||||||
) -> Result<String, FlowyError> {
|
) -> Result<String, FlowyError> {
|
||||||
let content_changeset: DateCellContentChangeset = serde_json::from_str(&changeset.into())?;
|
let content_changeset: DateCellContentChangeset = serde_json::from_str(&changeset.into())?;
|
||||||
let cell_content = match content_changeset.date_timestamp() {
|
let cell_data = match content_changeset.date_timestamp() {
|
||||||
None => "".to_owned(),
|
None => DateCellDataSerde::default(),
|
||||||
Some(date_timestamp) => {
|
Some(date_timestamp) => match (self.include_time, content_changeset.time) {
|
||||||
//
|
(true, Some(time)) => {
|
||||||
match (self.include_time, content_changeset.time) {
|
let time = time.to_uppercase();
|
||||||
(true, Some(time)) => {
|
let utc = self.utc_date_time_from_timestamp(date_timestamp);
|
||||||
let utc = self.utc_date_time_from_timestamp(date_timestamp);
|
let timestamp = self.timestamp_from_utc_with_time(&utc, &time)?;
|
||||||
let mut date_str = format!(
|
DateCellDataSerde { timestamp, time }
|
||||||
"{}",
|
|
||||||
utc.format_with_items(StrftimeItems::new(self.date_format.format_str()))
|
|
||||||
);
|
|
||||||
date_str = date_str.add(&time);
|
|
||||||
let timestamp = self.timestamp_from_str(&date_str)?;
|
|
||||||
timestamp.to_string()
|
|
||||||
}
|
|
||||||
_ => date_timestamp.to_string(),
|
|
||||||
}
|
}
|
||||||
}
|
_ => DateCellDataSerde::from_timestamp(date_timestamp),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
Ok(TypeOptionCellData::new(cell_content, self.field_type()).json())
|
|
||||||
|
Ok(TypeOptionCellData::new(cell_data.to_string(), self.field_type()).json())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -250,13 +266,39 @@ impl std::default::Default for TimeFormat {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, ProtoBuf, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Default, ProtoBuf)]
|
||||||
pub struct DateCellData {
|
pub struct DateCellData {
|
||||||
#[pb(index = 1)]
|
#[pb(index = 1)]
|
||||||
pub date: String,
|
pub date: String,
|
||||||
|
|
||||||
#[pb(index = 2)]
|
#[pb(index = 2)]
|
||||||
pub time: String,
|
pub time: String,
|
||||||
|
|
||||||
|
#[pb(index = 3)]
|
||||||
|
pub timestamp: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Serialize, Deserialize)]
|
||||||
|
pub struct DateCellDataSerde {
|
||||||
|
pub timestamp: i64,
|
||||||
|
pub time: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DateCellDataSerde {
|
||||||
|
fn from_timestamp(timestamp: i64) -> Self {
|
||||||
|
Self {
|
||||||
|
timestamp,
|
||||||
|
time: "".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_string(self) -> String {
|
||||||
|
serde_json::to_string(&self).unwrap_or("".to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> FlowyResult<Self> {
|
||||||
|
serde_json::from_str::<DateCellDataSerde>(s).map_err(internal_error)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, ProtoBuf)]
|
#[derive(Clone, Debug, Default, ProtoBuf)]
|
||||||
@ -335,7 +377,9 @@ impl std::convert::From<DateCellContentChangeset> for CellContentChangeset {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::services::field::FieldBuilder;
|
use crate::services::field::FieldBuilder;
|
||||||
use crate::services::field::{DateCellContentChangeset, DateFormat, DateTypeOption, TimeFormat};
|
use crate::services::field::{
|
||||||
|
DateCellContentChangeset, DateCellData, DateCellDataSerde, DateFormat, DateTypeOption, TimeFormat,
|
||||||
|
};
|
||||||
use crate::services::row::{CellDataOperation, TypeOptionCellData};
|
use crate::services::row::{CellDataOperation, TypeOptionCellData};
|
||||||
use flowy_grid_data_model::entities::FieldType;
|
use flowy_grid_data_model::entities::FieldType;
|
||||||
use strum::IntoEnumIterator;
|
use strum::IntoEnumIterator;
|
||||||
@ -360,39 +404,25 @@ mod tests {
|
|||||||
DateFormat::Friendly => {
|
DateFormat::Friendly => {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
"Mar 14,2022".to_owned(),
|
"Mar 14,2022".to_owned(),
|
||||||
type_option.decode_cell_data(data("1647251762"), &field_meta).content
|
type_option.decode_cell_data(data(1647251762), &field_meta).content
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
// "Mar 14,2022".to_owned(),
|
|
||||||
"".to_owned(),
|
|
||||||
type_option
|
|
||||||
.decode_cell_data(data("Mar 14,2022 17:56"), &field_meta)
|
|
||||||
.content
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
DateFormat::US => {
|
DateFormat::US => {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
"2022/03/14".to_owned(),
|
"2022/03/14".to_owned(),
|
||||||
type_option.decode_cell_data(data("1647251762"), &field_meta).content
|
type_option.decode_cell_data(data(1647251762), &field_meta).content
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
// "2022/03/14".to_owned(),
|
|
||||||
"".to_owned(),
|
|
||||||
type_option
|
|
||||||
.decode_cell_data(data("2022/03/14 17:56"), &field_meta)
|
|
||||||
.content
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
DateFormat::ISO => {
|
DateFormat::ISO => {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
"2022-03-14".to_owned(),
|
"2022-03-14".to_owned(),
|
||||||
type_option.decode_cell_data(data("1647251762"), &field_meta).content
|
type_option.decode_cell_data(data(1647251762), &field_meta).content
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
DateFormat::Local => {
|
DateFormat::Local => {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
"2022/03/14".to_owned(),
|
"2022/03/14".to_owned(),
|
||||||
type_option.decode_cell_data(data("1647251762"), &field_meta).content
|
type_option.decode_cell_data(data(1647251762), &field_meta).content
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -413,7 +443,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
"Mar 14,2022".to_owned(),
|
"Mar 14,2022".to_owned(),
|
||||||
type_option.decode_cell_data(data("1647251762"), &field_meta).content
|
type_option.decode_cell_data(data(1647251762), &field_meta).content
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
TimeFormat::TwelveHour => {
|
TimeFormat::TwelveHour => {
|
||||||
@ -423,7 +453,39 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
"Mar 14,2022".to_owned(),
|
"Mar 14,2022".to_owned(),
|
||||||
type_option.decode_cell_data(data("1647251762"), &field_meta).content
|
type_option.decode_cell_data(data(1647251762), &field_meta).content
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn date_description_time_format_test2() {
|
||||||
|
let mut type_option = DateTypeOption::default();
|
||||||
|
let field_meta = FieldBuilder::from_field_type(&FieldType::Number).build();
|
||||||
|
for time_format in TimeFormat::iter() {
|
||||||
|
type_option.time_format = time_format;
|
||||||
|
type_option.include_time = true;
|
||||||
|
match time_format {
|
||||||
|
TimeFormat::TwentyFourHour => {
|
||||||
|
assert_eq!(
|
||||||
|
"May 27,2022 00:00".to_owned(),
|
||||||
|
type_option.today_desc_from_timestamp(1653609600)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
"May 27,2022 00:00".to_owned(),
|
||||||
|
type_option.decode_cell_data(data(1653609600), &field_meta).content
|
||||||
|
);
|
||||||
|
}
|
||||||
|
TimeFormat::TwelveHour => {
|
||||||
|
assert_eq!(
|
||||||
|
"May 27,2022 12:00 AM".to_owned(),
|
||||||
|
type_option.today_desc_from_timestamp(1653609600)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
"May 27,2022 12:00 AM".to_owned(),
|
||||||
|
type_option.decode_cell_data(data(1653609600), &field_meta).content
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -494,7 +556,12 @@ mod tests {
|
|||||||
type_option.apply_changeset("he", None).unwrap();
|
type_option.apply_changeset("he", None).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn data(s: &str) -> String {
|
fn data(s: i64) -> String {
|
||||||
TypeOptionCellData::new(s, FieldType::DateTime).json()
|
let json = serde_json::to_string(&DateCellDataSerde {
|
||||||
|
timestamp: s,
|
||||||
|
time: "".to_string(),
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
TypeOptionCellData::new(&json, FieldType::DateTime).json()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user