chore: opti row rebuild

This commit is contained in:
appflowy 2022-03-09 12:11:27 +08:00
parent 00db755c29
commit 321682717c
6 changed files with 105 additions and 84 deletions

View File

@ -1,4 +1,5 @@
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
import 'package:equatable/equatable.dart';
class GridInfo {
List<Row> rows;
@ -23,15 +24,18 @@ class GridInfo {
}
}
class GridRowData {
Row row;
List<Field> fields;
Map<String, Cell> cellMap;
GridRowData({
class GridRowData extends Equatable {
final Row row;
final List<Field> fields;
final Map<String, Cell> cellMap;
const GridRowData({
required this.row,
required this.fields,
required this.cellMap,
});
@override
List<Object> get props => [row.hashCode, cellMap];
}
class GridColumnData {

View File

@ -1,6 +1,5 @@
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:dartz/dartz.dart';
import 'dart:async';
import 'data.dart';
import 'row_service.dart';
@ -9,18 +8,18 @@ part 'row_bloc.freezed.dart';
class RowBloc extends Bloc<RowEvent, RowState> {
final RowService service;
final GridRowData data;
RowBloc({required this.data, required this.service}) : super(RowState.initial()) {
RowBloc({required GridRowData data, required this.service}) : super(RowState.initial(data)) {
on<RowEvent>(
(event, emit) async {
await event.map(
initial: (_InitialRow value) async {},
createRow: (_CreateRow value) {},
highlightRow: (_HighlightRow value) {
emit(state.copyWith(
isHighlight: value.rowId.fold(() => false, (rowId) => rowId == data.row.id),
));
activeRow: (_ActiveRow value) {
emit(state.copyWith(active: true));
},
disactiveRow: (_DisactiveRow value) {
emit(state.copyWith(active: false));
},
);
},
@ -35,16 +34,18 @@ class RowBloc extends Bloc<RowEvent, RowState> {
@freezed
abstract class RowEvent with _$RowEvent {
const factory RowEvent.initial() = _InitialRow;
const factory RowEvent.initial(GridRowData data) = _InitialRow;
const factory RowEvent.createRow() = _CreateRow;
const factory RowEvent.highlightRow(Option<String> rowId) = _HighlightRow;
const factory RowEvent.activeRow() = _ActiveRow;
const factory RowEvent.disactiveRow() = _DisactiveRow;
}
@freezed
abstract class RowState with _$RowState {
const factory RowState({
required bool isHighlight,
required GridRowData data,
required bool active,
}) = _RowState;
factory RowState.initial() => const RowState(isHighlight: false);
factory RowState.initial(GridRowData data) => RowState(data: data, active: false);
}

View File

@ -139,7 +139,7 @@ class _GridBodyState extends State<GridBody> {
delegate: SliverChildBuilderDelegate(
(context, index) {
final data = gridInfo.rowAtIndex(index);
return RepaintBoundary(child: GridRowWidget(data));
return RepaintBoundary(child: GridRowWidget(data: data));
},
childCount: gridInfo.numberOfRows(),
),

View File

@ -1,9 +1,10 @@
import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart';
import 'package:flowy_infra/theme.dart';
import 'package:flowy_sdk/log.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class CellContainer extends StatelessWidget {
class CellContainer extends StatefulWidget {
final Widget child;
final double width;
const CellContainer({
@ -12,23 +13,27 @@ class CellContainer extends StatelessWidget {
required this.width,
}) : super(key: key);
@override
State<CellContainer> createState() => _CellContainerState();
}
class _CellContainerState extends State<CellContainer> {
@override
Widget build(BuildContext context) {
final theme = context.watch<AppTheme>();
final borderSide = BorderSide(color: theme.shader4, width: 0.4);
return GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () {},
child: Container(
constraints: BoxConstraints(
maxWidth: width,
maxWidth: widget.width,
),
decoration: BoxDecoration(
border: Border(right: borderSide, bottom: borderSide),
),
padding: GridSize.cellContentInsets,
child: Center(child: IntrinsicHeight(child: child)),
child: Center(child: IntrinsicHeight(child: widget.child)),
),
);
}

View File

@ -8,88 +8,103 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'cell_builder.dart';
import 'cell_container.dart';
import 'grid_cell.dart';
import 'package:dartz/dartz.dart';
class GridRowWidget extends StatelessWidget {
class GridRowWidget extends StatefulWidget {
final GridRowData data;
final Function(bool)? onHoverChange;
const GridRowWidget(this.data, {Key? key, this.onHoverChange}) : super(key: key);
GridRowWidget({required this.data, Key? key}) : super(key: ObjectKey(data.row.id));
@override
State<GridRowWidget> createState() => _GridRowWidgetState();
}
class _GridRowWidgetState extends State<GridRowWidget> {
late RowBloc _rowBloc;
@override
void initState() {
_rowBloc = getIt<RowBloc>(param1: widget.data);
super.initState();
}
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => getIt<RowBloc>(param1: data),
child: BlocBuilder<RowBloc, RowState>(
builder: (context, state) {
return GestureDetector(
behavior: HitTestBehavior.translucent,
child: MouseRegion(
cursor: SystemMouseCursors.click,
onEnter: (p) => context.read<RowBloc>().add(RowEvent.highlightRow(some(data.row.id))),
onExit: (p) => context.read<RowBloc>().add(RowEvent.highlightRow(none())),
child: SizedBox(
height: data.row.height.toDouble(),
child: Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: _buildCells(),
),
),
return BlocProvider.value(
value: _rowBloc,
child: GestureDetector(
behavior: HitTestBehavior.translucent,
child: MouseRegion(
cursor: SystemMouseCursors.click,
onEnter: (p) => _rowBloc.add(const RowEvent.activeRow()),
onExit: (p) => _rowBloc.add(const RowEvent.disactiveRow()),
child: SizedBox(
height: _rowBloc.state.data.row.height.toDouble(),
child: Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const LeadingRow(),
_buildCells(),
const TrailingRow(),
],
),
);
},
),
),
),
);
}
List<Widget> _buildCells() {
return [
SizedBox(
width: GridSize.leadingHeaderPadding,
child: LeadingRow(rowId: data.row.id),
),
...data.fields.map(
(field) {
final cellData = data.cellMap[field.id];
return CellContainer(
width: field.width.toDouble(),
child: GridCellBuilder.buildCell(field, cellData),
);
},
),
SizedBox(
width: GridSize.trailHeaderPadding,
child: TrailingRow(rowId: data.row.id),
)
].toList();
@override
Future<void> dispose() async {
_rowBloc.close();
super.dispose();
}
Widget _buildCells() {
return BlocBuilder<RowBloc, RowState>(
buildWhen: (p, c) => p.data != c.data,
builder: (context, state) {
return Row(
key: ValueKey(state.data.row.id),
children: state.data.fields.map(
(field) {
final cellData = state.data.cellMap[field.id];
return CellContainer(
width: field.width.toDouble(),
child: GridCellBuilder.buildCell(field, cellData),
);
},
).toList(),
);
},
);
}
}
class LeadingRow extends StatelessWidget {
final String rowId;
const LeadingRow({required this.rowId, Key? key}) : super(key: key);
const LeadingRow({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return BlocBuilder<RowBloc, RowState>(
builder: (context, state) {
if (state.isHighlight) {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
CreateRowButton(),
],
);
}
return const SizedBox.expand();
return BlocSelector<RowBloc, RowState, bool>(
selector: (state) => state.active,
builder: (context, isActive) {
return SizedBox(
width: GridSize.leadingHeaderPadding,
child: isActive
? Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
CreateRowButton(),
],
)
: null,
);
},
);
}
}
class TrailingRow extends StatelessWidget {
final String rowId;
const TrailingRow({required this.rowId, Key? key}) : super(key: key);
const TrailingRow({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {

View File

@ -18,10 +18,6 @@ class HeaderCell extends StatelessWidget {
hoverColor: theme.hover,
onTap: () {},
);
// return Text(
// field.name,
// style: const TextStyle(fontSize: 15.0, color: Colors.black),
// );
}
}