mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: allow fields to not wrap cell content (#5128)
This commit is contained in:
parent
891fd16a0c
commit
8947a89a24
@ -77,7 +77,7 @@ class _MobileDateCellEditScreenState extends State<MobileDateCellEditScreen> {
|
||||
create: (_) => DateCellEditorBloc(
|
||||
reminderBloc: getIt<ReminderBloc>(),
|
||||
cellController: widget.controller,
|
||||
)..add(const DateCellEditorEvent.initial()),
|
||||
),
|
||||
),
|
||||
],
|
||||
child: BlocBuilder<DateCellEditorBloc, DateCellEditorState>(
|
||||
|
@ -63,7 +63,7 @@ class _MobileEditPropertyScreenState extends State<MobileEditPropertyScreen> {
|
||||
isPrimary: widget.field.isPrimary,
|
||||
defaultValues: FieldOptionValues.fromField(field: widget.field.field),
|
||||
actions: [
|
||||
widget.field.fieldSettings?.visibility.isVisibleState() ?? true
|
||||
widget.field.visibility?.isVisibleState() ?? true
|
||||
? FieldOptionAction.hide
|
||||
: FieldOptionAction.show,
|
||||
FieldOptionAction.duplicate,
|
||||
|
@ -44,8 +44,8 @@ class _QuickEditFieldState extends State<QuickEditField> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
fieldVisibility = widget.fieldInfo.fieldSettings?.visibility ??
|
||||
FieldVisibility.AlwaysShown;
|
||||
fieldVisibility =
|
||||
widget.fieldInfo.visibility ?? FieldVisibility.AlwaysShown;
|
||||
controller.text = widget.fieldInfo.field.name;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:appflowy/plugins/database/application/cell/cell_controller_builder.dart';
|
||||
import 'package:appflowy/plugins/database/application/field/field_info.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
@ -20,8 +21,10 @@ class CheckboxCellBloc extends Bloc<CheckboxCellEvent, CheckboxCellState> {
|
||||
@override
|
||||
Future<void> close() async {
|
||||
if (_onCellChangedFn != null) {
|
||||
cellController.removeListener(_onCellChangedFn!);
|
||||
_onCellChangedFn = null;
|
||||
cellController.removeListener(
|
||||
onCellChanged: _onCellChangedFn!,
|
||||
onFieldChanged: _onFieldChangedListener,
|
||||
);
|
||||
}
|
||||
await cellController.dispose();
|
||||
return super.close();
|
||||
@ -53,13 +56,15 @@ class CheckboxCellBloc extends Bloc<CheckboxCellEvent, CheckboxCellState> {
|
||||
add(CheckboxCellEvent.didUpdateCell(_isSelected(cellData)));
|
||||
}
|
||||
},
|
||||
onCellFieldChanged: (field) {
|
||||
if (!isClosed) {
|
||||
add(CheckboxCellEvent.didUpdateField(field.name));
|
||||
}
|
||||
},
|
||||
onFieldChanged: _onFieldChangedListener,
|
||||
);
|
||||
}
|
||||
|
||||
void _onFieldChangedListener(FieldInfo fieldInfo) {
|
||||
if (!isClosed) {
|
||||
add(CheckboxCellEvent.didUpdateField(fieldInfo.name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@freezed
|
||||
|
@ -36,8 +36,7 @@ class ChecklistCellBloc extends Bloc<ChecklistCellEvent, ChecklistCellState> {
|
||||
@override
|
||||
Future<void> close() async {
|
||||
if (_onCellChangedFn != null) {
|
||||
cellController.removeListener(_onCellChangedFn!);
|
||||
_onCellChangedFn = null;
|
||||
cellController.removeListener(onCellChanged: _onCellChangedFn!);
|
||||
}
|
||||
await cellController.dispose();
|
||||
return super.close();
|
||||
@ -47,7 +46,7 @@ class ChecklistCellBloc extends Bloc<ChecklistCellEvent, ChecklistCellState> {
|
||||
on<ChecklistCellEvent>(
|
||||
(event, emit) async {
|
||||
await event.when(
|
||||
didReceiveOptions: (data) {
|
||||
didUpdateCell: (data) {
|
||||
if (data == null) {
|
||||
emit(
|
||||
const ChecklistCellState(
|
||||
@ -58,7 +57,6 @@ class ChecklistCellBloc extends Bloc<ChecklistCellEvent, ChecklistCellState> {
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
tasks: _makeChecklistSelectOptions(data),
|
||||
@ -91,7 +89,7 @@ class ChecklistCellBloc extends Bloc<ChecklistCellEvent, ChecklistCellState> {
|
||||
_onCellChangedFn = cellController.addListener(
|
||||
onCellChanged: (data) {
|
||||
if (!isClosed) {
|
||||
add(ChecklistCellEvent.didReceiveOptions(data));
|
||||
add(ChecklistCellEvent.didUpdateCell(data));
|
||||
}
|
||||
},
|
||||
);
|
||||
@ -111,9 +109,9 @@ class ChecklistCellBloc extends Bloc<ChecklistCellEvent, ChecklistCellState> {
|
||||
|
||||
@freezed
|
||||
class ChecklistCellEvent with _$ChecklistCellEvent {
|
||||
const factory ChecklistCellEvent.didReceiveOptions(
|
||||
const factory ChecklistCellEvent.didUpdateCell(
|
||||
ChecklistCellDataPB? data,
|
||||
) = _DidReceiveCellUpdate;
|
||||
) = _DidUpdateCell;
|
||||
const factory ChecklistCellEvent.updateTaskName(
|
||||
SelectOptionPB option,
|
||||
String name,
|
||||
|
@ -12,6 +12,7 @@ class DateCellBloc extends Bloc<DateCellEvent, DateCellState> {
|
||||
DateCellBloc({required this.cellController})
|
||||
: super(DateCellState.initial(cellController)) {
|
||||
_dispatch();
|
||||
_startListening();
|
||||
}
|
||||
|
||||
final DateCellController cellController;
|
||||
@ -20,8 +21,10 @@ class DateCellBloc extends Bloc<DateCellEvent, DateCellState> {
|
||||
@override
|
||||
Future<void> close() async {
|
||||
if (_onCellChangedFn != null) {
|
||||
cellController.removeListener(_onCellChangedFn!);
|
||||
_onCellChangedFn = null;
|
||||
cellController.removeListener(
|
||||
onCellChanged: _onCellChangedFn!,
|
||||
onFieldChanged: _onFieldChangedListener,
|
||||
);
|
||||
}
|
||||
await cellController.dispose();
|
||||
return super.close();
|
||||
@ -31,7 +34,6 @@ class DateCellBloc extends Bloc<DateCellEvent, DateCellState> {
|
||||
on<DateCellEvent>(
|
||||
(event, emit) async {
|
||||
event.when(
|
||||
initial: () => _startListening(),
|
||||
didReceiveCellUpdate: (DateCellDataPB? cellData) {
|
||||
emit(
|
||||
state.copyWith(
|
||||
@ -40,6 +42,9 @@ class DateCellBloc extends Bloc<DateCellEvent, DateCellState> {
|
||||
),
|
||||
);
|
||||
},
|
||||
didUpdateField: (fieldInfo) {
|
||||
emit(state.copyWith(fieldInfo: fieldInfo));
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
@ -52,15 +57,23 @@ class DateCellBloc extends Bloc<DateCellEvent, DateCellState> {
|
||||
add(DateCellEvent.didReceiveCellUpdate(data));
|
||||
}
|
||||
},
|
||||
onFieldChanged: _onFieldChangedListener,
|
||||
);
|
||||
}
|
||||
|
||||
void _onFieldChangedListener(FieldInfo fieldInfo) {
|
||||
if (!isClosed) {
|
||||
add(DateCellEvent.didUpdateField(fieldInfo));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@freezed
|
||||
class DateCellEvent with _$DateCellEvent {
|
||||
const factory DateCellEvent.initial() = _InitialCell;
|
||||
const factory DateCellEvent.didReceiveCellUpdate(DateCellDataPB? data) =
|
||||
_DidReceiveCellUpdate;
|
||||
const factory DateCellEvent.didUpdateField(FieldInfo fieldInfo) =
|
||||
_DidUpdateField;
|
||||
}
|
||||
|
||||
@freezed
|
||||
|
@ -39,6 +39,7 @@ class DateCellEditorBloc
|
||||
),
|
||||
super(DateCellEditorState.initial(cellController, reminderBloc)) {
|
||||
_dispatch();
|
||||
_startListening();
|
||||
}
|
||||
|
||||
final DateCellBackendService _dateCellBackendService;
|
||||
@ -50,7 +51,6 @@ class DateCellEditorBloc
|
||||
on<DateCellEditorEvent>(
|
||||
(event, emit) async {
|
||||
await event.when(
|
||||
initial: () async => _startListening(),
|
||||
didReceiveCellUpdate: (DateCellDataPB? cellData) {
|
||||
final dateCellData = _dateDataFromCellData(cellData);
|
||||
final endDay =
|
||||
@ -365,8 +365,9 @@ class DateCellEditorBloc
|
||||
@override
|
||||
Future<void> close() async {
|
||||
if (_onCellChangedFn != null) {
|
||||
cellController.removeListener(_onCellChangedFn!);
|
||||
_onCellChangedFn = null;
|
||||
cellController.removeListener(
|
||||
onCellChanged: _onCellChangedFn!,
|
||||
);
|
||||
}
|
||||
return super.close();
|
||||
}
|
||||
@ -417,9 +418,6 @@ class DateCellEditorBloc
|
||||
|
||||
@freezed
|
||||
class DateCellEditorEvent with _$DateCellEditorEvent {
|
||||
// initial event
|
||||
const factory DateCellEditorEvent.initial() = _Initial;
|
||||
|
||||
// notification that cell is updated in the backend
|
||||
const factory DateCellEditorEvent.didReceiveCellUpdate(
|
||||
DateCellDataPB? data,
|
||||
|
@ -1,15 +1,18 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:appflowy/plugins/database/application/cell/cell_controller_builder.dart';
|
||||
import 'package:appflowy/plugins/database/application/field/field_info.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'number_cell_bloc.freezed.dart';
|
||||
|
||||
class NumberCellBloc extends Bloc<NumberCellEvent, NumberCellState> {
|
||||
NumberCellBloc({required this.cellController})
|
||||
: super(NumberCellState.initial(cellController)) {
|
||||
NumberCellBloc({
|
||||
required this.cellController,
|
||||
}) : super(NumberCellState.initial(cellController)) {
|
||||
_dispatch();
|
||||
_startListening();
|
||||
}
|
||||
|
||||
final NumberCellController cellController;
|
||||
@ -18,8 +21,10 @@ class NumberCellBloc extends Bloc<NumberCellEvent, NumberCellState> {
|
||||
@override
|
||||
Future<void> close() async {
|
||||
if (_onCellChangedFn != null) {
|
||||
cellController.removeListener(_onCellChangedFn!);
|
||||
_onCellChangedFn = null;
|
||||
cellController.removeListener(
|
||||
onCellChanged: _onCellChangedFn!,
|
||||
onFieldChanged: _onFieldChangedListener,
|
||||
);
|
||||
}
|
||||
await cellController.dispose();
|
||||
return super.close();
|
||||
@ -29,12 +34,15 @@ class NumberCellBloc extends Bloc<NumberCellEvent, NumberCellState> {
|
||||
on<NumberCellEvent>(
|
||||
(event, emit) async {
|
||||
await event.when(
|
||||
initial: () {
|
||||
_startListening();
|
||||
},
|
||||
didReceiveCellUpdate: (cellData) {
|
||||
emit(state.copyWith(content: cellData ?? ""));
|
||||
},
|
||||
didUpdateField: (fieldInfo) {
|
||||
final wrap = fieldInfo.wrapCellContent;
|
||||
if (wrap != null) {
|
||||
emit(state.copyWith(wrap: wrap));
|
||||
}
|
||||
},
|
||||
updateCell: (text) async {
|
||||
if (state.content != text) {
|
||||
emit(state.copyWith(content: text));
|
||||
@ -62,27 +70,38 @@ class NumberCellBloc extends Bloc<NumberCellEvent, NumberCellState> {
|
||||
add(NumberCellEvent.didReceiveCellUpdate(cellContent));
|
||||
}
|
||||
},
|
||||
onFieldChanged: _onFieldChangedListener,
|
||||
);
|
||||
}
|
||||
|
||||
void _onFieldChangedListener(FieldInfo fieldInfo) {
|
||||
if (!isClosed) {
|
||||
add(NumberCellEvent.didUpdateField(fieldInfo));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@freezed
|
||||
class NumberCellEvent with _$NumberCellEvent {
|
||||
const factory NumberCellEvent.initial() = _Initial;
|
||||
const factory NumberCellEvent.updateCell(String text) = _UpdateCell;
|
||||
const factory NumberCellEvent.didReceiveCellUpdate(String? cellContent) =
|
||||
_DidReceiveCellUpdate;
|
||||
const factory NumberCellEvent.didUpdateField(FieldInfo fieldInfo) =
|
||||
_DidUpdateField;
|
||||
const factory NumberCellEvent.updateCell(String text) = _UpdateCell;
|
||||
}
|
||||
|
||||
@freezed
|
||||
class NumberCellState with _$NumberCellState {
|
||||
const factory NumberCellState({
|
||||
required String content,
|
||||
required bool wrap,
|
||||
}) = _NumberCellState;
|
||||
|
||||
factory NumberCellState.initial(TextCellController cellController) {
|
||||
final wrap = cellController.fieldInfo.wrapCellContent;
|
||||
return NumberCellState(
|
||||
content: cellController.getCellData() ?? "",
|
||||
wrap: wrap ?? true,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:appflowy/plugins/database/application/cell/cell_controller_builder.dart';
|
||||
import 'package:appflowy/plugins/database/application/field/field_info.dart';
|
||||
import 'package:appflowy/plugins/database/application/field/type_option/relation_type_option_cubit.dart';
|
||||
import 'package:appflowy/plugins/database/application/field/type_option/type_option_data_parser.dart';
|
||||
import 'package:appflowy/plugins/database/domain/field_service.dart';
|
||||
@ -16,7 +17,7 @@ part 'relation_cell_bloc.freezed.dart';
|
||||
|
||||
class RelationCellBloc extends Bloc<RelationCellEvent, RelationCellState> {
|
||||
RelationCellBloc({required this.cellController})
|
||||
: super(RelationCellState.initial()) {
|
||||
: super(RelationCellState.initial(cellController)) {
|
||||
_dispatch();
|
||||
_startListening();
|
||||
_init();
|
||||
@ -28,8 +29,10 @@ class RelationCellBloc extends Bloc<RelationCellEvent, RelationCellState> {
|
||||
@override
|
||||
Future<void> close() async {
|
||||
if (_onCellChangedFn != null) {
|
||||
cellController.removeListener(_onCellChangedFn!);
|
||||
_onCellChangedFn = null;
|
||||
cellController.removeListener(
|
||||
onCellChanged: _onCellChangedFn!,
|
||||
onFieldChanged: _onFieldChangedListener,
|
||||
);
|
||||
}
|
||||
return super.close();
|
||||
}
|
||||
@ -38,7 +41,7 @@ class RelationCellBloc extends Bloc<RelationCellEvent, RelationCellState> {
|
||||
on<RelationCellEvent>(
|
||||
(event, emit) async {
|
||||
await event.when(
|
||||
didUpdateCell: (RelationCellDataPB? cellData) async {
|
||||
didUpdateCell: (cellData) async {
|
||||
if (cellData == null ||
|
||||
cellData.rowIds.isEmpty ||
|
||||
state.relatedDatabaseMeta == null) {
|
||||
@ -60,7 +63,13 @@ class RelationCellBloc extends Bloc<RelationCellEvent, RelationCellState> {
|
||||
);
|
||||
emit(state.copyWith(rows: rows));
|
||||
},
|
||||
didUpdateRelationTypeOption: (typeOption) async {
|
||||
didUpdateField: (FieldInfo fieldInfo) async {
|
||||
final wrap = fieldInfo.wrapCellContent;
|
||||
if (wrap != null) {
|
||||
emit(state.copyWith(wrap: wrap));
|
||||
}
|
||||
final RelationTypeOptionPB typeOption =
|
||||
cellController.getTypeOption(RelationTypeOptionDataParser());
|
||||
if (typeOption.databaseId.isEmpty) {
|
||||
return;
|
||||
}
|
||||
@ -86,25 +95,23 @@ class RelationCellBloc extends Bloc<RelationCellEvent, RelationCellState> {
|
||||
add(RelationCellEvent.didUpdateCell(data));
|
||||
}
|
||||
},
|
||||
onCellFieldChanged: (field) {
|
||||
if (!isClosed) {
|
||||
final RelationTypeOptionPB typeOption =
|
||||
cellController.getTypeOption(RelationTypeOptionDataParser());
|
||||
add(RelationCellEvent.didUpdateRelationTypeOption(typeOption));
|
||||
}
|
||||
},
|
||||
onFieldChanged: _onFieldChangedListener,
|
||||
);
|
||||
}
|
||||
|
||||
void _onFieldChangedListener(FieldInfo fieldInfo) {
|
||||
if (!isClosed) {
|
||||
add(RelationCellEvent.didUpdateField(fieldInfo));
|
||||
}
|
||||
}
|
||||
|
||||
void _init() {
|
||||
final typeOption =
|
||||
cellController.getTypeOption(RelationTypeOptionDataParser());
|
||||
add(RelationCellEvent.didUpdateRelationTypeOption(typeOption));
|
||||
add(RelationCellEvent.didUpdateField(cellController.fieldInfo));
|
||||
}
|
||||
|
||||
void _loadCellData() {
|
||||
final cellData = cellController.getCellData();
|
||||
if (!isClosed) {
|
||||
if (!isClosed && cellData != null) {
|
||||
add(RelationCellEvent.didUpdateCell(cellData));
|
||||
}
|
||||
}
|
||||
@ -166,11 +173,10 @@ class RelationCellBloc extends Bloc<RelationCellEvent, RelationCellState> {
|
||||
|
||||
@freezed
|
||||
class RelationCellEvent with _$RelationCellEvent {
|
||||
const factory RelationCellEvent.didUpdateRelationTypeOption(
|
||||
RelationTypeOptionPB typeOption,
|
||||
) = _DidUpdateRelationTypeOption;
|
||||
const factory RelationCellEvent.didUpdateCell(RelationCellDataPB? data) =
|
||||
_DidUpdateCell;
|
||||
const factory RelationCellEvent.didUpdateField(FieldInfo fieldInfo) =
|
||||
_DidUpdateField;
|
||||
const factory RelationCellEvent.selectDatabaseId(
|
||||
String databaseId,
|
||||
) = _SelectDatabaseId;
|
||||
@ -182,10 +188,15 @@ class RelationCellState with _$RelationCellState {
|
||||
const factory RelationCellState({
|
||||
required DatabaseMeta? relatedDatabaseMeta,
|
||||
required List<RelatedRowDataPB> rows,
|
||||
required bool wrap,
|
||||
}) = _RelationCellState;
|
||||
|
||||
factory RelationCellState.initial() => const RelationCellState(
|
||||
relatedDatabaseMeta: null,
|
||||
rows: [],
|
||||
);
|
||||
factory RelationCellState.initial(RelationCellController cellController) {
|
||||
final wrap = cellController.fieldInfo.wrapCellContent;
|
||||
return RelationCellState(
|
||||
relatedDatabaseMeta: null,
|
||||
rows: [],
|
||||
wrap: wrap ?? true,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:appflowy/plugins/database/application/cell/cell_controller_builder.dart';
|
||||
import 'package:appflowy/plugins/database/application/field/field_info.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/select_option_entities.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
@ -9,9 +10,11 @@ part 'select_option_cell_bloc.freezed.dart';
|
||||
|
||||
class SelectOptionCellBloc
|
||||
extends Bloc<SelectOptionCellEvent, SelectOptionCellState> {
|
||||
SelectOptionCellBloc({required this.cellController})
|
||||
: super(SelectOptionCellState.initial(cellController)) {
|
||||
SelectOptionCellBloc({
|
||||
required this.cellController,
|
||||
}) : super(SelectOptionCellState.initial(cellController)) {
|
||||
_dispatch();
|
||||
_startListening();
|
||||
}
|
||||
|
||||
final SelectOptionCellController cellController;
|
||||
@ -20,8 +23,10 @@ class SelectOptionCellBloc
|
||||
@override
|
||||
Future<void> close() async {
|
||||
if (_onCellChangedFn != null) {
|
||||
cellController.removeListener(_onCellChangedFn!);
|
||||
_onCellChangedFn = null;
|
||||
cellController.removeListener(
|
||||
onCellChanged: _onCellChangedFn!,
|
||||
onFieldChanged: _onFieldChangedListener,
|
||||
);
|
||||
}
|
||||
await cellController.dispose();
|
||||
return super.close();
|
||||
@ -29,11 +34,8 @@ class SelectOptionCellBloc
|
||||
|
||||
void _dispatch() {
|
||||
on<SelectOptionCellEvent>(
|
||||
(event, emit) async {
|
||||
await event.when(
|
||||
initial: () async {
|
||||
_startListening();
|
||||
},
|
||||
(event, emit) {
|
||||
event.when(
|
||||
didReceiveOptions: (List<SelectOptionPB> selectedOptions) {
|
||||
emit(
|
||||
state.copyWith(
|
||||
@ -41,6 +43,12 @@ class SelectOptionCellBloc
|
||||
),
|
||||
);
|
||||
},
|
||||
didUpdateField: (fieldInfo) {
|
||||
final wrap = fieldInfo.wrapCellContent;
|
||||
if (wrap != null) {
|
||||
emit(state.copyWith(wrap: wrap));
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
@ -57,31 +65,41 @@ class SelectOptionCellBloc
|
||||
);
|
||||
}
|
||||
},
|
||||
onFieldChanged: _onFieldChangedListener,
|
||||
);
|
||||
}
|
||||
|
||||
void _onFieldChangedListener(FieldInfo fieldInfo) {
|
||||
if (!isClosed) {
|
||||
add(SelectOptionCellEvent.didUpdateField(fieldInfo));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@freezed
|
||||
class SelectOptionCellEvent with _$SelectOptionCellEvent {
|
||||
const factory SelectOptionCellEvent.initial() = _InitialCell;
|
||||
const factory SelectOptionCellEvent.didReceiveOptions(
|
||||
List<SelectOptionPB> selectedOptions,
|
||||
) = _DidReceiveOptions;
|
||||
const factory SelectOptionCellEvent.didUpdateField(FieldInfo fieldInfo) =
|
||||
_DidUpdateField;
|
||||
}
|
||||
|
||||
@freezed
|
||||
class SelectOptionCellState with _$SelectOptionCellState {
|
||||
const factory SelectOptionCellState({
|
||||
required List<SelectOptionPB> selectedOptions,
|
||||
required bool wrap,
|
||||
}) = _SelectOptionCellState;
|
||||
|
||||
factory SelectOptionCellState.initial(
|
||||
SelectOptionCellController cellController,
|
||||
) {
|
||||
final data = cellController.getCellData();
|
||||
|
||||
final wrap = cellController.fieldInfo.wrapCellContent;
|
||||
return SelectOptionCellState(
|
||||
selectedOptions: data?.selectOptions ?? [],
|
||||
wrap: wrap ?? true,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:appflowy/plugins/database/application/cell/cell_controller_builder.dart';
|
||||
import 'package:appflowy/plugins/database/application/field/field_info.dart';
|
||||
import 'package:appflowy/plugins/database/application/field/type_option/select_type_option_actions.dart';
|
||||
import 'package:appflowy/plugins/database/application/field/type_option/type_option_data_parser.dart';
|
||||
import 'package:appflowy/plugins/database/domain/field_service.dart';
|
||||
@ -163,8 +164,10 @@ class SelectOptionCellEditorBloc
|
||||
@override
|
||||
Future<void> close() async {
|
||||
if (_onCellChangedFn != null) {
|
||||
cellController.removeListener(_onCellChangedFn!);
|
||||
_onCellChangedFn = null;
|
||||
cellController.removeListener(
|
||||
onCellChanged: _onCellChangedFn!,
|
||||
onFieldChanged: _onFieldChangedListener,
|
||||
);
|
||||
}
|
||||
return super.close();
|
||||
}
|
||||
@ -172,27 +175,25 @@ class SelectOptionCellEditorBloc
|
||||
void _startListening() {
|
||||
_onCellChangedFn = cellController.addListener(
|
||||
onCellChanged: (cellData) {
|
||||
if (isClosed) {
|
||||
Log.warn("Unexpecteded closing the bloc");
|
||||
return;
|
||||
if (!isClosed) {
|
||||
add(
|
||||
SelectOptionCellEditorEvent.didUpdateCell(
|
||||
cellData == null ? [] : cellData.selectOptions,
|
||||
),
|
||||
);
|
||||
}
|
||||
add(
|
||||
SelectOptionCellEditorEvent.didUpdateCell(
|
||||
cellData == null ? [] : cellData.selectOptions,
|
||||
),
|
||||
);
|
||||
},
|
||||
onCellFieldChanged: (field) {
|
||||
if (isClosed) {
|
||||
Log.warn("Unexpecteded closing the bloc");
|
||||
return;
|
||||
}
|
||||
final loadedOptions = _loadAllOptions(cellController);
|
||||
add(SelectOptionCellEditorEvent.didUpdateOptions(loadedOptions));
|
||||
},
|
||||
onFieldChanged: _onFieldChangedListener,
|
||||
);
|
||||
}
|
||||
|
||||
void _onFieldChangedListener(FieldInfo fieldInfo) {
|
||||
if (!isClosed) {
|
||||
final loadedOptions = _loadAllOptions(cellController);
|
||||
add(SelectOptionCellEditorEvent.didUpdateOptions(loadedOptions));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _createOption({
|
||||
required String name,
|
||||
required SelectOptionColorPB color,
|
||||
|
@ -1,6 +1,7 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:appflowy/plugins/database/application/cell/cell_controller_builder.dart';
|
||||
import 'package:appflowy/plugins/database/application/field/field_info.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
@ -10,6 +11,7 @@ class TextCellBloc extends Bloc<TextCellEvent, TextCellState> {
|
||||
TextCellBloc({required this.cellController})
|
||||
: super(TextCellState.initial(cellController)) {
|
||||
_dispatch();
|
||||
_startListening();
|
||||
}
|
||||
|
||||
final TextCellController cellController;
|
||||
@ -18,8 +20,10 @@ class TextCellBloc extends Bloc<TextCellEvent, TextCellState> {
|
||||
@override
|
||||
Future<void> close() async {
|
||||
if (_onCellChangedFn != null) {
|
||||
cellController.removeListener(_onCellChangedFn!);
|
||||
_onCellChangedFn = null;
|
||||
cellController.removeListener(
|
||||
onCellChanged: _onCellChangedFn!,
|
||||
onFieldChanged: _onFieldChangedListener,
|
||||
);
|
||||
}
|
||||
await cellController.dispose();
|
||||
return super.close();
|
||||
@ -29,12 +33,15 @@ class TextCellBloc extends Bloc<TextCellEvent, TextCellState> {
|
||||
on<TextCellEvent>(
|
||||
(event, emit) {
|
||||
event.when(
|
||||
initial: () {
|
||||
_startListening();
|
||||
},
|
||||
didReceiveCellUpdate: (String content) {
|
||||
emit(state.copyWith(content: content));
|
||||
},
|
||||
didUpdateField: (fieldInfo) {
|
||||
final wrap = fieldInfo.wrapCellContent;
|
||||
if (wrap != null) {
|
||||
emit(state.copyWith(wrap: wrap));
|
||||
}
|
||||
},
|
||||
didUpdateEmoji: (String emoji) {
|
||||
emit(state.copyWith(emoji: emoji));
|
||||
},
|
||||
@ -58,20 +65,30 @@ class TextCellBloc extends Bloc<TextCellEvent, TextCellState> {
|
||||
add(TextCellEvent.didReceiveCellUpdate(cellContent ?? ""));
|
||||
}
|
||||
},
|
||||
onRowMetaChanged: () {
|
||||
if (!isClosed && cellController.fieldInfo.isPrimary) {
|
||||
add(TextCellEvent.didUpdateEmoji(cellController.icon ?? ""));
|
||||
}
|
||||
},
|
||||
onFieldChanged: _onFieldChangedListener,
|
||||
onRowMetaChanged: cellController.fieldInfo.isPrimary
|
||||
? () {
|
||||
if (!isClosed) {
|
||||
add(TextCellEvent.didUpdateEmoji(cellController.icon ?? ""));
|
||||
}
|
||||
}
|
||||
: null,
|
||||
);
|
||||
}
|
||||
|
||||
void _onFieldChangedListener(FieldInfo fieldInfo) {
|
||||
if (!isClosed) {
|
||||
add(TextCellEvent.didUpdateField(fieldInfo));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@freezed
|
||||
class TextCellEvent with _$TextCellEvent {
|
||||
const factory TextCellEvent.initial() = _InitialCell;
|
||||
const factory TextCellEvent.didReceiveCellUpdate(String cellContent) =
|
||||
_DidReceiveCellUpdate;
|
||||
const factory TextCellEvent.didUpdateField(FieldInfo fieldInfo) =
|
||||
_DidUpdateField;
|
||||
const factory TextCellEvent.updateText(String text) = _UpdateText;
|
||||
const factory TextCellEvent.enableEdit(bool enabled) = _EnableEdit;
|
||||
const factory TextCellEvent.didUpdateEmoji(String emoji) = _UpdateEmoji;
|
||||
@ -83,13 +100,20 @@ class TextCellState with _$TextCellState {
|
||||
required String content,
|
||||
required String emoji,
|
||||
required bool enableEdit,
|
||||
required bool wrap,
|
||||
}) = _TextCellState;
|
||||
|
||||
factory TextCellState.initial(TextCellController cellController) =>
|
||||
TextCellState(
|
||||
content: cellController.getCellData() ?? "",
|
||||
emoji:
|
||||
cellController.fieldInfo.isPrimary ? cellController.icon ?? "" : "",
|
||||
enableEdit: false,
|
||||
);
|
||||
factory TextCellState.initial(TextCellController cellController) {
|
||||
final cellData = cellController.getCellData() ?? "";
|
||||
final wrap = cellController.fieldInfo.wrapCellContent ?? false;
|
||||
final emoji =
|
||||
cellController.fieldInfo.isPrimary ? cellController.icon ?? "" : "";
|
||||
|
||||
return TextCellState(
|
||||
content: cellData,
|
||||
emoji: emoji,
|
||||
enableEdit: false,
|
||||
wrap: wrap,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -9,9 +9,11 @@ import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
part 'timestamp_cell_bloc.freezed.dart';
|
||||
|
||||
class TimestampCellBloc extends Bloc<TimestampCellEvent, TimestampCellState> {
|
||||
TimestampCellBloc({required this.cellController})
|
||||
: super(TimestampCellState.initial(cellController)) {
|
||||
TimestampCellBloc({
|
||||
required this.cellController,
|
||||
}) : super(TimestampCellState.initial(cellController)) {
|
||||
_dispatch();
|
||||
_startListening();
|
||||
}
|
||||
|
||||
final TimestampCellController cellController;
|
||||
@ -20,8 +22,10 @@ class TimestampCellBloc extends Bloc<TimestampCellEvent, TimestampCellState> {
|
||||
@override
|
||||
Future<void> close() async {
|
||||
if (_onCellChangedFn != null) {
|
||||
cellController.removeListener(_onCellChangedFn!);
|
||||
_onCellChangedFn = null;
|
||||
cellController.removeListener(
|
||||
onCellChanged: _onCellChangedFn!,
|
||||
onFieldChanged: _onFieldChangedListener,
|
||||
);
|
||||
}
|
||||
await cellController.dispose();
|
||||
return super.close();
|
||||
@ -31,7 +35,6 @@ class TimestampCellBloc extends Bloc<TimestampCellEvent, TimestampCellState> {
|
||||
on<TimestampCellEvent>(
|
||||
(event, emit) async {
|
||||
event.when(
|
||||
initial: () => _startListening(),
|
||||
didReceiveCellUpdate: (TimestampCellDataPB? cellData) {
|
||||
emit(
|
||||
state.copyWith(
|
||||
@ -40,6 +43,12 @@ class TimestampCellBloc extends Bloc<TimestampCellEvent, TimestampCellState> {
|
||||
),
|
||||
);
|
||||
},
|
||||
didUpdateField: (fieldInfo) {
|
||||
final wrap = fieldInfo.wrapCellContent;
|
||||
if (wrap != null) {
|
||||
emit(state.copyWith(wrap: wrap));
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
@ -52,16 +61,24 @@ class TimestampCellBloc extends Bloc<TimestampCellEvent, TimestampCellState> {
|
||||
add(TimestampCellEvent.didReceiveCellUpdate(data));
|
||||
}
|
||||
},
|
||||
onFieldChanged: _onFieldChangedListener,
|
||||
);
|
||||
}
|
||||
|
||||
void _onFieldChangedListener(FieldInfo fieldInfo) {
|
||||
if (!isClosed) {
|
||||
add(TimestampCellEvent.didUpdateField(fieldInfo));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@freezed
|
||||
class TimestampCellEvent with _$TimestampCellEvent {
|
||||
const factory TimestampCellEvent.initial() = _InitialCell;
|
||||
const factory TimestampCellEvent.didReceiveCellUpdate(
|
||||
TimestampCellDataPB? data,
|
||||
) = _DidReceiveCellUpdate;
|
||||
const factory TimestampCellEvent.didUpdateField(FieldInfo fieldInfo) =
|
||||
_DidUpdateField;
|
||||
}
|
||||
|
||||
@freezed
|
||||
@ -70,15 +87,18 @@ class TimestampCellState with _$TimestampCellState {
|
||||
required TimestampCellDataPB? data,
|
||||
required String dateStr,
|
||||
required FieldInfo fieldInfo,
|
||||
required bool wrap,
|
||||
}) = _TimestampCellState;
|
||||
|
||||
factory TimestampCellState.initial(TimestampCellController context) {
|
||||
final cellData = context.getCellData();
|
||||
factory TimestampCellState.initial(TimestampCellController cellController) {
|
||||
final cellData = cellController.getCellData();
|
||||
final wrap = cellController.fieldInfo.wrapCellContent;
|
||||
|
||||
return TimestampCellState(
|
||||
fieldInfo: context.fieldInfo,
|
||||
fieldInfo: cellController.fieldInfo,
|
||||
data: cellData,
|
||||
dateStr: cellData?.dateTime ?? "",
|
||||
wrap: wrap ?? true,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:appflowy/plugins/database/application/cell/cell_controller_builder.dart';
|
||||
import 'package:appflowy/plugins/database/application/field/field_info.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/url_entities.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
@ -9,9 +10,11 @@ import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
part 'url_cell_bloc.freezed.dart';
|
||||
|
||||
class URLCellBloc extends Bloc<URLCellEvent, URLCellState> {
|
||||
URLCellBloc({required this.cellController})
|
||||
: super(URLCellState.initial(cellController)) {
|
||||
URLCellBloc({
|
||||
required this.cellController,
|
||||
}) : super(URLCellState.initial(cellController)) {
|
||||
_dispatch();
|
||||
_startListening();
|
||||
}
|
||||
|
||||
final URLCellController cellController;
|
||||
@ -20,8 +23,10 @@ class URLCellBloc extends Bloc<URLCellEvent, URLCellState> {
|
||||
@override
|
||||
Future<void> close() async {
|
||||
if (_onCellChangedFn != null) {
|
||||
cellController.removeListener(_onCellChangedFn!);
|
||||
_onCellChangedFn = null;
|
||||
cellController.removeListener(
|
||||
onCellChanged: _onCellChangedFn!,
|
||||
onFieldChanged: _onFieldChangedListener,
|
||||
);
|
||||
}
|
||||
await cellController.dispose();
|
||||
return super.close();
|
||||
@ -31,12 +36,9 @@ class URLCellBloc extends Bloc<URLCellEvent, URLCellState> {
|
||||
on<URLCellEvent>(
|
||||
(event, emit) async {
|
||||
await event.when(
|
||||
initial: () {
|
||||
_startListening();
|
||||
},
|
||||
didReceiveCellUpdate: (cellData) async {
|
||||
didUpdateCell: (cellData) async {
|
||||
final content = cellData?.content ?? "";
|
||||
final isValid = await isUrlValid(content);
|
||||
final isValid = await _isUrlValid(content);
|
||||
emit(
|
||||
state.copyWith(
|
||||
content: content,
|
||||
@ -44,6 +46,12 @@ class URLCellBloc extends Bloc<URLCellEvent, URLCellState> {
|
||||
),
|
||||
);
|
||||
},
|
||||
didUpdateField: (fieldInfo) {
|
||||
final wrap = fieldInfo.wrapCellContent;
|
||||
if (wrap != null) {
|
||||
emit(state.copyWith(wrap: wrap));
|
||||
}
|
||||
},
|
||||
updateURL: (String url) {
|
||||
cellController.saveCellData(url, debounce: true);
|
||||
},
|
||||
@ -56,13 +64,20 @@ class URLCellBloc extends Bloc<URLCellEvent, URLCellState> {
|
||||
_onCellChangedFn = cellController.addListener(
|
||||
onCellChanged: (cellData) {
|
||||
if (!isClosed) {
|
||||
add(URLCellEvent.didReceiveCellUpdate(cellData));
|
||||
add(URLCellEvent.didUpdateCell(cellData));
|
||||
}
|
||||
},
|
||||
onFieldChanged: _onFieldChangedListener,
|
||||
);
|
||||
}
|
||||
|
||||
Future<bool> isUrlValid(String content) async {
|
||||
void _onFieldChangedListener(FieldInfo fieldInfo) {
|
||||
if (!isClosed) {
|
||||
add(URLCellEvent.didUpdateField(fieldInfo));
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> _isUrlValid(String content) async {
|
||||
if (content.isEmpty) {
|
||||
return true;
|
||||
}
|
||||
@ -90,10 +105,11 @@ class URLCellBloc extends Bloc<URLCellEvent, URLCellState> {
|
||||
|
||||
@freezed
|
||||
class URLCellEvent with _$URLCellEvent {
|
||||
const factory URLCellEvent.initial() = _InitialCell;
|
||||
const factory URLCellEvent.updateURL(String url) = _UpdateURL;
|
||||
const factory URLCellEvent.didReceiveCellUpdate(URLCellDataPB? cell) =
|
||||
_DidReceiveCellUpdate;
|
||||
const factory URLCellEvent.didUpdateCell(URLCellDataPB? cell) =
|
||||
_DidUpdateCell;
|
||||
const factory URLCellEvent.didUpdateField(FieldInfo fieldInfo) =
|
||||
_DidUpdateField;
|
||||
}
|
||||
|
||||
@freezed
|
||||
@ -101,13 +117,16 @@ class URLCellState with _$URLCellState {
|
||||
const factory URLCellState({
|
||||
required String content,
|
||||
required bool isValid,
|
||||
required bool wrap,
|
||||
}) = _URLCellState;
|
||||
|
||||
factory URLCellState.initial(URLCellController context) {
|
||||
final cellData = context.getCellData();
|
||||
factory URLCellState.initial(URLCellController cellController) {
|
||||
final cellData = cellController.getCellData();
|
||||
final wrap = cellController.fieldInfo.wrapCellContent;
|
||||
return URLCellState(
|
||||
content: cellData?.content ?? "",
|
||||
isValid: true,
|
||||
wrap: wrap ?? true,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,86 +0,0 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:appflowy/plugins/database/application/cell/cell_controller_builder.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/url_entities.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'url_cell_editor_bloc.freezed.dart';
|
||||
|
||||
class URLCellEditorBloc extends Bloc<URLCellEditorEvent, URLCellEditorState> {
|
||||
URLCellEditorBloc({required this.cellController})
|
||||
: super(URLCellEditorState.initial(cellController)) {
|
||||
_dispatch();
|
||||
}
|
||||
|
||||
final URLCellController cellController;
|
||||
void Function()? _onCellChangedFn;
|
||||
|
||||
void _dispatch() {
|
||||
on<URLCellEditorEvent>(
|
||||
(event, emit) async {
|
||||
await event.when(
|
||||
initial: () {
|
||||
_startListening();
|
||||
},
|
||||
updateText: (text) async {
|
||||
await cellController.saveCellData(text);
|
||||
emit(
|
||||
state.copyWith(
|
||||
content: text,
|
||||
isFinishEditing: true,
|
||||
),
|
||||
);
|
||||
},
|
||||
didReceiveCellUpdate: (cellData) {
|
||||
emit(state.copyWith(content: cellData?.content ?? ""));
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() async {
|
||||
if (_onCellChangedFn != null) {
|
||||
cellController.removeListener(_onCellChangedFn!);
|
||||
_onCellChangedFn = null;
|
||||
}
|
||||
await cellController.dispose();
|
||||
return super.close();
|
||||
}
|
||||
|
||||
void _startListening() {
|
||||
_onCellChangedFn = cellController.addListener(
|
||||
onCellChanged: (cellData) {
|
||||
if (!isClosed) {
|
||||
add(URLCellEditorEvent.didReceiveCellUpdate(cellData));
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@freezed
|
||||
class URLCellEditorEvent with _$URLCellEditorEvent {
|
||||
const factory URLCellEditorEvent.initial() = _InitialCell;
|
||||
const factory URLCellEditorEvent.didReceiveCellUpdate(URLCellDataPB? cell) =
|
||||
_DidReceiveCellUpdate;
|
||||
const factory URLCellEditorEvent.updateText(String text) = _UpdateText;
|
||||
}
|
||||
|
||||
@freezed
|
||||
class URLCellEditorState with _$URLCellEditorState {
|
||||
const factory URLCellEditorState({
|
||||
required String content,
|
||||
required bool isFinishEditing,
|
||||
}) = _URLCellEditorState;
|
||||
|
||||
factory URLCellEditorState.initial(URLCellController context) {
|
||||
final cellData = context.getCellData();
|
||||
return URLCellEditorState(
|
||||
content: cellData?.content ?? "",
|
||||
isFinishEditing: true,
|
||||
);
|
||||
}
|
||||
}
|
@ -64,7 +64,6 @@ class CellController<T, D> {
|
||||
RowMetaListener? _rowMetaListener;
|
||||
CellDataNotifier<T?>? _cellDataNotifier;
|
||||
|
||||
void Function(FieldInfo field)? _onCellFieldChanged;
|
||||
VoidCallback? _onRowMetaChanged;
|
||||
Timer? _loadDataOperation;
|
||||
Timer? _saveDataOperation;
|
||||
@ -104,16 +103,7 @@ class CellController<T, D> {
|
||||
// 2. Listen on the field event and load the cell data if needed.
|
||||
_fieldController.addSingleFieldListener(
|
||||
fieldId,
|
||||
onFieldChanged: (fieldInfo) {
|
||||
// reloadOnFieldChanged should be true if you want to reload the cell
|
||||
// data when the corresponding field is changed.
|
||||
// For example:
|
||||
// ¥12 -> $12
|
||||
if (_cellDataLoader.reloadOnFieldChange) {
|
||||
_loadData();
|
||||
}
|
||||
_onCellFieldChanged?.call(fieldInfo);
|
||||
},
|
||||
onFieldChanged: _onFieldChangedListener,
|
||||
);
|
||||
|
||||
// 3. If the field is primary listen to row meta changes.
|
||||
@ -130,22 +120,49 @@ class CellController<T, D> {
|
||||
/// Add a new listener
|
||||
VoidCallback? addListener({
|
||||
required void Function(T?) onCellChanged,
|
||||
void Function(FieldInfo field)? onCellFieldChanged,
|
||||
void Function(FieldInfo fieldInfo)? onFieldChanged,
|
||||
VoidCallback? onRowMetaChanged,
|
||||
}) {
|
||||
_onCellFieldChanged = onCellFieldChanged;
|
||||
_onRowMetaChanged = onRowMetaChanged;
|
||||
|
||||
/// Notify the listener, the cell data was changed.
|
||||
/// an adaptor for the onCellChanged listener
|
||||
void onCellChangedFn() => onCellChanged(_cellDataNotifier?.value);
|
||||
_cellDataNotifier?.addListener(onCellChangedFn);
|
||||
|
||||
if (onFieldChanged != null) {
|
||||
_fieldController.addSingleFieldListener(
|
||||
fieldId,
|
||||
onFieldChanged: onFieldChanged,
|
||||
);
|
||||
}
|
||||
|
||||
_onRowMetaChanged = onRowMetaChanged;
|
||||
|
||||
// Return the function pointer that can be used when calling removeListener.
|
||||
return onCellChangedFn;
|
||||
}
|
||||
|
||||
void removeListener(VoidCallback fn) {
|
||||
_cellDataNotifier?.removeListener(fn);
|
||||
void removeListener({
|
||||
required VoidCallback onCellChanged,
|
||||
void Function(FieldInfo fieldInfo)? onFieldChanged,
|
||||
VoidCallback? onRowMetaChanged,
|
||||
}) {
|
||||
_cellDataNotifier?.removeListener(onCellChanged);
|
||||
|
||||
if (onFieldChanged != null) {
|
||||
_fieldController.removeSingleFieldListener(
|
||||
fieldId: fieldId,
|
||||
onFieldChanged: onFieldChanged,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void _onFieldChangedListener(FieldInfo fieldInfo) {
|
||||
// reloadOnFieldChanged should be true if you want to reload the cell
|
||||
// data when the corresponding field is changed.
|
||||
// For example:
|
||||
// ¥12 -> $12
|
||||
if (_cellDataLoader.reloadOnFieldChange) {
|
||||
_loadData();
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the cell data. The cell data will be read from the cache first,
|
||||
@ -218,6 +235,11 @@ class CellController<T, D> {
|
||||
await _cellListener?.stop();
|
||||
_cellListener = null;
|
||||
|
||||
_fieldController.removeSingleFieldListener(
|
||||
fieldId: fieldId,
|
||||
onFieldChanged: _onFieldChangedListener,
|
||||
);
|
||||
|
||||
_loadDataOperation?.cancel();
|
||||
_saveDataOperation?.cancel();
|
||||
_cellDataNotifier?.dispose();
|
||||
|
@ -37,12 +37,7 @@ class CellDataLoader<T> {
|
||||
(result) => result.fold(
|
||||
(CellPB cell) {
|
||||
try {
|
||||
// Return null if the data of the cell is empty.
|
||||
if (cell.data.isEmpty) {
|
||||
return null;
|
||||
} else {
|
||||
return parser.parserData(cell.data);
|
||||
}
|
||||
return parser.parserData(cell.data);
|
||||
} catch (e, s) {
|
||||
Log.error('$parser parser cellData failed, $e');
|
||||
Log.error('Stack trace \n $s');
|
||||
|
@ -30,8 +30,7 @@ class FieldCellBloc extends Bloc<FieldCellEvent, FieldCellState> {
|
||||
emit(state.copyWith(width: width));
|
||||
},
|
||||
endUpdateWidth: () {
|
||||
if (state.width !=
|
||||
state.fieldInfo.fieldSettings?.width.toDouble()) {
|
||||
if (state.width != state.fieldInfo.width) {
|
||||
_fieldSettingsService.updateFieldSettings(
|
||||
fieldId: state.fieldInfo.id,
|
||||
width: state.width,
|
||||
|
@ -99,6 +99,14 @@ class FieldEditorBloc extends Bloc<FieldEditorEvent, FieldEditorState> {
|
||||
);
|
||||
_logIfError(result);
|
||||
},
|
||||
toggleWrapCellContent: () async {
|
||||
final currentWrap = state.field.wrapCellContent ?? false;
|
||||
final result = await fieldSettingsService.updateFieldSettings(
|
||||
fieldId: state.field.id,
|
||||
wrapCellContent: !currentWrap,
|
||||
);
|
||||
_logIfError(result);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
@ -148,6 +156,8 @@ class FieldEditorEvent with _$FieldEditorEvent {
|
||||
const factory FieldEditorEvent.insertRight() = _InsertRight;
|
||||
const factory FieldEditorEvent.toggleFieldVisibility() =
|
||||
_ToggleFieldVisiblity;
|
||||
const factory FieldEditorEvent.toggleWrapCellContent() =
|
||||
_ToggleWrapCellContent;
|
||||
}
|
||||
|
||||
@freezed
|
||||
|
@ -31,8 +31,12 @@ class FieldInfo with _$FieldInfo {
|
||||
|
||||
bool get isPrimary => field.isPrimary;
|
||||
|
||||
double? get width => fieldSettings?.width.toDouble();
|
||||
|
||||
FieldVisibility? get visibility => fieldSettings?.visibility;
|
||||
|
||||
bool? get wrapCellContent => fieldSettings?.wrapCellContent;
|
||||
|
||||
bool get canBeGroup {
|
||||
switch (field.fieldType) {
|
||||
case FieldType.URL:
|
||||
|
@ -58,6 +58,7 @@ class FieldSettingsBackendService {
|
||||
required String fieldId,
|
||||
FieldVisibility? fieldVisibility,
|
||||
double? width,
|
||||
bool? wrapCellContent,
|
||||
}) {
|
||||
final FieldSettingsChangesetPB payload = FieldSettingsChangesetPB.create()
|
||||
..viewId = viewId
|
||||
@ -71,6 +72,10 @@ class FieldSettingsBackendService {
|
||||
payload.width = width.round();
|
||||
}
|
||||
|
||||
if (wrapCellContent != null) {
|
||||
payload.wrapCellContent = wrapCellContent;
|
||||
}
|
||||
|
||||
return DatabaseEventUpdateFieldSettings(payload).send();
|
||||
}
|
||||
}
|
||||
|
@ -441,7 +441,7 @@ class _AddRowButton extends StatelessWidget {
|
||||
|
||||
double getMobileGridContentWidth(List<FieldInfo> fields) {
|
||||
final visibleFields = fields.where(
|
||||
(field) => field.fieldSettings?.visibility != FieldVisibility.AlwaysHidden,
|
||||
(field) => field.visibility != FieldVisibility.AlwaysHidden,
|
||||
);
|
||||
return (visibleFields.length + 1) * 200 +
|
||||
GridSize.horizontalHeaderPadding * 2;
|
||||
|
@ -113,7 +113,7 @@ List<CellContext> _makeCells(
|
||||
cellContexts.removeWhere((cellContext) {
|
||||
final fieldInfo = fieldController.getField(cellContext.fieldId);
|
||||
return fieldInfo == null ||
|
||||
!(fieldInfo.fieldSettings?.visibility.isVisibleState() ?? false) ||
|
||||
!(fieldInfo.visibility?.isVisibleState() ?? false) ||
|
||||
(groupFieldId != null && cellContext.fieldId == groupFieldId);
|
||||
});
|
||||
return cellContexts.toList();
|
||||
|
@ -41,7 +41,7 @@ class _DateCellState extends State<DateCardCell> {
|
||||
widget.databaseController,
|
||||
widget.cellContext,
|
||||
).as(),
|
||||
)..add(const DateCellEvent.initial());
|
||||
);
|
||||
},
|
||||
child: BlocBuilder<DateCellBloc, DateCellState>(
|
||||
buildWhen: (previous, current) => previous.dateStr != current.dateStr,
|
||||
|
@ -41,7 +41,7 @@ class _NumberCellState extends State<NumberCardCell> {
|
||||
widget.databaseController,
|
||||
widget.cellContext,
|
||||
).as(),
|
||||
)..add(const NumberCellEvent.initial());
|
||||
);
|
||||
},
|
||||
child: BlocBuilder<NumberCellBloc, NumberCellState>(
|
||||
buildWhen: (previous, current) => previous.content != current.content,
|
||||
|
@ -46,7 +46,7 @@ class _SelectOptionCellState extends State<SelectOptionCardCell> {
|
||||
widget.databaseController,
|
||||
widget.cellContext,
|
||||
).as(),
|
||||
)..add(const SelectOptionCellEvent.initial());
|
||||
);
|
||||
},
|
||||
child: BlocBuilder<SelectOptionCellBloc, SelectOptionCellState>(
|
||||
buildWhen: (previous, current) {
|
||||
|
@ -52,7 +52,7 @@ class _TextCellState extends State<TextCardCell> {
|
||||
widget.databaseController,
|
||||
widget.cellContext,
|
||||
).as(),
|
||||
)..add(const TextCellEvent.initial());
|
||||
);
|
||||
late final TextEditingController _textEditingController =
|
||||
TextEditingController(text: cellBloc.state.content);
|
||||
final focusNode = SingleListenerFocusNode();
|
||||
|
@ -41,7 +41,7 @@ class _TimestampCellState extends State<TimestampCardCell> {
|
||||
widget.databaseController,
|
||||
widget.cellContext,
|
||||
).as(),
|
||||
)..add(const TimestampCellEvent.initial());
|
||||
);
|
||||
},
|
||||
child: BlocBuilder<TimestampCellBloc, TimestampCellState>(
|
||||
buildWhen: (previous, current) => previous.dateStr != current.dateStr,
|
||||
|
@ -41,7 +41,7 @@ class _URLCellState extends State<URLCardCell> {
|
||||
widget.databaseController,
|
||||
widget.cellContext,
|
||||
).as(),
|
||||
)..add(const URLCellEvent.initial());
|
||||
);
|
||||
},
|
||||
child: BlocBuilder<URLCellBloc, URLCellState>(
|
||||
buildWhen: (previous, current) => previous.content != current.content,
|
||||
|
@ -27,27 +27,15 @@ class DesktopGridDateCellSkin extends IEditableDateCellSkin {
|
||||
direction: PopoverDirection.bottomWithLeftAligned,
|
||||
constraints: BoxConstraints.loose(const Size(260, 620)),
|
||||
margin: EdgeInsets.zero,
|
||||
child: Container(
|
||||
child: Align(
|
||||
alignment: AlignmentDirectional.centerStart,
|
||||
padding: GridSize.cellContentInsets,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Flexible(
|
||||
child: FlowyText.medium(
|
||||
state.dateStr,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
child: state.fieldInfo.wrapCellContent ?? false
|
||||
? _buildCellContent(state)
|
||||
: SingleChildScrollView(
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: _buildCellContent(state),
|
||||
),
|
||||
),
|
||||
if (state.data?.reminderId.isNotEmpty ?? false) ...[
|
||||
const HSpace(4),
|
||||
FlowyTooltip(
|
||||
message: LocaleKeys.grid_field_reminderOnDateTooltip.tr(),
|
||||
child: const FlowySvg(FlowySvgs.clock_alarm_s),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
popupBuilder: (BuildContext popoverContent) {
|
||||
return DateCellEditor(
|
||||
@ -60,4 +48,30 @@ class DesktopGridDateCellSkin extends IEditableDateCellSkin {
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildCellContent(DateCellState state) {
|
||||
final wrap = state.fieldInfo.wrapCellContent ?? false;
|
||||
return Padding(
|
||||
padding: GridSize.cellContentInsets,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Flexible(
|
||||
child: FlowyText.medium(
|
||||
state.dateStr,
|
||||
overflow: wrap ? null : TextOverflow.ellipsis,
|
||||
maxLines: wrap ? null : 1,
|
||||
),
|
||||
),
|
||||
if (state.data?.reminderId.isNotEmpty ?? false) ...[
|
||||
const HSpace(4),
|
||||
FlowyTooltip(
|
||||
message: LocaleKeys.grid_field_reminderOnDateTooltip.tr(),
|
||||
child: const FlowySvg(FlowySvgs.clock_alarm_s),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ import 'package:appflowy/plugins/database/grid/presentation/layout/sizes.dart';
|
||||
import 'package:appflowy/plugins/database/widgets/row/cells/cell_container.dart';
|
||||
import 'package:appflowy/plugins/database/application/cell/bloc/number_cell_bloc.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
import '../editable_cell_skeleton/number.dart';
|
||||
|
||||
@ -19,7 +20,7 @@ class DesktopGridNumberCellSkin extends IEditableNumberCellSkin {
|
||||
focusNode: focusNode,
|
||||
onEditingComplete: () => focusNode.unfocus(),
|
||||
onSubmitted: (_) => focusNode.unfocus(),
|
||||
maxLines: null,
|
||||
maxLines: context.watch<NumberCellBloc>().state.wrap ? null : 1,
|
||||
style: Theme.of(context).textTheme.bodyMedium,
|
||||
textInputAction: TextInputAction.done,
|
||||
decoration: InputDecoration(
|
||||
|
@ -3,6 +3,7 @@ import 'package:appflowy/plugins/database/grid/presentation/layout/sizes.dart';
|
||||
import 'package:appflowy/plugins/database/widgets/row/cells/cell_container.dart';
|
||||
import 'package:appflowy/plugins/database/widgets/cell_editor/relation_cell_editor.dart';
|
||||
import 'package:appflowy/plugins/database/application/cell/bloc/relation_cell_bloc.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
|
||||
import 'package:appflowy_popover/appflowy_popover.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
@ -32,13 +33,52 @@ class DesktopGridRelationCellSkin extends IEditableRelationCellSkin {
|
||||
child: const RelationCellEditor(),
|
||||
);
|
||||
},
|
||||
child: Container(
|
||||
child: Align(
|
||||
alignment: AlignmentDirectional.centerStart,
|
||||
child: state.wrap
|
||||
? _buildWrapRows(context, state.rows)
|
||||
: _buildNoWrapRows(context, state.rows),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildWrapRows(
|
||||
BuildContext context,
|
||||
List<RelatedRowDataPB> rows,
|
||||
) {
|
||||
return Padding(
|
||||
padding: GridSize.cellContentInsets,
|
||||
child: Wrap(
|
||||
runSpacing: 4,
|
||||
spacing: 4.0,
|
||||
children: rows.map(
|
||||
(row) {
|
||||
final isEmpty = row.name.isEmpty;
|
||||
return FlowyText.medium(
|
||||
isEmpty ? LocaleKeys.grid_row_titlePlaceholder.tr() : row.name,
|
||||
color: isEmpty ? Theme.of(context).hintColor : null,
|
||||
decoration: TextDecoration.underline,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
);
|
||||
},
|
||||
).toList(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildNoWrapRows(
|
||||
BuildContext context,
|
||||
List<RelatedRowDataPB> rows,
|
||||
) {
|
||||
return SingleChildScrollView(
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: Padding(
|
||||
padding: GridSize.cellContentInsets,
|
||||
child: Wrap(
|
||||
runSpacing: 4.0,
|
||||
spacing: 4.0,
|
||||
children: state.rows.map(
|
||||
child: SeparatedRow(
|
||||
separatorBuilder: () => const HSpace(4.0),
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: rows.map(
|
||||
(row) {
|
||||
final isEmpty = row.name.isEmpty;
|
||||
return FlowyText.medium(
|
||||
|
@ -3,7 +3,7 @@ import 'package:appflowy/plugins/database/widgets/row/cells/cell_container.dart'
|
||||
import 'package:appflowy/plugins/database/widgets/cell_editor/extension.dart';
|
||||
import 'package:appflowy/plugins/database/application/cell/bloc/select_option_cell_bloc.dart';
|
||||
import 'package:appflowy/plugins/database/widgets/cell_editor/select_option_cell_editor.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/select_option_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
|
||||
import 'package:appflowy_popover/appflowy_popover.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
@ -23,6 +23,7 @@ class DesktopGridSelectOptionCellSkin extends IEditableSelectOptionCellSkin {
|
||||
controller: popoverController,
|
||||
constraints: const BoxConstraints.tightFor(width: 300),
|
||||
margin: EdgeInsets.zero,
|
||||
triggerActions: PopoverTriggerFlags.none,
|
||||
direction: PopoverDirection.bottomWithLeftAligned,
|
||||
popupBuilder: (BuildContext popoverContext) {
|
||||
return SelectOptionCellEditor(
|
||||
@ -32,35 +33,67 @@ class DesktopGridSelectOptionCellSkin extends IEditableSelectOptionCellSkin {
|
||||
onClose: () => cellContainerNotifier.isFocus = false,
|
||||
child: BlocBuilder<SelectOptionCellBloc, SelectOptionCellState>(
|
||||
builder: (context, state) {
|
||||
return Container(
|
||||
return Align(
|
||||
alignment: AlignmentDirectional.centerStart,
|
||||
padding: GridSize.cellContentInsets,
|
||||
child: state.selectedOptions.isEmpty
|
||||
? const SizedBox.shrink()
|
||||
: _buildOptions(context, state.selectedOptions),
|
||||
child: state.wrap
|
||||
? _buildWrapOptions(context, state.selectedOptions)
|
||||
: _buildNoWrapOptions(context, state.selectedOptions),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildOptions(context, List<SelectOptionPB> options) {
|
||||
return Wrap(
|
||||
runSpacing: 4,
|
||||
children: options.map(
|
||||
(option) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(right: 4),
|
||||
child: SelectOptionTag(
|
||||
option: option,
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 1,
|
||||
horizontal: 8,
|
||||
Widget _buildWrapOptions(BuildContext context, List<SelectOptionPB> options) {
|
||||
return Padding(
|
||||
padding: GridSize.cellContentInsets,
|
||||
child: Wrap(
|
||||
runSpacing: 4,
|
||||
children: options.map(
|
||||
(option) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(right: 4),
|
||||
child: SelectOptionTag(
|
||||
option: option,
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 1,
|
||||
horizontal: 8,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
).toList(),
|
||||
);
|
||||
},
|
||||
).toList(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildNoWrapOptions(
|
||||
BuildContext context,
|
||||
List<SelectOptionPB> options,
|
||||
) {
|
||||
return SingleChildScrollView(
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: Padding(
|
||||
padding: GridSize.cellContentInsets,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: options.map(
|
||||
(option) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(right: 4),
|
||||
child: SelectOptionTag(
|
||||
option: option,
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 1,
|
||||
horizontal: 8,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
).toList(),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ class DesktopGridTextCellSkin extends IEditableTextCellSkin {
|
||||
child: TextField(
|
||||
controller: textEditingController,
|
||||
focusNode: focusNode,
|
||||
maxLines: null,
|
||||
maxLines: context.watch<TextCellBloc>().state.wrap ? null : 1,
|
||||
style: Theme.of(context).textTheme.bodyMedium,
|
||||
decoration: const InputDecoration(
|
||||
border: InputBorder.none,
|
||||
|
@ -16,10 +16,23 @@ class DesktopGridTimestampCellSkin extends IEditableTimestampCellSkin {
|
||||
) {
|
||||
return Container(
|
||||
alignment: AlignmentDirectional.centerStart,
|
||||
child: state.wrap
|
||||
? _buildCellContent(state)
|
||||
: SingleChildScrollView(
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: _buildCellContent(state),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildCellContent(TimestampCellState state) {
|
||||
return Padding(
|
||||
padding: GridSize.cellContentInsets,
|
||||
child: FlowyText.medium(
|
||||
state.dateStr,
|
||||
maxLines: null,
|
||||
overflow: state.wrap ? null : TextOverflow.ellipsis,
|
||||
maxLines: state.wrap ? null : 1,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ import 'package:appflowy/workspace/presentation/home/toast.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra/theme_extension.dart';
|
||||
import 'package:flowy_infra_ui/widget/flowy_tooltip.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
import '../editable_cell_skeleton/url.dart';
|
||||
|
||||
@ -24,28 +25,31 @@ class DesktopGridURLSkin extends IEditableURLCellSkin {
|
||||
TextEditingController textEditingController,
|
||||
URLCellDataNotifier cellDataNotifier,
|
||||
) {
|
||||
return TextField(
|
||||
controller: textEditingController,
|
||||
focusNode: focusNode,
|
||||
maxLines: null,
|
||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
decoration: TextDecoration.underline,
|
||||
),
|
||||
decoration: InputDecoration(
|
||||
contentPadding: GridSize.cellContentInsets,
|
||||
border: InputBorder.none,
|
||||
focusedBorder: InputBorder.none,
|
||||
enabledBorder: InputBorder.none,
|
||||
errorBorder: InputBorder.none,
|
||||
disabledBorder: InputBorder.none,
|
||||
hintStyle: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyMedium
|
||||
?.copyWith(color: Theme.of(context).hintColor),
|
||||
isDense: true,
|
||||
return BlocSelector<URLCellBloc, URLCellState, bool>(
|
||||
selector: (state) => state.wrap,
|
||||
builder: (context, wrap) => TextField(
|
||||
controller: textEditingController,
|
||||
focusNode: focusNode,
|
||||
maxLines: wrap ? null : 1,
|
||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
decoration: TextDecoration.underline,
|
||||
),
|
||||
decoration: InputDecoration(
|
||||
contentPadding: GridSize.cellContentInsets,
|
||||
border: InputBorder.none,
|
||||
focusedBorder: InputBorder.none,
|
||||
enabledBorder: InputBorder.none,
|
||||
errorBorder: InputBorder.none,
|
||||
disabledBorder: InputBorder.none,
|
||||
hintStyle: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyMedium
|
||||
?.copyWith(color: Theme.of(context).hintColor),
|
||||
isDense: true,
|
||||
),
|
||||
onTapOutside: (_) => focusNode.unfocus(),
|
||||
),
|
||||
onTapOutside: (_) => focusNode.unfocus(),
|
||||
);
|
||||
}
|
||||
|
||||
@ -179,8 +183,7 @@ class _VisitURLAccessoryState extends State<_VisitURLAccessory>
|
||||
bool enable() => widget.cellDataNotifier.value.isNotEmpty;
|
||||
|
||||
@override
|
||||
void onTap() =>
|
||||
openUrlCellLink(widget.cellDataNotifier.value);
|
||||
void onTap() => openUrlCellLink(widget.cellDataNotifier.value);
|
||||
}
|
||||
|
||||
class _URLAccessoryIconContainer extends StatelessWidget {
|
||||
@ -190,9 +193,8 @@ class _URLAccessoryIconContainer extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SizedBox(
|
||||
width: 26,
|
||||
height: 26,
|
||||
return SizedBox.square(
|
||||
dimension: 26,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(3.0),
|
||||
child: child,
|
||||
|
@ -57,7 +57,7 @@ class _DateCellState extends GridCellState<EditableDateCell> {
|
||||
widget.databaseController,
|
||||
widget.cellContext,
|
||||
).as(),
|
||||
)..add(const DateCellEvent.initial());
|
||||
);
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
|
@ -58,7 +58,7 @@ class _NumberCellState extends GridEditableTextCell<EditableNumberCell> {
|
||||
widget.databaseController,
|
||||
widget.cellContext,
|
||||
).as(),
|
||||
)..add(const NumberCellEvent.initial());
|
||||
);
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@ -81,12 +81,16 @@ class _NumberCellState extends GridEditableTextCell<EditableNumberCell> {
|
||||
child: BlocListener<NumberCellBloc, NumberCellState>(
|
||||
listener: (context, state) =>
|
||||
_textEditingController.text = state.content,
|
||||
child: widget.skin.build(
|
||||
context,
|
||||
widget.cellContainerNotifier,
|
||||
cellBloc,
|
||||
focusNode,
|
||||
_textEditingController,
|
||||
child: Builder(
|
||||
builder: (context) {
|
||||
return widget.skin.build(
|
||||
context,
|
||||
widget.cellContainerNotifier,
|
||||
cellBloc,
|
||||
focusNode,
|
||||
_textEditingController,
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
|
@ -64,7 +64,7 @@ class _SelectOptionCellState extends GridCellState<EditableSelectOptionCell> {
|
||||
widget.databaseController,
|
||||
widget.cellContext,
|
||||
).as(),
|
||||
)..add(const SelectOptionCellEvent.initial());
|
||||
);
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
|
@ -58,7 +58,7 @@ class _TextCellState extends GridEditableTextCell<EditableTextCell> {
|
||||
widget.databaseController,
|
||||
widget.cellContext,
|
||||
).as(),
|
||||
)..add(const TextCellEvent.initial());
|
||||
);
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@ -82,12 +82,16 @@ class _TextCellState extends GridEditableTextCell<EditableTextCell> {
|
||||
listener: (context, state) {
|
||||
_textEditingController.text = state.content;
|
||||
},
|
||||
child: widget.skin.build(
|
||||
context,
|
||||
widget.cellContainerNotifier,
|
||||
cellBloc,
|
||||
focusNode,
|
||||
_textEditingController,
|
||||
child: Builder(
|
||||
builder: (context) {
|
||||
return widget.skin.build(
|
||||
context,
|
||||
widget.cellContainerNotifier,
|
||||
cellBloc,
|
||||
focusNode,
|
||||
_textEditingController,
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
|
@ -57,7 +57,7 @@ class _TimestampCellState extends GridCellState<EditableTimestampCell> {
|
||||
widget.databaseController,
|
||||
widget.cellContext,
|
||||
).as(),
|
||||
)..add(const TimestampCellEvent.initial());
|
||||
);
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
|
@ -85,7 +85,7 @@ class _GridURLCellState extends GridEditableTextCell<EditableURLCell> {
|
||||
widget.databaseController,
|
||||
widget.cellContext,
|
||||
).as(),
|
||||
)..add(const URLCellEvent.initial());
|
||||
);
|
||||
|
||||
@override
|
||||
SingleListenerFocusNode focusNode = SingleListenerFocusNode();
|
||||
|
@ -42,7 +42,7 @@ class _DateCellEditor extends State<DateCellEditor> {
|
||||
create: (context) => DateCellEditorBloc(
|
||||
reminderBloc: getIt<ReminderBloc>(),
|
||||
cellController: widget.cellController,
|
||||
)..add(const DateCellEditorEvent.initial()),
|
||||
),
|
||||
),
|
||||
],
|
||||
child: BlocBuilder<DateCellEditorBloc, DateCellEditorState>(
|
||||
|
@ -1,7 +1,5 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/plugins/database/application/field/field_controller.dart';
|
||||
@ -12,12 +10,14 @@ import 'package:appflowy/plugins/database/grid/presentation/layout/sizes.dart';
|
||||
import 'package:appflowy/plugins/database/grid/presentation/widgets/common/type_option_separator.dart';
|
||||
import 'package:appflowy/util/field_type_extension.dart';
|
||||
import 'package:appflowy/workspace/presentation/widgets/dialogs.dart';
|
||||
import 'package:appflowy/workspace/presentation/widgets/toggle/toggle.dart';
|
||||
import 'package:appflowy/workspace/presentation/widgets/toggle/toggle_style.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
|
||||
import 'package:appflowy_popover/appflowy_popover.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
|
||||
import 'field_type_list.dart';
|
||||
import 'type_option_editor/builder.dart';
|
||||
@ -87,10 +87,12 @@ class _FieldEditorState extends State<FieldEditor> {
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
FieldNameTextField(
|
||||
padding: const EdgeInsets.fromLTRB(4, 4, 4, 8),
|
||||
padding: const EdgeInsets.fromLTRB(12, 12, 12, 8),
|
||||
textEditingController: textController,
|
||||
),
|
||||
VSpace(GridSize.typeOptionSeparatorHeight),
|
||||
_EditFieldButton(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||
onTap: () {
|
||||
setState(() => _currentPage = FieldEditorPage.details);
|
||||
},
|
||||
@ -107,8 +109,11 @@ class _FieldEditorState extends State<FieldEditor> {
|
||||
_actionCell(FieldAction.clearData),
|
||||
VSpace(GridSize.typeOptionSeparatorHeight),
|
||||
_actionCell(FieldAction.delete),
|
||||
const TypeOptionSeparator(spacing: 8.0),
|
||||
_actionCell(FieldAction.wrap),
|
||||
const VSpace(8.0),
|
||||
],
|
||||
).padding(all: 8.0),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@ -124,24 +129,32 @@ class _FieldEditorState extends State<FieldEditor> {
|
||||
|
||||
Widget _actionCell(FieldAction action) {
|
||||
return BlocBuilder<FieldEditorBloc, FieldEditorState>(
|
||||
builder: (context, state) => FieldActionCell(
|
||||
viewId: widget.viewId,
|
||||
fieldInfo: state.field,
|
||||
action: action,
|
||||
builder: (context, state) => Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||
child: FieldActionCell(
|
||||
viewId: widget.viewId,
|
||||
fieldInfo: state.field,
|
||||
action: action,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _EditFieldButton extends StatelessWidget {
|
||||
const _EditFieldButton({this.onTap});
|
||||
const _EditFieldButton({
|
||||
required this.padding,
|
||||
this.onTap,
|
||||
});
|
||||
|
||||
final EdgeInsetsGeometry padding;
|
||||
final void Function()? onTap;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SizedBox(
|
||||
return Container(
|
||||
height: GridSize.popoverItemHeight,
|
||||
padding: padding,
|
||||
child: FlowyButton(
|
||||
leftIcon: const FlowySvg(FlowySvgs.edit_s),
|
||||
text: FlowyText.medium(
|
||||
@ -184,10 +197,11 @@ class FieldActionCell extends StatelessWidget {
|
||||
),
|
||||
onHover: (_) => popoverMutex?.close(),
|
||||
onTap: () => action.run(context, viewId, fieldInfo),
|
||||
leftIcon: action.icon(
|
||||
leftIcon: action.leading(
|
||||
fieldInfo,
|
||||
enable ? null : Theme.of(context).disabledColor,
|
||||
),
|
||||
rightIcon: action.trailing(context, fieldInfo),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -198,10 +212,11 @@ enum FieldAction {
|
||||
toggleVisibility,
|
||||
duplicate,
|
||||
clearData,
|
||||
delete;
|
||||
delete,
|
||||
wrap;
|
||||
|
||||
Widget icon(FieldInfo fieldInfo, Color? color) {
|
||||
late final FlowySvgData svgData;
|
||||
Widget? leading(FieldInfo fieldInfo, Color? color) {
|
||||
FlowySvgData? svgData;
|
||||
switch (this) {
|
||||
case FieldAction.insertLeft:
|
||||
svgData = FlowySvgs.arrow_s;
|
||||
@ -220,6 +235,11 @@ enum FieldAction {
|
||||
svgData = FlowySvgs.reload_s;
|
||||
case FieldAction.delete:
|
||||
svgData = FlowySvgs.delete_s;
|
||||
default:
|
||||
}
|
||||
|
||||
if (svgData == null) {
|
||||
return null;
|
||||
}
|
||||
final icon = FlowySvg(
|
||||
svgData,
|
||||
@ -231,6 +251,21 @@ enum FieldAction {
|
||||
: icon;
|
||||
}
|
||||
|
||||
Widget? trailing(BuildContext context, FieldInfo fieldInfo) {
|
||||
if (this == FieldAction.wrap) {
|
||||
return Toggle(
|
||||
value: fieldInfo.wrapCellContent ?? false,
|
||||
onChanged: (_) => context
|
||||
.read<FieldEditorBloc>()
|
||||
.add(const FieldEditorEvent.toggleWrapCellContent()),
|
||||
style: ToggleStyle.big,
|
||||
padding: EdgeInsets.zero,
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
String title(FieldInfo fieldInfo) {
|
||||
switch (this) {
|
||||
case FieldAction.insertLeft:
|
||||
@ -250,6 +285,8 @@ enum FieldAction {
|
||||
return LocaleKeys.grid_field_clear.tr();
|
||||
case FieldAction.delete:
|
||||
return LocaleKeys.grid_field_delete.tr();
|
||||
case FieldAction.wrap:
|
||||
return LocaleKeys.grid_field_wrap.tr();
|
||||
}
|
||||
}
|
||||
|
||||
@ -308,6 +345,11 @@ enum FieldAction {
|
||||
).show(context);
|
||||
PopoverContainer.of(context).close();
|
||||
break;
|
||||
case FieldAction.wrap:
|
||||
context
|
||||
.read<FieldEditorBloc>()
|
||||
.add(const FieldEditorEvent.toggleWrapCellContent());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -117,7 +117,7 @@ class _GridCellEnterRegion extends StatelessWidget {
|
||||
onExit: (p) =>
|
||||
CellContainerNotifier.of(context, listen: false).isHover = false,
|
||||
child: Stack(
|
||||
alignment: AlignmentDirectional.center,
|
||||
alignment: Alignment.center,
|
||||
fit: StackFit.expand,
|
||||
children: children,
|
||||
),
|
||||
|
@ -653,6 +653,7 @@
|
||||
"insertRight": "Insert Right",
|
||||
"duplicate": "Duplicate",
|
||||
"delete": "Delete",
|
||||
"wrap": "Wrap",
|
||||
"clear": "Clear cells",
|
||||
"textFieldName": "Text",
|
||||
"checkboxFieldName": "Checkbox",
|
||||
@ -1474,4 +1475,4 @@
|
||||
"betaTooltip": "We currently only support searching for pages",
|
||||
"fromTrashHint": "From trash"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +1,13 @@
|
||||
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
|
||||
use flowy_error::ErrorCode;
|
||||
use lib_infra::validator_fn::required_not_empty_str;
|
||||
use std::ops::Deref;
|
||||
use validator::Validate;
|
||||
|
||||
use crate::entities::parser::NotEmptyStr;
|
||||
use crate::entities::RepeatedFieldIdPB;
|
||||
use crate::impl_into_field_visibility;
|
||||
use crate::services::field_settings::{FieldSettings, FieldSettingsChangesetParams};
|
||||
use crate::services::field_settings::FieldSettings;
|
||||
|
||||
/// Defines the field settings for a field in a view.
|
||||
#[derive(Debug, Default, Clone, ProtoBuf, Eq, PartialEq)]
|
||||
@ -18,6 +20,9 @@ pub struct FieldSettingsPB {
|
||||
|
||||
#[pb(index = 3)]
|
||||
pub width: i32,
|
||||
|
||||
#[pb(index = 4)]
|
||||
pub wrap_cell_content: bool,
|
||||
}
|
||||
|
||||
impl From<FieldSettings> for FieldSettingsPB {
|
||||
@ -26,6 +31,7 @@ impl From<FieldSettings> for FieldSettingsPB {
|
||||
field_id: value.field_id,
|
||||
visibility: value.visibility,
|
||||
width: value.width,
|
||||
wrap_cell_content: value.wrap_cell_content,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -93,11 +99,13 @@ impl std::convert::From<Vec<FieldSettingsPB>> for RepeatedFieldSettingsPB {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, ProtoBuf)]
|
||||
#[derive(Debug, Default, Clone, ProtoBuf, Validate)]
|
||||
pub struct FieldSettingsChangesetPB {
|
||||
#[validate(custom = "required_not_empty_str")]
|
||||
#[pb(index = 1)]
|
||||
pub view_id: String,
|
||||
|
||||
#[validate(custom = "required_not_empty_str")]
|
||||
#[pb(index = 2)]
|
||||
pub field_id: String,
|
||||
|
||||
@ -106,28 +114,7 @@ pub struct FieldSettingsChangesetPB {
|
||||
|
||||
#[pb(index = 4, one_of)]
|
||||
pub width: Option<i32>,
|
||||
}
|
||||
|
||||
impl From<FieldSettingsChangesetParams> for FieldSettingsChangesetPB {
|
||||
fn from(value: FieldSettingsChangesetParams) -> Self {
|
||||
Self {
|
||||
view_id: value.view_id,
|
||||
field_id: value.field_id,
|
||||
visibility: value.visibility,
|
||||
width: value.width,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<FieldSettingsChangesetPB> for FieldSettingsChangesetParams {
|
||||
type Error = ErrorCode;
|
||||
|
||||
fn try_from(value: FieldSettingsChangesetPB) -> Result<Self, Self::Error> {
|
||||
Ok(FieldSettingsChangesetParams {
|
||||
view_id: value.view_id,
|
||||
field_id: value.field_id,
|
||||
visibility: value.visibility,
|
||||
width: value.width,
|
||||
})
|
||||
}
|
||||
#[pb(index = 5, one_of)]
|
||||
pub wrap_cell_content: Option<bool>,
|
||||
}
|
||||
|
@ -14,7 +14,6 @@ use crate::services::field::{
|
||||
type_option_data_from_pb, ChecklistCellChangeset, DateCellChangeset, RelationCellChangeset,
|
||||
SelectOptionCellChangeset,
|
||||
};
|
||||
use crate::services::field_settings::FieldSettingsChangesetParams;
|
||||
use crate::services::group::GroupChangeset;
|
||||
use crate::services::share::csv::CSVFormat;
|
||||
|
||||
@ -944,7 +943,7 @@ pub(crate) async fn update_field_settings_handler(
|
||||
manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
) -> FlowyResult<()> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let params: FieldSettingsChangesetParams = data.into_inner().try_into()?;
|
||||
let params = data.try_into_inner()?;
|
||||
let database_editor = manager.get_database_with_view_id(¶ms.view_id).await?;
|
||||
database_editor
|
||||
.update_field_settings_with_changeset(params)
|
||||
|
@ -12,9 +12,7 @@ use crate::services::field::{
|
||||
type_option_data_from_pb, ChecklistCellChangeset, RelationTypeOption, SelectOptionCellChangeset,
|
||||
StrCellData, TimestampCellData, TypeOptionCellDataHandler, TypeOptionCellExt,
|
||||
};
|
||||
use crate::services::field_settings::{
|
||||
default_field_settings_by_layout_map, FieldSettings, FieldSettingsChangesetParams,
|
||||
};
|
||||
use crate::services::field_settings::{default_field_settings_by_layout_map, FieldSettings};
|
||||
use crate::services::filter::{Filter, FilterChangeset};
|
||||
use crate::services::group::{default_group_setting, GroupChangeset, GroupSetting, RowChangeset};
|
||||
use crate::services::share::csv::{CSVExport, CSVFormat};
|
||||
@ -1296,17 +1294,10 @@ impl DatabaseEditor {
|
||||
|
||||
pub async fn update_field_settings_with_changeset(
|
||||
&self,
|
||||
params: FieldSettingsChangesetParams,
|
||||
params: FieldSettingsChangesetPB,
|
||||
) -> FlowyResult<()> {
|
||||
let view = self.database_views.get_view_editor(¶ms.view_id).await?;
|
||||
view
|
||||
.v_update_field_settings(
|
||||
¶ms.view_id,
|
||||
¶ms.field_id,
|
||||
params.visibility,
|
||||
params.width,
|
||||
)
|
||||
.await?;
|
||||
view.v_update_field_settings(params).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -1735,45 +1726,43 @@ impl DatabaseViewOperation for DatabaseViewOperationImpl {
|
||||
field_settings
|
||||
}
|
||||
|
||||
fn update_field_settings(
|
||||
&self,
|
||||
view_id: &str,
|
||||
field_id: &str,
|
||||
visibility: Option<FieldVisibility>,
|
||||
width: Option<i32>,
|
||||
) {
|
||||
let field_settings_map = self.get_field_settings(view_id, &[field_id.to_string()]);
|
||||
fn update_field_settings(&self, params: FieldSettingsChangesetPB) {
|
||||
let field_settings_map = self.get_field_settings(¶ms.view_id, &[params.field_id.clone()]);
|
||||
|
||||
let new_field_settings = if let Some(field_settings) = field_settings_map.get(field_id) {
|
||||
FieldSettings {
|
||||
field_id: field_settings.field_id.clone(),
|
||||
visibility: visibility.unwrap_or(field_settings.visibility.clone()),
|
||||
width: width.unwrap_or(field_settings.width),
|
||||
}
|
||||
} else {
|
||||
let layout_type = self.get_layout_for_view(view_id);
|
||||
let default_field_settings = default_field_settings_by_layout_map()
|
||||
.get(&layout_type)
|
||||
.unwrap()
|
||||
.to_owned();
|
||||
let field_settings =
|
||||
FieldSettings::from_any_map(field_id, layout_type, &default_field_settings);
|
||||
FieldSettings {
|
||||
field_id: field_settings.field_id.clone(),
|
||||
visibility: visibility.unwrap_or(field_settings.visibility),
|
||||
width: width.unwrap_or(field_settings.width),
|
||||
}
|
||||
let field_settings = field_settings_map
|
||||
.get(¶ms.field_id)
|
||||
.cloned()
|
||||
.unwrap_or_else(|| {
|
||||
let layout_type = self.get_layout_for_view(¶ms.view_id);
|
||||
let default_field_settings = default_field_settings_by_layout_map();
|
||||
let default_field_settings = default_field_settings.get(&layout_type).unwrap();
|
||||
|
||||
FieldSettings::from_any_map(¶ms.field_id, layout_type, default_field_settings)
|
||||
});
|
||||
|
||||
let new_field_settings = FieldSettings {
|
||||
visibility: params
|
||||
.visibility
|
||||
.unwrap_or_else(|| field_settings.visibility.clone()),
|
||||
width: params.width.unwrap_or(field_settings.width),
|
||||
wrap_cell_content: params
|
||||
.wrap_cell_content
|
||||
.unwrap_or(field_settings.wrap_cell_content),
|
||||
..field_settings
|
||||
};
|
||||
|
||||
self.database.lock().update_field_settings(
|
||||
view_id,
|
||||
Some(vec![field_id.to_string()]),
|
||||
¶ms.view_id,
|
||||
Some(vec![params.field_id]),
|
||||
new_field_settings.clone(),
|
||||
);
|
||||
|
||||
send_notification(view_id, DatabaseNotification::DidUpdateFieldSettings)
|
||||
.payload(FieldSettingsPB::from(new_field_settings))
|
||||
.send()
|
||||
send_notification(
|
||||
¶ms.view_id,
|
||||
DatabaseNotification::DidUpdateFieldSettings,
|
||||
)
|
||||
.payload(FieldSettingsPB::from(new_field_settings))
|
||||
.send()
|
||||
}
|
||||
|
||||
fn update_calculation(&self, view_id: &str, calculation: Calculation) {
|
||||
|
@ -15,10 +15,10 @@ use lib_dispatch::prelude::af_spawn;
|
||||
|
||||
use crate::entities::{
|
||||
CalendarEventPB, CreateRowParams, CreateRowPayloadPB, DatabaseLayoutMetaPB,
|
||||
DatabaseLayoutSettingPB, DeleteSortPayloadPB, FieldType, FieldVisibility, GroupChangesPB,
|
||||
GroupPB, LayoutSettingChangeset, LayoutSettingParams, RemoveCalculationChangesetPB,
|
||||
ReorderSortPayloadPB, RowMetaPB, RowsChangePB, SortChangesetNotificationPB, SortPB,
|
||||
UpdateCalculationChangesetPB, UpdateSortPayloadPB,
|
||||
DatabaseLayoutSettingPB, DeleteSortPayloadPB, FieldSettingsChangesetPB, FieldType,
|
||||
GroupChangesPB, GroupPB, LayoutSettingChangeset, LayoutSettingParams,
|
||||
RemoveCalculationChangesetPB, ReorderSortPayloadPB, RowMetaPB, RowsChangePB,
|
||||
SortChangesetNotificationPB, SortPB, UpdateCalculationChangesetPB, UpdateSortPayloadPB,
|
||||
};
|
||||
use crate::notification::{send_notification, DatabaseNotification};
|
||||
use crate::services::calculations::{Calculation, CalculationChangeset, CalculationsController};
|
||||
@ -1034,20 +1034,8 @@ impl DatabaseViewEditor {
|
||||
self.delegate.get_field_settings(&self.view_id, field_ids)
|
||||
}
|
||||
|
||||
// pub async fn v_get_all_field_settings(&self) -> HashMap<String, FieldSettings> {
|
||||
// self.delegate.get_all_field_settings(&self.view_id)
|
||||
// }
|
||||
|
||||
pub async fn v_update_field_settings(
|
||||
&self,
|
||||
view_id: &str,
|
||||
field_id: &str,
|
||||
visibility: Option<FieldVisibility>,
|
||||
width: Option<i32>,
|
||||
) -> FlowyResult<()> {
|
||||
self
|
||||
.delegate
|
||||
.update_field_settings(view_id, field_id, visibility, width);
|
||||
pub async fn v_update_field_settings(&self, params: FieldSettingsChangesetPB) -> FlowyResult<()> {
|
||||
self.delegate.update_field_settings(params);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ use flowy_error::FlowyError;
|
||||
use lib_infra::future::{Fut, FutureResult};
|
||||
use lib_infra::priority_task::TaskDispatcher;
|
||||
|
||||
use crate::entities::{FieldType, FieldVisibility};
|
||||
use crate::entities::{FieldSettingsChangesetPB, FieldType};
|
||||
use crate::services::calculations::Calculation;
|
||||
use crate::services::field::TypeOptionCellDataHandler;
|
||||
use crate::services::field_settings::FieldSettings;
|
||||
@ -126,11 +126,5 @@ pub trait DatabaseViewOperation: Send + Sync + 'static {
|
||||
field_ids: &[String],
|
||||
) -> HashMap<String, FieldSettings>;
|
||||
|
||||
fn update_field_settings(
|
||||
&self,
|
||||
view_id: &str,
|
||||
field_id: &str,
|
||||
visibility: Option<FieldVisibility>,
|
||||
width: Option<i32>,
|
||||
);
|
||||
fn update_field_settings(&self, params: FieldSettingsChangesetPB);
|
||||
}
|
||||
|
@ -10,12 +10,13 @@ pub struct FieldSettings {
|
||||
pub field_id: String,
|
||||
pub visibility: FieldVisibility,
|
||||
pub width: i32,
|
||||
pub wrap_cell_content: bool,
|
||||
}
|
||||
|
||||
pub const VISIBILITY: &str = "visibility";
|
||||
pub const WIDTH: &str = "width";
|
||||
|
||||
pub const DEFAULT_WIDTH: i32 = 150;
|
||||
pub const WRAP_CELL_CONTENT: &str = "wrap";
|
||||
|
||||
impl FieldSettings {
|
||||
pub fn from_any_map(
|
||||
@ -31,11 +32,15 @@ impl FieldSettings {
|
||||
.get_i64_value(WIDTH)
|
||||
.map(|value| value as i32)
|
||||
.unwrap_or(DEFAULT_WIDTH);
|
||||
let wrap_cell_content = field_settings
|
||||
.get_bool_value(WRAP_CELL_CONTENT)
|
||||
.unwrap_or(false);
|
||||
|
||||
Self {
|
||||
field_id: field_id.to_string(),
|
||||
visibility,
|
||||
width,
|
||||
wrap_cell_content,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -45,15 +50,7 @@ impl From<FieldSettings> for FieldSettingsMap {
|
||||
FieldSettingsMapBuilder::new()
|
||||
.insert_i64_value(VISIBILITY, field_settings.visibility.into())
|
||||
.insert_i64_value(WIDTH, field_settings.width as i64)
|
||||
.insert_bool_value(WRAP_CELL_CONTENT, field_settings.wrap_cell_content)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
||||
/// Contains the changeset to a field's settings.
|
||||
/// A `Some` value constitutes a change in that particular setting
|
||||
pub struct FieldSettingsChangesetParams {
|
||||
pub view_id: String,
|
||||
pub field_id: String,
|
||||
pub visibility: Option<FieldVisibility>,
|
||||
pub width: Option<i32>,
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ use collab_database::views::{
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
use crate::entities::FieldVisibility;
|
||||
use crate::services::field_settings::{FieldSettings, VISIBILITY};
|
||||
use crate::services::field_settings::{FieldSettings, DEFAULT_WIDTH, VISIBILITY};
|
||||
|
||||
/// Helper struct to create a new field setting
|
||||
pub struct FieldSettingsBuilder {
|
||||
@ -19,8 +19,10 @@ impl FieldSettingsBuilder {
|
||||
let field_settings = FieldSettings {
|
||||
field_id: field_id.to_string(),
|
||||
visibility: FieldVisibility::AlwaysShown,
|
||||
width: 150,
|
||||
width: DEFAULT_WIDTH,
|
||||
wrap_cell_content: false,
|
||||
};
|
||||
|
||||
Self {
|
||||
inner: field_settings,
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
use flowy_database2::entities::FieldVisibility;
|
||||
use flowy_database2::services::field_settings::FieldSettingsChangesetParams;
|
||||
use flowy_database2::entities::{FieldSettingsChangesetPB, FieldVisibility};
|
||||
|
||||
use crate::database::database_editor::DatabaseEditorTest;
|
||||
|
||||
@ -60,11 +59,12 @@ impl FieldSettingsTest {
|
||||
visibility: Option<FieldVisibility>,
|
||||
width: Option<i32>,
|
||||
) {
|
||||
let params = FieldSettingsChangesetParams {
|
||||
let params = FieldSettingsChangesetPB {
|
||||
view_id: self.view_id.clone(),
|
||||
field_id,
|
||||
visibility,
|
||||
width,
|
||||
wrap_cell_content: None,
|
||||
};
|
||||
let _ = self
|
||||
.editor
|
||||
|
Loading…
x
Reference in New Issue
Block a user