mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
Merge pull request #925 from AppFlowy-IO/feat/edit_card_directly
Feat/edit card directly
This commit is contained in:
commit
624de03897
@ -142,7 +142,7 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
|
|||||||
for (final group in groups) {
|
for (final group in groups) {
|
||||||
final delegate = GroupControllerDelegateImpl(
|
final delegate = GroupControllerDelegateImpl(
|
||||||
controller: boardController,
|
controller: boardController,
|
||||||
didAddColumnItem: (groupId, row) {
|
onNewColumnItem: (groupId, row) {
|
||||||
add(BoardEvent.didCreateRow(groupId, row));
|
add(BoardEvent.didCreateRow(groupId, row));
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -313,11 +313,11 @@ class BoardColumnItem extends AFColumnItem {
|
|||||||
|
|
||||||
class GroupControllerDelegateImpl extends GroupControllerDelegate {
|
class GroupControllerDelegateImpl extends GroupControllerDelegate {
|
||||||
final AFBoardDataController controller;
|
final AFBoardDataController controller;
|
||||||
final void Function(String, RowPB) didAddColumnItem;
|
final void Function(String, RowPB) onNewColumnItem;
|
||||||
|
|
||||||
GroupControllerDelegateImpl({
|
GroupControllerDelegateImpl({
|
||||||
required this.controller,
|
required this.controller,
|
||||||
required this.didAddColumnItem,
|
required this.onNewColumnItem,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -329,10 +329,8 @@ class GroupControllerDelegateImpl extends GroupControllerDelegate {
|
|||||||
final item = BoardColumnItem(
|
final item = BoardColumnItem(
|
||||||
row: row,
|
row: row,
|
||||||
fieldId: group.fieldId,
|
fieldId: group.fieldId,
|
||||||
requestFocus: true,
|
|
||||||
);
|
);
|
||||||
controller.addColumnItem(group.groupId, item);
|
controller.addColumnItem(group.groupId, item);
|
||||||
didAddColumnItem(group.groupId, row);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -351,6 +349,17 @@ class GroupControllerDelegateImpl extends GroupControllerDelegate {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void addNewRow(GroupPB group, RowPB row) {
|
||||||
|
final item = BoardColumnItem(
|
||||||
|
row: row,
|
||||||
|
fieldId: group.fieldId,
|
||||||
|
requestFocus: true,
|
||||||
|
);
|
||||||
|
controller.addColumnItem(group.groupId, item);
|
||||||
|
onNewColumnItem(group.groupId, row);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class BoardEditingRow {
|
class BoardEditingRow {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_service.dart';
|
import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_service.dart';
|
||||||
|
import 'package:flutter/foundation.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';
|
||||||
@ -20,6 +21,12 @@ class BoardTextCellBloc extends Bloc<BoardTextCellEvent, BoardTextCellState> {
|
|||||||
didReceiveCellUpdate: (content) {
|
didReceiveCellUpdate: (content) {
|
||||||
emit(state.copyWith(content: content));
|
emit(state.copyWith(content: content));
|
||||||
},
|
},
|
||||||
|
updateText: (text) {
|
||||||
|
if (text != state.content) {
|
||||||
|
cellController.saveCellData(text);
|
||||||
|
emit(state.copyWith(content: text));
|
||||||
|
}
|
||||||
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -49,6 +56,7 @@ class BoardTextCellBloc extends Bloc<BoardTextCellEvent, BoardTextCellState> {
|
|||||||
@freezed
|
@freezed
|
||||||
class BoardTextCellEvent with _$BoardTextCellEvent {
|
class BoardTextCellEvent with _$BoardTextCellEvent {
|
||||||
const factory BoardTextCellEvent.initial() = _InitialCell;
|
const factory BoardTextCellEvent.initial() = _InitialCell;
|
||||||
|
const factory BoardTextCellEvent.updateText(String text) = _UpdateContent;
|
||||||
const factory BoardTextCellEvent.didReceiveCellUpdate(String cellContent) =
|
const factory BoardTextCellEvent.didReceiveCellUpdate(String cellContent) =
|
||||||
_DidReceiveCellUpdate;
|
_DidReceiveCellUpdate;
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ abstract class GroupControllerDelegate {
|
|||||||
void removeRow(GroupPB group, String rowId);
|
void removeRow(GroupPB group, String rowId);
|
||||||
void insertRow(GroupPB group, RowPB row, int? index);
|
void insertRow(GroupPB group, RowPB row, int? index);
|
||||||
void updateRow(GroupPB group, RowPB row);
|
void updateRow(GroupPB group, RowPB row);
|
||||||
|
void addNewRow(GroupPB group, RowPB row);
|
||||||
}
|
}
|
||||||
|
|
||||||
class GroupController {
|
class GroupController {
|
||||||
@ -48,8 +49,12 @@ class GroupController {
|
|||||||
group.rows.add(insertedRow.row);
|
group.rows.add(insertedRow.row);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (insertedRow.isNew) {
|
||||||
|
delegate.addNewRow(group, insertedRow.row);
|
||||||
|
} else {
|
||||||
delegate.insertRow(group, insertedRow.row, index);
|
delegate.insertRow(group, insertedRow.row, index);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (final updatedRow in changeset.updatedRows) {
|
for (final updatedRow in changeset.updatedRows) {
|
||||||
final index = group.rows.indexWhere(
|
final index = group.rows.indexWhere(
|
||||||
|
@ -196,10 +196,8 @@ class _BoardContentState extends State<BoardContent> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
final cellBuilder = BoardCellBuilder(cardController);
|
final cellBuilder = BoardCellBuilder(cardController);
|
||||||
final isEditing = context.read<BoardBloc>().state.editingRow.fold(
|
|
||||||
() => false,
|
final isEditing = context.read<BoardBloc>().state.editingRow.isSome();
|
||||||
(editingRow) => editingRow.row.id == rowPB.id,
|
|
||||||
);
|
|
||||||
|
|
||||||
return AppFlowyColumnItemCard(
|
return AppFlowyColumnItemCard(
|
||||||
key: ValueKey(columnItem.id),
|
key: ValueKey(columnItem.id),
|
||||||
@ -212,9 +210,6 @@ class _BoardContentState extends State<BoardContent> {
|
|||||||
isEditing: isEditing,
|
isEditing: isEditing,
|
||||||
cellBuilder: cellBuilder,
|
cellBuilder: cellBuilder,
|
||||||
dataController: cardController,
|
dataController: cardController,
|
||||||
onEditEditing: (rowId) {
|
|
||||||
context.read<BoardBloc>().add(BoardEvent.endEditRow(rowId));
|
|
||||||
},
|
|
||||||
openCard: (context) => _openCard(
|
openCard: (context) => _openCard(
|
||||||
gridId,
|
gridId,
|
||||||
fieldCache,
|
fieldCache,
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
abstract class FocusableBoardCell {
|
||||||
|
set becomeFocus(bool isFocus);
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
import 'package:app_flowy/plugins/board/application/card/board_select_option_cell_bloc.dart';
|
import 'package:app_flowy/plugins/board/application/card/board_select_option_cell_bloc.dart';
|
||||||
import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_service.dart';
|
import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_service.dart';
|
||||||
import 'package:app_flowy/plugins/grid/presentation/widgets/cell/select_option_cell/extension.dart';
|
import 'package:app_flowy/plugins/grid/presentation/widgets/cell/select_option_cell/extension.dart';
|
||||||
|
import 'package:app_flowy/plugins/grid/presentation/widgets/cell/select_option_cell/select_option_editor.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';
|
||||||
|
|
||||||
@ -41,7 +42,8 @@ class _BoardSelectOptionCellState extends State<BoardSelectOptionCell> {
|
|||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
if (state.selectedOptions
|
if (state.selectedOptions
|
||||||
.where((element) => element.id == widget.groupId)
|
.where((element) => element.id == widget.groupId)
|
||||||
.isNotEmpty) {
|
.isNotEmpty ||
|
||||||
|
state.selectedOptions.isEmpty) {
|
||||||
return const SizedBox();
|
return const SizedBox();
|
||||||
} else {
|
} else {
|
||||||
final children = state.selectedOptions
|
final children = state.selectedOptions
|
||||||
@ -52,10 +54,17 @@ class _BoardSelectOptionCellState extends State<BoardSelectOptionCell> {
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
.toList();
|
.toList();
|
||||||
return Align(
|
|
||||||
alignment: Alignment.centerLeft,
|
return IntrinsicHeight(
|
||||||
child: AbsorbPointer(
|
child: Stack(
|
||||||
child: Wrap(children: children, spacing: 4, runSpacing: 2),
|
alignment: AlignmentDirectional.center,
|
||||||
|
fit: StackFit.expand,
|
||||||
|
children: [
|
||||||
|
Wrap(children: children, spacing: 4, runSpacing: 2),
|
||||||
|
_SelectOptionDialog(
|
||||||
|
controller: widget.cellControllerBuilder.build(),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -70,3 +79,23 @@ class _BoardSelectOptionCellState extends State<BoardSelectOptionCell> {
|
|||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _SelectOptionDialog extends StatelessWidget {
|
||||||
|
final GridSelectOptionCellController _controller;
|
||||||
|
const _SelectOptionDialog({
|
||||||
|
Key? key,
|
||||||
|
required IGridCellController controller,
|
||||||
|
}) : _controller = controller as GridSelectOptionCellController,
|
||||||
|
super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return InkWell(onTap: () {
|
||||||
|
SelectOptionCellEditor.show(
|
||||||
|
context,
|
||||||
|
_controller,
|
||||||
|
() {},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,15 +1,19 @@
|
|||||||
import 'package:app_flowy/plugins/board/application/card/board_text_cell_bloc.dart';
|
import 'package:app_flowy/plugins/board/application/card/board_text_cell_bloc.dart';
|
||||||
import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_service.dart';
|
import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_service.dart';
|
||||||
import 'package:flowy_infra_ui/style_widget/text.dart';
|
import 'package:app_flowy/plugins/grid/presentation/widgets/cell/cell_builder.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';
|
||||||
|
|
||||||
class BoardTextCell extends StatefulWidget {
|
class BoardTextCell extends StatefulWidget {
|
||||||
final String groupId;
|
final String groupId;
|
||||||
|
final bool isFocus;
|
||||||
|
|
||||||
final GridCellControllerBuilder cellControllerBuilder;
|
final GridCellControllerBuilder cellControllerBuilder;
|
||||||
|
|
||||||
const BoardTextCell({
|
const BoardTextCell({
|
||||||
required this.groupId,
|
required this.groupId,
|
||||||
required this.cellControllerBuilder,
|
required this.cellControllerBuilder,
|
||||||
|
this.isFocus = false,
|
||||||
Key? key,
|
Key? key,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@ -19,14 +23,20 @@ class BoardTextCell extends StatefulWidget {
|
|||||||
|
|
||||||
class _BoardTextCellState extends State<BoardTextCell> {
|
class _BoardTextCellState extends State<BoardTextCell> {
|
||||||
late BoardTextCellBloc _cellBloc;
|
late BoardTextCellBloc _cellBloc;
|
||||||
|
late TextEditingController _controller;
|
||||||
|
SingleListenerFocusNode focusNode = SingleListenerFocusNode();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
final cellController =
|
final cellController =
|
||||||
widget.cellControllerBuilder.build() as GridCellController;
|
widget.cellControllerBuilder.build() as GridCellController;
|
||||||
|
|
||||||
_cellBloc = BoardTextCellBloc(cellController: cellController)
|
_cellBloc = BoardTextCellBloc(cellController: cellController)
|
||||||
..add(const BoardTextCellEvent.initial());
|
..add(const BoardTextCellEvent.initial());
|
||||||
|
_controller = TextEditingController(text: _cellBloc.state.content);
|
||||||
|
|
||||||
|
if (widget.isFocus) {
|
||||||
|
focusNode.requestFocus();
|
||||||
|
}
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,28 +44,38 @@ class _BoardTextCellState extends State<BoardTextCell> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocProvider.value(
|
return BlocProvider.value(
|
||||||
value: _cellBloc,
|
value: _cellBloc,
|
||||||
child: BlocBuilder<BoardTextCellBloc, BoardTextCellState>(
|
child: BlocListener<BoardTextCellBloc, BoardTextCellState>(
|
||||||
buildWhen: (previous, current) => previous.content != current.content,
|
listener: (context, state) {
|
||||||
builder: (context, state) {
|
if (_controller.text != state.content) {
|
||||||
if (state.content.isEmpty) {
|
_controller.text = state.content;
|
||||||
return const SizedBox();
|
}
|
||||||
} else {
|
},
|
||||||
return Align(
|
child: TextField(
|
||||||
alignment: Alignment.centerLeft,
|
controller: _controller,
|
||||||
child: ConstrainedBox(
|
focusNode: focusNode,
|
||||||
constraints: const BoxConstraints(maxHeight: 120),
|
onChanged: (value) => focusChanged(),
|
||||||
child: FlowyText.medium(state.content, fontSize: 14),
|
onEditingComplete: () => focusNode.unfocus(),
|
||||||
|
maxLines: 1,
|
||||||
|
style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
contentPadding: EdgeInsets.symmetric(vertical: 6),
|
||||||
|
border: InputBorder.none,
|
||||||
|
isDense: true,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
|
||||||
),
|
Future<void> focusChanged() async {
|
||||||
);
|
_cellBloc.add(BoardTextCellEvent.updateText(_controller.text));
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> dispose() async {
|
Future<void> dispose() async {
|
||||||
_cellBloc.close();
|
_cellBloc.close();
|
||||||
|
_controller.dispose();
|
||||||
|
focusNode.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,8 +10,6 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
|||||||
import 'card_cell_builder.dart';
|
import 'card_cell_builder.dart';
|
||||||
import 'card_container.dart';
|
import 'card_container.dart';
|
||||||
|
|
||||||
typedef OnEndEditing = void Function(String rowId);
|
|
||||||
|
|
||||||
class BoardCard extends StatefulWidget {
|
class BoardCard extends StatefulWidget {
|
||||||
final String gridId;
|
final String gridId;
|
||||||
final String groupId;
|
final String groupId;
|
||||||
@ -19,7 +17,6 @@ class BoardCard extends StatefulWidget {
|
|||||||
final bool isEditing;
|
final bool isEditing;
|
||||||
final CardDataController dataController;
|
final CardDataController dataController;
|
||||||
final BoardCellBuilder cellBuilder;
|
final BoardCellBuilder cellBuilder;
|
||||||
final OnEndEditing onEditEditing;
|
|
||||||
final void Function(BuildContext) openCard;
|
final void Function(BuildContext) openCard;
|
||||||
|
|
||||||
const BoardCard({
|
const BoardCard({
|
||||||
@ -29,7 +26,6 @@ class BoardCard extends StatefulWidget {
|
|||||||
required this.isEditing,
|
required this.isEditing,
|
||||||
required this.dataController,
|
required this.dataController,
|
||||||
required this.cellBuilder,
|
required this.cellBuilder,
|
||||||
required this.onEditEditing,
|
|
||||||
required this.openCard,
|
required this.openCard,
|
||||||
Key? key,
|
Key? key,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
@ -68,6 +64,7 @@ class _BoardCardState extends State<BoardCard> {
|
|||||||
widget.openCard(context);
|
widget.openCard(context);
|
||||||
},
|
},
|
||||||
child: Column(
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: _makeCells(
|
children: _makeCells(
|
||||||
context,
|
context,
|
||||||
state.cells.map((cell) => cell.identifier).toList(),
|
state.cells.map((cell) => cell.identifier).toList(),
|
||||||
@ -83,15 +80,33 @@ class _BoardCardState extends State<BoardCard> {
|
|||||||
BuildContext context,
|
BuildContext context,
|
||||||
List<GridCellIdentifier> cells,
|
List<GridCellIdentifier> cells,
|
||||||
) {
|
) {
|
||||||
return cells.map(
|
final List<Widget> children = [];
|
||||||
(GridCellIdentifier cellId) {
|
cells.asMap().forEach(
|
||||||
final child = widget.cellBuilder.buildCell(widget.groupId, cellId);
|
(int index, GridCellIdentifier cellId) {
|
||||||
return Padding(
|
Widget child = widget.cellBuilder.buildCell(
|
||||||
padding: const EdgeInsets.only(left: 4, right: 4, top: 6),
|
widget.groupId,
|
||||||
|
cellId,
|
||||||
|
widget.isEditing,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (index != 0) {
|
||||||
|
child = Padding(
|
||||||
|
key: cellId.key(),
|
||||||
|
padding: const EdgeInsets.only(left: 4, right: 4, top: 8),
|
||||||
child: child,
|
child: child,
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
child = Padding(
|
||||||
|
key: UniqueKey(),
|
||||||
|
padding: const EdgeInsets.only(left: 4, right: 4),
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
children.add(child);
|
||||||
},
|
},
|
||||||
).toList();
|
);
|
||||||
|
return children;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -19,7 +19,11 @@ class BoardCellBuilder {
|
|||||||
|
|
||||||
BoardCellBuilder(this.delegate);
|
BoardCellBuilder(this.delegate);
|
||||||
|
|
||||||
Widget buildCell(String groupId, GridCellIdentifier cellId) {
|
Widget buildCell(
|
||||||
|
String groupId,
|
||||||
|
GridCellIdentifier cellId,
|
||||||
|
bool isEditing,
|
||||||
|
) {
|
||||||
final cellControllerBuilder = GridCellControllerBuilder(
|
final cellControllerBuilder = GridCellControllerBuilder(
|
||||||
delegate: delegate,
|
delegate: delegate,
|
||||||
cellId: cellId,
|
cellId: cellId,
|
||||||
@ -62,6 +66,7 @@ class BoardCellBuilder {
|
|||||||
return BoardTextCell(
|
return BoardTextCell(
|
||||||
groupId: groupId,
|
groupId: groupId,
|
||||||
cellControllerBuilder: cellControllerBuilder,
|
cellControllerBuilder: cellControllerBuilder,
|
||||||
|
isFocus: isEditing,
|
||||||
key: key,
|
key: key,
|
||||||
);
|
);
|
||||||
case FieldType.URL:
|
case FieldType.URL:
|
||||||
|
@ -11,13 +11,15 @@ typedef UpdateFieldNotifiedValue = Either<Unit, FlowyError>;
|
|||||||
class CellListener {
|
class CellListener {
|
||||||
final String rowId;
|
final String rowId;
|
||||||
final String fieldId;
|
final String fieldId;
|
||||||
PublishNotifier<UpdateFieldNotifiedValue>? _updateCellNotifier = PublishNotifier();
|
PublishNotifier<UpdateFieldNotifiedValue>? _updateCellNotifier =
|
||||||
|
PublishNotifier();
|
||||||
GridNotificationListener? _listener;
|
GridNotificationListener? _listener;
|
||||||
CellListener({required this.rowId, required this.fieldId});
|
CellListener({required this.rowId, required this.fieldId});
|
||||||
|
|
||||||
void start({required void Function(UpdateFieldNotifiedValue) onCellChanged}) {
|
void start({required void Function(UpdateFieldNotifiedValue) onCellChanged}) {
|
||||||
_updateCellNotifier?.addPublishListener(onCellChanged);
|
_updateCellNotifier?.addPublishListener(onCellChanged);
|
||||||
_listener = GridNotificationListener(objectId: "$rowId:$fieldId", handler: _handler);
|
_listener = GridNotificationListener(
|
||||||
|
objectId: "$rowId:$fieldId", handler: _handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _handler(GridNotification ty, Either<Uint8List, FlowyError> result) {
|
void _handler(GridNotification ty, Either<Uint8List, FlowyError> result) {
|
||||||
|
@ -33,10 +33,17 @@ class GridCellCache {
|
|||||||
required this.gridId,
|
required this.gridId,
|
||||||
});
|
});
|
||||||
|
|
||||||
void remove(String fieldId) {
|
void removeCellWithFieldId(String fieldId) {
|
||||||
_cellDataByFieldId.remove(fieldId);
|
_cellDataByFieldId.remove(fieldId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void remove(GridCellCacheKey key) {
|
||||||
|
var map = _cellDataByFieldId[key.fieldId];
|
||||||
|
if (map != null) {
|
||||||
|
map.remove(key.rowId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void insert<T extends GridCell>(GridCellCacheKey key, T value) {
|
void insert<T extends GridCell>(GridCellCacheKey key, T value) {
|
||||||
var map = _cellDataByFieldId[key.fieldId];
|
var map = _cellDataByFieldId[key.fieldId];
|
||||||
if (map == null) {
|
if (map == null) {
|
||||||
|
@ -191,7 +191,7 @@ class IGridCellController<T, D> extends Equatable {
|
|||||||
_cellListener?.start(onCellChanged: (result) {
|
_cellListener?.start(onCellChanged: (result) {
|
||||||
result.fold(
|
result.fold(
|
||||||
(_) {
|
(_) {
|
||||||
_cellsCache.remove(fieldId);
|
_cellsCache.remove(_cacheKey);
|
||||||
_loadData();
|
_loadData();
|
||||||
},
|
},
|
||||||
(err) => Log.error(err),
|
(err) => Log.error(err),
|
||||||
|
@ -52,7 +52,8 @@ class GridRowCache {
|
|||||||
//
|
//
|
||||||
notifier.onRowFieldsChanged(() => _rowChangeReasonNotifier
|
notifier.onRowFieldsChanged(() => _rowChangeReasonNotifier
|
||||||
.receive(const RowsChangedReason.fieldDidChange()));
|
.receive(const RowsChangedReason.fieldDidChange()));
|
||||||
notifier.onRowFieldChanged((field) => _cellCache.remove(field.id));
|
notifier.onRowFieldChanged(
|
||||||
|
(field) => _cellCache.removeCellWithFieldId(field.id));
|
||||||
_rowInfos = block.rows.map((rowPB) => buildGridRow(rowPB)).toList();
|
_rowInfos = block.rows.map((rowPB) => buildGridRow(rowPB)).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "generated_plugin_registrant.h"
|
#include "generated_plugin_registrant.h"
|
||||||
|
|
||||||
#include <flowy_infra_ui/flowy_infra_u_i_plugin.h>
|
#include <flowy_infra_ui/flowy_infra_u_i_plugin.h>
|
||||||
|
#include <hotkey_manager/hotkey_manager_plugin.h>
|
||||||
#include <rich_clipboard_linux/rich_clipboard_plugin.h>
|
#include <rich_clipboard_linux/rich_clipboard_plugin.h>
|
||||||
#include <url_launcher_linux/url_launcher_plugin.h>
|
#include <url_launcher_linux/url_launcher_plugin.h>
|
||||||
#include <window_size/window_size_plugin.h>
|
#include <window_size/window_size_plugin.h>
|
||||||
@ -15,6 +16,9 @@ void fl_register_plugins(FlPluginRegistry* registry) {
|
|||||||
g_autoptr(FlPluginRegistrar) flowy_infra_ui_registrar =
|
g_autoptr(FlPluginRegistrar) flowy_infra_ui_registrar =
|
||||||
fl_plugin_registry_get_registrar_for_plugin(registry, "FlowyInfraUIPlugin");
|
fl_plugin_registry_get_registrar_for_plugin(registry, "FlowyInfraUIPlugin");
|
||||||
flowy_infra_u_i_plugin_register_with_registrar(flowy_infra_ui_registrar);
|
flowy_infra_u_i_plugin_register_with_registrar(flowy_infra_ui_registrar);
|
||||||
|
g_autoptr(FlPluginRegistrar) hotkey_manager_registrar =
|
||||||
|
fl_plugin_registry_get_registrar_for_plugin(registry, "HotkeyManagerPlugin");
|
||||||
|
hotkey_manager_plugin_register_with_registrar(hotkey_manager_registrar);
|
||||||
g_autoptr(FlPluginRegistrar) rich_clipboard_linux_registrar =
|
g_autoptr(FlPluginRegistrar) rich_clipboard_linux_registrar =
|
||||||
fl_plugin_registry_get_registrar_for_plugin(registry, "RichClipboardPlugin");
|
fl_plugin_registry_get_registrar_for_plugin(registry, "RichClipboardPlugin");
|
||||||
rich_clipboard_plugin_register_with_registrar(rich_clipboard_linux_registrar);
|
rich_clipboard_plugin_register_with_registrar(rich_clipboard_linux_registrar);
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
flowy_infra_ui
|
flowy_infra_ui
|
||||||
|
hotkey_manager
|
||||||
rich_clipboard_linux
|
rich_clipboard_linux
|
||||||
url_launcher_linux
|
url_launcher_linux
|
||||||
window_size
|
window_size
|
||||||
|
@ -9,6 +9,7 @@ import connectivity_plus_macos
|
|||||||
import device_info_plus_macos
|
import device_info_plus_macos
|
||||||
import flowy_infra_ui
|
import flowy_infra_ui
|
||||||
import flowy_sdk
|
import flowy_sdk
|
||||||
|
import hotkey_manager
|
||||||
import package_info_plus_macos
|
import package_info_plus_macos
|
||||||
import path_provider_macos
|
import path_provider_macos
|
||||||
import rich_clipboard_macos
|
import rich_clipboard_macos
|
||||||
@ -21,6 +22,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
|||||||
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
|
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
|
||||||
FlowyInfraUIPlugin.register(with: registry.registrar(forPlugin: "FlowyInfraUIPlugin"))
|
FlowyInfraUIPlugin.register(with: registry.registrar(forPlugin: "FlowyInfraUIPlugin"))
|
||||||
FlowySdkPlugin.register(with: registry.registrar(forPlugin: "FlowySdkPlugin"))
|
FlowySdkPlugin.register(with: registry.registrar(forPlugin: "FlowySdkPlugin"))
|
||||||
|
HotkeyManagerPlugin.register(with: registry.registrar(forPlugin: "HotkeyManagerPlugin"))
|
||||||
FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin"))
|
FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin"))
|
||||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||||
RichClipboardPlugin.register(with: registry.registrar(forPlugin: "RichClipboardPlugin"))
|
RichClipboardPlugin.register(with: registry.registrar(forPlugin: "RichClipboardPlugin"))
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
|
# 0.0.6
|
||||||
|
* Support scroll to bottom
|
||||||
|
* Fix some bugs
|
||||||
|
|
||||||
# 0.0.5
|
# 0.0.5
|
||||||
* Optimize insert card animation
|
* Optimize insert card animation
|
||||||
* Enable insert card at the end of the column
|
* Enable insert card at the end of the column
|
||||||
|
@ -11,13 +11,13 @@ class MultiBoardListExample extends StatefulWidget {
|
|||||||
class _MultiBoardListExampleState extends State<MultiBoardListExample> {
|
class _MultiBoardListExampleState extends State<MultiBoardListExample> {
|
||||||
final AFBoardDataController boardDataController = AFBoardDataController(
|
final AFBoardDataController boardDataController = AFBoardDataController(
|
||||||
onMoveColumn: (fromColumnId, fromIndex, toColumnId, toIndex) {
|
onMoveColumn: (fromColumnId, fromIndex, toColumnId, toIndex) {
|
||||||
debugPrint('Move column from $fromIndex to $toIndex');
|
// debugPrint('Move column from $fromIndex to $toIndex');
|
||||||
},
|
},
|
||||||
onMoveColumnItem: (columnId, fromIndex, toIndex) {
|
onMoveColumnItem: (columnId, fromIndex, toIndex) {
|
||||||
debugPrint('Move $columnId:$fromIndex to $columnId:$toIndex');
|
// debugPrint('Move $columnId:$fromIndex to $columnId:$toIndex');
|
||||||
},
|
},
|
||||||
onMoveColumnItemToColumn: (fromColumnId, fromIndex, toColumnId, toIndex) {
|
onMoveColumnItemToColumn: (fromColumnId, fromIndex, toColumnId, toIndex) {
|
||||||
debugPrint('Move $fromColumnId:$fromIndex to $toColumnId:$toIndex');
|
// debugPrint('Move $fromColumnId:$fromIndex to $toColumnId:$toIndex');
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -96,7 +96,7 @@ class _MultiBoardListExampleState extends State<MultiBoardListExample> {
|
|||||||
},
|
},
|
||||||
cardBuilder: (context, column, columnItem) {
|
cardBuilder: (context, column, columnItem) {
|
||||||
return AppFlowyColumnItemCard(
|
return AppFlowyColumnItemCard(
|
||||||
key: ObjectKey(columnItem),
|
key: ValueKey(columnItem.id),
|
||||||
child: _buildCard(columnItem),
|
child: _buildCard(columnItem),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -121,6 +121,32 @@ class _MultiBoardListExampleState extends State<MultiBoardListExample> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (item is RichTextItem) {
|
if (item is RichTextItem) {
|
||||||
|
return RichTextCard(item: item);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class RichTextCard extends StatefulWidget {
|
||||||
|
final RichTextItem item;
|
||||||
|
const RichTextCard({
|
||||||
|
required this.item,
|
||||||
|
Key? key,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<RichTextCard> createState() => _RichTextCardState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _RichTextCardState extends State<RichTextCard> {
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
return Align(
|
return Align(
|
||||||
alignment: Alignment.centerLeft,
|
alignment: Alignment.centerLeft,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
@ -129,13 +155,13 @@ class _MultiBoardListExampleState extends State<MultiBoardListExample> {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
item.title,
|
widget.item.title,
|
||||||
style: const TextStyle(fontSize: 14),
|
style: const TextStyle(fontSize: 14),
|
||||||
textAlign: TextAlign.left,
|
textAlign: TextAlign.left,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
Text(
|
Text(
|
||||||
item.subtitle,
|
widget.item.subtitle,
|
||||||
style: const TextStyle(fontSize: 12, color: Colors.grey),
|
style: const TextStyle(fontSize: 12, color: Colors.grey),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
@ -143,9 +169,6 @@ class _MultiBoardListExampleState extends State<MultiBoardListExample> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw UnimplementedError();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class TextItem extends AFColumnItem {
|
class TextItem extends AFColumnItem {
|
||||||
|
@ -4,7 +4,7 @@ import 'package:flutter/material.dart';
|
|||||||
const DART_LOG = "Dart_LOG";
|
const DART_LOG = "Dart_LOG";
|
||||||
|
|
||||||
class Log {
|
class Log {
|
||||||
static const enableLog = false;
|
static const enableLog = true;
|
||||||
|
|
||||||
static void info(String? message) {
|
static void info(String? message) {
|
||||||
if (enableLog) {
|
if (enableLog) {
|
||||||
@ -26,7 +26,7 @@ class Log {
|
|||||||
|
|
||||||
static void trace(String? message) {
|
static void trace(String? message) {
|
||||||
if (enableLog) {
|
if (enableLog) {
|
||||||
debugPrint('❗️[Trace] - ${DateTime.now().second}=> $message');
|
// debugPrint('❗️[Trace] - ${DateTime.now().second}=> $message');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,7 @@ class AFBoard extends StatelessWidget {
|
|||||||
final BoxConstraints columnConstraints;
|
final BoxConstraints columnConstraints;
|
||||||
|
|
||||||
///
|
///
|
||||||
final BoardPhantomController phantomController;
|
late final BoardPhantomController phantomController;
|
||||||
|
|
||||||
final ScrollController? scrollController;
|
final ScrollController? scrollController;
|
||||||
|
|
||||||
@ -85,8 +85,12 @@ class AFBoard extends StatelessWidget {
|
|||||||
this.columnConstraints = const BoxConstraints(maxWidth: 200),
|
this.columnConstraints = const BoxConstraints(maxWidth: 200),
|
||||||
this.config = const AFBoardConfig(),
|
this.config = const AFBoardConfig(),
|
||||||
Key? key,
|
Key? key,
|
||||||
}) : phantomController = BoardPhantomController(delegate: dataController),
|
}) : super(key: key) {
|
||||||
super(key: key);
|
phantomController = BoardPhantomController(
|
||||||
|
delegate: dataController,
|
||||||
|
columnsState: _columnState,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -194,6 +198,7 @@ class _AFBoardContentState extends State<AFBoardContent> {
|
|||||||
dataSource: widget.dataController,
|
dataSource: widget.dataController,
|
||||||
direction: Axis.horizontal,
|
direction: Axis.horizontal,
|
||||||
interceptor: interceptor,
|
interceptor: interceptor,
|
||||||
|
reorderable: false,
|
||||||
children: _buildColumns(),
|
children: _buildColumns(),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -244,7 +249,7 @@ class _AFBoardContentState extends State<AFBoardContent> {
|
|||||||
child: Consumer<AFBoardColumnDataController>(
|
child: Consumer<AFBoardColumnDataController>(
|
||||||
builder: (context, value, child) {
|
builder: (context, value, child) {
|
||||||
final boardColumn = AFBoardColumnWidget(
|
final boardColumn = AFBoardColumnWidget(
|
||||||
key: PageStorageKey<String>(columnData.id),
|
// key: PageStorageKey<String>(columnData.id),
|
||||||
// key: GlobalObjectKey(columnData.id),
|
// key: GlobalObjectKey(columnData.id),
|
||||||
margin: _marginFromIndex(columnIndex),
|
margin: _marginFromIndex(columnIndex),
|
||||||
itemMargin: widget.config.columnItemPadding,
|
itemMargin: widget.config.columnItemPadding,
|
||||||
|
@ -92,7 +92,7 @@ class AFBoardColumnWidget extends StatefulWidget {
|
|||||||
|
|
||||||
final ReorderDragTargetIndexKeyStorage? dragTargetIndexKeyStorage;
|
final ReorderDragTargetIndexKeyStorage? dragTargetIndexKeyStorage;
|
||||||
|
|
||||||
final GlobalKey globalKey;
|
final GlobalObjectKey globalKey;
|
||||||
|
|
||||||
AFBoardColumnWidget({
|
AFBoardColumnWidget({
|
||||||
Key? key,
|
Key? key,
|
||||||
@ -111,7 +111,7 @@ class AFBoardColumnWidget extends StatefulWidget {
|
|||||||
this.itemMargin = EdgeInsets.zero,
|
this.itemMargin = EdgeInsets.zero,
|
||||||
this.cornerRadius = 0.0,
|
this.cornerRadius = 0.0,
|
||||||
this.backgroundColor = Colors.transparent,
|
this.backgroundColor = Colors.transparent,
|
||||||
}) : globalKey = GlobalKey(),
|
}) : globalKey = GlobalObjectKey(dataSource.columnData.id),
|
||||||
config = const ReorderFlexConfig(),
|
config = const ReorderFlexConfig(),
|
||||||
super(key: key);
|
super(key: key);
|
||||||
|
|
||||||
|
@ -75,6 +75,7 @@ class ReorderDragTarget<T extends DragTargetData> extends StatefulWidget {
|
|||||||
final AnimationController deleteAnimationController;
|
final AnimationController deleteAnimationController;
|
||||||
|
|
||||||
final bool useMoveAnimation;
|
final bool useMoveAnimation;
|
||||||
|
final bool draggable;
|
||||||
|
|
||||||
const ReorderDragTarget({
|
const ReorderDragTarget({
|
||||||
Key? key,
|
Key? key,
|
||||||
@ -88,6 +89,7 @@ class ReorderDragTarget<T extends DragTargetData> extends StatefulWidget {
|
|||||||
required this.insertAnimationController,
|
required this.insertAnimationController,
|
||||||
required this.deleteAnimationController,
|
required this.deleteAnimationController,
|
||||||
required this.useMoveAnimation,
|
required this.useMoveAnimation,
|
||||||
|
required this.draggable,
|
||||||
this.onAccept,
|
this.onAccept,
|
||||||
this.onLeave,
|
this.onLeave,
|
||||||
this.draggableTargetBuilder,
|
this.draggableTargetBuilder,
|
||||||
@ -132,6 +134,9 @@ class _ReorderDragTargetState<T extends DragTargetData>
|
|||||||
List<T?> acceptedCandidates,
|
List<T?> acceptedCandidates,
|
||||||
List<dynamic> rejectedCandidates,
|
List<dynamic> rejectedCandidates,
|
||||||
) {
|
) {
|
||||||
|
if (!widget.draggable) {
|
||||||
|
return widget.child;
|
||||||
|
}
|
||||||
Widget feedbackBuilder = Builder(builder: (BuildContext context) {
|
Widget feedbackBuilder = Builder(builder: (BuildContext context) {
|
||||||
BoxConstraints contentSizeConstraints =
|
BoxConstraints contentSizeConstraints =
|
||||||
BoxConstraints.loose(_draggingFeedbackSize!);
|
BoxConstraints.loose(_draggingFeedbackSize!);
|
||||||
|
@ -131,6 +131,7 @@ class CrossReorderFlexDragTargetInterceptor extends DragTargetInterceptor {
|
|||||||
final String reorderFlexId;
|
final String reorderFlexId;
|
||||||
final List<String> acceptedReorderFlexIds;
|
final List<String> acceptedReorderFlexIds;
|
||||||
final CrossReorderFlexDragTargetDelegate delegate;
|
final CrossReorderFlexDragTargetDelegate delegate;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
final ReorderFlexDraggableTargetBuilder? draggableTargetBuilder;
|
final ReorderFlexDraggableTargetBuilder? draggableTargetBuilder;
|
||||||
|
|
||||||
@ -188,7 +189,7 @@ class CrossReorderFlexDragTargetInterceptor extends DragTargetInterceptor {
|
|||||||
);
|
);
|
||||||
|
|
||||||
Log.debug(
|
Log.debug(
|
||||||
'[$CrossReorderFlexDragTargetInterceptor] dargTargetIndex: $dragTargetIndex, reorderFlexId: $reorderFlexId');
|
'[$CrossReorderFlexDragTargetInterceptor] isNewDragTarget: $isNewDragTarget, dargTargetIndex: $dragTargetIndex, reorderFlexId: $reorderFlexId');
|
||||||
|
|
||||||
if (isNewDragTarget == false) {
|
if (isNewDragTarget == false) {
|
||||||
delegate.updateDragTargetData(reorderFlexId, dragTargetIndex);
|
delegate.updateDragTargetData(reorderFlexId, dragTargetIndex);
|
||||||
|
@ -82,6 +82,8 @@ class ReorderFlex extends StatefulWidget {
|
|||||||
|
|
||||||
final ReorderDragTargetIndexKeyStorage? dragTargetIndexKeyStorage;
|
final ReorderDragTargetIndexKeyStorage? dragTargetIndexKeyStorage;
|
||||||
|
|
||||||
|
final bool reorderable;
|
||||||
|
|
||||||
ReorderFlex({
|
ReorderFlex({
|
||||||
Key? key,
|
Key? key,
|
||||||
this.scrollController,
|
this.scrollController,
|
||||||
@ -89,6 +91,7 @@ class ReorderFlex extends StatefulWidget {
|
|||||||
required this.children,
|
required this.children,
|
||||||
required this.config,
|
required this.config,
|
||||||
required this.onReorder,
|
required this.onReorder,
|
||||||
|
this.reorderable = true,
|
||||||
this.dragStateStorage,
|
this.dragStateStorage,
|
||||||
this.dragTargetIndexKeyStorage,
|
this.dragTargetIndexKeyStorage,
|
||||||
this.onDragStarted,
|
this.onDragStarted,
|
||||||
@ -378,14 +381,13 @@ class ReorderFlexState extends State<ReorderFlex>
|
|||||||
dragState.currentIndex,
|
dragState.currentIndex,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
dragState.endDragging();
|
dragState.endDragging();
|
||||||
widget.onDragEnded?.call();
|
widget.onDragEnded?.call();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
onWillAccept: (FlexDragTargetData dragTargetData) {
|
onWillAccept: (FlexDragTargetData dragTargetData) {
|
||||||
// Do not receive any events if the Insert item is animating.
|
// Do not receive any events if the Insert item is animating.
|
||||||
if (_animation.deleteController.isAnimating) {
|
if (_animation.insertController.isAnimating) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -421,6 +423,7 @@ class ReorderFlexState extends State<ReorderFlex>
|
|||||||
deleteAnimationController: _animation.deleteController,
|
deleteAnimationController: _animation.deleteController,
|
||||||
draggableTargetBuilder: widget.interceptor?.draggableTargetBuilder,
|
draggableTargetBuilder: widget.interceptor?.draggableTargetBuilder,
|
||||||
useMoveAnimation: widget.config.useMoveAnimation,
|
useMoveAnimation: widget.config.useMoveAnimation,
|
||||||
|
draggable: widget.reorderable,
|
||||||
child: child,
|
child: child,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
|
import 'package:appflowy_board/appflowy_board.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
import '../../utils/log.dart';
|
import '../../utils/log.dart';
|
||||||
import '../board_column/board_column_data.dart';
|
|
||||||
import '../reorder_flex/drag_state.dart';
|
import '../reorder_flex/drag_state.dart';
|
||||||
import '../reorder_flex/drag_target.dart';
|
import '../reorder_flex/drag_target.dart';
|
||||||
import '../reorder_flex/drag_target_interceptor.dart';
|
import '../reorder_flex/drag_target_interceptor.dart';
|
||||||
@ -39,8 +39,12 @@ class BoardPhantomController extends OverlapDragTargetDelegate
|
|||||||
with CrossReorderFlexDragTargetDelegate {
|
with CrossReorderFlexDragTargetDelegate {
|
||||||
PhantomRecord? phantomRecord;
|
PhantomRecord? phantomRecord;
|
||||||
final BoardPhantomControllerDelegate delegate;
|
final BoardPhantomControllerDelegate delegate;
|
||||||
final columnsState = ColumnPhantomStateController();
|
final BoardColumnsState columnsState;
|
||||||
BoardPhantomController({required this.delegate});
|
final phantomState = ColumnPhantomState();
|
||||||
|
BoardPhantomController({
|
||||||
|
required this.delegate,
|
||||||
|
required this.columnsState,
|
||||||
|
});
|
||||||
|
|
||||||
bool isFromColumn(String columnId) {
|
bool isFromColumn(String columnId) {
|
||||||
if (phantomRecord != null) {
|
if (phantomRecord != null) {
|
||||||
@ -59,19 +63,19 @@ class BoardPhantomController extends OverlapDragTargetDelegate
|
|||||||
}
|
}
|
||||||
|
|
||||||
void columnStartDragging(String columnId) {
|
void columnStartDragging(String columnId) {
|
||||||
columnsState.setColumnIsDragging(columnId, true);
|
phantomState.setColumnIsDragging(columnId, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Remove the phantom in the column when the column is end dragging.
|
/// Remove the phantom in the column when the column is end dragging.
|
||||||
void columnEndDragging(String columnId) {
|
void columnEndDragging(String columnId) {
|
||||||
columnsState.setColumnIsDragging(columnId, false);
|
phantomState.setColumnIsDragging(columnId, false);
|
||||||
|
|
||||||
if (phantomRecord == null) return;
|
if (phantomRecord == null) return;
|
||||||
|
|
||||||
final fromColumnId = phantomRecord!.fromColumnId;
|
final fromColumnId = phantomRecord!.fromColumnId;
|
||||||
final toColumnId = phantomRecord!.toColumnId;
|
final toColumnId = phantomRecord!.toColumnId;
|
||||||
if (fromColumnId == columnId) {
|
if (fromColumnId == columnId) {
|
||||||
columnsState.notifyDidRemovePhantom(toColumnId);
|
phantomState.notifyDidRemovePhantom(toColumnId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (phantomRecord!.toColumnId == columnId) {
|
if (phantomRecord!.toColumnId == columnId) {
|
||||||
@ -82,8 +86,8 @@ class BoardPhantomController extends OverlapDragTargetDelegate
|
|||||||
phantomRecord!.toColumnIndex,
|
phantomRecord!.toColumnIndex,
|
||||||
);
|
);
|
||||||
|
|
||||||
Log.debug(
|
// Log.debug(
|
||||||
"[$BoardPhantomController] did move ${phantomRecord.toString()}");
|
// "[$BoardPhantomController] did move ${phantomRecord.toString()}");
|
||||||
phantomRecord = null;
|
phantomRecord = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -91,8 +95,8 @@ class BoardPhantomController extends OverlapDragTargetDelegate
|
|||||||
/// Remove the phantom in the column if it contains phantom
|
/// Remove the phantom in the column if it contains phantom
|
||||||
void _removePhantom(String columnId) {
|
void _removePhantom(String columnId) {
|
||||||
if (delegate.removePhantom(columnId)) {
|
if (delegate.removePhantom(columnId)) {
|
||||||
columnsState.notifyDidRemovePhantom(columnId);
|
phantomState.notifyDidRemovePhantom(columnId);
|
||||||
columnsState.removeColumnListener(columnId);
|
phantomState.removeColumnListener(columnId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,7 +109,7 @@ class BoardPhantomController extends OverlapDragTargetDelegate
|
|||||||
index: phantomIndex,
|
index: phantomIndex,
|
||||||
dragTargetData: dragTargetData,
|
dragTargetData: dragTargetData,
|
||||||
);
|
);
|
||||||
columnsState.addColumnListener(toColumnId, phantomContext);
|
phantomState.addColumnListener(toColumnId, phantomContext);
|
||||||
|
|
||||||
delegate.insertPhantom(
|
delegate.insertPhantom(
|
||||||
toColumnId,
|
toColumnId,
|
||||||
@ -113,7 +117,7 @@ class BoardPhantomController extends OverlapDragTargetDelegate
|
|||||||
PhantomColumnItem(phantomContext),
|
PhantomColumnItem(phantomContext),
|
||||||
);
|
);
|
||||||
|
|
||||||
columnsState.notifyDidInsertPhantom(toColumnId, phantomIndex);
|
phantomState.notifyDidInsertPhantom(toColumnId, phantomIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reset or initial the [PhantomRecord]
|
/// Reset or initial the [PhantomRecord]
|
||||||
@ -150,7 +154,8 @@ class BoardPhantomController extends OverlapDragTargetDelegate
|
|||||||
if (phantomRecord == null) {
|
if (phantomRecord == null) {
|
||||||
_resetPhantomRecord(reorderFlexId, dragTargetData, dragTargetIndex);
|
_resetPhantomRecord(reorderFlexId, dragTargetData, dragTargetIndex);
|
||||||
_insertPhantom(reorderFlexId, dragTargetData, dragTargetIndex);
|
_insertPhantom(reorderFlexId, dragTargetData, dragTargetIndex);
|
||||||
return false;
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
final isNewDragTarget = phantomRecord!.toColumnId != reorderFlexId;
|
final isNewDragTarget = phantomRecord!.toColumnId != reorderFlexId;
|
||||||
@ -204,7 +209,7 @@ class BoardPhantomController extends OverlapDragTargetDelegate
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
int getInsertedIndex(String dragTargetId) {
|
int getInsertedIndex(String dragTargetId) {
|
||||||
if (columnsState.isDragging(dragTargetId)) {
|
if (phantomState.isDragging(dragTargetId)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -243,8 +248,7 @@ class PhantomRecord {
|
|||||||
if (fromColumnIndex == index) {
|
if (fromColumnIndex == index) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Log.debug(
|
|
||||||
'[$PhantomRecord] Update Column:[$fromColumnId] remove position to $index');
|
|
||||||
fromColumnIndex = index;
|
fromColumnIndex = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import 'phantom_controller.dart';
|
import 'phantom_controller.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class ColumnPhantomStateController {
|
class ColumnPhantomState {
|
||||||
final _states = <String, ColumnState>{};
|
final _states = <String, ColumnState>{};
|
||||||
|
|
||||||
void setColumnIsDragging(String columnId, bool isDragging) {
|
void setColumnIsDragging(String columnId, bool isDragging) {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
name: appflowy_board
|
name: appflowy_board
|
||||||
description: AppFlowy board implementation.
|
description: AppFlowy board implementation.
|
||||||
version: 0.0.5
|
version: 0.0.6
|
||||||
homepage: https://github.com/AppFlowy-IO/AppFlowy
|
homepage: https://github.com/AppFlowy-IO/AppFlowy
|
||||||
repository: https://github.com/AppFlowy-IO/AppFlowy/tree/main/frontend/app_flowy/packages/appflowy_board
|
repository: https://github.com/AppFlowy-IO/AppFlowy/tree/main/frontend/app_flowy/packages/appflowy_board
|
||||||
|
|
||||||
|
@ -120,17 +120,28 @@ pub struct InsertedRowPB {
|
|||||||
|
|
||||||
#[pb(index = 2, one_of)]
|
#[pb(index = 2, one_of)]
|
||||||
pub index: Option<i32>,
|
pub index: Option<i32>,
|
||||||
|
|
||||||
|
#[pb(index = 3)]
|
||||||
|
pub is_new: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InsertedRowPB {
|
impl InsertedRowPB {
|
||||||
pub fn new(row: RowPB) -> Self {
|
pub fn new(row: RowPB) -> Self {
|
||||||
Self { row, index: None }
|
Self {
|
||||||
|
row,
|
||||||
|
index: None,
|
||||||
|
is_new: false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::convert::From<RowPB> for InsertedRowPB {
|
impl std::convert::From<RowPB> for InsertedRowPB {
|
||||||
fn from(row: RowPB) -> Self {
|
fn from(row: RowPB) -> Self {
|
||||||
Self { row, index: None }
|
Self {
|
||||||
|
row,
|
||||||
|
index: None,
|
||||||
|
is_new: false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,6 +164,7 @@ impl GridBlockManager {
|
|||||||
let insert_row = InsertedRowPB {
|
let insert_row = InsertedRowPB {
|
||||||
index: Some(to as i32),
|
index: Some(to as i32),
|
||||||
row: make_row_from_row_rev(row_rev),
|
row: make_row_from_row_rev(row_rev),
|
||||||
|
is_new: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
let notified_changeset = GridBlockChangesetPB {
|
let notified_changeset = GridBlockChangesetPB {
|
||||||
|
@ -98,6 +98,7 @@ impl GridViewRevisionEditor {
|
|||||||
let inserted_row = InsertedRowPB {
|
let inserted_row = InsertedRowPB {
|
||||||
row: row_pb.clone(),
|
row: row_pb.clone(),
|
||||||
index: None,
|
index: None,
|
||||||
|
is_new: true,
|
||||||
};
|
};
|
||||||
let changeset = GroupChangesetPB::insert(group_id.clone(), vec![inserted_row]);
|
let changeset = GroupChangesetPB::insert(group_id.clone(), vec![inserted_row]);
|
||||||
self.notify_did_update_group(changeset).await;
|
self.notify_did_update_group(changeset).await;
|
||||||
|
Loading…
Reference in New Issue
Block a user