Merge branch 'upstream-main' into feat/appflowy_tauri_3

# Conflicts:
#	frontend/appflowy_tauri/package.json
#	frontend/appflowy_tauri/src/appflowy_app/components/layout/HeaderPanel/Breadcrumbs.tsx
#	frontend/appflowy_tauri/src/appflowy_app/components/layout/MainPanel.tsx
#	frontend/appflowy_tauri/src/appflowy_app/components/layout/NavigationPanel/NavigationPanel.hooks.ts
#	frontend/appflowy_tauri/src/appflowy_app/components/layout/NavigationPanel/NavigationPanel.tsx
#	frontend/appflowy_tauri/src/appflowy_app/components/layout/NavigationPanel/PageItem.hooks.ts
#	frontend/appflowy_tauri/src/appflowy_app/components/layout/NavigationPanel/PageItem.tsx
#	frontend/appflowy_tauri/src/appflowy_app/components/layout/Screen.tsx
This commit is contained in:
ascarbek 2023-03-12 17:19:06 +06:00
commit a9c8bad599
244 changed files with 9303 additions and 2433 deletions

View File

@ -372,6 +372,7 @@
},
"calendar": {
"menuName": "Calendar",
"defaultNewCalendarTitle": "Untitled",
"navigation": {
"today": "Today",
"jumpToday": "Jump to Today",

View File

@ -2,9 +2,9 @@ part of 'cell_service.dart';
typedef CellByFieldId = LinkedHashMap<String, CellIdentifier>;
class GridBaseCell {
class DatabaseCell {
dynamic object;
GridBaseCell({
DatabaseCell({
required this.object,
});
}
@ -44,7 +44,7 @@ class CellCache {
}
}
void insert<T extends GridBaseCell>(CellCacheKey key, T value) {
void insert<T extends DatabaseCell>(CellCacheKey key, T value) {
var map = _cellDataByFieldId[key.fieldId];
if (map == null) {
_cellDataByFieldId[key.fieldId] = {};

View File

@ -170,7 +170,7 @@ class CellController<T, D> extends Equatable {
_loadDataOperation = Timer(const Duration(milliseconds: 10), () {
_cellDataLoader.loadData().then((data) {
if (data != null) {
_cellCache.insert(_cacheKey, GridBaseCell(object: data));
_cellCache.insert(_cacheKey, DatabaseCell(object: data));
} else {
_cellCache.remove(_cacheKey);
}

View File

@ -13,7 +13,7 @@ typedef SelectOptionCellController
= CellController<SelectOptionCellDataPB, String>;
typedef ChecklistCellController
= CellController<SelectOptionCellDataPB, String>;
typedef DateCellController = CellController<DateCellDataPB, CalendarData>;
typedef DateCellController = CellController<DateCellDataPB, DateCellData>;
typedef URLCellController = CellController<URLCellDataPB, String>;
class CellControllerBuilder {

View File

@ -27,24 +27,28 @@ class TextCellDataPersistence implements CellDataPersistence<String> {
}
@freezed
class CalendarData with _$CalendarData {
const factory CalendarData({required DateTime date, String? time}) =
_CalendarData;
class DateCellData with _$DateCellData {
const factory DateCellData({
required DateTime date,
String? time,
required bool includeTime,
}) = _DateCellData;
}
class DateCellDataPersistence implements CellDataPersistence<CalendarData> {
class DateCellDataPersistence implements CellDataPersistence<DateCellData> {
final CellIdentifier cellId;
DateCellDataPersistence({
required this.cellId,
});
@override
Future<Option<FlowyError>> save(CalendarData data) {
Future<Option<FlowyError>> save(DateCellData data) {
var payload = DateChangesetPB.create()..cellPath = _makeCellPath(cellId);
final date = (data.date.millisecondsSinceEpoch ~/ 1000).toString();
payload.date = date;
payload.isUtc = data.date.isUtc;
payload.includeTime = data.includeTime;
if (data.time != null) {
payload.time = data.time!;

View File

@ -0,0 +1,290 @@
import 'package:appflowy/plugins/database_view/application/field/field_controller.dart';
import 'package:appflowy/plugins/database_view/application/view/view_cache.dart';
import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-database/calendar_entities.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-database/field_entities.pbenum.dart';
import 'package:appflowy_backend/protobuf/flowy-database/group.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-database/group_changeset.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-database/row_entities.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-database/setting_entities.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:collection/collection.dart';
import 'dart:async';
import 'package:dartz/dartz.dart';
import 'database_service.dart';
import 'defines.dart';
import 'layout/layout_setting_listener.dart';
import 'row/row_cache.dart';
import 'group/group_listener.dart';
typedef OnRowsChanged = void Function(
List<RowInfo> rowInfos,
RowsChangedReason,
);
typedef OnGroupByField = void Function(List<GroupPB>);
typedef OnUpdateGroup = void Function(List<GroupPB>);
typedef OnDeleteGroup = void Function(List<String>);
typedef OnInsertGroup = void Function(InsertedGroupPB);
class GroupCallbacks {
final OnGroupByField? onGroupByField;
final OnUpdateGroup? onUpdateGroup;
final OnDeleteGroup? onDeleteGroup;
final OnInsertGroup? onInsertGroup;
GroupCallbacks({
this.onGroupByField,
this.onUpdateGroup,
this.onDeleteGroup,
this.onInsertGroup,
});
}
class LayoutCallbacks {
final void Function(LayoutSettingPB) onLayoutChanged;
final void Function(LayoutSettingPB) onLoadLayout;
LayoutCallbacks({
required this.onLayoutChanged,
required this.onLoadLayout,
});
}
class DatabaseCallbacks {
OnDatabaseChanged? onDatabaseChanged;
OnRowsChanged? onRowsChanged;
OnFieldsChanged? onFieldsChanged;
OnFiltersChanged? onFiltersChanged;
DatabaseCallbacks({
this.onDatabaseChanged,
this.onRowsChanged,
this.onFieldsChanged,
this.onFiltersChanged,
});
}
class DatabaseController {
final String viewId;
final DatabaseBackendService _databaseBackendSvc;
final FieldController fieldController;
late DatabaseViewCache _viewCache;
final LayoutTypePB layoutType;
// Callbacks
DatabaseCallbacks? _databaseCallbacks;
GroupCallbacks? _groupCallbacks;
LayoutCallbacks? _layoutCallbacks;
// Getters
List<RowInfo> get rowInfos => _viewCache.rowInfos;
RowCache get rowCache => _viewCache.rowCache;
// Listener
final DatabaseGroupListener groupListener;
final DatabaseLayoutListener layoutListener;
DatabaseController({required ViewPB view, required this.layoutType})
: viewId = view.id,
_databaseBackendSvc = DatabaseBackendService(viewId: view.id),
fieldController = FieldController(viewId: view.id),
groupListener = DatabaseGroupListener(view.id),
layoutListener = DatabaseLayoutListener(view.id) {
_viewCache = DatabaseViewCache(
viewId: viewId,
fieldController: fieldController,
);
_listenOnRowsChanged();
_listenOnFieldsChanged();
_listenOnGroupChanged();
_listenOnLayoutChanged();
}
void addListener({
DatabaseCallbacks? onDatabaseChanged,
LayoutCallbacks? onLayoutChanged,
GroupCallbacks? onGroupChanged,
}) {
_layoutCallbacks = onLayoutChanged;
_databaseCallbacks = onDatabaseChanged;
_groupCallbacks = onGroupChanged;
}
Future<Either<Unit, FlowyError>> open() async {
return _databaseBackendSvc.openGrid().then((result) {
return result.fold(
(database) async {
_databaseCallbacks?.onDatabaseChanged?.call(database);
_viewCache.rowCache.setInitialRows(database.rows);
return await fieldController
.loadFields(
fieldIds: database.fields,
)
.then(
(result) {
return result.fold(
(l) => Future(() async {
await _loadGroups();
await _loadLayoutSetting();
return left(l);
}),
(err) => right(err),
);
},
);
},
(err) => right(err),
);
});
}
Future<Either<RowPB, FlowyError>> createRow({
String? startRowId,
String? groupId,
void Function(RowDataBuilder builder)? withCells,
}) {
Map<String, String>? cellDataByFieldId;
if (withCells != null) {
final rowBuilder = RowDataBuilder();
withCells(rowBuilder);
cellDataByFieldId = rowBuilder.build();
}
return _databaseBackendSvc.createRow(
startRowId: startRowId,
groupId: groupId,
cellDataByFieldId: cellDataByFieldId,
);
}
Future<Either<Unit, FlowyError>> moveRow(RowPB fromRow,
{RowPB? toRow, String? groupId}) {
return _databaseBackendSvc.moveRow(
fromRowId: fromRow.id,
toGroupId: groupId,
toRowId: toRow?.id,
);
}
Future<Either<Unit, FlowyError>> moveGroup(
{required String fromGroupId, required String toGroupId}) {
return _databaseBackendSvc.moveGroup(
fromGroupId: fromGroupId,
toGroupId: toGroupId,
);
}
Future<void> updateCalenderLayoutSetting(
CalendarLayoutSettingsPB layoutSetting) async {
await _databaseBackendSvc
.updateLayoutSetting(calendarLayoutSetting: layoutSetting)
.then((result) {
result.fold((l) => null, (r) => Log.error(r));
});
}
Future<void> dispose() async {
await _databaseBackendSvc.closeView();
await fieldController.dispose();
await groupListener.stop();
}
Future<void> _loadGroups() async {
final result = await _databaseBackendSvc.loadGroups();
return Future(
() => result.fold(
(groups) {
_groupCallbacks?.onGroupByField?.call(groups.items);
},
(err) => Log.error(err),
),
);
}
Future<void> _loadLayoutSetting() async {
_databaseBackendSvc.getLayoutSetting(layoutType).then((result) {
result.fold(
(l) {
_layoutCallbacks?.onLoadLayout(l);
},
(r) => Log.error(r),
);
});
}
void _listenOnRowsChanged() {
_viewCache.addListener(onRowsChanged: (reason) {
_databaseCallbacks?.onRowsChanged?.call(rowInfos, reason);
});
}
void _listenOnFieldsChanged() {
fieldController.addListener(
onReceiveFields: (fields) {
_databaseCallbacks?.onFieldsChanged?.call(UnmodifiableListView(fields));
},
onFilters: (filters) {
_databaseCallbacks?.onFiltersChanged?.call(filters);
},
);
}
void _listenOnGroupChanged() {
groupListener.start(
onNumOfGroupsChanged: (result) {
result.fold((changeset) {
if (changeset.updateGroups.isNotEmpty) {
_groupCallbacks?.onUpdateGroup?.call(changeset.updateGroups);
}
if (changeset.deletedGroups.isNotEmpty) {
_groupCallbacks?.onDeleteGroup?.call(changeset.deletedGroups);
}
for (final insertedGroup in changeset.insertedGroups) {
_groupCallbacks?.onInsertGroup?.call(insertedGroup);
}
}, (r) => Log.error(r));
},
onGroupByNewField: (result) {
result.fold((groups) {
_groupCallbacks?.onGroupByField?.call(groups);
}, (r) => Log.error(r));
},
);
}
void _listenOnLayoutChanged() {
layoutListener.start(onLayoutChanged: (result) {
result.fold((l) {
_layoutCallbacks?.onLayoutChanged(l);
}, (r) => Log.error(r));
});
}
}
class RowDataBuilder {
final _cellDataByFieldId = <String, String>{};
void insertText(FieldInfo fieldInfo, String text) {
assert(fieldInfo.fieldType == FieldType.RichText);
_cellDataByFieldId[fieldInfo.field.id] = text;
}
void insertNumber(FieldInfo fieldInfo, int num) {
assert(fieldInfo.fieldType == FieldType.Number);
_cellDataByFieldId[fieldInfo.field.id] = num.toString();
}
void insertDate(FieldInfo fieldInfo, DateTime date) {
assert(fieldInfo.fieldType == FieldType.DateTime);
final timestamp = (date.millisecondsSinceEpoch ~/ 1000);
_cellDataByFieldId[fieldInfo.field.id] = timestamp.toString();
}
Map<String, String> build() {
return _cellDataByFieldId;
}
}

View File

@ -1,4 +1,7 @@
import 'package:appflowy_backend/protobuf/flowy-database/calendar_entities.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-database/database_entities.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-database/group_changeset.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-database/setting_entities.pb.dart';
import 'package:dartz/dartz.dart';
import 'package:appflowy_backend/dispatch/dispatch.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
@ -20,25 +23,56 @@ class DatabaseBackendService {
return DatabaseEventGetDatabase(payload).send();
}
Future<Either<RowPB, FlowyError>> createRow({Option<String>? startRowId}) {
var payload = CreateRowPayloadPB.create()..viewId = viewId;
startRowId?.fold(() => null, (id) => payload.startRowId = id);
return DatabaseEventCreateRow(payload).send();
}
Future<Either<RowPB, FlowyError>> createBoardCard(
String groupId,
Future<Either<RowPB, FlowyError>> createRow({
String? startRowId,
) {
CreateBoardCardPayloadPB payload = CreateBoardCardPayloadPB.create()
..viewId = viewId
..groupId = groupId;
String? groupId,
Map<String, String>? cellDataByFieldId,
}) {
var payload = CreateRowPayloadPB.create()..viewId = viewId;
if (startRowId != null) {
payload.startRowId = startRowId;
}
return DatabaseEventCreateBoardCard(payload).send();
if (groupId != null) {
payload.groupId = groupId;
}
if (cellDataByFieldId != null && cellDataByFieldId.isNotEmpty) {
payload.data = RowDataPB(cellDataByFieldId: cellDataByFieldId);
}
return DatabaseEventCreateRow(payload).send();
}
Future<Either<Unit, FlowyError>> moveRow({
required String fromRowId,
required String? toGroupId,
required String? toRowId,
}) {
var payload = MoveGroupRowPayloadPB.create()
..viewId = viewId
..fromRowId = fromRowId;
if (toGroupId != null) {
payload.toGroupId = toGroupId;
}
if (toRowId != null) {
payload.toRowId = toRowId;
}
return DatabaseEventMoveGroupRow(payload).send();
}
Future<Either<Unit, FlowyError>> moveGroup({
required String fromGroupId,
required String toGroupId,
}) {
final payload = MoveGroupPayloadPB.create()
..viewId = viewId
..fromGroupId = fromGroupId
..toGroupId = toGroupId;
return DatabaseEventMoveGroup(payload).send();
}
Future<Either<List<FieldPB>, FlowyError>> getFields(
@ -53,6 +87,28 @@ class DatabaseBackendService {
});
}
Future<Either<LayoutSettingPB, FlowyError>> getLayoutSetting(
LayoutTypePB layoutType) {
final payload = DatabaseLayoutIdPB.create()
..viewId = viewId
..layout = layoutType;
return DatabaseEventGetLayoutSetting(payload).send();
}
Future<Either<Unit, FlowyError>> updateLayoutSetting(
{CalendarLayoutSettingsPB? calendarLayoutSetting}) {
final layoutSetting = LayoutSettingPB.create();
if (calendarLayoutSetting != null) {
layoutSetting.calendar = calendarLayoutSetting;
}
final payload = UpdateLayoutSettingPB.create()
..viewId = viewId
..layoutSetting = layoutSetting;
return DatabaseEventSetLayoutSetting(payload).send();
}
Future<Either<Unit, FlowyError>> closeView() {
final request = ViewIdPB(value: viewId);
return FolderEventCloseView(request).send();

View File

@ -11,20 +11,20 @@ import 'package:appflowy_backend/protobuf/flowy-database/group_changeset.pb.dart
typedef GroupUpdateValue = Either<GroupChangesetPB, FlowyError>;
typedef GroupByNewFieldValue = Either<List<GroupPB>, FlowyError>;
class BoardListener {
class DatabaseGroupListener {
final String viewId;
PublishNotifier<GroupUpdateValue>? _groupUpdateNotifier = PublishNotifier();
PublishNotifier<GroupByNewFieldValue>? _groupByNewFieldNotifier =
PublishNotifier<GroupUpdateValue>? _numOfGroupsNotifier = PublishNotifier();
PublishNotifier<GroupByNewFieldValue>? _groupByFieldNotifier =
PublishNotifier();
DatabaseNotificationListener? _listener;
BoardListener(this.viewId);
DatabaseGroupListener(this.viewId);
void start({
required void Function(GroupUpdateValue) onBoardChanged,
required void Function(GroupUpdateValue) onNumOfGroupsChanged,
required void Function(GroupByNewFieldValue) onGroupByNewField,
}) {
_groupUpdateNotifier?.addPublishListener(onBoardChanged);
_groupByNewFieldNotifier?.addPublishListener(onGroupByNewField);
_numOfGroupsNotifier?.addPublishListener(onNumOfGroupsChanged);
_groupByFieldNotifier?.addPublishListener(onGroupByNewField);
_listener = DatabaseNotificationListener(
objectId: viewId,
handler: _handler,
@ -38,16 +38,16 @@ class BoardListener {
switch (ty) {
case DatabaseNotification.DidUpdateGroups:
result.fold(
(payload) => _groupUpdateNotifier?.value =
(payload) => _numOfGroupsNotifier?.value =
left(GroupChangesetPB.fromBuffer(payload)),
(error) => _groupUpdateNotifier?.value = right(error),
(error) => _numOfGroupsNotifier?.value = right(error),
);
break;
case DatabaseNotification.DidGroupByField:
result.fold(
(payload) => _groupByNewFieldNotifier?.value =
(payload) => _groupByFieldNotifier?.value =
left(GroupChangesetPB.fromBuffer(payload).initialGroups),
(error) => _groupByNewFieldNotifier?.value = right(error),
(error) => _groupByFieldNotifier?.value = right(error),
);
break;
default:
@ -57,10 +57,10 @@ class BoardListener {
Future<void> stop() async {
await _listener?.stop();
_groupUpdateNotifier?.dispose();
_groupUpdateNotifier = null;
_numOfGroupsNotifier?.dispose();
_numOfGroupsNotifier = null;
_groupByNewFieldNotifier?.dispose();
_groupByNewFieldNotifier = null;
_groupByFieldNotifier?.dispose();
_groupByFieldNotifier = null;
}
}

View File

@ -0,0 +1,51 @@
import 'dart:typed_data';
import 'package:appflowy/core/grid_notification.dart';
import 'package:flowy_infra/notifier.dart';
import 'package:appflowy_backend/protobuf/flowy-error/protobuf.dart';
import 'package:appflowy_backend/protobuf/flowy-database/protobuf.dart';
import 'package:dartz/dartz.dart';
typedef LayoutSettingsValue<T> = Either<T, FlowyError>;
class DatabaseLayoutListener {
final String viewId;
PublishNotifier<LayoutSettingsValue<LayoutSettingPB>>? _settingNotifier =
PublishNotifier();
DatabaseNotificationListener? _listener;
DatabaseLayoutListener(this.viewId);
void start({
required void Function(LayoutSettingsValue<LayoutSettingPB>)
onLayoutChanged,
}) {
_settingNotifier?.addPublishListener(onLayoutChanged);
_listener = DatabaseNotificationListener(
objectId: viewId,
handler: _handler,
);
}
void _handler(
DatabaseNotification ty,
Either<Uint8List, FlowyError> result,
) {
switch (ty) {
case DatabaseNotification.DidUpdateLayoutSettings:
result.fold(
(payload) => _settingNotifier?.value =
left(LayoutSettingPB.fromBuffer(payload)),
(error) => _settingNotifier?.value = right(error),
);
break;
default:
break;
}
}
Future<void> stop() async {
await _listener?.stop();
_settingNotifier?.dispose();
_settingNotifier = null;
}
}

View File

@ -61,7 +61,7 @@ class RowCache {
});
}
void initializeRows(List<RowPB> rows) {
void setInitialRows(List<RowPB> rows) {
for (final row in rows) {
final rowInfo = buildGridRow(row);
_rowList.add(rowInfo);

View File

@ -4,25 +4,27 @@ import 'row_cache.dart';
typedef OnRowChanged = void Function(CellByFieldId, RowsChangedReason);
class RowDataController {
final RowInfo rowInfo;
class RowController {
final String rowId;
final String viewId;
final List<VoidCallback> _onRowChangedListeners = [];
final RowCache _rowCache;
get cellCache => _rowCache.cellCache;
RowDataController({
required this.rowInfo,
RowController({
required this.rowId,
required this.viewId,
required RowCache rowCache,
}) : _rowCache = rowCache;
CellByFieldId loadData() {
return _rowCache.loadGridCells(rowInfo.rowPB.id);
return _rowCache.loadGridCells(rowId);
}
void addListener({OnRowChanged? onRowChanged}) {
_onRowChangedListeners.add(_rowCache.addListener(
rowId: rowInfo.rowPB.id,
rowId: rowId,
onCellUpdated: onRowChanged,
));
}

View File

@ -1,8 +1,6 @@
import 'package:appflowy_backend/protobuf/flowy-database/database_entities.pb.dart';
import 'package:dartz/dartz.dart';
import 'package:appflowy_backend/dispatch/dispatch.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-database/group_changeset.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-database/row_entities.pb.dart';
class RowBackendService {
@ -44,52 +42,3 @@ class RowBackendService {
return DatabaseEventDuplicateRow(payload).send();
}
}
class GroupBackendService {
final String viewId;
GroupBackendService({
required this.viewId,
});
Future<Either<Unit, FlowyError>> moveRow({
required String fromRowId,
required String toRowId,
}) {
var payload = MoveRowPayloadPB.create()
..viewId = viewId
..fromRowId = fromRowId
..toRowId = toRowId;
return DatabaseEventMoveRow(payload).send();
}
Future<Either<Unit, FlowyError>> moveGroupRow({
required String fromRowId,
required String toGroupId,
required String? toRowId,
}) {
var payload = MoveGroupRowPayloadPB.create()
..viewId = viewId
..fromRowId = fromRowId
..toGroupId = toGroupId;
if (toRowId != null) {
payload.toRowId = toRowId;
}
return DatabaseEventMoveGroupRow(payload).send();
}
Future<Either<Unit, FlowyError>> moveGroup({
required String fromGroupId,
required String toGroupId,
}) {
final payload = MoveGroupPayloadPB.create()
..viewId = viewId
..fromGroupId = fromGroupId
..toGroupId = toGroupId;
return DatabaseEventMoveGroup(payload).send();
}
}

View File

@ -13,25 +13,25 @@ import 'package:freezed_annotation/freezed_annotation.dart';
import '../../application/field/field_controller.dart';
import '../../application/row/row_cache.dart';
import '../../application/row/row_service.dart';
import 'board_data_controller.dart';
import '../../application/database_controller.dart';
import 'group_controller.dart';
part 'board_bloc.freezed.dart';
class BoardBloc extends Bloc<BoardEvent, BoardState> {
final BoardDataController _boardDataController;
final DatabaseController _databaseController;
late final AppFlowyBoardController boardController;
final GroupBackendService _groupBackendSvc;
final LinkedHashMap<String, GroupController> groupControllers =
LinkedHashMap();
FieldController get fieldController => _boardDataController.fieldController;
String get viewId => _boardDataController.viewId;
FieldController get fieldController => _databaseController.fieldController;
String get viewId => _databaseController.viewId;
BoardBloc({required ViewPB view})
: _groupBackendSvc = GroupBackendService(viewId: view.id),
_boardDataController = BoardDataController(view: view),
: _databaseController = DatabaseController(
view: view,
layoutType: LayoutTypePB.Board,
),
super(BoardState.initial(view.id)) {
boardController = AppFlowyBoardController(
onMoveGroup: (
@ -40,7 +40,10 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
toGroupId,
toIndex,
) {
_moveGroup(fromGroupId, toGroupId);
_databaseController.moveGroup(
fromGroupId: fromGroupId,
toGroupId: toGroupId,
);
},
onMoveGroupItem: (
groupId,
@ -49,7 +52,13 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
) {
final fromRow = groupControllers[groupId]?.rowAtIndex(fromIndex);
final toRow = groupControllers[groupId]?.rowAtIndex(toIndex);
_moveRow(fromRow, groupId, toRow);
if (fromRow != null) {
_databaseController.moveRow(
fromRow,
toRow: toRow,
groupId: groupId,
);
}
},
onMoveGroupItemToGroup: (
fromGroupId,
@ -59,7 +68,13 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
) {
final fromRow = groupControllers[fromGroupId]?.rowAtIndex(fromIndex);
final toRow = groupControllers[toGroupId]?.rowAtIndex(toIndex);
_moveRow(fromRow, toGroupId, toRow);
if (fromRow != null) {
_databaseController.moveRow(
fromRow,
toRow: toRow,
groupId: toGroupId,
);
}
},
);
@ -72,8 +87,8 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
},
createBottomRow: (groupId) async {
final startRowId = groupControllers[groupId]?.lastRow()?.id;
final result = await _boardDataController.createBoardCard(
groupId,
final result = await _databaseController.createRow(
groupId: groupId,
startRowId: startRowId,
);
result.fold(
@ -82,7 +97,8 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
);
},
createHeaderRow: (String groupId) async {
final result = await _boardDataController.createBoardCard(groupId);
final result =
await _databaseController.createRow(groupId: groupId);
result.fold(
(_) {},
(err) => Log.error(err),
@ -141,44 +157,11 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
}
boardController.enableGroupDragging(!isEdit);
// boardController.updateGroupItem(
// group.groupId,
// GroupItem(
// row: row,
// fieldInfo: fieldInfo,
// isDraggable: !isEdit,
// ),
// );
}
void _moveRow(RowPB? fromRow, String columnId, RowPB? toRow) {
if (fromRow != null) {
_groupBackendSvc
.moveGroupRow(
fromRowId: fromRow.id,
toGroupId: columnId,
toRowId: toRow?.id,
)
.then((result) {
result.fold((l) => null, (r) => add(BoardEvent.didReceiveError(r)));
});
}
}
void _moveGroup(String fromGroupId, String toGroupId) {
_groupBackendSvc
.moveGroup(
fromGroupId: fromGroupId,
toGroupId: toGroupId,
)
.then((result) {
result.fold((l) => null, (r) => add(BoardEvent.didReceiveError(r)));
});
}
@override
Future<void> close() async {
await _boardDataController.dispose();
await _databaseController.dispose();
for (final controller in groupControllers.values) {
controller.dispose();
}
@ -204,34 +187,36 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
}
RowCache? getRowCache(String blockId) {
return _boardDataController.rowCache;
return _databaseController.rowCache;
}
void _startListening() {
_boardDataController.addListener(
onDatabaseChanged: (grid) {
final onDatabaseChanged = DatabaseCallbacks(
onDatabaseChanged: (database) {
if (!isClosed) {
add(BoardEvent.didReceiveGridUpdate(grid));
add(BoardEvent.didReceiveGridUpdate(database));
}
},
didLoadGroups: (groups) {
);
final onGroupChanged = GroupCallbacks(
onGroupByField: (groups) {
if (isClosed) return;
initializeGroups(groups);
add(BoardEvent.didReceiveGroups(groups));
},
onDeletedGroup: (groupIds) {
onDeleteGroup: (groupIds) {
if (isClosed) return;
boardController.removeGroups(groupIds);
},
onInsertedGroup: (insertedGroup) {
onInsertGroup: (insertGroups) {
if (isClosed) return;
final group = insertedGroup.group;
final group = insertGroups.group;
final newGroup = initializeGroupData(group);
final controller = initializeGroupController(group);
groupControllers[controller.group.groupId] = (controller);
boardController.addGroup(newGroup);
},
onUpdatedGroup: (updatedGroups) {
onUpdateGroup: (updatedGroups) {
if (isClosed) return;
for (final group in updatedGroups) {
final columnController =
@ -239,15 +224,11 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
columnController?.updateGroupName(group.desc);
}
},
onError: (err) {
Log.error(err);
},
onResetGroups: (groups) {
if (isClosed) return;
);
initializeGroups(groups);
add(BoardEvent.didReceiveGroups(groups));
},
_databaseController.addListener(
onDatabaseChanged: onDatabaseChanged,
onGroupChanged: onGroupChanged,
);
}
@ -264,7 +245,7 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
}
Future<void> _openGrid(Emitter<BoardState> emit) async {
final result = await _boardDataController.openGrid();
final result = await _databaseController.open();
result.fold(
(grid) => emit(
state.copyWith(loadingState: GridLoadingState.finish(left(unit))),

View File

@ -1,144 +0,0 @@
import 'dart:collection';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'dart:async';
import 'package:dartz/dartz.dart';
import 'package:appflowy_backend/protobuf/flowy-database/protobuf.dart';
import '../../application/database_service.dart';
import '../../application/defines.dart';
import '../../application/field/field_controller.dart';
import '../../application/row/row_cache.dart';
import '../../application/view/view_cache.dart';
import 'board_listener.dart';
typedef DidLoadGroups = void Function(List<GroupPB>);
typedef OnUpdatedGroup = void Function(List<GroupPB>);
typedef OnDeletedGroup = void Function(List<String>);
typedef OnInsertedGroup = void Function(InsertedGroupPB);
typedef OnResetGroups = void Function(List<GroupPB>);
class BoardDataController {
final String viewId;
final DatabaseBackendService _databaseSvc;
final FieldController fieldController;
final BoardListener _listener;
late DatabaseViewCache _viewCache;
OnFieldsChanged? _onFieldsChanged;
OnDatabaseChanged? _onDatabaseChanged;
DidLoadGroups? _didLoadGroup;
OnRowsChanged? _onRowsChanged;
OnError? _onError;
List<RowInfo> get rowInfos => _viewCache.rowInfos;
RowCache get rowCache => _viewCache.rowCache;
BoardDataController({required ViewPB view})
: viewId = view.id,
_listener = BoardListener(view.id),
_databaseSvc = DatabaseBackendService(viewId: view.id),
fieldController = FieldController(viewId: view.id) {
//
_viewCache = DatabaseViewCache(
viewId: view.id,
fieldController: fieldController,
);
_viewCache.addListener(onRowsChanged: (reason) {
_onRowsChanged?.call(rowInfos, reason);
});
}
void addListener({
required OnDatabaseChanged onDatabaseChanged,
OnFieldsChanged? onFieldsChanged,
required DidLoadGroups didLoadGroups,
OnRowsChanged? onRowsChanged,
required OnUpdatedGroup onUpdatedGroup,
required OnDeletedGroup onDeletedGroup,
required OnInsertedGroup onInsertedGroup,
required OnResetGroups onResetGroups,
required OnError? onError,
}) {
_onDatabaseChanged = onDatabaseChanged;
_onFieldsChanged = onFieldsChanged;
_didLoadGroup = didLoadGroups;
_onRowsChanged = onRowsChanged;
_onError = onError;
fieldController.addListener(onReceiveFields: (fields) {
_onFieldsChanged?.call(UnmodifiableListView(fields));
});
_listener.start(
onBoardChanged: (result) {
result.fold(
(changeset) {
if (changeset.updateGroups.isNotEmpty) {
onUpdatedGroup.call(changeset.updateGroups);
}
if (changeset.deletedGroups.isNotEmpty) {
onDeletedGroup.call(changeset.deletedGroups);
}
for (final insertedGroup in changeset.insertedGroups) {
onInsertedGroup.call(insertedGroup);
}
},
(e) => _onError?.call(e),
);
},
onGroupByNewField: (result) {
result.fold(
(groups) => onResetGroups(groups),
(e) => _onError?.call(e),
);
},
);
}
Future<Either<Unit, FlowyError>> openGrid() async {
final result = await _databaseSvc.openGrid();
return result.fold(
(grid) async {
_onDatabaseChanged?.call(grid);
return fieldController.loadFields(fieldIds: grid.fields).then((result) {
return result.fold(
(l) => Future(() async {
await _loadGroups();
_viewCache.rowCache.initializeRows(grid.rows);
return left(l);
}),
(err) => right(err),
);
});
},
(err) => right(err),
);
}
Future<Either<RowPB, FlowyError>> createBoardCard(String groupId,
{String? startRowId}) {
return _databaseSvc.createBoardCard(groupId, startRowId);
}
Future<void> dispose() async {
await _viewCache.dispose();
await _databaseSvc.closeView();
await fieldController.dispose();
}
Future<void> _loadGroups() async {
final result = await _databaseSvc.loadGroups();
return Future(
() => result.fold(
(groups) {
_didLoadGroup?.call(groups.items);
},
(err) => _onError?.call(err),
),
);
}
}

View File

@ -1,39 +0,0 @@
import 'package:appflowy_backend/protobuf/flowy-database/row_entities.pb.dart';
import 'package:flutter/foundation.dart';
import '../../../application/cell/cell_service.dart';
import '../../../application/row/row_cache.dart';
import '../../presentation/card/card_cell_builder.dart';
typedef OnCardChanged = void Function(CellByFieldId, RowsChangedReason);
class CardDataController extends BoardCellBuilderDelegate {
final RowPB rowPB;
final RowCache _rowCache;
final List<VoidCallback> _onCardChangedListeners = [];
CardDataController({
required this.rowPB,
required RowCache rowCache,
}) : _rowCache = rowCache;
CellByFieldId loadData() {
return _rowCache.loadGridCells(rowPB.id);
}
void addListener({OnCardChanged? onRowChanged}) {
_onCardChangedListeners.add(_rowCache.addListener(
rowId: rowPB.id,
onCellUpdated: onRowChanged,
));
}
void dispose() {
for (final fn in _onCardChangedListeners) {
_rowCache.removeRowListener(fn);
}
}
@override
CellCache get cellCache => _rowCache.cellCache;
}

View File

@ -1,7 +1,11 @@
import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-database/protobuf.dart';
import 'group_listener.dart';
import 'dart:typed_data';
import 'package:appflowy/core/grid_notification.dart';
import 'package:flowy_infra/notifier.dart';
import 'package:dartz/dartz.dart';
typedef OnGroupError = void Function(FlowyError);
@ -14,14 +18,14 @@ abstract class GroupControllerDelegate {
class GroupController {
final GroupPB group;
final GroupListener _listener;
final SingleGroupListener _listener;
final GroupControllerDelegate delegate;
GroupController({
required String viewId,
required this.group,
required this.delegate,
}) : _listener = GroupListener(group);
}) : _listener = SingleGroupListener(group);
RowPB? rowAtIndex(int index) {
if (index < group.rows.length) {
@ -81,3 +85,45 @@ class GroupController {
_listener.stop();
}
}
typedef UpdateGroupNotifiedValue = Either<GroupRowsNotificationPB, FlowyError>;
class SingleGroupListener {
final GroupPB group;
PublishNotifier<UpdateGroupNotifiedValue>? _groupNotifier = PublishNotifier();
DatabaseNotificationListener? _listener;
SingleGroupListener(this.group);
void start({
required void Function(UpdateGroupNotifiedValue) onGroupChanged,
}) {
_groupNotifier?.addPublishListener(onGroupChanged);
_listener = DatabaseNotificationListener(
objectId: group.groupId,
handler: _handler,
);
}
void _handler(
DatabaseNotification ty,
Either<Uint8List, FlowyError> result,
) {
switch (ty) {
case DatabaseNotification.DidUpdateGroupRow:
result.fold(
(payload) => _groupNotifier?.value =
left(GroupRowsNotificationPB.fromBuffer(payload)),
(error) => _groupNotifier?.value = right(error),
);
break;
default:
break;
}
}
Future<void> stop() async {
await _listener?.stop();
_groupNotifier?.dispose();
_groupNotifier = null;
}
}

View File

@ -1,51 +0,0 @@
import 'dart:typed_data';
import 'package:appflowy/core/grid_notification.dart';
import 'package:flowy_infra/notifier.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-database/notification.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-database/group.pb.dart';
import 'package:dartz/dartz.dart';
import 'package:appflowy_backend/protobuf/flowy-database/group_changeset.pb.dart';
typedef UpdateGroupNotifiedValue = Either<GroupRowsNotificationPB, FlowyError>;
class GroupListener {
final GroupPB group;
PublishNotifier<UpdateGroupNotifiedValue>? _groupNotifier = PublishNotifier();
DatabaseNotificationListener? _listener;
GroupListener(this.group);
void start({
required void Function(UpdateGroupNotifiedValue) onGroupChanged,
}) {
_groupNotifier?.addPublishListener(onGroupChanged);
_listener = DatabaseNotificationListener(
objectId: group.groupId,
handler: _handler,
);
}
void _handler(
DatabaseNotification ty,
Either<Uint8List, FlowyError> result,
) {
switch (ty) {
case DatabaseNotification.DidUpdateGroupRow:
result.fold(
(payload) => _groupNotifier?.value =
left(GroupRowsNotificationPB.fromBuffer(payload)),
(error) => _groupNotifier?.value = right(error),
);
break;
default:
break;
}
}
Future<void> stop() async {
await _listener?.stop();
_groupNotifier?.dispose();
_groupNotifier = null;
}
}

View File

@ -6,8 +6,7 @@ import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/database_view/application/field/field_controller.dart';
import 'package:appflowy/plugins/database_view/application/row/row_cache.dart';
import 'package:appflowy/plugins/database_view/application/row/row_data_controller.dart';
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/cell/cell_builder.dart';
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/row/row_detail.dart';
import 'package:appflowy/plugins/database_view/widgets/row/row_detail.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-database/field_entities.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-database/row_entities.pb.dart';
@ -17,13 +16,14 @@ import 'package:flowy_infra/image.dart';
import 'package:flowy_infra_ui/flowy_infra_ui_web.dart';
import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flowy_infra_ui/widget/error_page.dart';
import 'package:flutter/material.dart';
import 'package:flutter/material.dart' hide Card;
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../widgets/card/cells/card_cell.dart';
import '../../widgets/card/card_cell_builder.dart';
import '../../widgets/row/cell_builder.dart';
import '../application/board_bloc.dart';
import '../application/card/card_data_controller.dart';
import 'card/card.dart';
import 'card/card_cell_builder.dart';
import '../../widgets/card/card.dart';
import 'toolbar/board_toolbar.dart';
class BoardPage extends StatelessWidget {
@ -78,6 +78,7 @@ class BoardContent extends StatefulWidget {
class _BoardContentState extends State<BoardContent> {
late AppFlowyBoardScrollController scrollManager;
final cardConfiguration = CardConfiguration<String>();
final config = AppFlowyBoardConfig(
groupBackgroundColor: HexColor.fromHex('#F7F8FC'),
@ -86,6 +87,16 @@ class _BoardContentState extends State<BoardContent> {
@override
void initState() {
scrollManager = AppFlowyBoardScrollController();
cardConfiguration.addSelectOptionHook((options, groupId) {
// The cell should hide if the option id is equal to the groupId.
final isInGroup =
options.where((element) => element.id == groupId).isNotEmpty;
if (isInGroup || options.isEmpty) {
return const SizedBox();
}
return null;
});
super.initState();
}
@ -225,15 +236,11 @@ class _BoardContentState extends State<BoardContent> {
/// Return placeholder widget if the rowCache is null.
if (rowCache == null) return SizedBox(key: ObjectKey(groupItem));
final cellCache = rowCache.cellCache;
final fieldController = context.read<BoardBloc>().fieldController;
final viewId = context.read<BoardBloc>().viewId;
final cardController = CardDataController(
rowCache: rowCache,
rowPB: rowPB,
);
final cellBuilder = BoardCellBuilder(cardController);
final cellBuilder = CardCellBuilder<String>(cellCache);
bool isEditing = false;
context.read<BoardBloc>().state.editingRow.fold(
() => null,
@ -247,13 +254,15 @@ class _BoardContentState extends State<BoardContent> {
key: ValueKey(groupItemId),
margin: config.cardPadding,
decoration: _makeBoxDecoration(context),
child: BoardCard(
child: Card<String>(
row: rowPB,
viewId: viewId,
groupId: groupData.group.groupId,
rowCache: rowCache,
cardData: groupData.group.groupId,
fieldId: groupItem.fieldInfo.id,
isEditing: isEditing,
cellBuilder: cellBuilder,
dataController: cardController,
configuration: cardConfiguration,
openCard: (context) => _openCard(
viewId,
fieldController,
@ -303,8 +312,9 @@ class _BoardContentState extends State<BoardContent> {
rowPB: rowPB,
);
final dataController = RowDataController(
rowInfo: rowInfo,
final dataController = RowController(
rowId: rowInfo.rowPB.id,
viewId: rowInfo.viewId,
rowCache: rowCache,
);

View File

@ -5,7 +5,6 @@ import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/style_widget/button.dart';
import 'package:flutter/material.dart';
import 'board_setting.dart';

View File

@ -1,5 +1,6 @@
import 'package:appflowy/plugins/database_view/application/cell/cell_service.dart';
import 'package:appflowy/plugins/database_view/application/field/field_controller.dart';
import 'package:appflowy/plugins/database_view/application/row/row_cache.dart';
import 'package:appflowy_backend/dispatch/dispatch.dart';
import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-error/protobuf.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/protobuf.dart';
@ -9,20 +10,24 @@ import 'package:dartz/dartz.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'calendar_data_controller.dart';
import '../../application/database_controller.dart';
import '../../application/row/row_cache.dart';
part 'calendar_bloc.freezed.dart';
class CalendarBloc extends Bloc<CalendarEvent, CalendarState> {
final CalendarDataController _databaseDataController;
final EventController calendarEventsController = EventController();
final DatabaseController _databaseController;
FieldController get fieldController =>
_databaseDataController.fieldController;
String get databaseId => _databaseDataController.databaseId;
// Getters
String get viewId => _databaseController.viewId;
CellCache get cellCache => _databaseController.rowCache.cellCache;
RowCache get rowCache => _databaseController.rowCache;
CalendarBloc({required ViewPB view})
: _databaseDataController = CalendarDataController(view: view),
: _databaseController = DatabaseController(
view: view,
layoutType: LayoutTypePB.Calendar,
),
super(CalendarState.initial(view.id)) {
on<CalendarEvent>(
(event, emit) async {
@ -30,23 +35,57 @@ class CalendarBloc extends Bloc<CalendarEvent, CalendarState> {
initial: () async {
_startListening();
await _openDatabase(emit);
_loadAllEvents();
},
didReceiveCalendarSettings: (CalendarSettingsPB settings) {
didReceiveCalendarSettings: (CalendarLayoutSettingsPB settings) {
emit(state.copyWith(settings: Some(settings)));
},
didReceiveDatabaseUpdate: (DatabasePB database) {
emit(state.copyWith(database: Some(database)));
},
didReceiveError: (FlowyError error) {
emit(state.copyWith(noneOrError: Some(error)));
didLoadAllEvents: (events) {
emit(state.copyWith(events: events));
},
createEvent: (DateTime date, String title) async {
await _createEvent(date, title);
},
didReceiveEvent: (CalendarEventData<CalendarCardData> newEvent) {
emit(state.copyWith(events: [...state.events, newEvent]));
},
didUpdateFieldInfos: (Map<String, FieldInfo> fieldInfoByFieldId) {
emit(state.copyWith(fieldInfoByFieldId: fieldInfoByFieldId));
},
);
},
);
}
FieldInfo? _getCalendarFieldInfo(String fieldId) {
final fieldInfos = _databaseController.fieldController.fieldInfos;
final index = fieldInfos.indexWhere(
(element) => element.field.id == fieldId,
);
if (index != -1) {
return fieldInfos[index];
} else {
return null;
}
}
FieldInfo? _getTitleFieldInfo() {
final fieldInfos = _databaseController.fieldController.fieldInfos;
final index = fieldInfos.indexWhere(
(element) => element.field.isPrimary,
);
if (index != -1) {
return fieldInfos[index];
} else {
return null;
}
}
Future<void> _openDatabase(Emitter<CalendarState> emit) async {
final result = await _databaseDataController.openDatabase();
final result = await _databaseController.open();
result.fold(
(database) => emit(
state.copyWith(loadingState: DatabaseLoadingState.finish(left(unit))),
@ -57,60 +96,145 @@ class CalendarBloc extends Bloc<CalendarEvent, CalendarState> {
);
}
RowCache? getRowCache(String blockId) {
return _databaseDataController.rowCache;
Future<void> _createEvent(DateTime date, String title) async {
state.settings.fold(
() => null,
(settings) async {
final dateField = _getCalendarFieldInfo(settings.layoutFieldId);
final titleField = _getTitleFieldInfo();
if (dateField != null && titleField != null) {
final result = await _databaseController.createRow(
withCells: (builder) {
builder.insertDate(dateField, date);
builder.insertText(titleField, title);
},
);
result.fold(
(newRow) => _loadEvent(newRow.id),
(err) => Log.error(err),
);
}
void _startListening() {
_databaseDataController.addListener(
onDatabaseChanged: (database) {
if (!isClosed) return;
add(CalendarEvent.didReceiveDatabaseUpdate(database));
},
onSettingsChanged: (CalendarSettingsPB settings) {
if (isClosed) return;
add(CalendarEvent.didReceiveCalendarSettings(settings));
},
onArrangeWithNewField: (field) {
if (isClosed) return;
_initializeEvents(field);
// add(CalendarEvent.)
},
onError: (err) {
Log.error(err);
},
);
}
void _initializeEvents(FieldPB dateField) {
calendarEventsController.removeWhere((element) => true);
Future<void> _loadEvent(String rowId) async {
final payload = RowIdPB(viewId: viewId, rowId: rowId);
DatabaseEventGetCalendarEvent(payload).send().then((result) {
result.fold(
(eventPB) {
final calendarEvent = _calendarEventDataFromEventPB(eventPB);
if (calendarEvent != null) {
add(CalendarEvent.didReceiveEvent(calendarEvent));
}
},
(r) => Log.error(r),
);
});
}
const events = <CalendarEventData<CalendarData>>[];
// final List<CalendarEventData<CalendarData>> events = rows.map((row) {
// final event = CalendarEventData(
// title: "",
// date: row -> dateField -> value,
// event: row,
// );
// return event;
// }).toList();
calendarEventsController.addAll(events);
Future<void> _loadAllEvents() async {
final payload = CalendarEventRequestPB.create()..viewId = viewId;
DatabaseEventGetAllCalendarEvents(payload).send().then((result) {
result.fold(
(events) {
if (!isClosed) {
final calendarEvents = <CalendarEventData<CalendarCardData>>[];
for (final eventPB in events.items) {
final calendarEvent = _calendarEventDataFromEventPB(eventPB);
if (calendarEvent != null) {
calendarEvents.add(calendarEvent);
}
}
add(CalendarEvent.didLoadAllEvents(calendarEvents));
}
},
(r) => Log.error(r),
);
});
}
CalendarEventData<CalendarCardData>? _calendarEventDataFromEventPB(
CalendarEventPB eventPB) {
final fieldInfo = state.fieldInfoByFieldId[eventPB.titleFieldId];
if (fieldInfo != null) {
final cellId = CellIdentifier(
viewId: viewId,
rowId: eventPB.rowId,
fieldInfo: fieldInfo,
);
final eventData = CalendarCardData(
event: eventPB,
cellId: cellId,
);
final date = DateTime.fromMillisecondsSinceEpoch(
eventPB.timestamp.toInt() * 1000,
isUtc: true,
);
return CalendarEventData(
title: eventPB.title,
date: date,
event: eventData,
);
} else {
return null;
}
}
void _startListening() {
final onDatabaseChanged = DatabaseCallbacks(
onDatabaseChanged: (database) {
if (isClosed) return;
},
onFieldsChanged: (fieldInfos) {
if (isClosed) return;
final fieldInfoByFieldId = {
for (var fieldInfo in fieldInfos) fieldInfo.field.id: fieldInfo
};
add(CalendarEvent.didUpdateFieldInfos(fieldInfoByFieldId));
},
);
final onLayoutChanged = LayoutCallbacks(
onLayoutChanged: _didReceiveLayoutSetting,
onLoadLayout: _didReceiveLayoutSetting,
);
_databaseController.addListener(
onDatabaseChanged: onDatabaseChanged,
onLayoutChanged: onLayoutChanged,
);
}
void _didReceiveLayoutSetting(LayoutSettingPB layoutSetting) {
if (layoutSetting.hasCalendar()) {
if (isClosed) return;
add(CalendarEvent.didReceiveCalendarSettings(layoutSetting.calendar));
}
}
}
typedef Events = List<CalendarEventData<CalendarCardData>>;
@freezed
class CalendarEvent with _$CalendarEvent {
const factory CalendarEvent.initial() = _InitialCalendar;
const factory CalendarEvent.didReceiveCalendarSettings(
CalendarSettingsPB settings) = _DidReceiveCalendarSettings;
const factory CalendarEvent.didReceiveError(FlowyError error) =
_DidReceiveError;
CalendarLayoutSettingsPB settings) = _ReceiveCalendarSettings;
const factory CalendarEvent.didLoadAllEvents(Events events) =
_ReceiveCalendarEvents;
const factory CalendarEvent.didReceiveEvent(
CalendarEventData<CalendarCardData> event) = _ReceiveEvent;
const factory CalendarEvent.didUpdateFieldInfos(
Map<String, FieldInfo> fieldInfoByFieldId) = _DidUpdateFieldInfos;
const factory CalendarEvent.createEvent(DateTime date, String title) =
_CreateEvent;
const factory CalendarEvent.didReceiveDatabaseUpdate(DatabasePB database) =
_DidReceiveDatabaseUpdate;
_ReceiveDatabaseUpdate;
}
@freezed
@ -118,9 +242,9 @@ class CalendarState with _$CalendarState {
const factory CalendarState({
required String databaseId,
required Option<DatabasePB> database,
required Option<FieldPB> dateField,
required Option<List<RowInfo>> unscheduledRows,
required Option<CalendarSettingsPB> settings,
required Events events,
required Map<String, FieldInfo> fieldInfoByFieldId,
required Option<CalendarLayoutSettingsPB> settings,
required DatabaseLoadingState loadingState,
required Option<FlowyError> noneOrError,
}) = _CalendarState;
@ -128,8 +252,8 @@ class CalendarState with _$CalendarState {
factory CalendarState.initial(String databaseId) => CalendarState(
database: none(),
databaseId: databaseId,
dateField: none(),
unscheduledRows: none(),
fieldInfoByFieldId: {},
events: [],
settings: none(),
noneOrError: none(),
loadingState: const _Loading(),
@ -153,7 +277,8 @@ class CalendarEditingRow {
});
}
class CalendarData {
final RowInfo rowInfo;
CalendarData(this.rowInfo);
class CalendarCardData {
final CalendarEventPB event;
final CellIdentifier cellId;
CalendarCardData({required this.cellId, required this.event});
}

View File

@ -1,115 +0,0 @@
import 'dart:async';
import 'dart:collection';
import 'package:appflowy/plugins/database_view/application/database_service.dart';
import 'package:appflowy/plugins/database_view/application/field/field_controller.dart';
import 'package:appflowy/plugins/database_view/application/row/row_cache.dart';
import 'package:appflowy/plugins/database_view/application/view/view_cache.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/protobuf.dart';
import 'package:appflowy_backend/protobuf/flowy-database/protobuf.dart';
import 'package:dartz/dartz.dart';
import 'calendar_listener.dart';
typedef OnFieldsChanged = void Function(UnmodifiableListView<FieldInfo>);
typedef OnDatabaseChanged = void Function(DatabasePB);
typedef OnSettingsChanged = void Function(CalendarSettingsPB);
typedef OnArrangeWithNewField = void Function(FieldPB);
typedef OnRowsChanged = void Function(List<RowInfo>, RowsChangedReason);
typedef OnError = void Function(FlowyError);
class CalendarDataController {
final String databaseId;
final DatabaseBackendService _databaseBackendSvc;
final FieldController fieldController;
final CalendarListener _listener;
late DatabaseViewCache _viewCache;
OnFieldsChanged? _onFieldsChanged;
OnDatabaseChanged? _onDatabaseChanged;
OnRowsChanged? _onRowsChanged;
OnSettingsChanged? _onSettingsChanged;
OnArrangeWithNewField? _onArrangeWithNewField;
OnError? _onError;
List<RowInfo> get rowInfos => _viewCache.rowInfos;
RowCache get rowCache => _viewCache.rowCache;
CalendarDataController({required ViewPB view})
: databaseId = view.id,
_listener = CalendarListener(view.id),
_databaseBackendSvc = DatabaseBackendService(viewId: view.id),
fieldController = FieldController(viewId: view.id) {
_viewCache = DatabaseViewCache(
viewId: view.id,
fieldController: fieldController,
);
_viewCache.addListener(onRowsChanged: (reason) {
_onRowsChanged?.call(rowInfos, reason);
});
}
void addListener({
required OnDatabaseChanged onDatabaseChanged,
OnFieldsChanged? onFieldsChanged,
OnRowsChanged? onRowsChanged,
required OnSettingsChanged? onSettingsChanged,
required OnArrangeWithNewField? onArrangeWithNewField,
required OnError? onError,
}) {
_onDatabaseChanged = onDatabaseChanged;
_onFieldsChanged = onFieldsChanged;
_onRowsChanged = onRowsChanged;
_onSettingsChanged = onSettingsChanged;
_onArrangeWithNewField = onArrangeWithNewField;
_onError = onError;
fieldController.addListener(onReceiveFields: (fields) {
_onFieldsChanged?.call(UnmodifiableListView(fields));
});
_listener.start(
onCalendarSettingsChanged: (result) {
result.fold(
(settings) => _onSettingsChanged?.call(settings),
(e) => _onError?.call(e),
);
},
onArrangeWithNewField: (result) {
result.fold(
(settings) => _onArrangeWithNewField?.call(settings),
(e) => _onError?.call(e),
);
},
);
}
Future<Either<Unit, FlowyError>> openDatabase() async {
final result = await _databaseBackendSvc.openGrid();
return result.fold(
(database) async {
_onDatabaseChanged?.call(database);
return fieldController
.loadFields(fieldIds: database.fields)
.then((result) {
return result.fold(
(l) => Future(() async {
_viewCache.rowCache.initializeRows(database.rows);
return left(l);
}),
(err) => right(err),
);
});
},
(err) => right(err),
);
}
Future<void> dispose() async {
await _viewCache.dispose();
await _databaseBackendSvc.closeView();
await fieldController.dispose();
}
}

View File

@ -1,65 +0,0 @@
import 'dart:typed_data';
import 'package:appflowy/core/grid_notification.dart';
import 'package:flowy_infra/notifier.dart';
import 'package:appflowy_backend/protobuf/flowy-error/protobuf.dart';
import 'package:appflowy_backend/protobuf/flowy-database/protobuf.dart';
import 'package:dartz/dartz.dart';
typedef CalendarSettingsValue = Either<CalendarSettingsPB, FlowyError>;
typedef ArrangeWithNewField = Either<FieldPB, FlowyError>;
class CalendarListener {
final String viewId;
PublishNotifier<CalendarSettingsValue>? _calendarSettingsNotifier =
PublishNotifier();
PublishNotifier<ArrangeWithNewField>? _arrangeWithNewFieldNotifier =
PublishNotifier();
DatabaseNotificationListener? _listener;
CalendarListener(this.viewId);
void start({
required void Function(CalendarSettingsValue) onCalendarSettingsChanged,
required void Function(ArrangeWithNewField) onArrangeWithNewField,
}) {
_calendarSettingsNotifier?.addPublishListener(onCalendarSettingsChanged);
_arrangeWithNewFieldNotifier?.addPublishListener(onArrangeWithNewField);
_listener = DatabaseNotificationListener(
objectId: viewId,
handler: _handler,
);
}
void _handler(
DatabaseNotification ty,
Either<Uint8List, FlowyError> result,
) {
switch (ty) {
case DatabaseNotification.DidUpdateCalendarSettings:
result.fold(
(payload) => _calendarSettingsNotifier?.value =
left(CalendarSettingsPB.fromBuffer(payload)),
(error) => _calendarSettingsNotifier?.value = right(error),
);
break;
case DatabaseNotification.DidArrangeCalendarWithNewField:
result.fold(
(payload) => _arrangeWithNewFieldNotifier?.value =
left(FieldPB.fromBuffer(payload)),
(error) => _arrangeWithNewFieldNotifier?.value = right(error),
);
break;
default:
break;
}
}
Future<void> stop() async {
await _listener?.stop();
_calendarSettingsNotifier?.dispose();
_calendarSettingsNotifier = null;
_arrangeWithNewFieldNotifier?.dispose();
_arrangeWithNewFieldNotifier = null;
}
}

View File

@ -77,8 +77,7 @@ class CalendarPluginDisplay extends PluginDisplay {
});
});
return CalendarPage(key: ValueKey(view.id));
// return CalendarPage(key: ValueKey(view.id), view: view);
return CalendarPage(key: ValueKey(view.id), view: view);
}
@override

View File

@ -1,56 +1,83 @@
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/database_view/application/row/row_data_controller.dart';
import 'package:appflowy/plugins/database_view/calendar/application/calendar_bloc.dart';
import 'package:appflowy/plugins/database_view/widgets/card/card_cell_builder.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:calendar_view/calendar_view.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/image.dart';
import 'package:flowy_infra/size.dart';
import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra_ui/style_widget/button.dart';
import 'package:flowy_infra_ui/style_widget/icon_button.dart';
import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/style_widget/hover.dart';
import 'package:flutter/material.dart';
import 'package:styled_widget/styled_widget.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:provider/provider.dart';
import '../../grid/presentation/layout/sizes.dart';
import '../../widgets/row/cell_builder.dart';
import '../../widgets/row/row_detail.dart';
import 'layout/sizes.dart';
import 'toolbar/calendar_toolbar.dart';
class CalendarPage extends StatelessWidget {
const CalendarPage({super.key});
class CalendarPage extends StatefulWidget {
final ViewPB view;
const CalendarPage({required this.view, super.key});
@override
Widget build(BuildContext context) {
return const CalendarContent();
}
State<CalendarPage> createState() => _CalendarPageState();
}
class CalendarContent extends StatefulWidget {
const CalendarContent({super.key});
@override
State<CalendarContent> createState() => _CalendarContentState();
}
class _CalendarContentState extends State<CalendarContent> {
late EventController _eventController;
class _CalendarPageState extends State<CalendarPage> {
final _eventController = EventController<CalendarCardData>();
GlobalKey<MonthViewState>? _calendarState;
late CalendarBloc _calendarBloc;
@override
void initState() {
_eventController = EventController();
_calendarState = GlobalKey<MonthViewState>();
_calendarBloc = CalendarBloc(view: widget.view)
..add(const CalendarEvent.initial());
super.initState();
}
@override
void dispose() {
_calendarBloc.close();
super.dispose();
}
@override
Widget build(BuildContext context) {
return CalendarControllerProvider(
controller: _eventController,
child: Column(
child: MultiBlocProvider(
providers: [
BlocProvider<CalendarBloc>.value(
value: _calendarBloc,
)
],
child: BlocListener<CalendarBloc, CalendarState>(
listenWhen: (previous, current) => previous.events != current.events,
listener: (context, state) {
if (state.events.isNotEmpty) {
_eventController.removeWhere((element) => true);
_eventController.addAll(state.events);
}
},
child: BlocBuilder<CalendarBloc, CalendarState>(
builder: (context, state) {
return Column(
children: [
// const _ToolbarBlocAdaptor(),
_toolbar(),
_buildCalendar(_eventController),
],
);
},
),
),
),
);
}
@ -125,9 +152,190 @@ class _CalendarContentState extends State<CalendarContent> {
);
}
Widget _calendarDayBuilder(date, event, isToday, isInMonth) {
Widget _calendarDayBuilder(
DateTime date,
List<CalendarEventData<CalendarCardData>> calenderEvents,
isToday,
isInMonth,
) {
final builder = CardCellBuilder(_calendarBloc.cellCache);
final cells = calenderEvents.map((value) => value.event!).map((event) {
final child = builder.buildCell(cellId: event.cellId);
return FlowyHover(
child: GestureDetector(
onTap: () {
final dataController = RowController(
rowId: event.cellId.rowId,
viewId: widget.view.id,
rowCache: _calendarBloc.rowCache,
);
FlowyOverlay.show(
context: context,
builder: (BuildContext context) {
return RowDetailPage(
cellBuilder:
GridCellBuilder(cellCache: _calendarBloc.cellCache),
dataController: dataController,
);
},
);
},
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: child,
),
),
);
}).toList();
return _CalendarCard(
isToday: isToday,
isInMonth: isInMonth,
date: date,
children: cells,
onCreateEvent: (date) {
_calendarBloc.add(
CalendarEvent.createEvent(
date,
LocaleKeys.calendar_defaultNewCalendarTitle.tr(),
),
);
},
);
}
}
class _CalendarCard extends StatelessWidget {
final bool isToday;
final bool isInMonth;
final DateTime date;
final List<Widget> children;
final void Function(DateTime) onCreateEvent;
const _CalendarCard({
required this.isToday,
required this.isInMonth,
required this.date,
required this.children,
required this.onCreateEvent,
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
Color backgroundColor = Theme.of(context).colorScheme.surface;
if (!isInMonth) {
backgroundColor = AFThemeExtension.of(context).lightGreyHover;
}
return ChangeNotifierProvider(
create: (_) => _CardEnterNotifier(),
builder: ((context, child) {
return Container(
color: backgroundColor,
child: MouseRegion(
cursor: SystemMouseCursors.click,
onEnter: (p) => notifyEnter(context, true),
onExit: (p) => notifyEnter(context, false),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
_Header(
date: date,
isInMonth: isInMonth,
isToday: isToday,
onCreate: () => onCreateEvent(date),
),
...children
],
),
),
),
);
}),
);
}
notifyEnter(BuildContext context, bool isEnter) {
Provider.of<_CardEnterNotifier>(
context,
listen: false,
).onEnter = isEnter;
}
}
class _Header extends StatelessWidget {
final bool isToday;
final bool isInMonth;
final DateTime date;
final VoidCallback onCreate;
const _Header({
required this.isToday,
required this.isInMonth,
required this.date,
required this.onCreate,
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Consumer<_CardEnterNotifier>(
builder: (context, notifier, _) {
final badge = _DayBadge(
isToday: isToday,
isInMonth: isInMonth,
date: date,
);
return Row(
children: [
if (notifier.onEnter) _NewEventButton(onClick: onCreate),
const Spacer(),
badge,
],
);
},
);
}
}
class _NewEventButton extends StatelessWidget {
final VoidCallback onClick;
const _NewEventButton({
required this.onClick,
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return FlowyIconButton(
onPressed: onClick,
iconPadding: EdgeInsets.zero,
icon: svgWidget(
"home/add",
color: Theme.of(context).colorScheme.onSurface,
),
width: 22,
);
}
}
class _DayBadge extends StatelessWidget {
final bool isToday;
final bool isInMonth;
final DateTime date;
const _DayBadge({
required this.isToday,
required this.isInMonth,
required this.date,
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
Color dayTextColor = Theme.of(context).colorScheme.onSurface;
Color cellBackgroundColor = Theme.of(context).colorScheme.surface;
String dayString = date.day == 1
? DateFormat('MMM d', context.locale.toLanguageTag()).format(date)
: date.day.toString();
@ -137,8 +345,8 @@ class _CalendarContentState extends State<CalendarContent> {
}
if (!isInMonth) {
dayTextColor = Theme.of(context).disabledColor;
cellBackgroundColor = AFThemeExtension.of(context).lightGreyHover;
}
Widget day = Container(
decoration: BoxDecoration(
color: isToday ? Theme.of(context).colorScheme.primary : null,
@ -151,12 +359,21 @@ class _CalendarContentState extends State<CalendarContent> {
),
);
return Container(
color: cellBackgroundColor,
child: Align(
alignment: Alignment.topRight,
child: day.padding(all: 6.0),
),
);
return day;
}
}
class _CardEnterNotifier extends ChangeNotifier {
bool _onEnter = false;
_CardEnterNotifier();
set onEnter(bool value) {
if (_onEnter != value) {
_onEnter = value;
notifyListeners();
}
}
bool get onEnter => _onEnter;
}

View File

@ -9,7 +9,7 @@ import 'package:appflowy_backend/protobuf/flowy-database/protobuf.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import '../../application/field/field_controller.dart';
import 'grid_data_controller.dart';
import '../../application/database_controller.dart';
import 'dart:collection';
part 'grid_bloc.freezed.dart';
@ -66,10 +66,10 @@ class GridBloc extends Bloc<GridEvent, GridState> {
}
void _startListening() {
databaseController.addListener(
onGridChanged: (grid) {
final onDatabaseChanged = DatabaseCallbacks(
onDatabaseChanged: (database) {
if (!isClosed) {
add(GridEvent.didReceiveGridUpdate(grid));
add(GridEvent.didReceiveGridUpdate(database));
}
},
onRowsChanged: (rowInfos, reason) {
@ -83,10 +83,11 @@ class GridBloc extends Bloc<GridEvent, GridState> {
}
},
);
databaseController.addListener(onDatabaseChanged: onDatabaseChanged);
}
Future<void> _openGrid(Emitter<GridState> emit) async {
final result = await databaseController.openGrid();
final result = await databaseController.open();
result.fold(
(grid) {
emit(

View File

@ -1,83 +0,0 @@
import 'package:appflowy/plugins/database_view/application/field/field_controller.dart';
import 'package:appflowy/plugins/database_view/application/view/view_cache.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:collection/collection.dart';
import 'dart:async';
import 'package:dartz/dartz.dart';
import '../../application/database_service.dart';
import '../../application/defines.dart';
import '../../application/row/row_cache.dart';
typedef OnRowsChanged = void Function(
List<RowInfo> rowInfos,
RowsChangedReason,
);
typedef ListenOnRowChangedCondition = bool Function();
class DatabaseController {
final String viewId;
final DatabaseBackendService _databaseBackendSvc;
final FieldController fieldController;
late DatabaseViewCache _viewCache;
OnRowsChanged? _onRowChanged;
OnDatabaseChanged? _onGridChanged;
List<RowInfo> get rowInfos => _viewCache.rowInfos;
RowCache get rowCache => _viewCache.rowCache;
DatabaseController({required ViewPB view})
: viewId = view.id,
_databaseBackendSvc = DatabaseBackendService(viewId: view.id),
fieldController = FieldController(viewId: view.id) {
_viewCache = DatabaseViewCache(
viewId: viewId,
fieldController: fieldController,
);
_viewCache.addListener(onRowsChanged: (reason) {
_onRowChanged?.call(rowInfos, reason);
});
}
void addListener({
OnDatabaseChanged? onGridChanged,
OnRowsChanged? onRowsChanged,
OnFieldsChanged? onFieldsChanged,
OnFiltersChanged? onFiltersChanged,
}) {
_onGridChanged = onGridChanged;
_onRowChanged = onRowsChanged;
fieldController.addListener(
onReceiveFields: (fields) {
onFieldsChanged?.call(UnmodifiableListView(fields));
},
onFilters: onFiltersChanged,
);
}
Future<Either<Unit, FlowyError>> openGrid() async {
return _databaseBackendSvc.openGrid().then((result) {
return result.fold(
(grid) async {
_onGridChanged?.call(grid);
_viewCache.rowCache.initializeRows(grid.rows);
final result = await fieldController.loadFields(
fieldIds: grid.fields,
);
return result;
},
(err) => right(err),
);
});
}
Future<void> createRow() async {
await _databaseBackendSvc.createRow();
}
Future<void> dispose() async {
await _databaseBackendSvc.closeView();
await fieldController.dispose();
}
}

View File

@ -14,11 +14,11 @@ part 'row_bloc.freezed.dart';
class RowBloc extends Bloc<RowEvent, RowState> {
final RowBackendService _rowBackendSvc;
final RowDataController _dataController;
final RowController _dataController;
RowBloc({
required RowInfo rowInfo,
required RowDataController dataController,
required RowController dataController,
}) : _rowBackendSvc = RowBackendService(viewId: rowInfo.viewId),
_dataController = dataController,
super(RowState.initial(rowInfo, dataController.loadData())) {

View File

@ -7,7 +7,7 @@ import '../../../application/row/row_data_controller.dart';
part 'row_detail_bloc.freezed.dart';
class RowDetailBloc extends Bloc<RowDetailEvent, RowDetailState> {
final RowDataController dataController;
final RowController dataController;
RowDetailBloc({
required this.dataController,
@ -27,7 +27,7 @@ class RowDetailBloc extends Bloc<RowDetailEvent, RowDetailState> {
},
deleteField: (_DeleteField value) {
final fieldService = FieldBackendService(
viewId: dataController.rowInfo.viewId,
viewId: dataController.viewId,
fieldId: value.fieldId,
);
fieldService.deleteField();

View File

@ -1,4 +1,6 @@
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/database_view/widgets/row/cell_builder.dart';
import 'package:appflowy_backend/protobuf/flowy-database/setting_entities.pbenum.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui_web.dart';
import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart';
@ -16,17 +18,16 @@ import '../../application/row/row_data_controller.dart';
import '../../application/setting/setting_bloc.dart';
import '../application/filter/filter_menu_bloc.dart';
import '../application/grid_bloc.dart';
import '../application/grid_data_controller.dart';
import '../../application/database_controller.dart';
import '../application/sort/sort_menu_bloc.dart';
import 'grid_scroll.dart';
import 'layout/layout.dart';
import 'layout/sizes.dart';
import 'widgets/accessory_menu.dart';
import 'widgets/cell/cell_builder.dart';
import 'widgets/row/grid_row.dart';
import 'widgets/row/row.dart';
import 'widgets/footer/grid_footer.dart';
import 'widgets/header/grid_header.dart';
import 'widgets/row/row_detail.dart';
import '../../widgets/row/row_detail.dart';
import 'widgets/shortcuts.dart';
import 'widgets/toolbar/grid_toolbar.dart';
@ -35,7 +36,10 @@ class GridPage extends StatefulWidget {
required this.view,
this.onDeleted,
Key? key,
}) : databaseController = DatabaseController(view: view),
}) : databaseController = DatabaseController(
view: view,
layoutType: LayoutTypePB.Grid,
),
super(key: key);
final ViewPB view;
@ -275,14 +279,15 @@ class _GridRowsState extends State<_GridRows> {
final fieldController =
context.read<GridBloc>().databaseController.fieldController;
final dataController = RowDataController(
rowInfo: rowInfo,
final dataController = RowController(
rowId: rowInfo.rowPB.id,
viewId: rowInfo.viewId,
rowCache: rowCache,
);
return SizeTransition(
sizeFactor: animation,
child: GridRowWidget(
child: GridRow(
rowInfo: rowInfo,
dataController: dataController,
cellBuilder: GridCellBuilder(cellCache: dataController.cellCache),
@ -307,8 +312,9 @@ class _GridRowsState extends State<_GridRows> {
RowCache rowCache,
GridCellBuilder cellBuilder,
) {
final dataController = RowDataController(
rowInfo: rowInfo,
final dataController = RowController(
viewId: rowInfo.viewId,
rowId: rowInfo.rowPB.id,
rowCache: rowCache,
);

View File

@ -1,7 +0,0 @@
export 'cell_builder.dart';
export 'text_cell.dart';
export 'number_cell.dart';
export 'date_cell/date_cell.dart';
export 'checkbox_cell.dart';
export 'select_option_cell/select_option_cell.dart';
export 'url_cell/url_cell.dart';

View File

@ -5,7 +5,6 @@ import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/image.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/widget/spacing.dart';
import 'package:appflowy_backend/protobuf/flowy-database/checkbox_filter.pbenum.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

View File

@ -4,7 +4,6 @@ import 'package:appflowy/workspace/presentation/widgets/pop_up_action.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/widget/spacing.dart';
import 'package:appflowy_backend/protobuf/flowy-database/checklist_filter.pbenum.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

View File

@ -8,7 +8,7 @@ import 'package:appflowy_backend/protobuf/flowy-database/select_type_option.pb.d
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../../cell/select_option_cell/extension.dart';
import '../../../../../../widgets/row/cells/select_option_cell/extension.dart';
import '../../filter_info.dart';
import 'select_option_loader.dart';

View File

@ -1,8 +1,6 @@
import 'package:appflowy/plugins/database_view/grid/application/filter/select_option_filter_bloc.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart';
import 'package:flowy_infra_ui/widget/spacing.dart';
import 'package:appflowy_backend/protobuf/flowy-database/field_entities.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-database/select_option_filter.pb.dart';
import 'package:flutter/material.dart';

View File

@ -4,7 +4,6 @@ import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/image.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/widget/spacing.dart';
import 'package:appflowy_backend/protobuf/flowy-database/text_filter.pb.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

View File

@ -5,7 +5,6 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra/image.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/style_widget/button.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

View File

@ -4,7 +4,6 @@ import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:flowy_infra/image.dart';
import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/style_widget/button.dart';
import 'package:flowy_infra_ui/style_widget/hover.dart';
import 'package:appflowy_backend/protobuf/flowy-database/field_entities.pb.dart';
import 'package:flutter/material.dart';

View File

@ -1,9 +1,6 @@
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:flowy_infra/image.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/style_widget/button.dart';
import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart';
import 'package:flowy_infra_ui/widget/spacing.dart';
import 'package:appflowy_backend/protobuf/flowy-database/field_entities.pb.dart';
import 'package:flutter/material.dart';
import '../../layout/sizes.dart';

View File

@ -5,7 +5,6 @@ import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:dartz/dartz.dart' show Either;
import 'package:flowy_infra/image.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/style_widget/button.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-database/field_entities.pb.dart';
import 'package:flutter/material.dart';

View File

@ -9,7 +9,6 @@ import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra/image.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/style_widget/button.dart';
import 'package:appflowy_backend/protobuf/flowy-database/field_entities.pb.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

View File

@ -6,8 +6,6 @@ import 'package:easy_localization/easy_localization.dart' hide DateFormat;
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:flowy_infra/image.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/style_widget/button.dart';
import 'package:flowy_infra_ui/widget/spacing.dart';
import 'package:appflowy_backend/protobuf/flowy-database/date_type_option_entities.pb.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

View File

@ -4,8 +4,6 @@ import 'package:appflowy/plugins/database_view/application/field/type_option/typ
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:flowy_infra/image.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/style_widget/button.dart';
import 'package:flowy_infra_ui/widget/spacing.dart';
import 'package:appflowy_backend/protobuf/flowy-database/format.pbenum.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

View File

@ -2,8 +2,6 @@ import 'package:appflowy/plugins/database_view/application/field/type_option/sel
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:flowy_infra/image.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/style_widget/button.dart';
import 'package:flowy_infra_ui/widget/spacing.dart';
import 'package:appflowy_backend/protobuf/flowy-database/select_type_option.pb.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@ -11,7 +9,7 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import '../../../layout/sizes.dart';
import '../../cell/select_option_cell/extension.dart';
import '../../../../../widgets/row/cells/select_option_cell/extension.dart';
import '../../common/type_option_separator.dart';
import 'select_option_editor.dart';

View File

@ -1,5 +1,5 @@
import 'package:appflowy/plugins/database_view/application/field/type_option/edit_select_option_bloc.dart';
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/cell/select_option_cell/extension.dart';
import 'package:appflowy/plugins/database_view/widgets/row/cells/select_option_cell/extension.dart';
import 'package:flowy_infra/image.dart';
import 'package:flowy_infra_ui/style_widget/button.dart';
import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart';

View File

@ -12,9 +12,9 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import '../../layout/sizes.dart';
class GridRowActionSheet extends StatelessWidget {
class RowActions extends StatelessWidget {
final RowInfo rowData;
const GridRowActionSheet({required this.rowData, Key? key}) : super(key: key);
const RowActions({required this.rowData, Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
@ -24,9 +24,7 @@ class GridRowActionSheet extends StatelessWidget {
builder: (context, state) {
final cells = _RowAction.values
.where((value) => value.enable())
.map(
(action) => _RowActionCell(action: action),
)
.map((action) => _ActionCell(action: action))
.toList();
//
@ -49,9 +47,9 @@ class GridRowActionSheet extends StatelessWidget {
}
}
class _RowActionCell extends StatelessWidget {
class _ActionCell extends StatelessWidget {
final _RowAction action;
const _RowActionCell({required this.action, Key? key}) : super(key: key);
const _ActionCell({required this.action, Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {

View File

@ -2,30 +2,29 @@ import 'package:appflowy/plugins/database_view/application/cell/cell_service.dar
import 'package:appflowy/plugins/database_view/application/row/row_cache.dart';
import 'package:appflowy/plugins/database_view/application/row/row_data_controller.dart';
import 'package:appflowy/plugins/database_view/grid/application/row/row_bloc.dart';
import 'package:appflowy/plugins/database_view/widgets/row/cell_builder.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:flowy_infra/image.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/style_widget/icon_button.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:provider/provider.dart';
import '../../../../widgets/row/accessory/cell_accessory.dart';
import '../../layout/sizes.dart';
import '../cell/cell_accessory.dart';
import '../cell/cell_container.dart';
import '../cell/prelude.dart';
import 'row_action_sheet.dart';
import '../../../../widgets/row/cells/cell_container.dart';
import 'action.dart';
import "package:appflowy/generated/locale_keys.g.dart";
import 'package:easy_localization/easy_localization.dart';
class GridRowWidget extends StatefulWidget {
class GridRow extends StatefulWidget {
final RowInfo rowInfo;
final RowDataController dataController;
final RowController dataController;
final GridCellBuilder cellBuilder;
final void Function(BuildContext, GridCellBuilder) openDetailPage;
const GridRowWidget({
const GridRow({
required this.rowInfo,
required this.dataController,
required this.cellBuilder,
@ -34,10 +33,10 @@ class GridRowWidget extends StatefulWidget {
}) : super(key: key);
@override
State<GridRowWidget> createState() => _GridRowWidgetState();
State<GridRow> createState() => _GridRowState();
}
class _GridRowWidgetState extends State<GridRowWidget> {
class _GridRowState extends State<GridRow> {
late RowBloc _rowBloc;
@override
@ -111,8 +110,7 @@ class _RowLeadingState extends State<_RowLeading> {
direction: PopoverDirection.rightWithCenterAligned,
margin: const EdgeInsets.all(6),
popupBuilder: (BuildContext popoverContext) {
return GridRowActionSheet(
rowData: context.read<RowBloc>().state.rowInfo);
return RowActions(rowData: context.read<RowBloc>().state.rowInfo);
},
child: Consumer<RegionStateNotifier>(
builder: (context, state, _) {

View File

@ -9,9 +9,6 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/image.dart';
import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/style_widget/button.dart';
import 'package:flowy_infra_ui/style_widget/icon_button.dart';
import 'package:flowy_infra_ui/widget/spacing.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'dart:math' as math;

View File

@ -4,7 +4,6 @@ import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/style_widget/button.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

View File

@ -6,9 +6,6 @@ import 'package:appflowy/startup/startup.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:flowy_infra/image.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/style_widget/button.dart';
import 'package:flowy_infra_ui/style_widget/icon_button.dart';
import 'package:flowy_infra_ui/widget/spacing.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:styled_widget/styled_widget.dart';

View File

@ -5,7 +5,6 @@ import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/style_widget/button.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:styled_widget/styled_widget.dart';

View File

@ -4,7 +4,6 @@ import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/style_widget/button.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

View File

@ -3,16 +3,16 @@ import 'package:freezed_annotation/freezed_annotation.dart';
import 'dart:async';
import '../../../application/cell/cell_controller_builder.dart';
part 'board_checkbox_cell_bloc.freezed.dart';
part 'checkbox_card_cell_bloc.freezed.dart';
class BoardCheckboxCellBloc
extends Bloc<BoardCheckboxCellEvent, BoardCheckboxCellState> {
class CheckboxCardCellBloc
extends Bloc<CheckboxCardCellEvent, CheckboxCardCellState> {
final CheckboxCellController cellController;
void Function()? _onCellChangedFn;
BoardCheckboxCellBloc({
CheckboxCardCellBloc({
required this.cellController,
}) : super(BoardCheckboxCellState.initial(cellController)) {
on<BoardCheckboxCellEvent>(
}) : super(CheckboxCardCellState.initial(cellController)) {
on<CheckboxCardCellEvent>(
(event, emit) async {
await event.when(
initial: () async {
@ -43,7 +43,7 @@ class BoardCheckboxCellBloc
_onCellChangedFn = cellController.startListening(
onCellChanged: ((cellContent) {
if (!isClosed) {
add(BoardCheckboxCellEvent.didReceiveCellUpdate(cellContent ?? ""));
add(CheckboxCardCellEvent.didReceiveCellUpdate(cellContent ?? ""));
}
}),
);
@ -51,21 +51,21 @@ class BoardCheckboxCellBloc
}
@freezed
class BoardCheckboxCellEvent with _$BoardCheckboxCellEvent {
const factory BoardCheckboxCellEvent.initial() = _InitialCell;
const factory BoardCheckboxCellEvent.select() = _Selected;
const factory BoardCheckboxCellEvent.didReceiveCellUpdate(
String cellContent) = _DidReceiveCellUpdate;
class CheckboxCardCellEvent with _$CheckboxCardCellEvent {
const factory CheckboxCardCellEvent.initial() = _InitialCell;
const factory CheckboxCardCellEvent.select() = _Selected;
const factory CheckboxCardCellEvent.didReceiveCellUpdate(String cellContent) =
_DidReceiveCellUpdate;
}
@freezed
class BoardCheckboxCellState with _$BoardCheckboxCellState {
const factory BoardCheckboxCellState({
class CheckboxCardCellState with _$CheckboxCardCellState {
const factory CheckboxCardCellState({
required bool isSelected,
}) = _CheckboxCellState;
factory BoardCheckboxCellState.initial(TextCellController context) {
return BoardCheckboxCellState(
factory CheckboxCardCellState.initial(TextCellController context) {
return CheckboxCardCellState(
isSelected: _isSelected(context.getCellData()));
}
}

View File

@ -5,15 +5,15 @@ import 'dart:async';
import '../../../application/cell/cell_controller_builder.dart';
import '../../../application/field/field_controller.dart';
part 'board_date_cell_bloc.freezed.dart';
part 'date_card_cell_bloc.freezed.dart';
class BoardDateCellBloc extends Bloc<BoardDateCellEvent, BoardDateCellState> {
class DateCardCellBloc extends Bloc<DateCardCellEvent, DateCardCellState> {
final DateCellController cellController;
void Function()? _onCellChangedFn;
BoardDateCellBloc({required this.cellController})
: super(BoardDateCellState.initial(cellController)) {
on<BoardDateCellEvent>(
DateCardCellBloc({required this.cellController})
: super(DateCardCellState.initial(cellController)) {
on<DateCardCellEvent>(
(event, emit) async {
event.when(
initial: () => _startListening(),
@ -40,7 +40,7 @@ class BoardDateCellBloc extends Bloc<BoardDateCellEvent, BoardDateCellState> {
_onCellChangedFn = cellController.startListening(
onCellChanged: ((data) {
if (!isClosed) {
add(BoardDateCellEvent.didReceiveCellUpdate(data));
add(DateCardCellEvent.didReceiveCellUpdate(data));
}
}),
);
@ -48,24 +48,24 @@ class BoardDateCellBloc extends Bloc<BoardDateCellEvent, BoardDateCellState> {
}
@freezed
class BoardDateCellEvent with _$BoardDateCellEvent {
const factory BoardDateCellEvent.initial() = _InitialCell;
const factory BoardDateCellEvent.didReceiveCellUpdate(DateCellDataPB? data) =
class DateCardCellEvent with _$DateCardCellEvent {
const factory DateCardCellEvent.initial() = _InitialCell;
const factory DateCardCellEvent.didReceiveCellUpdate(DateCellDataPB? data) =
_DidReceiveCellUpdate;
}
@freezed
class BoardDateCellState with _$BoardDateCellState {
const factory BoardDateCellState({
class DateCardCellState with _$DateCardCellState {
const factory DateCardCellState({
required DateCellDataPB? data,
required String dateStr,
required FieldInfo fieldInfo,
}) = _BoardDateCellState;
}) = _DateCardCellState;
factory BoardDateCellState.initial(DateCellController context) {
factory DateCardCellState.initial(DateCellController context) {
final cellData = context.getCellData();
return BoardDateCellState(
return DateCardCellState(
fieldInfo: context.fieldInfo,
data: cellData,
dateStr: _dateStrFromCellData(cellData),

View File

@ -4,16 +4,16 @@ import 'dart:async';
import '../../../application/cell/cell_controller_builder.dart';
part 'board_number_cell_bloc.freezed.dart';
part 'number_card_cell_bloc.freezed.dart';
class BoardNumberCellBloc
extends Bloc<BoardNumberCellEvent, BoardNumberCellState> {
class NumberCardCellBloc
extends Bloc<NumberCardCellEvent, NumberCardCellState> {
final NumberCellController cellController;
void Function()? _onCellChangedFn;
BoardNumberCellBloc({
NumberCardCellBloc({
required this.cellController,
}) : super(BoardNumberCellState.initial(cellController)) {
on<BoardNumberCellEvent>(
}) : super(NumberCardCellState.initial(cellController)) {
on<NumberCardCellEvent>(
(event, emit) async {
await event.when(
initial: () async {
@ -41,7 +41,7 @@ class BoardNumberCellBloc
_onCellChangedFn = cellController.startListening(
onCellChanged: ((cellContent) {
if (!isClosed) {
add(BoardNumberCellEvent.didReceiveCellUpdate(cellContent ?? ""));
add(NumberCardCellEvent.didReceiveCellUpdate(cellContent ?? ""));
}
}),
);
@ -49,20 +49,20 @@ class BoardNumberCellBloc
}
@freezed
class BoardNumberCellEvent with _$BoardNumberCellEvent {
const factory BoardNumberCellEvent.initial() = _InitialCell;
const factory BoardNumberCellEvent.didReceiveCellUpdate(String cellContent) =
class NumberCardCellEvent with _$NumberCardCellEvent {
const factory NumberCardCellEvent.initial() = _InitialCell;
const factory NumberCardCellEvent.didReceiveCellUpdate(String cellContent) =
_DidReceiveCellUpdate;
}
@freezed
class BoardNumberCellState with _$BoardNumberCellState {
const factory BoardNumberCellState({
class NumberCardCellState with _$NumberCardCellState {
const factory NumberCardCellState({
required String content,
}) = _BoardNumberCellState;
}) = _NumberCardCellState;
factory BoardNumberCellState.initial(TextCellController context) =>
BoardNumberCellState(
factory NumberCardCellState.initial(TextCellController context) =>
NumberCardCellState(
content: context.getCellData() ?? "",
);
}

View File

@ -4,17 +4,17 @@ import 'package:appflowy_backend/protobuf/flowy-database/select_type_option.pb.d
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
part 'board_select_option_cell_bloc.freezed.dart';
part 'select_option_card_cell_bloc.freezed.dart';
class BoardSelectOptionCellBloc
extends Bloc<BoardSelectOptionCellEvent, BoardSelectOptionCellState> {
class SelectOptionCardCellBloc
extends Bloc<SelectOptionCardCellEvent, SelectOptionCardCellState> {
final SelectOptionCellController cellController;
void Function()? _onCellChangedFn;
BoardSelectOptionCellBloc({
SelectOptionCardCellBloc({
required this.cellController,
}) : super(BoardSelectOptionCellState.initial(cellController)) {
on<BoardSelectOptionCellEvent>(
}) : super(SelectOptionCardCellState.initial(cellController)) {
on<SelectOptionCardCellEvent>(
(event, emit) async {
await event.when(
initial: () async {
@ -42,7 +42,7 @@ class BoardSelectOptionCellBloc
_onCellChangedFn = cellController.startListening(
onCellChanged: ((selectOptionContext) {
if (!isClosed) {
add(BoardSelectOptionCellEvent.didReceiveOptions(
add(SelectOptionCardCellEvent.didReceiveOptions(
selectOptionContext?.selectOptions ?? [],
));
}
@ -52,23 +52,23 @@ class BoardSelectOptionCellBloc
}
@freezed
class BoardSelectOptionCellEvent with _$BoardSelectOptionCellEvent {
const factory BoardSelectOptionCellEvent.initial() = _InitialCell;
const factory BoardSelectOptionCellEvent.didReceiveOptions(
class SelectOptionCardCellEvent with _$SelectOptionCardCellEvent {
const factory SelectOptionCardCellEvent.initial() = _InitialCell;
const factory SelectOptionCardCellEvent.didReceiveOptions(
List<SelectOptionPB> selectedOptions,
) = _DidReceiveOptions;
}
@freezed
class BoardSelectOptionCellState with _$BoardSelectOptionCellState {
const factory BoardSelectOptionCellState({
class SelectOptionCardCellState with _$SelectOptionCardCellState {
const factory SelectOptionCardCellState({
required List<SelectOptionPB> selectedOptions,
}) = _BoardSelectOptionCellState;
}) = _SelectOptionCardCellState;
factory BoardSelectOptionCellState.initial(
factory SelectOptionCardCellState.initial(
SelectOptionCellController context) {
final data = context.getCellData();
return BoardSelectOptionCellState(
return SelectOptionCardCellState(
selectedOptions: data?.selectOptions ?? [],
);
}

View File

@ -3,15 +3,15 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'dart:async';
part 'board_text_cell_bloc.freezed.dart';
part 'text_card_cell_bloc.freezed.dart';
class BoardTextCellBloc extends Bloc<BoardTextCellEvent, BoardTextCellState> {
class TextCardCellBloc extends Bloc<TextCardCellEvent, TextCardCellState> {
final TextCellController cellController;
void Function()? _onCellChangedFn;
BoardTextCellBloc({
TextCardCellBloc({
required this.cellController,
}) : super(BoardTextCellState.initial(cellController)) {
on<BoardTextCellEvent>(
}) : super(TextCardCellState.initial(cellController)) {
on<TextCardCellEvent>(
(event, emit) async {
await event.when(
initial: () async {
@ -48,7 +48,7 @@ class BoardTextCellBloc extends Bloc<BoardTextCellEvent, BoardTextCellState> {
_onCellChangedFn = cellController.startListening(
onCellChanged: ((cellContent) {
if (!isClosed) {
add(BoardTextCellEvent.didReceiveCellUpdate(cellContent ?? ""));
add(TextCardCellEvent.didReceiveCellUpdate(cellContent ?? ""));
}
}),
);
@ -56,23 +56,23 @@ class BoardTextCellBloc extends Bloc<BoardTextCellEvent, BoardTextCellState> {
}
@freezed
class BoardTextCellEvent with _$BoardTextCellEvent {
const factory BoardTextCellEvent.initial() = _InitialCell;
const factory BoardTextCellEvent.updateText(String text) = _UpdateContent;
const factory BoardTextCellEvent.enableEdit(bool enabled) = _EnableEdit;
const factory BoardTextCellEvent.didReceiveCellUpdate(String cellContent) =
class TextCardCellEvent with _$TextCardCellEvent {
const factory TextCardCellEvent.initial() = _InitialCell;
const factory TextCardCellEvent.updateText(String text) = _UpdateContent;
const factory TextCardCellEvent.enableEdit(bool enabled) = _EnableEdit;
const factory TextCardCellEvent.didReceiveCellUpdate(String cellContent) =
_DidReceiveCellUpdate;
}
@freezed
class BoardTextCellState with _$BoardTextCellState {
const factory BoardTextCellState({
class TextCardCellState with _$TextCardCellState {
const factory TextCardCellState({
required String content,
required bool enableEdit,
}) = _BoardTextCellState;
}) = _TextCardCellState;
factory BoardTextCellState.initial(TextCellController context) =>
BoardTextCellState(
factory TextCardCellState.initial(TextCellController context) =>
TextCardCellState(
content: context.getCellData() ?? "",
enableEdit: false,
);

View File

@ -4,15 +4,15 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'dart:async';
part 'board_url_cell_bloc.freezed.dart';
part 'url_card_cell_bloc.freezed.dart';
class BoardURLCellBloc extends Bloc<BoardURLCellEvent, BoardURLCellState> {
class URLCardCellBloc extends Bloc<URLCardCellEvent, URLCardCellState> {
final URLCellController cellController;
void Function()? _onCellChangedFn;
BoardURLCellBloc({
URLCardCellBloc({
required this.cellController,
}) : super(BoardURLCellState.initial(cellController)) {
on<BoardURLCellEvent>(
}) : super(URLCardCellState.initial(cellController)) {
on<URLCardCellEvent>(
(event, emit) async {
event.when(
initial: () {
@ -46,7 +46,7 @@ class BoardURLCellBloc extends Bloc<BoardURLCellEvent, BoardURLCellState> {
_onCellChangedFn = cellController.startListening(
onCellChanged: ((cellData) {
if (!isClosed) {
add(BoardURLCellEvent.didReceiveCellUpdate(cellData));
add(URLCardCellEvent.didReceiveCellUpdate(cellData));
}
}),
);
@ -54,23 +54,23 @@ class BoardURLCellBloc extends Bloc<BoardURLCellEvent, BoardURLCellState> {
}
@freezed
class BoardURLCellEvent with _$BoardURLCellEvent {
const factory BoardURLCellEvent.initial() = _InitialCell;
const factory BoardURLCellEvent.updateURL(String url) = _UpdateURL;
const factory BoardURLCellEvent.didReceiveCellUpdate(URLCellDataPB? cell) =
class URLCardCellEvent with _$URLCardCellEvent {
const factory URLCardCellEvent.initial() = _InitialCell;
const factory URLCardCellEvent.updateURL(String url) = _UpdateURL;
const factory URLCardCellEvent.didReceiveCellUpdate(URLCellDataPB? cell) =
_DidReceiveCellUpdate;
}
@freezed
class BoardURLCellState with _$BoardURLCellState {
const factory BoardURLCellState({
class URLCardCellState with _$URLCardCellState {
const factory URLCardCellState({
required String content,
required String url,
}) = _BoardURLCellState;
}) = _URLCardCellState;
factory BoardURLCellState.initial(URLCellController context) {
factory URLCardCellState.initial(URLCellController context) {
final cellData = context.getCellData();
return BoardURLCellState(
return URLCardCellState(
content: cellData?.content ?? "",
url: cellData?.url ?? "",
);

View File

@ -2,7 +2,7 @@ import 'package:appflowy/plugins/database_view/application/cell/cell_controller_
import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../application/card/board_number_cell_bloc.dart';
import 'bloc/number_card_cell_bloc.dart';
import 'define.dart';
class BoardNumberCell extends StatefulWidget {
@ -16,19 +16,19 @@ class BoardNumberCell extends StatefulWidget {
}) : super(key: key);
@override
State<BoardNumberCell> createState() => _BoardNumberCellState();
State<BoardNumberCell> createState() => _NumberCardCellState();
}
class _BoardNumberCellState extends State<BoardNumberCell> {
late BoardNumberCellBloc _cellBloc;
class _NumberCardCellState extends State<BoardNumberCell> {
late NumberCardCellBloc _cellBloc;
@override
void initState() {
final cellController =
widget.cellControllerBuilder.build() as NumberCellController;
_cellBloc = BoardNumberCellBloc(cellController: cellController)
..add(const BoardNumberCellEvent.initial());
_cellBloc = NumberCardCellBloc(cellController: cellController)
..add(const NumberCardCellEvent.initial());
super.initState();
}
@ -36,7 +36,7 @@ class _BoardNumberCellState extends State<BoardNumberCell> {
Widget build(BuildContext context) {
return BlocProvider.value(
value: _cellBloc,
child: BlocBuilder<BoardNumberCellBloc, BoardNumberCellState>(
child: BlocBuilder<NumberCardCellBloc, NumberCardCellState>(
buildWhen: (previous, current) => previous.content != current.content,
builder: (context, state) {
if (state.content.isEmpty) {
@ -46,7 +46,7 @@ class _BoardNumberCellState extends State<BoardNumberCell> {
alignment: Alignment.centerLeft,
child: Padding(
padding: EdgeInsets.symmetric(
vertical: BoardSizes.cardCellVPadding,
vertical: CardSizes.cardCellVPadding,
),
child: FlowyText.medium(
state.content,

View File

@ -1,47 +1,52 @@
import 'package:appflowy/plugins/database_view/board/application/card/card_bloc.dart';
import 'package:appflowy/plugins/database_view/board/application/card/card_data_controller.dart';
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/row/row_action_sheet.dart';
import 'package:appflowy/plugins/database_view/application/row/row_cache.dart';
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/row/action.dart';
import 'package:appflowy_backend/protobuf/flowy-database/row_entities.pb.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:flowy_infra/image.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'board_cell.dart';
import 'card_bloc.dart';
import 'cells/card_cell.dart';
import 'card_cell_builder.dart';
import 'container/accessory.dart';
import 'container/card_container.dart';
class BoardCard extends StatefulWidget {
class Card<CustomCardData> extends StatefulWidget {
final RowPB row;
final String viewId;
final String groupId;
final String fieldId;
final CustomCardData? cardData;
final bool isEditing;
final CardDataController dataController;
final BoardCellBuilder cellBuilder;
final RowCache rowCache;
final CardCellBuilder<CustomCardData> cellBuilder;
final void Function(BuildContext) openCard;
final VoidCallback onStartEditing;
final VoidCallback onEndEditing;
final CardConfiguration<CustomCardData>? configuration;
const BoardCard({
const Card({
required this.row,
required this.viewId,
required this.groupId,
required this.fieldId,
required this.isEditing,
required this.dataController,
required this.rowCache,
required this.cellBuilder,
required this.openCard,
required this.onStartEditing,
required this.onEndEditing,
this.cardData,
this.configuration,
Key? key,
}) : super(key: key);
@override
State<BoardCard> createState() => _BoardCardState();
State<Card<CustomCardData>> createState() => _CardState<CustomCardData>();
}
class _BoardCardState extends State<BoardCard> {
late BoardCardBloc _cardBloc;
class _CardState<T> extends State<Card<T>> {
late CardBloc _cardBloc;
late EditableRowNotifier rowNotifier;
late PopoverController popoverController;
AccessoryType? accessoryType;
@ -49,11 +54,12 @@ class _BoardCardState extends State<BoardCard> {
@override
void initState() {
rowNotifier = EditableRowNotifier(isEditing: widget.isEditing);
_cardBloc = BoardCardBloc(
_cardBloc = CardBloc(
viewId: widget.viewId,
groupFieldId: widget.fieldId,
dataController: widget.dataController,
isEditing: widget.isEditing,
row: widget.row,
rowCache: widget.rowCache,
)..add(const BoardCardEvent.initial());
rowNotifier.isEditing.addListener(() {
@ -75,7 +81,7 @@ class _BoardCardState extends State<BoardCard> {
Widget build(BuildContext context) {
return BlocProvider.value(
value: _cardBloc,
child: BlocBuilder<BoardCardBloc, BoardCardState>(
child: BlocBuilder<CardBloc, BoardCardState>(
buildWhen: (previous, current) {
// Rebuild when:
// 1.If the length of the cells is not the same
@ -110,11 +116,12 @@ class _BoardCardState extends State<BoardCard> {
},
openAccessory: _handleOpenAccessory,
openCard: (context) => widget.openCard(context),
child: _CellColumn(
groupId: widget.groupId,
child: _CardContent<T>(
rowNotifier: rowNotifier,
cellBuilder: widget.cellBuilder,
cells: state.cells,
cardConfiguration: widget.configuration,
cardData: widget.cardData,
),
),
);
@ -142,8 +149,8 @@ class _BoardCardState extends State<BoardCard> {
case AccessoryType.edit:
throw UnimplementedError();
case AccessoryType.more:
return GridRowActionSheet(
rowData: context.read<BoardCardBloc>().rowInfo(),
return RowActions(
rowData: context.read<CardBloc>().rowInfo(),
);
}
}
@ -156,16 +163,18 @@ class _BoardCardState extends State<BoardCard> {
}
}
class _CellColumn extends StatelessWidget {
final String groupId;
final BoardCellBuilder cellBuilder;
class _CardContent<CustomCardData> extends StatelessWidget {
final CardCellBuilder<CustomCardData> cellBuilder;
final EditableRowNotifier rowNotifier;
final List<BoardCellEquatable> cells;
const _CellColumn({
required this.groupId,
final CardConfiguration<CustomCardData>? cardConfiguration;
final CustomCardData? cardData;
const _CardContent({
required this.rowNotifier,
required this.cellBuilder,
required this.cells,
required this.cardData,
this.cardConfiguration,
Key? key,
}) : super(key: key);
@ -188,7 +197,7 @@ class _CellColumn extends StatelessWidget {
cells.asMap().forEach(
(int index, BoardCellEquatable cell) {
final isEditing = index == 0 ? rowNotifier.isEditing.value : false;
final cellNotifier = EditableCellNotifier(isEditing: isEditing);
final cellNotifier = EditableCardNotifier(isEditing: isEditing);
if (index == 0) {
// Only use the first cell to receive user's input when click the edit
@ -200,9 +209,10 @@ class _CellColumn extends StatelessWidget {
key: cell.identifier.key(),
padding: const EdgeInsets.only(left: 4, right: 4),
child: cellBuilder.buildCell(
groupId,
cell.identifier,
cellNotifier,
cellId: cell.identifier,
cellNotifier: cellNotifier,
cardConfiguration: cardConfiguration,
cardData: cardData,
),
);

View File

@ -1,34 +1,36 @@
import 'dart:collection';
import 'package:equatable/equatable.dart';
import 'package:appflowy_backend/protobuf/flowy-database/row_entities.pb.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'dart:async';
import '../../../application/cell/cell_service.dart';
import '../../../application/row/row_cache.dart';
import '../../../application/row/row_service.dart';
import 'card_data_controller.dart';
import '../../application/cell/cell_service.dart';
import '../../application/row/row_cache.dart';
import '../../application/row/row_service.dart';
part 'card_bloc.freezed.dart';
class BoardCardBloc extends Bloc<BoardCardEvent, BoardCardState> {
class CardBloc extends Bloc<BoardCardEvent, BoardCardState> {
final RowPB row;
final String groupFieldId;
final RowBackendService _rowBackendSvc;
final CardDataController _dataController;
final RowCache _rowCache;
VoidCallback? _rowCallback;
BoardCardBloc({
CardBloc({
required this.row,
required this.groupFieldId,
required String viewId,
required CardDataController dataController,
required RowCache rowCache,
required bool isEditing,
}) : _rowBackendSvc = RowBackendService(
viewId: viewId,
),
_dataController = dataController,
}) : _rowBackendSvc = RowBackendService(viewId: viewId),
_rowCache = rowCache,
super(
BoardCardState.initial(
dataController.rowPB,
_makeCells(groupFieldId, dataController.loadData()),
row,
_makeCells(groupFieldId, rowCache.loadGridCells(row.id)),
isEditing,
),
) {
@ -54,7 +56,10 @@ class BoardCardBloc extends Bloc<BoardCardEvent, BoardCardState> {
@override
Future<void> close() async {
_dataController.dispose();
if (_rowCallback != null) {
_rowCache.removeRowListener(_rowCallback!);
_rowCallback = null;
}
return super.close();
}
@ -69,8 +74,9 @@ class BoardCardBloc extends Bloc<BoardCardEvent, BoardCardState> {
}
Future<void> _startListening() async {
_dataController.addListener(
onRowChanged: (cellMap, reason) {
_rowCallback = _rowCache.addListener(
rowId: row.id,
onCellUpdated: (cellMap, reason) {
if (!isClosed) {
final cells = _makeCells(groupFieldId, cellMap);
add(BoardCardEvent.didReceiveCells(cells, reason));

View File

@ -2,83 +2,78 @@ import 'package:appflowy/plugins/database_view/application/cell/cell_controller_
import 'package:appflowy_backend/protobuf/flowy-database/field_entities.pb.dart';
import 'package:flutter/material.dart';
import '../../../application/cell/cell_service.dart';
import 'board_cell.dart';
import 'board_checkbox_cell.dart';
import 'board_checklist_cell.dart';
import 'board_date_cell.dart';
import 'board_number_cell.dart';
import 'board_select_option_cell.dart';
import 'board_text_cell.dart';
import 'board_url_cell.dart';
import '../../application/cell/cell_service.dart';
import 'cells/card_cell.dart';
import 'cells/checkbox_card_cell.dart';
import 'cells/checklist_card_cell.dart';
import 'cells/date_card_cell.dart';
import 'cells/number_card_cell.dart';
import 'cells/select_option_card_cell.dart';
import 'cells/text_card_cell.dart';
import 'cells/url_card_cell.dart';
abstract class BoardCellBuilderDelegate {
CellCache get cellCache;
}
// T represents as the Generic card data
class CardCellBuilder<CustomCardData> {
final CellCache cellCache;
class BoardCellBuilder {
final BoardCellBuilderDelegate delegate;
CardCellBuilder(this.cellCache);
BoardCellBuilder(this.delegate);
Widget buildCell(
String groupId,
CellIdentifier cellId,
EditableCellNotifier cellNotifier,
) {
Widget buildCell({
CustomCardData? cardData,
required CellIdentifier cellId,
EditableCardNotifier? cellNotifier,
CardConfiguration<CustomCardData>? cardConfiguration,
}) {
final cellControllerBuilder = CellControllerBuilder(
cellId: cellId,
cellCache: delegate.cellCache,
cellCache: cellCache,
);
final key = cellId.key();
switch (cellId.fieldType) {
case FieldType.Checkbox:
return BoardCheckboxCell(
groupId: groupId,
return CheckboxCardCell(
cellControllerBuilder: cellControllerBuilder,
key: key,
);
case FieldType.DateTime:
return BoardDateCell(
groupId: groupId,
return DateCardCell(
cellControllerBuilder: cellControllerBuilder,
key: key,
);
case FieldType.SingleSelect:
return BoardSelectOptionCell(
groupId: groupId,
return SelectOptionCardCell<CustomCardData>(
renderHook: cardConfiguration?.renderHook[FieldType.SingleSelect],
cellControllerBuilder: cellControllerBuilder,
cardData: cardData,
key: key,
);
case FieldType.MultiSelect:
return BoardSelectOptionCell(
groupId: groupId,
return SelectOptionCardCell<CustomCardData>(
renderHook: cardConfiguration?.renderHook[FieldType.MultiSelect],
cellControllerBuilder: cellControllerBuilder,
cardData: cardData,
editableNotifier: cellNotifier,
key: key,
);
case FieldType.Checklist:
return BoardChecklistCell(
return ChecklistCardCell(
cellControllerBuilder: cellControllerBuilder,
key: key,
);
case FieldType.Number:
return BoardNumberCell(
groupId: groupId,
return NumberCardCell(
cellControllerBuilder: cellControllerBuilder,
key: key,
);
case FieldType.RichText:
return BoardTextCell(
groupId: groupId,
return TextCardCell(
cellControllerBuilder: cellControllerBuilder,
editableNotifier: cellNotifier,
key: key,
);
case FieldType.URL:
return BoardUrlCell(
groupId: groupId,
return URLCardCell(
cellControllerBuilder: cellControllerBuilder,
key: key,
);

View File

@ -1,14 +1,39 @@
import 'package:appflowy/plugins/database_view/application/cell/cell_service.dart';
import 'package:appflowy_backend/protobuf/flowy-database/field_entities.pbenum.dart';
import 'package:appflowy_backend/protobuf/flowy-database/select_type_option.pb.dart';
import 'package:flutter/material.dart';
abstract class FocusableBoardCell {
set becomeFocus(bool isFocus);
typedef CellRenderHook<C, T> = Widget? Function(C cellData, T cardData);
typedef RenderHookByFieldType<C> = Map<FieldType, CellRenderHook<dynamic, C>>;
class CardConfiguration<CustomCardData> {
final RenderHookByFieldType<CustomCardData> renderHook = {};
CardConfiguration();
void addSelectOptionHook(
CellRenderHook<List<SelectOptionPB>, CustomCardData> hook,
) {
selectOptionHook(cellData, cardData) {
if (cellData is List<SelectOptionPB>) {
hook(cellData, cardData);
}
}
class EditableCellNotifier {
renderHook[FieldType.SingleSelect] = selectOptionHook;
renderHook[FieldType.MultiSelect] = selectOptionHook;
}
}
abstract class CardCell<T> extends StatefulWidget {
final T? cardData;
const CardCell({super.key, this.cardData});
}
class EditableCardNotifier {
final ValueNotifier<bool> isCellEditing;
EditableCellNotifier({bool isEditing = false})
EditableCardNotifier({bool isEditing = false})
: isCellEditing = ValueNotifier(isEditing);
void dispose() {
@ -17,7 +42,7 @@ class EditableCellNotifier {
}
class EditableRowNotifier {
final Map<EditableCellId, EditableCellNotifier> _cells = {};
final Map<EditableCellId, EditableCardNotifier> _cells = {};
final ValueNotifier<bool> isEditing;
EditableRowNotifier({required bool isEditing})
@ -25,7 +50,7 @@ class EditableRowNotifier {
void bindCell(
CellIdentifier cellIdentifier,
EditableCellNotifier notifier,
EditableCardNotifier notifier,
) {
assert(
_cells.values.isEmpty,
@ -80,7 +105,7 @@ abstract class EditableCell {
// the row notifier receive its cells event. For example: begin editing the
// cell or end editing the cell.
//
EditableCellNotifier? get editableNotifier;
EditableCardNotifier? get editableNotifier;
}
class EditableCellId {

View File

@ -1,33 +1,33 @@
import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
import 'package:appflowy/plugins/database_view/board/application/card/board_checkbox_cell_bloc.dart';
import 'package:flowy_infra/image.dart';
import 'package:flowy_infra_ui/style_widget/icon_button.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class BoardCheckboxCell extends StatefulWidget {
final String groupId;
import '../bloc/checkbox_card_cell_bloc.dart';
import 'card_cell.dart';
class CheckboxCardCell extends CardCell {
final CellControllerBuilder cellControllerBuilder;
const BoardCheckboxCell({
required this.groupId,
const CheckboxCardCell({
required this.cellControllerBuilder,
Key? key,
}) : super(key: key);
@override
State<BoardCheckboxCell> createState() => _BoardCheckboxCellState();
State<CheckboxCardCell> createState() => _CheckboxCardCellState();
}
class _BoardCheckboxCellState extends State<BoardCheckboxCell> {
late BoardCheckboxCellBloc _cellBloc;
class _CheckboxCardCellState extends State<CheckboxCardCell> {
late CheckboxCardCellBloc _cellBloc;
@override
void initState() {
final cellController =
widget.cellControllerBuilder.build() as CheckboxCellController;
_cellBloc = BoardCheckboxCellBloc(cellController: cellController);
_cellBloc.add(const BoardCheckboxCellEvent.initial());
_cellBloc = CheckboxCardCellBloc(cellController: cellController);
_cellBloc.add(const CheckboxCardCellEvent.initial());
super.initState();
}
@ -35,7 +35,7 @@ class _BoardCheckboxCellState extends State<BoardCheckboxCell> {
Widget build(BuildContext context) {
return BlocProvider.value(
value: _cellBloc,
child: BlocBuilder<BoardCheckboxCellBloc, BoardCheckboxCellState>(
child: BlocBuilder<CheckboxCardCellBloc, CheckboxCardCellState>(
buildWhen: (previous, current) =>
previous.isSelected != current.isSelected,
builder: (context, state) {
@ -49,8 +49,8 @@ class _BoardCheckboxCellState extends State<BoardCheckboxCell> {
icon: icon,
width: 20,
onPressed: () => context
.read<BoardCheckboxCellBloc>()
.add(const BoardCheckboxCellEvent.select()),
.read<CheckboxCardCellBloc>()
.add(const CheckboxCardCellEvent.select()),
),
);
},

View File

@ -1,27 +1,28 @@
import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
import 'package:appflowy/plugins/database_view/widgets/row/cells/checklist_cell/checklist_progress_bar.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../../grid/application/cell/checklist_cell_bloc.dart';
import '../../../grid/presentation/widgets/cell/checklist_cell/checklist_progress_bar.dart';
import '../../row/cells/checklist_cell/checklist_cell_bloc.dart';
import 'card_cell.dart';
class BoardChecklistCell extends StatefulWidget {
class ChecklistCardCell extends CardCell {
final CellControllerBuilder cellControllerBuilder;
const BoardChecklistCell({required this.cellControllerBuilder, Key? key})
const ChecklistCardCell({required this.cellControllerBuilder, Key? key})
: super(key: key);
@override
State<BoardChecklistCell> createState() => _BoardChecklistCellState();
State<ChecklistCardCell> createState() => _ChecklistCardCellState();
}
class _BoardChecklistCellState extends State<BoardChecklistCell> {
late ChecklistCellBloc _cellBloc;
class _ChecklistCardCellState extends State<ChecklistCardCell> {
late ChecklistCardCellBloc _cellBloc;
@override
void initState() {
final cellController =
widget.cellControllerBuilder.build() as ChecklistCellController;
_cellBloc = ChecklistCellBloc(cellController: cellController);
_cellBloc = ChecklistCardCellBloc(cellController: cellController);
_cellBloc.add(const ChecklistCellEvent.initial());
super.initState();
}
@ -30,7 +31,7 @@ class _BoardChecklistCellState extends State<BoardChecklistCell> {
Widget build(BuildContext context) {
return BlocProvider.value(
value: _cellBloc,
child: BlocBuilder<ChecklistCellBloc, ChecklistCellState>(
child: BlocBuilder<ChecklistCardCellBloc, ChecklistCellState>(
builder: (context, state) =>
ChecklistProgressBar(percent: state.percent),
),

View File

@ -1,35 +1,34 @@
import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
import 'package:appflowy/plugins/database_view/board/application/card/board_date_cell_bloc.dart';
import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'define.dart';
import '../bloc/date_card_cell_bloc.dart';
import '../define.dart';
import 'card_cell.dart';
class BoardDateCell extends StatefulWidget {
final String groupId;
class DateCardCell extends CardCell {
final CellControllerBuilder cellControllerBuilder;
const BoardDateCell({
required this.groupId,
const DateCardCell({
required this.cellControllerBuilder,
Key? key,
}) : super(key: key);
@override
State<BoardDateCell> createState() => _BoardDateCellState();
State<DateCardCell> createState() => _DateCardCellState();
}
class _BoardDateCellState extends State<BoardDateCell> {
late BoardDateCellBloc _cellBloc;
class _DateCardCellState extends State<DateCardCell> {
late DateCardCellBloc _cellBloc;
@override
void initState() {
final cellController =
widget.cellControllerBuilder.build() as DateCellController;
_cellBloc = BoardDateCellBloc(cellController: cellController)
..add(const BoardDateCellEvent.initial());
_cellBloc = DateCardCellBloc(cellController: cellController)
..add(const DateCardCellEvent.initial());
super.initState();
}
@ -37,7 +36,7 @@ class _BoardDateCellState extends State<BoardDateCell> {
Widget build(BuildContext context) {
return BlocProvider.value(
value: _cellBloc,
child: BlocBuilder<BoardDateCellBloc, BoardDateCellState>(
child: BlocBuilder<DateCardCellBloc, DateCardCellState>(
buildWhen: (previous, current) => previous.dateStr != current.dateStr,
builder: (context, state) {
if (state.dateStr.isEmpty) {
@ -47,7 +46,7 @@ class _BoardDateCellState extends State<BoardDateCell> {
alignment: Alignment.centerLeft,
child: Padding(
padding: EdgeInsets.symmetric(
vertical: BoardSizes.cardCellVPadding,
vertical: CardSizes.cardCellVPadding,
),
child: FlowyText.regular(
state.dateStr,

View File

@ -0,0 +1,68 @@
import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../bloc/number_card_cell_bloc.dart';
import '../define.dart';
import 'card_cell.dart';
class NumberCardCell extends CardCell {
final CellControllerBuilder cellControllerBuilder;
const NumberCardCell({
required this.cellControllerBuilder,
Key? key,
}) : super(key: key);
@override
State<NumberCardCell> createState() => _NumberCardCellState();
}
class _NumberCardCellState extends State<NumberCardCell> {
late NumberCardCellBloc _cellBloc;
@override
void initState() {
final cellController =
widget.cellControllerBuilder.build() as NumberCellController;
_cellBloc = NumberCardCellBloc(cellController: cellController)
..add(const NumberCardCellEvent.initial());
super.initState();
}
@override
Widget build(BuildContext context) {
return BlocProvider.value(
value: _cellBloc,
child: BlocBuilder<NumberCardCellBloc, NumberCardCellState>(
buildWhen: (previous, current) => previous.content != current.content,
builder: (context, state) {
if (state.content.isEmpty) {
return const SizedBox();
} else {
return Align(
alignment: Alignment.centerLeft,
child: Padding(
padding: EdgeInsets.symmetric(
vertical: CardSizes.cardCellVPadding,
),
child: FlowyText.medium(
state.content,
fontSize: 14,
),
),
);
}
},
),
);
}
@override
Future<void> dispose() async {
_cellBloc.close();
super.dispose();
}
}

View File

@ -1,32 +1,35 @@
import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
import 'package:appflowy/plugins/database_view/widgets/row/cells/select_option_cell/extension.dart';
import 'package:appflowy/plugins/database_view/widgets/row/cells/select_option_cell/select_option_editor.dart';
import 'package:appflowy_backend/protobuf/flowy-database/select_type_option.pb.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../../grid/presentation/widgets/cell/select_option_cell/extension.dart';
import '../../../grid/presentation/widgets/cell/select_option_cell/select_option_editor.dart';
import '../../application/card/board_select_option_cell_bloc.dart';
import 'board_cell.dart';
import '../bloc/select_option_card_cell_bloc.dart';
import 'card_cell.dart';
class BoardSelectOptionCell extends StatefulWidget with EditableCell {
final String groupId;
class SelectOptionCardCell<T> extends CardCell<T> with EditableCell {
final CellControllerBuilder cellControllerBuilder;
@override
final EditableCellNotifier? editableNotifier;
final CellRenderHook<List<SelectOptionPB>, T>? renderHook;
const BoardSelectOptionCell({
required this.groupId,
@override
final EditableCardNotifier? editableNotifier;
SelectOptionCardCell({
required this.cellControllerBuilder,
required T? cardData,
this.renderHook,
this.editableNotifier,
Key? key,
}) : super(key: key);
}) : super(key: key, cardData: cardData);
@override
State<BoardSelectOptionCell> createState() => _BoardSelectOptionCellState();
State<SelectOptionCardCell> createState() => _SelectOptionCardCellState();
}
class _BoardSelectOptionCellState extends State<BoardSelectOptionCell> {
late BoardSelectOptionCellBloc _cellBloc;
class _SelectOptionCardCellState extends State<SelectOptionCardCell> {
late SelectOptionCardCellBloc _cellBloc;
late PopoverController _popover;
@override
@ -34,8 +37,8 @@ class _BoardSelectOptionCellState extends State<BoardSelectOptionCell> {
_popover = PopoverController();
final cellController =
widget.cellControllerBuilder.build() as SelectOptionCellController;
_cellBloc = BoardSelectOptionCellBloc(cellController: cellController)
..add(const BoardSelectOptionCellEvent.initial());
_cellBloc = SelectOptionCardCellBloc(cellController: cellController)
..add(const SelectOptionCardCellEvent.initial());
super.initState();
}
@ -43,12 +46,17 @@ class _BoardSelectOptionCellState extends State<BoardSelectOptionCell> {
Widget build(BuildContext context) {
return BlocProvider.value(
value: _cellBloc,
child: BlocBuilder<BoardSelectOptionCellBloc, BoardSelectOptionCellState>(
child: BlocBuilder<SelectOptionCardCellBloc, SelectOptionCardCellState>(
buildWhen: (previous, current) {
return previous.selectedOptions != current.selectedOptions;
}, builder: (context, state) {
// Returns SizedBox if the content of the cell is empty
if (_isEmpty(state)) return const SizedBox();
Widget? custom = widget.renderHook?.call(
state.selectedOptions,
widget.cardData,
);
if (custom != null) {
return custom;
}
final children = state.selectedOptions.map(
(option) {
@ -73,14 +81,6 @@ class _BoardSelectOptionCellState extends State<BoardSelectOptionCell> {
);
}
bool _isEmpty(BoardSelectOptionCellState state) {
// The cell should hide if the option id is equal to the groupId.
final isInGroup = state.selectedOptions
.where((element) => element.id == widget.groupId)
.isNotEmpty;
return isInGroup || state.selectedOptions.isEmpty;
}
Widget _wrapPopover(Widget child) {
final constraints = BoxConstraints.loose(Size(
SelectOptionCellEditor.editorPanelWidth,

View File

@ -1,33 +1,31 @@
import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/cell/cell_builder.dart';
import 'package:flowy_infra/size.dart';
import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:textstyle_extensions/textstyle_extensions.dart';
import '../../application/card/board_text_cell_bloc.dart';
import 'board_cell.dart';
import 'define.dart';
import '../../row/cell_builder.dart';
import '../bloc/text_card_cell_bloc.dart';
import '../define.dart';
import 'card_cell.dart';
class BoardTextCell extends StatefulWidget with EditableCell {
final String groupId;
class TextCardCell extends CardCell with EditableCell {
@override
final EditableCellNotifier? editableNotifier;
final EditableCardNotifier? editableNotifier;
final CellControllerBuilder cellControllerBuilder;
const BoardTextCell({
required this.groupId,
const TextCardCell({
required this.cellControllerBuilder,
this.editableNotifier,
Key? key,
}) : super(key: key);
@override
State<BoardTextCell> createState() => _BoardTextCellState();
State<TextCardCell> createState() => _TextCardCellState();
}
class _BoardTextCellState extends State<BoardTextCell> {
late BoardTextCellBloc _cellBloc;
class _TextCardCellState extends State<TextCardCell> {
late TextCardCellBloc _cellBloc;
late TextEditingController _controller;
bool focusWhenInit = false;
final focusNode = SingleListenerFocusNode();
@ -36,8 +34,8 @@ class _BoardTextCellState extends State<BoardTextCell> {
void initState() {
final cellController =
widget.cellControllerBuilder.build() as TextCellController;
_cellBloc = BoardTextCellBloc(cellController: cellController)
..add(const BoardTextCellEvent.initial());
_cellBloc = TextCardCellBloc(cellController: cellController)
..add(const TextCardCellEvent.initial());
_controller = TextEditingController(text: _cellBloc.state.content);
focusWhenInit = widget.editableNotifier?.isCellEditing.value ?? false;
if (focusWhenInit) {
@ -51,7 +49,7 @@ class _BoardTextCellState extends State<BoardTextCell> {
if (!focusNode.hasFocus) {
focusWhenInit = false;
widget.editableNotifier?.isCellEditing.value = false;
_cellBloc.add(const BoardTextCellEvent.enableEdit(false));
_cellBloc.add(const TextCardCellEvent.enableEdit(false));
}
});
_bindEditableNotifier();
@ -68,12 +66,12 @@ class _BoardTextCellState extends State<BoardTextCell> {
focusNode.requestFocus();
});
}
_cellBloc.add(BoardTextCellEvent.enableEdit(isEditing));
_cellBloc.add(TextCardCellEvent.enableEdit(isEditing));
});
}
@override
void didUpdateWidget(covariant BoardTextCell oldWidget) {
void didUpdateWidget(covariant TextCardCell oldWidget) {
_bindEditableNotifier();
super.didUpdateWidget(oldWidget);
}
@ -82,13 +80,13 @@ class _BoardTextCellState extends State<BoardTextCell> {
Widget build(BuildContext context) {
return BlocProvider.value(
value: _cellBloc,
child: BlocListener<BoardTextCellBloc, BoardTextCellState>(
child: BlocListener<TextCardCellBloc, TextCardCellState>(
listener: (context, state) {
if (_controller.text != state.content) {
_controller.text = state.content;
}
},
child: BlocBuilder<BoardTextCellBloc, BoardTextCellState>(
child: BlocBuilder<TextCardCellBloc, TextCardCellState>(
buildWhen: (previous, current) {
if (previous.content != current.content &&
_controller.text == current.content &&
@ -120,7 +118,7 @@ class _BoardTextCellState extends State<BoardTextCell> {
}
Future<void> focusChanged() async {
_cellBloc.add(BoardTextCellEvent.updateText(_controller.text));
_cellBloc.add(TextCardCellEvent.updateText(_controller.text));
}
@override
@ -131,10 +129,10 @@ class _BoardTextCellState extends State<BoardTextCell> {
super.dispose();
}
Widget _buildText(BoardTextCellState state) {
Widget _buildText(TextCardCellState state) {
return Padding(
padding: EdgeInsets.symmetric(
vertical: BoardSizes.cardCellVPadding,
vertical: CardSizes.cardCellVPadding,
),
child: FlowyText.medium(
state.content,
@ -156,7 +154,7 @@ class _BoardTextCellState extends State<BoardTextCell> {
decoration: InputDecoration(
// Magic number 4 makes the textField take up the same space as FlowyText
contentPadding: EdgeInsets.symmetric(
vertical: BoardSizes.cardCellVPadding + 4,
vertical: CardSizes.cardCellVPadding + 4,
),
border: InputBorder.none,
isDense: true,

View File

@ -4,32 +4,31 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:textstyle_extensions/textstyle_extensions.dart';
import '../../application/card/board_url_cell_bloc.dart';
import 'define.dart';
import '../bloc/url_card_cell_bloc.dart';
import '../define.dart';
import 'card_cell.dart';
class BoardUrlCell extends StatefulWidget {
final String groupId;
class URLCardCell extends CardCell {
final CellControllerBuilder cellControllerBuilder;
const BoardUrlCell({
required this.groupId,
const URLCardCell({
required this.cellControllerBuilder,
Key? key,
}) : super(key: key);
@override
State<BoardUrlCell> createState() => _BoardUrlCellState();
State<URLCardCell> createState() => _URLCardCellState();
}
class _BoardUrlCellState extends State<BoardUrlCell> {
late BoardURLCellBloc _cellBloc;
class _URLCardCellState extends State<URLCardCell> {
late URLCardCellBloc _cellBloc;
@override
void initState() {
final cellController =
widget.cellControllerBuilder.build() as URLCellController;
_cellBloc = BoardURLCellBloc(cellController: cellController);
_cellBloc.add(const BoardURLCellEvent.initial());
_cellBloc = URLCardCellBloc(cellController: cellController);
_cellBloc.add(const URLCardCellEvent.initial());
super.initState();
}
@ -37,7 +36,7 @@ class _BoardUrlCellState extends State<BoardUrlCell> {
Widget build(BuildContext context) {
return BlocProvider.value(
value: _cellBloc,
child: BlocBuilder<BoardURLCellBloc, BoardURLCellState>(
child: BlocBuilder<URLCardCellBloc, URLCardCellState>(
buildWhen: (previous, current) => previous.content != current.content,
builder: (context, state) {
if (state.content.isEmpty) {
@ -47,7 +46,7 @@ class _BoardUrlCellState extends State<BoardUrlCell> {
alignment: Alignment.centerLeft,
child: Padding(
padding: EdgeInsets.symmetric(
vertical: BoardSizes.cardCellVPadding,
vertical: CardSizes.cardCellVPadding,
),
child: RichText(
textAlign: TextAlign.left,

View File

@ -9,7 +9,7 @@ import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:textstyle_extensions/textstyle_extensions.dart';
import 'cell_builder.dart';
import '../cell_builder.dart';
class GridCellAccessoryBuildContext {
final BuildContext anchorContext;

View File

@ -3,16 +3,16 @@ import 'package:appflowy_backend/protobuf/flowy-database/field_entities.pb.dart'
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter/material.dart';
import '../../../../application/cell/cell_service.dart';
import 'cell_accessory.dart';
import 'cell_shortcuts.dart';
import 'checkbox_cell.dart';
import 'checklist_cell/checklist_cell.dart';
import 'date_cell/date_cell.dart';
import 'number_cell.dart';
import 'select_option_cell/select_option_cell.dart';
import 'text_cell.dart';
import 'url_cell/url_cell.dart';
import '../../application/cell/cell_service.dart';
import 'accessory/cell_accessory.dart';
import 'accessory/cell_shortcuts.dart';
import 'cells/checkbox_cell/checkbox_cell.dart';
import 'cells/checklist_cell/checklist_cell.dart';
import 'cells/date_cell/date_cell.dart';
import 'cells/number_cell/number_cell.dart';
import 'cells/select_option_cell/select_option_cell.dart';
import 'cells/text_cell/text_cell.dart';
import 'cells/url_cell/url_cell.dart';
class GridCellBuilder {
final CellCache cellCache;

View File

@ -2,11 +2,11 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:styled_widget/styled_widget.dart';
import '../../layout/sizes.dart';
import '../row/grid_row.dart';
import 'cell_accessory.dart';
import 'cell_builder.dart';
import 'cell_shortcuts.dart';
import '../../../grid/presentation/layout/sizes.dart';
import '../../../grid/presentation/widgets/row/row.dart';
import '../accessory/cell_accessory.dart';
import '../accessory/cell_shortcuts.dart';
import '../cell_builder.dart';
class CellContainer extends StatelessWidget {
final GridCellWidget child;

View File

@ -1,12 +1,12 @@
import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/plugins/database_view/application/cell/cell_service.dart';
import 'package:flowy_infra/image.dart';
import 'package:flowy_infra_ui/style_widget/icon_button.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../../application/cell/checkbox_cell_bloc.dart';
import '../../layout/sizes.dart';
import 'cell_builder.dart';
import 'checkbox_cell_bloc.dart';
import '../../../../grid/presentation/layout/sizes.dart';
import '../../cell_builder.dart';
class GridCheckboxCell extends GridCellWidget {
final CellControllerBuilder cellControllerBuilder;
@ -26,7 +26,8 @@ class _CheckboxCellState extends GridCellState<GridCheckboxCell> {
void initState() {
final cellController =
widget.cellControllerBuilder.build() as CheckboxCellController;
_cellBloc = getIt<CheckboxCellBloc>(param1: cellController)
_cellBloc = CheckboxCellBloc(
service: CellBackendService(), cellController: cellController)
..add(const CheckboxCellEvent.initial());
super.initState();
}

View File

@ -1,12 +1,12 @@
import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
import 'package:appflowy/plugins/database_view/grid/application/cell/checklist_cell_bloc.dart';
import 'package:appflowy/plugins/database_view/grid/presentation/layout/sizes.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../cell_builder.dart';
import '../../cell_builder.dart';
import 'checklist_cell_bloc.dart';
import 'checklist_cell_editor.dart';
import 'checklist_progress_bar.dart';
@ -20,7 +20,7 @@ class GridChecklistCell extends GridCellWidget {
}
class GridChecklistCellState extends GridCellState<GridChecklistCell> {
late ChecklistCellBloc _cellBloc;
late ChecklistCardCellBloc _cellBloc;
late final PopoverController _popover;
@override
@ -28,7 +28,7 @@ class GridChecklistCellState extends GridCellState<GridChecklistCell> {
_popover = PopoverController();
final cellController =
widget.cellControllerBuilder.build() as ChecklistCellController;
_cellBloc = ChecklistCellBloc(cellController: cellController);
_cellBloc = ChecklistCardCellBloc(cellController: cellController);
_cellBloc.add(const ChecklistCellEvent.initial());
super.initState();
}
@ -54,7 +54,7 @@ class GridChecklistCellState extends GridCellState<GridChecklistCell> {
onClose: () => widget.onCellEditing.value = false,
child: Padding(
padding: GridSize.cellContentInsets,
child: BlocBuilder<ChecklistCellBloc, ChecklistCellState>(
child: BlocBuilder<ChecklistCardCellBloc, ChecklistCellState>(
builder: (context, state) =>
ChecklistProgressBar(percent: state.percent),
),

View File

@ -1,18 +1,19 @@
import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
import 'package:appflowy/plugins/database_view/widgets/row/cells/select_option_cell/select_option_service.dart';
import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-database/select_type_option.pb.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'dart:async';
import 'checklist_cell_editor_bloc.dart';
import 'select_option_service.dart';
part 'checklist_cell_bloc.freezed.dart';
class ChecklistCellBloc extends Bloc<ChecklistCellEvent, ChecklistCellState> {
class ChecklistCardCellBloc
extends Bloc<ChecklistCellEvent, ChecklistCellState> {
final ChecklistCellController cellController;
final SelectOptionBackendService _selectOptionSvc;
void Function()? _onCellChangedFn;
ChecklistCellBloc({
ChecklistCardCellBloc({
required this.cellController,
}) : _selectOptionSvc =
SelectOptionBackendService(cellId: cellController.cellId),

View File

@ -2,16 +2,12 @@ import 'package:appflowy/plugins/database_view/application/cell/cell_controller_
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:flowy_infra/image.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/style_widget/button.dart';
import 'package:flowy_infra_ui/style_widget/icon_button.dart';
import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart';
import 'package:flowy_infra_ui/widget/spacing.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../../../application/cell/checklist_cell_editor_bloc.dart';
import '../../../layout/sizes.dart';
import '../../header/type_option/select_option_editor.dart';
import '../../../../grid/presentation/layout/sizes.dart';
import '../../../../grid/presentation/widgets/header/type_option/select_option_editor.dart';
import 'checklist_cell_editor_bloc.dart';
import 'checklist_progress_bar.dart';
class GridChecklistCellEditor extends StatefulWidget {

View File

@ -1,12 +1,12 @@
import 'dart:async';
import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
import 'package:appflowy/plugins/database_view/widgets/row/cells/select_option_cell/select_option_service.dart';
import 'package:dartz/dartz.dart';
import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-database/select_type_option.pb.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'select_option_service.dart';
part 'checklist_cell_editor_bloc.freezed.dart';

View File

@ -1,6 +1,6 @@
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/database_view/grid/application/cell/checklist_cell_editor_bloc.dart';
import 'package:appflowy/plugins/database_view/grid/presentation/layout/sizes.dart';
import 'package:appflowy/plugins/database_view/widgets/row/cells/checklist_cell/checklist_cell_editor_bloc.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';

View File

@ -15,19 +15,20 @@ import 'package:table_calendar/table_calendar.dart';
import 'dart:async';
import 'package:dartz/dartz.dart';
import 'package:protobuf/protobuf.dart';
import 'package:fixnum/fixnum.dart' as $fixnum;
part 'date_cal_bloc.freezed.dart';
class DateCalBloc extends Bloc<DateCalEvent, DateCalState> {
class DateCellCalendarBloc
extends Bloc<DateCellCalendarEvent, DateCellCalendarState> {
final DateCellController cellController;
void Function()? _onCellChangedFn;
DateCalBloc({
DateCellCalendarBloc({
required DateTypeOptionPB dateTypeOptionPB,
required DateCellDataPB? cellData,
required this.cellController,
}) : super(DateCalState.initial(dateTypeOptionPB, cellData)) {
on<DateCalEvent>(
}) : super(DateCellCalendarState.initial(dateTypeOptionPB, cellData)) {
on<DateCellCalendarEvent>(
(event, emit) async {
await event.when(
initial: () async => _startListening(),
@ -41,13 +42,13 @@ class DateCalBloc extends Bloc<DateCalEvent, DateCalState> {
emit(state.copyWith(focusedDay: focusedDay));
},
didReceiveCellUpdate: (DateCellDataPB? cellData) {
final calData = calDataFromCellData(cellData);
final time = calData.foldRight(
final dateCellData = calDataFromCellData(cellData);
final time = dateCellData.foldRight(
"", (dateData, previous) => dateData.time ?? '');
emit(state.copyWith(calData: calData, time: time));
emit(state.copyWith(dateCellData: dateCellData, time: time));
},
setIncludeTime: (includeTime) async {
await _updateTypeOption(emit, includeTime: includeTime);
await _updateDateData(emit, includeTime: includeTime);
},
setDateFormat: (dateFormat) async {
await _updateTypeOption(emit, dateFormat: dateFormat);
@ -56,24 +57,28 @@ class DateCalBloc extends Bloc<DateCalEvent, DateCalState> {
await _updateTypeOption(emit, timeFormat: timeFormat);
},
setTime: (time) async {
if (state.calData.isSome()) {
if (state.dateCellData.isSome()) {
await _updateDateData(emit, time: time);
}
},
didUpdateCalData:
(Option<CalendarData> data, Option<String> timeFormatError) {
(Option<DateCellData> data, Option<String> timeFormatError) {
emit(state.copyWith(
calData: data, timeFormatError: timeFormatError));
dateCellData: data, timeFormatError: timeFormatError));
},
);
},
);
}
Future<void> _updateDateData(Emitter<DateCalState> emit,
{DateTime? date, String? time}) {
final CalendarData newDateData = state.calData.fold(
() => CalendarData(date: date ?? DateTime.now(), time: time),
Future<void> _updateDateData(Emitter<DateCellCalendarState> emit,
{DateTime? date, String? time, bool? includeTime}) {
final DateCellData newDateData = state.dateCellData.fold(
() => DateCellData(
date: date ?? DateTime.now(),
time: time,
includeTime: includeTime ?? false,
),
(dateData) {
var newDateData = dateData;
if (date != null && !isSameDay(newDateData.date, date)) {
@ -83,6 +88,11 @@ class DateCalBloc extends Bloc<DateCalEvent, DateCalState> {
if (newDateData.time != time) {
newDateData = newDateData.copyWith(time: time);
}
if (includeTime != null && newDateData.includeTime != includeTime) {
newDateData = newDateData.copyWith(includeTime: includeTime);
}
return newDateData;
},
);
@ -91,15 +101,16 @@ class DateCalBloc extends Bloc<DateCalEvent, DateCalState> {
}
Future<void> _saveDateData(
Emitter<DateCalState> emit, CalendarData newCalData) async {
if (state.calData == Some(newCalData)) {
Emitter<DateCellCalendarState> emit, DateCellData newCalData) async {
if (state.dateCellData == Some(newCalData)) {
return;
}
updateCalData(
Option<CalendarData> calData, Option<String> timeFormatError) {
Option<DateCellData> dateCellData, Option<String> timeFormatError) {
if (!isClosed) {
add(DateCalEvent.didUpdateCalData(calData, timeFormatError));
add(DateCellCalendarEvent.didUpdateCalData(
dateCellData, timeFormatError));
}
}
@ -109,7 +120,7 @@ class DateCalBloc extends Bloc<DateCalEvent, DateCalState> {
(err) {
switch (ErrorCode.valueOf(err.code)!) {
case ErrorCode.InvalidDateTimeFormat:
updateCalData(state.calData, Some(timeFormatPrompt(err)));
updateCalData(state.dateCellData, Some(timeFormatPrompt(err)));
break;
default:
Log.error(err);
@ -148,17 +159,16 @@ class DateCalBloc extends Bloc<DateCalEvent, DateCalState> {
_onCellChangedFn = cellController.startListening(
onCellChanged: ((cell) {
if (!isClosed) {
add(DateCalEvent.didReceiveCellUpdate(cell));
add(DateCellCalendarEvent.didReceiveCellUpdate(cell));
}
}),
);
}
Future<void>? _updateTypeOption(
Emitter<DateCalState> emit, {
Emitter<DateCellCalendarState> emit, {
DateFormat? dateFormat,
TimeFormat? timeFormat,
bool? includeTime,
}) async {
state.dateTypeOptionPB.freeze();
final newDateTypeOption = state.dateTypeOptionPB.rebuild((typeOption) {
@ -169,10 +179,6 @@ class DateCalBloc extends Bloc<DateCalEvent, DateCalState> {
if (timeFormat != null) {
typeOption.timeFormat = timeFormat;
}
if (includeTime != null) {
typeOption.includeTime = includeTime;
}
});
final result = await FieldBackendService.updateFieldTypeOption(
@ -191,48 +197,51 @@ class DateCalBloc extends Bloc<DateCalEvent, DateCalState> {
}
@freezed
class DateCalEvent with _$DateCalEvent {
const factory DateCalEvent.initial() = _Initial;
const factory DateCalEvent.selectDay(DateTime day) = _SelectDay;
const factory DateCalEvent.setCalFormat(CalendarFormat format) =
class DateCellCalendarEvent with _$DateCellCalendarEvent {
const factory DateCellCalendarEvent.initial() = _Initial;
const factory DateCellCalendarEvent.selectDay(DateTime day) = _SelectDay;
const factory DateCellCalendarEvent.setCalFormat(CalendarFormat format) =
_CalendarFormat;
const factory DateCalEvent.setFocusedDay(DateTime day) = _FocusedDay;
const factory DateCalEvent.setTimeFormat(TimeFormat timeFormat) = _TimeFormat;
const factory DateCalEvent.setDateFormat(DateFormat dateFormat) = _DateFormat;
const factory DateCalEvent.setIncludeTime(bool includeTime) = _IncludeTime;
const factory DateCalEvent.setTime(String time) = _Time;
const factory DateCalEvent.didReceiveCellUpdate(DateCellDataPB? data) =
_DidReceiveCellUpdate;
const factory DateCalEvent.didUpdateCalData(
Option<CalendarData> data, Option<String> timeFormatError) =
const factory DateCellCalendarEvent.setFocusedDay(DateTime day) = _FocusedDay;
const factory DateCellCalendarEvent.setTimeFormat(TimeFormat timeFormat) =
_TimeFormat;
const factory DateCellCalendarEvent.setDateFormat(DateFormat dateFormat) =
_DateFormat;
const factory DateCellCalendarEvent.setIncludeTime(bool includeTime) =
_IncludeTime;
const factory DateCellCalendarEvent.setTime(String time) = _Time;
const factory DateCellCalendarEvent.didReceiveCellUpdate(
DateCellDataPB? data) = _DidReceiveCellUpdate;
const factory DateCellCalendarEvent.didUpdateCalData(
Option<DateCellData> data, Option<String> timeFormatError) =
_DidUpdateCalData;
}
@freezed
class DateCalState with _$DateCalState {
const factory DateCalState({
class DateCellCalendarState with _$DateCellCalendarState {
const factory DateCellCalendarState({
required DateTypeOptionPB dateTypeOptionPB,
required CalendarFormat format,
required DateTime focusedDay,
required Option<String> timeFormatError,
required Option<CalendarData> calData,
required Option<DateCellData> dateCellData,
required String? time,
required String timeHintText,
}) = _DateCalState;
}) = _DateCellCalendarState;
factory DateCalState.initial(
factory DateCellCalendarState.initial(
DateTypeOptionPB dateTypeOptionPB,
DateCellDataPB? cellData,
) {
Option<CalendarData> calData = calDataFromCellData(cellData);
Option<DateCellData> dateCellData = calDataFromCellData(cellData);
final time =
calData.foldRight("", (dateData, previous) => dateData.time ?? '');
return DateCalState(
dateCellData.foldRight("", (dateData, previous) => dateData.time ?? '');
return DateCellCalendarState(
dateTypeOptionPB: dateTypeOptionPB,
format: CalendarFormat.month,
focusedDay: DateTime.now(),
time: time,
calData: calData,
dateCellData: dateCellData,
timeFormatError: none(),
timeHintText: _timeHintText(dateTypeOptionPB),
);
@ -245,30 +254,33 @@ String _timeHintText(DateTypeOptionPB typeOption) {
return LocaleKeys.document_date_timeHintTextInTwelveHour.tr();
case TimeFormat.TwentyFourHour:
return LocaleKeys.document_date_timeHintTextInTwentyFourHour.tr();
}
default:
return "";
}
}
Option<CalendarData> calDataFromCellData(DateCellDataPB? cellData) {
Option<DateCellData> calDataFromCellData(DateCellDataPB? cellData) {
String? time = timeFromCellData(cellData);
Option<CalendarData> calData = none();
Option<DateCellData> dateData = none();
if (cellData != null) {
final timestamp = cellData.timestamp * 1000;
final date = DateTime.fromMillisecondsSinceEpoch(timestamp.toInt());
calData = Some(CalendarData(date: date, time: time));
final date = DateTime.fromMillisecondsSinceEpoch(
timestamp.toInt(),
isUtc: true,
);
dateData = Some(DateCellData(
date: date,
time: time,
includeTime: cellData.includeTime,
));
}
return calData;
}
$fixnum.Int64 timestampFromDateTime(DateTime dateTime) {
final timestamp = (dateTime.millisecondsSinceEpoch ~/ 1000);
return $fixnum.Int64(timestamp);
return dateData;
}
String? timeFromCellData(DateCellDataPB? cellData) {
String? time;
if (cellData?.hasTime() ?? false) {
time = cellData?.time;
if (cellData == null || !cellData.hasTime()) {
return null;
}
return time;
return cellData.time;
}

View File

@ -1,13 +1,12 @@
import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
import 'package:appflowy/plugins/database_view/grid/application/cell/date_cell_bloc.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import '../../../layout/sizes.dart';
import '../cell_builder.dart';
import '../../../../grid/presentation/layout/sizes.dart';
import '../../cell_builder.dart';
import 'date_cell_bloc.dart';
import 'date_editor.dart';
class DateCellStyle extends GridCellStyle {
@ -50,7 +49,7 @@ class _DateCellState extends GridCellState<GridDateCell> {
_popover = PopoverController();
final cellController =
widget.cellControllerBuilder.build() as DateCellController;
_cellBloc = getIt<DateCellBloc>(param1: cellController)
_cellBloc = DateCellBloc(cellController: cellController)
..add(const DateCellEvent.initial());
super.initState();
}

View File

@ -1,7 +1,6 @@
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
import 'package:appflowy/plugins/database_view/application/field/type_option/type_option_context.dart';
import 'package:appflowy/plugins/database_view/grid/application/cell/date_cal_bloc.dart';
import 'package:appflowy/workspace/presentation/widgets/toggle/toggle.dart';
import 'package:appflowy/workspace/presentation/widgets/toggle/toggle_style.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
@ -11,9 +10,7 @@ import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra/image.dart';
import 'package:flowy_infra/size.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/style_widget/button.dart';
import 'package:flowy_infra_ui/widget/rounded_input_field.dart';
import 'package:flowy_infra_ui/widget/spacing.dart';
import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pbserver.dart';
import 'package:appflowy_backend/protobuf/flowy-database/date_type_option.pb.dart';
@ -21,9 +18,10 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:table_calendar/table_calendar.dart';
import 'package:textstyle_extensions/textstyle_extensions.dart';
import '../../../layout/sizes.dart';
import '../../common/type_option_separator.dart';
import '../../header/type_option/date.dart';
import '../../../../grid/presentation/layout/sizes.dart';
import '../../../../grid/presentation/widgets/common/type_option_separator.dart';
import '../../../../grid/presentation/widgets/header/type_option/date.dart';
import 'date_cal_bloc.dart';
final kToday = DateTime.now();
final kFirstDay = DateTime(kToday.year, kToday.month - 3, kToday.day);
@ -92,17 +90,17 @@ class _CellCalendarWidget extends StatefulWidget {
class _CellCalendarWidgetState extends State<_CellCalendarWidget> {
late PopoverMutex popoverMutex;
late DateCalBloc bloc;
late DateCellCalendarBloc bloc;
@override
void initState() {
popoverMutex = PopoverMutex();
bloc = DateCalBloc(
bloc = DateCellCalendarBloc(
dateTypeOptionPB: widget.dateTypeOptionPB,
cellData: widget.cellContext.getCellData(),
cellController: widget.cellContext,
)..add(const DateCalEvent.initial());
)..add(const DateCellCalendarEvent.initial());
super.initState();
}
@ -110,18 +108,20 @@ class _CellCalendarWidgetState extends State<_CellCalendarWidget> {
Widget build(BuildContext context) {
return BlocProvider.value(
value: bloc,
child: BlocBuilder<DateCalBloc, DateCalState>(
child: BlocBuilder<DateCellCalendarBloc, DateCellCalendarState>(
buildWhen: (p, c) => p != c,
builder: (context, state) {
bool includeTime = state.dateCellData
.fold(() => false, (dateData) => dateData.includeTime);
List<Widget> children = [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0),
child: _buildCalendar(context),
),
if (state.dateTypeOptionPB.includeTime) ...[
if (includeTime) ...[
const VSpace(12.0),
_TimeTextField(
bloc: context.read<DateCalBloc>(),
bloc: context.read<DateCellCalendarBloc>(),
popoverMutex: popoverMutex,
),
],
@ -151,7 +151,7 @@ class _CellCalendarWidgetState extends State<_CellCalendarWidget> {
}
Widget _buildCalendar(BuildContext context) {
return BlocBuilder<DateCalBloc, DateCalState>(
return BlocBuilder<DateCellCalendarBloc, DateCellCalendarState>(
builder: (context, state) {
final textStyle = Theme.of(context).textTheme.bodyMedium!;
final boxDecoration = BoxDecoration(
@ -208,23 +208,25 @@ class _CellCalendarWidgetState extends State<_CellCalendarWidget> {
textStyle.textColor(Theme.of(context).disabledColor),
),
selectedDayPredicate: (day) {
return state.calData.fold(
return state.dateCellData.fold(
() => false,
(dateData) => isSameDay(dateData.date, day),
);
},
onDaySelected: (selectedDay, focusedDay) {
context
.read<DateCalBloc>()
.add(DateCalEvent.selectDay(selectedDay));
.read<DateCellCalendarBloc>()
.add(DateCellCalendarEvent.selectDay(selectedDay));
},
onFormatChanged: (format) {
context.read<DateCalBloc>().add(DateCalEvent.setCalFormat(format));
context
.read<DateCellCalendarBloc>()
.add(DateCellCalendarEvent.setCalFormat(format));
},
onPageChanged: (focusedDay) {
context
.read<DateCalBloc>()
.add(DateCalEvent.setFocusedDay(focusedDay));
.read<DateCellCalendarBloc>()
.add(DateCellCalendarEvent.setFocusedDay(focusedDay));
},
);
},
@ -237,8 +239,11 @@ class _IncludeTimeButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocSelector<DateCalBloc, DateCalState, bool>(
selector: (state) => state.dateTypeOptionPB.includeTime,
return BlocSelector<DateCellCalendarBloc, DateCellCalendarState, bool>(
selector: (state) => state.dateCellData.fold(
() => false,
(dateData) => dateData.includeTime,
),
builder: (context, includeTime) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0),
@ -258,8 +263,8 @@ class _IncludeTimeButton extends StatelessWidget {
Toggle(
value: includeTime,
onChanged: (value) => context
.read<DateCalBloc>()
.add(DateCalEvent.setIncludeTime(!value)),
.read<DateCellCalendarBloc>()
.add(DateCellCalendarEvent.setIncludeTime(!value)),
style: ToggleStyle.big,
padding: EdgeInsets.zero,
),
@ -274,7 +279,7 @@ class _IncludeTimeButton extends StatelessWidget {
}
class _TimeTextField extends StatefulWidget {
final DateCalBloc bloc;
final DateCellCalendarBloc bloc;
final PopoverMutex popoverMutex;
const _TimeTextField({
@ -298,7 +303,7 @@ class _TimeTextFieldState extends State<_TimeTextField> {
_focusNode.addListener(() {
if (mounted) {
widget.bloc.add(DateCalEvent.setTime(_controller.text));
widget.bloc.add(DateCellCalendarEvent.setTime(_controller.text));
}
});
@ -340,7 +345,7 @@ class _TimeTextFieldState extends State<_TimeTextField> {
errorText: widget.bloc.state.timeFormatError
.fold(() => "", (error) => error),
onEditingComplete: (value) =>
widget.bloc.add(DateCalEvent.setTime(value)),
widget.bloc.add(DateCellCalendarEvent.setTime(value)),
),
),
);
@ -364,7 +369,8 @@ class _DateTypeOptionButton extends StatelessWidget {
Widget build(BuildContext context) {
final title =
"${LocaleKeys.grid_field_dateFormat.tr()} & ${LocaleKeys.grid_field_timeFormat.tr()}";
return BlocSelector<DateCalBloc, DateCalState, DateTypeOptionPB>(
return BlocSelector<DateCellCalendarBloc, DateCellCalendarState,
DateTypeOptionPB>(
selector: (state) => state.dateTypeOptionPB,
builder: (context, dateTypeOptionPB) {
return AppFlowyPopover(
@ -391,7 +397,7 @@ class _DateTypeOptionButton extends StatelessWidget {
return _CalDateTimeSetting(
dateTypeOptionPB: dateTypeOptionPB,
onEvent: (event) {
context.read<DateCalBloc>().add(event);
context.read<DateCellCalendarBloc>().add(event);
popoverMutex.close();
},
);
@ -404,7 +410,7 @@ class _DateTypeOptionButton extends StatelessWidget {
class _CalDateTimeSetting extends StatefulWidget {
final DateTypeOptionPB dateTypeOptionPB;
final Function(DateCalEvent) onEvent;
final Function(DateCellCalendarEvent) onEvent;
const _CalDateTimeSetting({
required this.dateTypeOptionPB,
required this.onEvent,
@ -430,7 +436,7 @@ class _CalDateTimeSettingState extends State<_CalDateTimeSetting> {
return DateFormatList(
selectedFormat: widget.dateTypeOptionPB.dateFormat,
onSelected: (format) {
widget.onEvent(DateCalEvent.setDateFormat(format));
widget.onEvent(DateCellCalendarEvent.setDateFormat(format));
timeSettingPopoverMutex.close();
},
);
@ -448,7 +454,7 @@ class _CalDateTimeSettingState extends State<_CalDateTimeSetting> {
return TimeFormatList(
selectedFormat: widget.dateTypeOptionPB.timeFormat,
onSelected: (format) {
widget.onEvent(DateCalEvent.setTimeFormat(format));
widget.onEvent(DateCellCalendarEvent.setTimeFormat(format));
timeSettingPopoverMutex.close();
});
},

View File

@ -1,12 +1,11 @@
import 'dart:async';
import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../../application/cell/number_cell_bloc.dart';
import '../../layout/sizes.dart';
import 'cell_builder.dart';
import 'number_cell_bloc.dart';
import '../../../../grid/presentation/layout/sizes.dart';
import '../../cell_builder.dart';
class GridNumberCell extends GridCellWidget {
final CellControllerBuilder cellControllerBuilder;
@ -26,8 +25,9 @@ class _NumberCellState extends GridFocusNodeCellState<GridNumberCell> {
@override
void initState() {
final cellController = widget.cellControllerBuilder.build();
_cellBloc = getIt<NumberCellBloc>(param1: cellController)
final cellController =
widget.cellControllerBuilder.build() as NumberCellController;
_cellBloc = NumberCellBloc(cellController: cellController)
..add(const NumberCellEvent.initial());
_controller = TextEditingController(text: _cellBloc.state.cellContent);
super.initState();

View File

@ -1,15 +1,14 @@
import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:appflowy_backend/protobuf/flowy-database/select_type_option.pb.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../../../application/cell/select_option_cell_bloc.dart';
import '../../../layout/sizes.dart';
import '../cell_builder.dart';
import '../../../../grid/presentation/layout/sizes.dart';
import '../../cell_builder.dart';
import 'extension.dart';
import 'select_option_cell_bloc.dart';
import 'select_option_editor.dart';
class SelectOptionCellStyle extends GridCellStyle {
@ -48,7 +47,7 @@ class _SingleSelectCellState extends GridCellState<GridSingleSelectCell> {
void initState() {
final cellController =
widget.cellControllerBuilder.build() as SelectOptionCellController;
_cellBloc = getIt<SelectOptionCellBloc>(param1: cellController)
_cellBloc = SelectOptionCellBloc(cellController: cellController)
..add(const SelectOptionCellEvent.initial());
_popover = PopoverController();
super.initState();
@ -111,7 +110,7 @@ class _MultiSelectCellState extends GridCellState<GridMultiSelectCell> {
void initState() {
final cellController =
widget.cellControllerBuilder.build() as SelectOptionCellController;
_cellBloc = getIt<SelectOptionCellBloc>(param1: cellController)
_cellBloc = SelectOptionCellBloc(cellController: cellController)
..add(const SelectOptionCellEvent.initial());
_popover = PopoverController();
super.initState();

View File

@ -1,14 +1,10 @@
import 'dart:collection';
import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
import 'package:appflowy/plugins/database_view/grid/application/cell/select_option_editor_bloc.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra/image.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/style_widget/icon_button.dart';
import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart';
import 'package:flowy_infra_ui/widget/spacing.dart';
import 'package:appflowy_backend/protobuf/flowy-database/select_type_option.pb.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@ -16,10 +12,11 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:textfield_tags/textfield_tags.dart';
import '../../../layout/sizes.dart';
import '../../common/type_option_separator.dart';
import '../../header/type_option/select_option_editor.dart';
import '../../../../grid/presentation/layout/sizes.dart';
import '../../../../grid/presentation/widgets/common/type_option_separator.dart';
import '../../../../grid/presentation/widgets/header/type_option/select_option_editor.dart';
import 'extension.dart';
import 'select_option_editor_bloc.dart';
import 'text_field.dart';
const double _editorPanelWidth = 300;

View File

@ -1,11 +1,10 @@
import 'dart:async';
import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
import 'package:appflowy/plugins/database_view/grid/application/cell/text_cell_bloc.dart';
import 'package:appflowy/plugins/database_view/widgets/row/cells/text_cell/text_cell_bloc.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:appflowy/startup/startup.dart';
import '../../layout/sizes.dart';
import 'cell_builder.dart';
import '../../../../grid/presentation/layout/sizes.dart';
import '../../cell_builder.dart';
class GridTextCellStyle extends GridCellStyle {
String? placeholder;
@ -40,8 +39,9 @@ class _GridTextCellState extends GridFocusNodeCellState<GridTextCell> {
@override
void initState() {
final cellController = widget.cellControllerBuilder.build();
_cellBloc = getIt<TextCellBloc>(param1: cellController);
final cellController =
widget.cellControllerBuilder.build() as TextCellController;
_cellBloc = TextCellBloc(cellController: cellController);
_cellBloc.add(const TextCellEvent.initial());
_controller = TextEditingController(text: _cellBloc.state.content);
super.initState();

View File

@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
import 'dart:async';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../../../application/cell/url_cell_editor_bloc.dart';
import 'url_cell_editor_bloc.dart';
class URLCellEditor extends StatefulWidget {
final VoidCallback onExit;

Some files were not shown because too many files have changed in this diff Show More