Merge pull request #793 from AppFlowy-IO/feat/refactor_plugin_path

Refactor plugins path
This commit is contained in:
Nathan.fooo 2022-08-09 12:37:52 +08:00 committed by GitHub
commit aaee3003ce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
160 changed files with 1153 additions and 677 deletions

View File

@ -4,7 +4,7 @@ import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:app_flowy/generated/locale_keys.g.dart'; import 'package:app_flowy/generated/locale_keys.g.dart';
import 'package:app_flowy/plugin/plugin.dart'; import 'package:app_flowy/startup/plugin/plugin.dart';
class BlankPluginBuilder extends PluginBuilder { class BlankPluginBuilder extends PluginBuilder {
@override @override
@ -42,7 +42,8 @@ class BlankPagePlugin extends Plugin {
class BlankPagePluginDisplay extends PluginDisplay with NavigationItem { class BlankPagePluginDisplay extends PluginDisplay with NavigationItem {
@override @override
Widget get leftBarItem => FlowyText.medium(LocaleKeys.blankPageTitle.tr(), fontSize: 12); Widget get leftBarItem =>
FlowyText.medium(LocaleKeys.blankPageTitle.tr(), fontSize: 12);
@override @override
Widget buildWidget() => const BlankPage(); Widget buildWidget() => const BlankPage();

View File

@ -1,10 +1,10 @@
import 'package:app_flowy/workspace/presentation/home/home_stack.dart'; import 'package:app_flowy/workspace/presentation/home/home_stack.dart';
import 'package:app_flowy/workspace/presentation/plugins/widgets/left_bar_item.dart'; import 'package:app_flowy/workspace/presentation/widgets/left_bar_item.dart';
import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart';
import 'package:app_flowy/plugin/plugin.dart'; import 'package:app_flowy/startup/plugin/plugin.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'src/board_page.dart'; import 'presentation/board_page.dart';
class BoardPluginBuilder implements PluginBuilder { class BoardPluginBuilder implements PluginBuilder {
@override @override

View File

@ -1,7 +1,7 @@
import 'dart:convert'; import 'dart:convert';
import 'package:app_flowy/workspace/application/doc/doc_service.dart'; import 'package:app_flowy/plugins/trash/application/trash_service.dart';
import 'package:app_flowy/workspace/application/trash/trash_service.dart';
import 'package:app_flowy/workspace/application/view/view_listener.dart'; import 'package:app_flowy/workspace/application/view/view_listener.dart';
import 'package:app_flowy/plugins/doc/application/doc_service.dart';
import 'package:flowy_sdk/protobuf/flowy-folder/trash.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-folder/trash.pb.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-folder/view.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart';
@ -43,14 +43,17 @@ class DocumentBloc extends Bloc<DocumentEvent, DocumentState> {
emit(state.copyWith(isDeleted: false)); emit(state.copyWith(isDeleted: false));
}, },
deletePermanently: (DeletePermanently value) async { deletePermanently: (DeletePermanently value) async {
final result = await trashService.deleteViews([Tuple2(view.id, TrashType.TrashView)]); final result = await trashService
.deleteViews([Tuple2(view.id, TrashType.TrashView)]);
final newState = result.fold((l) => state.copyWith(forceClose: true), (r) => state); final newState = result.fold(
(l) => state.copyWith(forceClose: true), (r) => state);
emit(newState); emit(newState);
}, },
restorePage: (RestorePage value) async { restorePage: (RestorePage value) async {
final result = await trashService.putback(view.id); final result = await trashService.putback(view.id);
final newState = result.fold((l) => state.copyWith(isDeleted: false), (r) => state); final newState = result.fold(
(l) => state.copyWith(isDeleted: false), (r) => state);
emit(newState); emit(newState);
}, },
); );
@ -93,10 +96,12 @@ class DocumentBloc extends Bloc<DocumentEvent, DocumentState> {
final documentDelta = document.toDelta(); final documentDelta = document.toDelta();
_composeDelta(delta, documentDelta); _composeDelta(delta, documentDelta);
}); });
emit(state.copyWith(loadingState: DocumentLoadingState.finish(left(unit)))); emit(state.copyWith(
loadingState: DocumentLoadingState.finish(left(unit))));
}, },
(err) { (err) {
emit(state.copyWith(loadingState: DocumentLoadingState.finish(right(err)))); emit(state.copyWith(
loadingState: DocumentLoadingState.finish(right(err))));
}, },
); );
} }
@ -156,5 +161,6 @@ class DocumentState with _$DocumentState {
@freezed @freezed
class DocumentLoadingState with _$DocumentLoadingState { class DocumentLoadingState with _$DocumentLoadingState {
const factory DocumentLoadingState.loading() = _Loading; const factory DocumentLoadingState.loading() = _Loading;
const factory DocumentLoadingState.finish(Either<Unit, FlowyError> successOrFail) = _Finish; const factory DocumentLoadingState.finish(
Either<Unit, FlowyError> successOrFail) = _Finish;
} }

View File

@ -1,8 +1,8 @@
import 'dart:async'; import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'package:app_flowy/startup/tasks/rust_sdk.dart'; import 'package:app_flowy/startup/tasks/rust_sdk.dart';
import 'package:app_flowy/workspace/application/doc/share_service.dart';
import 'package:app_flowy/workspace/application/markdown/delta_markdown.dart'; import 'package:app_flowy/workspace/application/markdown/delta_markdown.dart';
import 'package:app_flowy/plugins/doc/application/share_service.dart';
import 'package:flowy_sdk/protobuf/flowy-text-block/entities.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-text-block/entities.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
@ -14,13 +14,15 @@ part 'share_bloc.freezed.dart';
class DocShareBloc extends Bloc<DocShareEvent, DocShareState> { class DocShareBloc extends Bloc<DocShareEvent, DocShareState> {
ShareService service; ShareService service;
ViewPB view; ViewPB view;
DocShareBloc({required this.view, required this.service}) : super(const DocShareState.initial()) { DocShareBloc({required this.view, required this.service})
: super(const DocShareState.initial()) {
on<DocShareEvent>((event, emit) async { on<DocShareEvent>((event, emit) async {
await event.map( await event.map(
shareMarkdown: (ShareMarkdown value) async { shareMarkdown: (ShareMarkdown value) async {
await service.exportMarkdown(view.id).then((result) { await service.exportMarkdown(view.id).then((result) {
result.fold( result.fold(
(value) => emit(DocShareState.finish(left(_convertDeltaToMarkdown(value)))), (value) => emit(
DocShareState.finish(left(_convertDeltaToMarkdown(value)))),
(error) => emit(DocShareState.finish(right(error))), (error) => emit(DocShareState.finish(right(error))),
); );
}); });
@ -73,5 +75,6 @@ class DocShareEvent with _$DocShareEvent {
class DocShareState with _$DocShareState { class DocShareState with _$DocShareState {
const factory DocShareState.initial() = _Initial; const factory DocShareState.initial() = _Initial;
const factory DocShareState.loading() = _Loading; const factory DocShareState.loading() = _Loading;
const factory DocShareState.finish(Either<ExportDataPB, FlowyError> successOrFail) = _Finish; const factory DocShareState.finish(
Either<ExportDataPB, FlowyError> successOrFail) = _Finish;
} }

View File

@ -1,14 +1,14 @@
library docuemnt_plugin; library docuemnt_plugin;
import 'package:app_flowy/generated/locale_keys.g.dart'; import 'package:app_flowy/generated/locale_keys.g.dart';
import 'package:app_flowy/plugin/plugin.dart'; import 'package:app_flowy/startup/plugin/plugin.dart';
import 'package:app_flowy/startup/startup.dart'; import 'package:app_flowy/startup/startup.dart';
import 'package:app_flowy/workspace/application/appearance.dart'; import 'package:app_flowy/workspace/application/appearance.dart';
import 'package:app_flowy/workspace/application/doc/share_bloc.dart';
import 'package:app_flowy/workspace/application/view/view_listener.dart'; import 'package:app_flowy/workspace/application/view/view_listener.dart';
import 'package:app_flowy/plugins/doc/application/share_bloc.dart';
import 'package:app_flowy/workspace/presentation/home/home_stack.dart'; import 'package:app_flowy/workspace/presentation/home/home_stack.dart';
import 'package:app_flowy/workspace/presentation/home/toast.dart'; import 'package:app_flowy/workspace/presentation/home/toast.dart';
import 'package:app_flowy/workspace/presentation/plugins/widgets/left_bar_item.dart'; import 'package:app_flowy/workspace/presentation/widgets/left_bar_item.dart';
import 'package:app_flowy/workspace/presentation/widgets/dialogs.dart'; import 'package:app_flowy/workspace/presentation/widgets/dialogs.dart';
import 'package:app_flowy/workspace/presentation/widgets/pop_up_action.dart'; import 'package:app_flowy/workspace/presentation/widgets/pop_up_action.dart';
import 'package:clipboard/clipboard.dart'; import 'package:clipboard/clipboard.dart';
@ -26,12 +26,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'src/document_page.dart'; import 'document_page.dart';
export './src/document_page.dart';
export './src/widget/toolbar/history_button.dart';
export './src/widget/toolbar/tool_bar.dart';
export './src/widget/toolbar/toolbar_icon_button.dart';
class DocumentPluginBuilder extends PluginBuilder { class DocumentPluginBuilder extends PluginBuilder {
@override @override
@ -58,7 +53,9 @@ class DocumentPlugin implements Plugin {
ViewListener? _listener; ViewListener? _listener;
late PluginType _pluginType; late PluginType _pluginType;
DocumentPlugin({required PluginType pluginType, required ViewPB view, Key? key}) : _view = view { DocumentPlugin(
{required PluginType pluginType, required ViewPB view, Key? key})
: _view = view {
_pluginType = pluginType; _pluginType = pluginType;
_listener = getIt<ViewListener>(param1: view); _listener = getIt<ViewListener>(param1: view);
_listener?.start(onViewUpdated: (result) { _listener?.start(onViewUpdated: (result) {
@ -112,7 +109,8 @@ class DocumentPluginDisplay extends PluginDisplay<int> with NavigationItem {
class DocumentShareButton extends StatelessWidget { class DocumentShareButton extends StatelessWidget {
final ViewPB view; final ViewPB view;
DocumentShareButton({Key? key, required this.view}) : super(key: ValueKey(view.hashCode)); DocumentShareButton({Key? key, required this.view})
: super(key: ValueKey(view.hashCode));
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -149,7 +147,8 @@ class DocumentShareButton extends StatelessWidget {
fontSize: 12, fontSize: 12,
borderRadius: Corners.s6Border, borderRadius: Corners.s6Border,
color: Colors.lightBlue, color: Colors.lightBlue,
onPressed: () => _showActionList(context, Offset(-(buttonWidth / 2), 10)), onPressed: () => _showActionList(
context, Offset(-(buttonWidth / 2), 10)),
), ),
), ),
), ),
@ -165,7 +164,8 @@ class DocumentShareButton extends StatelessWidget {
case ExportType.Link: case ExportType.Link:
break; break;
case ExportType.Markdown: case ExportType.Markdown:
FlutterClipboard.copy(exportData.data).then((value) => Log.info('copied to clipboard')); FlutterClipboard.copy(exportData.data)
.then((value) => Log.info('copied to clipboard'));
break; break;
case ExportType.Text: case ExportType.Text:
break; break;
@ -179,11 +179,15 @@ class DocumentShareButton extends StatelessWidget {
result.fold(() {}, (action) { result.fold(() {}, (action) {
switch (action) { switch (action) {
case ShareAction.markdown: case ShareAction.markdown:
context.read<DocShareBloc>().add(const DocShareEvent.shareMarkdown()); context
showMessageToast('Exported to: ${LocaleKeys.notifications_export_path.tr()}'); .read<DocShareBloc>()
.add(const DocShareEvent.shareMarkdown());
showMessageToast(
'Exported to: ${LocaleKeys.notifications_export_path.tr()}');
break; break;
case ShareAction.copyLink: case ShareAction.copyLink:
FlowyAlertDialog(title: LocaleKeys.shareAction_workInProgress.tr()).show(context); FlowyAlertDialog(title: LocaleKeys.shareAction_workInProgress.tr())
.show(context);
break; break;
} }
}); });
@ -198,7 +202,8 @@ class DocumentShareButton extends StatelessWidget {
class ShareActions with ActionList<ShareActionWrapper>, FlowyOverlayDelegate { class ShareActions with ActionList<ShareActionWrapper>, FlowyOverlayDelegate {
final Function(dartz.Option<ShareAction>) onSelected; final Function(dartz.Option<ShareAction>) onSelected;
final _items = ShareAction.values.map((action) => ShareActionWrapper(action)).toList(); final _items =
ShareAction.values.map((action) => ShareActionWrapper(action)).toList();
ShareActions({required this.onSelected}); ShareActions({required this.onSelected});
@ -212,7 +217,8 @@ class ShareActions with ActionList<ShareActionWrapper>, FlowyOverlayDelegate {
List<ShareActionWrapper> get items => _items; List<ShareActionWrapper> get items => _items;
@override @override
void Function(dartz.Option<ShareActionWrapper> p1) get selectCallback => (result) { void Function(dartz.Option<ShareActionWrapper> p1) get selectCallback =>
(result) {
result.fold( result.fold(
() => onSelected(dartz.none()), () => onSelected(dartz.none()),
(wrapper) => onSelected( (wrapper) => onSelected(

View File

@ -1,7 +1,7 @@
import 'package:app_flowy/startup/startup.dart'; import 'package:app_flowy/startup/startup.dart';
import 'package:app_flowy/workspace/application/appearance.dart'; import 'package:app_flowy/workspace/application/appearance.dart';
import 'package:app_flowy/workspace/application/doc/doc_bloc.dart'; import 'package:app_flowy/plugins/doc/presentation/banner.dart';
import 'package:app_flowy/workspace/presentation/plugins/doc/document.dart'; import 'package:app_flowy/plugins/doc/presentation/toolbar/tool_bar.dart';
import 'package:flowy_infra_ui/style_widget/scrolling/styled_scroll_bar.dart'; import 'package:flowy_infra_ui/style_widget/scrolling/styled_scroll_bar.dart';
import 'package:flowy_infra_ui/widget/spacing.dart'; import 'package:flowy_infra_ui/widget/spacing.dart';
import 'package:flutter_quill/flutter_quill.dart' as quill; import 'package:flutter_quill/flutter_quill.dart' as quill;
@ -10,8 +10,8 @@ import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'application/doc_bloc.dart';
import 'styles.dart'; import 'styles.dart';
import 'widget/banner.dart';
class DocumentPage extends StatefulWidget { class DocumentPage extends StatefulWidget {
final ViewPB view; final ViewPB view;
@ -29,7 +29,8 @@ class _DocumentPageState extends State<DocumentPage> {
@override @override
void initState() { void initState() {
documentBloc = getIt<DocumentBloc>(param1: super.widget.view)..add(const DocumentEvent.initial()); documentBloc = getIt<DocumentBloc>(param1: super.widget.view)
..add(const DocumentEvent.initial());
super.initState(); super.initState();
} }
@ -39,10 +40,12 @@ class _DocumentPageState extends State<DocumentPage> {
providers: [ providers: [
BlocProvider<DocumentBloc>.value(value: documentBloc), BlocProvider<DocumentBloc>.value(value: documentBloc),
], ],
child: BlocBuilder<DocumentBloc, DocumentState>(builder: (context, state) { child:
BlocBuilder<DocumentBloc, DocumentState>(builder: (context, state) {
return state.loadingState.map( return state.loadingState.map(
// loading: (_) => const FlowyProgressIndicator(), // loading: (_) => const FlowyProgressIndicator(),
loading: (_) => SizedBox.expand(child: Container(color: Colors.transparent)), loading: (_) =>
SizedBox.expand(child: Container(color: Colors.transparent)),
finish: (result) => result.successOrFail.fold( finish: (result) => result.successOrFail.fold(
(_) { (_) {
if (state.forceClose) { if (state.forceClose) {
@ -90,8 +93,11 @@ class _DocumentPageState extends State<DocumentPage> {
Widget _renderBanner(BuildContext context) { Widget _renderBanner(BuildContext context) {
return DocumentBanner( return DocumentBanner(
onRestore: () => context.read<DocumentBloc>().add(const DocumentEvent.restorePage()), onRestore: () =>
onDelete: () => context.read<DocumentBloc>().add(const DocumentEvent.deletePermanently()), context.read<DocumentBloc>().add(const DocumentEvent.restorePage()),
onDelete: () => context
.read<DocumentBloc>()
.add(const DocumentEvent.deletePermanently()),
); );
} }

View File

@ -1,11 +1,10 @@
import 'package:app_flowy/plugins/doc/presentation/style_widgets.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_quill/flutter_quill.dart'; import 'package:flutter_quill/flutter_quill.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:tuple/tuple.dart'; import 'package:tuple/tuple.dart';
import 'package:flowy_infra/theme.dart'; import 'package:flowy_infra/theme.dart';
import 'widget/style_widgets.dart';
DefaultStyles customStyles(BuildContext context) { DefaultStyles customStyles(BuildContext context) {
const baseSpacing = Tuple2<double, double>(6, 0); const baseSpacing = Tuple2<double, double>(6, 0);
@ -53,7 +52,8 @@ DefaultStyles customStyles(BuildContext context) {
const Tuple2(8, 0), const Tuple2(8, 0),
const Tuple2(0, 0), const Tuple2(0, 0),
null), null),
paragraph: DefaultTextBlockStyle(baseStyle, const Tuple2(10, 0), const Tuple2(0, 0), null), paragraph: DefaultTextBlockStyle(
baseStyle, const Tuple2(10, 0), const Tuple2(0, 0), null),
bold: const TextStyle(fontWeight: FontWeight.bold), bold: const TextStyle(fontWeight: FontWeight.bold),
italic: const TextStyle(fontStyle: FontStyle.italic), italic: const TextStyle(fontStyle: FontStyle.italic),
small: const TextStyle(fontSize: 12, color: Colors.black45), small: const TextStyle(fontSize: 12, color: Colors.black45),
@ -78,8 +78,8 @@ DefaultStyles customStyles(BuildContext context) {
const Tuple2(0, 0), const Tuple2(0, 0),
const Tuple2(0, 0), const Tuple2(0, 0),
null), null),
lists: lists: DefaultListBlockStyle(baseStyle, baseSpacing, const Tuple2(0, 6),
DefaultListBlockStyle(baseStyle, baseSpacing, const Tuple2(0, 6), null, StyleWidgetBuilder.checkbox(theme)), null, StyleWidgetBuilder.checkbox(theme)),
quote: DefaultTextBlockStyle( quote: DefaultTextBlockStyle(
TextStyle(color: baseStyle.color!.withOpacity(0.6)), TextStyle(color: baseStyle.color!.withOpacity(0.6)),
baseSpacing, baseSpacing,
@ -102,9 +102,12 @@ DefaultStyles customStyles(BuildContext context) {
color: Colors.grey.shade50, color: Colors.grey.shade50,
borderRadius: BorderRadius.circular(2), borderRadius: BorderRadius.circular(2),
)), )),
indent: DefaultTextBlockStyle(baseStyle, baseSpacing, const Tuple2(0, 6), null), indent: DefaultTextBlockStyle(
align: DefaultTextBlockStyle(baseStyle, const Tuple2(0, 0), const Tuple2(0, 0), null), baseStyle, baseSpacing, const Tuple2(0, 6), null),
leading: DefaultTextBlockStyle(baseStyle, const Tuple2(0, 0), const Tuple2(0, 0), null), align: DefaultTextBlockStyle(
baseStyle, const Tuple2(0, 0), const Tuple2(0, 0), null),
leading: DefaultTextBlockStyle(
baseStyle, const Tuple2(0, 0), const Tuple2(0, 0), null),
sizeSmall: const TextStyle(fontSize: 10), sizeSmall: const TextStyle(fontSize: 10),
sizeLarge: const TextStyle(fontSize: 18), sizeLarge: const TextStyle(fontSize: 18),
sizeHuge: const TextStyle(fontSize: 22)); sizeHuge: const TextStyle(fontSize: 22));

View File

@ -1,6 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'package:app_flowy/workspace/application/grid/grid_service.dart'; import 'package:app_flowy/plugins/grid/application/grid_service.dart';
import 'package:app_flowy/workspace/application/grid/row/row_service.dart'; import 'package:app_flowy/plugins/grid/application/row/row_service.dart';
import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/log.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/block_entities.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/block_entities.pb.dart';

View File

@ -1,7 +1,7 @@
import 'dart:async'; import 'dart:async';
import 'dart:collection'; import 'dart:collection';
import 'package:app_flowy/workspace/application/grid/grid_service.dart'; import 'package:app_flowy/plugins/grid/application/grid_service.dart';
import 'package:dartz/dartz.dart'; import 'package:dartz/dartz.dart';
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
import 'package:flowy_sdk/dispatch/dispatch.dart'; import 'package:flowy_sdk/dispatch/dispatch.dart';
@ -14,8 +14,8 @@ import 'package:flowy_sdk/protobuf/flowy-grid/select_option.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/url_type_option_entities.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/url_type_option_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:app_flowy/workspace/application/grid/cell/cell_listener.dart'; import 'package:app_flowy/plugins/grid/application/cell/cell_listener.dart';
import 'package:app_flowy/workspace/application/grid/field/field_service.dart'; import 'package:app_flowy/plugins/grid/application/field/field_service.dart';
import 'dart:convert' show utf8; import 'dart:convert' show utf8;
import '../../field/type_option/type_option_service.dart'; import '../../field/type_option/type_option_service.dart';

View File

@ -1,8 +1,10 @@
part of 'cell_service.dart'; part of 'cell_service.dart';
typedef GridCellController = IGridCellController<String, String>; typedef GridCellController = IGridCellController<String, String>;
typedef GridSelectOptionCellController = IGridCellController<SelectOptionCellDataPB, String>; typedef GridSelectOptionCellController
typedef GridDateCellController = IGridCellController<DateCellDataPB, CalendarData>; = IGridCellController<SelectOptionCellDataPB, String>;
typedef GridDateCellController
= IGridCellController<DateCellDataPB, CalendarData>;
typedef GridURLCellController = IGridCellController<URLCellDataPB, String>; typedef GridURLCellController = IGridCellController<URLCellDataPB, String>;
class GridCellControllerBuilder { class GridCellControllerBuilder {
@ -19,7 +21,8 @@ class GridCellControllerBuilder {
_cellId = cellId; _cellId = cellId;
IGridCellController build() { IGridCellController build() {
final cellFieldNotifier = GridCellFieldNotifier(notifier: _GridFieldChangedNotifierImpl(_fieldCache)); final cellFieldNotifier = GridCellFieldNotifier(
notifier: _GridFieldChangedNotifierImpl(_fieldCache));
switch (_cellId.fieldType) { switch (_cellId.fieldType) {
case FieldType.Checkbox: case FieldType.Checkbox:
@ -142,8 +145,10 @@ class IGridCellController<T, D> extends Equatable {
_cellDataLoader = cellDataLoader, _cellDataLoader = cellDataLoader,
_cellDataPersistence = cellDataPersistence, _cellDataPersistence = cellDataPersistence,
_fieldNotifier = fieldNotifier, _fieldNotifier = fieldNotifier,
_fieldService = FieldService(gridId: cellId.gridId, fieldId: cellId.field.id), _fieldService =
_cacheKey = GridCellCacheKey(rowId: cellId.rowId, fieldId: cellId.field.id); FieldService(gridId: cellId.gridId, fieldId: cellId.field.id),
_cacheKey =
GridCellCacheKey(rowId: cellId.rowId, fieldId: cellId.field.id);
IGridCellController<T, D> clone() { IGridCellController<T, D> clone() {
return IGridCellController( return IGridCellController(
@ -164,7 +169,9 @@ class IGridCellController<T, D> extends Equatable {
FieldType get fieldType => cellId.field.fieldType; FieldType get fieldType => cellId.field.fieldType;
VoidCallback? startListening({required void Function(T?) onCellChanged, VoidCallback? onCellFieldChanged}) { VoidCallback? startListening(
{required void Function(T?) onCellChanged,
VoidCallback? onCellFieldChanged}) {
if (isListening) { if (isListening) {
Log.error("Already started. It seems like you should call clone first"); Log.error("Already started. It seems like you should call clone first");
return null; return null;
@ -226,8 +233,11 @@ class IGridCellController<T, D> extends Equatable {
/// Return the FieldTypeOptionDataPB that can be parsed into corresponding class using the [parser]. /// Return the FieldTypeOptionDataPB that can be parsed into corresponding class using the [parser].
/// [PD] is the type that the parser return. /// [PD] is the type that the parser return.
Future<Either<PD, FlowyError>> getFieldTypeOption<PD, P extends TypeOptionDataParser>(P parser) { Future<Either<PD, FlowyError>>
return _fieldService.getFieldTypeOptionData(fieldType: fieldType).then((result) { getFieldTypeOption<PD, P extends TypeOptionDataParser>(P parser) {
return _fieldService
.getFieldTypeOptionData(fieldType: fieldType)
.then((result) {
return result.fold( return result.fold(
(data) => parser.fromBuffer(data.typeOptionData), (data) => parser.fromBuffer(data.typeOptionData),
(err) => right(err), (err) => right(err),
@ -239,7 +249,9 @@ class IGridCellController<T, D> extends Equatable {
/// You can set [dedeplicate] to true (default is false) to reduce the save operation. /// You can set [dedeplicate] to true (default is false) to reduce the save operation.
/// It's useful when you call this method when user editing the [TextField]. /// It's useful when you call this method when user editing the [TextField].
/// The default debounce interval is 300 milliseconds. /// The default debounce interval is 300 milliseconds.
void saveCellData(D data, {bool deduplicate = false, void Function(Option<FlowyError>)? resultCallback}) async { void saveCellData(D data,
{bool deduplicate = false,
void Function(Option<FlowyError>)? resultCallback}) async {
if (deduplicate) { if (deduplicate) {
_loadDataOperation?.cancel(); _loadDataOperation?.cancel();
@ -288,7 +300,8 @@ class IGridCellController<T, D> extends Equatable {
} }
@override @override
List<Object> get props => [_cellsCache.get(_cacheKey) ?? "", cellId.rowId + cellId.field.id]; List<Object> get props =>
[_cellsCache.get(_cacheKey) ?? "", cellId.rowId + cellId.field.id];
} }
class _GridFieldChangedNotifierImpl extends GridFieldChangedNotifier { class _GridFieldChangedNotifierImpl extends GridFieldChangedNotifier {
@ -300,7 +313,7 @@ class _GridFieldChangedNotifierImpl extends GridFieldChangedNotifier {
@override @override
void dispose() { void dispose() {
if (_onChangesetFn != null) { if (_onChangesetFn != null) {
_cache.removeListener(onChangsetListener: _onChangesetFn!); _cache.removeListener(onChangesetListener: _onChangesetFn!);
_onChangesetFn = null; _onChangesetFn = null;
} }
} }

View File

@ -1,6 +1,7 @@
import 'package:app_flowy/generated/locale_keys.g.dart'; import 'package:app_flowy/generated/locale_keys.g.dart';
import 'package:app_flowy/workspace/application/grid/field/field_service.dart'; import 'package:app_flowy/plugins/grid/application/field/field_service.dart';
import 'package:easy_localization/easy_localization.dart' show StringTranslateExtension; import 'package:easy_localization/easy_localization.dart'
show StringTranslateExtension;
import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/log.dart';
import 'package:flowy_sdk/protobuf/flowy-error-code/code.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-error-code/code.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
@ -40,7 +41,8 @@ class DateCalBloc extends Bloc<DateCalEvent, DateCalState> {
}, },
didReceiveCellUpdate: (DateCellDataPB? cellData) { didReceiveCellUpdate: (DateCellDataPB? cellData) {
final calData = calDataFromCellData(cellData); final calData = calDataFromCellData(cellData);
final time = calData.foldRight("", (dateData, previous) => dateData.time); final time =
calData.foldRight("", (dateData, previous) => dateData.time);
emit(state.copyWith(calData: calData, time: time)); emit(state.copyWith(calData: calData, time: time));
}, },
setIncludeTime: (includeTime) async { setIncludeTime: (includeTime) async {
@ -57,15 +59,18 @@ class DateCalBloc extends Bloc<DateCalEvent, DateCalState> {
await _updateDateData(emit, time: time); await _updateDateData(emit, time: time);
} }
}, },
didUpdateCalData: (Option<CalendarData> data, Option<String> timeFormatError) { didUpdateCalData:
emit(state.copyWith(calData: data, timeFormatError: timeFormatError)); (Option<CalendarData> data, Option<String> timeFormatError) {
emit(state.copyWith(
calData: data, timeFormatError: timeFormatError));
}, },
); );
}, },
); );
} }
Future<void> _updateDateData(Emitter<DateCalState> emit, {DateTime? date, String? time}) { Future<void> _updateDateData(Emitter<DateCalState> emit,
{DateTime? date, String? time}) {
final CalendarData newDateData = state.calData.fold( final CalendarData newDateData = state.calData.fold(
() => CalendarData(date: date ?? DateTime.now(), time: time), () => CalendarData(date: date ?? DateTime.now(), time: time),
(dateData) { (dateData) {
@ -84,13 +89,17 @@ class DateCalBloc extends Bloc<DateCalEvent, DateCalState> {
return _saveDateData(emit, newDateData); return _saveDateData(emit, newDateData);
} }
Future<void> _saveDateData(Emitter<DateCalState> emit, CalendarData newCalData) async { Future<void> _saveDateData(
Emitter<DateCalState> emit, CalendarData newCalData) async {
if (state.calData == Some(newCalData)) { if (state.calData == Some(newCalData)) {
return; return;
} }
updateCalData(Option<CalendarData> calData, Option<String> timeFormatError) { updateCalData(
if (!isClosed) add(DateCalEvent.didUpdateCalData(calData, timeFormatError)); Option<CalendarData> calData, Option<String> timeFormatError) {
if (!isClosed) {
add(DateCalEvent.didUpdateCalData(calData, timeFormatError));
}
} }
cellContext.saveCellData(newCalData, resultCallback: (result) { cellContext.saveCellData(newCalData, resultCallback: (result) {
@ -172,7 +181,9 @@ class DateCalBloc extends Bloc<DateCalEvent, DateCalState> {
); );
result.fold( result.fold(
(l) => emit(state.copyWith(dateTypeOption: newDateTypeOption, timeHintText: _timeHintText(newDateTypeOption))), (l) => emit(state.copyWith(
dateTypeOption: newDateTypeOption,
timeHintText: _timeHintText(newDateTypeOption))),
(err) => Log.error(err), (err) => Log.error(err),
); );
} }
@ -182,14 +193,17 @@ class DateCalBloc extends Bloc<DateCalEvent, DateCalState> {
class DateCalEvent with _$DateCalEvent { class DateCalEvent with _$DateCalEvent {
const factory DateCalEvent.initial() = _Initial; const factory DateCalEvent.initial() = _Initial;
const factory DateCalEvent.selectDay(DateTime day) = _SelectDay; const factory DateCalEvent.selectDay(DateTime day) = _SelectDay;
const factory DateCalEvent.setCalFormat(CalendarFormat format) = _CalendarFormat; const factory DateCalEvent.setCalFormat(CalendarFormat format) =
_CalendarFormat;
const factory DateCalEvent.setFocusedDay(DateTime day) = _FocusedDay; const factory DateCalEvent.setFocusedDay(DateTime day) = _FocusedDay;
const factory DateCalEvent.setTimeFormat(TimeFormat timeFormat) = _TimeFormat; const factory DateCalEvent.setTimeFormat(TimeFormat timeFormat) = _TimeFormat;
const factory DateCalEvent.setDateFormat(DateFormat dateFormat) = _DateFormat; const factory DateCalEvent.setDateFormat(DateFormat dateFormat) = _DateFormat;
const factory DateCalEvent.setIncludeTime(bool includeTime) = _IncludeTime; const factory DateCalEvent.setIncludeTime(bool includeTime) = _IncludeTime;
const factory DateCalEvent.setTime(String time) = _Time; const factory DateCalEvent.setTime(String time) = _Time;
const factory DateCalEvent.didReceiveCellUpdate(DateCellDataPB? data) = _DidReceiveCellUpdate; const factory DateCalEvent.didReceiveCellUpdate(DateCellDataPB? data) =
const factory DateCalEvent.didUpdateCalData(Option<CalendarData> data, Option<String> timeFormatError) = _DidReceiveCellUpdate;
const factory DateCalEvent.didUpdateCalData(
Option<CalendarData> data, Option<String> timeFormatError) =
_DidUpdateCalData; _DidUpdateCalData;
} }

View File

@ -2,11 +2,12 @@ import 'dart:async';
import 'package:flowy_sdk/protobuf/flowy-grid/select_option.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/select_option.pb.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:app_flowy/workspace/application/grid/cell/cell_service/cell_service.dart'; import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_service.dart';
part 'select_option_cell_bloc.freezed.dart'; part 'select_option_cell_bloc.freezed.dart';
class SelectOptionCellBloc extends Bloc<SelectOptionCellEvent, SelectOptionCellState> { class SelectOptionCellBloc
extends Bloc<SelectOptionCellEvent, SelectOptionCellState> {
final GridSelectOptionCellController cellContext; final GridSelectOptionCellController cellContext;
void Function()? _onCellChangedFn; void Function()? _onCellChangedFn;
@ -66,7 +67,8 @@ class SelectOptionCellState with _$SelectOptionCellState {
required List<SelectOptionPB> selectedOptions, required List<SelectOptionPB> selectedOptions,
}) = _SelectOptionCellState; }) = _SelectOptionCellState;
factory SelectOptionCellState.initial(GridSelectOptionCellController context) { factory SelectOptionCellState.initial(
GridSelectOptionCellController context) {
final data = context.getCellData(); final data = context.getCellData();
return SelectOptionCellState( return SelectOptionCellState(

View File

@ -4,20 +4,22 @@ import 'package:flowy_sdk/log.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/select_option.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/select_option.pb.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:app_flowy/workspace/application/grid/cell/cell_service/cell_service.dart'; import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_service.dart';
import 'select_option_service.dart'; import 'select_option_service.dart';
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
part 'select_option_editor_bloc.freezed.dart'; part 'select_option_editor_bloc.freezed.dart';
class SelectOptionCellEditorBloc extends Bloc<SelectOptionEditorEvent, SelectOptionEditorState> { class SelectOptionCellEditorBloc
extends Bloc<SelectOptionEditorEvent, SelectOptionEditorState> {
final SelectOptionService _selectOptionService; final SelectOptionService _selectOptionService;
final GridSelectOptionCellController cellController; final GridSelectOptionCellController cellController;
Timer? _delayOperation; Timer? _delayOperation;
SelectOptionCellEditorBloc({ SelectOptionCellEditorBloc({
required this.cellController, required this.cellController,
}) : _selectOptionService = SelectOptionService(cellId: cellController.cellId), }) : _selectOptionService =
SelectOptionService(cellId: cellController.cellId),
super(SelectOptionEditorState.initial(cellController)) { super(SelectOptionEditorState.initial(cellController)) {
on<SelectOptionEditorEvent>( on<SelectOptionEditorEvent>(
(event, emit) async { (event, emit) async {
@ -87,7 +89,8 @@ class SelectOptionCellEditorBloc extends Bloc<SelectOptionEditorEvent, SelectOpt
} }
void _onSelectOption(String optionId) { void _onSelectOption(String optionId) {
final hasSelected = state.selectedOptions.firstWhereOrNull((option) => option.id == optionId); final hasSelected = state.selectedOptions
.firstWhereOrNull((option) => option.id == optionId);
if (hasSelected != null) { if (hasSelected != null) {
_selectOptionService.unSelect(optionId: optionId); _selectOptionService.unSelect(optionId: optionId);
} else { } else {
@ -96,7 +99,8 @@ class SelectOptionCellEditorBloc extends Bloc<SelectOptionEditorEvent, SelectOpt
} }
void _filterOption(String optionName, Emitter<SelectOptionEditorState> emit) { void _filterOption(String optionName, Emitter<SelectOptionEditorState> emit) {
final _MakeOptionResult result = _makeOptions(Some(optionName), state.allOptions); final _MakeOptionResult result =
_makeOptions(Some(optionName), state.allOptions);
emit(state.copyWith( emit(state.copyWith(
filter: Some(optionName), filter: Some(optionName),
options: result.options, options: result.options,
@ -112,7 +116,8 @@ class SelectOptionCellEditorBloc extends Bloc<SelectOptionEditorEvent, SelectOpt
return; return;
} }
return result.fold( return result.fold(
(data) => add(SelectOptionEditorEvent.didReceiveOptions(data.options, data.selectOptions)), (data) => add(SelectOptionEditorEvent.didReceiveOptions(
data.options, data.selectOptions)),
(err) { (err) {
Log.error(err); Log.error(err);
return null; return null;
@ -122,7 +127,8 @@ class SelectOptionCellEditorBloc extends Bloc<SelectOptionEditorEvent, SelectOpt
}); });
} }
_MakeOptionResult _makeOptions(Option<String> filter, List<SelectOptionPB> allOptions) { _MakeOptionResult _makeOptions(
Option<String> filter, List<SelectOptionPB> allOptions) {
final List<SelectOptionPB> options = List.from(allOptions); final List<SelectOptionPB> options = List.from(allOptions);
Option<String> createOption = filter; Option<String> createOption = filter;
@ -165,12 +171,18 @@ class SelectOptionCellEditorBloc extends Bloc<SelectOptionEditorEvent, SelectOpt
class SelectOptionEditorEvent with _$SelectOptionEditorEvent { class SelectOptionEditorEvent with _$SelectOptionEditorEvent {
const factory SelectOptionEditorEvent.initial() = _Initial; const factory SelectOptionEditorEvent.initial() = _Initial;
const factory SelectOptionEditorEvent.didReceiveOptions( const factory SelectOptionEditorEvent.didReceiveOptions(
List<SelectOptionPB> options, List<SelectOptionPB> selectedOptions) = _DidReceiveOptions; List<SelectOptionPB> options, List<SelectOptionPB> selectedOptions) =
const factory SelectOptionEditorEvent.newOption(String optionName) = _NewOption; _DidReceiveOptions;
const factory SelectOptionEditorEvent.selectOption(String optionId) = _SelectOption; const factory SelectOptionEditorEvent.newOption(String optionName) =
const factory SelectOptionEditorEvent.updateOption(SelectOptionPB option) = _UpdateOption; _NewOption;
const factory SelectOptionEditorEvent.deleteOption(SelectOptionPB option) = _DeleteOption; const factory SelectOptionEditorEvent.selectOption(String optionId) =
const factory SelectOptionEditorEvent.filterOption(String optionName) = _SelectOptionFilter; _SelectOption;
const factory SelectOptionEditorEvent.updateOption(SelectOptionPB option) =
_UpdateOption;
const factory SelectOptionEditorEvent.deleteOption(SelectOptionPB option) =
_DeleteOption;
const factory SelectOptionEditorEvent.filterOption(String optionName) =
_SelectOptionFilter;
} }
@freezed @freezed
@ -183,7 +195,8 @@ class SelectOptionEditorState with _$SelectOptionEditorState {
required Option<String> filter, required Option<String> filter,
}) = _SelectOptionEditorState; }) = _SelectOptionEditorState;
factory SelectOptionEditorState.initial(GridSelectOptionCellController context) { factory SelectOptionEditorState.initial(
GridSelectOptionCellController context) {
final data = context.getCellData(loadIfNotExist: false); final data = context.getCellData(loadIfNotExist: false);
return SelectOptionEditorState( return SelectOptionEditorState(
options: data?.options ?? [], options: data?.options ?? [],

View File

@ -2,7 +2,7 @@ import 'package:dartz/dartz.dart';
import 'package:flowy_sdk/dispatch/dispatch.dart'; import 'package:flowy_sdk/dispatch/dispatch.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/cell_entities.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/cell_entities.pb.dart';
import 'package:app_flowy/workspace/application/grid/field/type_option/type_option_service.dart'; import 'package:app_flowy/plugins/grid/application/field/type_option/type_option_service.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/select_option.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/select_option.pb.dart';
import 'cell_service/cell_service.dart'; import 'cell_service/cell_service.dart';
@ -15,7 +15,9 @@ class SelectOptionService {
String get rowId => cellId.rowId; String get rowId => cellId.rowId;
Future<Either<Unit, FlowyError>> create({required String name}) { Future<Either<Unit, FlowyError>> create({required String name}) {
return TypeOptionService(gridId: gridId, fieldId: fieldId).newOption(name: name).then( return TypeOptionService(gridId: gridId, fieldId: fieldId)
.newOption(name: name)
.then(
(result) { (result) {
return result.fold( return result.fold(
(option) { (option) {

View File

@ -1,5 +1,5 @@
import 'package:app_flowy/workspace/application/grid/field/field_listener.dart'; import 'package:app_flowy/plugins/grid/application/field/field_listener.dart';
import 'package:app_flowy/workspace/application/grid/field/field_service.dart'; import 'package:app_flowy/plugins/grid/application/field/field_service.dart';
import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/log.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_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
@ -15,7 +15,8 @@ class FieldCellBloc extends Bloc<FieldCellEvent, FieldCellState> {
FieldCellBloc({ FieldCellBloc({
required GridFieldCellContext cellContext, required GridFieldCellContext cellContext,
}) : _fieldListener = SingleFieldListener(fieldId: cellContext.field.id), }) : _fieldListener = SingleFieldListener(fieldId: cellContext.field.id),
_fieldService = FieldService(gridId: cellContext.gridId, fieldId: cellContext.field.id), _fieldService = FieldService(
gridId: cellContext.gridId, fieldId: cellContext.field.id),
super(FieldCellState.initial(cellContext)) { super(FieldCellState.initial(cellContext)) {
on<FieldCellEvent>( on<FieldCellEvent>(
(event, emit) async { (event, emit) async {
@ -62,8 +63,10 @@ class FieldCellBloc extends Bloc<FieldCellEvent, FieldCellState> {
@freezed @freezed
class FieldCellEvent with _$FieldCellEvent { class FieldCellEvent with _$FieldCellEvent {
const factory FieldCellEvent.initial() = _InitialCell; const factory FieldCellEvent.initial() = _InitialCell;
const factory FieldCellEvent.didReceiveFieldUpdate(GridFieldPB field) = _DidReceiveFieldUpdate; const factory FieldCellEvent.didReceiveFieldUpdate(GridFieldPB field) =
const factory FieldCellEvent.startUpdateWidth(double offset) = _StartUpdateWidth; _DidReceiveFieldUpdate;
const factory FieldCellEvent.startUpdateWidth(double offset) =
_StartUpdateWidth;
const factory FieldCellEvent.endUpdateWidth() = _EndUpdateWidth; const factory FieldCellEvent.endUpdateWidth() = _EndUpdateWidth;
} }
@ -75,7 +78,8 @@ class FieldCellState with _$FieldCellState {
required double width, required double width,
}) = _FieldCellState; }) = _FieldCellState;
factory FieldCellState.initial(GridFieldCellContext cellContext) => FieldCellState( factory FieldCellState.initial(GridFieldCellContext cellContext) =>
FieldCellState(
gridId: cellContext.gridId, gridId: cellContext.gridId,
field: cellContext.field, field: cellContext.field,
width: cellContext.field.width.toDouble(), width: cellContext.field.width.toDouble(),

View File

@ -1,4 +1,4 @@
import 'package:app_flowy/workspace/application/grid/field/type_option/type_option_service.dart'; import 'package:app_flowy/plugins/grid/application/field/type_option/type_option_service.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option_entities.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option_entities.pb.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
@ -16,20 +16,24 @@ class DateTypeOptionDataParser extends TypeOptionDataParser<DateTypeOption> {
} }
} }
class DateTypeOptionBloc extends Bloc<DateTypeOptionEvent, DateTypeOptionState> { class DateTypeOptionBloc
extends Bloc<DateTypeOptionEvent, DateTypeOptionState> {
DateTypeOptionBloc({required DateTypeOptionContext typeOptionContext}) DateTypeOptionBloc({required DateTypeOptionContext typeOptionContext})
: super(DateTypeOptionState.initial(typeOptionContext.typeOption)) { : super(DateTypeOptionState.initial(typeOptionContext.typeOption)) {
on<DateTypeOptionEvent>( on<DateTypeOptionEvent>(
(event, emit) async { (event, emit) async {
event.map( event.map(
didSelectDateFormat: (_DidSelectDateFormat value) { didSelectDateFormat: (_DidSelectDateFormat value) {
emit(state.copyWith(typeOption: _updateTypeOption(dateFormat: value.format))); emit(state.copyWith(
typeOption: _updateTypeOption(dateFormat: value.format)));
}, },
didSelectTimeFormat: (_DidSelectTimeFormat value) { didSelectTimeFormat: (_DidSelectTimeFormat value) {
emit(state.copyWith(typeOption: _updateTypeOption(timeFormat: value.format))); emit(state.copyWith(
typeOption: _updateTypeOption(timeFormat: value.format)));
}, },
includeTime: (_IncludeTime value) { includeTime: (_IncludeTime value) {
emit(state.copyWith(typeOption: _updateTypeOption(includeTime: value.includeTime))); emit(state.copyWith(
typeOption: _updateTypeOption(includeTime: value.includeTime)));
}, },
); );
}, },
@ -65,9 +69,12 @@ class DateTypeOptionBloc extends Bloc<DateTypeOptionEvent, DateTypeOptionState>
@freezed @freezed
class DateTypeOptionEvent with _$DateTypeOptionEvent { class DateTypeOptionEvent with _$DateTypeOptionEvent {
const factory DateTypeOptionEvent.didSelectDateFormat(DateFormat format) = _DidSelectDateFormat; const factory DateTypeOptionEvent.didSelectDateFormat(DateFormat format) =
const factory DateTypeOptionEvent.didSelectTimeFormat(TimeFormat format) = _DidSelectTimeFormat; _DidSelectDateFormat;
const factory DateTypeOptionEvent.includeTime(bool includeTime) = _IncludeTime; const factory DateTypeOptionEvent.didSelectTimeFormat(TimeFormat format) =
_DidSelectTimeFormat;
const factory DateTypeOptionEvent.includeTime(bool includeTime) =
_IncludeTime;
} }
@freezed @freezed
@ -76,5 +83,6 @@ class DateTypeOptionState with _$DateTypeOptionState {
required DateTypeOption typeOption, required DateTypeOption typeOption,
}) = _DateTypeOptionState; }) = _DateTypeOptionState;
factory DateTypeOptionState.initial(DateTypeOption typeOption) => DateTypeOptionState(typeOption: typeOption); factory DateTypeOptionState.initial(DateTypeOption typeOption) =>
DateTypeOptionState(typeOption: typeOption);
} }

View File

@ -1,4 +1,4 @@
import 'package:app_flowy/workspace/application/grid/field/field_service.dart'; import 'package:app_flowy/plugins/grid/application/field/field_service.dart';
import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/log.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/multi_select_type_option.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/multi_select_type_option.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/select_option.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/select_option.pb.dart';
@ -7,7 +7,8 @@ import 'package:protobuf/protobuf.dart';
import 'select_option_type_option_bloc.dart'; import 'select_option_type_option_bloc.dart';
import 'type_option_service.dart'; import 'type_option_service.dart';
class MultiSelectTypeOptionContext extends TypeOptionWidgetContext<MultiSelectTypeOption> class MultiSelectTypeOptionContext
extends TypeOptionWidgetContext<MultiSelectTypeOption>
with SelectOptionTypeOptionAction { with SelectOptionTypeOptionAction {
final TypeOptionService service; final TypeOptionService service;
@ -25,7 +26,8 @@ class MultiSelectTypeOptionContext extends TypeOptionWidgetContext<MultiSelectTy
return (SelectOptionPB option) { return (SelectOptionPB option) {
typeOption.freeze(); typeOption.freeze();
typeOption = typeOption.rebuild((typeOption) { typeOption = typeOption.rebuild((typeOption) {
final index = typeOption.options.indexWhere((element) => element.id == option.id); final index =
typeOption.options.indexWhere((element) => element.id == option.id);
if (index != -1) { if (index != -1) {
typeOption.options.removeAt(index); typeOption.options.removeAt(index);
} }
@ -61,7 +63,8 @@ class MultiSelectTypeOptionContext extends TypeOptionWidgetContext<MultiSelectTy
return (SelectOptionPB option) { return (SelectOptionPB option) {
typeOption.freeze(); typeOption.freeze();
typeOption = typeOption.rebuild((typeOption) { typeOption = typeOption.rebuild((typeOption) {
final index = typeOption.options.indexWhere((element) => element.id == option.id); final index =
typeOption.options.indexWhere((element) => element.id == option.id);
if (index != -1) { if (index != -1) {
typeOption.options[index] = option; typeOption.options[index] = option;
} }
@ -71,7 +74,8 @@ class MultiSelectTypeOptionContext extends TypeOptionWidgetContext<MultiSelectTy
} }
} }
class MultiSelectTypeOptionWidgetDataParser extends TypeOptionDataParser<MultiSelectTypeOption> { class MultiSelectTypeOptionWidgetDataParser
extends TypeOptionDataParser<MultiSelectTypeOption> {
@override @override
MultiSelectTypeOption fromBuffer(List<int> buffer) { MultiSelectTypeOption fromBuffer(List<int> buffer) {
return MultiSelectTypeOption.fromBuffer(buffer); return MultiSelectTypeOption.fromBuffer(buffer);

View File

@ -1,4 +1,4 @@
import 'package:app_flowy/workspace/application/grid/field/type_option/type_option_service.dart'; import 'package:app_flowy/plugins/grid/application/field/type_option/type_option_service.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/format.pbenum.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/format.pbenum.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/number_type_option.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/number_type_option.pb.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
@ -10,14 +10,16 @@ part 'number_bloc.freezed.dart';
typedef NumberTypeOptionContext = TypeOptionWidgetContext<NumberTypeOption>; typedef NumberTypeOptionContext = TypeOptionWidgetContext<NumberTypeOption>;
class NumberTypeOptionWidgetDataParser extends TypeOptionDataParser<NumberTypeOption> { class NumberTypeOptionWidgetDataParser
extends TypeOptionDataParser<NumberTypeOption> {
@override @override
NumberTypeOption fromBuffer(List<int> buffer) { NumberTypeOption fromBuffer(List<int> buffer) {
return NumberTypeOption.fromBuffer(buffer); return NumberTypeOption.fromBuffer(buffer);
} }
} }
class NumberTypeOptionBloc extends Bloc<NumberTypeOptionEvent, NumberTypeOptionState> { class NumberTypeOptionBloc
extends Bloc<NumberTypeOptionEvent, NumberTypeOptionState> {
NumberTypeOptionBloc({required NumberTypeOptionContext typeOptionContext}) NumberTypeOptionBloc({required NumberTypeOptionContext typeOptionContext})
: super(NumberTypeOptionState.initial(typeOptionContext.typeOption)) { : super(NumberTypeOptionState.initial(typeOptionContext.typeOption)) {
on<NumberTypeOptionEvent>( on<NumberTypeOptionEvent>(
@ -46,7 +48,8 @@ class NumberTypeOptionBloc extends Bloc<NumberTypeOptionEvent, NumberTypeOptionS
@freezed @freezed
class NumberTypeOptionEvent with _$NumberTypeOptionEvent { class NumberTypeOptionEvent with _$NumberTypeOptionEvent {
const factory NumberTypeOptionEvent.didSelectFormat(NumberFormat format) = _DidSelectFormat; const factory NumberTypeOptionEvent.didSelectFormat(NumberFormat format) =
_DidSelectFormat;
} }
@freezed @freezed
@ -55,7 +58,8 @@ class NumberTypeOptionState with _$NumberTypeOptionState {
required NumberTypeOption typeOption, required NumberTypeOption typeOption,
}) = _NumberTypeOptionState; }) = _NumberTypeOptionState;
factory NumberTypeOptionState.initial(NumberTypeOption typeOption) => NumberTypeOptionState( factory NumberTypeOptionState.initial(NumberTypeOption typeOption) =>
NumberTypeOptionState(
typeOption: typeOption, typeOption: typeOption,
); );
} }

View File

@ -1,4 +1,4 @@
import 'package:app_flowy/workspace/application/grid/field/field_service.dart'; import 'package:app_flowy/plugins/grid/application/field/field_service.dart';
import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/log.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/select_option.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/select_option.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/single_select_type_option.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/single_select_type_option.pb.dart';
@ -7,7 +7,8 @@ import 'package:protobuf/protobuf.dart';
import 'select_option_type_option_bloc.dart'; import 'select_option_type_option_bloc.dart';
import 'type_option_service.dart'; import 'type_option_service.dart';
class SingleSelectTypeOptionContext extends TypeOptionWidgetContext<SingleSelectTypeOptionPB> class SingleSelectTypeOptionContext
extends TypeOptionWidgetContext<SingleSelectTypeOptionPB>
with SelectOptionTypeOptionAction { with SelectOptionTypeOptionAction {
final TypeOptionService service; final TypeOptionService service;
@ -25,7 +26,8 @@ class SingleSelectTypeOptionContext extends TypeOptionWidgetContext<SingleSelect
return (SelectOptionPB option) { return (SelectOptionPB option) {
typeOption.freeze(); typeOption.freeze();
typeOption = typeOption.rebuild((typeOption) { typeOption = typeOption.rebuild((typeOption) {
final index = typeOption.options.indexWhere((element) => element.id == option.id); final index =
typeOption.options.indexWhere((element) => element.id == option.id);
if (index != -1) { if (index != -1) {
typeOption.options.removeAt(index); typeOption.options.removeAt(index);
} }
@ -61,7 +63,8 @@ class SingleSelectTypeOptionContext extends TypeOptionWidgetContext<SingleSelect
return (SelectOptionPB option) { return (SelectOptionPB option) {
typeOption.freeze(); typeOption.freeze();
typeOption = typeOption.rebuild((typeOption) { typeOption = typeOption.rebuild((typeOption) {
final index = typeOption.options.indexWhere((element) => element.id == option.id); final index =
typeOption.options.indexWhere((element) => element.id == option.id);
if (index != -1) { if (index != -1) {
typeOption.options[index] = option; typeOption.options[index] = option;
} }
@ -71,7 +74,8 @@ class SingleSelectTypeOptionContext extends TypeOptionWidgetContext<SingleSelect
} }
} }
class SingleSelectTypeOptionWidgetDataParser extends TypeOptionDataParser<SingleSelectTypeOptionPB> { class SingleSelectTypeOptionWidgetDataParser
extends TypeOptionDataParser<SingleSelectTypeOptionPB> {
@override @override
SingleSelectTypeOptionPB fromBuffer(List<int> buffer) { SingleSelectTypeOptionPB fromBuffer(List<int> buffer) {
return SingleSelectTypeOptionPB.fromBuffer(buffer); return SingleSelectTypeOptionPB.fromBuffer(buffer);

View File

@ -1,6 +1,6 @@
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:app_flowy/workspace/application/grid/field/field_service.dart'; import 'package:app_flowy/plugins/grid/application/field/field_service.dart';
import 'package:dartz/dartz.dart'; import 'package:dartz/dartz.dart';
import 'package:flowy_sdk/dispatch/dispatch.dart'; import 'package:flowy_sdk/dispatch/dispatch.dart';
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
@ -92,7 +92,9 @@ class TypeOptionContext2<T> {
return Future(() => left(_data!)); return Future(() => left(_data!));
} }
return _fieldService.getFieldTypeOptionData(fieldType: field.fieldType).then((result) { return _fieldService
.getFieldTypeOptionData(fieldType: field.fieldType)
.then((result) {
return result.fold( return result.fold(
(data) { (data) {
_data = dataBuilder.fromBuffer(data.typeOptionData); _data = dataBuilder.fromBuffer(data.typeOptionData);

View File

@ -1,4 +1,4 @@
import 'package:app_flowy/workspace/application/grid/field/field_service.dart'; import 'package:app_flowy/plugins/grid/application/field/field_service.dart';
import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/log.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_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
@ -33,7 +33,8 @@ class GridHeaderBloc extends Bloc<GridHeaderEvent, GridHeaderState> {
); );
} }
Future<void> _moveField(_MoveField value, Emitter<GridHeaderState> emit) async { Future<void> _moveField(
_MoveField value, Emitter<GridHeaderState> emit) async {
final fields = List<GridFieldPB>.from(state.fields); final fields = List<GridFieldPB>.from(state.fields);
fields.insert(value.toIndex, fields.removeAt(value.fromIndex)); fields.insert(value.toIndex, fields.removeAt(value.fromIndex));
emit(state.copyWith(fields: fields)); emit(state.copyWith(fields: fields));
@ -62,13 +63,16 @@ class GridHeaderBloc extends Bloc<GridHeaderEvent, GridHeaderState> {
@freezed @freezed
class GridHeaderEvent with _$GridHeaderEvent { class GridHeaderEvent with _$GridHeaderEvent {
const factory GridHeaderEvent.initial() = _InitialHeader; const factory GridHeaderEvent.initial() = _InitialHeader;
const factory GridHeaderEvent.didReceiveFieldUpdate(List<GridFieldPB> fields) = _DidReceiveFieldUpdate; const factory GridHeaderEvent.didReceiveFieldUpdate(
const factory GridHeaderEvent.moveField(GridFieldPB field, int fromIndex, int toIndex) = _MoveField; List<GridFieldPB> fields) = _DidReceiveFieldUpdate;
const factory GridHeaderEvent.moveField(
GridFieldPB field, int fromIndex, int toIndex) = _MoveField;
} }
@freezed @freezed
class GridHeaderState with _$GridHeaderState { class GridHeaderState with _$GridHeaderState {
const factory GridHeaderState({required List<GridFieldPB> fields}) = _GridHeaderState; const factory GridHeaderState({required List<GridFieldPB> fields}) =
_GridHeaderState;
factory GridHeaderState.initial(List<GridFieldPB> fields) { factory GridHeaderState.initial(List<GridFieldPB> fields) {
// final List<GridFieldPB> newFields = List.from(fields); // final List<GridFieldPB> newFields = List.from(fields);

View File

@ -1,6 +1,6 @@
import 'dart:collection'; import 'dart:collection';
import 'package:app_flowy/workspace/application/grid/field/grid_listenr.dart'; import 'package:app_flowy/plugins/grid/application/field/grid_listener.dart';
import 'package:dartz/dartz.dart'; import 'package:dartz/dartz.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/log.dart';
@ -26,13 +26,15 @@ class GridService {
return GridEventGetGrid(payload).send(); return GridEventGetGrid(payload).send();
} }
Future<Either<GridRowPB, FlowyError>> createRow({Option<String>? startRowId}) { Future<Either<GridRowPB, FlowyError>> createRow(
{Option<String>? startRowId}) {
CreateRowPayloadPB payload = CreateRowPayloadPB.create()..gridId = gridId; CreateRowPayloadPB payload = CreateRowPayloadPB.create()..gridId = gridId;
startRowId?.fold(() => null, (id) => payload.startRowId = id); startRowId?.fold(() => null, (id) => payload.startRowId = id);
return GridEventCreateRow(payload).send(); return GridEventCreateRow(payload).send();
} }
Future<Either<RepeatedGridFieldPB, FlowyError>> getFields({required List<GridFieldIdPB> fieldIds}) { Future<Either<RepeatedGridFieldPB, FlowyError>> getFields(
{required List<GridFieldIdPB> fieldIds}) {
final payload = QueryFieldPayloadPB.create() final payload = QueryFieldPayloadPB.create()
..gridId = gridId ..gridId = gridId
..fieldIds = RepeatedGridFieldIdPB(items: fieldIds); ..fieldIds = RepeatedGridFieldIdPB(items: fieldIds);
@ -64,9 +66,11 @@ class GridFieldCache {
final GridFieldsListener _fieldListener; final GridFieldsListener _fieldListener;
FieldsNotifier? _fieldNotifier = FieldsNotifier(); FieldsNotifier? _fieldNotifier = FieldsNotifier();
final Map<FieldsCallback, VoidCallback> _fieldsCallbackMap = {}; final Map<FieldsCallback, VoidCallback> _fieldsCallbackMap = {};
final Map<FieldChangesetCallback, FieldChangesetCallback> _changesetCallbackMap = {}; final Map<FieldChangesetCallback, FieldChangesetCallback>
_changesetCallbackMap = {};
GridFieldCache({required this.gridId}) : _fieldListener = GridFieldsListener(gridId: gridId) { GridFieldCache({required this.gridId})
: _fieldListener = GridFieldsListener(gridId: gridId) {
_fieldListener.start(onFieldsChanged: (result) { _fieldListener.start(onFieldsChanged: (result) {
result.fold( result.fold(
(changeset) { (changeset) {
@ -88,7 +92,8 @@ class GridFieldCache {
_fieldNotifier = null; _fieldNotifier = null;
} }
UnmodifiableListView<GridFieldPB> get unmodifiableFields => UnmodifiableListView(_fieldNotifier?.fields ?? []); UnmodifiableListView<GridFieldPB> get unmodifiableFields =>
UnmodifiableListView(_fieldNotifier?.fields ?? []);
List<GridFieldPB> get fields => [..._fieldNotifier?.fields ?? []]; List<GridFieldPB> get fields => [..._fieldNotifier?.fields ?? []];
@ -127,7 +132,7 @@ class GridFieldCache {
void removeListener({ void removeListener({
FieldsCallback? onFieldsListener, FieldsCallback? onFieldsListener,
FieldChangesetCallback? onChangsetListener, FieldChangesetCallback? onChangesetListener,
}) { }) {
if (onFieldsListener != null) { if (onFieldsListener != null) {
final fn = _fieldsCallbackMap.remove(onFieldsListener); final fn = _fieldsCallbackMap.remove(onFieldsListener);
@ -136,8 +141,8 @@ class GridFieldCache {
} }
} }
if (onChangsetListener != null) { if (onChangesetListener != null) {
_changesetCallbackMap.remove(onChangsetListener); _changesetCallbackMap.remove(onChangesetListener);
} }
} }
@ -175,7 +180,8 @@ class GridFieldCache {
} }
final List<GridFieldPB> newFields = fields; final List<GridFieldPB> newFields = fields;
for (final updatedField in updatedFields) { for (final updatedField in updatedFields) {
final index = newFields.indexWhere((field) => field.id == updatedField.id); final index =
newFields.indexWhere((field) => field.id == updatedField.id);
if (index != -1) { if (index != -1) {
newFields.removeAt(index); newFields.removeAt(index);
newFields.insert(index, updatedField); newFields.insert(index, updatedField);
@ -219,7 +225,7 @@ class GridRowCacheFieldNotifierImpl extends GridRowCacheFieldNotifier {
} }
if (_onChangesetFn != null) { if (_onChangesetFn != null) {
_cache.removeListener(onChangsetListener: _onChangesetFn!); _cache.removeListener(onChangesetListener: _onChangesetFn!);
_onChangesetFn = null; _onChangesetFn = null;
} }
} }

View File

@ -1,4 +1,4 @@
import 'package:app_flowy/workspace/application/grid/row/row_service.dart'; import 'package:app_flowy/plugins/grid/application/row/row_service.dart';
import 'package:flowy_sdk/log.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:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
@ -8,7 +8,8 @@ import 'package:dartz/dartz.dart';
part 'row_action_sheet_bloc.freezed.dart'; part 'row_action_sheet_bloc.freezed.dart';
class RowActionSheetBloc extends Bloc<RowActionSheetEvent, RowActionSheetState> { class RowActionSheetBloc
extends Bloc<RowActionSheetEvent, RowActionSheetState> {
final RowService _rowService; final RowService _rowService;
RowActionSheetBloc({required GridRowInfo rowData}) RowActionSheetBloc({required GridRowInfo rowData})
@ -56,7 +57,8 @@ class RowActionSheetState with _$RowActionSheetState {
required GridRowInfo rowData, required GridRowInfo rowData,
}) = _RowActionSheetState; }) = _RowActionSheetState;
factory RowActionSheetState.initial(GridRowInfo rowData) => RowActionSheetState( factory RowActionSheetState.initial(GridRowInfo rowData) =>
RowActionSheetState(
rowData: rowData, rowData: rowData,
); );
} }

View File

@ -1,5 +1,5 @@
import 'dart:collection'; import 'dart:collection';
import 'package:app_flowy/workspace/application/grid/cell/cell_service/cell_service.dart'; import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_service.dart';
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.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_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
@ -34,7 +34,9 @@ class RowBloc extends Bloc<RowEvent, RowState> {
_rowService.createRow(); _rowService.createRow();
}, },
didReceiveCellDatas: (_DidReceiveCellDatas value) async { didReceiveCellDatas: (_DidReceiveCellDatas value) async {
final fields = value.gridCellMap.values.map((e) => GridCellEquatable(e.field)).toList(); final fields = value.gridCellMap.values
.map((e) => GridCellEquatable(e.field))
.toList();
final snapshots = UnmodifiableListView(fields); final snapshots = UnmodifiableListView(fields);
emit(state.copyWith( emit(state.copyWith(
gridCellMap: value.gridCellMap, gridCellMap: value.gridCellMap,
@ -59,7 +61,8 @@ class RowBloc extends Bloc<RowEvent, RowState> {
Future<void> _startListening() async { Future<void> _startListening() async {
_rowListenFn = _rowCache.addListener( _rowListenFn = _rowCache.addListener(
rowId: state.rowInfo.id, rowId: state.rowInfo.id,
onCellUpdated: (cellDatas, reason) => add(RowEvent.didReceiveCellDatas(cellDatas, reason)), onCellUpdated: (cellDatas, reason) =>
add(RowEvent.didReceiveCellDatas(cellDatas, reason)),
listenWhen: () => !isClosed, listenWhen: () => !isClosed,
); );
} }
@ -69,7 +72,8 @@ class RowBloc extends Bloc<RowEvent, RowState> {
class RowEvent with _$RowEvent { class RowEvent with _$RowEvent {
const factory RowEvent.initial() = _InitialRow; const factory RowEvent.initial() = _InitialRow;
const factory RowEvent.createRow() = _CreateRow; const factory RowEvent.createRow() = _CreateRow;
const factory RowEvent.didReceiveCellDatas(GridCellMap gridCellMap, GridRowChangeReason reason) = const factory RowEvent.didReceiveCellDatas(
GridCellMap gridCellMap, GridRowChangeReason reason) =
_DidReceiveCellDatas; _DidReceiveCellDatas;
} }
@ -82,10 +86,12 @@ class RowState with _$RowState {
GridRowChangeReason? changeReason, GridRowChangeReason? changeReason,
}) = _RowState; }) = _RowState;
factory RowState.initial(GridRowInfo rowInfo, GridCellMap cellDataMap) => RowState( factory RowState.initial(GridRowInfo rowInfo, GridCellMap cellDataMap) =>
RowState(
rowInfo: rowInfo, rowInfo: rowInfo,
gridCellMap: cellDataMap, gridCellMap: cellDataMap,
snapshots: UnmodifiableListView(cellDataMap.values.map((e) => GridCellEquatable(e.field)).toList()), snapshots: UnmodifiableListView(
cellDataMap.values.map((e) => GridCellEquatable(e.field)).toList()),
); );
} }

View File

@ -1,4 +1,4 @@
import 'package:app_flowy/workspace/application/grid/cell/cell_service/cell_service.dart'; import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_service.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:freezed_annotation/freezed_annotation.dart';
import 'dart:async'; import 'dart:async';
@ -42,7 +42,8 @@ class RowDetailBloc extends Bloc<RowDetailEvent, RowDetailState> {
Future<void> _startListening() async { Future<void> _startListening() async {
_rowListenFn = _rowCache.addListener( _rowListenFn = _rowCache.addListener(
rowId: rowInfo.id, rowId: rowInfo.id,
onCellUpdated: (cellDatas, reason) => add(RowDetailEvent.didReceiveCellDatas(cellDatas.values.toList())), onCellUpdated: (cellDatas, reason) =>
add(RowDetailEvent.didReceiveCellDatas(cellDatas.values.toList())),
listenWhen: () => !isClosed, listenWhen: () => !isClosed,
); );
} }
@ -58,7 +59,8 @@ class RowDetailBloc extends Bloc<RowDetailEvent, RowDetailState> {
@freezed @freezed
class RowDetailEvent with _$RowDetailEvent { class RowDetailEvent with _$RowDetailEvent {
const factory RowDetailEvent.initial() = _Initial; const factory RowDetailEvent.initial() = _Initial;
const factory RowDetailEvent.didReceiveCellDatas(List<GridCellIdentifier> gridCells) = _DidReceiveCellDatas; const factory RowDetailEvent.didReceiveCellDatas(
List<GridCellIdentifier> gridCells) = _DidReceiveCellDatas;
} }
@freezed @freezed

View File

@ -1,5 +1,5 @@
import 'dart:collection'; import 'dart:collection';
import 'package:app_flowy/workspace/application/grid/cell/cell_service/cell_service.dart'; import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_service.dart';
import 'package:dartz/dartz.dart'; import 'package:dartz/dartz.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/log.dart';
@ -53,9 +53,12 @@ class GridRowCache {
_rowChangeReasonNotifier = _GridRowChangesetNotifier(), _rowChangeReasonNotifier = _GridRowChangesetNotifier(),
_fieldNotifier = notifier { _fieldNotifier = notifier {
// //
notifier.onFieldsChanged(() => _rowChangeReasonNotifier.receive(const GridRowChangeReason.fieldDidChange())); notifier.onFieldsChanged(() => _rowChangeReasonNotifier
.receive(const GridRowChangeReason.fieldDidChange()));
notifier.onFieldChanged((field) => _cellCache.remove(field.id)); notifier.onFieldChanged((field) => _cellCache.remove(field.id));
_rowInfos = block.rows.map((rowInfo) => buildGridRow(rowInfo.id, rowInfo.height.toDouble())).toList(); _rowInfos = block.rows
.map((rowInfo) => buildGridRow(rowInfo.id, rowInfo.height.toDouble()))
.toList();
} }
Future<void> dispose() async { Future<void> dispose() async {
@ -81,7 +84,9 @@ class GridRowCache {
final List<GridRowInfo> newRows = []; final List<GridRowInfo> newRows = [];
final DeletedIndexs deletedIndex = []; final DeletedIndexs deletedIndex = [];
final Map<String, String> deletedRowByRowId = {for (var rowId in deletedRows) rowId: rowId}; final Map<String, String> deletedRowByRowId = {
for (var rowId in deletedRows) rowId: rowId
};
_rowInfos.asMap().forEach((index, row) { _rowInfos.asMap().forEach((index, row) {
if (deletedRowByRowId[row.id] == null) { if (deletedRowByRowId[row.id] == null) {
@ -107,7 +112,8 @@ class GridRowCache {
rowId: insertRow.rowId, rowId: insertRow.rowId,
); );
insertIndexs.add(insertIndex); insertIndexs.add(insertIndex);
_rowInfos.insert(insertRow.index, (buildGridRow(insertRow.rowId, insertRow.height.toDouble()))); _rowInfos.insert(insertRow.index,
(buildGridRow(insertRow.rowId, insertRow.height.toDouble())));
} }
_rowChangeReasonNotifier.receive(GridRowChangeReason.insert(insertIndexs)); _rowChangeReasonNotifier.receive(GridRowChangeReason.insert(insertIndexs));
@ -126,7 +132,8 @@ class GridRowCache {
_rowByRowId[rowId] = updatedRow.row; _rowByRowId[rowId] = updatedRow.row;
_rowInfos.removeAt(index); _rowInfos.removeAt(index);
_rowInfos.insert(index, buildGridRow(rowId, updatedRow.row.height.toDouble())); _rowInfos.insert(
index, buildGridRow(rowId, updatedRow.row.height.toDouble()));
updatedIndexs[rowId] = UpdatedIndex(index: index, rowId: rowId); updatedIndexs[rowId] = UpdatedIndex(index: index, rowId: rowId);
} }
} }
@ -225,7 +232,8 @@ class GridRowCache {
updatedRow.freeze(); updatedRow.freeze();
_rowByRowId[updatedRow.id] = updatedRow; _rowByRowId[updatedRow.id] = updatedRow;
final index = _rowInfos.indexWhere((gridRow) => gridRow.id == updatedRow.id); final index =
_rowInfos.indexWhere((gridRow) => gridRow.id == updatedRow.id);
if (index != -1) { if (index != -1) {
// update the corresponding row in _rows if they are not the same // update the corresponding row in _rows if they are not the same
if (_rowInfos[index].rawRow != updatedRow) { if (_rowInfos[index].rawRow != updatedRow) {
@ -237,7 +245,8 @@ class GridRowCache {
updatedIndexs[row.id] = UpdatedIndex(index: index, rowId: row.id); updatedIndexs[row.id] = UpdatedIndex(index: index, rowId: row.id);
// //
_rowChangeReasonNotifier.receive(GridRowChangeReason.update(updatedIndexs)); _rowChangeReasonNotifier
.receive(GridRowChangeReason.update(updatedIndexs));
} }
} }
} }
@ -275,7 +284,8 @@ class RowService {
final String blockId; final String blockId;
final String rowId; final String rowId;
RowService({required this.gridId, required this.blockId, required this.rowId}); RowService(
{required this.gridId, required this.blockId, required this.rowId});
Future<Either<GridRowPB, FlowyError>> createRow() { Future<Either<GridRowPB, FlowyError>> createRow() {
CreateRowPayloadPB payload = CreateRowPayloadPB.create() CreateRowPayloadPB payload = CreateRowPayloadPB.create()
@ -285,7 +295,8 @@ class RowService {
return GridEventCreateRow(payload).send(); return GridEventCreateRow(payload).send();
} }
Future<Either<Unit, FlowyError>> moveRow(String rowId, int fromIndex, int toIndex) { Future<Either<Unit, FlowyError>> moveRow(
String rowId, int fromIndex, int toIndex) {
final payload = MoveItemPayloadPB.create() final payload = MoveItemPayloadPB.create()
..gridId = gridId ..gridId = gridId
..itemId = rowId ..itemId = rowId

View File

@ -1,5 +1,5 @@
import 'package:app_flowy/workspace/application/grid/field/field_service.dart'; import 'package:app_flowy/plugins/grid/application/field/field_service.dart';
import 'package:app_flowy/workspace/application/grid/grid_service.dart'; import 'package:app_flowy/plugins/grid/application/grid_service.dart';
import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/log.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_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
@ -22,8 +22,10 @@ class GridPropertyBloc extends Bloc<GridPropertyEvent, GridPropertyState> {
_startListening(); _startListening();
}, },
setFieldVisibility: (_SetFieldVisibility value) async { setFieldVisibility: (_SetFieldVisibility value) async {
final fieldService = FieldService(gridId: gridId, fieldId: value.fieldId); final fieldService =
final result = await fieldService.updateField(visibility: value.visibility); FieldService(gridId: gridId, fieldId: value.fieldId);
final result =
await fieldService.updateField(visibility: value.visibility);
result.fold( result.fold(
(l) => null, (l) => null,
(err) => Log.error(err), (err) => Log.error(err),
@ -50,7 +52,8 @@ class GridPropertyBloc extends Bloc<GridPropertyEvent, GridPropertyState> {
} }
void _startListening() { void _startListening() {
_onFieldsFn = (fields) => add(GridPropertyEvent.didReceiveFieldUpdate(fields)); _onFieldsFn =
(fields) => add(GridPropertyEvent.didReceiveFieldUpdate(fields));
_fieldCache.addListener( _fieldCache.addListener(
onFields: _onFieldsFn, onFields: _onFieldsFn,
listenWhen: () => !isClosed, listenWhen: () => !isClosed,
@ -61,9 +64,12 @@ class GridPropertyBloc extends Bloc<GridPropertyEvent, GridPropertyState> {
@freezed @freezed
class GridPropertyEvent with _$GridPropertyEvent { class GridPropertyEvent with _$GridPropertyEvent {
const factory GridPropertyEvent.initial() = _Initial; const factory GridPropertyEvent.initial() = _Initial;
const factory GridPropertyEvent.setFieldVisibility(String fieldId, bool visibility) = _SetFieldVisibility; const factory GridPropertyEvent.setFieldVisibility(
const factory GridPropertyEvent.didReceiveFieldUpdate(List<GridFieldPB> fields) = _DidReceiveFieldUpdate; String fieldId, bool visibility) = _SetFieldVisibility;
const factory GridPropertyEvent.moveField(int fromIndex, int toIndex) = _MoveField; const factory GridPropertyEvent.didReceiveFieldUpdate(
List<GridFieldPB> fields) = _DidReceiveFieldUpdate;
const factory GridPropertyEvent.moveField(int fromIndex, int toIndex) =
_MoveField;
} }
@freezed @freezed
@ -73,7 +79,8 @@ class GridPropertyState with _$GridPropertyState {
required List<GridFieldPB> fields, required List<GridFieldPB> fields,
}) = _GridPropertyState; }) = _GridPropertyState;
factory GridPropertyState.initial(String gridId, List<GridFieldPB> fields) => GridPropertyState( factory GridPropertyState.initial(String gridId, List<GridFieldPB> fields) =>
GridPropertyState(
gridId: gridId, gridId: gridId,
fields: fields, fields: fields,
); );

View File

@ -1,12 +1,12 @@
import 'package:app_flowy/generated/locale_keys.g.dart'; import 'package:app_flowy/generated/locale_keys.g.dart';
import 'package:app_flowy/plugin/plugin.dart'; import 'package:app_flowy/startup/plugin/plugin.dart';
import 'package:app_flowy/workspace/presentation/home/home_stack.dart'; import 'package:app_flowy/workspace/presentation/home/home_stack.dart';
import 'package:app_flowy/workspace/presentation/plugins/widgets/left_bar_item.dart'; import 'package:app_flowy/workspace/presentation/widgets/left_bar_item.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'src/grid_page.dart'; import 'presentation/grid_page.dart';
class GridPluginBuilder implements PluginBuilder { class GridPluginBuilder implements PluginBuilder {
@override @override

View File

@ -1,6 +1,6 @@
import 'package:app_flowy/startup/startup.dart'; import 'package:app_flowy/startup/startup.dart';
import 'package:app_flowy/workspace/application/grid/grid_bloc.dart'; import 'package:app_flowy/plugins/grid/application/grid_bloc.dart';
import 'package:app_flowy/workspace/application/grid/row/row_service.dart'; import 'package:app_flowy/plugins/grid/application/row/row_service.dart';
import 'package:flowy_infra/theme.dart'; import 'package:flowy_infra/theme.dart';
import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart'; import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart';
import 'package:flowy_infra_ui/style_widget/scrolling/styled_scroll_bar.dart'; import 'package:flowy_infra_ui/style_widget/scrolling/styled_scroll_bar.dart';
@ -35,13 +35,15 @@ class _GridPageState extends State<GridPage> {
return MultiBlocProvider( return MultiBlocProvider(
providers: [ providers: [
BlocProvider<GridBloc>( BlocProvider<GridBloc>(
create: (context) => getIt<GridBloc>(param1: widget.view)..add(const GridEvent.initial()), create: (context) => getIt<GridBloc>(param1: widget.view)
..add(const GridEvent.initial()),
), ),
], ],
child: BlocBuilder<GridBloc, GridState>( child: BlocBuilder<GridBloc, GridState>(
builder: (context, state) { builder: (context, state) {
return state.loadingState.map( return state.loadingState.map(
loading: (_) => const Center(child: CircularProgressIndicator.adaptive()), loading: (_) =>
const Center(child: CircularProgressIndicator.adaptive()),
finish: (result) => result.successOrFail.fold( finish: (result) => result.successOrFail.fold(
(_) => const GridShortcuts(child: FlowyGrid()), (_) => const GridShortcuts(child: FlowyGrid()),
(err) => FlowyErrorPage(err.toString()), (err) => FlowyErrorPage(err.toString()),
@ -76,7 +78,8 @@ class FlowyGrid extends StatefulWidget {
} }
class _FlowyGridState extends State<FlowyGrid> { class _FlowyGridState extends State<FlowyGrid> {
final _scrollController = GridScrollController(scrollGroupContorller: LinkedScrollControllerGroup()); final _scrollController = GridScrollController(
scrollGroupContorller: LinkedScrollControllerGroup());
late ScrollController headerScrollController; late ScrollController headerScrollController;
@override @override
@ -204,7 +207,8 @@ class _GridRowsState extends State<_GridRows> {
for (final item in value.items) { for (final item in value.items) {
_key.currentState?.removeItem( _key.currentState?.removeItem(
item.index, item.index,
(context, animation) => _renderRow(context, item.row, animation), (context, animation) =>
_renderRow(context, item.row, animation),
); );
} }
}, },
@ -215,8 +219,10 @@ class _GridRowsState extends State<_GridRows> {
return SliverAnimatedList( return SliverAnimatedList(
key: _key, key: _key,
initialItemCount: context.read<GridBloc>().state.rowInfos.length, initialItemCount: context.read<GridBloc>().state.rowInfos.length,
itemBuilder: (BuildContext context, int index, Animation<double> animation) { itemBuilder:
final GridRowInfo rowInfo = context.read<GridBloc>().state.rowInfos[index]; (BuildContext context, int index, Animation<double> animation) {
final GridRowInfo rowInfo =
context.read<GridBloc>().state.rowInfos[index];
return _renderRow(context, rowInfo, animation); return _renderRow(context, rowInfo, animation);
}, },
); );
@ -229,7 +235,8 @@ class _GridRowsState extends State<_GridRows> {
GridRowInfo rowInfo, GridRowInfo rowInfo,
Animation<double> animation, Animation<double> animation,
) { ) {
final rowCache = context.read<GridBloc>().getRowCache(rowInfo.blockId, rowInfo.id); final rowCache =
context.read<GridBloc>().getRowCache(rowInfo.blockId, rowInfo.id);
final fieldCache = context.read<GridBloc>().fieldCache; final fieldCache = context.read<GridBloc>().fieldCache;
if (rowCache != null) { if (rowCache != null) {
return SizeTransition( return SizeTransition(
@ -266,10 +273,10 @@ class _GridFooter extends StatelessWidget {
SizedBox(width: GridSize.leadingHeaderPadding), SizedBox(width: GridSize.leadingHeaderPadding),
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
const SizedBox(width: 120, child: GridAddRowButton()), const SizedBox(width: 120, child: GridAddRowButton()),
const SizedBox(height: 30), const SizedBox(height: 30),
_rowCountTextWidget(theme: theme,count: rowCount) _rowCountTextWidget(theme: theme, count: rowCount)
], ],
), ),
], ],
@ -280,16 +287,18 @@ class _GridFooter extends StatelessWidget {
); );
} }
Widget _rowCountTextWidget({required AppTheme theme, required int count}){ Widget _rowCountTextWidget({required AppTheme theme, required int count}) {
return Row( return Row(
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: [ children: [
FlowyText.regular('Count : ', FlowyText.regular(
fontSize: 13, 'Count : ',
color: theme.shader3, fontSize: 13,
color: theme.shader3,
), ),
FlowyText.regular(count.toString(), FlowyText.regular(
fontSize: 13, count.toString(),
fontSize: 13,
), ),
], ],
); );

View File

@ -1,5 +1,5 @@
import 'package:app_flowy/workspace/application/grid/cell/cell_service/cell_service.dart'; import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_service.dart';
import 'package:app_flowy/workspace/application/grid/grid_service.dart'; import 'package:app_flowy/plugins/grid/application/grid_service.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/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
@ -30,19 +30,36 @@ class GridCellBuilder {
final key = cell.key(); final key = cell.key();
switch (cell.fieldType) { switch (cell.fieldType) {
case FieldType.Checkbox: case FieldType.Checkbox:
return GridCheckboxCell(cellControllerBuilder: cellControllerBuilder, key: key); return GridCheckboxCell(
cellControllerBuilder: cellControllerBuilder, key: key);
case FieldType.DateTime: case FieldType.DateTime:
return GridDateCell(cellControllerBuilder: cellControllerBuilder, key: key, style: style); return GridDateCell(
cellControllerBuilder: cellControllerBuilder,
key: key,
style: style);
case FieldType.SingleSelect: case FieldType.SingleSelect:
return GridSingleSelectCell(cellContorllerBuilder: cellControllerBuilder, style: style, key: key); return GridSingleSelectCell(
cellContorllerBuilder: cellControllerBuilder,
style: style,
key: key);
case FieldType.MultiSelect: case FieldType.MultiSelect:
return GridMultiSelectCell(cellContorllerBuilder: cellControllerBuilder, style: style, key: key); return GridMultiSelectCell(
cellContorllerBuilder: cellControllerBuilder,
style: style,
key: key);
case FieldType.Number: case FieldType.Number:
return GridNumberCell(cellContorllerBuilder: cellControllerBuilder, key: key); return GridNumberCell(
cellContorllerBuilder: cellControllerBuilder, key: key);
case FieldType.RichText: case FieldType.RichText:
return GridTextCell(cellContorllerBuilder: cellControllerBuilder, style: style, key: key); return GridTextCell(
cellContorllerBuilder: cellControllerBuilder,
style: style,
key: key);
case FieldType.URL: case FieldType.URL:
return GridURLCell(cellContorllerBuilder: cellControllerBuilder, style: style, key: key); return GridURLCell(
cellContorllerBuilder: cellControllerBuilder,
style: style,
key: key);
} }
throw UnimplementedError; throw UnimplementedError;
} }
@ -65,7 +82,8 @@ abstract class CellEditable {
ValueNotifier<bool> get onCellEditing; ValueNotifier<bool> get onCellEditing;
} }
abstract class GridCellWidget extends StatefulWidget implements CellAccessory, CellEditable, CellShortcuts { abstract class GridCellWidget extends StatefulWidget
implements CellAccessory, CellEditable, CellShortcuts {
GridCellWidget({Key? key}) : super(key: key) { GridCellWidget({Key? key}) : super(key: key) {
onCellEditing.addListener(() { onCellEditing.addListener(() {
onCellFocus.value = onCellEditing.value; onCellFocus.value = onCellEditing.value;
@ -83,7 +101,8 @@ abstract class GridCellWidget extends StatefulWidget implements CellAccessory, C
final ValueNotifier<bool> onCellEditing = ValueNotifier<bool>(false); final ValueNotifier<bool> onCellEditing = ValueNotifier<bool>(false);
@override @override
List<GridCellAccessory> Function(GridCellAccessoryBuildContext buildContext)? get accessoryBuilder => null; List<GridCellAccessory> Function(GridCellAccessoryBuildContext buildContext)?
get accessoryBuilder => null;
@override @override
final GridCellFocusListener beginFocus = GridCellFocusListener(); final GridCellFocusListener beginFocus = GridCellFocusListener();
@ -129,12 +148,14 @@ abstract class GridCellState<T extends GridCellWidget> extends State<T> {
void onInsert(String value) {} void onInsert(String value) {}
} }
abstract class GridFocusNodeCellState<T extends GridCellWidget> extends GridCellState<T> { abstract class GridFocusNodeCellState<T extends GridCellWidget>
extends GridCellState<T> {
SingleListenrFocusNode focusNode = SingleListenrFocusNode(); SingleListenrFocusNode focusNode = SingleListenrFocusNode();
@override @override
void initState() { void initState() {
widget.shortcutHandlers[CellKeyboardKey.onEnter] = () => focusNode.unfocus(); widget.shortcutHandlers[CellKeyboardKey.onEnter] =
() => focusNode.unfocus();
_listenOnFocusNodeChanged(); _listenOnFocusNodeChanged();
super.initState(); super.initState();
} }

View File

@ -1,10 +1,10 @@
import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart';
import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/row/grid_row.dart';
import 'package:flowy_infra/theme.dart'; import 'package:flowy_infra/theme.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:styled_widget/styled_widget.dart'; import 'package:styled_widget/styled_widget.dart';
import '../../layout/sizes.dart';
import '../row/grid_row.dart';
import 'cell_accessory.dart'; import 'cell_accessory.dart';
import 'cell_builder.dart'; import 'cell_builder.dart';
import 'cell_shortcuts.dart'; import 'cell_shortcuts.dart';
@ -24,9 +24,11 @@ class CellContainer extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ChangeNotifierProxyProvider<RegionStateNotifier, CellContainerNotifier>( return ChangeNotifierProxyProvider<RegionStateNotifier,
CellContainerNotifier>(
create: (_) => CellContainerNotifier(child), create: (_) => CellContainerNotifier(child),
update: (_, rowStateNotifier, cellStateNotifier) => cellStateNotifier!..onEnter = rowStateNotifier.onEnter, update: (_, rowStateNotifier, cellStateNotifier) =>
cellStateNotifier!..onEnter = rowStateNotifier.onEnter,
child: Selector<CellContainerNotifier, bool>( child: Selector<CellContainerNotifier, bool>(
selector: (context, notifier) => notifier.isFocus, selector: (context, notifier) => notifier.isFocus,
builder: (context, isFocus, _) { builder: (context, isFocus, _) {
@ -39,7 +41,8 @@ class CellContainer extends StatelessWidget {
)); ));
if (accessories.isNotEmpty) { if (accessories.isNotEmpty) {
container = CellEnterRegion(child: container, accessories: accessories); container =
CellEnterRegion(child: container, accessories: accessories);
} }
} }
@ -65,7 +68,8 @@ class CellContainer extends StatelessWidget {
return BoxDecoration(border: Border.fromBorderSide(borderSide)); return BoxDecoration(border: Border.fromBorderSide(borderSide));
} else { } else {
final borderSide = BorderSide(color: theme.shader5, width: 1.0); final borderSide = BorderSide(color: theme.shader5, width: 1.0);
return BoxDecoration(border: Border(right: borderSide, bottom: borderSide)); return BoxDecoration(
border: Border(right: borderSide, bottom: borderSide));
} }
} }
} }
@ -73,7 +77,9 @@ class CellContainer extends StatelessWidget {
class CellEnterRegion extends StatelessWidget { class CellEnterRegion extends StatelessWidget {
final Widget child; final Widget child;
final List<GridCellAccessory> accessories; final List<GridCellAccessory> accessories;
const CellEnterRegion({required this.child, required this.accessories, Key? key}) : super(key: key); const CellEnterRegion(
{required this.child, required this.accessories, Key? key})
: super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -82,13 +88,18 @@ class CellEnterRegion extends StatelessWidget {
builder: (context, onEnter, _) { builder: (context, onEnter, _) {
List<Widget> children = [child]; List<Widget> children = [child];
if (onEnter) { if (onEnter) {
children.add(CellAccessoryContainer(accessories: accessories).positioned(right: 0)); children.add(CellAccessoryContainer(accessories: accessories)
.positioned(right: 0));
} }
return MouseRegion( return MouseRegion(
cursor: SystemMouseCursors.click, cursor: SystemMouseCursors.click,
onEnter: (p) => Provider.of<CellContainerNotifier>(context, listen: false).onEnter = true, onEnter: (p) =>
onExit: (p) => Provider.of<CellContainerNotifier>(context, listen: false).onEnter = false, Provider.of<CellContainerNotifier>(context, listen: false)
.onEnter = true,
onExit: (p) =>
Provider.of<CellContainerNotifier>(context, listen: false)
.onEnter = false,
child: Stack( child: Stack(
alignment: AlignmentDirectional.center, alignment: AlignmentDirectional.center,
fit: StackFit.expand, fit: StackFit.expand,
@ -102,7 +113,6 @@ class CellEnterRegion extends StatelessWidget {
class CellContainerNotifier extends ChangeNotifier { class CellContainerNotifier extends ChangeNotifier {
final CellEditable cellEditable; final CellEditable cellEditable;
bool mouted = false;
VoidCallback? _onCellFocusListener; VoidCallback? _onCellFocusListener;
bool _isFocus = false; bool _isFocus = false;
bool _onEnter = false; bool _onEnter = false;

View File

@ -1,5 +1,5 @@
import 'package:app_flowy/startup/startup.dart'; import 'package:app_flowy/startup/startup.dart';
import 'package:app_flowy/workspace/application/grid/prelude.dart'; import 'package:app_flowy/plugins/grid/application/prelude.dart';
import 'package:flowy_infra/image.dart'; import 'package:flowy_infra/image.dart';
import 'package:flowy_infra_ui/style_widget/icon_button.dart'; import 'package:flowy_infra_ui/style_widget/icon_button.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
@ -23,7 +23,8 @@ class _CheckboxCellState extends GridCellState<GridCheckboxCell> {
@override @override
void initState() { void initState() {
final cellContext = widget.cellControllerBuilder.build(); final cellContext = widget.cellControllerBuilder.build();
_cellBloc = getIt<CheckboxCellBloc>(param1: cellContext)..add(const CheckboxCellEvent.initial()); _cellBloc = getIt<CheckboxCellBloc>(param1: cellContext)
..add(const CheckboxCellEvent.initial());
super.initState(); super.initState();
} }
@ -33,11 +34,15 @@ class _CheckboxCellState extends GridCellState<GridCheckboxCell> {
value: _cellBloc, value: _cellBloc,
child: BlocBuilder<CheckboxCellBloc, CheckboxCellState>( child: BlocBuilder<CheckboxCellBloc, CheckboxCellState>(
builder: (context, state) { builder: (context, state) {
final icon = state.isSelected ? svgWidget('editor/editor_check') : svgWidget('editor/editor_uncheck'); final icon = state.isSelected
? svgWidget('editor/editor_check')
: svgWidget('editor/editor_uncheck');
return Align( return Align(
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
child: FlowyIconButton( child: FlowyIconButton(
onPressed: () => context.read<CheckboxCellBloc>().add(const CheckboxCellEvent.select()), onPressed: () => context
.read<CheckboxCellBloc>()
.add(const CheckboxCellEvent.select()),
iconPadding: EdgeInsets.zero, iconPadding: EdgeInsets.zero,
icon: icon, icon: icon,
width: 20, width: 20,

View File

@ -2,7 +2,7 @@ import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:app_flowy/startup/startup.dart'; import 'package:app_flowy/startup/startup.dart';
import 'package:app_flowy/workspace/application/grid/prelude.dart'; import 'package:app_flowy/plugins/grid/application/prelude.dart';
import '../cell_builder.dart'; import '../cell_builder.dart';
import 'date_editor.dart'; import 'date_editor.dart';
@ -44,13 +44,16 @@ class _DateCellState extends GridCellState<GridDateCell> {
@override @override
void initState() { void initState() {
final cellContext = widget.cellControllerBuilder.build(); final cellContext = widget.cellControllerBuilder.build();
_cellBloc = getIt<DateCellBloc>(param1: cellContext)..add(const DateCellEvent.initial()); _cellBloc = getIt<DateCellBloc>(param1: cellContext)
..add(const DateCellEvent.initial());
super.initState(); super.initState();
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final alignment = widget.cellStyle != null ? widget.cellStyle!.alignment : Alignment.center; final alignment = widget.cellStyle != null
? widget.cellStyle!.alignment
: Alignment.center;
return BlocProvider.value( return BlocProvider.value(
value: _cellBloc, value: _cellBloc,
child: BlocBuilder<DateCellBloc, DateCellState>( child: BlocBuilder<DateCellBloc, DateCellState>(
@ -77,7 +80,8 @@ class _DateCellState extends GridCellState<GridDateCell> {
void _showCalendar(BuildContext context) { void _showCalendar(BuildContext context) {
final bloc = context.read<DateCellBloc>(); final bloc = context.read<DateCellBloc>();
widget.onCellEditing.value = true; widget.onCellEditing.value = true;
final calendar = DateCellEditor(onDismissed: () => widget.onCellEditing.value = false); final calendar =
DateCellEditor(onDismissed: () => widget.onCellEditing.value = false);
calendar.show( calendar.show(
context, context,
cellController: bloc.cellContext.clone(), cellController: bloc.cellContext.clone(),

View File

@ -1,7 +1,5 @@
import 'package:app_flowy/generated/locale_keys.g.dart'; import 'package:app_flowy/generated/locale_keys.g.dart';
import 'package:app_flowy/workspace/application/grid/cell/date_cal_bloc.dart'; import 'package:app_flowy/plugins/grid/application/cell/date_cal_bloc.dart';
import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart';
import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/type_option/date.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/image.dart'; import 'package:flowy_infra/image.dart';
import 'package:flowy_infra/theme.dart'; import 'package:flowy_infra/theme.dart';
@ -15,7 +13,10 @@ import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:table_calendar/table_calendar.dart'; import 'package:table_calendar/table_calendar.dart';
import 'package:app_flowy/workspace/application/grid/prelude.dart'; import 'package:app_flowy/plugins/grid/application/prelude.dart';
import '../../../layout/sizes.dart';
import '../../header/type_option/date.dart';
final kToday = DateTime.now(); final kToday = DateTime.now();
final kFirstDay = DateTime(kToday.year, kToday.month - 3, kToday.day); final kFirstDay = DateTime(kToday.year, kToday.month - 3, kToday.day);
@ -35,7 +36,8 @@ class DateCellEditor with FlowyOverlayDelegate {
}) async { }) async {
DateCellEditor.remove(context); DateCellEditor.remove(context);
final result = await cellController.getFieldTypeOption(DateTypeOptionDataParser()); final result =
await cellController.getFieldTypeOption(DateTypeOptionDataParser());
result.fold( result.fold(
(dateTypeOption) { (dateTypeOption) {
final calendar = _CellCalendarWidget( final calendar = _CellCalendarWidget(
@ -167,7 +169,9 @@ class _CellCalendarWidget extends StatelessWidget {
}, },
onDaySelected: (selectedDay, focusedDay) { onDaySelected: (selectedDay, focusedDay) {
_CalDateTimeSetting.hide(context); _CalDateTimeSetting.hide(context);
context.read<DateCalBloc>().add(DateCalEvent.selectDay(selectedDay)); context
.read<DateCalBloc>()
.add(DateCalEvent.selectDay(selectedDay));
}, },
onFormatChanged: (format) { onFormatChanged: (format) {
_CalDateTimeSetting.hide(context); _CalDateTimeSetting.hide(context);
@ -175,7 +179,9 @@ class _CellCalendarWidget extends StatelessWidget {
}, },
onPageChanged: (focusedDay) { onPageChanged: (focusedDay) {
_CalDateTimeSetting.hide(context); _CalDateTimeSetting.hide(context);
context.read<DateCalBloc>().add(DateCalEvent.setFocusedDay(focusedDay)); context
.read<DateCalBloc>()
.add(DateCalEvent.setFocusedDay(focusedDay));
}, },
); );
}, },
@ -200,11 +206,14 @@ class _IncludeTimeButton extends StatelessWidget {
children: [ children: [
svgWidget("grid/clock", color: theme.iconColor), svgWidget("grid/clock", color: theme.iconColor),
const HSpace(4), const HSpace(4),
FlowyText.medium(LocaleKeys.grid_field_includeTime.tr(), fontSize: 14), FlowyText.medium(LocaleKeys.grid_field_includeTime.tr(),
fontSize: 14),
const Spacer(), const Spacer(),
Switch( Switch(
value: includeTime, value: includeTime,
onChanged: (newValue) => context.read<DateCalBloc>().add(DateCalEvent.setIncludeTime(newValue)), onChanged: (newValue) => context
.read<DateCalBloc>()
.add(DateCalEvent.setIncludeTime(newValue)),
), ),
], ],
), ),
@ -294,7 +303,9 @@ class _DateTypeOptionButton extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = context.watch<AppTheme>(); final theme = context.watch<AppTheme>();
final title = LocaleKeys.grid_field_dateFormat.tr() + " &" + LocaleKeys.grid_field_timeFormat.tr(); final title = LocaleKeys.grid_field_dateFormat.tr() +
" &" +
LocaleKeys.grid_field_timeFormat.tr();
return BlocSelector<DateCalBloc, DateCalState, DateTypeOption>( return BlocSelector<DateCalBloc, DateCalState, DateTypeOption>(
selector: (state) => state.dateTypeOption, selector: (state) => state.dateTypeOption,
builder: (context, dateTypeOption) { builder: (context, dateTypeOption) {
@ -321,7 +332,9 @@ class _DateTypeOptionButton extends StatelessWidget {
class _CalDateTimeSetting extends StatefulWidget { class _CalDateTimeSetting extends StatefulWidget {
final DateTypeOption dateTypeOption; final DateTypeOption dateTypeOption;
final Function(DateCalEvent) onEvent; final Function(DateCalEvent) onEvent;
const _CalDateTimeSetting({required this.dateTypeOption, required this.onEvent, Key? key}) : super(key: key); const _CalDateTimeSetting(
{required this.dateTypeOption, required this.onEvent, Key? key})
: super(key: key);
@override @override
State<_CalDateTimeSetting> createState() => _CalDateTimeSettingState(); State<_CalDateTimeSetting> createState() => _CalDateTimeSettingState();
@ -358,7 +371,8 @@ class _CalDateTimeSettingState extends State<_CalDateTimeSetting> {
DateFormatButton(onTap: () { DateFormatButton(onTap: () {
final list = DateFormatList( final list = DateFormatList(
selectedFormat: widget.dateTypeOption.dateFormat, selectedFormat: widget.dateTypeOption.dateFormat,
onSelected: (format) => widget.onEvent(DateCalEvent.setDateFormat(format)), onSelected: (format) =>
widget.onEvent(DateCalEvent.setDateFormat(format)),
); );
_showOverlay(context, list); _showOverlay(context, list);
}), }),
@ -367,7 +381,8 @@ class _CalDateTimeSettingState extends State<_CalDateTimeSetting> {
onTap: () { onTap: () {
final list = TimeFormatList( final list = TimeFormatList(
selectedFormat: widget.dateTypeOption.timeFormat, selectedFormat: widget.dateTypeOption.timeFormat,
onSelected: (format) => widget.onEvent(DateCalEvent.setTimeFormat(format)), onSelected: (format) =>
widget.onEvent(DateCalEvent.setTimeFormat(format)),
); );
_showOverlay(context, list); _showOverlay(context, list);
}, },

View File

@ -1,6 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'package:app_flowy/startup/startup.dart'; import 'package:app_flowy/startup/startup.dart';
import 'package:app_flowy/workspace/application/grid/prelude.dart'; import 'package:app_flowy/plugins/grid/application/prelude.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
@ -26,8 +26,10 @@ class _NumberCellState extends GridFocusNodeCellState<GridNumberCell> {
@override @override
void initState() { void initState() {
final cellContext = widget.cellContorllerBuilder.build(); final cellContext = widget.cellContorllerBuilder.build();
_cellBloc = getIt<NumberCellBloc>(param1: cellContext)..add(const NumberCellEvent.initial()); _cellBloc = getIt<NumberCellBloc>(param1: cellContext)
_controller = TextEditingController(text: contentFromState(_cellBloc.state)); ..add(const NumberCellEvent.initial());
_controller =
TextEditingController(text: contentFromState(_cellBloc.state));
super.initState(); super.initState();
} }
@ -39,7 +41,8 @@ class _NumberCellState extends GridFocusNodeCellState<GridNumberCell> {
listeners: [ listeners: [
BlocListener<NumberCellBloc, NumberCellState>( BlocListener<NumberCellBloc, NumberCellState>(
listenWhen: (p, c) => p.content != c.content, listenWhen: (p, c) => p.content != c.content,
listener: (context, state) => _controller.text = contentFromState(state), listener: (context, state) =>
_controller.text = contentFromState(state),
), ),
], ],
child: TextField( child: TextField(
@ -70,7 +73,8 @@ class _NumberCellState extends GridFocusNodeCellState<GridNumberCell> {
if (mounted) { if (mounted) {
_delayOperation?.cancel(); _delayOperation?.cancel();
_delayOperation = Timer(const Duration(milliseconds: 300), () { _delayOperation = Timer(const Duration(milliseconds: 300), () {
if (_cellBloc.isClosed == false && _controller.text != contentFromState(_cellBloc.state)) { if (_cellBloc.isClosed == false &&
_controller.text != contentFromState(_cellBloc.state)) {
_cellBloc.add(NumberCellEvent.updateCell(_controller.text)); _cellBloc.add(NumberCellEvent.updateCell(_controller.text));
} }
}); });

View File

@ -4,3 +4,4 @@ export 'number_cell.dart';
export 'date_cell/date_cell.dart'; export 'date_cell/date_cell.dart';
export 'checkbox_cell.dart'; export 'checkbox_cell.dart';
export 'select_option_cell/select_option_cell.dart'; export 'select_option_cell/select_option_cell.dart';
export 'url_cell/url_cell.dart';

View File

@ -1,6 +1,6 @@
import 'package:app_flowy/startup/startup.dart'; import 'package:app_flowy/startup/startup.dart';
import 'package:app_flowy/workspace/application/grid/prelude.dart'; import 'package:app_flowy/plugins/grid/application/prelude.dart';
import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/cell/cell_builder.dart';
import 'package:flowy_infra/theme.dart'; import 'package:flowy_infra/theme.dart';
import 'package:flowy_infra_ui/style_widget/text.dart'; import 'package:flowy_infra_ui/style_widget/text.dart';
// ignore: unused_import // ignore: unused_import
@ -9,6 +9,7 @@ import 'package:flowy_sdk/protobuf/flowy-grid/select_option.pb.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import '../cell_builder.dart';
import 'extension.dart'; import 'extension.dart';
import 'select_option_editor.dart'; import 'select_option_editor.dart';
@ -45,8 +46,10 @@ class _SingleSelectCellState extends State<GridSingleSelectCell> {
@override @override
void initState() { void initState() {
final cellContext = widget.cellContorllerBuilder.build() as GridSelectOptionCellController; final cellContext =
_cellBloc = getIt<SelectOptionCellBloc>(param1: cellContext)..add(const SelectOptionCellEvent.initial()); widget.cellContorllerBuilder.build() as GridSelectOptionCellController;
_cellBloc = getIt<SelectOptionCellBloc>(param1: cellContext)
..add(const SelectOptionCellEvent.initial());
super.initState(); super.initState();
} }
@ -99,8 +102,10 @@ class _MultiSelectCellState extends State<GridMultiSelectCell> {
@override @override
void initState() { void initState() {
final cellContext = widget.cellContorllerBuilder.build() as GridSelectOptionCellController; final cellContext =
_cellBloc = getIt<SelectOptionCellBloc>(param1: cellContext)..add(const SelectOptionCellEvent.initial()); widget.cellContorllerBuilder.build() as GridSelectOptionCellController;
_cellBloc = getIt<SelectOptionCellBloc>(param1: cellContext)
..add(const SelectOptionCellEvent.initial());
super.initState(); super.initState();
} }
@ -147,7 +152,8 @@ class _SelectOptionCell extends StatelessWidget {
if (selectOptions.isEmpty && cellStyle != null) { if (selectOptions.isEmpty && cellStyle != null) {
child = Align( child = Align(
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
child: FlowyText.medium(cellStyle!.placeholder, fontSize: 14, color: theme.shader3), child: FlowyText.medium(cellStyle!.placeholder,
fontSize: 14, color: theme.shader3),
); );
} else { } else {
final tags = selectOptions final tags = selectOptions
@ -172,8 +178,10 @@ class _SelectOptionCell extends StatelessWidget {
InkWell( InkWell(
onTap: () { onTap: () {
onFocus(true); onFocus(true);
final cellContext = cellContorllerBuilder.build() as GridSelectOptionCellController; final cellContext =
SelectOptionCellEditor.show(context, cellContext, () => onFocus(false)); cellContorllerBuilder.build() as GridSelectOptionCellController;
SelectOptionCellEditor.show(
context, cellContext, () => onFocus(false));
}, },
), ),
], ],

View File

@ -1,9 +1,7 @@
import 'dart:collection'; import 'dart:collection';
import 'package:app_flowy/workspace/application/grid/cell/cell_service/cell_service.dart'; import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_service.dart';
import 'package:app_flowy/workspace/application/grid/cell/select_option_editor_bloc.dart'; import 'package:app_flowy/plugins/grid/application/cell/select_option_editor_bloc.dart';
import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart';
import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/type_option/select_option_editor.dart';
import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/common/text_field.dart';
import 'package:flowy_infra/image.dart'; import 'package:flowy_infra/image.dart';
import 'package:flowy_infra/theme.dart'; import 'package:flowy_infra/theme.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart';
@ -18,6 +16,9 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:app_flowy/generated/locale_keys.g.dart'; import 'package:app_flowy/generated/locale_keys.g.dart';
import 'package:textfield_tags/textfield_tags.dart'; import 'package:textfield_tags/textfield_tags.dart';
import '../../../layout/sizes.dart';
import '../../common/text_field.dart';
import '../../header/type_option/select_option_editor.dart';
import 'extension.dart'; import 'extension.dart';
import 'text_field.dart'; import 'text_field.dart';
@ -105,7 +106,8 @@ class _OptionList extends StatelessWidget {
builder: (context, state) { builder: (context, state) {
List<Widget> cells = []; List<Widget> cells = [];
cells.addAll(state.options.map((option) { cells.addAll(state.options.map((option) {
return _SelectOptionCell(option, state.selectedOptions.contains(option)); return _SelectOptionCell(
option, state.selectedOptions.contains(option));
}).toList()); }).toList());
state.createOption.fold( state.createOption.fold(
@ -146,8 +148,10 @@ class _TextField extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocBuilder<SelectOptionCellEditorBloc, SelectOptionEditorState>( return BlocBuilder<SelectOptionCellEditorBloc, SelectOptionEditorState>(
builder: (context, state) { builder: (context, state) {
final optionMap = LinkedHashMap<String, SelectOptionPB>.fromIterable(state.selectedOptions, final optionMap = LinkedHashMap<String, SelectOptionPB>.fromIterable(
key: (option) => option.name, value: (option) => option); state.selectedOptions,
key: (option) => option.name,
value: (option) => option);
return SizedBox( return SizedBox(
height: 42, height: 42,
@ -156,12 +160,17 @@ class _TextField extends StatelessWidget {
selectedOptionMap: optionMap, selectedOptionMap: optionMap,
distanceToText: _editorPannelWidth * 0.7, distanceToText: _editorPannelWidth * 0.7,
tagController: _tagController, tagController: _tagController,
onClick: () => FlowyOverlay.of(context).remove(SelectOptionTypeOptionEditor.identifier), onClick: () => FlowyOverlay.of(context)
.remove(SelectOptionTypeOptionEditor.identifier),
newText: (text) { newText: (text) {
context.read<SelectOptionCellEditorBloc>().add(SelectOptionEditorEvent.filterOption(text)); context
.read<SelectOptionCellEditorBloc>()
.add(SelectOptionEditorEvent.filterOption(text));
}, },
onNewTag: (tagName) { onNewTag: (tagName) {
context.read<SelectOptionCellEditorBloc>().add(SelectOptionEditorEvent.newOption(tagName)); context
.read<SelectOptionCellEditorBloc>()
.add(SelectOptionEditorEvent.newOption(tagName));
}, },
), ),
); );
@ -208,7 +217,9 @@ class _CreateOptionCell extends StatelessWidget {
SelectOptionTag( SelectOptionTag(
name: name, name: name,
color: theme.shader6, color: theme.shader6,
onSelected: () => context.read<SelectOptionCellEditorBloc>().add(SelectOptionEditorEvent.newOption(name)), onSelected: () => context
.read<SelectOptionCellEditorBloc>()
.add(SelectOptionEditorEvent.newOption(name)),
), ),
], ],
); );
@ -218,7 +229,8 @@ class _CreateOptionCell extends StatelessWidget {
class _SelectOptionCell extends StatelessWidget { class _SelectOptionCell extends StatelessWidget {
final SelectOptionPB option; final SelectOptionPB option;
final bool isSelected; final bool isSelected;
const _SelectOptionCell(this.option, this.isSelected, {Key? key}) : super(key: key); const _SelectOptionCell(this.option, this.isSelected, {Key? key})
: super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -232,7 +244,9 @@ class _SelectOptionCell extends StatelessWidget {
child: SelectOptionTagCell( child: SelectOptionTagCell(
option: option, option: option,
onSelected: (option) { onSelected: (option) {
context.read<SelectOptionCellEditorBloc>().add(SelectOptionEditorEvent.selectOption(option.id)); context
.read<SelectOptionCellEditorBloc>()
.add(SelectOptionEditorEvent.selectOption(option.id));
}, },
children: [ children: [
if (isSelected) if (isSelected)
@ -258,12 +272,17 @@ class _SelectOptionCell extends StatelessWidget {
final pannel = SelectOptionTypeOptionEditor( final pannel = SelectOptionTypeOptionEditor(
option: option, option: option,
onDeleted: () { onDeleted: () {
context.read<SelectOptionCellEditorBloc>().add(SelectOptionEditorEvent.deleteOption(option)); context
.read<SelectOptionCellEditorBloc>()
.add(SelectOptionEditorEvent.deleteOption(option));
}, },
onUpdated: (updatedOption) { onUpdated: (updatedOption) {
context.read<SelectOptionCellEditorBloc>().add(SelectOptionEditorEvent.updateOption(updatedOption)); context
.read<SelectOptionCellEditorBloc>()
.add(SelectOptionEditorEvent.updateOption(updatedOption));
}, },
key: ValueKey(option.id), // Use ValueKey to refresh the UI, otherwise, it will remain the old value. key: ValueKey(option
.id), // Use ValueKey to refresh the UI, otherwise, it will remain the old value.
); );
final overlayIdentifier = (SelectOptionTypeOptionEditor).toString(); final overlayIdentifier = (SelectOptionTypeOptionEditor).toString();

View File

@ -2,7 +2,7 @@ import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:app_flowy/startup/startup.dart'; import 'package:app_flowy/startup/startup.dart';
import 'package:app_flowy/workspace/application/grid/prelude.dart'; import 'package:app_flowy/plugins/grid/application/prelude.dart';
import 'cell_builder.dart'; import 'cell_builder.dart';
class GridTextCellStyle extends GridCellStyle { class GridTextCellStyle extends GridCellStyle {
@ -86,7 +86,8 @@ class _GridTextCellState extends GridFocusNodeCellState<GridTextCell> {
if (mounted) { if (mounted) {
_delayOperation?.cancel(); _delayOperation?.cancel();
_delayOperation = Timer(const Duration(milliseconds: 300), () { _delayOperation = Timer(const Duration(milliseconds: 300), () {
if (_cellBloc.isClosed == false && _controller.text != _cellBloc.state.content) { if (_cellBloc.isClosed == false &&
_controller.text != _cellBloc.state.content) {
_cellBloc.add(TextCellEvent.updateText(_controller.text)); _cellBloc.add(TextCellEvent.updateText(_controller.text));
} }
}); });

View File

@ -1,5 +1,5 @@
import 'package:app_flowy/workspace/application/grid/cell/cell_service/cell_service.dart'; import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_service.dart';
import 'package:app_flowy/workspace/application/grid/cell/url_cell_editor_bloc.dart'; import 'package:app_flowy/plugins/grid/application/cell/url_cell_editor_bloc.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'dart:async'; import 'dart:async';
@ -9,7 +9,9 @@ import 'package:flutter_bloc/flutter_bloc.dart';
class URLCellEditor extends StatefulWidget with FlowyOverlayDelegate { class URLCellEditor extends StatefulWidget with FlowyOverlayDelegate {
final GridURLCellController cellController; final GridURLCellController cellController;
final VoidCallback completed; final VoidCallback completed;
const URLCellEditor({required this.cellController, required this.completed, Key? key}) : super(key: key); const URLCellEditor(
{required this.cellController, required this.completed, Key? key})
: super(key: key);
@override @override
State<URLCellEditor> createState() => _URLCellEditorState(); State<URLCellEditor> createState() => _URLCellEditorState();
@ -105,7 +107,8 @@ class _URLCellEditorState extends State<URLCellEditor> {
Future<void> focusChanged() async { Future<void> focusChanged() async {
if (mounted) { if (mounted) {
if (_cellBloc.isClosed == false && _controller.text != _cellBloc.state.content) { if (_cellBloc.isClosed == false &&
_controller.text != _cellBloc.state.content) {
_cellBloc.add(URLCellEditorEvent.updateText(_controller.text)); _cellBloc.add(URLCellEditorEvent.updateText(_controller.text));
} }
} }

View File

@ -1,16 +1,16 @@
import 'dart:async'; import 'dart:async';
import 'package:app_flowy/generated/locale_keys.g.dart'; import 'package:app_flowy/generated/locale_keys.g.dart';
import 'package:app_flowy/workspace/application/grid/cell/url_cell_bloc.dart'; import 'package:app_flowy/plugins/grid/application/cell/url_cell_bloc.dart';
import 'package:app_flowy/workspace/presentation/home/toast.dart'; import 'package:app_flowy/workspace/presentation/home/toast.dart';
import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/cell/cell_accessory.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/image.dart'; import 'package:flowy_infra/image.dart';
import 'package:flowy_infra/theme.dart'; import 'package:flowy_infra/theme.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:app_flowy/workspace/application/grid/prelude.dart'; import 'package:app_flowy/plugins/grid/application/prelude.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
import '../cell_accessory.dart';
import '../cell_builder.dart'; import '../cell_builder.dart';
import 'cell_editor.dart'; import 'cell_editor.dart';
@ -48,34 +48,41 @@ class GridURLCell extends GridCellWidget {
@override @override
GridCellState<GridURLCell> createState() => _GridURLCellState(); GridCellState<GridURLCell> createState() => _GridURLCellState();
GridCellAccessory accessoryFromType(GridURLCellAccessoryType ty, GridCellAccessoryBuildContext buildContext) { GridCellAccessory accessoryFromType(
GridURLCellAccessoryType ty, GridCellAccessoryBuildContext buildContext) {
switch (ty) { switch (ty) {
case GridURLCellAccessoryType.edit: case GridURLCellAccessoryType.edit:
final cellContext = cellContorllerBuilder.build() as GridURLCellController; final cellContext =
return _EditURLAccessory(cellContext: cellContext, anchorContext: buildContext.anchorContext); cellContorllerBuilder.build() as GridURLCellController;
return _EditURLAccessory(
cellContext: cellContext,
anchorContext: buildContext.anchorContext);
case GridURLCellAccessoryType.copyURL: case GridURLCellAccessoryType.copyURL:
final cellContext = cellContorllerBuilder.build() as GridURLCellController; final cellContext =
cellContorllerBuilder.build() as GridURLCellController;
return _CopyURLAccessory(cellContext: cellContext); return _CopyURLAccessory(cellContext: cellContext);
} }
} }
@override @override
List<GridCellAccessory> Function(GridCellAccessoryBuildContext buildContext) get accessoryBuilder => (buildContext) { List<GridCellAccessory> Function(GridCellAccessoryBuildContext buildContext)
final List<GridCellAccessory> accessories = []; get accessoryBuilder => (buildContext) {
if (cellStyle != null) { final List<GridCellAccessory> accessories = [];
accessories.addAll(cellStyle!.accessoryTypes.map((ty) { if (cellStyle != null) {
return accessoryFromType(ty, buildContext); accessories.addAll(cellStyle!.accessoryTypes.map((ty) {
})); return accessoryFromType(ty, buildContext);
} }));
}
// If the accessories is empty then the default accessory will be GridURLCellAccessoryType.edit // If the accessories is empty then the default accessory will be GridURLCellAccessoryType.edit
if (accessories.isEmpty) { if (accessories.isEmpty) {
accessories.add(accessoryFromType(GridURLCellAccessoryType.edit, buildContext)); accessories.add(accessoryFromType(
} GridURLCellAccessoryType.edit, buildContext));
}
return accessories; return accessories;
}; };
} }
class _GridURLCellState extends GridCellState<GridURLCell> { class _GridURLCellState extends GridCellState<GridURLCell> {
@ -83,7 +90,8 @@ class _GridURLCellState extends GridCellState<GridURLCell> {
@override @override
void initState() { void initState() {
final cellContext = widget.cellContorllerBuilder.build() as GridURLCellController; final cellContext =
widget.cellContorllerBuilder.build() as GridURLCellController;
_cellBloc = URLCellBloc(cellContext: cellContext); _cellBloc = URLCellBloc(cellContext: cellContext);
_cellBloc.add(const URLCellEvent.initial()); _cellBloc.add(const URLCellEvent.initial());
super.initState(); super.initState();
@ -132,7 +140,8 @@ class _GridURLCellState extends GridCellState<GridURLCell> {
if (url.isNotEmpty && await canLaunchUrl(uri)) { if (url.isNotEmpty && await canLaunchUrl(uri)) {
await launchUrl(uri); await launchUrl(uri);
} else { } else {
final cellContext = widget.cellContorllerBuilder.build() as GridURLCellController; final cellContext =
widget.cellContorllerBuilder.build() as GridURLCellController;
widget.onCellEditing.value = true; widget.onCellEditing.value = true;
URLCellEditor.show(context, cellContext, () { URLCellEditor.show(context, cellContext, () {
widget.onCellEditing.value = false; widget.onCellEditing.value = false;
@ -177,7 +186,8 @@ class _EditURLAccessory extends StatelessWidget with GridCellAccessory {
class _CopyURLAccessory extends StatelessWidget with GridCellAccessory { class _CopyURLAccessory extends StatelessWidget with GridCellAccessory {
final GridURLCellController cellContext; final GridURLCellController cellContext;
const _CopyURLAccessory({required this.cellContext, Key? key}) : super(key: key); const _CopyURLAccessory({required this.cellContext, Key? key})
: super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -187,7 +197,8 @@ class _CopyURLAccessory extends StatelessWidget with GridCellAccessory {
@override @override
void onTap() { void onTap() {
final content = cellContext.getCellData(loadIfNotExist: false)?.content ?? ""; final content =
cellContext.getCellData(loadIfNotExist: false)?.content ?? "";
Clipboard.setData(ClipboardData(text: content)); Clipboard.setData(ClipboardData(text: content));
showMessageToast(LocaleKeys.grid_row_copyProperty.tr()); showMessageToast(LocaleKeys.grid_row_copyProperty.tr());
} }

View File

@ -1,4 +1,4 @@
import 'package:app_flowy/workspace/application/grid/grid_bloc.dart'; import 'package:app_flowy/plugins/grid/application/grid_bloc.dart';
import 'package:flowy_infra/image.dart'; import 'package:flowy_infra/image.dart';
import 'package:flowy_infra/theme.dart'; import 'package:flowy_infra/theme.dart';
import 'package:flowy_infra_ui/style_widget/button.dart'; import 'package:flowy_infra_ui/style_widget/button.dart';

View File

@ -1,6 +1,5 @@
import 'package:app_flowy/workspace/application/grid/field/field_cell_bloc.dart'; import 'package:app_flowy/plugins/grid/application/field/field_cell_bloc.dart';
import 'package:app_flowy/workspace/application/grid/field/field_service.dart'; import 'package:app_flowy/plugins/grid/application/field/field_service.dart';
import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart';
import 'package:flowy_infra/image.dart'; import 'package:flowy_infra/image.dart';
import 'package:flowy_infra/theme.dart'; import 'package:flowy_infra/theme.dart';
import 'package:flowy_infra_ui/style_widget/button.dart'; import 'package:flowy_infra_ui/style_widget/button.dart';
@ -9,6 +8,7 @@ import 'package:flowy_infra_ui/style_widget/text.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 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import '../../layout/sizes.dart';
import 'field_type_extension.dart'; import 'field_type_extension.dart';
import 'field_cell_action_sheet.dart'; import 'field_cell_action_sheet.dart';
@ -21,7 +21,8 @@ class GridFieldCell extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider( return BlocProvider(
create: (context) => FieldCellBloc(cellContext: cellContext)..add(const FieldCellEvent.initial()), create: (context) => FieldCellBloc(cellContext: cellContext)
..add(const FieldCellEvent.initial()),
child: BlocBuilder<FieldCellBloc, FieldCellState>( child: BlocBuilder<FieldCellBloc, FieldCellState>(
// buildWhen: (p, c) => p.field != c.field, // buildWhen: (p, c) => p.field != c.field,
builder: (context, state) { builder: (context, state) {
@ -53,7 +54,8 @@ class GridFieldCell extends StatelessWidget {
void _showActionSheet(BuildContext context) { void _showActionSheet(BuildContext context) {
final state = context.read<FieldCellBloc>().state; final state = context.read<FieldCellBloc>().state;
GridFieldCellActionSheet( GridFieldCellActionSheet(
cellContext: GridFieldCellContext(gridId: state.gridId, field: state.field), cellContext:
GridFieldCellContext(gridId: state.gridId, field: state.field),
onEdited: () => _showFieldEditor(context), onEdited: () => _showFieldEditor(context),
).show(context); ).show(context);
} }
@ -96,7 +98,8 @@ class _GridHeaderCellContainer extends StatelessWidget {
return Container( return Container(
width: width, width: width,
decoration: decoration, decoration: decoration,
child: ConstrainedBox(constraints: const BoxConstraints.expand(), child: child), child: ConstrainedBox(
constraints: const BoxConstraints.expand(), child: child),
); );
} }
} }

View File

@ -1,6 +1,5 @@
import 'package:app_flowy/startup/startup.dart'; import 'package:app_flowy/startup/startup.dart';
import 'package:app_flowy/workspace/application/grid/prelude.dart'; import 'package:app_flowy/plugins/grid/application/prelude.dart';
import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart';
import 'package:flowy_infra/image.dart'; import 'package:flowy_infra/image.dart';
import 'package:flowy_infra/theme.dart'; import 'package:flowy_infra/theme.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart';
@ -12,10 +11,15 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:app_flowy/generated/locale_keys.g.dart'; import 'package:app_flowy/generated/locale_keys.g.dart';
class GridFieldCellActionSheet extends StatelessWidget with FlowyOverlayDelegate { import '../../layout/sizes.dart';
class GridFieldCellActionSheet extends StatelessWidget
with FlowyOverlayDelegate {
final GridFieldCellContext cellContext; final GridFieldCellContext cellContext;
final VoidCallback onEdited; final VoidCallback onEdited;
const GridFieldCellActionSheet({required this.cellContext, required this.onEdited, Key? key}) : super(key: key); const GridFieldCellActionSheet(
{required this.cellContext, required this.onEdited, Key? key})
: super(key: key);
void show(BuildContext overlayContext) { void show(BuildContext overlayContext) {
FlowyOverlay.of(overlayContext).insertWithAnchor( FlowyOverlay.of(overlayContext).insertWithAnchor(
@ -44,7 +48,8 @@ class GridFieldCellActionSheet extends StatelessWidget with FlowyOverlayDelegate
}, },
), ),
const VSpace(6), const VSpace(6),
_FieldOperationList(cellContext, () => FlowyOverlay.of(context).remove(identifier())), _FieldOperationList(cellContext,
() => FlowyOverlay.of(context).remove(identifier())),
], ],
), ),
), ),
@ -73,7 +78,8 @@ class _EditFieldButton extends StatelessWidget {
return SizedBox( return SizedBox(
height: GridSize.typeOptionItemHeight, height: GridSize.typeOptionItemHeight,
child: FlowyButton( child: FlowyButton(
text: FlowyText.medium(LocaleKeys.grid_field_editProperty.tr(), fontSize: 12), text: FlowyText.medium(LocaleKeys.grid_field_editProperty.tr(),
fontSize: 12),
hoverColor: theme.hover, hoverColor: theme.hover,
onTap: onEdited, onTap: onEdited,
), ),
@ -86,7 +92,8 @@ class _EditFieldButton extends StatelessWidget {
class _FieldOperationList extends StatelessWidget { class _FieldOperationList extends StatelessWidget {
final GridFieldCellContext fieldData; final GridFieldCellContext fieldData;
final VoidCallback onDismissed; final VoidCallback onDismissed;
const _FieldOperationList(this.fieldData, this.onDismissed, {Key? key}) : super(key: key); const _FieldOperationList(this.fieldData, this.onDismissed, {Key? key})
: super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -143,7 +150,8 @@ class FieldActionCell extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = context.watch<AppTheme>(); final theme = context.watch<AppTheme>();
return FlowyButton( return FlowyButton(
text: FlowyText.medium(action.title(), fontSize: 12, color: enable ? null : theme.shader4), text: FlowyText.medium(action.title(),
fontSize: 12, color: enable ? null : theme.shader4),
hoverColor: theme.hover, hoverColor: theme.hover,
onTap: () { onTap: () {
if (enable) { if (enable) {
@ -188,13 +196,19 @@ extension _FieldActionExtension on FieldAction {
void run(BuildContext context) { void run(BuildContext context) {
switch (this) { switch (this) {
case FieldAction.hide: case FieldAction.hide:
context.read<FieldActionSheetBloc>().add(const FieldActionSheetEvent.hideField()); context
.read<FieldActionSheetBloc>()
.add(const FieldActionSheetEvent.hideField());
break; break;
case FieldAction.duplicate: case FieldAction.duplicate:
context.read<FieldActionSheetBloc>().add(const FieldActionSheetEvent.duplicateField()); context
.read<FieldActionSheetBloc>()
.add(const FieldActionSheetEvent.duplicateField());
break; break;
case FieldAction.delete: case FieldAction.delete:
context.read<FieldActionSheetBloc>().add(const FieldActionSheetEvent.deleteField()); context
.read<FieldActionSheetBloc>()
.add(const FieldActionSheetEvent.deleteField());
break; break;
} }
} }

View File

@ -1,5 +1,5 @@
import 'package:app_flowy/workspace/application/grid/field/field_editor_bloc.dart'; import 'package:app_flowy/plugins/grid/application/field/field_editor_bloc.dart';
import 'package:app_flowy/workspace/application/grid/field/field_service.dart'; import 'package:app_flowy/plugins/grid/application/field/field_service.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/style_widget/text.dart'; import 'package:flowy_infra_ui/style_widget/text.dart';
@ -36,7 +36,8 @@ class FieldEditor extends StatelessWidget with FlowyOverlayDelegate {
return ListView( return ListView(
shrinkWrap: true, shrinkWrap: true,
children: [ children: [
FlowyText.medium(LocaleKeys.grid_field_editProperty.tr(), fontSize: 12), FlowyText.medium(LocaleKeys.grid_field_editProperty.tr(),
fontSize: 12),
const VSpace(10), const VSpace(10),
const _FieldNameCell(), const _FieldNameCell(),
const VSpace(10), const VSpace(10),
@ -85,7 +86,8 @@ class _FieldTypeOptionCell extends StatelessWidget {
return state.field.fold( return state.field.fold(
() => const SizedBox(), () => const SizedBox(),
(fieldContext) { (fieldContext) {
final dataController = context.read<FieldEditorBloc>().dataController; final dataController =
context.read<FieldEditorBloc>().dataController;
return FieldTypeOptionEditor(dataController: dataController); return FieldTypeOptionEditor(dataController: dataController);
}, },
); );
@ -105,7 +107,9 @@ class _FieldNameCell extends StatelessWidget {
name: state.name, name: state.name,
errorText: context.read<FieldEditorBloc>().state.errorText, errorText: context.read<FieldEditorBloc>().state.errorText,
onNameChanged: (newName) { onNameChanged: (newName) {
context.read<FieldEditorBloc>().add(FieldEditorEvent.updateName(newName)); context
.read<FieldEditorBloc>()
.add(FieldEditorEvent.updateName(newName));
}, },
); );
}, },

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