Skip to content

Commit f21ca6c

Browse files
committed
refactor: CellCalendar with bloc
1 parent 13cb7ee commit f21ca6c

File tree

23 files changed

+575
-402
lines changed

23 files changed

+575
-402
lines changed

frontend/app_flowy/lib/startup/deps_resolver.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,13 +153,13 @@ void _resolveGridDeps(GetIt getIt) {
153153
getIt.registerFactoryParam<FieldActionSheetBloc, GridFieldCellContext, void>(
154154
(data, _) => FieldActionSheetBloc(
155155
field: data.field,
156-
service: FieldService(gridId: data.gridId),
156+
fieldService: FieldService(gridId: data.gridId, fieldId: data.field.id),
157157
),
158158
);
159159

160160
getIt.registerFactoryParam<FieldEditorBloc, String, EditFieldContextLoader>(
161161
(gridId, fieldLoader) => FieldEditorBloc(
162-
service: FieldService(gridId: gridId),
162+
gridId: gridId,
163163
fieldLoader: fieldLoader,
164164
),
165165
);

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

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import 'dart:async';
22
import 'dart:collection';
33

44
import 'package:app_flowy/workspace/application/grid/cell/select_option_service.dart';
5+
import 'package:app_flowy/workspace/application/grid/field/field_service.dart';
56
import 'package:dartz/dartz.dart';
67
import 'package:equatable/equatable.dart';
78
import 'package:flowy_sdk/dispatch/dispatch.dart';
@@ -12,7 +13,6 @@ import 'package:flowy_sdk/protobuf/flowy-grid/cell_entities.pb.dart';
1213
import 'package:flowy_sdk/protobuf/flowy-grid/selection_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

1818
part 'cell_service.freezed.dart';
@@ -59,15 +59,16 @@ class GridCellContextBuilder {
5959
}
6060

6161
// ignore: must_be_immutable
62-
class GridCellContext<C> extends Equatable {
62+
class GridCellContext<T> extends Equatable {
6363
final GridCell gridCell;
6464
final GridCellCache cellCache;
6565
final GridCellCacheKey _cacheKey;
66-
final GridCellDataLoader<C> cellDataLoader;
66+
final GridCellDataLoader<T> cellDataLoader;
6767
final CellService _cellService = CellService();
68+
final FieldService _fieldService;
6869

6970
late final CellListener _cellListener;
70-
late final ValueNotifier<C?> _cellDataNotifier;
71+
late final ValueNotifier<T?> _cellDataNotifier;
7172
bool isListening = false;
7273
VoidCallback? _onFieldChangedFn;
7374
Timer? _delayOperation;
@@ -76,9 +77,10 @@ class GridCellContext<C> extends Equatable {
7677
required this.gridCell,
7778
required this.cellCache,
7879
required this.cellDataLoader,
79-
}) : _cacheKey = GridCellCacheKey(objectId: gridCell.rowId, fieldId: gridCell.field.id);
80+
}) : _fieldService = FieldService(gridId: gridCell.gridId, fieldId: gridCell.field.id),
81+
_cacheKey = GridCellCacheKey(objectId: gridCell.rowId, fieldId: gridCell.field.id);
8082

81-
GridCellContext<C> clone() {
83+
GridCellContext<T> clone() {
8284
return GridCellContext(
8385
gridCell: gridCell,
8486
cellDataLoader: cellDataLoader,
@@ -98,16 +100,14 @@ class GridCellContext<C> extends Equatable {
98100

99101
FieldType get fieldType => gridCell.field.fieldType;
100102

101-
GridCellCacheKey get cacheKey => _cacheKey;
102-
103-
VoidCallback? startListening({required void Function(C) onCellChanged}) {
103+
VoidCallback? startListening({required void Function(T) onCellChanged}) {
104104
if (isListening) {
105105
Log.error("Already started. It seems like you should call clone first");
106106
return null;
107107
}
108108

109109
isListening = true;
110-
_cellDataNotifier = ValueNotifier(cellCache.get(cacheKey));
110+
_cellDataNotifier = ValueNotifier(cellCache.get(_cacheKey));
111111
_cellListener = CellListener(rowId: gridCell.rowId, fieldId: gridCell.field.id);
112112
_cellListener.start(onCellChanged: (result) {
113113
result.fold(
@@ -120,12 +120,12 @@ class GridCellContext<C> extends Equatable {
120120
_onFieldChangedFn = () {
121121
_loadData();
122122
};
123-
cellCache.addListener(cacheKey, _onFieldChangedFn!);
123+
cellCache.addListener(_cacheKey, _onFieldChangedFn!);
124124
}
125125

126126
onCellChangedFn() {
127127
final value = _cellDataNotifier.value;
128-
if (value is C) {
128+
if (value is T) {
129129
onCellChanged(value);
130130
}
131131

@@ -142,14 +142,18 @@ class GridCellContext<C> extends Equatable {
142142
_cellDataNotifier.removeListener(fn);
143143
}
144144

145-
C? getCellData() {
146-
final data = cellCache.get(cacheKey);
145+
T? getCellData() {
146+
final data = cellCache.get(_cacheKey);
147147
if (data == null) {
148148
_loadData();
149149
}
150150
return data;
151151
}
152152

153+
Future<Either<List<int>, FlowyError>> getTypeOptionData() {
154+
return _fieldService.getTypeOptionData(fieldType: fieldType);
155+
}
156+
153157
void saveCellData(String data) {
154158
_cellService.updateCell(gridId: gridId, fieldId: field.id, rowId: rowId, data: data).then((result) {
155159
result.fold((l) => null, (err) => Log.error(err));
@@ -161,7 +165,7 @@ class GridCellContext<C> extends Equatable {
161165
_delayOperation = Timer(const Duration(milliseconds: 10), () {
162166
cellDataLoader.loadData().then((data) {
163167
_cellDataNotifier.value = data;
164-
cellCache.insert(GridCellCacheData(key: cacheKey, object: data));
168+
cellCache.insert(GridCellCacheData(key: _cacheKey, object: data));
165169
});
166170
});
167171
}
@@ -170,13 +174,13 @@ class GridCellContext<C> extends Equatable {
170174
_delayOperation?.cancel();
171175

172176
if (_onFieldChangedFn != null) {
173-
cellCache.removeListener(cacheKey, _onFieldChangedFn!);
177+
cellCache.removeListener(_cacheKey, _onFieldChangedFn!);
174178
_onFieldChangedFn = null;
175179
}
176180
}
177181

178182
@override
179-
List<Object> get props => [cellCache.get(cacheKey) ?? "", cellId];
183+
List<Object> get props => [cellCache.get(_cacheKey) ?? "", cellId];
180184
}
181185

182186
abstract class GridCellDataLoader<T> {
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show Cell, Field;
2+
import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart';
3+
import 'package:flutter_bloc/flutter_bloc.dart';
4+
import 'package:freezed_annotation/freezed_annotation.dart';
5+
import 'package:table_calendar/table_calendar.dart';
6+
import 'dart:async';
7+
import 'cell_service.dart';
8+
import 'package:dartz/dartz.dart';
9+
part 'date_cal_bloc.freezed.dart';
10+
11+
class DateCalBloc extends Bloc<DateCalEvent, DateCalState> {
12+
final GridDefaultCellContext cellContext;
13+
void Function()? _onCellChangedFn;
14+
15+
DateCalBloc({required this.cellContext}) : super(DateCalState.initial(cellContext)) {
16+
on<DateCalEvent>(
17+
(event, emit) async {
18+
event.map(
19+
initial: (_Initial value) {
20+
_startListening();
21+
},
22+
selectDay: (_SelectDay value) {
23+
if (!isSameDay(state.selectedDay, value.day)) {
24+
_updateCellData(value.day);
25+
emit(state.copyWith(selectedDay: value.day));
26+
}
27+
},
28+
setFormat: (_CalendarFormat value) {
29+
emit(state.copyWith(format: value.format));
30+
},
31+
setFocusedDay: (_FocusedDay value) {
32+
emit(state.copyWith(focusedDay: value.day));
33+
},
34+
didReceiveCellUpdate: (_DidReceiveCellUpdate value) {},
35+
didReceiveFieldUpdate: (_DidReceiveFieldUpdate value) {
36+
emit(state.copyWith(field: value.field));
37+
},
38+
);
39+
},
40+
);
41+
}
42+
43+
@override
44+
Future<void> close() async {
45+
if (_onCellChangedFn != null) {
46+
cellContext.removeListener(_onCellChangedFn!);
47+
_onCellChangedFn = null;
48+
}
49+
cellContext.dispose();
50+
return super.close();
51+
}
52+
53+
void _startListening() {
54+
_onCellChangedFn = cellContext.startListening(
55+
onCellChanged: ((cell) {
56+
if (!isClosed) {
57+
add(DateCalEvent.didReceiveCellUpdate(cell));
58+
}
59+
}),
60+
);
61+
}
62+
63+
void _updateCellData(DateTime day) {
64+
final data = day.millisecondsSinceEpoch ~/ 1000;
65+
cellContext.saveCellData(data.toString());
66+
}
67+
}
68+
69+
@freezed
70+
class DateCalEvent with _$DateCalEvent {
71+
const factory DateCalEvent.initial() = _Initial;
72+
const factory DateCalEvent.selectDay(DateTime day) = _SelectDay;
73+
const factory DateCalEvent.setFormat(CalendarFormat format) = _CalendarFormat;
74+
const factory DateCalEvent.setFocusedDay(DateTime day) = _FocusedDay;
75+
const factory DateCalEvent.didReceiveCellUpdate(Cell cell) = _DidReceiveCellUpdate;
76+
const factory DateCalEvent.didReceiveFieldUpdate(Field field) = _DidReceiveFieldUpdate;
77+
}
78+
79+
@freezed
80+
class DateCalState with _$DateCalState {
81+
const factory DateCalState({
82+
required Field field,
83+
required Option<DateTypeOption> typeOptinoData,
84+
required CalendarFormat format,
85+
required DateTime focusedDay,
86+
DateTime? selectedDay,
87+
}) = _DateCalState;
88+
89+
factory DateCalState.initial(GridCellContext context) => DateCalState(
90+
field: context.field,
91+
typeOptinoData: none(),
92+
format: CalendarFormat.month,
93+
focusedDay: DateTime.now(),
94+
);
95+
}

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import 'package:flutter_bloc/flutter_bloc.dart';
33
import 'package:freezed_annotation/freezed_annotation.dart';
44
import 'dart:async';
55
import 'cell_service.dart';
6-
76
part 'date_cell_bloc.freezed.dart';
87

98
class DateCellBloc extends Bloc<DateCellEvent, DateCellState> {
@@ -72,7 +71,6 @@ class DateCellState with _$DateCellState {
7271
const factory DateCellState({
7372
required String content,
7473
required Field field,
75-
DateTime? selectedDay,
7674
}) = _DateCellState;
7775

7876
factory DateCellState.initial(GridCellContext context) => DateCellState(

frontend/app_flowy/lib/workspace/application/grid/field/field_action_sheet_bloc.dart

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,36 +8,36 @@ import 'field_service.dart';
88
part 'field_action_sheet_bloc.freezed.dart';
99

1010
class FieldActionSheetBloc extends Bloc<FieldActionSheetEvent, FieldActionSheetState> {
11-
final FieldService service;
11+
final FieldService fieldService;
1212

13-
FieldActionSheetBloc({required Field field, required this.service})
13+
FieldActionSheetBloc({required Field field, required this.fieldService})
1414
: super(FieldActionSheetState.initial(EditFieldContext.create()..gridField = field)) {
1515
on<FieldActionSheetEvent>(
1616
(event, emit) async {
1717
await event.map(
1818
updateFieldName: (_UpdateFieldName value) async {
19-
final result = await service.updateField(fieldId: field.id, name: value.name);
19+
final result = await fieldService.updateField(name: value.name);
2020
result.fold(
2121
(l) => null,
2222
(err) => Log.error(err),
2323
);
2424
},
2525
hideField: (_HideField value) async {
26-
final result = await service.updateField(fieldId: field.id, visibility: false);
26+
final result = await fieldService.updateField(visibility: false);
2727
result.fold(
2828
(l) => null,
2929
(err) => Log.error(err),
3030
);
3131
},
3232
deleteField: (_DeleteField value) async {
33-
final result = await service.deleteField(fieldId: field.id);
33+
final result = await fieldService.deleteField();
3434
result.fold(
3535
(l) => null,
3636
(err) => Log.error(err),
3737
);
3838
},
3939
duplicateField: (_DuplicateField value) async {
40-
final result = await service.duplicateField(fieldId: field.id);
40+
final result = await fieldService.duplicateField();
4141
result.fold(
4242
(l) => null,
4343
(err) => Log.error(err),

frontend/app_flowy/lib/workspace/application/grid/field/field_cell_bloc.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class FieldCellBloc extends Bloc<FieldCellEvent, FieldCellState> {
1515
FieldCellBloc({
1616
required GridFieldCellContext cellContext,
1717
}) : _fieldListener = SingleFieldListener(fieldId: cellContext.field.id),
18-
_fieldService = FieldService(gridId: cellContext.gridId),
18+
_fieldService = FieldService(gridId: cellContext.gridId, fieldId: cellContext.field.id),
1919
super(FieldCellState.initial(cellContext)) {
2020
on<FieldCellEvent>(
2121
(event, emit) async {
@@ -30,7 +30,7 @@ class FieldCellBloc extends Bloc<FieldCellEvent, FieldCellState> {
3030
final defaultWidth = state.field.width.toDouble();
3131
final width = defaultWidth + value.offset;
3232
if (width > defaultWidth && width < 300) {
33-
_fieldService.updateField(fieldId: state.field.id, width: width);
33+
_fieldService.updateField(width: width);
3434
}
3535
},
3636
);

frontend/app_flowy/lib/workspace/application/grid/field/field_editor_bloc.dart

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@ import 'package:protobuf/protobuf.dart';
1111
part 'field_editor_bloc.freezed.dart';
1212

1313
class FieldEditorBloc extends Bloc<FieldEditorEvent, FieldEditorState> {
14-
final FieldService service;
14+
final String gridId;
1515
final EditFieldContextLoader _loader;
1616

1717
FieldEditorBloc({
18-
required this.service,
18+
required this.gridId,
1919
required EditFieldContextLoader fieldLoader,
2020
}) : _loader = fieldLoader,
21-
super(FieldEditorState.initial(service.gridId)) {
21+
super(FieldEditorState.initial(gridId)) {
2222
on<FieldEditorEvent>(
2323
(event, emit) async {
2424
await event.map(
@@ -73,7 +73,9 @@ class FieldEditorBloc extends Bloc<FieldEditorEvent, FieldEditorState> {
7373
newContext.typeOptionData = typeOptionData;
7474
}
7575
});
76-
service.insertField(
76+
77+
FieldService.insertField(
78+
gridId: gridId,
7779
field: newContext.gridField,
7880
typeOptionData: newContext.typeOptionData,
7981
);
@@ -87,7 +89,8 @@ class FieldEditorBloc extends Bloc<FieldEditorEvent, FieldEditorState> {
8789
await state.editFieldContext.fold(
8890
() async => null,
8991
(context) async {
90-
final result = await service.insertField(
92+
final result = await FieldService.insertField(
93+
gridId: gridId,
9194
field: context.gridField,
9295
typeOptionData: context.typeOptionData,
9396
);

0 commit comments

Comments
 (0)