mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2025-11-15 09:57:40 +00:00
chore: config option editor ui
This commit is contained in:
parent
271a8485b6
commit
5358203a46
@ -186,7 +186,8 @@
|
|||||||
"blueColor": "Blue",
|
"blueColor": "Blue",
|
||||||
"deleteTag": "Delete tag",
|
"deleteTag": "Delete tag",
|
||||||
"colorPannelTitle": "Colors",
|
"colorPannelTitle": "Colors",
|
||||||
"pannelTitle": "Select an option"
|
"pannelTitle": "Select an option or create one",
|
||||||
|
"searchOption": "Search for an option"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -151,7 +151,7 @@ void _resolveGridDeps(GetIt getIt) {
|
|||||||
(view, _) => GridBloc(view: view, service: GridService()),
|
(view, _) => GridBloc(view: view, service: GridService()),
|
||||||
);
|
);
|
||||||
|
|
||||||
getIt.registerFactoryParam<RowBloc, GridRowData, void>(
|
getIt.registerFactoryParam<RowBloc, RowData, void>(
|
||||||
(data, _) => RowBloc(
|
(data, _) => RowBloc(
|
||||||
rowData: data,
|
rowData: data,
|
||||||
rowlistener: RowListener(rowId: data.rowId),
|
rowlistener: RowListener(rowId: data.rowId),
|
||||||
@ -179,35 +179,35 @@ void _resolveGridDeps(GetIt getIt) {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
getIt.registerFactoryParam<TextCellBloc, FutureCellData, void>(
|
getIt.registerFactoryParam<TextCellBloc, CellData, void>(
|
||||||
(cellData, _) => TextCellBloc(
|
(cellData, _) => TextCellBloc(
|
||||||
service: CellService(),
|
service: CellService(),
|
||||||
cellData: cellData,
|
cellData: cellData,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
getIt.registerFactoryParam<SelectionCellBloc, FutureCellData, void>(
|
getIt.registerFactoryParam<SelectionCellBloc, CellData, void>(
|
||||||
(cellData, _) => SelectionCellBloc(
|
(cellData, _) => SelectionCellBloc(
|
||||||
service: CellService(),
|
service: CellService(),
|
||||||
cellData: cellData,
|
cellData: cellData,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
getIt.registerFactoryParam<NumberCellBloc, FutureCellData, void>(
|
getIt.registerFactoryParam<NumberCellBloc, CellData, void>(
|
||||||
(cellData, _) => NumberCellBloc(
|
(cellData, _) => NumberCellBloc(
|
||||||
service: CellService(),
|
service: CellService(),
|
||||||
cellData: cellData,
|
cellData: cellData,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
getIt.registerFactoryParam<DateCellBloc, FutureCellData, void>(
|
getIt.registerFactoryParam<DateCellBloc, CellData, void>(
|
||||||
(cellData, _) => DateCellBloc(
|
(cellData, _) => DateCellBloc(
|
||||||
service: CellService(),
|
service: CellService(),
|
||||||
cellData: cellData,
|
cellData: cellData,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
getIt.registerFactoryParam<CheckboxCellBloc, FutureCellData, void>(
|
getIt.registerFactoryParam<CheckboxCellBloc, CellData, void>(
|
||||||
(cellData, _) => CheckboxCellBloc(
|
(cellData, _) => CheckboxCellBloc(
|
||||||
service: CellService(),
|
service: CellService(),
|
||||||
cellData: cellData,
|
cellData: cellData,
|
||||||
|
|||||||
@ -9,11 +9,11 @@ part 'checkbox_cell_bloc.freezed.dart';
|
|||||||
|
|
||||||
class CheckboxCellBloc extends Bloc<CheckboxCellEvent, CheckboxCellState> {
|
class CheckboxCellBloc extends Bloc<CheckboxCellEvent, CheckboxCellState> {
|
||||||
final CellService service;
|
final CellService service;
|
||||||
// final FutureCellData cellData;
|
// final CellData cellData;
|
||||||
|
|
||||||
CheckboxCellBloc({
|
CheckboxCellBloc({
|
||||||
required this.service,
|
required this.service,
|
||||||
required FutureCellData cellData,
|
required CellData cellData,
|
||||||
}) : super(CheckboxCellState.initial()) {
|
}) : super(CheckboxCellState.initial()) {
|
||||||
on<CheckboxCellEvent>(
|
on<CheckboxCellEvent>(
|
||||||
(event, emit) async {
|
(event, emit) async {
|
||||||
|
|||||||
@ -9,7 +9,7 @@ part 'date_cell_bloc.freezed.dart';
|
|||||||
|
|
||||||
class DateCellBloc extends Bloc<DateCellEvent, DateCellState> {
|
class DateCellBloc extends Bloc<DateCellEvent, DateCellState> {
|
||||||
final CellService service;
|
final CellService service;
|
||||||
final FutureCellData cellData;
|
final CellData cellData;
|
||||||
|
|
||||||
DateCellBloc({
|
DateCellBloc({
|
||||||
required this.service,
|
required this.service,
|
||||||
|
|||||||
@ -12,7 +12,7 @@ class NumberCellBloc extends Bloc<NumberCellEvent, NumberCellState> {
|
|||||||
|
|
||||||
NumberCellBloc({
|
NumberCellBloc({
|
||||||
required this.service,
|
required this.service,
|
||||||
required FutureCellData cellData,
|
required CellData cellData,
|
||||||
}) : super(NumberCellState.initial()) {
|
}) : super(NumberCellState.initial()) {
|
||||||
on<NumberCellEvent>(
|
on<NumberCellEvent>(
|
||||||
(event, emit) async {
|
(event, emit) async {
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
|
import 'package:app_flowy/workspace/application/grid/field/field_service.dart';
|
||||||
import 'package:app_flowy/workspace/application/grid/row/row_service.dart';
|
import 'package:app_flowy/workspace/application/grid/row/row_service.dart';
|
||||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
import 'package:flowy_sdk/log.dart';
|
||||||
|
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/meta.pb.dart';
|
||||||
import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart';
|
import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.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';
|
||||||
@ -13,12 +15,17 @@ class SelectionCellBloc extends Bloc<SelectionCellEvent, SelectionCellState> {
|
|||||||
|
|
||||||
SelectionCellBloc({
|
SelectionCellBloc({
|
||||||
required this.service,
|
required this.service,
|
||||||
required FutureCellData cellData,
|
required CellData cellData,
|
||||||
}) : super(SelectionCellState.initial()) {
|
}) : super(SelectionCellState.initial(cellData)) {
|
||||||
on<SelectionCellEvent>(
|
on<SelectionCellEvent>(
|
||||||
(event, emit) async {
|
(event, emit) async {
|
||||||
await event.map(
|
await event.map(
|
||||||
initial: (_InitialCell value) async {},
|
initial: (_InitialCell value) async {
|
||||||
|
_loadOptions();
|
||||||
|
},
|
||||||
|
didReceiveOptions: (_DidReceiveOptions value) {
|
||||||
|
emit(state.copyWith(options: value.options, selectedOptions: value.selectedOptions));
|
||||||
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -28,19 +35,57 @@ class SelectionCellBloc extends Bloc<SelectionCellEvent, SelectionCellState> {
|
|||||||
Future<void> close() async {
|
Future<void> close() async {
|
||||||
return super.close();
|
return super.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _loadOptions() async {
|
||||||
|
final result = await FieldContextLoaderAdaptor(
|
||||||
|
gridId: state.cellData.gridId,
|
||||||
|
field: state.cellData.field,
|
||||||
|
).load();
|
||||||
|
|
||||||
|
result.fold(
|
||||||
|
(context) {
|
||||||
|
List<SelectOption> options = [];
|
||||||
|
switch (state.cellData.field.fieldType) {
|
||||||
|
case FieldType.MultiSelect:
|
||||||
|
options.addAll(MultiSelectTypeOption.fromBuffer(context.typeOptionData).options);
|
||||||
|
break;
|
||||||
|
case FieldType.SingleSelect:
|
||||||
|
options.addAll(SingleSelectTypeOption.fromBuffer(context.typeOptionData).options);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Log.error("Invalid field type, expect single select or multiple select");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
final ids = state.cellData.cell?.content.split(',');
|
||||||
|
final selectedOptions = ids?.map((id) => options.firstWhere((option) => option.id == id)).toList() ?? [];
|
||||||
|
add(SelectionCellEvent.didReceiveOptions(options, selectedOptions));
|
||||||
|
},
|
||||||
|
(err) => Log.error(err),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@freezed
|
@freezed
|
||||||
class SelectionCellEvent with _$SelectionCellEvent {
|
class SelectionCellEvent with _$SelectionCellEvent {
|
||||||
const factory SelectionCellEvent.initial() = _InitialCell;
|
const factory SelectionCellEvent.initial() = _InitialCell;
|
||||||
|
const factory SelectionCellEvent.didReceiveOptions(
|
||||||
|
List<SelectOption> options,
|
||||||
|
List<SelectOption> selectedOptions,
|
||||||
|
) = _DidReceiveOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
@freezed
|
@freezed
|
||||||
class SelectionCellState with _$SelectionCellState {
|
class SelectionCellState with _$SelectionCellState {
|
||||||
const factory SelectionCellState() = _SelectionCellState;
|
const factory SelectionCellState({
|
||||||
// required String girdId,
|
required CellData cellData,
|
||||||
// required Field field,
|
required List<SelectOption> options,
|
||||||
// required List<SelectOption> options,
|
required List<SelectOption> selectedOptions,
|
||||||
|
}) = _SelectionCellState;
|
||||||
|
|
||||||
factory SelectionCellState.initial() => const SelectionCellState();
|
factory SelectionCellState.initial(CellData cellData) => SelectionCellState(
|
||||||
|
cellData: cellData,
|
||||||
|
options: [],
|
||||||
|
selectedOptions: [],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,16 +11,18 @@ import 'cell_service.dart';
|
|||||||
|
|
||||||
part 'selection_editor_bloc.freezed.dart';
|
part 'selection_editor_bloc.freezed.dart';
|
||||||
|
|
||||||
class SelectionEditorBloc extends Bloc<SelectionEditorEvent, SelectionEditorState> {
|
class SelectOptionEditorBloc extends Bloc<SelectOptionEditorEvent, SelectOptionEditorState> {
|
||||||
final CellService service = CellService();
|
final CellService service = CellService();
|
||||||
final FieldListener _listener;
|
final FieldListener _listener;
|
||||||
|
|
||||||
SelectionEditorBloc({
|
SelectOptionEditorBloc({
|
||||||
required String gridId,
|
required String gridId,
|
||||||
required Field field,
|
required Field field,
|
||||||
|
required List<SelectOption> options,
|
||||||
|
required List<SelectOption> selectedOptions,
|
||||||
}) : _listener = FieldListener(fieldId: field.id),
|
}) : _listener = FieldListener(fieldId: field.id),
|
||||||
super(SelectionEditorState.initial(gridId, field)) {
|
super(SelectOptionEditorState.initial(gridId, field, options, selectedOptions)) {
|
||||||
on<SelectionEditorEvent>(
|
on<SelectOptionEditorEvent>(
|
||||||
(event, emit) async {
|
(event, emit) async {
|
||||||
await event.map(
|
await event.map(
|
||||||
initial: (_Initial value) async {
|
initial: (_Initial value) async {
|
||||||
@ -34,6 +36,7 @@ class SelectionEditorBloc extends Bloc<SelectionEditorEvent, SelectionEditorStat
|
|||||||
didReceiveOptions: (_DidReceiveOptions value) {
|
didReceiveOptions: (_DidReceiveOptions value) {
|
||||||
emit(state.copyWith(options: value.options));
|
emit(state.copyWith(options: value.options));
|
||||||
},
|
},
|
||||||
|
newOption: (_newOption value) {},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -48,7 +51,7 @@ class SelectionEditorBloc extends Bloc<SelectionEditorEvent, SelectionEditorStat
|
|||||||
void _startListening() {
|
void _startListening() {
|
||||||
_listener.updateFieldNotifier.addPublishListener((result) {
|
_listener.updateFieldNotifier.addPublishListener((result) {
|
||||||
result.fold(
|
result.fold(
|
||||||
(field) => add(SelectionEditorEvent.didReceiveFieldUpdate(field)),
|
(field) => add(SelectOptionEditorEvent.didReceiveFieldUpdate(field)),
|
||||||
(err) => Log.error(err),
|
(err) => Log.error(err),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -70,7 +73,7 @@ class SelectionEditorBloc extends Bloc<SelectionEditorEvent, SelectionEditorStat
|
|||||||
Log.error("Invalid field type, expect single select or multiple select");
|
Log.error("Invalid field type, expect single select or multiple select");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
add(SelectionEditorEvent.didReceiveOptions(options));
|
add(SelectOptionEditorEvent.didReceiveOptions(options));
|
||||||
},
|
},
|
||||||
(err) => Log.error(err),
|
(err) => Log.error(err),
|
||||||
);
|
);
|
||||||
@ -78,25 +81,33 @@ class SelectionEditorBloc extends Bloc<SelectionEditorEvent, SelectionEditorStat
|
|||||||
}
|
}
|
||||||
|
|
||||||
@freezed
|
@freezed
|
||||||
class SelectionEditorEvent with _$SelectionEditorEvent {
|
class SelectOptionEditorEvent with _$SelectOptionEditorEvent {
|
||||||
const factory SelectionEditorEvent.initial() = _Initial;
|
const factory SelectOptionEditorEvent.initial() = _Initial;
|
||||||
const factory SelectionEditorEvent.didReceiveFieldUpdate(Field field) = _DidReceiveFieldUpdate;
|
const factory SelectOptionEditorEvent.didReceiveFieldUpdate(Field field) = _DidReceiveFieldUpdate;
|
||||||
const factory SelectionEditorEvent.didReceiveOptions(List<SelectOption> options) = _DidReceiveOptions;
|
const factory SelectOptionEditorEvent.didReceiveOptions(List<SelectOption> options) = _DidReceiveOptions;
|
||||||
|
const factory SelectOptionEditorEvent.newOption(String optionName) = _newOption;
|
||||||
}
|
}
|
||||||
|
|
||||||
@freezed
|
@freezed
|
||||||
class SelectionEditorState with _$SelectionEditorState {
|
class SelectOptionEditorState with _$SelectOptionEditorState {
|
||||||
const factory SelectionEditorState({
|
const factory SelectOptionEditorState({
|
||||||
required String gridId,
|
required String gridId,
|
||||||
required Field field,
|
required Field field,
|
||||||
required List<SelectOption> options,
|
required List<SelectOption> options,
|
||||||
}) = _SelectionEditorState;
|
required List<SelectOption> selectedOptions,
|
||||||
|
}) = _SelectOptionEditorState;
|
||||||
|
|
||||||
factory SelectionEditorState.initial(String gridId, Field field) {
|
factory SelectOptionEditorState.initial(
|
||||||
return SelectionEditorState(
|
String gridId,
|
||||||
|
Field field,
|
||||||
|
List<SelectOption> options,
|
||||||
|
List<SelectOption> selectedOptions,
|
||||||
|
) {
|
||||||
|
return SelectOptionEditorState(
|
||||||
gridId: gridId,
|
gridId: gridId,
|
||||||
field: field,
|
field: field,
|
||||||
options: [],
|
options: options,
|
||||||
|
selectedOptions: selectedOptions,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,7 +11,7 @@ class TextCellBloc extends Bloc<TextCellEvent, TextCellState> {
|
|||||||
|
|
||||||
TextCellBloc({
|
TextCellBloc({
|
||||||
required this.service,
|
required this.service,
|
||||||
required FutureCellData cellData,
|
required CellData cellData,
|
||||||
}) : super(TextCellState.initial(cellData)) {
|
}) : super(TextCellState.initial(cellData)) {
|
||||||
on<TextCellEvent>(
|
on<TextCellEvent>(
|
||||||
(event, emit) async {
|
(event, emit) async {
|
||||||
@ -53,7 +53,7 @@ class TextCellBloc extends Bloc<TextCellEvent, TextCellState> {
|
|||||||
@freezed
|
@freezed
|
||||||
class TextCellEvent with _$TextCellEvent {
|
class TextCellEvent with _$TextCellEvent {
|
||||||
const factory TextCellEvent.initial() = _InitialCell;
|
const factory TextCellEvent.initial() = _InitialCell;
|
||||||
const factory TextCellEvent.didReceiveCellData(GridCellData cellData) = _DidReceiveCellData;
|
const factory TextCellEvent.didReceiveCellData(CellData cellData) = _DidReceiveCellData;
|
||||||
const factory TextCellEvent.updateText(String text) = _UpdateText;
|
const factory TextCellEvent.updateText(String text) = _UpdateText;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,10 +61,10 @@ class TextCellEvent with _$TextCellEvent {
|
|||||||
class TextCellState with _$TextCellState {
|
class TextCellState with _$TextCellState {
|
||||||
const factory TextCellState({
|
const factory TextCellState({
|
||||||
required String content,
|
required String content,
|
||||||
required FutureCellData cellData,
|
required CellData cellData,
|
||||||
}) = _TextCellState;
|
}) = _TextCellState;
|
||||||
|
|
||||||
factory TextCellState.initial(FutureCellData cellData) => TextCellState(
|
factory TextCellState.initial(CellData cellData) => TextCellState(
|
||||||
content: cellData.cell?.content ?? "",
|
content: cellData.cell?.content ?? "",
|
||||||
cellData: cellData,
|
cellData: cellData,
|
||||||
);
|
);
|
||||||
|
|||||||
@ -169,14 +169,14 @@ class GridBlockRow {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
class GridRowData extends Equatable {
|
class RowData extends Equatable {
|
||||||
final String gridId;
|
final String gridId;
|
||||||
final String rowId;
|
final String rowId;
|
||||||
final String blockId;
|
final String blockId;
|
||||||
final List<Field> fields;
|
final List<Field> fields;
|
||||||
final double height;
|
final double height;
|
||||||
|
|
||||||
const GridRowData({
|
const RowData({
|
||||||
required this.gridId,
|
required this.gridId,
|
||||||
required this.rowId,
|
required this.rowId,
|
||||||
required this.blockId,
|
required this.blockId,
|
||||||
@ -184,8 +184,8 @@ class GridRowData extends Equatable {
|
|||||||
required this.height,
|
required this.height,
|
||||||
});
|
});
|
||||||
|
|
||||||
factory GridRowData.fromBlockRow(GridBlockRow row, List<Field> fields) {
|
factory RowData.fromBlockRow(GridBlockRow row, List<Field> fields) {
|
||||||
return GridRowData(
|
return RowData(
|
||||||
gridId: row.gridId,
|
gridId: row.gridId,
|
||||||
rowId: row.rowId,
|
rowId: row.rowId,
|
||||||
blockId: row.blockId,
|
blockId: row.blockId,
|
||||||
|
|||||||
@ -13,14 +13,14 @@ import 'package:dartz/dartz.dart';
|
|||||||
|
|
||||||
part 'row_bloc.freezed.dart';
|
part 'row_bloc.freezed.dart';
|
||||||
|
|
||||||
typedef CellDataMap = LinkedHashMap<String, GridCellData>;
|
typedef CellDataMap = LinkedHashMap<String, CellData>;
|
||||||
|
|
||||||
class RowBloc extends Bloc<RowEvent, RowState> {
|
class RowBloc extends Bloc<RowEvent, RowState> {
|
||||||
final RowService rowService;
|
final RowService rowService;
|
||||||
final RowListener rowlistener;
|
final RowListener rowlistener;
|
||||||
final GridFieldsListener fieldListener;
|
final GridFieldsListener fieldListener;
|
||||||
|
|
||||||
RowBloc({required GridRowData rowData, required this.rowlistener})
|
RowBloc({required RowData rowData, required this.rowlistener})
|
||||||
: rowService = RowService(
|
: rowService = RowService(
|
||||||
gridId: rowData.gridId,
|
gridId: rowData.gridId,
|
||||||
blockId: rowData.blockId,
|
blockId: rowData.blockId,
|
||||||
@ -112,7 +112,7 @@ class RowBloc extends Bloc<RowEvent, RowState> {
|
|||||||
var map = CellDataMap.new();
|
var map = CellDataMap.new();
|
||||||
for (final field in state.fields) {
|
for (final field in state.fields) {
|
||||||
if (field.visibility) {
|
if (field.visibility) {
|
||||||
map[field.id] = GridCellData(
|
map[field.id] = CellData(
|
||||||
rowId: row.id,
|
rowId: row.id,
|
||||||
gridId: rowService.gridId,
|
gridId: rowService.gridId,
|
||||||
blockId: rowService.blockId,
|
blockId: rowService.blockId,
|
||||||
@ -143,7 +143,7 @@ class RowState with _$RowState {
|
|||||||
required Option<CellDataMap> cellDataMap,
|
required Option<CellDataMap> cellDataMap,
|
||||||
}) = _RowState;
|
}) = _RowState;
|
||||||
|
|
||||||
factory RowState.initial(GridRowData data) => RowState(
|
factory RowState.initial(RowData data) => RowState(
|
||||||
rowId: data.rowId,
|
rowId: data.rowId,
|
||||||
rowHeight: data.height,
|
rowHeight: data.height,
|
||||||
fields: data.fields,
|
fields: data.fields,
|
||||||
|
|||||||
@ -29,16 +29,14 @@ class RowService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef FutureCellData = GridCellData;
|
class CellData extends Equatable {
|
||||||
|
|
||||||
class GridCellData extends Equatable {
|
|
||||||
final String gridId;
|
final String gridId;
|
||||||
final String rowId;
|
final String rowId;
|
||||||
final String blockId;
|
final String blockId;
|
||||||
final Field field;
|
final Field field;
|
||||||
final Cell? cell;
|
final Cell? cell;
|
||||||
|
|
||||||
const GridCellData({
|
const CellData({
|
||||||
required this.rowId,
|
required this.rowId,
|
||||||
required this.gridId,
|
required this.gridId,
|
||||||
required this.blockId,
|
required this.blockId,
|
||||||
|
|||||||
@ -157,7 +157,7 @@ class _FlowyGridState extends State<FlowyGrid> {
|
|||||||
(context, index) {
|
(context, index) {
|
||||||
final blockRow = context.read<GridBloc>().state.rows[index];
|
final blockRow = context.read<GridBloc>().state.rows[index];
|
||||||
final fields = context.read<GridBloc>().state.fields;
|
final fields = context.read<GridBloc>().state.fields;
|
||||||
final rowData = GridRowData.fromBlockRow(blockRow, fields);
|
final rowData = RowData.fromBlockRow(blockRow, fields);
|
||||||
return GridRowWidget(data: rowData, key: ValueKey(rowData.rowId));
|
return GridRowWidget(data: rowData, key: ValueKey(rowData.rowId));
|
||||||
},
|
},
|
||||||
childCount: context.read<GridBloc>().state.rows.length,
|
childCount: context.read<GridBloc>().state.rows.length,
|
||||||
|
|||||||
@ -9,8 +9,9 @@ class GridSize {
|
|||||||
static double get leadingHeaderPadding => 30 * scale;
|
static double get leadingHeaderPadding => 30 * scale;
|
||||||
static double get trailHeaderPadding => 140 * scale;
|
static double get trailHeaderPadding => 140 * scale;
|
||||||
static double get headerContainerPadding => 0 * scale;
|
static double get headerContainerPadding => 0 * scale;
|
||||||
static double get cellContentPadding => 10 * scale;
|
static double get cellHPadding => 10 * scale;
|
||||||
static double get typeOptionItemHeight => 30 * scale;
|
static double get cellVPadding => 8 * scale;
|
||||||
|
static double get typeOptionItemHeight => 32 * scale;
|
||||||
static double get typeOptionSeparatorHeight => 6 * scale;
|
static double get typeOptionSeparatorHeight => 6 * scale;
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -19,13 +20,13 @@ class GridSize {
|
|||||||
vertical: GridSize.headerContainerPadding,
|
vertical: GridSize.headerContainerPadding,
|
||||||
);
|
);
|
||||||
static EdgeInsets get cellContentInsets => EdgeInsets.symmetric(
|
static EdgeInsets get cellContentInsets => EdgeInsets.symmetric(
|
||||||
horizontal: GridSize.cellContentPadding,
|
horizontal: GridSize.cellHPadding,
|
||||||
vertical: GridSize.cellContentPadding,
|
vertical: GridSize.cellVPadding,
|
||||||
);
|
);
|
||||||
|
|
||||||
static EdgeInsets get fieldContentInsets => EdgeInsets.symmetric(
|
static EdgeInsets get fieldContentInsets => EdgeInsets.symmetric(
|
||||||
horizontal: GridSize.cellContentPadding,
|
horizontal: GridSize.cellHPadding,
|
||||||
vertical: GridSize.cellContentPadding,
|
vertical: GridSize.cellVPadding,
|
||||||
);
|
);
|
||||||
|
|
||||||
static EdgeInsets get typeOptionContentInsets => const EdgeInsets.symmetric(
|
static EdgeInsets get typeOptionContentInsets => const EdgeInsets.symmetric(
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import 'number_cell.dart';
|
|||||||
import 'selection_cell/selection_cell.dart';
|
import 'selection_cell/selection_cell.dart';
|
||||||
import 'text_cell.dart';
|
import 'text_cell.dart';
|
||||||
|
|
||||||
Widget buildGridCell(FutureCellData cellData) {
|
Widget buildGridCell(CellData cellData) {
|
||||||
final key = ValueKey(cellData.field.id + cellData.rowId);
|
final key = ValueKey(cellData.field.id + cellData.rowId);
|
||||||
switch (cellData.field.fieldType) {
|
switch (cellData.field.fieldType) {
|
||||||
case FieldType.Checkbox:
|
case FieldType.Checkbox:
|
||||||
|
|||||||
@ -38,7 +38,7 @@ class CellContainer extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
decoration: _makeBoxDecoration(context, state),
|
decoration: _makeBoxDecoration(context, state),
|
||||||
padding: GridSize.cellContentInsets,
|
padding: GridSize.cellContentInsets,
|
||||||
child: Center(child: IntrinsicHeight(child: child)),
|
child: Center(child: child),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import 'package:flutter/widgets.dart';
|
|||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
|
||||||
class CheckboxCell extends StatefulWidget {
|
class CheckboxCell extends StatefulWidget {
|
||||||
final FutureCellData cellData;
|
final CellData cellData;
|
||||||
|
|
||||||
const CheckboxCell({
|
const CheckboxCell({
|
||||||
required this.cellData,
|
required this.cellData,
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import 'package:flutter/widgets.dart';
|
|||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
|
||||||
class DateCell extends StatefulWidget {
|
class DateCell extends StatefulWidget {
|
||||||
final FutureCellData cellData;
|
final CellData cellData;
|
||||||
|
|
||||||
const DateCell({
|
const DateCell({
|
||||||
required this.cellData,
|
required this.cellData,
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
|
||||||
class NumberCell extends StatefulWidget {
|
class NumberCell extends StatefulWidget {
|
||||||
final FutureCellData cellData;
|
final CellData cellData;
|
||||||
|
|
||||||
const NumberCell({
|
const NumberCell({
|
||||||
required this.cellData,
|
required this.cellData,
|
||||||
|
|||||||
@ -1,3 +1,6 @@
|
|||||||
|
import 'dart:collection';
|
||||||
|
|
||||||
|
import 'package:flowy_infra/size.dart';
|
||||||
import 'package:flowy_infra/theme.dart';
|
import 'package:flowy_infra/theme.dart';
|
||||||
import 'package:flowy_infra_ui/style_widget/text.dart';
|
import 'package:flowy_infra_ui/style_widget/text.dart';
|
||||||
import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart';
|
import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart';
|
||||||
@ -61,10 +64,19 @@ extension SelectOptionColorExtension on SelectOptionColor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class SelectOptionTextField extends StatelessWidget {
|
class SelectOptionTextField extends StatelessWidget {
|
||||||
final TextEditingController _controller;
|
|
||||||
final FocusNode _focusNode;
|
final FocusNode _focusNode;
|
||||||
|
final TextEditingController _controller;
|
||||||
|
final TextfieldTagsController tagController;
|
||||||
|
final LinkedHashMap<String, SelectOption> optionMap;
|
||||||
|
final double distanceToText;
|
||||||
|
|
||||||
|
final Function(String) onNewTag;
|
||||||
|
|
||||||
SelectOptionTextField({
|
SelectOptionTextField({
|
||||||
|
required this.optionMap,
|
||||||
|
required this.distanceToText,
|
||||||
|
required this.tagController,
|
||||||
|
required this.onNewTag,
|
||||||
TextEditingController? controller,
|
TextEditingController? controller,
|
||||||
FocusNode? focusNode,
|
FocusNode? focusNode,
|
||||||
Key? key,
|
Key? key,
|
||||||
@ -74,26 +86,45 @@ class SelectOptionTextField extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final theme = context.watch<AppTheme>();
|
||||||
|
|
||||||
return TextFieldTags(
|
return TextFieldTags(
|
||||||
textEditingController: _controller,
|
textEditingController: _controller,
|
||||||
initialTags: ["abc", "bdf"],
|
textfieldTagsController: tagController,
|
||||||
|
initialTags: optionMap.keys.toList(),
|
||||||
focusNode: _focusNode,
|
focusNode: _focusNode,
|
||||||
textSeparators: const [' ', ','],
|
textSeparators: const [' ', ','],
|
||||||
inputfieldBuilder: (BuildContext context, editController, focusNode, error, onChanged, onSubmitted) {
|
inputfieldBuilder: (BuildContext context, editController, focusNode, error, onChanged, onSubmitted) {
|
||||||
return ((context, sc, tags, onTagDelegate) {
|
return ((context, sc, tags, onTagDelegate) {
|
||||||
|
tags.retainWhere((name) => optionMap.containsKey(name) == false);
|
||||||
|
if (tags.isNotEmpty) {
|
||||||
|
assert(tags.length == 1);
|
||||||
|
onNewTag(tags.first);
|
||||||
|
}
|
||||||
|
|
||||||
return TextField(
|
return TextField(
|
||||||
controller: editController,
|
controller: editController,
|
||||||
focusNode: focusNode,
|
focusNode: focusNode,
|
||||||
onChanged: onChanged,
|
onChanged: onChanged,
|
||||||
onSubmitted: onSubmitted,
|
onSubmitted: onSubmitted,
|
||||||
onEditingComplete: () => focusNode.unfocus(),
|
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
|
style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
contentPadding: EdgeInsets.zero,
|
border: OutlineInputBorder(
|
||||||
border: InputBorder.none,
|
borderSide: BorderSide(color: theme.shader3, width: 1.0),
|
||||||
|
borderRadius: Corners.s10Border,
|
||||||
|
),
|
||||||
isDense: true,
|
isDense: true,
|
||||||
prefixIcon: _renderTags(tags, sc),
|
prefixIcon: _renderTags(sc),
|
||||||
|
hintText: LocaleKeys.grid_selectOption_searchOption.tr(),
|
||||||
|
prefixIconConstraints: BoxConstraints(maxWidth: distanceToText),
|
||||||
|
focusedBorder: OutlineInputBorder(
|
||||||
|
borderSide: BorderSide(
|
||||||
|
color: theme.main1,
|
||||||
|
width: 1.0,
|
||||||
|
),
|
||||||
|
borderRadius: Corners.s10Border,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -101,41 +132,26 @@ class SelectOptionTextField extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget? _renderTags(List<String> tags, ScrollController sc) {
|
Widget? _renderTags(ScrollController sc) {
|
||||||
if (tags.isEmpty) {
|
if (optionMap.isEmpty) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return SingleChildScrollView(
|
final children = optionMap.values.map((option) => SelectOptionTag(option: option)).toList();
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: SingleChildScrollView(
|
||||||
controller: sc,
|
controller: sc,
|
||||||
scrollDirection: Axis.horizontal,
|
scrollDirection: Axis.horizontal,
|
||||||
child: Row(children: [
|
child: Row(children: children),
|
||||||
Container(
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Color.fromARGB(255, 74, 137, 92),
|
|
||||||
shape: BoxShape.rectangle,
|
|
||||||
borderRadius: BorderRadius.circular(6.0),
|
|
||||||
),
|
),
|
||||||
child: FlowyText.medium("efc", fontSize: 12),
|
|
||||||
),
|
|
||||||
Container(
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Color.fromARGB(255, 74, 137, 92),
|
|
||||||
shape: BoxShape.rectangle,
|
|
||||||
borderRadius: BorderRadius.circular(6.0),
|
|
||||||
),
|
|
||||||
child: FlowyText.medium("abc", fontSize: 12),
|
|
||||||
margin: const EdgeInsets.symmetric(horizontal: 5.0),
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 5.0),
|
|
||||||
)
|
|
||||||
]),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SelectionBadge extends StatelessWidget {
|
class SelectOptionTag extends StatelessWidget {
|
||||||
final SelectOption option;
|
final SelectOption option;
|
||||||
const SelectionBadge({required this.option, Key? key}) : super(key: key);
|
const SelectOptionTag({required this.option, Key? key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -143,9 +159,11 @@ class SelectionBadge extends StatelessWidget {
|
|||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: option.color.make(context),
|
color: option.color.make(context),
|
||||||
shape: BoxShape.rectangle,
|
shape: BoxShape.rectangle,
|
||||||
borderRadius: BorderRadius.circular(6.0),
|
borderRadius: BorderRadius.circular(8.0),
|
||||||
),
|
),
|
||||||
child: FlowyText.medium(option.name, fontSize: 12),
|
child: Center(child: FlowyText.medium(option.name, fontSize: 12)),
|
||||||
|
margin: const EdgeInsets.symmetric(horizontal: 3.0),
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 6.0),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,9 +6,10 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
|
||||||
import 'extension.dart';
|
import 'extension.dart';
|
||||||
|
import 'selection_editor.dart';
|
||||||
|
|
||||||
class SingleSelectCell extends StatefulWidget {
|
class SingleSelectCell extends StatefulWidget {
|
||||||
final FutureCellData cellData;
|
final CellData cellData;
|
||||||
|
|
||||||
const SingleSelectCell({
|
const SingleSelectCell({
|
||||||
required this.cellData,
|
required this.cellData,
|
||||||
@ -20,30 +21,28 @@ class SingleSelectCell extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _SingleSelectCellState extends State<SingleSelectCell> {
|
class _SingleSelectCellState extends State<SingleSelectCell> {
|
||||||
late CellFocusNode _focusNode;
|
|
||||||
late SelectionCellBloc _cellBloc;
|
late SelectionCellBloc _cellBloc;
|
||||||
late TextEditingController _controller;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
_cellBloc = getIt<SelectionCellBloc>(param1: widget.cellData);
|
_cellBloc = getIt<SelectionCellBloc>(param1: widget.cellData)..add(const SelectionCellEvent.initial());
|
||||||
_controller = TextEditingController();
|
|
||||||
_focusNode = CellFocusNode();
|
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
_focusNode.addCallback(context, () {
|
|
||||||
Log.info(_focusNode.hasFocus);
|
|
||||||
});
|
|
||||||
return BlocProvider.value(
|
return BlocProvider.value(
|
||||||
value: _cellBloc,
|
value: _cellBloc,
|
||||||
child: BlocBuilder<SelectionCellBloc, SelectionCellState>(
|
child: BlocBuilder<SelectionCellBloc, SelectionCellState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
return SelectOptionTextField(
|
final children = state.selectedOptions.map((option) => SelectOptionTag(option: option)).toList();
|
||||||
focusNode: _focusNode,
|
return SizedBox.expand(
|
||||||
controller: _controller,
|
child: InkWell(
|
||||||
|
onTap: () {
|
||||||
|
SelectionEditor.show(context, state.cellData, state.options, state.selectedOptions);
|
||||||
|
},
|
||||||
|
child: Row(children: children),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -53,14 +52,13 @@ class _SingleSelectCellState extends State<SingleSelectCell> {
|
|||||||
@override
|
@override
|
||||||
Future<void> dispose() async {
|
Future<void> dispose() async {
|
||||||
_cellBloc.close();
|
_cellBloc.close();
|
||||||
_focusNode.dispose();
|
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
class MultiSelectCell extends StatefulWidget {
|
class MultiSelectCell extends StatefulWidget {
|
||||||
final FutureCellData cellData;
|
final CellData cellData;
|
||||||
|
|
||||||
const MultiSelectCell({
|
const MultiSelectCell({
|
||||||
required this.cellData,
|
required this.cellData,
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
|
import 'dart:collection';
|
||||||
|
|
||||||
import 'package:app_flowy/workspace/application/grid/cell_bloc/selection_editor_bloc.dart';
|
import 'package:app_flowy/workspace/application/grid/cell_bloc/selection_editor_bloc.dart';
|
||||||
import 'package:app_flowy/workspace/application/grid/row/row_service.dart';
|
import 'package:app_flowy/workspace/application/grid/row/row_service.dart';
|
||||||
import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart';
|
import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart';
|
||||||
|
import 'package:flowy_infra/image.dart';
|
||||||
import 'package:flowy_infra/theme.dart';
|
import 'package:flowy_infra/theme.dart';
|
||||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||||
import 'package:flowy_infra_ui/style_widget/hover.dart';
|
import 'package:flowy_infra_ui/style_widget/hover.dart';
|
||||||
@ -12,42 +15,81 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:app_flowy/generated/locale_keys.g.dart';
|
import 'package:app_flowy/generated/locale_keys.g.dart';
|
||||||
|
import 'package:textfield_tags/textfield_tags.dart';
|
||||||
|
|
||||||
import 'extension.dart';
|
import 'extension.dart';
|
||||||
|
|
||||||
class SelectionEditor extends StatelessWidget {
|
const double _editorPannelWidth = 300;
|
||||||
final GridCellData cellData;
|
|
||||||
const SelectionEditor({required this.cellData, Key? key}) : super(key: key);
|
|
||||||
|
|
||||||
void show(BuildContext context) {
|
class SelectionEditor extends StatelessWidget {
|
||||||
FlowyOverlay.of(context).insertWithAnchor(
|
final CellData cellData;
|
||||||
widget: OverlayContainer(
|
final List<SelectOption> options;
|
||||||
child: this,
|
final List<SelectOption> selectedOptions;
|
||||||
constraints: BoxConstraints.loose(const Size(240, 200)),
|
|
||||||
),
|
const SelectionEditor({
|
||||||
identifier: toString(),
|
required this.cellData,
|
||||||
anchorContext: context,
|
required this.options,
|
||||||
anchorDirection: AnchorDirection.bottomWithLeftAligned,
|
required this.selectedOptions,
|
||||||
);
|
Key? key,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
static String identifier() {
|
||||||
|
return (SelectionEditor).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (context) => SelectionEditorBloc(gridId: cellData.gridId, field: cellData.field),
|
create: (context) => SelectOptionEditorBloc(
|
||||||
child: BlocBuilder<SelectionEditorBloc, SelectionEditorState>(
|
gridId: cellData.gridId,
|
||||||
|
field: cellData.field,
|
||||||
|
options: options,
|
||||||
|
selectedOptions: selectedOptions,
|
||||||
|
),
|
||||||
|
child: BlocBuilder<SelectOptionEditorBloc, SelectOptionEditorState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
return Column(
|
return CustomScrollView(
|
||||||
children: const [
|
shrinkWrap: true,
|
||||||
_Title(),
|
slivers: [
|
||||||
VSpace(10),
|
SliverToBoxAdapter(child: _TextField()),
|
||||||
_OptionList(),
|
const SliverToBoxAdapter(child: VSpace(10)),
|
||||||
|
const SliverToBoxAdapter(child: _Title()),
|
||||||
|
const SliverToBoxAdapter(child: _OptionList()),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void show(
|
||||||
|
BuildContext context,
|
||||||
|
CellData cellData,
|
||||||
|
List<SelectOption> options,
|
||||||
|
List<SelectOption> selectedOptions,
|
||||||
|
) {
|
||||||
|
SelectionEditor.hide(context);
|
||||||
|
final editor = SelectionEditor(
|
||||||
|
cellData: cellData,
|
||||||
|
options: options,
|
||||||
|
selectedOptions: selectedOptions,
|
||||||
|
);
|
||||||
|
|
||||||
|
//
|
||||||
|
FlowyOverlay.of(context).insertWithAnchor(
|
||||||
|
widget: OverlayContainer(
|
||||||
|
child: SizedBox(width: _editorPannelWidth, child: editor),
|
||||||
|
constraints: BoxConstraints.loose(const Size(_editorPannelWidth, 300)),
|
||||||
|
),
|
||||||
|
identifier: SelectionEditor.identifier(),
|
||||||
|
anchorContext: context,
|
||||||
|
anchorDirection: AnchorDirection.bottomWithCenterAligned,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hide(BuildContext context) {
|
||||||
|
FlowyOverlay.of(context).remove(identifier());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _OptionList extends StatelessWidget {
|
class _OptionList extends StatelessWidget {
|
||||||
@ -55,9 +97,9 @@ class _OptionList extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocBuilder<SelectionEditorBloc, SelectionEditorState>(
|
return BlocBuilder<SelectOptionEditorBloc, SelectOptionEditorState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
final cells = state.options.map((option) => _SelectionCell(option)).toList();
|
final cells = state.options.map((option) => _SelectOptionCell(option)).toList();
|
||||||
final list = ListView.separated(
|
final list = ListView.separated(
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
controller: ScrollController(),
|
controller: ScrollController(),
|
||||||
@ -76,40 +118,84 @@ class _OptionList extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _TextField extends StatelessWidget {
|
||||||
|
final TextfieldTagsController _tagController = TextfieldTagsController();
|
||||||
|
|
||||||
|
_TextField({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return BlocConsumer<SelectOptionEditorBloc, SelectOptionEditorState>(
|
||||||
|
listener: (context, state) {},
|
||||||
|
buildWhen: (previous, current) => previous.field.id != current.field.id,
|
||||||
|
builder: (context, state) {
|
||||||
|
final optionMap = LinkedHashMap<String, SelectOption>.fromIterable(state.selectedOptions,
|
||||||
|
key: (option) => option.name, value: (option) => option);
|
||||||
|
return SizedBox(
|
||||||
|
height: 42,
|
||||||
|
child: SelectOptionTextField(
|
||||||
|
optionMap: optionMap,
|
||||||
|
distanceToText: _editorPannelWidth * 0.7,
|
||||||
|
tagController: _tagController,
|
||||||
|
onNewTag: (newTagName) {
|
||||||
|
context.read<SelectOptionEditorBloc>().add(SelectOptionEditorEvent.newOption(newTagName));
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class _Title extends StatelessWidget {
|
class _Title extends StatelessWidget {
|
||||||
const _Title({Key? key}) : super(key: key);
|
const _Title({Key? key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final theme = context.watch<AppTheme>();
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
height: GridSize.typeOptionItemHeight,
|
height: GridSize.typeOptionItemHeight,
|
||||||
child: FlowyText.medium(LocaleKeys.grid_selectOption_pannelTitle.tr(), fontSize: 12),
|
child: Padding(
|
||||||
);
|
padding: const EdgeInsets.symmetric(horizontal: 6),
|
||||||
}
|
child: FlowyText.medium(
|
||||||
}
|
LocaleKeys.grid_selectOption_pannelTitle.tr(),
|
||||||
|
fontSize: 12,
|
||||||
class _SelectionCell extends StatelessWidget {
|
color: theme.shader3,
|
||||||
final SelectOption option;
|
),
|
||||||
const _SelectionCell(this.option, {Key? key}) : super(key: key);
|
),
|
||||||
|
);
|
||||||
@override
|
}
|
||||||
Widget build(BuildContext context) {
|
}
|
||||||
final theme = context.watch<AppTheme>();
|
|
||||||
|
class _SelectOptionCell extends StatelessWidget {
|
||||||
// return FlowyButton(
|
final SelectOption option;
|
||||||
// text: FlowyText.medium(fieldType.title(), fontSize: 12),
|
const _SelectOptionCell(this.option, {Key? key}) : super(key: key);
|
||||||
// hoverColor: theme.hover,
|
|
||||||
// onTap: () => onSelectField(fieldType),
|
@override
|
||||||
// leftIcon: svgWidget(fieldType.iconName(), color: theme.iconColor),
|
Widget build(BuildContext context) {
|
||||||
// );
|
final theme = context.watch<AppTheme>();
|
||||||
|
return SizedBox(
|
||||||
return InkWell(
|
height: GridSize.typeOptionItemHeight,
|
||||||
onTap: () {},
|
child: InkWell(
|
||||||
child: FlowyHover(
|
onTap: () {},
|
||||||
config: HoverDisplayConfig(hoverColor: theme.hover),
|
child: FlowyHover(
|
||||||
builder: (_, onHover) {
|
config: HoverDisplayConfig(hoverColor: theme.hover),
|
||||||
return SelectionBadge(option: option);
|
builder: (_, onHover) {
|
||||||
},
|
List<Widget> children = [
|
||||||
|
SelectOptionTag(option: option),
|
||||||
|
const Spacer(),
|
||||||
|
];
|
||||||
|
|
||||||
|
if (onHover) {
|
||||||
|
children.add(svgWidget("editor/details", color: theme.iconColor));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.all(3.0),
|
||||||
|
child: Row(children: children),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
|||||||
import 'cell_container.dart';
|
import 'cell_container.dart';
|
||||||
|
|
||||||
class GridTextCell extends GridCell {
|
class GridTextCell extends GridCell {
|
||||||
final FutureCellData cellData;
|
final CellData cellData;
|
||||||
const GridTextCell({
|
const GridTextCell({
|
||||||
required this.cellData,
|
required this.cellData,
|
||||||
Key? key,
|
Key? key,
|
||||||
|
|||||||
@ -0,0 +1,44 @@
|
|||||||
|
import 'package:app_flowy/startup/startup.dart';
|
||||||
|
import 'package:app_flowy/workspace/application/grid/prelude.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
|
||||||
|
class NumberCell extends StatefulWidget {
|
||||||
|
final CellData cellData;
|
||||||
|
|
||||||
|
const NumberCell({
|
||||||
|
required this.cellData,
|
||||||
|
Key? key,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<NumberCell> createState() => _NumberCellState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _NumberCellState extends State<NumberCell> {
|
||||||
|
late NumberCellBloc _cellBloc;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
_cellBloc = getIt<NumberCellBloc>(param1: widget.cellData);
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return BlocProvider.value(
|
||||||
|
value: _cellBloc,
|
||||||
|
child: BlocBuilder<NumberCellBloc, NumberCellState>(
|
||||||
|
builder: (context, state) {
|
||||||
|
return Container();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> dispose() async {
|
||||||
|
_cellBloc.close();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -10,7 +10,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
|||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
class GridRowWidget extends StatefulWidget {
|
class GridRowWidget extends StatefulWidget {
|
||||||
final GridRowData data;
|
final RowData data;
|
||||||
const GridRowWidget({required this.data, Key? key}) : super(key: key);
|
const GridRowWidget({required this.data, Key? key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@ -0,0 +1,44 @@
|
|||||||
|
import 'package:app_flowy/startup/startup.dart';
|
||||||
|
import 'package:app_flowy/workspace/application/grid/prelude.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
|
||||||
|
class NumberCell extends StatefulWidget {
|
||||||
|
final CellData cellData;
|
||||||
|
|
||||||
|
const NumberCell({
|
||||||
|
required this.cellData,
|
||||||
|
Key? key,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<NumberCell> createState() => _NumberCellState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _NumberCellState extends State<NumberCell> {
|
||||||
|
late NumberCellBloc _cellBloc;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
_cellBloc = getIt<NumberCellBloc>(param1: widget.cellData);
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return BlocProvider.value(
|
||||||
|
value: _cellBloc,
|
||||||
|
child: BlocBuilder<NumberCellBloc, NumberCellState>(
|
||||||
|
builder: (context, state) {
|
||||||
|
return Container();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> dispose() async {
|
||||||
|
_cellBloc.close();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -44,7 +44,7 @@ class FlowyText extends StatelessWidget {
|
|||||||
softWrap: false,
|
softWrap: false,
|
||||||
textAlign: textAlign,
|
textAlign: textAlign,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: theme.textColor,
|
color: color ?? theme.textColor,
|
||||||
fontWeight: fontWeight,
|
fontWeight: fontWeight,
|
||||||
fontSize: fontSize + 2,
|
fontSize: fontSize + 2,
|
||||||
fontFamily: 'Mulish',
|
fontFamily: 'Mulish',
|
||||||
|
|||||||
@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use strum_macros::{Display, EnumCount as EnumCountMacro, EnumIter, EnumString};
|
use strum_macros::{Display, EnumCount as EnumCountMacro, EnumIter, EnumString};
|
||||||
|
|
||||||
pub const DEFAULT_ROW_HEIGHT: i32 = 36;
|
pub const DEFAULT_ROW_HEIGHT: i32 = 42;
|
||||||
pub const DEFAULT_FIELD_WIDTH: i32 = 150;
|
pub const DEFAULT_FIELD_WIDTH: i32 = 150;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, Serialize, Deserialize, ProtoBuf)]
|
#[derive(Debug, Clone, Default, Serialize, Deserialize, ProtoBuf)]
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user