Skip to content

Commit 7ff841c

Browse files
authored
Merge pull request #512 from AppFlowy-IO/feat_grid_url
feat: add new field type - URL
2 parents 7cb9ec3 + 4a9627b commit 7ff841c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+1370
-117
lines changed
Lines changed: 3 additions & 0 deletions
Loading

frontend/app_flowy/assets/translations/en.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@
160160
"numberFieldName": "Numbers",
161161
"singleSelectFieldName": "Select",
162162
"multiSelectFieldName": "Multiselect",
163+
"urlFieldName": "URL",
163164
"numberFormat": " Number format",
164165
"dateFormat": " Date format",
165166
"includeTime": " Include time",

frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_service.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
1010
import 'package:flowy_sdk/protobuf/flowy-grid/cell_entities.pb.dart';
1111
import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart';
1212
import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart';
13+
import 'package:flowy_sdk/protobuf/flowy-grid/url_type_option.pb.dart';
1314
import 'package:flutter/foundation.dart';
1415
import 'package:freezed_annotation/freezed_annotation.dart';
15-
1616
import 'package:app_flowy/workspace/application/grid/cell/cell_listener.dart';
1717
import 'package:app_flowy/workspace/application/grid/cell/select_option_service.dart';
1818
import 'package:app_flowy/workspace/application/grid/field/field_service.dart';

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

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ part of 'cell_service.dart';
33
typedef GridCellContext = _GridCellContext<String, String>;
44
typedef GridSelectOptionCellContext = _GridCellContext<SelectOptionCellData, String>;
55
typedef GridDateCellContext = _GridCellContext<DateCellData, DateCalData>;
6+
typedef GridURLCellContext = _GridCellContext<URLCellData, String>;
67

78
class GridCellContextBuilder {
89
final GridCellCache _cellCache;
@@ -75,12 +76,25 @@ class GridCellContextBuilder {
7576
cellDataLoader: cellDataLoader,
7677
cellDataPersistence: CellDataPersistence(gridCell: _gridCell),
7778
);
78-
default:
79-
throw UnimplementedError;
79+
80+
case FieldType.URL:
81+
final cellDataLoader = GridCellDataLoader(
82+
gridCell: _gridCell,
83+
parser: URLCellDataParser(),
84+
);
85+
return GridURLCellContext(
86+
gridCell: _gridCell,
87+
cellCache: _cellCache,
88+
cellDataLoader: cellDataLoader,
89+
cellDataPersistence: CellDataPersistence(gridCell: _gridCell),
90+
);
8091
}
92+
throw UnimplementedError;
8193
}
8294
}
8395

96+
// T: the type of the CellData
97+
// D: the type of the data that will be save to disk
8498
// ignore: must_be_immutable
8599
class _GridCellContext<T, D> extends Equatable {
86100
final GridCell gridCell;
@@ -94,7 +108,8 @@ class _GridCellContext<T, D> extends Equatable {
94108
late final ValueNotifier<T?> _cellDataNotifier;
95109
bool isListening = false;
96110
VoidCallback? _onFieldChangedFn;
97-
Timer? _delayOperation;
111+
Timer? _loadDataOperation;
112+
Timer? _saveDataOperation;
98113

99114
_GridCellContext({
100115
required this.gridCell,
@@ -124,7 +139,7 @@ class _GridCellContext<T, D> extends Equatable {
124139

125140
FieldType get fieldType => gridCell.field.fieldType;
126141

127-
VoidCallback? startListening({required void Function(T) onCellChanged}) {
142+
VoidCallback? startListening({required void Function(T?) onCellChanged}) {
128143
if (isListening) {
129144
Log.error("Already started. It seems like you should call clone first");
130145
return null;
@@ -148,7 +163,7 @@ class _GridCellContext<T, D> extends Equatable {
148163
}
149164

150165
onCellChangedFn() {
151-
onCellChanged(_cellDataNotifier.value as T);
166+
onCellChanged(_cellDataNotifier.value);
152167

153168
if (cellDataLoader.config.reloadOnCellChanged) {
154169
_loadData();
@@ -175,13 +190,26 @@ class _GridCellContext<T, D> extends Equatable {
175190
return _fieldService.getFieldTypeOptionData(fieldType: fieldType);
176191
}
177192

178-
Future<Option<FlowyError>> saveCellData(D data) {
179-
return cellDataPersistence.save(data);
193+
void saveCellData(D data, {bool deduplicate = false, void Function(Option<FlowyError>)? resultCallback}) async {
194+
if (deduplicate) {
195+
_loadDataOperation?.cancel();
196+
_loadDataOperation = Timer(const Duration(milliseconds: 300), () async {
197+
final result = await cellDataPersistence.save(data);
198+
if (resultCallback != null) {
199+
resultCallback(result);
200+
}
201+
});
202+
} else {
203+
final result = await cellDataPersistence.save(data);
204+
if (resultCallback != null) {
205+
resultCallback(result);
206+
}
207+
}
180208
}
181209

182210
void _loadData() {
183-
_delayOperation?.cancel();
184-
_delayOperation = Timer(const Duration(milliseconds: 10), () {
211+
_loadDataOperation?.cancel();
212+
_loadDataOperation = Timer(const Duration(milliseconds: 10), () {
185213
cellDataLoader.loadData().then((data) {
186214
_cellDataNotifier.value = data;
187215
cellCache.insert(GridCellCacheData(key: _cacheKey, object: data));
@@ -190,7 +218,8 @@ class _GridCellContext<T, D> extends Equatable {
190218
}
191219

192220
void dispose() {
193-
_delayOperation?.cancel();
221+
_loadDataOperation?.cancel();
222+
_saveDataOperation?.cancel();
194223

195224
if (_onFieldChangedFn != null) {
196225
cellCache.removeFieldListener(_cacheKey, _onFieldChangedFn!);

frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/data_loader.dart

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,11 @@ class GridCellDataLoader<T> extends IGridCellDataLoader<T> {
5858
return fut.then(
5959
(result) => result.fold((Cell cell) {
6060
try {
61-
return parser.parserData(cell.data);
61+
if (cell.data.isEmpty) {
62+
return null;
63+
} else {
64+
return parser.parserData(cell.data);
65+
}
6266
} catch (e, s) {
6367
Log.error('$parser parser cellData failed, $e');
6468
Log.error('Stack trace \n $s');
@@ -105,19 +109,20 @@ class StringCellDataParser implements ICellDataParser<String> {
105109
class DateCellDataParser implements ICellDataParser<DateCellData> {
106110
@override
107111
DateCellData? parserData(List<int> data) {
108-
if (data.isEmpty) {
109-
return null;
110-
}
111112
return DateCellData.fromBuffer(data);
112113
}
113114
}
114115

115116
class SelectOptionCellDataParser implements ICellDataParser<SelectOptionCellData> {
116117
@override
117118
SelectOptionCellData? parserData(List<int> data) {
118-
if (data.isEmpty) {
119-
return null;
120-
}
121119
return SelectOptionCellData.fromBuffer(data);
122120
}
123121
}
122+
123+
class URLCellDataParser implements ICellDataParser<URLCellData> {
124+
@override
125+
URLCellData? parserData(List<int> data) {
126+
return URLCellData.fromBuffer(data);
127+
}
128+
}

frontend/app_flowy/lib/workspace/application/grid/cell/checkbox_cell_bloc.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ class CheckboxCellBloc extends Bloc<CheckboxCellEvent, CheckboxCellState> {
5858
class CheckboxCellEvent with _$CheckboxCellEvent {
5959
const factory CheckboxCellEvent.initial() = _Initial;
6060
const factory CheckboxCellEvent.select() = _Selected;
61-
const factory CheckboxCellEvent.didReceiveCellUpdate(String cellData) = _DidReceiveCellUpdate;
61+
const factory CheckboxCellEvent.didReceiveCellUpdate(String? cellData) = _DidReceiveCellUpdate;
6262
}
6363

6464
@freezed

frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ class DateCalBloc extends Bloc<DateCalEvent, DateCalState> {
3737
setFocusedDay: (focusedDay) {
3838
emit(state.copyWith(focusedDay: focusedDay));
3939
},
40-
didReceiveCellUpdate: (DateCellData cellData) {
40+
didReceiveCellUpdate: (DateCellData? cellData) {
4141
final dateData = dateDataFromCellData(cellData);
4242
final time = dateData.foldRight("", (dateData, previous) => dateData.time);
4343
emit(state.copyWith(dateData: dateData, time: time));
@@ -83,25 +83,26 @@ class DateCalBloc extends Bloc<DateCalEvent, DateCalState> {
8383
return;
8484
}
8585

86-
final result = await cellContext.saveCellData(newDateData);
87-
result.fold(
88-
() => emit(state.copyWith(
89-
dateData: Some(newDateData),
90-
timeFormatError: none(),
91-
)),
92-
(err) {
93-
switch (ErrorCode.valueOf(err.code)!) {
94-
case ErrorCode.InvalidDateTimeFormat:
95-
emit(state.copyWith(
96-
dateData: Some(newDateData),
97-
timeFormatError: Some(timeFormatPrompt(err)),
98-
));
99-
break;
100-
default:
101-
Log.error(err);
102-
}
103-
},
104-
);
86+
cellContext.saveCellData(newDateData, resultCallback: (result) {
87+
result.fold(
88+
() => emit(state.copyWith(
89+
dateData: Some(newDateData),
90+
timeFormatError: none(),
91+
)),
92+
(err) {
93+
switch (ErrorCode.valueOf(err.code)!) {
94+
case ErrorCode.InvalidDateTimeFormat:
95+
emit(state.copyWith(
96+
dateData: Some(newDateData),
97+
timeFormatError: Some(timeFormatPrompt(err)),
98+
));
99+
break;
100+
default:
101+
Log.error(err);
102+
}
103+
},
104+
);
105+
});
105106
}
106107

107108
String timeFormatPrompt(FlowyError error) {
@@ -183,7 +184,7 @@ class DateCalEvent with _$DateCalEvent {
183184
const factory DateCalEvent.setDateFormat(DateFormat dateFormat) = _DateFormat;
184185
const factory DateCalEvent.setIncludeTime(bool includeTime) = _IncludeTime;
185186
const factory DateCalEvent.setTime(String time) = _Time;
186-
const factory DateCalEvent.didReceiveCellUpdate(DateCellData data) = _DidReceiveCellUpdate;
187+
const factory DateCalEvent.didReceiveCellUpdate(DateCellData? data) = _DidReceiveCellUpdate;
187188
}
188189

189190
@freezed

frontend/app_flowy/lib/workspace/application/grid/cell/date_cell_bloc.dart

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,13 @@ class DateCellBloc extends Bloc<DateCellEvent, DateCellState> {
1616
(event, emit) async {
1717
event.when(
1818
initial: () => _startListening(),
19-
didReceiveCellUpdate: (DateCellData value) => emit(state.copyWith(data: Some(value))),
19+
didReceiveCellUpdate: (DateCellData? cellData) {
20+
if (cellData != null) {
21+
emit(state.copyWith(data: Some(cellData)));
22+
} else {
23+
emit(state.copyWith(data: none()));
24+
}
25+
},
2026
didReceiveFieldUpdate: (Field value) => emit(state.copyWith(field: value)),
2127
);
2228
},
@@ -47,7 +53,7 @@ class DateCellBloc extends Bloc<DateCellEvent, DateCellState> {
4753
@freezed
4854
class DateCellEvent with _$DateCellEvent {
4955
const factory DateCellEvent.initial() = _InitialCell;
50-
const factory DateCellEvent.didReceiveCellUpdate(DateCellData data) = _DidReceiveCellUpdate;
56+
const factory DateCellEvent.didReceiveCellUpdate(DateCellData? data) = _DidReceiveCellUpdate;
5157
const factory DateCellEvent.didReceiveFieldUpdate(Field field) = _DidReceiveFieldUpdate;
5258
}
5359

frontend/app_flowy/lib/workspace/application/grid/cell/number_cell_bloc.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class NumberCellBloc extends Bloc<NumberCellEvent, NumberCellState> {
1919
_startListening();
2020
},
2121
didReceiveCellUpdate: (_DidReceiveCellUpdate value) {
22-
emit(state.copyWith(content: value.cellContent));
22+
emit(state.copyWith(content: value.cellContent ?? ""));
2323
},
2424
updateCell: (_UpdateCell value) async {
2525
await _updateCellValue(value, emit);
@@ -58,7 +58,7 @@ class NumberCellBloc extends Bloc<NumberCellEvent, NumberCellState> {
5858
class NumberCellEvent with _$NumberCellEvent {
5959
const factory NumberCellEvent.initial() = _Initial;
6060
const factory NumberCellEvent.updateCell(String text) = _UpdateCell;
61-
const factory NumberCellEvent.didReceiveCellUpdate(String cellContent) = _DidReceiveCellUpdate;
61+
const factory NumberCellEvent.didReceiveCellUpdate(String? cellContent) = _DidReceiveCellUpdate;
6262
}
6363

6464
@freezed

frontend/app_flowy/lib/workspace/application/grid/cell/select_option_cell_bloc.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class SelectOptionCellBloc extends Bloc<SelectOptionCellEvent, SelectOptionCellS
4444
onCellChanged: ((selectOptionContext) {
4545
if (!isClosed) {
4646
add(SelectOptionCellEvent.didReceiveOptions(
47-
selectOptionContext.selectOptions,
47+
selectOptionContext?.selectOptions ?? [],
4848
));
4949
}
5050
}),

0 commit comments

Comments
 (0)