chore: Merge main 521 (#2574)

* chore: merge main branch

* chore: remove document plugins

* chore: add color generator

* ci: tests
This commit is contained in:
Nathan.fooo
2023-05-21 15:08:50 +08:00
committed by GitHub
parent eaa1dcdeb9
commit 5cc8340e05
27 changed files with 416 additions and 240 deletions

View File

@ -44,7 +44,6 @@ class DateCellDataPersistence implements CellDataPersistence<DateCellData> {
@override
Future<Option<FlowyError>> save(DateCellData data) {
var payload = DateChangesetPB.create()..cellPath = _makeCellPath(cellId);
if (data.dateTime != null) {
final date = (data.dateTime!.millisecondsSinceEpoch ~/ 1000).toString();
payload.date = date;

View File

@ -176,18 +176,28 @@ class DatabaseController {
);
}
Future<Either<Unit, FlowyError>> moveRow({
Future<Either<Unit, FlowyError>> moveGroupRow({
required RowPB fromRow,
required String groupId,
RowPB? toRow,
}) {
return _databaseViewBackendSvc.moveRow(
return _databaseViewBackendSvc.moveGroupRow(
fromRowId: fromRow.id,
toGroupId: groupId,
toRowId: toRow?.id,
);
}
Future<Either<Unit, FlowyError>> moveRow({
required RowPB fromRow,
required RowPB toRow,
}) {
return _databaseViewBackendSvc.moveRow(
fromRowId: fromRow.id,
toRowId: toRow.id,
);
}
Future<Either<Unit, FlowyError>> moveGroup({
required String fromGroupId,
required String toGroupId,

View File

@ -43,7 +43,7 @@ class DatabaseViewBackendService {
return DatabaseEventCreateRow(payload).send();
}
Future<Either<Unit, FlowyError>> moveRow({
Future<Either<Unit, FlowyError>> moveGroupRow({
required RowId fromRowId,
required String toGroupId,
RowId? toRowId,
@ -60,6 +60,18 @@ class DatabaseViewBackendService {
return DatabaseEventMoveGroupRow(payload).send();
}
Future<Either<Unit, FlowyError>> moveRow({
required String fromRowId,
required String toRowId,
}) {
var payload = MoveRowPayloadPB.create()
..viewId = viewId
..fromRowId = fromRowId
..toRowId = toRowId;
return DatabaseEventMoveRow(payload).send();
}
Future<Either<Unit, FlowyError>> moveGroup({
required String fromGroupId,
required String toGroupId,

View File

@ -30,7 +30,7 @@ abstract class RowCacheDelegate {
class RowCache {
final String viewId;
/// _rows containers the current block's rows
/// _rows contains the current block's rows
/// Use List to reverse the order of the GridRow.
final RowList _rowList = RowList();

View File

@ -54,7 +54,7 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
final fromRow = groupControllers[groupId]?.rowAtIndex(fromIndex);
final toRow = groupControllers[groupId]?.rowAtIndex(toIndex);
if (fromRow != null) {
_databaseController.moveRow(
_databaseController.moveGroupRow(
fromRow: fromRow,
toRow: toRow,
groupId: groupId,
@ -70,7 +70,7 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
final fromRow = groupControllers[fromGroupId]?.rowAtIndex(fromIndex);
final toRow = groupControllers[toGroupId]?.rowAtIndex(toIndex);
if (fromRow != null) {
_databaseController.moveRow(
_databaseController.moveGroupRow(
fromRow: fromRow,
toRow: toRow,
groupId: toGroupId,

View File

@ -161,6 +161,9 @@ class CalendarDayCard extends StatelessWidget {
});
renderHook.addSelectOptionHook((selectedOptions, cardData, _) {
if (selectedOptions.isEmpty) {
return const SizedBox.shrink();
}
final children = selectedOptions.map(
(option) {
return SelectOptionTag.fromOption(

View File

@ -35,6 +35,17 @@ class GridBloc extends Bloc<GridEvent, GridState> {
);
await rowService.deleteRow(rowInfo.rowPB.id);
},
moveRow: (int from, int to) {
final List<RowInfo> rows = [...state.rowInfos];
final fromRow = rows[from].rowPB;
final toRow = rows[to].rowPB;
rows.insert(to, rows.removeAt(from));
emit(state.copyWith(rowInfos: rows));
databaseController.moveRow(fromRow: fromRow, toRow: toRow);
},
didReceiveGridUpdate: (grid) {
emit(state.copyWith(grid: Some(grid)));
},
@ -110,6 +121,7 @@ class GridEvent with _$GridEvent {
const factory GridEvent.initial() = InitialGrid;
const factory GridEvent.createRow() = _CreateRow;
const factory GridEvent.deleteRow(RowInfo rowInfo) = _DeleteRow;
const factory GridEvent.moveRow(int from, int to) = _MoveRow;
const factory GridEvent.didReceiveRowUpdate(
List<RowInfo> rows,
RowsChangedReason listState,

View File

@ -91,21 +91,6 @@ class _GridPageState extends State<GridPage> {
),
);
}
@override
void dispose() {
super.dispose();
}
@override
void deactivate() {
super.deactivate();
}
@override
void didUpdateWidget(covariant GridPage oldWidget) {
super.didUpdateWidget(oldWidget);
}
}
class FlowyGrid extends StatefulWidget {
@ -119,12 +104,12 @@ class _FlowyGridState extends State<FlowyGrid> {
final _scrollController = GridScrollController(
scrollGroupController: LinkedScrollControllerGroup(),
);
late ScrollController headerScrollController;
late final ScrollController headerScrollController;
@override
void initState() {
headerScrollController = _scrollController.linkHorizontalController();
super.initState();
headerScrollController = _scrollController.linkHorizontalController();
}
@override
@ -216,49 +201,78 @@ class _GridRowsState extends State<_GridRows> {
@override
Widget build(BuildContext context) {
return BlocConsumer<GridBloc, GridState>(
listenWhen: (previous, current) => previous.reason != current.reason,
listener: (context, state) {
state.reason.whenOrNull(
insert: (item) {
_key.currentState?.insertItem(item.index);
},
delete: (item) {
_key.currentState?.removeItem(
item.index,
(context, animation) =>
_renderRow(context, item.rowInfo, animation),
return Builder(
builder: (context) {
final filterState = context.watch<GridFilterMenuBloc>().state;
final sortState = context.watch<SortMenuBloc>().state;
return BlocConsumer<GridBloc, GridState>(
listenWhen: (previous, current) => previous.reason != current.reason,
listener: (context, state) {
state.reason.whenOrNull(
insert: (item) {
_key.currentState?.insertItem(item.index);
},
delete: (item) {
_key.currentState?.removeItem(
item.index,
(context, animation) => _renderRow(
context,
item.rowInfo,
animation: animation,
),
);
},
);
},
reorderSingleRow: (reorderRow, rowInfo) {
// _key.currentState?.removeItem(
// reorderRow.oldIndex,
// (context, animation) => _renderRow(context, rowInfo, animation),
// );
// _key.currentState?.insertItem(reorderRow.newIndex);
},
);
},
buildWhen: (previous, current) {
return current.reason.whenOrNull(
buildWhen: (previous, current) {
return current.reason.maybeWhen(
reorderRows: () => true,
reorderSingleRow: (reorderRow, rowInfo) => true,
) ??
false;
},
builder: (context, state) {
return SliverAnimatedList(
key: _key,
initialItemCount: context.read<GridBloc>().state.rowInfos.length,
itemBuilder:
(BuildContext context, int index, Animation<double> animation) {
final rowInfos = context.read<GridBloc>().state.rowInfos;
if (index >= rowInfos.length) {
return const SizedBox();
} else {
final RowInfo rowInfo = rowInfos[index];
return _renderRow(context, rowInfo, animation);
}
delete: (item) => true,
insert: (item) => true,
orElse: () => false,
);
},
builder: (context, state) {
final rowInfos = context.watch<GridBloc>().state.rowInfos;
return SliverFillRemaining(
child: ReorderableListView.builder(
key: _key,
buildDefaultDragHandles: false,
proxyDecorator: (child, index, animation) => Material(
color: Colors.white.withOpacity(.1),
child: Opacity(
opacity: .5,
child: child,
),
),
onReorder: (fromIndex, newIndex) {
final toIndex =
newIndex > fromIndex ? newIndex - 1 : newIndex;
if (fromIndex == toIndex) {
return;
}
context
.read<GridBloc>()
.add(GridEvent.moveRow(fromIndex, toIndex));
},
itemCount: rowInfos.length,
itemBuilder: (BuildContext context, int index) {
final RowInfo rowInfo = rowInfos[index];
return _renderRow(
context,
rowInfo,
index: index,
isSortEnabled: sortState.sortInfos.isNotEmpty,
isFilterEnabled: filterState.filters.isNotEmpty,
);
},
),
);
},
);
},
@ -267,15 +281,18 @@ class _GridRowsState extends State<_GridRows> {
Widget _renderRow(
BuildContext context,
RowInfo rowInfo,
Animation<double> animation,
) {
RowInfo rowInfo, {
int? index,
bool isSortEnabled = false,
bool isFilterEnabled = false,
Animation<double>? animation,
}) {
final rowCache = context.read<GridBloc>().getRowCache(
rowInfo.rowPB.id,
);
/// Return placeholder widget if the rowCache is null.
if (rowCache == null) return const SizedBox();
if (rowCache == null) return const SizedBox.shrink();
final fieldController =
context.read<GridBloc>().databaseController.fieldController;
@ -285,24 +302,32 @@ class _GridRowsState extends State<_GridRows> {
rowCache: rowCache,
);
return SizeTransition(
sizeFactor: animation,
child: GridRow(
rowInfo: rowInfo,
dataController: dataController,
cellBuilder: GridCellBuilder(cellCache: dataController.cellCache),
openDetailPage: (context, cellBuilder) {
_openRowDetailPage(
context,
rowInfo,
fieldController,
rowCache,
cellBuilder,
);
},
key: ValueKey(rowInfo.rowPB.id),
),
final child = GridRow(
key: ValueKey(rowInfo.rowPB.id),
index: index,
isDraggable: !isSortEnabled && !isFilterEnabled,
rowInfo: rowInfo,
dataController: dataController,
cellBuilder: GridCellBuilder(cellCache: dataController.cellCache),
openDetailPage: (context, cellBuilder) {
_openRowDetailPage(
context,
rowInfo,
fieldController,
rowCache,
cellBuilder,
);
},
);
if (animation != null) {
return SizeTransition(
sizeFactor: animation,
child: child,
);
}
return child;
}
void _openRowDetailPage(

View File

@ -25,29 +25,34 @@ class GridRow extends StatefulWidget {
final GridCellBuilder cellBuilder;
final void Function(BuildContext, GridCellBuilder) openDetailPage;
final int? index;
final bool isDraggable;
const GridRow({
super.key,
required this.rowInfo,
required this.dataController,
required this.cellBuilder,
required this.openDetailPage,
Key? key,
}) : super(key: key);
this.index,
this.isDraggable = false,
});
@override
State<GridRow> createState() => _GridRowState();
}
class _GridRowState extends State<GridRow> {
late RowBloc _rowBloc;
late final RowBloc _rowBloc;
@override
void initState() {
super.initState();
_rowBloc = RowBloc(
rowInfo: widget.rowInfo,
dataController: widget.dataController,
);
_rowBloc.add(const RowEvent.initial());
super.initState();
}
@override
@ -70,9 +75,11 @@ class _GridRowState extends State<GridRow> {
return Row(
children: [
const _RowLeading(),
_RowLeading(
index: widget.index,
isDraggable: widget.isDraggable,
),
content,
const _RowTrailing(),
],
);
},
@ -89,19 +96,25 @@ class _GridRowState extends State<GridRow> {
}
class _RowLeading extends StatefulWidget {
const _RowLeading({Key? key}) : super(key: key);
final int? index;
final bool isDraggable;
const _RowLeading({
this.index,
this.isDraggable = false,
});
@override
State<_RowLeading> createState() => _RowLeadingState();
}
class _RowLeadingState extends State<_RowLeading> {
late PopoverController popoverController;
late final PopoverController popoverController;
@override
void initState() {
popoverController = PopoverController();
super.initState();
popoverController = PopoverController();
}
@override
@ -131,23 +144,28 @@ class _RowLeadingState extends State<_RowLeading> {
mainAxisAlignment: MainAxisAlignment.center,
children: [
const _InsertButton(),
_MenuButton(
openMenu: () {
popoverController.show();
},
),
if (isDraggable) ...[
ReorderableDragStartListener(
index: widget.index!,
child: _MenuButton(
isDragEnabled: isDraggable,
openMenu: () {
popoverController.show();
},
),
),
] else ...[
_MenuButton(
openMenu: () {
popoverController.show();
},
),
],
],
);
}
}
class _RowTrailing extends StatelessWidget {
const _RowTrailing({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const SizedBox();
}
bool get isDraggable => widget.index != null && widget.isDraggable;
}
class _InsertButton extends StatelessWidget {
@ -172,25 +190,31 @@ class _InsertButton extends StatelessWidget {
class _MenuButton extends StatefulWidget {
final VoidCallback openMenu;
final bool isDragEnabled;
const _MenuButton({
required this.openMenu,
Key? key,
}) : super(key: key);
this.isDragEnabled = false,
});
@override
State<_MenuButton> createState() => _MenuButtonState();
}
class _MenuButtonState extends State<_MenuButton> {
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return FlowyIconButton(
tooltipText: LocaleKeys.tooltip_openMenu.tr(),
tooltipText:
widget.isDragEnabled ? null : LocaleKeys.tooltip_openMenu.tr(),
richTooltipText: widget.isDragEnabled
? TextSpan(
children: [
TextSpan(text: '${LocaleKeys.tooltip_dragRow.tr()}\n'),
TextSpan(text: LocaleKeys.tooltip_openMenu.tr()),
],
)
: null,
hoverColor: AFThemeExtension.of(context).lightGreyHover,
width: 20,
height: 30,
@ -258,6 +282,7 @@ class RowContent extends StatelessWidget {
if (builder != null) {
accessories.addAll(builder(buildContext));
}
return accessories;
},
child: child,
@ -289,12 +314,12 @@ class _RowEnterRegion extends StatefulWidget {
}
class _RowEnterRegionState extends State<_RowEnterRegion> {
late RegionStateNotifier _rowStateNotifier;
late final RegionStateNotifier _rowStateNotifier;
@override
void initState() {
_rowStateNotifier = RegionStateNotifier();
super.initState();
_rowStateNotifier = RegionStateNotifier();
}
@override

View File

@ -74,6 +74,7 @@ class GridCellBuilder {
key: key,
);
}
throw UnimplementedError;
}
}
@ -83,7 +84,7 @@ class BlankCell extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container();
return const SizedBox.shrink();
}
}

View File

@ -68,18 +68,15 @@ class CellContainer extends StatelessWidget {
if (isFocus) {
final borderSide = BorderSide(
color: Theme.of(context).colorScheme.primary,
width: 1.0,
);
return BoxDecoration(border: Border.fromBorderSide(borderSide));
} else {
final borderSide = BorderSide(
color: Theme.of(context).dividerColor,
width: 1.0,
);
return BoxDecoration(
border: Border(right: borderSide, bottom: borderSide),
);
}
final borderSide = BorderSide(color: Theme.of(context).dividerColor);
return BoxDecoration(
border: Border(right: borderSide, bottom: borderSide),
);
}
}

View File

@ -82,7 +82,6 @@ class DateCellCalendarBloc
date != null && time == null,
);
String? newTime = time ?? state.time;
DateTime? newDate = _utcToLocalAddTime(date);
if (time != null && time.isNotEmpty) {
newDate = state.dateTime ?? DateTime.now();