chore: enable drag to expand field's width

This commit is contained in:
appflowy 2022-05-31 16:14:12 +08:00
parent 4e3d2672ec
commit ab896cbc8f
5 changed files with 50 additions and 42 deletions

View File

@ -24,13 +24,15 @@ class FieldCellBloc extends Bloc<FieldCellEvent, FieldCellState> {
_startListening(); _startListening();
}, },
didReceiveFieldUpdate: (field) { didReceiveFieldUpdate: (field) {
emit(state.copyWith(field: field)); emit(state.copyWith(field: cellContext.field));
}, },
updateWidth: (offset) { startUpdateWidth: (offset) {
final defaultWidth = state.field.width.toDouble(); final width = state.width + offset;
final width = defaultWidth + offset; emit(state.copyWith(width: width));
if (width > defaultWidth && width < 300) { },
_fieldService.updateField(width: width); endUpdateWidth: () {
if (state.width != state.field.width.toDouble()) {
_fieldService.updateField(width: state.width);
} }
}, },
); );
@ -61,7 +63,8 @@ class FieldCellBloc extends Bloc<FieldCellEvent, FieldCellState> {
class FieldCellEvent with _$FieldCellEvent { class FieldCellEvent with _$FieldCellEvent {
const factory FieldCellEvent.initial() = _InitialCell; const factory FieldCellEvent.initial() = _InitialCell;
const factory FieldCellEvent.didReceiveFieldUpdate(Field field) = _DidReceiveFieldUpdate; const factory FieldCellEvent.didReceiveFieldUpdate(Field field) = _DidReceiveFieldUpdate;
const factory FieldCellEvent.updateWidth(double offset) = _UpdateWidth; const factory FieldCellEvent.startUpdateWidth(double offset) = _StartUpdateWidth;
const factory FieldCellEvent.endUpdateWidth() = _EndUpdateWidth;
} }
@freezed @freezed
@ -69,10 +72,12 @@ class FieldCellState with _$FieldCellState {
const factory FieldCellState({ const factory FieldCellState({
required String gridId, required String gridId,
required Field field, required Field field,
required double width,
}) = _FieldCellState; }) = _FieldCellState;
factory FieldCellState.initial(GridFieldCellContext cellContext) => FieldCellState( factory FieldCellState.initial(GridFieldCellContext cellContext) => FieldCellState(
gridId: cellContext.gridId, gridId: cellContext.gridId,
field: cellContext.field, field: cellContext.field,
width: cellContext.field.width.toDouble(),
); );
} }

View File

@ -30,7 +30,7 @@ class RowBloc extends Bloc<RowEvent, RowState> {
_rowService.createRow(); _rowService.createRow();
}, },
didReceiveCellDatas: (_DidReceiveCellDatas value) async { didReceiveCellDatas: (_DidReceiveCellDatas value) async {
final fields = value.gridCellMap.values.map((e) => CellSnapshot(e.field)).toList(); final fields = value.gridCellMap.values.map((e) => GridCellEquatable(e.field)).toList();
final snapshots = UnmodifiableListView(fields); final snapshots = UnmodifiableListView(fields);
emit(state.copyWith( emit(state.copyWith(
gridCellMap: value.gridCellMap, gridCellMap: value.gridCellMap,
@ -74,26 +74,27 @@ class RowState with _$RowState {
const factory RowState({ const factory RowState({
required GridRow rowData, required GridRow rowData,
required GridCellMap gridCellMap, required GridCellMap gridCellMap,
required UnmodifiableListView<CellSnapshot> snapshots, required UnmodifiableListView<GridCellEquatable> snapshots,
GridRowChangeReason? changeReason, GridRowChangeReason? changeReason,
}) = _RowState; }) = _RowState;
factory RowState.initial(GridRow rowData, GridCellMap cellDataMap) => RowState( factory RowState.initial(GridRow rowData, GridCellMap cellDataMap) => RowState(
rowData: rowData, rowData: rowData,
gridCellMap: cellDataMap, gridCellMap: cellDataMap,
snapshots: UnmodifiableListView(cellDataMap.values.map((e) => CellSnapshot(e.field)).toList()), snapshots: UnmodifiableListView(cellDataMap.values.map((e) => GridCellEquatable(e.field)).toList()),
); );
} }
class CellSnapshot extends Equatable { class GridCellEquatable extends Equatable {
final Field _field; final Field _field;
const CellSnapshot(Field field) : _field = field; const GridCellEquatable(Field field) : _field = field;
@override @override
List<Object?> get props => [ List<Object?> get props => [
_field.id, _field.id,
_field.fieldType, _field.fieldType,
_field.visibility, _field.visibility,
_field.width,
]; ];
} }

View File

@ -6,7 +6,6 @@ import 'package:flowy_infra/theme.dart';
import 'package:flowy_infra_ui/style_widget/button.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/hover.dart';
import 'package:flowy_infra_ui/style_widget/text.dart'; import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flowy_sdk/log.dart';
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show Field; import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show Field;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
@ -24,6 +23,7 @@ class GridFieldCell extends StatelessWidget {
return BlocProvider( return BlocProvider(
create: (context) => FieldCellBloc(cellContext: cellContext)..add(const FieldCellEvent.initial()), create: (context) => FieldCellBloc(cellContext: cellContext)..add(const FieldCellEvent.initial()),
child: BlocBuilder<FieldCellBloc, FieldCellState>( child: BlocBuilder<FieldCellBloc, FieldCellState>(
// buildWhen: (p, c) => p.field != c.field,
builder: (context, state) { builder: (context, state) {
final button = FieldCellButton( final button = FieldCellButton(
field: state.field, field: state.field,
@ -38,7 +38,7 @@ class GridFieldCell extends StatelessWidget {
); );
return _GridHeaderCellContainer( return _GridHeaderCellContainer(
width: state.field.width.toDouble(), width: state.width,
child: Stack( child: Stack(
alignment: Alignment.centerRight, alignment: Alignment.centerRight,
fit: StackFit.expand, fit: StackFit.expand,
@ -60,13 +60,14 @@ class GridFieldCell extends StatelessWidget {
void _showFieldEditor(BuildContext context) { void _showFieldEditor(BuildContext context) {
final state = context.read<FieldCellBloc>().state; final state = context.read<FieldCellBloc>().state;
final field = state.field;
FieldEditor( FieldEditor(
gridId: state.gridId, gridId: state.gridId,
fieldName: state.field.name, fieldName: field.name,
contextLoader: FieldContextLoader( contextLoader: FieldContextLoader(
gridId: state.gridId, gridId: state.gridId,
field: state.field, field: field,
), ),
).show(context); ).show(context);
} }
@ -113,19 +114,17 @@ class _DragToExpandLine extends StatelessWidget {
onTap: () {}, onTap: () {},
child: GestureDetector( child: GestureDetector(
behavior: HitTestBehavior.opaque, behavior: HitTestBehavior.opaque,
onHorizontalDragCancel: () {},
onHorizontalDragUpdate: (value) { onHorizontalDragUpdate: (value) {
// context.read<FieldCellBloc>().add(FieldCellEvent.updateWidth(value.delta.dx)); context.read<FieldCellBloc>().add(FieldCellEvent.startUpdateWidth(value.delta.dx));
Log.info(value);
}, },
onHorizontalDragEnd: (end) { onHorizontalDragEnd: (end) {
Log.info(end); context.read<FieldCellBloc>().add(const FieldCellEvent.endUpdateWidth());
}, },
child: FlowyHover( child: FlowyHover(
style: HoverStyle( style: HoverStyle(
hoverColor: theme.main1, hoverColor: theme.main1,
borderRadius: BorderRadius.zero, borderRadius: BorderRadius.zero,
contentMargin: const EdgeInsets.only(left: 5), contentMargin: const EdgeInsets.only(left: 6),
), ),
child: const SizedBox(width: 2), child: const SizedBox(width: 2),
), ),

View File

@ -27,7 +27,7 @@ impl TypeOptionBuilder for RichTextTypeOptionBuilder {
#[derive(Debug, Clone, Default, Serialize, Deserialize, ProtoBuf)] #[derive(Debug, Clone, Default, Serialize, Deserialize, ProtoBuf)]
pub struct RichTextTypeOption { pub struct RichTextTypeOption {
#[pb(index = 1)] #[pb(index = 1)]
data: String, //It's not used. data: String, //It's not used yet
} }
impl_type_option!(RichTextTypeOption, FieldType::RichText); impl_type_option!(RichTextTypeOption, FieldType::RichText);

View File

@ -30,7 +30,7 @@ impl TypeOptionBuilder for URLTypeOptionBuilder {
#[derive(Debug, Clone, Serialize, Deserialize, Default, ProtoBuf)] #[derive(Debug, Clone, Serialize, Deserialize, Default, ProtoBuf)]
pub struct URLTypeOption { pub struct URLTypeOption {
#[pb(index = 1)] #[pb(index = 1)]
data: String, //It's not used. data: String, //It's not used yet.
} }
impl_type_option!(URLTypeOption, FieldType::URL); impl_type_option!(URLTypeOption, FieldType::URL);
@ -56,28 +56,31 @@ impl CellDataOperation<EncodedCellData<URLCellData>, String> for URLTypeOption {
C: Into<CellContentChangeset>, C: Into<CellContentChangeset>,
{ {
let changeset = changeset.into(); let changeset = changeset.into();
let mut cell_data = URLCellData { let mut url = "".to_string();
url: "".to_string(),
content: changeset.to_string(),
};
if let Ok(Some(m)) = URL_REGEX.find(&changeset) { if let Ok(Some(m)) = URL_REGEX.find(&changeset) {
// Only support https scheme by now url = auto_append_scheme(m.as_str());
match url::Url::parse(m.as_str()) { }
Ok(url) => { URLCellData {
if url.scheme() == "https" { url,
cell_data.url = url.into(); content: changeset.to_string(),
} else { }
cell_data.url = format!("https://{}", m.as_str()); .to_json()
} }
} }
Err(_) => {
cell_data.url = format!("https://{}", m.as_str()); fn auto_append_scheme(s: &str) -> String {
} // Only support https scheme by now
match url::Url::parse(s) {
Ok(url) => {
if url.scheme() == "https" {
url.into()
} else {
format!("https://{}", s)
} }
} }
Err(_) => {
cell_data.to_json() format!("https://{}", s)
}
} }
} }