mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2025-04-24 22:57:12 -04:00
Merge pull request #440 from AppFlowy-IO/fix_grid_ui_bugs
Fix grid UI bugs
This commit is contained in:
commit
1e997ccaad
18 changed files with 199 additions and 117 deletions
|
@ -0,0 +1,66 @@
|
||||||
|
import 'package:app_flowy/workspace/application/grid/field/field_listener.dart';
|
||||||
|
import 'package:app_flowy/workspace/application/grid/field/field_service.dart';
|
||||||
|
import 'package:flowy_sdk/log.dart';
|
||||||
|
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show Field;
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
part 'field_cell_bloc.freezed.dart';
|
||||||
|
|
||||||
|
class FieldCellBloc extends Bloc<FieldCellEvent, FieldCellState> {
|
||||||
|
final FieldListener _fieldListener;
|
||||||
|
|
||||||
|
FieldCellBloc({
|
||||||
|
required GridFieldCellContext cellContext,
|
||||||
|
}) : _fieldListener = FieldListener(fieldId: cellContext.field.id),
|
||||||
|
super(FieldCellState.initial(cellContext)) {
|
||||||
|
on<FieldCellEvent>(
|
||||||
|
(event, emit) async {
|
||||||
|
await event.map(
|
||||||
|
initial: (_InitialCell value) async {
|
||||||
|
_startListening();
|
||||||
|
},
|
||||||
|
didReceiveFieldUpdate: (_DidReceiveFieldUpdate value) {
|
||||||
|
emit(state.copyWith(field: value.field));
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> close() async {
|
||||||
|
await _fieldListener.stop();
|
||||||
|
return super.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _startListening() {
|
||||||
|
_fieldListener.updateFieldNotifier.addPublishListener((result) {
|
||||||
|
result.fold(
|
||||||
|
(field) => add(FieldCellEvent.didReceiveFieldUpdate(field)),
|
||||||
|
(err) => Log.error(err),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
_fieldListener.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
class FieldCellEvent with _$FieldCellEvent {
|
||||||
|
const factory FieldCellEvent.initial() = _InitialCell;
|
||||||
|
const factory FieldCellEvent.didReceiveFieldUpdate(Field field) = _DidReceiveFieldUpdate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
class FieldCellState with _$FieldCellState {
|
||||||
|
const factory FieldCellState({
|
||||||
|
required String gridId,
|
||||||
|
required Field field,
|
||||||
|
}) = _FieldCellState;
|
||||||
|
|
||||||
|
factory FieldCellState.initial(GridFieldCellContext cellContext) => FieldCellState(
|
||||||
|
gridId: cellContext.gridId,
|
||||||
|
field: cellContext.field,
|
||||||
|
);
|
||||||
|
}
|
|
@ -4,11 +4,11 @@ import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'package:protobuf/protobuf.dart';
|
import 'package:protobuf/protobuf.dart';
|
||||||
import 'package:dartz/dartz.dart';
|
import 'package:dartz/dartz.dart';
|
||||||
part 'edit_option_bloc.freezed.dart';
|
part 'edit_select_option_bloc.freezed.dart';
|
||||||
|
|
||||||
class EditOptionBloc extends Bloc<EditOptionEvent, EditOptionState> {
|
class EditSelectOptionBloc extends Bloc<EditSelectOptionEvent, EditSelectOptionState> {
|
||||||
EditOptionBloc({required SelectOption option}) : super(EditOptionState.initial(option)) {
|
EditSelectOptionBloc({required SelectOption option}) : super(EditSelectOptionState.initial(option)) {
|
||||||
on<EditOptionEvent>(
|
on<EditSelectOptionEvent>(
|
||||||
(event, emit) async {
|
(event, emit) async {
|
||||||
event.map(
|
event.map(
|
||||||
updateName: (_UpdateName value) {
|
updateName: (_UpdateName value) {
|
||||||
|
@ -46,20 +46,20 @@ class EditOptionBloc extends Bloc<EditOptionEvent, EditOptionState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@freezed
|
@freezed
|
||||||
class EditOptionEvent with _$EditOptionEvent {
|
class EditSelectOptionEvent with _$EditSelectOptionEvent {
|
||||||
const factory EditOptionEvent.updateName(String name) = _UpdateName;
|
const factory EditSelectOptionEvent.updateName(String name) = _UpdateName;
|
||||||
const factory EditOptionEvent.updateColor(SelectOptionColor color) = _UpdateColor;
|
const factory EditSelectOptionEvent.updateColor(SelectOptionColor color) = _UpdateColor;
|
||||||
const factory EditOptionEvent.delete() = _Delete;
|
const factory EditSelectOptionEvent.delete() = _Delete;
|
||||||
}
|
}
|
||||||
|
|
||||||
@freezed
|
@freezed
|
||||||
class EditOptionState with _$EditOptionState {
|
class EditSelectOptionState with _$EditSelectOptionState {
|
||||||
const factory EditOptionState({
|
const factory EditSelectOptionState({
|
||||||
required SelectOption option,
|
required SelectOption option,
|
||||||
required Option<bool> deleted,
|
required Option<bool> deleted,
|
||||||
}) = _EditOptionState;
|
}) = _EditSelectOptionState;
|
||||||
|
|
||||||
factory EditOptionState.initial(SelectOption option) => EditOptionState(
|
factory EditSelectOptionState.initial(SelectOption option) => EditSelectOptionState(
|
||||||
option: option,
|
option: option,
|
||||||
deleted: none(),
|
deleted: none(),
|
||||||
);
|
);
|
|
@ -3,11 +3,11 @@ 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';
|
||||||
import 'package:dartz/dartz.dart';
|
import 'package:dartz/dartz.dart';
|
||||||
part 'option_pannel_bloc.freezed.dart';
|
part 'field_option_pannel_bloc.freezed.dart';
|
||||||
|
|
||||||
class OptionPannelBloc extends Bloc<OptionPannelEvent, OptionPannelState> {
|
class FieldOptionPannelBloc extends Bloc<FieldOptionPannelEvent, FieldOptionPannelState> {
|
||||||
OptionPannelBloc({required List<SelectOption> options}) : super(OptionPannelState.initial(options)) {
|
FieldOptionPannelBloc({required List<SelectOption> options}) : super(FieldOptionPannelState.initial(options)) {
|
||||||
on<OptionPannelEvent>(
|
on<FieldOptionPannelEvent>(
|
||||||
(event, emit) async {
|
(event, emit) async {
|
||||||
await event.map(
|
await event.map(
|
||||||
createOption: (_CreateOption value) async {
|
createOption: (_CreateOption value) async {
|
||||||
|
@ -37,25 +37,25 @@ class OptionPannelBloc extends Bloc<OptionPannelEvent, OptionPannelState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@freezed
|
@freezed
|
||||||
class OptionPannelEvent with _$OptionPannelEvent {
|
class FieldOptionPannelEvent with _$FieldOptionPannelEvent {
|
||||||
const factory OptionPannelEvent.createOption(String optionName) = _CreateOption;
|
const factory FieldOptionPannelEvent.createOption(String optionName) = _CreateOption;
|
||||||
const factory OptionPannelEvent.beginAddingOption() = _BeginAddingOption;
|
const factory FieldOptionPannelEvent.beginAddingOption() = _BeginAddingOption;
|
||||||
const factory OptionPannelEvent.endAddingOption() = _EndAddingOption;
|
const factory FieldOptionPannelEvent.endAddingOption() = _EndAddingOption;
|
||||||
const factory OptionPannelEvent.updateOption(SelectOption option) = _UpdateOption;
|
const factory FieldOptionPannelEvent.updateOption(SelectOption option) = _UpdateOption;
|
||||||
const factory OptionPannelEvent.deleteOption(SelectOption option) = _DeleteOption;
|
const factory FieldOptionPannelEvent.deleteOption(SelectOption option) = _DeleteOption;
|
||||||
}
|
}
|
||||||
|
|
||||||
@freezed
|
@freezed
|
||||||
class OptionPannelState with _$OptionPannelState {
|
class FieldOptionPannelState with _$FieldOptionPannelState {
|
||||||
const factory OptionPannelState({
|
const factory FieldOptionPannelState({
|
||||||
required List<SelectOption> options,
|
required List<SelectOption> options,
|
||||||
required bool isEditingOption,
|
required bool isEditingOption,
|
||||||
required Option<String> newOptionName,
|
required Option<String> newOptionName,
|
||||||
required Option<SelectOption> updateOption,
|
required Option<SelectOption> updateOption,
|
||||||
required Option<SelectOption> deleteOption,
|
required Option<SelectOption> deleteOption,
|
||||||
}) = _OptionPannelState;
|
}) = _FieldOptionPannelState;
|
||||||
|
|
||||||
factory OptionPannelState.initial(List<SelectOption> options) => OptionPannelState(
|
factory FieldOptionPannelState.initial(List<SelectOption> options) => FieldOptionPannelState(
|
||||||
options: options,
|
options: options,
|
||||||
isEditingOption: false,
|
isEditingOption: false,
|
||||||
newOptionName: none(),
|
newOptionName: none(),
|
|
@ -37,7 +37,7 @@ class _SingleSelectCellState extends State<SingleSelectCell> {
|
||||||
return SizedBox.expand(
|
return SizedBox.expand(
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
SelectOptionEditor.show(context, state.cellData, state.options, state.selectedOptions);
|
SelectOptionCellEditor.show(context, state.cellData, state.options, state.selectedOptions);
|
||||||
},
|
},
|
||||||
child: Row(children: children),
|
child: Row(children: children),
|
||||||
),
|
),
|
||||||
|
@ -86,7 +86,7 @@ class _MultiSelectCellState extends State<MultiSelectCell> {
|
||||||
return SizedBox.expand(
|
return SizedBox.expand(
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
SelectOptionEditor.show(context, state.cellData, state.options, state.selectedOptions);
|
SelectOptionCellEditor.show(context, state.cellData, state.options, state.selectedOptions);
|
||||||
},
|
},
|
||||||
child: Row(children: children),
|
child: Row(children: children),
|
||||||
),
|
),
|
||||||
|
|
|
@ -18,19 +18,18 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
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';
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
|
||||||
import 'package:textfield_tags/textfield_tags.dart';
|
import 'package:textfield_tags/textfield_tags.dart';
|
||||||
|
|
||||||
import 'extension.dart';
|
import 'extension.dart';
|
||||||
|
|
||||||
const double _editorPannelWidth = 300;
|
const double _editorPannelWidth = 300;
|
||||||
|
|
||||||
class SelectOptionEditor extends StatelessWidget with FlowyOverlayDelegate {
|
class SelectOptionCellEditor extends StatelessWidget with FlowyOverlayDelegate {
|
||||||
final CellData cellData;
|
final CellData cellData;
|
||||||
final List<SelectOption> options;
|
final List<SelectOption> options;
|
||||||
final List<SelectOption> selectedOptions;
|
final List<SelectOption> selectedOptions;
|
||||||
|
|
||||||
const SelectOptionEditor({
|
const SelectOptionCellEditor({
|
||||||
required this.cellData,
|
required this.cellData,
|
||||||
required this.options,
|
required this.options,
|
||||||
required this.selectedOptions,
|
required this.selectedOptions,
|
||||||
|
@ -38,7 +37,7 @@ class SelectOptionEditor extends StatelessWidget with FlowyOverlayDelegate {
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
static String identifier() {
|
static String identifier() {
|
||||||
return (SelectOptionEditor).toString();
|
return (SelectOptionCellEditor).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -73,8 +72,8 @@ class SelectOptionEditor extends StatelessWidget with FlowyOverlayDelegate {
|
||||||
List<SelectOption> options,
|
List<SelectOption> options,
|
||||||
List<SelectOption> selectedOptions,
|
List<SelectOption> selectedOptions,
|
||||||
) {
|
) {
|
||||||
SelectOptionEditor.hide(context);
|
SelectOptionCellEditor.remove(context);
|
||||||
final editor = SelectOptionEditor(
|
final editor = SelectOptionCellEditor(
|
||||||
cellData: cellData,
|
cellData: cellData,
|
||||||
options: options,
|
options: options,
|
||||||
selectedOptions: selectedOptions,
|
selectedOptions: selectedOptions,
|
||||||
|
@ -86,14 +85,14 @@ class SelectOptionEditor extends StatelessWidget with FlowyOverlayDelegate {
|
||||||
child: SizedBox(width: _editorPannelWidth, child: editor),
|
child: SizedBox(width: _editorPannelWidth, child: editor),
|
||||||
constraints: BoxConstraints.loose(const Size(_editorPannelWidth, 300)),
|
constraints: BoxConstraints.loose(const Size(_editorPannelWidth, 300)),
|
||||||
),
|
),
|
||||||
identifier: SelectOptionEditor.identifier(),
|
identifier: SelectOptionCellEditor.identifier(),
|
||||||
anchorContext: context,
|
anchorContext: context,
|
||||||
anchorDirection: AnchorDirection.bottomWithCenterAligned,
|
anchorDirection: AnchorDirection.bottomWithCenterAligned,
|
||||||
delegate: editor,
|
delegate: editor,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hide(BuildContext context) {
|
static void remove(BuildContext context) {
|
||||||
FlowyOverlay.of(context).remove(identifier());
|
FlowyOverlay.of(context).remove(identifier());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,7 +207,7 @@ class _SelectOptionCell extends StatelessWidget {
|
||||||
if (onHover) {
|
if (onHover) {
|
||||||
children.add(FlowyIconButton(
|
children.add(FlowyIconButton(
|
||||||
width: 30,
|
width: 30,
|
||||||
onPressed: () => _showEditOptionPannel(context),
|
onPressed: () => _showEditPannel(context),
|
||||||
iconPadding: const EdgeInsets.fromLTRB(4, 4, 4, 4),
|
iconPadding: const EdgeInsets.fromLTRB(4, 4, 4, 4),
|
||||||
icon: svgWidget("editor/details", color: theme.iconColor),
|
icon: svgWidget("editor/details", color: theme.iconColor),
|
||||||
));
|
));
|
||||||
|
@ -224,7 +223,7 @@ class _SelectOptionCell extends StatelessWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _showEditOptionPannel(BuildContext context) {
|
void _showEditPannel(BuildContext context) {
|
||||||
final pannel = EditSelectOptionPannel(
|
final pannel = EditSelectOptionPannel(
|
||||||
option: option,
|
option: option,
|
||||||
onDeleted: () {
|
onDeleted: () {
|
||||||
|
@ -233,9 +232,9 @@ class _SelectOptionCell extends StatelessWidget {
|
||||||
onUpdated: (updatedOption) {
|
onUpdated: (updatedOption) {
|
||||||
context.read<SelectOptionEditorBloc>().add(SelectOptionEditorEvent.updateOption(updatedOption));
|
context.read<SelectOptionEditorBloc>().add(SelectOptionEditorEvent.updateOption(updatedOption));
|
||||||
},
|
},
|
||||||
// key: ValueKey(option.id),
|
key: ValueKey(option.id), // Use ValueKey to refresh the UI, otherwise, it will remain the old value.
|
||||||
);
|
);
|
||||||
final overlayIdentifier = pannel.toString();
|
final overlayIdentifier = (EditSelectOptionPannel).toString();
|
||||||
|
|
||||||
FlowyOverlay.of(context).remove(overlayIdentifier);
|
FlowyOverlay.of(context).remove(overlayIdentifier);
|
||||||
FlowyOverlay.of(context).insertWithAnchor(
|
FlowyOverlay.of(context).insertWithAnchor(
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import 'package:app_flowy/workspace/application/grid/field/field_cell_bloc.dart';
|
||||||
import 'package:app_flowy/workspace/application/grid/field/field_service.dart';
|
import 'package:app_flowy/workspace/application/grid/field/field_service.dart';
|
||||||
import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.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';
|
||||||
|
@ -12,46 +13,55 @@ import 'field_cell_action_sheet.dart';
|
||||||
import 'field_editor.dart';
|
import 'field_editor.dart';
|
||||||
|
|
||||||
class GridFieldCell extends StatelessWidget {
|
class GridFieldCell extends StatelessWidget {
|
||||||
final GridFieldCellContext fieldCellContext;
|
final GridFieldCellContext cellContext;
|
||||||
const GridFieldCell(this.fieldCellContext, {Key? key}) : super(key: key);
|
const GridFieldCell(this.cellContext, {Key? key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final theme = context.watch<AppTheme>();
|
final theme = context.watch<AppTheme>();
|
||||||
final field = fieldCellContext.field;
|
|
||||||
|
|
||||||
final button = FlowyButton(
|
return BlocProvider(
|
||||||
hoverColor: theme.hover,
|
create: (context) => FieldCellBloc(cellContext: cellContext)..add(const FieldCellEvent.initial()),
|
||||||
onTap: () => _showActionSheet(context),
|
child: BlocBuilder<FieldCellBloc, FieldCellState>(
|
||||||
rightIcon: svgWidget("editor/details", color: theme.iconColor),
|
builder: (context, state) {
|
||||||
leftIcon: svgWidget(field.fieldType.iconName(), color: theme.iconColor),
|
final button = FlowyButton(
|
||||||
text: FlowyText.medium(field.name, fontSize: 12),
|
hoverColor: theme.hover,
|
||||||
padding: GridSize.cellContentInsets,
|
onTap: () => _showActionSheet(context),
|
||||||
);
|
rightIcon: svgWidget("editor/details", color: theme.iconColor),
|
||||||
|
leftIcon: svgWidget(state.field.fieldType.iconName(), color: theme.iconColor),
|
||||||
|
text: FlowyText.medium(state.field.name, fontSize: 12),
|
||||||
|
padding: GridSize.cellContentInsets,
|
||||||
|
);
|
||||||
|
|
||||||
final borderSide = BorderSide(color: theme.shader4, width: 0.4);
|
final borderSide = BorderSide(color: theme.shader4, width: 0.4);
|
||||||
final decoration = BoxDecoration(border: Border(top: borderSide, right: borderSide, bottom: borderSide));
|
final decoration = BoxDecoration(border: Border(top: borderSide, right: borderSide, bottom: borderSide));
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
width: field.width.toDouble(),
|
width: state.field.width.toDouble(),
|
||||||
decoration: decoration,
|
decoration: decoration,
|
||||||
child: button,
|
child: button,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _showActionSheet(BuildContext context) {
|
void _showActionSheet(BuildContext context) {
|
||||||
|
final state = context.read<FieldCellBloc>().state;
|
||||||
GridFieldCellActionSheet(
|
GridFieldCellActionSheet(
|
||||||
fieldCellContext: fieldCellContext,
|
cellContext: GridFieldCellContext(gridId: state.gridId, field: state.field),
|
||||||
onEdited: () => _showFieldEditor(context),
|
onEdited: () => _showFieldEditor(context),
|
||||||
).show(context);
|
).show(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _showFieldEditor(BuildContext context) {
|
void _showFieldEditor(BuildContext context) {
|
||||||
|
final state = context.read<FieldCellBloc>().state;
|
||||||
|
|
||||||
FieldEditor(
|
FieldEditor(
|
||||||
gridId: fieldCellContext.gridId,
|
gridId: state.gridId,
|
||||||
fieldContextLoader: FieldContextLoaderAdaptor(
|
fieldContextLoader: FieldContextLoaderAdaptor(
|
||||||
gridId: fieldCellContext.gridId,
|
gridId: state.gridId,
|
||||||
field: fieldCellContext.field,
|
field: state.field,
|
||||||
),
|
),
|
||||||
).show(context);
|
).show(context);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,9 +13,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';
|
||||||
|
|
||||||
class GridFieldCellActionSheet extends StatelessWidget with FlowyOverlayDelegate {
|
class GridFieldCellActionSheet extends StatelessWidget with FlowyOverlayDelegate {
|
||||||
final GridFieldCellContext fieldCellContext;
|
final GridFieldCellContext cellContext;
|
||||||
final VoidCallback onEdited;
|
final VoidCallback onEdited;
|
||||||
const GridFieldCellActionSheet({required this.fieldCellContext, 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(
|
||||||
|
@ -33,7 +33,7 @@ class GridFieldCellActionSheet extends StatelessWidget with FlowyOverlayDelegate
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (context) => getIt<FieldActionSheetBloc>(param1: fieldCellContext),
|
create: (context) => getIt<FieldActionSheetBloc>(param1: cellContext),
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
|
@ -44,15 +44,15 @@ class GridFieldCellActionSheet extends StatelessWidget with FlowyOverlayDelegate
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
const VSpace(6),
|
const VSpace(6),
|
||||||
_FieldOperationList(fieldCellContext, () => FlowyOverlay.of(context).remove(identifier())),
|
_FieldOperationList(cellContext, () => FlowyOverlay.of(context).remove(identifier())),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
String identifier() {
|
static String identifier() {
|
||||||
return toString();
|
return (GridFieldCellActionSheet).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
@ -41,8 +41,8 @@ class FieldEditor extends FlowyOverlayDelegate {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
String identifier() {
|
static String identifier() {
|
||||||
return toString();
|
return (FieldEditor).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
@ -58,7 +58,7 @@ class _GridHeaderDelegate extends SliverPersistentHeaderDelegate {
|
||||||
@override
|
@override
|
||||||
bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) {
|
bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) {
|
||||||
if (oldDelegate is _GridHeaderDelegate) {
|
if (oldDelegate is _GridHeaderDelegate) {
|
||||||
return fields != oldDelegate.fields;
|
return fields.length != oldDelegate.fields.length;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,7 +114,7 @@ class DateFormatList extends StatelessWidget {
|
||||||
dateFormat: format,
|
dateFormat: format,
|
||||||
onSelected: (format) {
|
onSelected: (format) {
|
||||||
onSelected(format);
|
onSelected(format);
|
||||||
FlowyOverlay.of(context).remove(identifier());
|
FlowyOverlay.of(context).remove(DateFormatList.identifier());
|
||||||
},
|
},
|
||||||
isSelected: selectedFormat == format);
|
isSelected: selectedFormat == format);
|
||||||
}).toList();
|
}).toList();
|
||||||
|
@ -135,8 +135,8 @@ class DateFormatList extends StatelessWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
String identifier() {
|
static String identifier() {
|
||||||
return toString();
|
return (DateFormatList).toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,7 +205,7 @@ class TimeFormatList extends StatelessWidget {
|
||||||
timeFormat: format,
|
timeFormat: format,
|
||||||
onSelected: (format) {
|
onSelected: (format) {
|
||||||
onSelected(format);
|
onSelected(format);
|
||||||
FlowyOverlay.of(context).remove(identifier());
|
FlowyOverlay.of(context).remove(TimeFormatList.identifier());
|
||||||
});
|
});
|
||||||
}).toList();
|
}).toList();
|
||||||
|
|
||||||
|
@ -225,8 +225,8 @@ class TimeFormatList extends StatelessWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
String identifier() {
|
static String identifier() {
|
||||||
return toString();
|
return (TimeFormatList).toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import 'package:app_flowy/workspace/application/grid/field/type_option/edit_option_bloc.dart';
|
import 'package:app_flowy/workspace/application/grid/field/type_option/edit_select_option_bloc.dart';
|
||||||
import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart';
|
import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart';
|
||||||
import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/extension.dart';
|
import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/extension.dart';
|
||||||
import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/type_option/widget.dart';
|
import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/type_option/widget.dart';
|
||||||
|
@ -28,23 +28,23 @@ class EditSelectOptionPannel extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (context) => EditOptionBloc(option: option),
|
create: (context) => EditSelectOptionBloc(option: option),
|
||||||
child: MultiBlocListener(
|
child: MultiBlocListener(
|
||||||
listeners: [
|
listeners: [
|
||||||
BlocListener<EditOptionBloc, EditOptionState>(
|
BlocListener<EditSelectOptionBloc, EditSelectOptionState>(
|
||||||
listenWhen: (p, c) => p.deleted != c.deleted,
|
listenWhen: (p, c) => p.deleted != c.deleted,
|
||||||
listener: (context, state) {
|
listener: (context, state) {
|
||||||
state.deleted.fold(() => null, (_) => onDeleted());
|
state.deleted.fold(() => null, (_) => onDeleted());
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
BlocListener<EditOptionBloc, EditOptionState>(
|
BlocListener<EditSelectOptionBloc, EditSelectOptionState>(
|
||||||
listenWhen: (p, c) => p.option != c.option,
|
listenWhen: (p, c) => p.option != c.option,
|
||||||
listener: (context, state) {
|
listener: (context, state) {
|
||||||
onUpdated(state.option);
|
onUpdated(state.option);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
child: BlocBuilder<EditOptionBloc, EditOptionState>(
|
child: BlocBuilder<EditSelectOptionBloc, EditSelectOptionState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
List<Widget> slivers = [
|
List<Widget> slivers = [
|
||||||
SliverToBoxAdapter(child: _OptionNameTextField(state.option.name)),
|
SliverToBoxAdapter(child: _OptionNameTextField(state.option.name)),
|
||||||
|
@ -82,7 +82,7 @@ class _DeleteTag extends StatelessWidget {
|
||||||
hoverColor: theme.hover,
|
hoverColor: theme.hover,
|
||||||
leftIcon: svgWidget("grid/delete", color: theme.iconColor),
|
leftIcon: svgWidget("grid/delete", color: theme.iconColor),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
context.read<EditOptionBloc>().add(const EditOptionEvent.delete());
|
context.read<EditSelectOptionBloc>().add(const EditSelectOptionEvent.delete());
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -99,7 +99,9 @@ class _OptionNameTextField extends StatelessWidget {
|
||||||
name: name,
|
name: name,
|
||||||
onCanceled: () {},
|
onCanceled: () {},
|
||||||
onDone: (optionName) {
|
onDone: (optionName) {
|
||||||
context.read<EditOptionBloc>().add(EditOptionEvent.updateName(optionName));
|
if (name != optionName) {
|
||||||
|
context.read<EditSelectOptionBloc>().add(EditSelectOptionEvent.updateName(optionName));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -178,7 +180,7 @@ class _SelectOptionColorCell extends StatelessWidget {
|
||||||
leftIcon: colorIcon,
|
leftIcon: colorIcon,
|
||||||
rightIcon: checkmark,
|
rightIcon: checkmark,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
context.read<EditOptionBloc>().add(EditOptionEvent.updateColor(color));
|
context.read<EditSelectOptionBloc>().add(EditSelectOptionEvent.updateColor(color));
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import 'package:app_flowy/workspace/application/grid/field/type_option/option_pannel_bloc.dart';
|
import 'package:app_flowy/workspace/application/grid/field/type_option/field_option_pannel_bloc.dart';
|
||||||
import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart';
|
import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart';
|
||||||
import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_switcher.dart';
|
import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_switcher.dart';
|
||||||
import 'package:flowy_infra/image.dart';
|
import 'package:flowy_infra/image.dart';
|
||||||
|
@ -15,7 +15,7 @@ import 'package:app_flowy/generated/locale_keys.g.dart';
|
||||||
import 'edit_option_pannel.dart';
|
import 'edit_option_pannel.dart';
|
||||||
import 'widget.dart';
|
import 'widget.dart';
|
||||||
|
|
||||||
class OptionPannel extends StatelessWidget {
|
class FieldSelectOptionPannel extends StatelessWidget {
|
||||||
final List<SelectOption> options;
|
final List<SelectOption> options;
|
||||||
final VoidCallback beginEdit;
|
final VoidCallback beginEdit;
|
||||||
final Function(String optionName) createOptionCallback;
|
final Function(String optionName) createOptionCallback;
|
||||||
|
@ -23,7 +23,7 @@ class OptionPannel extends StatelessWidget {
|
||||||
final Function(SelectOption) deleteOptionCallback;
|
final Function(SelectOption) deleteOptionCallback;
|
||||||
final TypeOptionOverlayDelegate overlayDelegate;
|
final TypeOptionOverlayDelegate overlayDelegate;
|
||||||
|
|
||||||
const OptionPannel({
|
const FieldSelectOptionPannel({
|
||||||
required this.options,
|
required this.options,
|
||||||
required this.beginEdit,
|
required this.beginEdit,
|
||||||
required this.createOptionCallback,
|
required this.createOptionCallback,
|
||||||
|
@ -36,8 +36,8 @@ class OptionPannel extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (context) => OptionPannelBloc(options: options),
|
create: (context) => FieldOptionPannelBloc(options: options),
|
||||||
child: BlocConsumer<OptionPannelBloc, OptionPannelState>(
|
child: BlocConsumer<FieldOptionPannelBloc, FieldOptionPannelState>(
|
||||||
listener: (context, state) {
|
listener: (context, state) {
|
||||||
if (state.isEditingOption) {
|
if (state.isEditingOption) {
|
||||||
beginEdit();
|
beginEdit();
|
||||||
|
@ -88,7 +88,7 @@ class OptionTitle extends StatelessWidget {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final theme = context.watch<AppTheme>();
|
final theme = context.watch<AppTheme>();
|
||||||
|
|
||||||
return BlocBuilder<OptionPannelBloc, OptionPannelState>(
|
return BlocBuilder<FieldOptionPannelBloc, FieldOptionPannelState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
List<Widget> children = [FlowyText.medium(LocaleKeys.grid_field_optionTitle.tr(), fontSize: 12)];
|
List<Widget> children = [FlowyText.medium(LocaleKeys.grid_field_optionTitle.tr(), fontSize: 12)];
|
||||||
if (state.options.isNotEmpty) {
|
if (state.options.isNotEmpty) {
|
||||||
|
@ -105,7 +105,7 @@ class OptionTitle extends StatelessWidget {
|
||||||
),
|
),
|
||||||
hoverColor: theme.hover,
|
hoverColor: theme.hover,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
context.read<OptionPannelBloc>().add(const OptionPannelEvent.beginAddingOption());
|
context.read<FieldOptionPannelBloc>().add(const FieldOptionPannelEvent.beginAddingOption());
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -127,7 +127,7 @@ class _OptionList extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocBuilder<OptionPannelBloc, OptionPannelState>(
|
return BlocBuilder<FieldOptionPannelBloc, FieldOptionPannelState>(
|
||||||
buildWhen: (previous, current) {
|
buildWhen: (previous, current) {
|
||||||
return previous.options != current.options;
|
return previous.options != current.options;
|
||||||
},
|
},
|
||||||
|
@ -159,12 +159,13 @@ class _OptionList extends StatelessWidget {
|
||||||
option: option,
|
option: option,
|
||||||
onDeleted: () {
|
onDeleted: () {
|
||||||
delegate.hideOverlay(context);
|
delegate.hideOverlay(context);
|
||||||
context.read<OptionPannelBloc>().add(OptionPannelEvent.deleteOption(option));
|
context.read<FieldOptionPannelBloc>().add(FieldOptionPannelEvent.deleteOption(option));
|
||||||
},
|
},
|
||||||
onUpdated: (updatedOption) {
|
onUpdated: (updatedOption) {
|
||||||
delegate.hideOverlay(context);
|
delegate.hideOverlay(context);
|
||||||
context.read<OptionPannelBloc>().add(OptionPannelEvent.updateOption(updatedOption));
|
context.read<FieldOptionPannelBloc>().add(FieldOptionPannelEvent.updateOption(updatedOption));
|
||||||
},
|
},
|
||||||
|
key: ValueKey(option.id),
|
||||||
);
|
);
|
||||||
delegate.showOverlay(context, pannel);
|
delegate.showOverlay(context, pannel);
|
||||||
},
|
},
|
||||||
|
@ -208,7 +209,7 @@ class _AddOptionButton extends StatelessWidget {
|
||||||
text: FlowyText.medium(LocaleKeys.grid_field_addSelectOption.tr(), fontSize: 12),
|
text: FlowyText.medium(LocaleKeys.grid_field_addSelectOption.tr(), fontSize: 12),
|
||||||
hoverColor: theme.hover,
|
hoverColor: theme.hover,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
context.read<OptionPannelBloc>().add(const OptionPannelEvent.beginAddingOption());
|
context.read<FieldOptionPannelBloc>().add(const FieldOptionPannelEvent.beginAddingOption());
|
||||||
},
|
},
|
||||||
leftIcon: svgWidget("home/add", color: theme.iconColor),
|
leftIcon: svgWidget("home/add", color: theme.iconColor),
|
||||||
),
|
),
|
||||||
|
@ -222,12 +223,13 @@ class _OptionNameTextField extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return NameTextField(
|
return NameTextField(
|
||||||
name: "",
|
name: "",
|
||||||
onCanceled: () {
|
onCanceled: () {
|
||||||
context.read<OptionPannelBloc>().add(const OptionPannelEvent.endAddingOption());
|
context.read<FieldOptionPannelBloc>().add(const FieldOptionPannelEvent.endAddingOption());
|
||||||
},
|
},
|
||||||
onDone: (optionName) {
|
onDone: (optionName) {
|
||||||
context.read<OptionPannelBloc>().add(OptionPannelEvent.createOption(optionName));
|
context.read<FieldOptionPannelBloc>().add(FieldOptionPannelEvent.createOption(optionName));
|
||||||
});
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -5,7 +5,7 @@ import 'package:flowy_sdk/protobuf/flowy-grid/selection_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 'option_pannel.dart';
|
import 'field_option_pannel.dart';
|
||||||
|
|
||||||
class MultiSelectTypeOptionBuilder extends TypeOptionBuilder {
|
class MultiSelectTypeOptionBuilder extends TypeOptionBuilder {
|
||||||
final MultiSelectTypeOptionWidget _widget;
|
final MultiSelectTypeOptionWidget _widget;
|
||||||
|
@ -48,7 +48,7 @@ class MultiSelectTypeOptionWidget extends TypeOptionWidget {
|
||||||
dataDelegate.didUpdateTypeOptionData(state.typeOption.writeToBuffer());
|
dataDelegate.didUpdateTypeOptionData(state.typeOption.writeToBuffer());
|
||||||
},
|
},
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
return OptionPannel(
|
return FieldSelectOptionPannel(
|
||||||
options: state.typeOption.options,
|
options: state.typeOption.options,
|
||||||
beginEdit: () {
|
beginEdit: () {
|
||||||
overlayDelegate.hideOverlay(context);
|
overlayDelegate.hideOverlay(context);
|
||||||
|
|
|
@ -81,7 +81,7 @@ class NumberFormatList extends StatelessWidget {
|
||||||
format: format,
|
format: format,
|
||||||
onSelected: (format) {
|
onSelected: (format) {
|
||||||
onSelected(format);
|
onSelected(format);
|
||||||
FlowyOverlay.of(context).remove(identifier());
|
FlowyOverlay.of(context).remove(NumberFormatList.identifier());
|
||||||
});
|
});
|
||||||
}).toList();
|
}).toList();
|
||||||
|
|
||||||
|
@ -101,8 +101,8 @@ class NumberFormatList extends StatelessWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
String identifier() {
|
static String identifier() {
|
||||||
return toString();
|
return (NumberFormatList).toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header
|
||||||
import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart';
|
import 'package:flowy_sdk/protobuf/flowy-grid/selection_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 'option_pannel.dart';
|
import 'field_option_pannel.dart';
|
||||||
|
|
||||||
class SingleSelectTypeOptionBuilder extends TypeOptionBuilder {
|
class SingleSelectTypeOptionBuilder extends TypeOptionBuilder {
|
||||||
final SingleSelectTypeOptionWidget _widget;
|
final SingleSelectTypeOptionWidget _widget;
|
||||||
|
@ -47,7 +47,7 @@ class SingleSelectTypeOptionWidget extends TypeOptionWidget {
|
||||||
dataDelegate.didUpdateTypeOptionData(state.typeOption.writeToBuffer());
|
dataDelegate.didUpdateTypeOptionData(state.typeOption.writeToBuffer());
|
||||||
},
|
},
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
return OptionPannel(
|
return FieldSelectOptionPannel(
|
||||||
options: state.typeOption.options,
|
options: state.typeOption.options,
|
||||||
beginEdit: () {
|
beginEdit: () {
|
||||||
overlayDelegate.hideOverlay(context);
|
overlayDelegate.hideOverlay(context);
|
||||||
|
|
|
@ -60,13 +60,12 @@ class _NameTextFieldState extends State<NameTextField> {
|
||||||
}
|
}
|
||||||
|
|
||||||
void notifyDidEndEditing() {
|
void notifyDidEndEditing() {
|
||||||
if (_controller.text.isEmpty) {
|
if (!_focusNode.hasFocus) {
|
||||||
if (isEdited) {
|
if (_controller.text.isEmpty) {
|
||||||
widget.onCanceled();
|
widget.onCanceled();
|
||||||
|
} else {
|
||||||
|
widget.onDone(_controller.text);
|
||||||
}
|
}
|
||||||
isEdited = true;
|
|
||||||
} else {
|
|
||||||
widget.onDone(_controller.text);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ edition = "2018"
|
||||||
name = "dart_ffi"
|
name = "dart_ffi"
|
||||||
# this value will change depending on the target os
|
# this value will change depending on the target os
|
||||||
# default static lib
|
# default static lib
|
||||||
crate-type = ["staticlib"]
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|
|
@ -58,7 +58,7 @@ impl ClientGridEditor {
|
||||||
start_field_id,
|
start_field_id,
|
||||||
grid_id,
|
grid_id,
|
||||||
} = params;
|
} = params;
|
||||||
|
let field_id = field.id.clone();
|
||||||
let _ = self
|
let _ = self
|
||||||
.modify(|grid| {
|
.modify(|grid| {
|
||||||
if grid.contain_field(&field.id) {
|
if grid.contain_field(&field.id) {
|
||||||
|
@ -84,6 +84,7 @@ impl ClientGridEditor {
|
||||||
})
|
})
|
||||||
.await?;
|
.await?;
|
||||||
let _ = self.notify_did_update_grid().await?;
|
let _ = self.notify_did_update_grid().await?;
|
||||||
|
let _ = self.notify_did_update_field(&field_id).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,7 +114,9 @@ impl ClientGridEditor {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn replace_field(&self, field_meta: FieldMeta) -> FlowyResult<()> {
|
pub async fn replace_field(&self, field_meta: FieldMeta) -> FlowyResult<()> {
|
||||||
|
let field_id = field_meta.id.clone();
|
||||||
let _ = self.modify(|pad| Ok(pad.replace_field(field_meta)?)).await?;
|
let _ = self.modify(|pad| Ok(pad.replace_field(field_meta)?)).await?;
|
||||||
|
let _ = self.notify_did_update_field(&field_id).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -407,12 +410,13 @@ impl ClientGridEditor {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(level = "trace", skip_all, err)]
|
||||||
async fn notify_did_update_field(&self, field_id: &str) -> FlowyResult<()> {
|
async fn notify_did_update_field(&self, field_id: &str) -> FlowyResult<()> {
|
||||||
let mut field_metas = self.get_field_metas(Some(vec![field_id])).await?;
|
let mut field_metas = self.get_field_metas(Some(vec![field_id])).await?;
|
||||||
debug_assert!(field_metas.len() == 1);
|
debug_assert!(field_metas.len() == 1);
|
||||||
|
|
||||||
if let Some(field_meta) = field_metas.pop() {
|
if let Some(field_meta) = field_metas.pop() {
|
||||||
send_dart_notification(&self.grid_id, GridNotification::DidUpdateField)
|
send_dart_notification(&field_id, GridNotification::DidUpdateField)
|
||||||
.payload(field_meta)
|
.payload(field_meta)
|
||||||
.send();
|
.send();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue