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