Skip to content

Commit 77ff2e9

Browse files
authored
chore: include time per cell (#1901)
* style: autoformat * chore: add include_time to cell data * chore: remove include_time from date field type options * chore: fix tests * chore: custom deserializer for date cell data * chore: add more tests * chore: simplify date calculation logic * chore: move include time to per-cell setting in UI * test: add another text str test * chore: adapt changes from upstream
1 parent 5e8f6a5 commit 77ff2e9

File tree

13 files changed

+340
-170
lines changed

13 files changed

+340
-170
lines changed

frontend/appflowy_flutter/lib/plugins/database_view/application/cell/cell_controller_builder.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ typedef SelectOptionCellController
1313
= CellController<SelectOptionCellDataPB, String>;
1414
typedef ChecklistCellController
1515
= CellController<SelectOptionCellDataPB, String>;
16-
typedef DateCellController = CellController<DateCellDataPB, CalendarData>;
16+
typedef DateCellController = CellController<DateCellDataPB, DateCellData>;
1717
typedef URLCellController = CellController<URLCellDataPB, String>;
1818

1919
class CellControllerBuilder {

frontend/appflowy_flutter/lib/plugins/database_view/application/cell/cell_data_persistence.dart

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,24 +27,28 @@ class TextCellDataPersistence implements CellDataPersistence<String> {
2727
}
2828

2929
@freezed
30-
class CalendarData with _$CalendarData {
31-
const factory CalendarData({required DateTime date, String? time}) =
32-
_CalendarData;
30+
class DateCellData with _$DateCellData {
31+
const factory DateCellData({
32+
required DateTime date,
33+
String? time,
34+
required bool includeTime,
35+
}) = _DateCellData;
3336
}
3437

35-
class DateCellDataPersistence implements CellDataPersistence<CalendarData> {
38+
class DateCellDataPersistence implements CellDataPersistence<DateCellData> {
3639
final CellIdentifier cellId;
3740
DateCellDataPersistence({
3841
required this.cellId,
3942
});
4043

4144
@override
42-
Future<Option<FlowyError>> save(CalendarData data) {
45+
Future<Option<FlowyError>> save(DateCellData data) {
4346
var payload = DateChangesetPB.create()..cellPath = _makeCellPath(cellId);
4447

4548
final date = (data.date.millisecondsSinceEpoch ~/ 1000).toString();
4649
payload.date = date;
4750
payload.isUtc = data.date.isUtc;
51+
payload.includeTime = data.includeTime;
4852

4953
if (data.time != null) {
5054
payload.time = data.time!;

frontend/appflowy_flutter/lib/plugins/database_view/widgets/row/cells/date_cell/date_cal_bloc.dart

Lines changed: 45 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import 'package:table_calendar/table_calendar.dart';
1515
import 'dart:async';
1616
import 'package:dartz/dartz.dart';
1717
import 'package:protobuf/protobuf.dart';
18-
import 'package:fixnum/fixnum.dart' as $fixnum;
18+
1919
part 'date_cal_bloc.freezed.dart';
2020

2121
class DateCellCalendarBloc
@@ -42,13 +42,13 @@ class DateCellCalendarBloc
4242
emit(state.copyWith(focusedDay: focusedDay));
4343
},
4444
didReceiveCellUpdate: (DateCellDataPB? cellData) {
45-
final calData = calDataFromCellData(cellData);
46-
final time = calData.foldRight(
45+
final dateCellData = calDataFromCellData(cellData);
46+
final time = dateCellData.foldRight(
4747
"", (dateData, previous) => dateData.time ?? '');
48-
emit(state.copyWith(calData: calData, time: time));
48+
emit(state.copyWith(dateCellData: dateCellData, time: time));
4949
},
5050
setIncludeTime: (includeTime) async {
51-
await _updateTypeOption(emit, includeTime: includeTime);
51+
await _updateDateData(emit, includeTime: includeTime);
5252
},
5353
setDateFormat: (dateFormat) async {
5454
await _updateTypeOption(emit, dateFormat: dateFormat);
@@ -57,24 +57,28 @@ class DateCellCalendarBloc
5757
await _updateTypeOption(emit, timeFormat: timeFormat);
5858
},
5959
setTime: (time) async {
60-
if (state.calData.isSome()) {
60+
if (state.dateCellData.isSome()) {
6161
await _updateDateData(emit, time: time);
6262
}
6363
},
6464
didUpdateCalData:
65-
(Option<CalendarData> data, Option<String> timeFormatError) {
65+
(Option<DateCellData> data, Option<String> timeFormatError) {
6666
emit(state.copyWith(
67-
calData: data, timeFormatError: timeFormatError));
67+
dateCellData: data, timeFormatError: timeFormatError));
6868
},
6969
);
7070
},
7171
);
7272
}
7373

7474
Future<void> _updateDateData(Emitter<DateCellCalendarState> emit,
75-
{DateTime? date, String? time}) {
76-
final CalendarData newDateData = state.calData.fold(
77-
() => CalendarData(date: date ?? DateTime.now(), time: time),
75+
{DateTime? date, String? time, bool? includeTime}) {
76+
final DateCellData newDateData = state.dateCellData.fold(
77+
() => DateCellData(
78+
date: date ?? DateTime.now(),
79+
time: time,
80+
includeTime: includeTime ?? false,
81+
),
7882
(dateData) {
7983
var newDateData = dateData;
8084
if (date != null && !isSameDay(newDateData.date, date)) {
@@ -84,6 +88,11 @@ class DateCellCalendarBloc
8488
if (newDateData.time != time) {
8589
newDateData = newDateData.copyWith(time: time);
8690
}
91+
92+
if (includeTime != null && newDateData.includeTime != includeTime) {
93+
newDateData = newDateData.copyWith(includeTime: includeTime);
94+
}
95+
8796
return newDateData;
8897
},
8998
);
@@ -92,15 +101,16 @@ class DateCellCalendarBloc
92101
}
93102

94103
Future<void> _saveDateData(
95-
Emitter<DateCellCalendarState> emit, CalendarData newCalData) async {
96-
if (state.calData == Some(newCalData)) {
104+
Emitter<DateCellCalendarState> emit, DateCellData newCalData) async {
105+
if (state.dateCellData == Some(newCalData)) {
97106
return;
98107
}
99108

100109
updateCalData(
101-
Option<CalendarData> calData, Option<String> timeFormatError) {
110+
Option<DateCellData> dateCellData, Option<String> timeFormatError) {
102111
if (!isClosed) {
103-
add(DateCellCalendarEvent.didUpdateCalData(calData, timeFormatError));
112+
add(DateCellCalendarEvent.didUpdateCalData(
113+
dateCellData, timeFormatError));
104114
}
105115
}
106116

@@ -110,7 +120,7 @@ class DateCellCalendarBloc
110120
(err) {
111121
switch (ErrorCode.valueOf(err.code)!) {
112122
case ErrorCode.InvalidDateTimeFormat:
113-
updateCalData(state.calData, Some(timeFormatPrompt(err)));
123+
updateCalData(state.dateCellData, Some(timeFormatPrompt(err)));
114124
break;
115125
default:
116126
Log.error(err);
@@ -159,7 +169,6 @@ class DateCellCalendarBloc
159169
Emitter<DateCellCalendarState> emit, {
160170
DateFormat? dateFormat,
161171
TimeFormat? timeFormat,
162-
bool? includeTime,
163172
}) async {
164173
state.dateTypeOptionPB.freeze();
165174
final newDateTypeOption = state.dateTypeOptionPB.rebuild((typeOption) {
@@ -170,10 +179,6 @@ class DateCellCalendarBloc
170179
if (timeFormat != null) {
171180
typeOption.timeFormat = timeFormat;
172181
}
173-
174-
if (includeTime != null) {
175-
typeOption.includeTime = includeTime;
176-
}
177182
});
178183

179184
final result = await FieldBackendService.updateFieldTypeOption(
@@ -208,7 +213,7 @@ class DateCellCalendarEvent with _$DateCellCalendarEvent {
208213
const factory DateCellCalendarEvent.didReceiveCellUpdate(
209214
DateCellDataPB? data) = _DidReceiveCellUpdate;
210215
const factory DateCellCalendarEvent.didUpdateCalData(
211-
Option<CalendarData> data, Option<String> timeFormatError) =
216+
Option<DateCellData> data, Option<String> timeFormatError) =
212217
_DidUpdateCalData;
213218
}
214219

@@ -219,7 +224,7 @@ class DateCellCalendarState with _$DateCellCalendarState {
219224
required CalendarFormat format,
220225
required DateTime focusedDay,
221226
required Option<String> timeFormatError,
222-
required Option<CalendarData> calData,
227+
required Option<DateCellData> dateCellData,
223228
required String? time,
224229
required String timeHintText,
225230
}) = _DateCellCalendarState;
@@ -228,15 +233,15 @@ class DateCellCalendarState with _$DateCellCalendarState {
228233
DateTypeOptionPB dateTypeOptionPB,
229234
DateCellDataPB? cellData,
230235
) {
231-
Option<CalendarData> calData = calDataFromCellData(cellData);
236+
Option<DateCellData> dateCellData = calDataFromCellData(cellData);
232237
final time =
233-
calData.foldRight("", (dateData, previous) => dateData.time ?? '');
238+
dateCellData.foldRight("", (dateData, previous) => dateData.time ?? '');
234239
return DateCellCalendarState(
235240
dateTypeOptionPB: dateTypeOptionPB,
236241
format: CalendarFormat.month,
237242
focusedDay: DateTime.now(),
238243
time: time,
239-
calData: calData,
244+
dateCellData: dateCellData,
240245
timeFormatError: none(),
241246
timeHintText: _timeHintText(dateTypeOptionPB),
242247
);
@@ -249,30 +254,30 @@ String _timeHintText(DateTypeOptionPB typeOption) {
249254
return LocaleKeys.document_date_timeHintTextInTwelveHour.tr();
250255
case TimeFormat.TwentyFourHour:
251256
return LocaleKeys.document_date_timeHintTextInTwentyFourHour.tr();
257+
default:
258+
return "";
252259
}
253-
return "";
254260
}
255261

256-
Option<CalendarData> calDataFromCellData(DateCellDataPB? cellData) {
262+
Option<DateCellData> calDataFromCellData(DateCellDataPB? cellData) {
257263
String? time = timeFromCellData(cellData);
258-
Option<CalendarData> calData = none();
264+
Option<DateCellData> dateData = none();
259265
if (cellData != null) {
260266
final timestamp = cellData.timestamp * 1000;
261267
final date = DateTime.fromMillisecondsSinceEpoch(timestamp.toInt());
262-
calData = Some(CalendarData(date: date, time: time));
268+
dateData = Some(DateCellData(
269+
date: date,
270+
time: time,
271+
includeTime: cellData.includeTime,
272+
));
263273
}
264-
return calData;
265-
}
266-
267-
$fixnum.Int64 timestampFromDateTime(DateTime dateTime) {
268-
final timestamp = (dateTime.millisecondsSinceEpoch ~/ 1000);
269-
return $fixnum.Int64(timestamp);
274+
return dateData;
270275
}
271276

272277
String? timeFromCellData(DateCellDataPB? cellData) {
273-
String? time;
274-
if (cellData?.hasTime() ?? false) {
275-
time = cellData?.time;
278+
if (cellData == null || !cellData.hasTime()) {
279+
return null;
276280
}
277-
return time;
281+
282+
return cellData.time;
278283
}

frontend/appflowy_flutter/lib/plugins/database_view/widgets/row/cells/date_cell/date_editor.dart

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -111,12 +111,14 @@ class _CellCalendarWidgetState extends State<_CellCalendarWidget> {
111111
child: BlocBuilder<DateCellCalendarBloc, DateCellCalendarState>(
112112
buildWhen: (p, c) => p != c,
113113
builder: (context, state) {
114+
bool includeTime = state.dateCellData
115+
.fold(() => false, (dateData) => dateData.includeTime);
114116
List<Widget> children = [
115117
Padding(
116118
padding: const EdgeInsets.symmetric(horizontal: 12.0),
117119
child: _buildCalendar(context),
118120
),
119-
if (state.dateTypeOptionPB.includeTime) ...[
121+
if (includeTime) ...[
120122
const VSpace(12.0),
121123
_TimeTextField(
122124
bloc: context.read<DateCellCalendarBloc>(),
@@ -206,7 +208,7 @@ class _CellCalendarWidgetState extends State<_CellCalendarWidget> {
206208
textStyle.textColor(Theme.of(context).disabledColor),
207209
),
208210
selectedDayPredicate: (day) {
209-
return state.calData.fold(
211+
return state.dateCellData.fold(
210212
() => false,
211213
(dateData) => isSameDay(dateData.date, day),
212214
);
@@ -238,7 +240,10 @@ class _IncludeTimeButton extends StatelessWidget {
238240
@override
239241
Widget build(BuildContext context) {
240242
return BlocSelector<DateCellCalendarBloc, DateCellCalendarState, bool>(
241-
selector: (state) => state.dateTypeOptionPB.includeTime,
243+
selector: (state) => state.dateCellData.fold(
244+
() => false,
245+
(dateData) => dateData.includeTime,
246+
),
242247
builder: (context, includeTime) {
243248
return Padding(
244249
padding: const EdgeInsets.symmetric(horizontal: 12.0),

frontend/rust-lib/flowy-database/src/event_handler.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,7 @@ pub(crate) async fn update_date_cell_handler(
517517
let cell_changeset = DateCellChangeset {
518518
date: data.date,
519519
time: data.time,
520+
include_time: data.include_time,
520521
is_utc: data.is_utc,
521522
};
522523

frontend/rust-lib/flowy-database/src/services/cell/cell_operation.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ pub trait CellDataChangeset: TypeOption {
3939
/// The changeset is able to parse into the concrete data struct if `TypeOption::CellChangeset`
4040
/// implements the `FromCellChangesetString` trait.
4141
/// For example,the SelectOptionCellChangeset,DateCellChangeset. etc.
42-
///
42+
///
4343
fn apply_changeset(
4444
&self,
4545
changeset: <Self as TypeOption>::CellChangeset,
@@ -142,7 +142,7 @@ where
142142

143143
/// Decode the opaque cell data from one field type to another using the corresponding `TypeOption`
144144
///
145-
/// The cell data might become an empty string depends on the to_field_type's `TypeOption`
145+
/// The cell data might become an empty string depends on the to_field_type's `TypeOption`
146146
/// support transform the from_field_type's cell data or not.
147147
///
148148
/// # Arguments
@@ -252,6 +252,7 @@ pub fn insert_date_cell(timestamp: i64, field_rev: &FieldRevision) -> CellRevisi
252252
let cell_data = serde_json::to_string(&DateCellChangeset {
253253
date: Some(timestamp.to_string()),
254254
time: None,
255+
include_time: Some(false),
255256
is_utc: true,
256257
})
257258
.unwrap();
@@ -279,7 +280,7 @@ pub fn delete_select_option_cell(
279280
CellRevision::new(data)
280281
}
281282

282-
/// Deserialize the String into cell specific data type.
283+
/// Deserialize the String into cell specific data type.
283284
pub trait FromCellString {
284285
fn from_cell_str(s: &str) -> FlowyResult<Self>
285286
where

frontend/rust-lib/flowy-database/src/services/database_view/editor.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -862,7 +862,8 @@ impl DatabaseViewEditor {
862862
let timestamp = date_cell
863863
.into_date_field_cell_data()
864864
.unwrap_or_default()
865-
.into();
865+
.timestamp
866+
.unwrap_or_default();
866867

867868
Some(CalendarEventPB {
868869
row_id: row_id.to_string(),
@@ -896,7 +897,7 @@ impl DatabaseViewEditor {
896897
// timestamp
897898
let timestamp = date_cell
898899
.into_date_field_cell_data()
899-
.map(|date_cell_data| date_cell_data.0.unwrap_or_default())
900+
.map(|date_cell_data| date_cell_data.timestamp.unwrap_or_default())
900901
.unwrap_or_default();
901902

902903
(row_id, timestamp)

0 commit comments

Comments
 (0)