mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
chore: select option cell & header editor UI + move to theme.of(context).texttheme (#1483)
* chore: improvements for suffix text in textfields * chore: port more const textstyles to theme provider styles * chore: select option editor UI improvements
This commit is contained in:
parent
f02e77fcd8
commit
3b3b61e67c
@ -1,4 +1,5 @@
|
|||||||
import 'package:flowy_infra/color_extension.dart';
|
import 'package:flowy_infra/color_extension.dart';
|
||||||
|
import 'package:flowy_infra/size.dart';
|
||||||
import 'package:flowy_infra_ui/style_widget/hover.dart';
|
import 'package:flowy_infra_ui/style_widget/hover.dart';
|
||||||
import 'package:flowy_infra_ui/style_widget/text.dart';
|
import 'package:flowy_infra_ui/style_widget/text.dart';
|
||||||
import 'package:flowy_sdk/protobuf/flowy-grid/select_type_option.pb.dart';
|
import 'package:flowy_sdk/protobuf/flowy-grid/select_type_option.pb.dart';
|
||||||
@ -87,17 +88,13 @@ class SelectOptionTag extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ChoiceChip(
|
return Container(
|
||||||
pressElevation: 1,
|
padding: const EdgeInsets.symmetric(vertical: 2.0, horizontal: 8.0),
|
||||||
label: FlowyText.medium(
|
decoration: BoxDecoration(
|
||||||
name,
|
color: color,
|
||||||
overflow: TextOverflow.clip,
|
borderRadius: Corners.s6Border,
|
||||||
),
|
),
|
||||||
selectedColor: color,
|
child: FlowyText.medium(name, overflow: TextOverflow.ellipsis),
|
||||||
backgroundColor: color,
|
|
||||||
labelPadding: const EdgeInsets.symmetric(horizontal: 6),
|
|
||||||
selected: true,
|
|
||||||
onSelected: (_) => onSelected?.call(),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -115,30 +112,29 @@ class SelectOptionTagCell extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Stack(
|
return FlowyHover(
|
||||||
fit: StackFit.expand,
|
child: InkWell(
|
||||||
children: [
|
child: Row(
|
||||||
FlowyHover(
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
child: InkWell(
|
children: [
|
||||||
child: Padding(
|
Expanded(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 3),
|
child: Align(
|
||||||
child: Row(
|
alignment: Alignment.centerLeft,
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
child: Padding(
|
||||||
children: [
|
padding: const EdgeInsets.all(5.0),
|
||||||
SelectOptionTag.fromOption(
|
child: SelectOptionTag.fromOption(
|
||||||
context: context,
|
context: context,
|
||||||
option: option,
|
option: option,
|
||||||
onSelected: () => onSelected(option),
|
onSelected: () => onSelected(option),
|
||||||
),
|
),
|
||||||
const Spacer(),
|
),
|
||||||
...children,
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
onTap: () => onSelected(option),
|
...children,
|
||||||
),
|
],
|
||||||
),
|
),
|
||||||
],
|
onTap: () => onSelected(option),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -223,7 +223,7 @@ class _SelectOptionWrapState extends State<SelectOptionWrap> {
|
|||||||
).toList();
|
).toList();
|
||||||
|
|
||||||
child = Wrap(
|
child = Wrap(
|
||||||
runSpacing: 2,
|
runSpacing: 4,
|
||||||
children: children,
|
children: children,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -53,21 +53,24 @@ class _SelectOptionCellEditorState extends State<SelectOptionCellEditor> {
|
|||||||
)..add(const SelectOptionEditorEvent.initial()),
|
)..add(const SelectOptionEditorEvent.initial()),
|
||||||
child: BlocBuilder<SelectOptionCellEditorBloc, SelectOptionEditorState>(
|
child: BlocBuilder<SelectOptionCellEditorBloc, SelectOptionEditorState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
|
final List<Widget> children = [
|
||||||
|
_TextField(popoverMutex: popoverMutex),
|
||||||
|
const TypeOptionSeparator(),
|
||||||
|
const _Title(),
|
||||||
|
_OptionList(popoverMutex: popoverMutex),
|
||||||
|
];
|
||||||
|
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.all(6.0),
|
padding: const EdgeInsets.all(6.0),
|
||||||
child: CustomScrollView(
|
child: ListView.separated(
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
slivers: [
|
itemCount: children.length,
|
||||||
SliverToBoxAdapter(
|
itemBuilder: (BuildContext context, int index) {
|
||||||
child: _TextField(popoverMutex: popoverMutex),
|
return children[index];
|
||||||
),
|
},
|
||||||
const SliverToBoxAdapter(child: TypeOptionSeparator()),
|
separatorBuilder: (BuildContext context, int index) {
|
||||||
const SliverToBoxAdapter(child: VSpace(6)),
|
return VSpace(GridSize.typeOptionSeparatorHeight);
|
||||||
const SliverToBoxAdapter(child: _Title()),
|
},
|
||||||
SliverToBoxAdapter(
|
|
||||||
child: _OptionList(popoverMutex: popoverMutex),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -143,35 +146,32 @@ class _TextField extends StatelessWidget {
|
|||||||
key: (option) => option.name,
|
key: (option) => option.name,
|
||||||
value: (option) => option);
|
value: (option) => option);
|
||||||
|
|
||||||
return SizedBox(
|
return SelectOptionTextField(
|
||||||
height: 52,
|
options: state.options,
|
||||||
child: SelectOptionTextField(
|
selectedOptionMap: optionMap,
|
||||||
options: state.options,
|
distanceToText: _editorPanelWidth * 0.7,
|
||||||
selectedOptionMap: optionMap,
|
maxLength: 30,
|
||||||
distanceToText: _editorPanelWidth * 0.7,
|
tagController: _tagController,
|
||||||
maxLength: 30,
|
textSeparators: const [','],
|
||||||
tagController: _tagController,
|
onClick: () => popoverMutex.close(),
|
||||||
textSeparators: const [','],
|
newText: (text) {
|
||||||
onClick: () => popoverMutex.close(),
|
context
|
||||||
newText: (text) {
|
.read<SelectOptionCellEditorBloc>()
|
||||||
context
|
.add(SelectOptionEditorEvent.filterOption(text));
|
||||||
.read<SelectOptionCellEditorBloc>()
|
},
|
||||||
.add(SelectOptionEditorEvent.filterOption(text));
|
onSubmitted: (tagName) {
|
||||||
},
|
context
|
||||||
onSubmitted: (tagName) {
|
.read<SelectOptionCellEditorBloc>()
|
||||||
context
|
.add(SelectOptionEditorEvent.trySelectOption(tagName));
|
||||||
.read<SelectOptionCellEditorBloc>()
|
},
|
||||||
.add(SelectOptionEditorEvent.trySelectOption(tagName));
|
onPaste: (tagNames, remainder) {
|
||||||
},
|
context
|
||||||
onPaste: (tagNames, remainder) {
|
.read<SelectOptionCellEditorBloc>()
|
||||||
context
|
.add(SelectOptionEditorEvent.selectMultipleOptions(
|
||||||
.read<SelectOptionCellEditorBloc>()
|
tagNames,
|
||||||
.add(SelectOptionEditorEvent.selectMultipleOptions(
|
remainder,
|
||||||
tagNames,
|
));
|
||||||
remainder,
|
},
|
||||||
));
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -209,12 +209,17 @@ class _CreateOptionCell extends StatelessWidget {
|
|||||||
color: Theme.of(context).hintColor,
|
color: Theme.of(context).hintColor,
|
||||||
),
|
),
|
||||||
const HSpace(10),
|
const HSpace(10),
|
||||||
SelectOptionTag(
|
Expanded(
|
||||||
name: name,
|
child: Align(
|
||||||
color: AFThemeExtension.of(context).lightGreyHover,
|
alignment: Alignment.centerLeft,
|
||||||
onSelected: () => context
|
child: SelectOptionTag(
|
||||||
.read<SelectOptionCellEditorBloc>()
|
name: name,
|
||||||
.add(SelectOptionEditorEvent.newOption(name)),
|
color: AFThemeExtension.of(context).lightGreyHover,
|
||||||
|
onSelected: () => context
|
||||||
|
.read<SelectOptionCellEditorBloc>()
|
||||||
|
.add(SelectOptionEditorEvent.newOption(name)),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
@ -271,14 +276,13 @@ class _SelectOptionCellState extends State<_SelectOptionCell> {
|
|||||||
children: [
|
children: [
|
||||||
if (widget.isSelected)
|
if (widget.isSelected)
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(right: 6),
|
padding: const EdgeInsets.only(left: 6),
|
||||||
child: svgWidget("grid/checkmark"),
|
child: svgWidget("grid/checkmark"),
|
||||||
),
|
),
|
||||||
FlowyIconButton(
|
FlowyIconButton(
|
||||||
width: 30,
|
|
||||||
onPressed: () => _popoverController.show(),
|
onPressed: () => _popoverController.show(),
|
||||||
hoverColor: Colors.transparent,
|
hoverColor: Colors.transparent,
|
||||||
iconPadding: const EdgeInsets.fromLTRB(4, 4, 4, 4),
|
iconPadding: const EdgeInsets.symmetric(horizontal: 6.0),
|
||||||
icon: svgWidget(
|
icon: svgWidget(
|
||||||
"editor/details",
|
"editor/details",
|
||||||
color: Theme.of(context).colorScheme.onSurface,
|
color: Theme.of(context).colorScheme.onSurface,
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import 'dart:collection';
|
import 'dart:collection';
|
||||||
|
|
||||||
import 'package:flowy_infra/size.dart';
|
import 'package:flowy_infra/size.dart';
|
||||||
import 'package:flowy_infra/text_style.dart';
|
|
||||||
import 'package:flowy_sdk/protobuf/flowy-grid/select_type_option.pb.dart';
|
import 'package:flowy_sdk/protobuf/flowy-grid/select_type_option.pb.dart';
|
||||||
import 'package:flutter/gestures.dart';
|
import 'package:flutter/gestures.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@ -49,7 +48,6 @@ class SelectOptionTextField extends StatefulWidget {
|
|||||||
class _SelectOptionTextFieldState extends State<SelectOptionTextField> {
|
class _SelectOptionTextFieldState extends State<SelectOptionTextField> {
|
||||||
late FocusNode focusNode;
|
late FocusNode focusNode;
|
||||||
late TextEditingController controller;
|
late TextEditingController controller;
|
||||||
var textLength = 0;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@ -64,7 +62,7 @@ class _SelectOptionTextFieldState extends State<SelectOptionTextField> {
|
|||||||
|
|
||||||
String? _suffixText() {
|
String? _suffixText() {
|
||||||
if (widget.maxLength != null) {
|
if (widget.maxLength != null) {
|
||||||
return '${textLength.toString()}/${widget.maxLength.toString()}';
|
return ' ${controller.text.length}/${widget.maxLength}';
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -92,7 +90,6 @@ class _SelectOptionTextFieldState extends State<SelectOptionTextField> {
|
|||||||
focusNode: focusNode,
|
focusNode: focusNode,
|
||||||
onTap: widget.onClick,
|
onTap: widget.onClick,
|
||||||
onChanged: (text) {
|
onChanged: (text) {
|
||||||
textLength = text.length;
|
|
||||||
if (onChanged != null) {
|
if (onChanged != null) {
|
||||||
onChanged(text);
|
onChanged(text);
|
||||||
}
|
}
|
||||||
@ -112,11 +109,11 @@ class _SelectOptionTextFieldState extends State<SelectOptionTextField> {
|
|||||||
maxLength: widget.maxLength,
|
maxLength: widget.maxLength,
|
||||||
maxLengthEnforcement:
|
maxLengthEnforcement:
|
||||||
MaxLengthEnforcement.truncateAfterCompositionEnds,
|
MaxLengthEnforcement.truncateAfterCompositionEnds,
|
||||||
style: TextStyles.body1.size(FontSizes.s14),
|
style: Theme.of(context).textTheme.bodyMedium,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
enabledBorder: OutlineInputBorder(
|
enabledBorder: OutlineInputBorder(
|
||||||
borderSide: BorderSide(
|
borderSide: BorderSide(
|
||||||
color: Theme.of(context).colorScheme.primary,
|
color: Theme.of(context).colorScheme.outline,
|
||||||
width: 1.0,
|
width: 1.0,
|
||||||
),
|
),
|
||||||
borderRadius: Corners.s10Border,
|
borderRadius: Corners.s10Border,
|
||||||
@ -124,6 +121,10 @@ class _SelectOptionTextFieldState extends State<SelectOptionTextField> {
|
|||||||
isDense: true,
|
isDense: true,
|
||||||
prefixIcon: _renderTags(context, sc),
|
prefixIcon: _renderTags(context, sc),
|
||||||
hintText: LocaleKeys.grid_selectOption_searchOption.tr(),
|
hintText: LocaleKeys.grid_selectOption_searchOption.tr(),
|
||||||
|
hintStyle: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.bodySmall!
|
||||||
|
.textColor(Theme.of(context).hintColor),
|
||||||
suffixText: _suffixText(),
|
suffixText: _suffixText(),
|
||||||
counterText: "",
|
counterText: "",
|
||||||
prefixIconConstraints:
|
prefixIconConstraints:
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
import 'package:flowy_infra/text_style.dart';
|
|
||||||
import 'package:flowy_infra_ui/widget/rounded_input_field.dart';
|
import 'package:flowy_infra_ui/widget/rounded_input_field.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/scheduler.dart';
|
import 'package:flutter/scheduler.dart';
|
||||||
import 'package:textstyle_extensions/textstyle_extensions.dart';
|
|
||||||
|
|
||||||
class InputTextField extends StatefulWidget {
|
class InputTextField extends StatefulWidget {
|
||||||
final void Function(String)? onDone;
|
final void Function(String)? onDone;
|
||||||
@ -47,15 +45,13 @@ class _InputTextFieldState extends State<InputTextField> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final height = widget.maxLength == null ? 36.0 : 56.0;
|
|
||||||
|
|
||||||
return RoundedInputField(
|
return RoundedInputField(
|
||||||
controller: _controller,
|
controller: _controller,
|
||||||
focusNode: _focusNode,
|
focusNode: _focusNode,
|
||||||
autoFocus: true,
|
autoFocus: true,
|
||||||
height: height,
|
height: 36.0,
|
||||||
maxLength: widget.maxLength,
|
maxLength: widget.maxLength,
|
||||||
style: TextStyles.body1.size(13),
|
style: Theme.of(context).textTheme.bodyMedium,
|
||||||
onChanged: (text) {
|
onChanged: (text) {
|
||||||
if (widget.onChanged != null) {
|
if (widget.onChanged != null) {
|
||||||
widget.onChanged!(text);
|
widget.onChanged!(text);
|
||||||
|
@ -193,9 +193,12 @@ class _OptionCellState extends State<_OptionCell> {
|
|||||||
_popoverController.show();
|
_popoverController.show();
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
svgWidget(
|
Padding(
|
||||||
"grid/details",
|
padding: const EdgeInsets.symmetric(horizontal: 6.0),
|
||||||
color: Theme.of(context).colorScheme.onSurface,
|
child: svgWidget(
|
||||||
|
"grid/details",
|
||||||
|
color: Theme.of(context).colorScheme.onSurface,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -73,6 +73,14 @@ class _RoundedInputFieldState extends State<RoundedInputField> {
|
|||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String? _suffixText() {
|
||||||
|
if (widget.maxLength != null) {
|
||||||
|
return ' ${widget.controller!.text.length}/${widget.maxLength}';
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var borderColor =
|
var borderColor =
|
||||||
@ -117,8 +125,12 @@ class _RoundedInputFieldState extends State<RoundedInputField> {
|
|||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
contentPadding: widget.contentPadding,
|
contentPadding: widget.contentPadding,
|
||||||
hintText: widget.hintText,
|
hintText: widget.hintText,
|
||||||
hintStyle:
|
hintStyle: Theme.of(context)
|
||||||
Theme.of(context).textTheme.bodySmall!.textColor(borderColor),
|
.textTheme
|
||||||
|
.bodySmall!
|
||||||
|
.textColor(Theme.of(context).hintColor),
|
||||||
|
suffixText: _suffixText(),
|
||||||
|
counterText: "",
|
||||||
enabledBorder: OutlineInputBorder(
|
enabledBorder: OutlineInputBorder(
|
||||||
borderSide: BorderSide(
|
borderSide: BorderSide(
|
||||||
color: borderColor,
|
color: borderColor,
|
||||||
|
Loading…
Reference in New Issue
Block a user