mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
chore: auto resize row height
This commit is contained in:
parent
f3c82f5c30
commit
d4de5767a6
@ -21,6 +21,17 @@ class RowService {
|
||||
return GridEventCreateRow(payload).send();
|
||||
}
|
||||
|
||||
Future<Either<Unit, FlowyError>> moveRow(String rowId, int fromIndex, int toIndex) {
|
||||
final payload = MoveItemPayload.create()
|
||||
..gridId = gridId
|
||||
..itemId = rowId
|
||||
..ty = MoveItemType.MoveRow
|
||||
..fromIndex = fromIndex
|
||||
..toIndex = toIndex;
|
||||
|
||||
return GridEventMoveItem(payload).send();
|
||||
}
|
||||
|
||||
Future<Either<Row, FlowyError>> getRow() {
|
||||
final payload = RowIdentifierPayload.create()
|
||||
..gridId = gridId
|
||||
|
@ -107,7 +107,7 @@ class _FlowyGridState extends State<FlowyGrid> {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const _GridToolbarAdaptor(),
|
||||
_gridHeader(context, state.gridId, contentWidth),
|
||||
_gridHeader(context, state.gridId),
|
||||
Flexible(child: child),
|
||||
],
|
||||
);
|
||||
@ -147,16 +147,12 @@ class _FlowyGridState extends State<FlowyGrid> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _gridHeader(BuildContext context, String gridId, double contentWidth) {
|
||||
Widget _gridHeader(BuildContext context, String gridId) {
|
||||
final fieldCache = context.read<GridBloc>().fieldCache;
|
||||
|
||||
return SizedBox(
|
||||
width: contentWidth,
|
||||
child: GridHeaderSliverAdaptor(
|
||||
gridId: gridId,
|
||||
fieldCache: fieldCache,
|
||||
anchorScrollController: headerScrollController,
|
||||
),
|
||||
return GridHeaderSliverAdaptor(
|
||||
gridId: gridId,
|
||||
fieldCache: fieldCache,
|
||||
anchorScrollController: headerScrollController,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -33,9 +33,7 @@ class CellContainer extends StatelessWidget {
|
||||
child: Consumer<CellStateNotifier>(
|
||||
builder: (context, state, _) {
|
||||
return Container(
|
||||
constraints: BoxConstraints(
|
||||
maxWidth: width,
|
||||
),
|
||||
constraints: BoxConstraints(maxWidth: width, maxHeight: 42),
|
||||
decoration: _makeBoxDecoration(context, state),
|
||||
padding: GridSize.cellContentInsets,
|
||||
child: Center(child: child),
|
||||
|
@ -6,6 +6,7 @@ import 'package:flowy_infra/theme.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/button.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/hover.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/text.dart';
|
||||
import 'package:flowy_sdk/log.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'field_type_extension.dart';
|
||||
@ -28,49 +29,19 @@ class GridFieldCell extends StatelessWidget {
|
||||
final button = FlowyButton(
|
||||
hoverColor: theme.shader6,
|
||||
onTap: () => _showActionSheet(context),
|
||||
// rightIcon: svgWidget("editor/details", color: theme.iconColor),
|
||||
leftIcon: svgWidget(state.field.fieldType.iconName(), color: theme.iconColor),
|
||||
text: FlowyText.medium(state.field.name, fontSize: 12),
|
||||
padding: GridSize.cellContentInsets,
|
||||
);
|
||||
|
||||
final line = InkWell(
|
||||
onTap: () {},
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onHorizontalDragCancel: () {},
|
||||
onHorizontalDragUpdate: (value) {
|
||||
context.read<FieldCellBloc>().add(FieldCellEvent.updateWidth(value.delta.dx));
|
||||
},
|
||||
child: FlowyHover(
|
||||
style: HoverStyle(
|
||||
hoverColor: theme.main1,
|
||||
borderRadius: BorderRadius.zero,
|
||||
contentMargin: const EdgeInsets.only(left: 5),
|
||||
),
|
||||
builder: (_, onHover) => const SizedBox(width: 2),
|
||||
),
|
||||
),
|
||||
);
|
||||
const line = Positioned(top: 0, bottom: 0, right: 0, child: _DragToExpandLine());
|
||||
|
||||
final borderSide = BorderSide(color: theme.shader4, width: 0.4);
|
||||
final decoration = BoxDecoration(
|
||||
border: Border(
|
||||
top: borderSide,
|
||||
right: borderSide,
|
||||
bottom: borderSide,
|
||||
));
|
||||
|
||||
return Container(
|
||||
return _CellContainer(
|
||||
width: state.field.width.toDouble(),
|
||||
decoration: decoration,
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints.expand(),
|
||||
child: Stack(
|
||||
alignment: Alignment.centerRight,
|
||||
fit: StackFit.expand,
|
||||
children: [button, Positioned(top: 0, bottom: 0, right: 0, child: line)],
|
||||
),
|
||||
child: Stack(
|
||||
alignment: Alignment.centerRight,
|
||||
fit: StackFit.expand,
|
||||
children: [button, line],
|
||||
),
|
||||
);
|
||||
},
|
||||
@ -98,3 +69,65 @@ class GridFieldCell extends StatelessWidget {
|
||||
).show(context);
|
||||
}
|
||||
}
|
||||
|
||||
class _CellContainer extends StatelessWidget {
|
||||
final Widget child;
|
||||
final double width;
|
||||
const _CellContainer({
|
||||
required this.child,
|
||||
required this.width,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = context.watch<AppTheme>();
|
||||
final borderSide = BorderSide(color: theme.shader4, width: 0.4);
|
||||
final decoration = BoxDecoration(
|
||||
border: Border(
|
||||
top: borderSide,
|
||||
right: borderSide,
|
||||
bottom: borderSide,
|
||||
));
|
||||
|
||||
return Container(
|
||||
width: width,
|
||||
decoration: decoration,
|
||||
child: ConstrainedBox(constraints: const BoxConstraints.expand(), child: child),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _DragToExpandLine extends StatelessWidget {
|
||||
const _DragToExpandLine({
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = context.watch<AppTheme>();
|
||||
|
||||
return InkWell(
|
||||
onTap: () {},
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onHorizontalDragCancel: () {},
|
||||
onHorizontalDragUpdate: (value) {
|
||||
// context.read<FieldCellBloc>().add(FieldCellEvent.updateWidth(value.delta.dx));
|
||||
Log.info(value);
|
||||
},
|
||||
onHorizontalDragEnd: (end) {
|
||||
Log.info(end);
|
||||
},
|
||||
child: FlowyHover(
|
||||
style: HoverStyle(
|
||||
hoverColor: theme.main1,
|
||||
borderRadius: BorderRadius.zero,
|
||||
contentMargin: const EdgeInsets.only(left: 5),
|
||||
),
|
||||
builder: (_, onHover) => const SizedBox(width: 2),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -32,15 +32,21 @@ class _GridHeaderSliverAdaptorState extends State<GridHeaderSliverAdaptor> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (context) =>
|
||||
getIt<GridHeaderBloc>(param1: widget.gridId, param2: widget.fieldCache)..add(const GridHeaderEvent.initial()),
|
||||
create: (context) {
|
||||
final bloc = getIt<GridHeaderBloc>(param1: widget.gridId, param2: widget.fieldCache);
|
||||
bloc.add(const GridHeaderEvent.initial());
|
||||
return bloc;
|
||||
},
|
||||
child: BlocBuilder<GridHeaderBloc, GridHeaderState>(
|
||||
buildWhen: (previous, current) => previous.fields.length != current.fields.length,
|
||||
builder: (context, state) {
|
||||
return SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
controller: widget.anchorScrollController,
|
||||
child: SizedBox(height: GridSize.headerHeight, child: _GridHeader(gridId: widget.gridId)),
|
||||
child: SizedBox(
|
||||
height: GridSize.headerHeight,
|
||||
child: _GridHeader(gridId: widget.gridId),
|
||||
),
|
||||
);
|
||||
|
||||
// return SliverPersistentHeader(
|
||||
@ -54,32 +60,6 @@ class _GridHeaderSliverAdaptorState extends State<GridHeaderSliverAdaptor> {
|
||||
}
|
||||
}
|
||||
|
||||
class SliverHeaderDelegateImplementation extends SliverPersistentHeaderDelegate {
|
||||
final String gridId;
|
||||
final List<Field> fields;
|
||||
|
||||
SliverHeaderDelegateImplementation({required this.gridId, required this.fields});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
|
||||
return _GridHeader(gridId: gridId);
|
||||
}
|
||||
|
||||
@override
|
||||
double get maxExtent => GridSize.headerHeight;
|
||||
|
||||
@override
|
||||
double get minExtent => GridSize.headerHeight;
|
||||
|
||||
@override
|
||||
bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) {
|
||||
if (oldDelegate is SliverHeaderDelegateImplementation) {
|
||||
return fields.length != oldDelegate.fields.length;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
class _GridHeader extends StatefulWidget {
|
||||
final String gridId;
|
||||
const _GridHeader({Key? key, required this.gridId}) : super(key: key);
|
||||
@ -177,3 +157,29 @@ class CreateFieldButton extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class SliverHeaderDelegateImplementation extends SliverPersistentHeaderDelegate {
|
||||
final String gridId;
|
||||
final List<Field> fields;
|
||||
|
||||
SliverHeaderDelegateImplementation({required this.gridId, required this.fields});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
|
||||
return _GridHeader(gridId: gridId);
|
||||
}
|
||||
|
||||
@override
|
||||
double get maxExtent => GridSize.headerHeight;
|
||||
|
||||
@override
|
||||
double get minExtent => GridSize.headerHeight;
|
||||
|
||||
@override
|
||||
bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) {
|
||||
if (oldDelegate is SliverHeaderDelegateImplementation) {
|
||||
return fields.length != oldDelegate.fields.length;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -44,10 +44,11 @@ class _GridRowWidgetState extends State<GridRowWidget> {
|
||||
child: BlocBuilder<RowBloc, RowState>(
|
||||
buildWhen: (p, c) => p.rowData.height != c.rowData.height,
|
||||
builder: (context, state) {
|
||||
return SizedBox(
|
||||
height: _rowBloc.state.rowData.height,
|
||||
return LimitedBox(
|
||||
maxHeight: 200,
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: const [
|
||||
_RowLeading(),
|
||||
_RowCells(),
|
||||
@ -147,7 +148,11 @@ class _RowCells extends StatelessWidget {
|
||||
buildWhen: (previous, current) => previous.cellDataMap != current.cellDataMap,
|
||||
builder: (context, state) {
|
||||
final List<Widget> children = state.cellDataMap.fold(() => [], _toCells);
|
||||
return Row(children: children);
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: children,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -51,16 +51,16 @@ impl ClientGridBlockMetaEditor {
|
||||
let mut row_count = 0;
|
||||
let mut row_index = None;
|
||||
let _ = self
|
||||
.modify(|pad| {
|
||||
.modify(|block_pad| {
|
||||
if let Some(start_row_id) = start_row_id.as_ref() {
|
||||
match pad.index_of_row(start_row_id) {
|
||||
match block_pad.index_of_row(start_row_id) {
|
||||
None => {}
|
||||
Some(index) => row_index = Some(index + 1),
|
||||
}
|
||||
}
|
||||
|
||||
let change = pad.add_row_meta(row, start_row_id)?;
|
||||
row_count = pad.number_of_rows();
|
||||
let change = block_pad.add_row_meta(row, start_row_id)?;
|
||||
row_count = block_pad.number_of_rows();
|
||||
Ok(change)
|
||||
})
|
||||
.await?;
|
||||
@ -71,9 +71,9 @@ impl ClientGridBlockMetaEditor {
|
||||
pub async fn delete_rows(&self, ids: Vec<Cow<'_, String>>) -> FlowyResult<i32> {
|
||||
let mut row_count = 0;
|
||||
let _ = self
|
||||
.modify(|pad| {
|
||||
let changeset = pad.delete_rows(ids)?;
|
||||
row_count = pad.number_of_rows();
|
||||
.modify(|block_pad| {
|
||||
let changeset = block_pad.delete_rows(ids)?;
|
||||
row_count = block_pad.number_of_rows();
|
||||
Ok(changeset)
|
||||
})
|
||||
.await?;
|
||||
@ -81,7 +81,14 @@ impl ClientGridBlockMetaEditor {
|
||||
}
|
||||
|
||||
pub async fn update_row(&self, changeset: RowMetaChangeset) -> FlowyResult<()> {
|
||||
let _ = self.modify(|pad| Ok(pad.update_row(changeset)?)).await?;
|
||||
let _ = self.modify(|block_pad| Ok(block_pad.update_row(changeset)?)).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn move_row(&self, row_id: &str, from: usize, to: usize) -> FlowyResult<()> {
|
||||
let _ = self
|
||||
.modify(|block_pad| Ok(block_pad.move_row(row_id, from, to)?))
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -154,6 +154,32 @@ impl GridBlockMetaEditorManager {
|
||||
Ok(changesets)
|
||||
}
|
||||
|
||||
pub(crate) async fn move_row(&self, row_id: &str, from: usize, to: usize) -> FlowyResult<()> {
|
||||
let editor = self.get_editor_from_row_id(row_id).await?;
|
||||
let _ = editor.move_row(row_id, from, to).await?;
|
||||
|
||||
match editor.get_row_metas(Some(vec![Cow::Borrowed(row_id)])).await?.pop() {
|
||||
None => {}
|
||||
Some(row_meta) => {
|
||||
let row_order = RowOrder::from(&row_meta);
|
||||
let insert_row = IndexRowOrder {
|
||||
row_order: row_order.clone(),
|
||||
index: Some(to as i32),
|
||||
};
|
||||
let notified_changeset = GridRowsChangeset {
|
||||
block_id: editor.block_id.clone(),
|
||||
inserted_rows: vec![insert_row],
|
||||
deleted_rows: vec![row_order],
|
||||
updated_rows: vec![],
|
||||
};
|
||||
|
||||
let _ = self.notify_did_update_rows(notified_changeset).await?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn update_cell(&self, changeset: CellChangeset) -> FlowyResult<()> {
|
||||
let row_id = changeset.row_id.clone();
|
||||
let editor = self.get_editor_from_row_id(&row_id).await?;
|
||||
|
@ -388,7 +388,7 @@ impl ClientGridEditor {
|
||||
self.move_field(¶ms.item_id, params.from_index, params.to_index)
|
||||
.await
|
||||
}
|
||||
MoveItemType::MoveRow => self.move_row(params.from_index, params.to_index, ¶ms.item_id).await,
|
||||
MoveItemType::MoveRow => self.move_row(¶ms.item_id, params.from_index, params.to_index).await,
|
||||
}
|
||||
}
|
||||
|
||||
@ -411,9 +411,12 @@ impl ClientGridEditor {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn move_row(&self, from: i32, to: i32, row_id: &str) -> FlowyResult<()> {
|
||||
// GridRowsChangeset
|
||||
todo!()
|
||||
pub async fn move_row(&self, row_id: &str, from: i32, to: i32) -> FlowyResult<()> {
|
||||
let _ = self
|
||||
.block_meta_manager
|
||||
.move_row(row_id, from as usize, to as usize)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn delta_bytes(&self) -> Bytes {
|
||||
|
@ -149,6 +149,19 @@ impl GridBlockMetaPad {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn move_row(&mut self, row_id: &str, from: usize, to: usize) -> CollaborateResult<Option<GridBlockMetaChange>> {
|
||||
self.modify(|row_metas| {
|
||||
if let Some(position) = row_metas.iter().position(|row_meta| row_meta.id == row_id) {
|
||||
debug_assert_eq!(from, position);
|
||||
let row_meta = row_metas.remove(position);
|
||||
row_metas.insert(to, row_meta);
|
||||
Ok(Some(()))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn modify<F>(&mut self, f: F) -> CollaborateResult<Option<GridBlockMetaChange>>
|
||||
where
|
||||
F: for<'a> FnOnce(&'a mut Vec<Arc<RowMeta>>) -> CollaborateResult<Option<()>>,
|
||||
|
Loading…
Reference in New Issue
Block a user