mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2025-04-24 22:57:12 -04:00
Merge pull request #1001 from AppFlowy-IO/merge/release_005
Merge/release 005
This commit is contained in:
commit
3d2bfcc7c1
20 changed files with 284 additions and 250 deletions
|
@ -99,7 +99,6 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
endEditRow: (rowId) {
|
endEditRow: (rowId) {
|
||||||
assert(state.editingRow.isSome());
|
|
||||||
state.editingRow.fold(() => null, (editingRow) {
|
state.editingRow.fold(() => null, (editingRow) {
|
||||||
assert(editingRow.row.id == rowId);
|
assert(editingRow.row.id == rowId);
|
||||||
emit(state.copyWith(editingRow: none()));
|
emit(state.copyWith(editingRow: none()));
|
||||||
|
|
|
@ -7,20 +7,20 @@ import 'package:flowy_sdk/protobuf/flowy-grid/block_entities.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 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'card_data_controller.dart';
|
import 'card_data_controller.dart';
|
||||||
|
|
||||||
part 'card_bloc.freezed.dart';
|
part 'card_bloc.freezed.dart';
|
||||||
|
|
||||||
class BoardCardBloc extends Bloc<BoardCardEvent, BoardCardState> {
|
class BoardCardBloc extends Bloc<BoardCardEvent, BoardCardState> {
|
||||||
final String fieldId;
|
final String groupFieldId;
|
||||||
final RowFFIService _rowService;
|
final RowFFIService _rowService;
|
||||||
final CardDataController _dataController;
|
final CardDataController _dataController;
|
||||||
|
|
||||||
BoardCardBloc({
|
BoardCardBloc({
|
||||||
required this.fieldId,
|
required this.groupFieldId,
|
||||||
required String gridId,
|
required String gridId,
|
||||||
required CardDataController dataController,
|
required CardDataController dataController,
|
||||||
|
required bool isEditing,
|
||||||
}) : _rowService = RowFFIService(
|
}) : _rowService = RowFFIService(
|
||||||
gridId: gridId,
|
gridId: gridId,
|
||||||
blockId: dataController.rowPB.blockId,
|
blockId: dataController.rowPB.blockId,
|
||||||
|
@ -29,7 +29,8 @@ class BoardCardBloc extends Bloc<BoardCardEvent, BoardCardState> {
|
||||||
super(
|
super(
|
||||||
BoardCardState.initial(
|
BoardCardState.initial(
|
||||||
dataController.rowPB,
|
dataController.rowPB,
|
||||||
_makeCells(fieldId, dataController.loadData()),
|
_makeCells(groupFieldId, dataController.loadData()),
|
||||||
|
isEditing,
|
||||||
),
|
),
|
||||||
) {
|
) {
|
||||||
on<BoardCardEvent>(
|
on<BoardCardEvent>(
|
||||||
|
@ -44,6 +45,9 @@ class BoardCardBloc extends Bloc<BoardCardEvent, BoardCardState> {
|
||||||
changeReason: reason,
|
changeReason: reason,
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
|
setIsEditing: (bool isEditing) {
|
||||||
|
emit(state.copyWith(isEditing: isEditing));
|
||||||
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -69,7 +73,7 @@ class BoardCardBloc extends Bloc<BoardCardEvent, BoardCardState> {
|
||||||
_dataController.addListener(
|
_dataController.addListener(
|
||||||
onRowChanged: (cellMap, reason) {
|
onRowChanged: (cellMap, reason) {
|
||||||
if (!isClosed) {
|
if (!isClosed) {
|
||||||
final cells = _makeCells(fieldId, cellMap);
|
final cells = _makeCells(groupFieldId, cellMap);
|
||||||
add(BoardCardEvent.didReceiveCells(cells, reason));
|
add(BoardCardEvent.didReceiveCells(cells, reason));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -77,22 +81,24 @@ class BoardCardBloc extends Bloc<BoardCardEvent, BoardCardState> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UnmodifiableListView<BoardCellEquatable> _makeCells(
|
List<BoardCellEquatable> _makeCells(
|
||||||
String fieldId, GridCellMap originalCellMap) {
|
String groupFieldId, GridCellMap originalCellMap) {
|
||||||
List<BoardCellEquatable> cells = [];
|
List<BoardCellEquatable> cells = [];
|
||||||
for (final entry in originalCellMap.entries) {
|
for (final entry in originalCellMap.entries) {
|
||||||
if (entry.value.fieldId != fieldId) {
|
// Filter out the cell if it's fieldId equal to the groupFieldId
|
||||||
|
if (entry.value.fieldId != groupFieldId) {
|
||||||
cells.add(BoardCellEquatable(entry.value));
|
cells.add(BoardCellEquatable(entry.value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return UnmodifiableListView(cells);
|
return cells;
|
||||||
}
|
}
|
||||||
|
|
||||||
@freezed
|
@freezed
|
||||||
class BoardCardEvent with _$BoardCardEvent {
|
class BoardCardEvent with _$BoardCardEvent {
|
||||||
const factory BoardCardEvent.initial() = _InitialRow;
|
const factory BoardCardEvent.initial() = _InitialRow;
|
||||||
|
const factory BoardCardEvent.setIsEditing(bool isEditing) = _IsEditing;
|
||||||
const factory BoardCardEvent.didReceiveCells(
|
const factory BoardCardEvent.didReceiveCells(
|
||||||
UnmodifiableListView<BoardCellEquatable> cells,
|
List<BoardCellEquatable> cells,
|
||||||
RowsChangedReason reason,
|
RowsChangedReason reason,
|
||||||
) = _DidReceiveCells;
|
) = _DidReceiveCells;
|
||||||
}
|
}
|
||||||
|
@ -101,15 +107,20 @@ class BoardCardEvent with _$BoardCardEvent {
|
||||||
class BoardCardState with _$BoardCardState {
|
class BoardCardState with _$BoardCardState {
|
||||||
const factory BoardCardState({
|
const factory BoardCardState({
|
||||||
required RowPB rowPB,
|
required RowPB rowPB,
|
||||||
required UnmodifiableListView<BoardCellEquatable> cells,
|
required List<BoardCellEquatable> cells,
|
||||||
|
required bool isEditing,
|
||||||
RowsChangedReason? changeReason,
|
RowsChangedReason? changeReason,
|
||||||
}) = _BoardCardState;
|
}) = _BoardCardState;
|
||||||
|
|
||||||
factory BoardCardState.initial(
|
factory BoardCardState.initial(
|
||||||
RowPB rowPB, UnmodifiableListView<BoardCellEquatable> cells) =>
|
RowPB rowPB,
|
||||||
|
List<BoardCellEquatable> cells,
|
||||||
|
bool isEditing,
|
||||||
|
) =>
|
||||||
BoardCardState(
|
BoardCardState(
|
||||||
rowPB: rowPB,
|
rowPB: rowPB,
|
||||||
cells: cells,
|
cells: cells,
|
||||||
|
isEditing: isEditing,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,10 +130,12 @@ class BoardCellEquatable extends Equatable {
|
||||||
const BoardCellEquatable(this.identifier);
|
const BoardCellEquatable(this.identifier);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object?> get props => [
|
List<Object?> get props {
|
||||||
identifier.fieldContext.id,
|
return [
|
||||||
identifier.fieldContext.fieldType,
|
identifier.fieldContext.id,
|
||||||
identifier.fieldContext.visibility,
|
identifier.fieldContext.fieldType,
|
||||||
identifier.fieldContext.width,
|
identifier.fieldContext.visibility,
|
||||||
];
|
identifier.fieldContext.width,
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,6 +64,7 @@ class BoardContent extends StatefulWidget {
|
||||||
|
|
||||||
class _BoardContentState extends State<BoardContent> {
|
class _BoardContentState extends State<BoardContent> {
|
||||||
late AppFlowyBoardScrollController scrollManager;
|
late AppFlowyBoardScrollController scrollManager;
|
||||||
|
final Map<String, ValueKey> cardKeysCache = {};
|
||||||
|
|
||||||
final config = AppFlowyBoardConfig(
|
final config = AppFlowyBoardConfig(
|
||||||
groupBackgroundColor: HexColor.fromHex('#F7F8FC'),
|
groupBackgroundColor: HexColor.fromHex('#F7F8FC'),
|
||||||
|
@ -83,6 +84,7 @@ class _BoardContentState extends State<BoardContent> {
|
||||||
buildWhen: (previous, current) => previous.groupIds != current.groupIds,
|
buildWhen: (previous, current) => previous.groupIds != current.groupIds,
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
final column = Column(
|
final column = Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [const _ToolbarBlocAdaptor(), _buildBoard(context)],
|
children: [const _ToolbarBlocAdaptor(), _buildBoard(context)],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -240,8 +242,15 @@ class _BoardContentState extends State<BoardContent> {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
ValueKey? key = cardKeysCache[columnItem.id];
|
||||||
|
if (key == null) {
|
||||||
|
final newKey = ValueKey(columnItem.id);
|
||||||
|
cardKeysCache[columnItem.id] = newKey;
|
||||||
|
key = newKey;
|
||||||
|
}
|
||||||
|
|
||||||
return AppFlowyGroupCard(
|
return AppFlowyGroupCard(
|
||||||
key: ValueKey(columnItem.id),
|
key: key,
|
||||||
margin: config.cardPadding,
|
margin: config.cardPadding,
|
||||||
decoration: _makeBoxDecoration(context),
|
decoration: _makeBoxDecoration(context),
|
||||||
child: BoardCard(
|
child: BoardCard(
|
||||||
|
|
|
@ -1,47 +1,74 @@
|
||||||
import 'package:app_flowy/plugins/grid/application/prelude.dart';
|
import 'package:app_flowy/plugins/grid/application/prelude.dart';
|
||||||
import 'package:flowy_infra/notifier.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
abstract class FocusableBoardCell {
|
abstract class FocusableBoardCell {
|
||||||
set becomeFocus(bool isFocus);
|
set becomeFocus(bool isFocus);
|
||||||
}
|
}
|
||||||
|
|
||||||
class EditableCellNotifier {
|
class EditableCellNotifier {
|
||||||
final Notifier becomeFirstResponder = Notifier();
|
final ValueNotifier<bool> isCellEditing;
|
||||||
|
|
||||||
final Notifier resignFirstResponder = Notifier();
|
EditableCellNotifier({bool isEditing = false})
|
||||||
|
: isCellEditing = ValueNotifier(isEditing);
|
||||||
|
|
||||||
EditableCellNotifier();
|
void dispose() {
|
||||||
|
isCellEditing.dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class EditableRowNotifier {
|
class EditableRowNotifier {
|
||||||
final Map<EditableCellId, EditableCellNotifier> _cells = {};
|
final Map<EditableCellId, EditableCellNotifier> _cells = {};
|
||||||
|
final ValueNotifier<bool> isEditing;
|
||||||
|
|
||||||
|
EditableRowNotifier({required bool isEditing})
|
||||||
|
: isEditing = ValueNotifier(isEditing);
|
||||||
|
|
||||||
void insertCell(
|
void insertCell(
|
||||||
GridCellIdentifier cellIdentifier,
|
GridCellIdentifier cellIdentifier,
|
||||||
EditableCellNotifier notifier,
|
EditableCellNotifier notifier,
|
||||||
) {
|
) {
|
||||||
|
assert(
|
||||||
|
_cells.values.isEmpty,
|
||||||
|
'Only one cell can receive the notification',
|
||||||
|
);
|
||||||
|
final id = EditableCellId.from(cellIdentifier);
|
||||||
|
_cells[id]?.dispose();
|
||||||
|
|
||||||
|
notifier.isCellEditing.addListener(() {
|
||||||
|
isEditing.value = notifier.isCellEditing.value;
|
||||||
|
});
|
||||||
|
|
||||||
_cells[EditableCellId.from(cellIdentifier)] = notifier;
|
_cells[EditableCellId.from(cellIdentifier)] = notifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
void becomeFirstResponder() {
|
void becomeFirstResponder() {
|
||||||
for (final notifier in _cells.values) {
|
if (_cells.values.isEmpty) return;
|
||||||
notifier.becomeFirstResponder.notify();
|
assert(
|
||||||
}
|
_cells.values.length == 1,
|
||||||
|
'Only one cell can receive the notification',
|
||||||
|
);
|
||||||
|
_cells.values.first.isCellEditing.value = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void resignFirstResponder() {
|
void resignFirstResponder() {
|
||||||
for (final notifier in _cells.values) {
|
if (_cells.values.isEmpty) return;
|
||||||
notifier.resignFirstResponder.notify();
|
assert(
|
||||||
}
|
_cells.values.length == 1,
|
||||||
|
'Only one cell can receive the notification',
|
||||||
|
);
|
||||||
|
_cells.values.first.isCellEditing.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear() {
|
void clear() {
|
||||||
|
for (final notifier in _cells.values) {
|
||||||
|
notifier.dispose();
|
||||||
|
}
|
||||||
_cells.clear();
|
_cells.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void dispose() {
|
void dispose() {
|
||||||
for (final notifier in _cells.values) {
|
for (final notifier in _cells.values) {
|
||||||
notifier.resignFirstResponder.notify();
|
notifier.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
_cells.clear();
|
_cells.clear();
|
||||||
|
|
|
@ -5,6 +5,8 @@ import 'package:flowy_infra_ui/style_widget/text.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 'define.dart';
|
||||||
|
|
||||||
class BoardDateCell extends StatefulWidget {
|
class BoardDateCell extends StatefulWidget {
|
||||||
final String groupId;
|
final String groupId;
|
||||||
final GridCellControllerBuilder cellControllerBuilder;
|
final GridCellControllerBuilder cellControllerBuilder;
|
||||||
|
@ -44,10 +46,15 @@ class _BoardDateCellState extends State<BoardDateCell> {
|
||||||
} else {
|
} else {
|
||||||
return Align(
|
return Align(
|
||||||
alignment: Alignment.centerLeft,
|
alignment: Alignment.centerLeft,
|
||||||
child: FlowyText.regular(
|
child: Padding(
|
||||||
state.dateStr,
|
padding: EdgeInsets.symmetric(
|
||||||
fontSize: 13,
|
vertical: BoardSizes.cardCellVPadding,
|
||||||
color: context.read<AppTheme>().shader3,
|
),
|
||||||
|
child: FlowyText.regular(
|
||||||
|
state.dateStr,
|
||||||
|
fontSize: 13,
|
||||||
|
color: context.read<AppTheme>().shader3,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,8 @@ import 'package:flowy_infra_ui/style_widget/text.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 'define.dart';
|
||||||
|
|
||||||
class BoardNumberCell extends StatefulWidget {
|
class BoardNumberCell extends StatefulWidget {
|
||||||
final String groupId;
|
final String groupId;
|
||||||
final GridCellControllerBuilder cellControllerBuilder;
|
final GridCellControllerBuilder cellControllerBuilder;
|
||||||
|
@ -43,9 +45,14 @@ class _BoardNumberCellState extends State<BoardNumberCell> {
|
||||||
} else {
|
} else {
|
||||||
return Align(
|
return Align(
|
||||||
alignment: Alignment.centerLeft,
|
alignment: Alignment.centerLeft,
|
||||||
child: FlowyText.medium(
|
child: Padding(
|
||||||
state.content,
|
padding: EdgeInsets.symmetric(
|
||||||
fontSize: 14,
|
vertical: BoardSizes.cardCellVPadding,
|
||||||
|
),
|
||||||
|
child: FlowyText.medium(
|
||||||
|
state.content,
|
||||||
|
fontSize: 14,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,23 +56,23 @@ class _BoardSelectOptionCellState extends State<BoardSelectOptionCell> {
|
||||||
(option) => SelectOptionTag.fromOption(
|
(option) => SelectOptionTag.fromOption(
|
||||||
context: context,
|
context: context,
|
||||||
option: option,
|
option: option,
|
||||||
|
onSelected: () {
|
||||||
|
SelectOptionCellEditor.show(
|
||||||
|
context: context,
|
||||||
|
cellController: widget.cellControllerBuilder.build()
|
||||||
|
as GridSelectOptionCellController,
|
||||||
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
return IntrinsicHeight(
|
return IntrinsicHeight(
|
||||||
child: Stack(
|
child: Padding(
|
||||||
alignment: AlignmentDirectional.center,
|
padding: const EdgeInsets.symmetric(vertical: 6),
|
||||||
fit: StackFit.expand,
|
child: SizedBox.expand(
|
||||||
children: [
|
child: Wrap(spacing: 4, runSpacing: 2, children: children),
|
||||||
Padding(
|
),
|
||||||
padding: const EdgeInsets.symmetric(vertical: 6),
|
|
||||||
child: Wrap(spacing: 4, runSpacing: 2, children: children),
|
|
||||||
),
|
|
||||||
_SelectOptionDialog(
|
|
||||||
controller: widget.cellControllerBuilder.build(),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -87,23 +87,3 @@ 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,
|
|
||||||
() {},
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -9,7 +9,6 @@ import 'define.dart';
|
||||||
|
|
||||||
class BoardTextCell extends StatefulWidget with EditableCell {
|
class BoardTextCell extends StatefulWidget with EditableCell {
|
||||||
final String groupId;
|
final String groupId;
|
||||||
final bool isFocus;
|
|
||||||
@override
|
@override
|
||||||
final EditableCellNotifier? editableNotifier;
|
final EditableCellNotifier? editableNotifier;
|
||||||
final GridCellControllerBuilder cellControllerBuilder;
|
final GridCellControllerBuilder cellControllerBuilder;
|
||||||
|
@ -18,7 +17,6 @@ class BoardTextCell extends StatefulWidget with EditableCell {
|
||||||
required this.groupId,
|
required this.groupId,
|
||||||
required this.cellControllerBuilder,
|
required this.cellControllerBuilder,
|
||||||
this.editableNotifier,
|
this.editableNotifier,
|
||||||
this.isFocus = false,
|
|
||||||
Key? key,
|
Key? key,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@ -39,40 +37,42 @@ class _BoardTextCellState extends State<BoardTextCell> {
|
||||||
_cellBloc = BoardTextCellBloc(cellController: cellController)
|
_cellBloc = BoardTextCellBloc(cellController: cellController)
|
||||||
..add(const BoardTextCellEvent.initial());
|
..add(const BoardTextCellEvent.initial());
|
||||||
_controller = TextEditingController(text: _cellBloc.state.content);
|
_controller = TextEditingController(text: _cellBloc.state.content);
|
||||||
focusWhenInit = widget.isFocus;
|
focusWhenInit = widget.editableNotifier?.isCellEditing.value ?? false;
|
||||||
|
if (focusWhenInit) {
|
||||||
if (widget.isFocus) {
|
|
||||||
focusNode.requestFocus();
|
focusNode.requestFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
focusNode.addListener(() {
|
focusNode.addListener(() {
|
||||||
if (!focusNode.hasFocus) {
|
if (!focusNode.hasFocus) {
|
||||||
|
focusWhenInit = false;
|
||||||
|
widget.editableNotifier?.isCellEditing.value = false;
|
||||||
_cellBloc.add(const BoardTextCellEvent.enableEdit(false));
|
_cellBloc.add(const BoardTextCellEvent.enableEdit(false));
|
||||||
|
|
||||||
if (focusWhenInit) {
|
|
||||||
setState(() {
|
|
||||||
focusWhenInit = false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
_bindEditableNotifier();
|
||||||
widget.editableNotifier?.becomeFirstResponder.addListener(() {
|
|
||||||
if (!mounted) return;
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
||||||
focusNode.requestFocus();
|
|
||||||
});
|
|
||||||
_cellBloc.add(const BoardTextCellEvent.enableEdit(true));
|
|
||||||
});
|
|
||||||
|
|
||||||
widget.editableNotifier?.resignFirstResponder.addListener(() {
|
|
||||||
if (!mounted) return;
|
|
||||||
_cellBloc.add(const BoardTextCellEvent.enableEdit(false));
|
|
||||||
});
|
|
||||||
|
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _bindEditableNotifier() {
|
||||||
|
widget.editableNotifier?.isCellEditing.addListener(() {
|
||||||
|
if (!mounted) return;
|
||||||
|
|
||||||
|
final isEditing = widget.editableNotifier?.isCellEditing.value ?? false;
|
||||||
|
if (isEditing) {
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
focusNode.requestFocus();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
_cellBloc.add(BoardTextCellEvent.enableEdit(isEditing));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didUpdateWidget(covariant BoardTextCell oldWidget) {
|
||||||
|
_bindEditableNotifier();
|
||||||
|
super.didUpdateWidget(oldWidget);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocProvider.value(
|
return BlocProvider.value(
|
||||||
|
@ -84,6 +84,15 @@ class _BoardTextCellState extends State<BoardTextCell> {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: BlocBuilder<BoardTextCellBloc, BoardTextCellState>(
|
child: BlocBuilder<BoardTextCellBloc, BoardTextCellState>(
|
||||||
|
buildWhen: (previous, current) {
|
||||||
|
if (previous.content != current.content &&
|
||||||
|
_controller.text == current.content &&
|
||||||
|
current.enableEdit) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return previous != current;
|
||||||
|
},
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
if (state.content.isEmpty &&
|
if (state.content.isEmpty &&
|
||||||
state.enableEdit == false &&
|
state.enableEdit == false &&
|
||||||
|
@ -127,24 +136,26 @@ class _BoardTextCellState extends State<BoardTextCell> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildTextField() {
|
Widget _buildTextField() {
|
||||||
return TextField(
|
return IntrinsicHeight(
|
||||||
controller: _controller,
|
child: TextField(
|
||||||
focusNode: focusNode,
|
controller: _controller,
|
||||||
onChanged: (value) => focusChanged(),
|
focusNode: focusNode,
|
||||||
onEditingComplete: () => focusNode.unfocus(),
|
onChanged: (value) => focusChanged(),
|
||||||
maxLines: 1,
|
onEditingComplete: () => focusNode.unfocus(),
|
||||||
style: const TextStyle(
|
maxLines: null,
|
||||||
fontSize: 14,
|
style: const TextStyle(
|
||||||
fontWeight: FontWeight.w500,
|
fontSize: 14,
|
||||||
fontFamily: 'Mulish',
|
fontWeight: FontWeight.w500,
|
||||||
),
|
fontFamily: 'Mulish',
|
||||||
decoration: InputDecoration(
|
),
|
||||||
// Magic number 4 makes the textField take up the same space as FlowyText
|
decoration: InputDecoration(
|
||||||
contentPadding: EdgeInsets.symmetric(
|
// Magic number 4 makes the textField take up the same space as FlowyText
|
||||||
vertical: BoardSizes.cardCellVPadding + 4,
|
contentPadding: EdgeInsets.symmetric(
|
||||||
|
vertical: BoardSizes.cardCellVPadding + 4,
|
||||||
|
),
|
||||||
|
border: InputBorder.none,
|
||||||
|
isDense: true,
|
||||||
),
|
),
|
||||||
border: InputBorder.none,
|
|
||||||
isDense: true,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,8 @@ import 'package:flowy_infra/theme.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 'define.dart';
|
||||||
|
|
||||||
class BoardUrlCell extends StatefulWidget {
|
class BoardUrlCell extends StatefulWidget {
|
||||||
final String groupId;
|
final String groupId;
|
||||||
final GridCellControllerBuilder cellControllerBuilder;
|
final GridCellControllerBuilder cellControllerBuilder;
|
||||||
|
@ -43,14 +45,19 @@ class _BoardUrlCellState extends State<BoardUrlCell> {
|
||||||
} else {
|
} else {
|
||||||
return Align(
|
return Align(
|
||||||
alignment: Alignment.centerLeft,
|
alignment: Alignment.centerLeft,
|
||||||
child: RichText(
|
child: Padding(
|
||||||
textAlign: TextAlign.left,
|
padding: EdgeInsets.symmetric(
|
||||||
text: TextSpan(
|
vertical: BoardSizes.cardCellVPadding,
|
||||||
text: state.content,
|
),
|
||||||
style: TextStyle(
|
child: RichText(
|
||||||
color: theme.main2,
|
textAlign: TextAlign.left,
|
||||||
fontSize: 14,
|
text: TextSpan(
|
||||||
decoration: TextDecoration.underline,
|
text: state.content,
|
||||||
|
style: TextStyle(
|
||||||
|
color: theme.main2,
|
||||||
|
fontSize: 14,
|
||||||
|
decoration: TextDecoration.underline,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -5,6 +5,7 @@ import 'package:app_flowy/plugins/grid/presentation/widgets/row/row_action_sheet
|
||||||
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_web.dart';
|
import 'package:flowy_infra_ui/flowy_infra_ui_web.dart';
|
||||||
|
import 'package:flutter/foundation.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 'board_cell.dart';
|
import 'board_cell.dart';
|
||||||
|
@ -41,12 +42,19 @@ class _BoardCardState extends State<BoardCard> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
rowNotifier = EditableRowNotifier();
|
rowNotifier = EditableRowNotifier(isEditing: widget.isEditing);
|
||||||
_cardBloc = BoardCardBloc(
|
_cardBloc = BoardCardBloc(
|
||||||
gridId: widget.gridId,
|
gridId: widget.gridId,
|
||||||
fieldId: widget.fieldId,
|
groupFieldId: widget.fieldId,
|
||||||
dataController: widget.dataController,
|
dataController: widget.dataController,
|
||||||
|
isEditing: widget.isEditing,
|
||||||
)..add(const BoardCardEvent.initial());
|
)..add(const BoardCardEvent.initial());
|
||||||
|
|
||||||
|
rowNotifier.isEditing.addListener(() {
|
||||||
|
if (!mounted) return;
|
||||||
|
_cardBloc.add(BoardCardEvent.setIsEditing(rowNotifier.isEditing.value));
|
||||||
|
});
|
||||||
|
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,10 +64,15 @@ class _BoardCardState extends State<BoardCard> {
|
||||||
value: _cardBloc,
|
value: _cardBloc,
|
||||||
child: BlocBuilder<BoardCardBloc, BoardCardState>(
|
child: BlocBuilder<BoardCardBloc, BoardCardState>(
|
||||||
buildWhen: (previous, current) {
|
buildWhen: (previous, current) {
|
||||||
return previous.cells.length != current.cells.length;
|
if (previous.cells.length != current.cells.length ||
|
||||||
|
previous.isEditing != current.isEditing) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return !listEquals(previous.cells, current.cells);
|
||||||
},
|
},
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
return BoardCardContainer(
|
return BoardCardContainer(
|
||||||
|
buildAccessoryWhen: () => state.isEditing == false,
|
||||||
accessoryBuilder: (context) {
|
accessoryBuilder: (context) {
|
||||||
return [
|
return [
|
||||||
_CardEditOption(
|
_CardEditOption(
|
||||||
|
@ -92,17 +105,24 @@ class _BoardCardState extends State<BoardCard> {
|
||||||
rowNotifier.clear();
|
rowNotifier.clear();
|
||||||
cells.asMap().forEach(
|
cells.asMap().forEach(
|
||||||
(int index, GridCellIdentifier cellId) {
|
(int index, GridCellIdentifier cellId) {
|
||||||
final cellNotifier = EditableCellNotifier();
|
EditableCellNotifier cellNotifier;
|
||||||
|
if (index == 0) {
|
||||||
|
// Only use the first cell to receive user's input when click the edit
|
||||||
|
// button
|
||||||
|
cellNotifier = EditableCellNotifier(
|
||||||
|
isEditing: rowNotifier.isEditing.value,
|
||||||
|
);
|
||||||
|
rowNotifier.insertCell(cellId, cellNotifier);
|
||||||
|
} else {
|
||||||
|
cellNotifier = EditableCellNotifier();
|
||||||
|
}
|
||||||
|
|
||||||
Widget child = widget.cellBuilder.buildCell(
|
Widget child = widget.cellBuilder.buildCell(
|
||||||
widget.groupId,
|
widget.groupId,
|
||||||
cellId,
|
cellId,
|
||||||
index == 0 ? widget.isEditing : false,
|
|
||||||
cellNotifier,
|
cellNotifier,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (index == 0) {
|
|
||||||
rowNotifier.insertCell(cellId, cellNotifier);
|
|
||||||
}
|
|
||||||
child = Padding(
|
child = Padding(
|
||||||
key: cellId.key(),
|
key: cellId.key(),
|
||||||
padding: const EdgeInsets.only(left: 4, right: 4),
|
padding: const EdgeInsets.only(left: 4, right: 4),
|
||||||
|
|
|
@ -23,7 +23,6 @@ class BoardCellBuilder {
|
||||||
Widget buildCell(
|
Widget buildCell(
|
||||||
String groupId,
|
String groupId,
|
||||||
GridCellIdentifier cellId,
|
GridCellIdentifier cellId,
|
||||||
bool isEditing,
|
|
||||||
EditableCellNotifier cellNotifier,
|
EditableCellNotifier cellNotifier,
|
||||||
) {
|
) {
|
||||||
final cellControllerBuilder = GridCellControllerBuilder(
|
final cellControllerBuilder = GridCellControllerBuilder(
|
||||||
|
@ -69,7 +68,6 @@ class BoardCellBuilder {
|
||||||
return BoardTextCell(
|
return BoardTextCell(
|
||||||
groupId: groupId,
|
groupId: groupId,
|
||||||
cellControllerBuilder: cellControllerBuilder,
|
cellControllerBuilder: cellControllerBuilder,
|
||||||
isFocus: isEditing,
|
|
||||||
editableNotifier: cellNotifier,
|
editableNotifier: cellNotifier,
|
||||||
key: key,
|
key: key,
|
||||||
);
|
);
|
||||||
|
|
|
@ -7,11 +7,13 @@ import 'package:styled_widget/styled_widget.dart';
|
||||||
class BoardCardContainer extends StatelessWidget {
|
class BoardCardContainer extends StatelessWidget {
|
||||||
final Widget child;
|
final Widget child;
|
||||||
final CardAccessoryBuilder? accessoryBuilder;
|
final CardAccessoryBuilder? accessoryBuilder;
|
||||||
|
final bool Function()? buildAccessoryWhen;
|
||||||
final void Function(BuildContext) onTap;
|
final void Function(BuildContext) onTap;
|
||||||
const BoardCardContainer({
|
const BoardCardContainer({
|
||||||
required this.child,
|
required this.child,
|
||||||
required this.onTap,
|
required this.onTap,
|
||||||
this.accessoryBuilder,
|
this.accessoryBuilder,
|
||||||
|
this.buildAccessoryWhen,
|
||||||
Key? key,
|
Key? key,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@ -22,7 +24,12 @@ class BoardCardContainer extends StatelessWidget {
|
||||||
child: Consumer<_CardContainerNotifier>(
|
child: Consumer<_CardContainerNotifier>(
|
||||||
builder: (context, notifier, _) {
|
builder: (context, notifier, _) {
|
||||||
Widget container = Center(child: child);
|
Widget container = Center(child: child);
|
||||||
if (accessoryBuilder != null) {
|
bool shouldBuildAccessory = true;
|
||||||
|
if (buildAccessoryWhen != null) {
|
||||||
|
shouldBuildAccessory = buildAccessoryWhen!.call();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (accessoryBuilder != null && shouldBuildAccessory) {
|
||||||
final accessories = accessoryBuilder!(context);
|
final accessories = accessoryBuilder!(context);
|
||||||
if (accessories.isNotEmpty) {
|
if (accessories.isNotEmpty) {
|
||||||
container = _CardEnterRegion(
|
container = _CardEnterRegion(
|
||||||
|
|
|
@ -46,7 +46,8 @@ class _DateCellState extends GridCellState<GridDateCell> {
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
_popover = PopoverController();
|
_popover = PopoverController();
|
||||||
final cellController = widget.cellControllerBuilder.build();
|
final cellController =
|
||||||
|
widget.cellControllerBuilder.build() as GridDateCellController;
|
||||||
_cellBloc = getIt<DateCellBloc>(param1: cellController)
|
_cellBloc = getIt<DateCellBloc>(param1: cellController)
|
||||||
..add(const DateCellEvent.initial());
|
..add(const DateCellEvent.initial());
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
|
@ -27,13 +27,13 @@ const double _editorPannelWidth = 300;
|
||||||
|
|
||||||
class SelectOptionCellEditor extends StatelessWidget with FlowyOverlayDelegate {
|
class SelectOptionCellEditor extends StatelessWidget with FlowyOverlayDelegate {
|
||||||
final GridSelectOptionCellController cellController;
|
final GridSelectOptionCellController cellController;
|
||||||
final VoidCallback onDismissed;
|
final VoidCallback? onDismissed;
|
||||||
|
|
||||||
static double editorPanelWidth = 300;
|
static double editorPanelWidth = 300;
|
||||||
|
|
||||||
const SelectOptionCellEditor({
|
const SelectOptionCellEditor({
|
||||||
required this.cellController,
|
required this.cellController,
|
||||||
required this.onDismissed,
|
this.onDismissed,
|
||||||
Key? key,
|
Key? key,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@ -61,14 +61,14 @@ class SelectOptionCellEditor extends StatelessWidget with FlowyOverlayDelegate {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void show(
|
static void show({
|
||||||
BuildContext context,
|
required BuildContext context,
|
||||||
GridSelectOptionCellController cellContext,
|
required GridSelectOptionCellController cellController,
|
||||||
VoidCallback onDismissed,
|
VoidCallback? onDismissed,
|
||||||
) {
|
}) {
|
||||||
SelectOptionCellEditor.remove(context);
|
SelectOptionCellEditor.remove(context);
|
||||||
final editor = SelectOptionCellEditor(
|
final editor = SelectOptionCellEditor(
|
||||||
cellController: cellContext,
|
cellController: cellController,
|
||||||
onDismissed: onDismissed,
|
onDismissed: onDismissed,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -97,7 +97,7 @@ class SelectOptionCellEditor extends StatelessWidget with FlowyOverlayDelegate {
|
||||||
bool asBarrier() => true;
|
bool asBarrier() => true;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void didRemove() => onDismissed();
|
void didRemove() => onDismissed?.call();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _OptionList extends StatelessWidget {
|
class _OptionList extends StatelessWidget {
|
||||||
|
|
|
@ -25,7 +25,7 @@ class AppFlowyGroupFooter extends StatefulWidget {
|
||||||
class _AppFlowyGroupFooterState extends State<AppFlowyGroupFooter> {
|
class _AppFlowyGroupFooterState extends State<AppFlowyGroupFooter> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return GestureDetector(
|
return InkWell(
|
||||||
onTap: widget.onAddButtonClick,
|
onTap: widget.onAddButtonClick,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: widget.height,
|
height: widget.height,
|
||||||
|
|
|
@ -8,7 +8,9 @@ pub trait GroupAction: Send + Sync {
|
||||||
fn default_cell_rev(&self) -> Option<CellRevision> {
|
fn default_cell_rev(&self) -> Option<CellRevision> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
fn use_default_group(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
fn can_group(&self, content: &str, cell_data: &Self::CellDataType) -> bool;
|
fn can_group(&self, content: &str, cell_data: &Self::CellDataType) -> bool;
|
||||||
fn add_row_if_match(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupChangesetPB>;
|
fn add_row_if_match(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupChangesetPB>;
|
||||||
fn remove_row_if_match(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupChangesetPB>;
|
fn remove_row_if_match(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupChangesetPB>;
|
||||||
|
|
|
@ -97,11 +97,8 @@ where
|
||||||
self.groups_map.values().collect()
|
self.groups_map.values().collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the all the groups that contain the default group.
|
pub(crate) fn default_group(&self) -> &Group {
|
||||||
pub(crate) fn clone_groups(&self) -> Vec<Group> {
|
&self.default_group
|
||||||
let mut groups: Vec<Group> = self.groups_map.values().cloned().collect();
|
|
||||||
groups.push(self.default_group.clone());
|
|
||||||
groups
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterate mut the groups. The default group will be the last one that get mutated.
|
/// Iterate mut the groups. The default group will be the last one that get mutated.
|
||||||
|
|
|
@ -182,7 +182,13 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn groups(&self) -> Vec<Group> {
|
fn groups(&self) -> Vec<Group> {
|
||||||
self.group_ctx.clone_groups()
|
if self.use_default_group() {
|
||||||
|
let mut groups: Vec<Group> = self.group_ctx.concrete_groups().into_iter().cloned().collect();
|
||||||
|
groups.push(self.group_ctx.default_group().clone());
|
||||||
|
groups
|
||||||
|
} else {
|
||||||
|
self.group_ctx.concrete_groups().into_iter().cloned().collect()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_group(&self, group_id: &str) -> Option<(usize, Group)> {
|
fn get_group(&self, group_id: &str) -> Option<(usize, Group)> {
|
||||||
|
@ -243,7 +249,7 @@ where
|
||||||
let cell_data = cell_bytes.parser::<P>()?;
|
let cell_data = cell_bytes.parser::<P>()?;
|
||||||
let mut changesets = self.add_row_if_match(row_rev, &cell_data);
|
let mut changesets = self.add_row_if_match(row_rev, &cell_data);
|
||||||
let default_group_changeset = self.update_default_group(row_rev, &changesets);
|
let default_group_changeset = self.update_default_group(row_rev, &changesets);
|
||||||
tracing::info!("default_group_changeset: {}", default_group_changeset);
|
tracing::trace!("default_group_changeset: {}", default_group_changeset);
|
||||||
if !default_group_changeset.is_empty() {
|
if !default_group_changeset.is_empty() {
|
||||||
changesets.push(default_group_changeset);
|
changesets.push(default_group_changeset);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,10 @@ impl GroupAction for CheckboxGroupController {
|
||||||
Some(CellRevision::new(UNCHECK.to_string()))
|
Some(CellRevision::new(UNCHECK.to_string()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn use_default_group(&self) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
fn can_group(&self, content: &str, cell_data: &Self::CellDataType) -> bool {
|
fn can_group(&self, content: &str, cell_data: &Self::CellDataType) -> bool {
|
||||||
if cell_data.is_check() {
|
if cell_data.is_check() {
|
||||||
content == CHECK
|
content == CHECK
|
||||||
|
|
|
@ -3,7 +3,6 @@ use crate::services::field::*;
|
||||||
use crate::services::row::RowRevisionBuilder;
|
use crate::services::row::RowRevisionBuilder;
|
||||||
use flowy_grid_data_model::revision::BuildGridContext;
|
use flowy_grid_data_model::revision::BuildGridContext;
|
||||||
use flowy_sync::client_grid::GridBuilder;
|
use flowy_sync::client_grid::GridBuilder;
|
||||||
use lib_infra::util::timestamp;
|
|
||||||
|
|
||||||
pub fn make_default_grid() -> BuildGridContext {
|
pub fn make_default_grid() -> BuildGridContext {
|
||||||
let mut grid_builder = GridBuilder::new();
|
let mut grid_builder = GridBuilder::new();
|
||||||
|
@ -59,6 +58,45 @@ pub fn make_default_board() -> BuildGridContext {
|
||||||
let single_select_field_id = single_select_field.id.clone();
|
let single_select_field_id = single_select_field.id.clone();
|
||||||
grid_builder.add_field(single_select_field);
|
grid_builder.add_field(single_select_field);
|
||||||
|
|
||||||
|
for i in 0..3 {
|
||||||
|
let mut row_builder = RowRevisionBuilder::new(grid_builder.block_id(), grid_builder.field_revs());
|
||||||
|
row_builder.insert_select_option_cell(&single_select_field_id, to_do_option.id.clone());
|
||||||
|
let data = format!("Card {}", i + 1);
|
||||||
|
row_builder.insert_text_cell(&text_field_id, data);
|
||||||
|
let row = row_builder.build();
|
||||||
|
grid_builder.add_row(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
grid_builder.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn make_default_board_2() -> BuildGridContext {
|
||||||
|
let mut grid_builder = GridBuilder::new();
|
||||||
|
// text
|
||||||
|
let text_field = FieldBuilder::new(RichTextTypeOptionBuilder::default())
|
||||||
|
.name("Description")
|
||||||
|
.visibility(true)
|
||||||
|
.primary(true)
|
||||||
|
.build();
|
||||||
|
let text_field_id = text_field.id.clone();
|
||||||
|
grid_builder.add_field(text_field);
|
||||||
|
|
||||||
|
// single select
|
||||||
|
let to_do_option = SelectOptionPB::with_color("To Do", SelectOptionColorPB::Purple);
|
||||||
|
let doing_option = SelectOptionPB::with_color("Doing", SelectOptionColorPB::Orange);
|
||||||
|
let done_option = SelectOptionPB::with_color("Done", SelectOptionColorPB::Yellow);
|
||||||
|
let single_select_type_option = SingleSelectTypeOptionBuilder::default()
|
||||||
|
.add_option(to_do_option.clone())
|
||||||
|
.add_option(doing_option.clone())
|
||||||
|
.add_option(done_option.clone());
|
||||||
|
let single_select_field = FieldBuilder::new(single_select_type_option)
|
||||||
|
.name("Status")
|
||||||
|
.visibility(true)
|
||||||
|
.build();
|
||||||
|
let single_select_field_id = single_select_field.id.clone();
|
||||||
|
grid_builder.add_field(single_select_field);
|
||||||
|
|
||||||
// MultiSelect
|
// MultiSelect
|
||||||
let work_option = SelectOptionPB::with_color("Work", SelectOptionColorPB::Aqua);
|
let work_option = SelectOptionPB::with_color("Work", SelectOptionColorPB::Aqua);
|
||||||
let travel_option = SelectOptionPB::with_color("Travel", SelectOptionColorPB::Green);
|
let travel_option = SelectOptionPB::with_color("Travel", SelectOptionColorPB::Green);
|
||||||
|
@ -152,102 +190,3 @@ pub fn make_default_board() -> BuildGridContext {
|
||||||
|
|
||||||
grid_builder.build()
|
grid_builder.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn make_default_board2() -> BuildGridContext {
|
|
||||||
let mut grid_builder = GridBuilder::new();
|
|
||||||
// text
|
|
||||||
let text_field = FieldBuilder::new(RichTextTypeOptionBuilder::default())
|
|
||||||
.name("Name")
|
|
||||||
.visibility(true)
|
|
||||||
.primary(true)
|
|
||||||
.build();
|
|
||||||
let text_field_id = text_field.id.clone();
|
|
||||||
grid_builder.add_field(text_field);
|
|
||||||
|
|
||||||
// date
|
|
||||||
let date_type_option = DateTypeOptionBuilder::default();
|
|
||||||
let date_field = FieldBuilder::new(date_type_option)
|
|
||||||
.name("Date")
|
|
||||||
.visibility(true)
|
|
||||||
.build();
|
|
||||||
let date_field_id = date_field.id.clone();
|
|
||||||
let timestamp = timestamp();
|
|
||||||
grid_builder.add_field(date_field);
|
|
||||||
|
|
||||||
// single select
|
|
||||||
let in_progress_option = SelectOptionPB::new("In progress");
|
|
||||||
let not_started_option = SelectOptionPB::new("Not started");
|
|
||||||
let done_option = SelectOptionPB::new("Done");
|
|
||||||
let single_select_type_option = SingleSelectTypeOptionBuilder::default()
|
|
||||||
.add_option(not_started_option.clone())
|
|
||||||
.add_option(in_progress_option)
|
|
||||||
.add_option(done_option);
|
|
||||||
let single_select_field = FieldBuilder::new(single_select_type_option)
|
|
||||||
.name("Status")
|
|
||||||
.visibility(true)
|
|
||||||
.build();
|
|
||||||
let single_select_field_id = single_select_field.id.clone();
|
|
||||||
grid_builder.add_field(single_select_field);
|
|
||||||
|
|
||||||
// MultiSelect
|
|
||||||
let apple_option = SelectOptionPB::new("Apple");
|
|
||||||
let banana_option = SelectOptionPB::new("Banana");
|
|
||||||
let pear_option = SelectOptionPB::new("Pear");
|
|
||||||
let multi_select_type_option = MultiSelectTypeOptionBuilder::default()
|
|
||||||
.add_option(banana_option.clone())
|
|
||||||
.add_option(apple_option.clone())
|
|
||||||
.add_option(pear_option);
|
|
||||||
let multi_select_field = FieldBuilder::new(multi_select_type_option)
|
|
||||||
.name("Fruit")
|
|
||||||
.visibility(true)
|
|
||||||
.build();
|
|
||||||
let multi_select_field_id = multi_select_field.id.clone();
|
|
||||||
grid_builder.add_field(multi_select_field);
|
|
||||||
|
|
||||||
// Number
|
|
||||||
let number_type_option = NumberTypeOptionBuilder::default().set_format(NumberFormat::USD);
|
|
||||||
let number_field = FieldBuilder::new(number_type_option)
|
|
||||||
.name("Price")
|
|
||||||
.visibility(true)
|
|
||||||
.build();
|
|
||||||
let number_field_id = number_field.id.clone();
|
|
||||||
grid_builder.add_field(number_field);
|
|
||||||
|
|
||||||
// Checkbox
|
|
||||||
let checkbox_type_option = CheckboxTypeOptionBuilder::default();
|
|
||||||
let checkbox_field = FieldBuilder::new(checkbox_type_option).name("Reimbursement").build();
|
|
||||||
let checkbox_field_id = checkbox_field.id.clone();
|
|
||||||
grid_builder.add_field(checkbox_field);
|
|
||||||
|
|
||||||
// Url
|
|
||||||
let url_type_option = URLTypeOptionBuilder::default();
|
|
||||||
let url_field = FieldBuilder::new(url_type_option).name("Shop Link").build();
|
|
||||||
let url_field_id = url_field.id.clone();
|
|
||||||
grid_builder.add_field(url_field);
|
|
||||||
|
|
||||||
// Insert rows
|
|
||||||
for i in 0..10 {
|
|
||||||
// insert single select
|
|
||||||
let mut row_builder = RowRevisionBuilder::new(grid_builder.block_id(), grid_builder.field_revs());
|
|
||||||
row_builder.insert_select_option_cell(&single_select_field_id, not_started_option.id.clone());
|
|
||||||
// insert multi select
|
|
||||||
row_builder.insert_select_option_cell(&multi_select_field_id, apple_option.id.clone());
|
|
||||||
row_builder.insert_select_option_cell(&multi_select_field_id, banana_option.id.clone());
|
|
||||||
// insert text
|
|
||||||
row_builder.insert_text_cell(&text_field_id, format!("Card {}", i));
|
|
||||||
// insert date
|
|
||||||
row_builder.insert_date_cell(&date_field_id, timestamp);
|
|
||||||
// number
|
|
||||||
row_builder.insert_number_cell(&number_field_id, i);
|
|
||||||
// checkbox
|
|
||||||
row_builder.insert_checkbox_cell(&checkbox_field_id, i % 2 == 0);
|
|
||||||
// url
|
|
||||||
row_builder.insert_url_cell(&url_field_id, "https://appflowy.io".to_string());
|
|
||||||
|
|
||||||
let row = row_builder.build();
|
|
||||||
grid_builder.add_row(row);
|
|
||||||
}
|
|
||||||
|
|
||||||
grid_builder.build()
|
|
||||||
}
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue