mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
fix: fix bugs
This commit is contained in:
parent
065a72a8da
commit
547b8ec29c
@ -177,7 +177,9 @@
|
||||
"limeColor": "Lime",
|
||||
"greenColor": "Green",
|
||||
"aquaColor": "Aqua",
|
||||
"blueColor": "Blue"
|
||||
"blueColor": "Blue",
|
||||
"deleteTag": "Delete tag",
|
||||
"colorPannelTitle": "Colors"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,12 @@ class OptionPannelBloc extends Bloc<OptionPannelEvent, OptionPannelState> {
|
||||
endAddingOption: (_EndAddingOption value) {
|
||||
emit(state.copyWith(isEditingOption: false, newOptionName: none()));
|
||||
},
|
||||
updateOption: (_UpdateOption value) {
|
||||
emit(state.copyWith(updateOption: Some(value.option)));
|
||||
},
|
||||
deleteOption: (_DeleteOption value) {
|
||||
emit(state.copyWith(deleteOption: Some(value.option)));
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
@ -35,6 +41,8 @@ class OptionPannelEvent with _$OptionPannelEvent {
|
||||
const factory OptionPannelEvent.createOption(String optionName) = _CreateOption;
|
||||
const factory OptionPannelEvent.beginAddingOption() = _BeginAddingOption;
|
||||
const factory OptionPannelEvent.endAddingOption() = _EndAddingOption;
|
||||
const factory OptionPannelEvent.updateOption(SelectOption option) = _UpdateOption;
|
||||
const factory OptionPannelEvent.deleteOption(SelectOption option) = _DeleteOption;
|
||||
}
|
||||
|
||||
@freezed
|
||||
@ -43,11 +51,15 @@ class OptionPannelState with _$OptionPannelState {
|
||||
required List<SelectOption> options,
|
||||
required bool isEditingOption,
|
||||
required Option<String> newOptionName,
|
||||
required Option<SelectOption> updateOption,
|
||||
required Option<SelectOption> deleteOption,
|
||||
}) = _OptionPannelState;
|
||||
|
||||
factory OptionPannelState.initial(List<SelectOption> options) => OptionPannelState(
|
||||
options: options,
|
||||
isEditingOption: false,
|
||||
newOptionName: none(),
|
||||
updateOption: none(),
|
||||
deleteOption: none(),
|
||||
);
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:protobuf/protobuf.dart';
|
||||
import 'type_option_service.dart';
|
||||
|
||||
part 'single_select_bloc.freezed.dart';
|
||||
@ -11,9 +11,13 @@ part 'single_select_bloc.freezed.dart';
|
||||
class SingleSelectTypeOptionBloc extends Bloc<SingleSelectTypeOptionEvent, SingleSelectTypeOptionState> {
|
||||
final TypeOptionService service;
|
||||
|
||||
SingleSelectTypeOptionBloc(SingleSelectTypeOption typeOption, String fieldId)
|
||||
: service = TypeOptionService(fieldId: fieldId),
|
||||
super(SingleSelectTypeOptionState.initial(typeOption)) {
|
||||
SingleSelectTypeOptionBloc(
|
||||
SingleSelectTypeOption typeOption,
|
||||
String fieldId,
|
||||
) : service = TypeOptionService(fieldId: fieldId),
|
||||
super(
|
||||
SingleSelectTypeOptionState.initial(typeOption),
|
||||
) {
|
||||
on<SingleSelectTypeOptionEvent>(
|
||||
(event, emit) async {
|
||||
await event.map(
|
||||
@ -21,13 +25,17 @@ class SingleSelectTypeOptionBloc extends Bloc<SingleSelectTypeOptionEvent, Singl
|
||||
final result = await service.createOption(value.optionName);
|
||||
result.fold(
|
||||
(option) {
|
||||
state.typeOption.options.insert(0, option);
|
||||
emit(state);
|
||||
emit(state.copyWith(typeOption: _insertOption(option)));
|
||||
},
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
},
|
||||
updateOptions: (_UpdateOptions value) async {},
|
||||
updateOption: (_UpdateOption value) async {
|
||||
emit(state.copyWith(typeOption: _updateOption(value.option)));
|
||||
},
|
||||
deleteOption: (_DeleteOption value) {
|
||||
emit(state.copyWith(typeOption: _deleteOption(value.option)));
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
@ -37,12 +45,40 @@ class SingleSelectTypeOptionBloc extends Bloc<SingleSelectTypeOptionEvent, Singl
|
||||
Future<void> close() async {
|
||||
return super.close();
|
||||
}
|
||||
|
||||
SingleSelectTypeOption _insertOption(SelectOption option) {
|
||||
state.typeOption.freeze();
|
||||
return state.typeOption.rebuild((typeOption) {
|
||||
typeOption.options.insert(0, option);
|
||||
});
|
||||
}
|
||||
|
||||
SingleSelectTypeOption _updateOption(SelectOption option) {
|
||||
state.typeOption.freeze();
|
||||
return state.typeOption.rebuild((typeOption) {
|
||||
final index = typeOption.options.indexWhere((element) => element.id == option.id);
|
||||
if (index != -1) {
|
||||
typeOption.options[index] = option;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
SingleSelectTypeOption _deleteOption(SelectOption option) {
|
||||
state.typeOption.freeze();
|
||||
return state.typeOption.rebuild((typeOption) {
|
||||
final index = typeOption.options.indexWhere((element) => element.id == option.id);
|
||||
if (index != -1) {
|
||||
typeOption.options.removeAt(index);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@freezed
|
||||
class SingleSelectTypeOptionEvent with _$SingleSelectTypeOptionEvent {
|
||||
const factory SingleSelectTypeOptionEvent.createOption(String optionName) = _CreateOption;
|
||||
const factory SingleSelectTypeOptionEvent.updateOptions(List<SelectOption> options) = _UpdateOptions;
|
||||
const factory SingleSelectTypeOptionEvent.updateOption(SelectOption option) = _UpdateOption;
|
||||
const factory SingleSelectTypeOptionEvent.deleteOption(SelectOption option) = _DeleteOption;
|
||||
}
|
||||
|
||||
@freezed
|
||||
|
@ -79,7 +79,7 @@ class _FieldTypeSwitcherState extends State<FieldTypeSwitcher> {
|
||||
final list = FieldTypeList(onSelectField: (fieldType) {
|
||||
context.read<FieldTypeSwitchBloc>().add(FieldTypeSwitchEvent.toFieldType(fieldType));
|
||||
});
|
||||
_showOverlay(context, FieldTypeList.identifier(), list);
|
||||
_showOverlay(context, list);
|
||||
},
|
||||
leftIcon: svg(field.fieldType.iconName(), color: theme.iconColor),
|
||||
rightIcon: svg("grid/more", color: theme.iconColor),
|
||||
@ -92,18 +92,27 @@ class _FieldTypeSwitcherState extends State<FieldTypeSwitcher> {
|
||||
required Field field,
|
||||
required TypeOptionData data,
|
||||
}) {
|
||||
final delegate = TypeOptionOperationDelegate(
|
||||
didUpdateTypeOptionData: (data) {
|
||||
context.read<FieldTypeSwitchBloc>().add(FieldTypeSwitchEvent.didUpdateTypeOptionData(data));
|
||||
},
|
||||
requireToShowOverlay: _showOverlay,
|
||||
final overlayDelegate = TypeOptionOverlayDelegate(
|
||||
showOverlay: _showOverlay,
|
||||
hideOverlay: _hideOverlay,
|
||||
);
|
||||
final builder = _makeTypeOptionBuild(field: field, data: data, delegate: delegate);
|
||||
|
||||
final dataDelegate = TypeOptionDataDelegate(didUpdateTypeOptionData: (data) {
|
||||
context.read<FieldTypeSwitchBloc>().add(FieldTypeSwitchEvent.didUpdateTypeOptionData(data));
|
||||
});
|
||||
|
||||
final builder = _makeTypeOptionBuild(
|
||||
field: field,
|
||||
data: data,
|
||||
overlayDelegate: overlayDelegate,
|
||||
dataDelegate: dataDelegate,
|
||||
);
|
||||
|
||||
return builder.customWidget;
|
||||
}
|
||||
|
||||
void _showOverlay(BuildContext context, String identifier, Widget child) {
|
||||
void _showOverlay(BuildContext context, Widget child, {VoidCallback? onRemoved}) {
|
||||
final identifier = child.toString();
|
||||
if (currentOverlayIdentifier != null) {
|
||||
FlowyOverlay.of(context).remove(currentOverlayIdentifier!);
|
||||
}
|
||||
@ -112,7 +121,7 @@ class _FieldTypeSwitcherState extends State<FieldTypeSwitcher> {
|
||||
FlowyOverlay.of(context).insertWithAnchor(
|
||||
widget: OverlayContainer(
|
||||
child: child,
|
||||
constraints: BoxConstraints.loose(const Size(240, 400)),
|
||||
constraints: BoxConstraints.loose(const Size(340, 400)),
|
||||
),
|
||||
identifier: identifier,
|
||||
anchorContext: context,
|
||||
@ -136,19 +145,20 @@ abstract class TypeOptionBuilder {
|
||||
TypeOptionBuilder _makeTypeOptionBuild({
|
||||
required Field field,
|
||||
required TypeOptionData data,
|
||||
required TypeOptionOperationDelegate delegate,
|
||||
required TypeOptionOverlayDelegate overlayDelegate,
|
||||
required TypeOptionDataDelegate dataDelegate,
|
||||
}) {
|
||||
switch (field.fieldType) {
|
||||
case FieldType.Checkbox:
|
||||
return CheckboxTypeOptionBuilder(data);
|
||||
case FieldType.DateTime:
|
||||
return DateTypeOptionBuilder(data, delegate);
|
||||
return DateTypeOptionBuilder(data, overlayDelegate, dataDelegate);
|
||||
case FieldType.SingleSelect:
|
||||
return SingleSelectTypeOptionBuilder(field.id, data, delegate);
|
||||
return SingleSelectTypeOptionBuilder(field.id, data, overlayDelegate, dataDelegate);
|
||||
case FieldType.MultiSelect:
|
||||
return MultiSelectTypeOptionBuilder(data, delegate);
|
||||
return MultiSelectTypeOptionBuilder(data, overlayDelegate);
|
||||
case FieldType.Number:
|
||||
return NumberTypeOptionBuilder(data, delegate);
|
||||
return NumberTypeOptionBuilder(data, overlayDelegate, dataDelegate);
|
||||
case FieldType.RichText:
|
||||
return RichTextTypeOptionBuilder(data);
|
||||
|
||||
@ -163,20 +173,30 @@ abstract class TypeOptionWidget extends StatelessWidget {
|
||||
|
||||
typedef TypeOptionData = Uint8List;
|
||||
typedef TypeOptionDataCallback = void Function(TypeOptionData typeOptionData);
|
||||
typedef ShowOverlayCallback = void Function(BuildContext anchorContext, String overlayIdentifier, Widget child);
|
||||
typedef ShowOverlayCallback = void Function(
|
||||
BuildContext anchorContext,
|
||||
Widget child, {
|
||||
VoidCallback? onRemoved,
|
||||
});
|
||||
typedef HideOverlayCallback = void Function(BuildContext anchorContext);
|
||||
|
||||
class TypeOptionOperationDelegate {
|
||||
TypeOptionDataCallback didUpdateTypeOptionData;
|
||||
ShowOverlayCallback requireToShowOverlay;
|
||||
class TypeOptionOverlayDelegate {
|
||||
ShowOverlayCallback showOverlay;
|
||||
HideOverlayCallback hideOverlay;
|
||||
TypeOptionOperationDelegate({
|
||||
required this.didUpdateTypeOptionData,
|
||||
required this.requireToShowOverlay,
|
||||
TypeOptionOverlayDelegate({
|
||||
required this.showOverlay,
|
||||
required this.hideOverlay,
|
||||
});
|
||||
}
|
||||
|
||||
class TypeOptionDataDelegate {
|
||||
TypeOptionDataCallback didUpdateTypeOptionData;
|
||||
|
||||
TypeOptionDataDelegate({
|
||||
required this.didUpdateTypeOptionData,
|
||||
});
|
||||
}
|
||||
|
||||
class RichTextTypeOptionBuilder extends TypeOptionBuilder {
|
||||
RichTextTypeOption typeOption;
|
||||
|
||||
|
@ -17,22 +17,6 @@ class FieldTypeList extends StatelessWidget {
|
||||
final SelectFieldCallback onSelectField;
|
||||
const FieldTypeList({required this.onSelectField, Key? key}) : super(key: key);
|
||||
|
||||
static void show(BuildContext context, SelectFieldCallback onSelectField) {
|
||||
final list = FieldTypeList(onSelectField: onSelectField);
|
||||
FieldTypeList.hide(context);
|
||||
FlowyOverlay.of(context).insertWithAnchor(
|
||||
widget: OverlayContainer(
|
||||
child: list,
|
||||
constraints: BoxConstraints.loose(const Size(140, 300)),
|
||||
),
|
||||
identifier: FieldTypeList.identifier(),
|
||||
anchorContext: context,
|
||||
anchorDirection: AnchorDirection.leftWithCenterAligned,
|
||||
style: FlowyOverlayStyle(blur: false),
|
||||
anchorOffset: const Offset(-20, 0),
|
||||
);
|
||||
}
|
||||
|
||||
static void hide(BuildContext context) {
|
||||
FlowyOverlay.of(context).remove(FieldTypeList.identifier());
|
||||
}
|
||||
|
@ -15,30 +15,39 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
class DateTypeOptionBuilder extends TypeOptionBuilder {
|
||||
DateTypeOption typeOption;
|
||||
TypeOptionOperationDelegate delegate;
|
||||
final DateTypeOptionWidget _widget;
|
||||
|
||||
DateTypeOptionBuilder(TypeOptionData typeOptionData, this.delegate)
|
||||
: typeOption = DateTypeOption.fromBuffer(typeOptionData);
|
||||
DateTypeOptionBuilder(
|
||||
TypeOptionData typeOptionData,
|
||||
TypeOptionOverlayDelegate overlayDelegate,
|
||||
TypeOptionDataDelegate dataDelegate,
|
||||
) : _widget = DateTypeOptionWidget(
|
||||
typeOption: DateTypeOption.fromBuffer(typeOptionData),
|
||||
dataDelegate: dataDelegate,
|
||||
overlayDelegate: overlayDelegate,
|
||||
);
|
||||
|
||||
@override
|
||||
Widget? get customWidget => DateTypeOptionWidget(
|
||||
typeOption: typeOption,
|
||||
operationDelegate: delegate,
|
||||
);
|
||||
Widget? get customWidget => _widget;
|
||||
}
|
||||
|
||||
class DateTypeOptionWidget extends TypeOptionWidget {
|
||||
final DateTypeOption typeOption;
|
||||
final TypeOptionOperationDelegate operationDelegate;
|
||||
const DateTypeOptionWidget({required this.typeOption, required this.operationDelegate, Key? key}) : super(key: key);
|
||||
final TypeOptionOverlayDelegate overlayDelegate;
|
||||
final TypeOptionDataDelegate dataDelegate;
|
||||
const DateTypeOptionWidget({
|
||||
required this.typeOption,
|
||||
required this.dataDelegate,
|
||||
required this.overlayDelegate,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (context) => getIt<DateTypeOptionBloc>(param1: typeOption),
|
||||
child: BlocConsumer<DateTypeOptionBloc, DateTypeOptionState>(
|
||||
listener: (context, state) => operationDelegate.didUpdateTypeOptionData(state.typeOption.writeToBuffer()),
|
||||
listener: (context, state) => dataDelegate.didUpdateTypeOptionData(state.typeOption.writeToBuffer()),
|
||||
builder: (context, state) {
|
||||
return Column(children: [
|
||||
_dateFormatButton(context),
|
||||
@ -61,7 +70,7 @@ class DateTypeOptionWidget extends TypeOptionWidget {
|
||||
final list = DateFormatList(onSelected: (format) {
|
||||
context.read<DateTypeOptionBloc>().add(DateTypeOptionEvent.didSelectDateFormat(format));
|
||||
});
|
||||
operationDelegate.requireToShowOverlay(context, list.identifier(), list);
|
||||
overlayDelegate.showOverlay(context, list);
|
||||
},
|
||||
rightIcon: svg("grid/more", color: theme.iconColor),
|
||||
),
|
||||
@ -80,7 +89,7 @@ class DateTypeOptionWidget extends TypeOptionWidget {
|
||||
final list = TimeFormatList(onSelected: (format) {
|
||||
context.read<DateTypeOptionBloc>().add(DateTypeOptionEvent.didSelectTimeFormat(format));
|
||||
});
|
||||
operationDelegate.requireToShowOverlay(context, list.identifier(), list);
|
||||
overlayDelegate.showOverlay(context, list);
|
||||
},
|
||||
rightIcon: svg("grid/more", color: theme.iconColor),
|
||||
),
|
||||
|
@ -1,18 +1,151 @@
|
||||
import 'package:app_flowy/workspace/application/grid/field/type_option/edit_option_bloc.dart';
|
||||
import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart';
|
||||
import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/type_option/widget.dart';
|
||||
import 'package:flowy_infra/image.dart';
|
||||
import 'package:flowy_infra/theme.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/button.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/text.dart';
|
||||
import 'package:flowy_infra_ui/widget/spacing.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:app_flowy/generated/locale_keys.g.dart';
|
||||
|
||||
class EditSelectOptionPannel extends StatelessWidget {
|
||||
final SelectOption option;
|
||||
final VoidCallback onDeleted;
|
||||
final Function(SelectOption) onUpdated;
|
||||
const EditSelectOptionPannel({
|
||||
required this.option,
|
||||
required this.onDeleted,
|
||||
required this.onUpdated,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (context) => EditOptionBloc(option: option),
|
||||
child: MultiBlocListener(
|
||||
listeners: [
|
||||
BlocListener<EditOptionBloc, EditOptionState>(
|
||||
listenWhen: (p, c) => p.deleted != c.deleted,
|
||||
listener: (context, state) {
|
||||
state.deleted.fold(() => null, (_) => onDeleted());
|
||||
},
|
||||
),
|
||||
BlocListener<EditOptionBloc, EditOptionState>(
|
||||
listenWhen: (p, c) => p.option != c.option,
|
||||
listener: (context, state) {
|
||||
onUpdated(state.option);
|
||||
},
|
||||
),
|
||||
],
|
||||
child: BlocBuilder<EditOptionBloc, EditOptionState>(
|
||||
builder: (context, state) {
|
||||
List<Widget> slivers = [
|
||||
SliverToBoxAdapter(child: _OptionNameTextField(state.option.name)),
|
||||
const SliverToBoxAdapter(child: VSpace(10)),
|
||||
const SliverToBoxAdapter(child: _DeleteTag()),
|
||||
const SliverToBoxAdapter(child: TypeOptionSeparator()),
|
||||
const SliverToBoxAdapter(child: SelectOptionColorList()),
|
||||
];
|
||||
|
||||
return CustomScrollView(
|
||||
slivers: slivers,
|
||||
controller: ScrollController(),
|
||||
physics: StyledScrollPhysics(),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _DeleteTag extends StatelessWidget {
|
||||
const _DeleteTag({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = context.watch<AppTheme>();
|
||||
return SizedBox(
|
||||
height: GridSize.typeOptionItemHeight,
|
||||
child: FlowyButton(
|
||||
text: FlowyText.medium(LocaleKeys.grid_selectOption_deleteTag.tr(), fontSize: 12),
|
||||
hoverColor: theme.hover,
|
||||
leftIcon: svg("grid/delete", color: theme.iconColor),
|
||||
onTap: () {
|
||||
context.read<EditOptionBloc>().add(const EditOptionEvent.delete());
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _OptionNameTextField extends StatelessWidget {
|
||||
final String name;
|
||||
const _OptionNameTextField(this.name, {Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return NameTextField(
|
||||
name: name,
|
||||
onCanceled: () {},
|
||||
onDone: (optionName) {
|
||||
context.read<EditOptionBloc>().add(EditOptionEvent.updateName(optionName));
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class SelectOptionColorList extends StatelessWidget {
|
||||
const SelectOptionColorList({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container();
|
||||
final optionItems = SelectOptionColor.values.map((option) {
|
||||
// Color color = option.color();
|
||||
// var hex = option.color.value.toRadixString(16);
|
||||
// if (hex.startsWith('ff')) {
|
||||
// hex = hex.substring(2);
|
||||
// }
|
||||
// hex = '#$hex';
|
||||
|
||||
return _SelectOptionColorItem(option: option, isSelected: true);
|
||||
}).toList();
|
||||
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: GridSize.typeOptionContentInsets,
|
||||
child: SizedBox(
|
||||
height: GridSize.typeOptionItemHeight,
|
||||
child: FlowyText.medium(
|
||||
LocaleKeys.grid_selectOption_colorPannelTitle.tr(),
|
||||
fontSize: 12,
|
||||
textAlign: TextAlign.left,
|
||||
),
|
||||
),
|
||||
),
|
||||
ListView.separated(
|
||||
shrinkWrap: true,
|
||||
controller: ScrollController(),
|
||||
separatorBuilder: (context, index) {
|
||||
return VSpace(GridSize.typeOptionSeparatorHeight);
|
||||
},
|
||||
itemCount: optionItems.length,
|
||||
physics: StyledScrollPhysics(),
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return optionItems[index];
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,12 +157,12 @@ class _SelectOptionColorItem extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = context.watch<AppTheme>();
|
||||
|
||||
Widget? checkmark;
|
||||
if (isSelected) {
|
||||
checkmark = svg("grid/details", color: theme.iconColor);
|
||||
}
|
||||
|
||||
final String hex = '#${option.color(context).value.toRadixString(16)}';
|
||||
final colorIcon = SizedBox.square(
|
||||
dimension: 16,
|
||||
child: Container(
|
||||
@ -40,15 +173,17 @@ class _SelectOptionColorItem extends StatelessWidget {
|
||||
),
|
||||
);
|
||||
|
||||
return FlowyButton(
|
||||
text: FlowyText.medium(
|
||||
option.name(),
|
||||
fontSize: 12,
|
||||
return SizedBox(
|
||||
height: GridSize.typeOptionItemHeight,
|
||||
child: FlowyButton(
|
||||
text: FlowyText.medium(option.name(), fontSize: 12),
|
||||
hoverColor: theme.hover,
|
||||
leftIcon: colorIcon,
|
||||
rightIcon: checkmark,
|
||||
onTap: () {
|
||||
context.read<EditOptionBloc>().add(EditOptionEvent.updateColor(hex));
|
||||
},
|
||||
),
|
||||
hoverColor: theme.hover,
|
||||
leftIcon: colorIcon,
|
||||
rightIcon: checkmark,
|
||||
onTap: () {},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ import 'option_pannel.dart';
|
||||
|
||||
class MultiSelectTypeOptionBuilder extends TypeOptionBuilder {
|
||||
MultiSelectTypeOption typeOption;
|
||||
TypeOptionOperationDelegate delegate;
|
||||
TypeOptionOverlayDelegate delegate;
|
||||
|
||||
MultiSelectTypeOptionBuilder(TypeOptionData typeOptionData, this.delegate)
|
||||
: typeOption = MultiSelectTypeOption.fromBuffer(typeOptionData);
|
||||
@ -20,8 +20,8 @@ class MultiSelectTypeOptionBuilder extends TypeOptionBuilder {
|
||||
|
||||
class MultiSelectTypeOptionWidget extends TypeOptionWidget {
|
||||
final MultiSelectTypeOption typeOption;
|
||||
final TypeOptionOperationDelegate delegate;
|
||||
const MultiSelectTypeOptionWidget(this.typeOption, this.delegate, {Key? key}) : super(key: key);
|
||||
final TypeOptionOverlayDelegate overlayDelegate;
|
||||
const MultiSelectTypeOptionWidget(this.typeOption, this.overlayDelegate, {Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -32,14 +32,14 @@ class MultiSelectTypeOptionWidget extends TypeOptionWidget {
|
||||
return OptionPannel(
|
||||
options: state.typeOption.options,
|
||||
beginEdit: () {
|
||||
delegate.hideOverlay(context);
|
||||
overlayDelegate.hideOverlay(context);
|
||||
},
|
||||
createOptionCallback: (name) {
|
||||
context.read<MultiSelectTypeOptionBloc>().add(MultiSelectTypeOptionEvent.createOption(name));
|
||||
},
|
||||
updateOptionsCallback: (options) {
|
||||
context.read<MultiSelectTypeOptionBloc>().add(MultiSelectTypeOptionEvent.updateOptions(options));
|
||||
},
|
||||
updateOptionCallback: (updateOption) {},
|
||||
deleteOptionCallback: (deleteOption) {},
|
||||
overlayDelegate: overlayDelegate,
|
||||
);
|
||||
},
|
||||
),
|
||||
|
@ -15,25 +15,29 @@ import 'package:easy_localization/easy_localization.dart' hide NumberFormat;
|
||||
import 'package:app_flowy/generated/locale_keys.g.dart';
|
||||
|
||||
class NumberTypeOptionBuilder extends TypeOptionBuilder {
|
||||
NumberTypeOption typeOption;
|
||||
TypeOptionOperationDelegate delegate;
|
||||
final NumberTypeOptionWidget _widget;
|
||||
|
||||
NumberTypeOptionBuilder(
|
||||
TypeOptionData typeOptionData,
|
||||
this.delegate,
|
||||
) : typeOption = NumberTypeOption.fromBuffer(typeOptionData);
|
||||
TypeOptionOverlayDelegate overlayDelegate,
|
||||
TypeOptionDataDelegate dataDelegate,
|
||||
) : _widget = NumberTypeOptionWidget(
|
||||
typeOption: NumberTypeOption.fromBuffer(typeOptionData),
|
||||
dataDelegate: dataDelegate,
|
||||
overlayDelegate: overlayDelegate,
|
||||
);
|
||||
|
||||
@override
|
||||
Widget? get customWidget => NumberTypeOptionWidget(
|
||||
typeOption: typeOption,
|
||||
operationDelegate: delegate,
|
||||
);
|
||||
Widget? get customWidget => _widget;
|
||||
}
|
||||
|
||||
class NumberTypeOptionWidget extends TypeOptionWidget {
|
||||
final TypeOptionOperationDelegate operationDelegate;
|
||||
final TypeOptionDataDelegate dataDelegate;
|
||||
final TypeOptionOverlayDelegate overlayDelegate;
|
||||
final NumberTypeOption typeOption;
|
||||
const NumberTypeOptionWidget({required this.typeOption, required this.operationDelegate, Key? key}) : super(key: key);
|
||||
const NumberTypeOptionWidget(
|
||||
{required this.typeOption, required this.dataDelegate, required this.overlayDelegate, Key? key})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -43,7 +47,7 @@ class NumberTypeOptionWidget extends TypeOptionWidget {
|
||||
child: SizedBox(
|
||||
height: GridSize.typeOptionItemHeight,
|
||||
child: BlocConsumer<NumberTypeOptionBloc, NumberTypeOptionState>(
|
||||
listener: (context, state) => operationDelegate.didUpdateTypeOptionData(state.typeOption.writeToBuffer()),
|
||||
listener: (context, state) => dataDelegate.didUpdateTypeOptionData(state.typeOption.writeToBuffer()),
|
||||
builder: (context, state) {
|
||||
return FlowyButton(
|
||||
text: FlowyText.medium(LocaleKeys.grid_field_numberFormat.tr(), fontSize: 12),
|
||||
@ -53,7 +57,7 @@ class NumberTypeOptionWidget extends TypeOptionWidget {
|
||||
final list = NumberFormatList(onSelected: (format) {
|
||||
context.read<NumberTypeOptionBloc>().add(NumberTypeOptionEvent.didSelectFormat(format));
|
||||
});
|
||||
operationDelegate.requireToShowOverlay(context, list.identifier(), list);
|
||||
overlayDelegate.showOverlay(context, list);
|
||||
},
|
||||
rightIcon: svg("grid/more", color: theme.iconColor),
|
||||
);
|
||||
|
@ -1,5 +1,6 @@
|
||||
import 'package:app_flowy/workspace/application/grid/field/type_option/option_pannel_bloc.dart';
|
||||
import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart';
|
||||
import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_tyep_switcher.dart';
|
||||
import 'package:flowy_infra/image.dart';
|
||||
import 'package:flowy_infra/theme.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/button.dart';
|
||||
@ -11,18 +12,24 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:app_flowy/generated/locale_keys.g.dart';
|
||||
|
||||
import 'edit_option_pannel.dart';
|
||||
import 'widget.dart';
|
||||
|
||||
class OptionPannel extends StatelessWidget {
|
||||
final List<SelectOption> options;
|
||||
final VoidCallback beginEdit;
|
||||
final Function(String optionName) createOptionCallback;
|
||||
final Function(List<SelectOption>) updateOptionsCallback;
|
||||
final Function(SelectOption) updateOptionCallback;
|
||||
final Function(SelectOption) deleteOptionCallback;
|
||||
final TypeOptionOverlayDelegate overlayDelegate;
|
||||
|
||||
const OptionPannel({
|
||||
required this.options,
|
||||
required this.beginEdit,
|
||||
required this.createOptionCallback,
|
||||
required this.updateOptionsCallback,
|
||||
required this.updateOptionCallback,
|
||||
required this.deleteOptionCallback,
|
||||
required this.overlayDelegate,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@ -39,6 +46,16 @@ class OptionPannel extends StatelessWidget {
|
||||
() => null,
|
||||
(optionName) => createOptionCallback(optionName),
|
||||
);
|
||||
|
||||
state.updateOption.fold(
|
||||
() => null,
|
||||
(updateOption) => updateOptionCallback(updateOption),
|
||||
);
|
||||
|
||||
state.deleteOption.fold(
|
||||
() => null,
|
||||
(deleteOption) => deleteOptionCallback(deleteOption),
|
||||
);
|
||||
},
|
||||
builder: (context, state) {
|
||||
List<Widget> children = [
|
||||
@ -46,7 +63,7 @@ class OptionPannel extends StatelessWidget {
|
||||
const OptionTitle(),
|
||||
];
|
||||
if (state.isEditingOption) {
|
||||
children.add(const _AddOptionTextField());
|
||||
children.add(const _OptionNameTextField());
|
||||
}
|
||||
|
||||
if (state.options.isEmpty && !state.isEditingOption) {
|
||||
@ -54,7 +71,7 @@ class OptionPannel extends StatelessWidget {
|
||||
}
|
||||
|
||||
if (state.options.isNotEmpty) {
|
||||
children.add(_OptionList(key: ObjectKey(state.options)));
|
||||
children.add(_OptionList(overlayDelegate));
|
||||
}
|
||||
|
||||
return Column(children: children);
|
||||
@ -105,14 +122,18 @@ class OptionTitle extends StatelessWidget {
|
||||
}
|
||||
|
||||
class _OptionList extends StatelessWidget {
|
||||
const _OptionList({Key? key}) : super(key: key);
|
||||
final TypeOptionOverlayDelegate delegate;
|
||||
const _OptionList(this.delegate, {Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<OptionPannelBloc, OptionPannelState>(
|
||||
buildWhen: (previous, current) {
|
||||
return previous.options != current.options;
|
||||
},
|
||||
builder: (context, state) {
|
||||
final optionItems = state.options.map((option) {
|
||||
return _OptionItem(option: option);
|
||||
return _makeOptionItem(context, option);
|
||||
}).toList();
|
||||
|
||||
return ListView.separated(
|
||||
@ -129,11 +150,37 @@ class _OptionList extends StatelessWidget {
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
_OptionItem _makeOptionItem(BuildContext context, SelectOption option) {
|
||||
return _OptionItem(
|
||||
option: option,
|
||||
onEdited: (option) {
|
||||
final pannel = EditSelectOptionPannel(
|
||||
option: option,
|
||||
onDeleted: () {
|
||||
delegate.hideOverlay(context);
|
||||
context.read<OptionPannelBloc>().add(OptionPannelEvent.deleteOption(option));
|
||||
},
|
||||
onUpdated: (updatedOption) {
|
||||
delegate.hideOverlay(context);
|
||||
context.read<OptionPannelBloc>().add(OptionPannelEvent.updateOption(updatedOption));
|
||||
},
|
||||
key: ValueKey(option.id),
|
||||
);
|
||||
delegate.showOverlay(context, pannel);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _OptionItem extends StatelessWidget {
|
||||
final SelectOption option;
|
||||
const _OptionItem({required this.option, Key? key}) : super(key: key);
|
||||
final Function(SelectOption) onEdited;
|
||||
const _OptionItem({
|
||||
required this.option,
|
||||
required this.onEdited,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -143,7 +190,7 @@ class _OptionItem extends StatelessWidget {
|
||||
child: FlowyButton(
|
||||
text: FlowyText.medium(option.name, fontSize: 12),
|
||||
hoverColor: theme.hover,
|
||||
onTap: () {},
|
||||
onTap: () => onEdited(option),
|
||||
rightIcon: svg("grid/details", color: theme.iconColor),
|
||||
),
|
||||
);
|
||||
@ -170,8 +217,8 @@ class _AddOptionButton extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
class _AddOptionTextField extends StatelessWidget {
|
||||
const _AddOptionTextField({Key? key}) : super(key: key);
|
||||
class _OptionNameTextField extends StatelessWidget {
|
||||
const _OptionNameTextField({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -12,11 +12,13 @@ class SingleSelectTypeOptionBuilder extends TypeOptionBuilder {
|
||||
SingleSelectTypeOptionBuilder(
|
||||
String fieldId,
|
||||
TypeOptionData typeOptionData,
|
||||
TypeOptionOperationDelegate delegate,
|
||||
TypeOptionOverlayDelegate overlayDelegate,
|
||||
TypeOptionDataDelegate dataDelegate,
|
||||
) : _widget = SingleSelectTypeOptionWidget(
|
||||
fieldId,
|
||||
SingleSelectTypeOption.fromBuffer(typeOptionData),
|
||||
delegate,
|
||||
fieldId: fieldId,
|
||||
typeOption: SingleSelectTypeOption.fromBuffer(typeOptionData),
|
||||
dataDelegate: dataDelegate,
|
||||
overlayDelegate: overlayDelegate,
|
||||
);
|
||||
|
||||
@override
|
||||
@ -26,27 +28,41 @@ class SingleSelectTypeOptionBuilder extends TypeOptionBuilder {
|
||||
class SingleSelectTypeOptionWidget extends TypeOptionWidget {
|
||||
final String fieldId;
|
||||
final SingleSelectTypeOption typeOption;
|
||||
final TypeOptionOperationDelegate delegate;
|
||||
const SingleSelectTypeOptionWidget(this.fieldId, this.typeOption, this.delegate, {Key? key}) : super(key: key);
|
||||
final TypeOptionOverlayDelegate overlayDelegate;
|
||||
final TypeOptionDataDelegate dataDelegate;
|
||||
const SingleSelectTypeOptionWidget({
|
||||
required this.fieldId,
|
||||
required this.typeOption,
|
||||
required this.dataDelegate,
|
||||
required this.overlayDelegate,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (context) => getIt<SingleSelectTypeOptionBloc>(param1: typeOption, param2: fieldId),
|
||||
child: BlocConsumer<SingleSelectTypeOptionBloc, SingleSelectTypeOptionState>(
|
||||
listener: (context, state) => delegate.didUpdateTypeOptionData(state.typeOption.writeToBuffer()),
|
||||
listener: (context, state) {
|
||||
dataDelegate.didUpdateTypeOptionData(state.typeOption.writeToBuffer());
|
||||
},
|
||||
builder: (context, state) {
|
||||
return OptionPannel(
|
||||
options: state.typeOption.options,
|
||||
beginEdit: () {
|
||||
delegate.hideOverlay(context);
|
||||
overlayDelegate.hideOverlay(context);
|
||||
},
|
||||
createOptionCallback: (name) {
|
||||
context.read<SingleSelectTypeOptionBloc>().add(SingleSelectTypeOptionEvent.createOption(name));
|
||||
},
|
||||
updateOptionsCallback: (options) {
|
||||
context.read<SingleSelectTypeOptionBloc>().add(SingleSelectTypeOptionEvent.updateOptions(options));
|
||||
updateOptionCallback: (updateOption) {
|
||||
context.read<SingleSelectTypeOptionBloc>().add(SingleSelectTypeOptionEvent.updateOption(updateOption));
|
||||
},
|
||||
deleteOptionCallback: (deleteOption) {
|
||||
context.read<SingleSelectTypeOptionBloc>().add(SingleSelectTypeOptionEvent.deleteOption(deleteOption));
|
||||
},
|
||||
overlayDelegate: overlayDelegate,
|
||||
key: ValueKey(state.typeOption.hashCode),
|
||||
);
|
||||
},
|
||||
),
|
||||
|
Loading…
Reference in New Issue
Block a user