123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290 |
- 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;
- }
- }
|