chore: add board data controller

This commit is contained in:
appflowy 2022-08-11 15:00:36 +08:00
parent 8b535720ef
commit cefd571dd0
19 changed files with 141 additions and 151 deletions

View File

@ -1,6 +1,5 @@
import 'dart:async'; import 'dart:async';
import 'package:app_flowy/plugins/grid/application/block/block_cache.dart'; import 'package:app_flowy/plugins/grid/application/block/block_cache.dart';
import 'package:app_flowy/plugins/grid/application/grid_data_controller.dart';
import 'package:app_flowy/plugins/grid/application/row/row_cache.dart'; import 'package:app_flowy/plugins/grid/application/row/row_cache.dart';
import 'package:app_flowy/plugins/grid/presentation/widgets/header/type_option/builder.dart'; import 'package:app_flowy/plugins/grid/presentation/widgets/header/type_option/builder.dart';
import 'package:appflowy_board/appflowy_board.dart'; import 'package:appflowy_board/appflowy_board.dart';
@ -14,14 +13,16 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:freezed_annotation/freezed_annotation.dart';
import 'dart:collection'; import 'dart:collection';
import 'board_data_controller.dart';
part 'board_bloc.freezed.dart'; part 'board_bloc.freezed.dart';
class BoardBloc extends Bloc<BoardEvent, BoardState> { class BoardBloc extends Bloc<BoardEvent, BoardState> {
final GridDataController _gridDataController; final BoardDataController _dataController;
late final AFBoardDataController boardDataController; late final AFBoardDataController boardDataController;
BoardBloc({required ViewPB view}) BoardBloc({required ViewPB view})
: _gridDataController = GridDataController(view: view), : _dataController = BoardDataController(view: view),
super(BoardState.initial(view.id)) { super(BoardState.initial(view.id)) {
boardDataController = AFBoardDataController( boardDataController = AFBoardDataController(
onMoveColumn: ( onMoveColumn: (
@ -51,7 +52,7 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
await _loadGrid(emit); await _loadGrid(emit);
}, },
createRow: () { createRow: () {
_gridDataController.createRow(); _dataController.createRow();
}, },
didReceiveGridUpdate: (GridPB grid) { didReceiveGridUpdate: (GridPB grid) {
emit(state.copyWith(grid: Some(grid))); emit(state.copyWith(grid: Some(grid)));
@ -66,39 +67,34 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
@override @override
Future<void> close() async { Future<void> close() async {
await _gridDataController.dispose(); await _dataController.dispose();
return super.close(); return super.close();
} }
GridRowCache? getRowCache(String blockId, String rowId) { GridRowCache? getRowCache(String blockId, String rowId) {
final GridBlockCache? blockCache = _gridDataController.blocks[blockId]; final GridBlockCache? blockCache = _dataController.blocks[blockId];
return blockCache?.rowCache; return blockCache?.rowCache;
} }
void _startListening() { void _startListening() {
_gridDataController.addListener( _dataController.addListener(
onGridChanged: (grid) { onGridChanged: (grid) {
if (!isClosed) { if (!isClosed) {
add(BoardEvent.didReceiveGridUpdate(grid)); add(BoardEvent.didReceiveGridUpdate(grid));
} }
}, },
onRowsChanged: (rowInfos, reason) {
if (!isClosed) {
_buildColumnItems(rowInfos);
}
},
onFieldsChanged: (fields) { onFieldsChanged: (fields) {
if (!isClosed) { if (!isClosed) {
_buildColumns(fields); _buildColumns(fields);
} }
}, },
onGroupChanged: (groups) {},
onError: (err) {
Log.error(err);
},
); );
} }
void _buildColumnItems(List<RowInfo> rowInfos) {
for (final rowInfo in rowInfos) {}
}
void _buildColumns(UnmodifiableListView<FieldPB> fields) { void _buildColumns(UnmodifiableListView<FieldPB> fields) {
FieldPB? groupField; FieldPB? groupField;
for (final field in fields) { for (final field in fields) {
@ -114,7 +110,7 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
void _buildColumnsFromSingleSelect(FieldPB field) { void _buildColumnsFromSingleSelect(FieldPB field) {
final typeOptionContext = makeTypeOptionContext<SingleSelectTypeOptionPB>( final typeOptionContext = makeTypeOptionContext<SingleSelectTypeOptionPB>(
gridId: _gridDataController.gridId, gridId: _dataController.gridId,
field: field, field: field,
); );
@ -135,7 +131,7 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
} }
Future<void> _loadGrid(Emitter<BoardState> emit) async { Future<void> _loadGrid(Emitter<BoardState> emit) async {
final result = await _gridDataController.loadData(); final result = await _dataController.loadData();
result.fold( result.fold(
(grid) => emit( (grid) => emit(
state.copyWith(loadingState: GridLoadingState.finish(left(unit))), state.copyWith(loadingState: GridLoadingState.finish(left(unit))),

View File

@ -1,121 +1,113 @@
// import 'dart:collection'; import 'dart:collection';
// import 'package:flowy_sdk/log.dart'; import 'package:app_flowy/plugins/grid/application/block/block_cache.dart';
// import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; import 'package:app_flowy/plugins/grid/application/field/field_cache.dart';
// import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart'; import 'package:app_flowy/plugins/grid/application/grid_service.dart';
// import 'package:flowy_sdk/protobuf/flowy-grid/block_entities.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
// import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart';
// import 'package:flowy_sdk/protobuf/flowy-grid/grid_entities.pb.dart'; import 'dart:async';
// import 'dart:async'; import 'package:dartz/dartz.dart';
// import 'package:dartz/dartz.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/protobuf.dart';
// typedef OnFieldsChanged = void Function(UnmodifiableListView<FieldPB>); typedef OnFieldsChanged = void Function(UnmodifiableListView<FieldPB>);
// typedef OnGridChanged = void Function(GridPB); typedef OnGridChanged = void Function(GridPB);
typedef OnGroupChanged = void Function(List<GroupPB>);
typedef OnError = void Function(FlowyError);
class BoardDataController {
final String gridId;
final GridService _gridFFIService;
final GridFieldCache fieldCache;
// class ridDataController { // key: the block id
// final String gridId; final LinkedHashMap<String, GridBlockCache> _blocks;
// final GridService _gridFFIService; UnmodifiableMapView<String, GridBlockCache> get blocks =>
// final GridFieldCache fieldCache; UnmodifiableMapView(_blocks);
// // key: the block id OnFieldsChanged? _onFieldsChanged;
// final LinkedHashMap<String, GridBlockCache> _blocks; OnGridChanged? _onGridChanged;
// UnmodifiableMapView<String, GridBlockCache> get blocks => OnGroupChanged? _onGroupChanged;
// UnmodifiableMapView(_blocks); OnError? _onError;
// OnRowsChanged? _onRowChanged; BoardDataController({required ViewPB view})
// OnFieldsChanged? _onFieldsChanged; : gridId = view.id,
// OnGridChanged? _onGridChanged; _blocks = LinkedHashMap.identity(),
_gridFFIService = GridService(gridId: view.id),
fieldCache = GridFieldCache(gridId: view.id);
// List<GridRowInfo> get rowInfos { void addListener({
// final List<GridRowInfo> rows = []; OnGridChanged? onGridChanged,
// for (var block in _blocks.values) { OnFieldsChanged? onFieldsChanged,
// rows.addAll(block.rows); OnGroupChanged? onGroupChanged,
// } OnError? onError,
// return rows; }) {
// } _onGridChanged = onGridChanged;
_onFieldsChanged = onFieldsChanged;
_onGroupChanged = onGroupChanged;
_onError = onError;
// GridDataController({required ViewPB view}) fieldCache.addListener(onFields: (fields) {
// : gridId = view.id, _onFieldsChanged?.call(UnmodifiableListView(fields));
// _blocks = LinkedHashMap.identity(), });
// _gridFFIService = GridService(gridId: view.id), }
// fieldCache = GridFieldCache(gridId: view.id);
// void addListener({ Future<Either<Unit, FlowyError>> loadData() async {
// required OnGridChanged onGridChanged, final result = await _gridFFIService.loadGrid();
// required OnRowsChanged onRowsChanged, return Future(
// required OnFieldsChanged onFieldsChanged, () => result.fold(
// }) { (grid) async {
// _onGridChanged = onGridChanged; _onGridChanged?.call(grid);
// _onRowChanged = onRowsChanged; return await _loadFields(grid).then((result) {
// _onFieldsChanged = onFieldsChanged; return result.fold(
(l) {
_loadGroups();
return left(l);
},
(err) => right(err),
);
});
},
(err) => right(err),
),
);
}
// fieldCache.addListener(onFields: (fields) { void createRow() {
// _onFieldsChanged?.call(UnmodifiableListView(fields)); _gridFFIService.createRow();
// }); }
// }
// Future<Either<Unit, FlowyError>> loadData() async { Future<void> dispose() async {
// final result = await _gridFFIService.loadGrid(); await _gridFFIService.closeGrid();
// return Future( await fieldCache.dispose();
// () => result.fold(
// (grid) async {
// _initialBlocks(grid.blocks);
// _onGridChanged?.call(grid);
// return await _loadFields(grid);
// },
// (err) => right(err),
// ),
// );
// }
// void createRow() { for (final blockCache in _blocks.values) {
// _gridFFIService.createRow(); blockCache.dispose();
// } }
}
// Future<void> dispose() async { Future<Either<Unit, FlowyError>> _loadFields(GridPB grid) async {
// await _gridFFIService.closeGrid(); final result = await _gridFFIService.getFields(fieldIds: grid.fields);
// await fieldCache.dispose(); return Future(
() => result.fold(
(fields) {
fieldCache.fields = fields.items;
_onFieldsChanged?.call(UnmodifiableListView(fieldCache.fields));
return left(unit);
},
(err) => right(err),
),
);
}
// for (final blockCache in _blocks.values) { Future<void> _loadGroups() async {
// blockCache.dispose(); final result = await _gridFFIService.loadGroups();
// } return Future(
// } () => result.fold(
(groups) {
// void _initialBlocks(List<BlockPB> blocks) { _onGroupChanged?.call(groups.items);
// for (final block in blocks) { },
// if (_blocks[block.id] != null) { (err) => _onError?.call(err),
// Log.warn("Initial duplicate block's cache: ${block.id}"); ),
// return; );
// } }
}
// final cache = GridBlockCache(
// gridId: gridId,
// block: block,
// fieldCache: fieldCache,
// );
// cache.addListener(
// onChangeReason: (reason) {
// _onRowChanged?.call(rowInfos, reason);
// },
// );
// _blocks[block.id] = cache;
// }
// }
// Future<Either<Unit, FlowyError>> _loadFields(GridPB grid) async {
// final result = await _gridFFIService.getFields(fieldIds: grid.fields);
// return Future(
// () => result.fold(
// (fields) {
// fieldCache.fields = fields.items;
// _onFieldsChanged?.call(UnmodifiableListView(fieldCache.fields));
// return left(unit);
// },
// (err) => right(err),
// ),
// );
// }
// }

View File

@ -31,7 +31,7 @@ class BoardPluginBuilder implements PluginBuilder {
class BoardPluginConfig implements PluginConfig { class BoardPluginConfig implements PluginConfig {
@override @override
bool get creatable => true; bool get creatable => false;
} }
class BoardPlugin extends Plugin { class BoardPlugin extends Plugin {

View File

@ -8,6 +8,6 @@ class BoardCard extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container(child: Text('1234')); return const Text('1234');
} }
} }

View File

@ -1,13 +1,10 @@
import 'package:dartz/dartz.dart'; import 'package:dartz/dartz.dart';
import 'package:flowy_infra/notifier.dart';
import 'package:flowy_sdk/dispatch/dispatch.dart'; import 'package:flowy_sdk/dispatch/dispatch.dart';
import 'package:flowy_sdk/log.dart';
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/grid_entities.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/grid_entities.pb.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:protobuf/protobuf.dart';
part 'field_service.freezed.dart'; part 'field_service.freezed.dart';
/// FieldService consists of lots of event functions. We define the events in the backend(Rust), /// FieldService consists of lots of event functions. We define the events in the backend(Rust),

View File

@ -75,7 +75,7 @@ class SelectOptionTypeOptionState with _$SelectOptionTypeOptionState {
required List<SelectOptionPB> options, required List<SelectOptionPB> options,
required bool isEditingOption, required bool isEditingOption,
required Option<String> newOptionName, required Option<String> newOptionName,
}) = _SelectOptionTyepOptionState; }) = _SelectOptionTypeOptionState;
factory SelectOptionTypeOptionState.initial(List<SelectOptionPB> options) => factory SelectOptionTypeOptionState.initial(List<SelectOptionPB> options) =>
SelectOptionTypeOptionState( SelectOptionTypeOptionState(

View File

@ -20,7 +20,7 @@ typedef OnRowsChanged = void Function(
List<RowInfo> rowInfos, List<RowInfo> rowInfos,
RowChangeReason, RowChangeReason,
); );
typedef ListenONRowChangedCondition = bool Function(); typedef ListenOnRowChangedCondition = bool Function();
class GridDataController { class GridDataController {
final String gridId; final String gridId;

View File

@ -5,6 +5,7 @@ import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/block_entities.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/block_entities.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/grid_entities.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/grid_entities.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/group.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/row_entities.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/row_entities.pb.dart';
class GridService { class GridService {
@ -38,4 +39,9 @@ class GridService {
final request = ViewIdPB(value: gridId); final request = ViewIdPB(value: gridId);
return FolderEventCloseView(request).send(); return FolderEventCloseView(request).send();
} }
Future<Either<RepeatedGridGroupPB, FlowyError>> loadGroups() {
final payload = GridIdPB(value: gridId);
return GridEventGetGroup(payload).send();
}
} }

View File

@ -1,6 +1,5 @@
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:app_flowy/plugins/grid/application/field/type_option/multi_select_type_option.dart';
import 'package:app_flowy/plugins/grid/application/field/type_option/type_option_context.dart'; import 'package:app_flowy/plugins/grid/application/field/type_option/type_option_context.dart';
import 'package:app_flowy/plugins/grid/application/field/type_option/type_option_data_controller.dart'; import 'package:app_flowy/plugins/grid/application/field/type_option/type_option_data_controller.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/checkbox_type_option.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/checkbox_type_option.pb.dart';
@ -11,7 +10,6 @@ import 'package:flowy_sdk/protobuf/flowy-grid/single_select_type_option.pb.dart'
import 'package:flowy_sdk/protobuf/flowy-grid/text_type_option.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/text_type_option.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/url_type_option.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/url_type_option.pb.dart';
import 'package:protobuf/protobuf.dart'; import 'package:protobuf/protobuf.dart';
import 'package:app_flowy/plugins/grid/application/prelude.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'checkbox.dart'; import 'checkbox.dart';

View File

@ -1,5 +1,5 @@
pub use crate::entities::view::ViewDataTypePB; pub use crate::entities::view::ViewDataTypePB;
use crate::entities::{SubViewDataTypePB, ViewInfoPB}; use crate::entities::ViewInfoPB;
use crate::manager::{ViewDataProcessor, ViewDataProcessorMap}; use crate::manager::{ViewDataProcessor, ViewDataProcessorMap};
use crate::{ use crate::{
dart_notification::{send_dart_notification, FolderNotification}, dart_notification::{send_dart_notification, FolderNotification},

View File

@ -359,6 +359,7 @@ pub async fn create_view(
desc: desc.to_string(), desc: desc.to_string(),
thumbnail: None, thumbnail: None,
data_type, data_type,
sub_data_type: None,
plugin_type: 0, plugin_type: 0,
data: vec![], data: vec![],
}; };

View File

@ -32,7 +32,7 @@ impl std::convert::From<&GridGroupRevision> for GridGroupConfigurationPB {
#[derive(ProtoBuf, Debug, Default, Clone)] #[derive(ProtoBuf, Debug, Default, Clone)]
pub struct RepeatedGridGroupPB { pub struct RepeatedGridGroupPB {
#[pb(index = 1)] #[pb(index = 1)]
groups: Vec<GroupPB>, items: Vec<GroupPB>,
} }
#[derive(ProtoBuf, Debug, Default, Clone)] #[derive(ProtoBuf, Debug, Default, Clone)]

View File

@ -6,7 +6,7 @@ use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
use flowy_error::ErrorCode; use flowy_error::ErrorCode;
use flowy_grid_data_model::parser::NotEmptyStr; use flowy_grid_data_model::parser::NotEmptyStr;
use flowy_grid_data_model::revision::GridLayoutRevision; use flowy_grid_data_model::revision::GridLayoutRevision;
use flowy_sync::entities::grid::{DeleteGroupParams, GridSettingChangesetParams}; use flowy_sync::entities::grid::GridSettingChangesetParams;
use std::collections::HashMap; use std::collections::HashMap;
use std::convert::TryInto; use std::convert::TryInto;
use strum::IntoEnumIterator; use strum::IntoEnumIterator;

View File

@ -35,6 +35,8 @@ pub struct GridRevisionEditor {
block_manager: Arc<GridBlockManager>, block_manager: Arc<GridBlockManager>,
#[allow(dead_code)] #[allow(dead_code)]
pub(crate) filter_service: Arc<GridFilterService>, pub(crate) filter_service: Arc<GridFilterService>,
#[allow(dead_code)]
pub(crate) group_service: Arc<GridGroupService>, pub(crate) group_service: Arc<GridGroupService>,
} }

View File

@ -5,8 +5,11 @@ use std::sync::Arc;
use tokio::sync::RwLock; use tokio::sync::RwLock;
pub(crate) struct GridGroupService { pub(crate) struct GridGroupService {
#[allow(dead_code)]
scheduler: Arc<dyn GridServiceTaskScheduler>, scheduler: Arc<dyn GridServiceTaskScheduler>,
#[allow(dead_code)]
grid_pad: Arc<RwLock<GridRevisionPad>>, grid_pad: Arc<RwLock<GridRevisionPad>>,
#[allow(dead_code)]
block_manager: Arc<GridBlockManager>, block_manager: Arc<GridBlockManager>,
} }

View File

@ -1,3 +1,3 @@
mod group_service; mod group_service;
pub use group_service::*; pub(crate) use group_service::*;

View File

@ -50,18 +50,16 @@ impl<'a> RowRevisionBuilder<'a> {
} }
} }
pub fn insert_select_option_cell(mut self, field_id: &str, data: String) -> Self { pub fn insert_select_option_cell(&mut self, field_id: &str, data: String) {
match self.field_rev_map.get(&field_id.to_owned()) { match self.field_rev_map.get(&field_id.to_owned()) {
None => { None => {
tracing::warn!("Invalid field_id: {}", field_id); tracing::warn!("Invalid field_id: {}", field_id);
self
} }
Some(field_rev) => { Some(field_rev) => {
let cell_data = SelectOptionCellChangeset::from_insert(&data).to_str(); let cell_data = SelectOptionCellChangeset::from_insert(&data).to_str();
let data = apply_cell_data_changeset(cell_data, None, field_rev).unwrap(); let data = apply_cell_data_changeset(cell_data, None, field_rev).unwrap();
let cell = CellRevision::new(data); let cell = CellRevision::new(data);
self.payload.cell_by_field_id.insert(field_id.to_owned(), cell); self.payload.cell_by_field_id.insert(field_id.to_owned(), cell);
self
} }
} }
} }

View File

@ -48,19 +48,18 @@ pub fn make_default_board() -> BuildGridContext {
let done_option = SelectOptionPB::new("Done"); let done_option = SelectOptionPB::new("Done");
let single_select = SingleSelectTypeOptionBuilder::default() let single_select = SingleSelectTypeOptionBuilder::default()
.add_option(not_started_option.clone()) .add_option(not_started_option.clone())
.add_option(in_progress_option.clone()) .add_option(in_progress_option)
.add_option(done_option.clone()); .add_option(done_option);
let single_select_field = FieldBuilder::new(single_select).name("Status").visibility(true).build(); let single_select_field = FieldBuilder::new(single_select).name("Status").visibility(true).build();
let single_select_field_id = single_select_field.id.clone(); let single_select_field_id = single_select_field.id.clone();
grid_builder.add_field(single_select_field); grid_builder.add_field(single_select_field);
// rows // Insert rows
for _ in 0..3 { for _ in 0..3 {
grid_builder.add_row( let mut row_builder = RowRevisionBuilder::new(grid_builder.block_id(), grid_builder.field_revs());
RowRevisionBuilder::new(grid_builder.block_id(), grid_builder.field_revs()) row_builder.insert_select_option_cell(&single_select_field_id, not_started_option.id.clone());
.insert_select_option_cell(&single_select_field_id, not_started_option.id.clone()) let row = row_builder.build();
.build(), grid_builder.add_row(row);
);
} }
grid_builder.build() grid_builder.build()

View File

@ -10,7 +10,6 @@ use flowy_grid_data_model::revision::{FieldRevision, RowRevision};
use strum::EnumCount; use strum::EnumCount;
pub struct GridRowTestBuilder<'a> { pub struct GridRowTestBuilder<'a> {
block_id: String,
field_revs: &'a [Arc<FieldRevision>], field_revs: &'a [Arc<FieldRevision>],
inner_builder: RowRevisionBuilder<'a>, inner_builder: RowRevisionBuilder<'a>,
} }
@ -20,7 +19,6 @@ impl<'a> GridRowTestBuilder<'a> {
assert_eq!(field_revs.len(), FieldType::COUNT); assert_eq!(field_revs.len(), FieldType::COUNT);
let inner_builder = RowRevisionBuilder::new(block_id, field_revs); let inner_builder = RowRevisionBuilder::new(block_id, field_revs);
Self { Self {
block_id: block_id.to_owned(),
field_revs, field_revs,
inner_builder, inner_builder,
} }