chore: adjust board card UI (#3954)

* chore: adjust board card UI

* chore: fix accessory popover and add title placeholder

* chore: add pubspec.lock

* chore: fix integration test

* chore: apply suggestions from code review

Co-authored-by: Mathias Mogensen <42929161+Xazin@users.noreply.github.com>

* chore: apply suggestions from Mathias

---------

Co-authored-by: Mathias Mogensen <42929161+Xazin@users.noreply.github.com>
This commit is contained in:
Richard Shiue 2023-11-24 00:25:12 +08:00 committed by GitHub
parent bddaac05ae
commit e18e031710
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 294 additions and 279 deletions

View File

@ -1,5 +1,6 @@
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/plugins/database_view/board/presentation/widgets/board_column_header.dart';
import 'package:appflowy/plugins/database_view/widgets/card/container/card_container.dart';
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
import 'package:appflowy_board/appflowy_board.dart';
import 'package:flowy_infra_ui/style_widget/text.dart';
@ -15,8 +16,8 @@ const defaultLastCardName = 'Card 3';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('board add row test', () {
testWidgets('Add card from header', (tester) async {
group('board add row test:', () {
testWidgets('from header', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
@ -45,7 +46,7 @@ void main() {
const newCardName = 'Card 4';
await tester.enterText(
find.descendant(
of: find.byType(IntrinsicHeight),
of: find.byType(RowCardContainer),
matching: find.byType(TextField),
),
newCardName,
@ -59,7 +60,7 @@ void main() {
expect(firstCardText.text, newCardName);
});
testWidgets('Add card from footer', (tester) async {
testWidgets('from footer', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
@ -87,7 +88,7 @@ void main() {
const newCardName = 'Card 4';
await tester.enterText(
find.descendant(
of: find.byType(IntrinsicHeight),
of: find.byType(RowCardContainer),
matching: find.byType(TextField),
),
newCardName,

View File

@ -17,6 +17,7 @@ import 'package:appflowy_backend/protobuf/flowy-database2/row_entities.pb.dart';
import 'package:appflowy_board/appflowy_board.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/style_widget/hover.dart';
import 'package:flowy_infra_ui/widget/error_page.dart';
import 'package:flowy_infra_ui/widget/flowy_tooltip.dart';
import 'package:flutter/material.dart' hide Card;
@ -159,10 +160,12 @@ class _BoardContentState extends State<BoardContent> {
boardScrollController: scrollManager,
scrollController: scrollController,
controller: context.read<BoardBloc>().boardController,
groupConstraints: const BoxConstraints.tightFor(width: 300),
groupConstraints: const BoxConstraints.tightFor(width: 256),
config: const AppFlowyBoardConfig(
groupPadding: EdgeInsets.symmetric(horizontal: 4),
groupItemPadding: EdgeInsets.symmetric(horizontal: 4),
footerPadding: EdgeInsets.fromLTRB(4, 14, 4, 4),
stretchGroupHeight: false,
),
leading: HiddenGroupsColumn(margin: config.headerPadding),
trailing: showCreateGroupButton
@ -200,20 +203,15 @@ class _BoardContentState extends State<BoardContent> {
Widget _buildFooter(BuildContext context, AppFlowyGroupData columnData) {
return AppFlowyGroupFooter(
height: 50,
height: 36,
margin: config.footerPadding,
icon: SizedBox(
height: 20,
width: 20,
child: FlowySvg(
FlowySvgs.add_s,
color: Theme.of(context).hintColor,
),
icon: FlowySvg(
FlowySvgs.add_s,
color: Theme.of(context).hintColor,
),
title: FlowyText.medium(
LocaleKeys.board_column_createNewCard.tr(),
color: Theme.of(context).hintColor,
fontSize: 14,
),
onAddButtonClick: () => context
.read<BoardBloc>()
@ -266,6 +264,14 @@ class _BoardContentState extends State<BoardContent> {
rowMeta: rowMeta,
rowCache: rowCache,
),
styleConfiguration: RowCardStyleConfiguration(
hoverStyle: HoverStyle(
hoverColor: Theme.of(context).brightness == Brightness.light
? const Color(0x0F1F2329)
: const Color(0x0FEFF4FB),
foregroundColorOnHover: Theme.of(context).colorScheme.onBackground,
),
),
onStartEditing: () => boardBloc
.add(BoardEvent.startEditingRow(groupData.group, groupItem.row)),
onEndEditing: () =>
@ -280,8 +286,10 @@ class _BoardContentState extends State<BoardContent> {
borderRadius: const BorderRadius.all(Radius.circular(6)),
border: Border.fromBorderSide(
BorderSide(
color: Theme.of(context).dividerColor,
width: 1.4,
color: Theme.of(context).brightness == Brightness.light
? const Color(0xFF1F2329).withOpacity(0.12)
: const Color(0xFF59647A),
width: 1.0,
),
),
boxShadow: [

View File

@ -3,7 +3,6 @@ import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/database_view/board/application/board_bloc.dart';
import 'package:appflowy/plugins/database_view/grid/presentation/layout/sizes.dart';
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/header/field_type_extension.dart';
import 'package:appflowy/plugins/database_view/widgets/card/define.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pbenum.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/group.pb.dart';
import 'package:appflowy_board/appflowy_board.dart';
@ -158,10 +157,8 @@ class _BoardColumnHeaderState extends State<BoardColumnHeader> {
filled: true,
fillColor: Theme.of(context).colorScheme.surface,
hoverColor: Colors.transparent,
contentPadding: EdgeInsets.symmetric(
vertical: CardSizes.cardCellVPadding + 4,
horizontal: 8,
),
contentPadding:
const EdgeInsets.symmetric(vertical: 12, horizontal: 8),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).colorScheme.primary,

View File

@ -73,9 +73,9 @@ class RowCard<CustomCardData> extends StatefulWidget {
}
class _RowCardState<T> extends State<RowCard<T>> {
final popoverController = PopoverController();
late final CardBloc _cardBloc;
late final EditableRowNotifier rowNotifier;
late final PopoverController popoverController;
AccessoryType? accessoryType;
@override
@ -100,8 +100,6 @@ class _RowCardState<T> extends State<RowCard<T>> {
widget.onEndEditing();
}
});
popoverController = PopoverController();
}
@override
@ -111,26 +109,21 @@ class _RowCardState<T> extends State<RowCard<T>> {
child: BlocBuilder<CardBloc, RowCardState>(
buildWhen: (previous, current) {
// Rebuild when:
// 1.If the length of the cells is not the same
// 2.isEditing changed
// 1. If the length of the cells is not the same or isEditing changed
if (previous.cells.length != current.cells.length ||
previous.isEditing != current.isEditing) {
return true;
}
// 3.Compare the content of the cells. The cells consists of
// list of [BoardCellEquatable] that extends the [Equatable].
// 2. the content of the cells changed
return !listEquals(previous.cells, current.cells);
},
builder: (context, state) {
// mobile
if (PlatformExtension.isMobile) {
// TODO(yijing): refactor it in mobile to display card in database view
return RowCardContainer(
buildAccessoryWhen: () => state.isEditing == false,
accessoryBuilder: (context) {
return [];
},
accessories: const [],
openAccessory: (p0) {},
openCard: (context) => widget.openCard(context),
child: _CardContent<T>(
@ -143,29 +136,27 @@ class _RowCardState<T> extends State<RowCard<T>> {
),
);
}
// desktop
return AppFlowyPopover(
controller: popoverController,
triggerActions: PopoverTriggerFlags.none,
constraints: BoxConstraints.loose(const Size(140, 200)),
margin: const EdgeInsets.all(6),
direction: PopoverDirection.rightWithCenterAligned,
popupBuilder: (popoverContext) => _handlePopoverBuilder(
context,
popoverContext,
),
popupBuilder: (popoverContext) {
return RowActions(
viewId: _cardBloc.viewId,
rowId: _cardBloc.rowMeta.id,
groupId: widget.groupId,
);
},
child: RowCardContainer(
buildAccessoryWhen: () => state.isEditing == false,
accessoryBuilder: (context) {
if (widget.styleConfiguration.showAccessory == false) {
return [];
} else {
return [
_CardEditOption(rowNotifier: rowNotifier),
CardMoreOption(),
];
}
},
accessories: [
if (widget.styleConfiguration.showAccessory) ...[
_CardEditOption(rowNotifier: rowNotifier),
const CardMoreOption(),
],
],
openAccessory: _handleOpenAccessory,
openCard: (context) => widget.openCard(context),
child: _CardContent<T>(
@ -194,22 +185,6 @@ class _RowCardState<T> extends State<RowCard<T>> {
}
}
Widget _handlePopoverBuilder(
BuildContext context,
BuildContext popoverContext,
) {
switch (accessoryType!) {
case AccessoryType.edit:
throw UnimplementedError();
case AccessoryType.more:
return RowActions(
viewId: context.read<CardBloc>().viewId,
rowId: context.read<CardBloc>().rowMeta.id,
groupId: widget.groupId,
);
}
}
@override
Future<void> dispose() async {
rowNotifier.dispose();
@ -241,6 +216,7 @@ class _CardContent<CustomCardData> extends StatelessWidget {
if (styleConfiguration.hoverStyle != null) {
return FlowyHover(
style: styleConfiguration.hoverStyle,
buildWhenOnHover: () => !rowNotifier.isEditing.value,
child: Padding(
padding: styleConfiguration.cardPadding,
child: Column(
@ -296,21 +272,21 @@ class _CardContent<CustomCardData> extends StatelessWidget {
}
class CardMoreOption extends StatelessWidget with CardAccessory {
CardMoreOption({Key? key}) : super(key: key);
const CardMoreOption({super.key});
@override
AccessoryType get type => AccessoryType.more;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(3.0),
child: FlowySvg(
FlowySvgs.details_s,
color: Theme.of(context).iconTheme.color,
FlowySvgs.three_dots_s,
color: Theme.of(context).hintColor,
),
);
}
@override
AccessoryType get type => AccessoryType.more;
}
class _CardEditOption extends StatelessWidget with CardAccessory {
@ -326,7 +302,7 @@ class _CardEditOption extends StatelessWidget with CardAccessory {
padding: const EdgeInsets.all(3.0),
child: FlowySvg(
FlowySvgs.edit_s,
color: Theme.of(context).iconTheme.color,
color: Theme.of(context).hintColor,
),
);
}
@ -346,7 +322,7 @@ class RowCardStyleConfiguration {
const RowCardStyleConfiguration({
this.showAccessory = true,
this.cellPadding = const EdgeInsets.only(left: 4, right: 4),
this.cellPadding = EdgeInsets.zero,
this.cardPadding = const EdgeInsets.all(8),
this.hoverStyle,
});

View File

@ -5,6 +5,7 @@ import 'package:flowy_infra_ui/style_widget/icon_button.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../define.dart';
import 'card_cell.dart';
class CheckboxCardCell extends CardCell {
@ -24,11 +25,11 @@ class _CheckboxCellState extends State<CheckboxCardCell> {
@override
void initState() {
super.initState();
final cellController =
widget.cellControllerBuilder.build() as CheckboxCellController;
_cellBloc = CheckboxCellBloc(cellController: cellController);
_cellBloc.add(const CheckboxCellEvent.initial());
super.initState();
_cellBloc = CheckboxCellBloc(cellController: cellController)
..add(const CheckboxCellEvent.initial());
}
@override
@ -47,7 +48,7 @@ class _CheckboxCellState extends State<CheckboxCardCell> {
return Align(
alignment: Alignment.centerLeft,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 2),
padding: CardSizes.cardCellPadding,
child: FlowyIconButton(
iconPadding: EdgeInsets.zero,
icon: icon,

View File

@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../row/cells/checklist_cell/checklist_cell_bloc.dart';
import '../define.dart';
import 'card_cell.dart';
class ChecklistCardCell extends CardCell {
@ -37,7 +38,7 @@ class _ChecklistCellState extends State<ChecklistCardCell> {
return const SizedBox.shrink();
}
return Padding(
padding: const EdgeInsets.symmetric(vertical: 4),
padding: CardSizes.cardCellPadding,
child: ChecklistProgressBar(
tasks: state.tasks,
percent: state.percent,

View File

@ -42,31 +42,28 @@ class _DateCellState extends State<DateCardCell> {
buildWhen: (previous, current) => previous.dateStr != current.dateStr,
builder: (context, state) {
if (state.dateStr.isEmpty) {
return const SizedBox();
} else {
final Widget? custom = widget.renderHook?.call(
state.data,
widget.cardData,
context,
);
if (custom != null) {
return custom;
}
return Align(
alignment: Alignment.centerLeft,
child: Padding(
padding: EdgeInsets.symmetric(
vertical: CardSizes.cardCellVPadding,
),
child: FlowyText.regular(
state.dateStr,
fontSize: 13,
color: Theme.of(context).hintColor,
),
),
);
return const SizedBox.shrink();
}
final Widget? custom = widget.renderHook?.call(
state.data,
widget.cardData,
context,
);
if (custom != null) {
return custom;
}
return Align(
alignment: Alignment.centerLeft,
child: Padding(
padding: CardSizes.cardCellPadding,
child: FlowyText.regular(
state.dateStr,
fontSize: 11,
color: Theme.of(context).hintColor,
),
),
);
},
),
);

View File

@ -52,30 +52,28 @@ class _NumberCellState extends State<NumberCardCell> {
previous.cellContent != current.cellContent,
builder: (context, state) {
if (state.cellContent.isEmpty) {
return const SizedBox();
} else {
final Widget? custom = widget.renderHook?.call(
state.cellContent,
widget.cardData,
context,
);
if (custom != null) {
return custom;
}
return Align(
alignment: Alignment.centerLeft,
child: Padding(
padding: EdgeInsets.symmetric(
vertical: CardSizes.cardCellVPadding,
),
child: FlowyText.medium(
state.cellContent,
fontSize: widget.style?.fontSize ?? 14,
),
),
);
return const SizedBox.shrink();
}
final Widget? custom = widget.renderHook?.call(
state.cellContent,
widget.cardData,
context,
);
if (custom != null) {
return custom;
}
return Align(
alignment: Alignment.centerLeft,
child: Padding(
padding: CardSizes.cardCellPadding,
child: FlowyText.regular(
state.cellContent,
fontSize: widget.style?.fontSize ?? 11,
color: Theme.of(context).hintColor,
),
),
);
},
),
);

View File

@ -5,6 +5,7 @@ import 'package:appflowy_backend/protobuf/flowy-database2/select_option.pb.dart'
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../define.dart';
import 'card_cell.dart';
class SelectOptionCardCellStyle extends CardCellStyle {}
@ -69,12 +70,11 @@ class _SelectOptionCellState extends State<SelectOptionCardCell> {
)
.toList();
return IntrinsicHeight(
return Align(
alignment: AlignmentDirectional.topStart,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 6),
child: SizedBox.expand(
child: Wrap(spacing: 4, runSpacing: 2, children: children),
),
padding: CardSizes.cardCellPadding,
child: Wrap(spacing: 4, runSpacing: 2, children: children),
),
);
},

View File

@ -1,10 +1,13 @@
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
import 'package:appflowy/plugins/database_view/widgets/row/cells/text_cell/text_cell_bloc.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flowy_infra_ui/widget/spacing.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../row/cell_builder.dart';
import '../define.dart';
import 'card_cell.dart';
@ -120,24 +123,30 @@ class _TextCellState extends State<TextCardCell> {
return custom;
}
final isTitle =
context.read<TextCellBloc>().cellController.fieldInfo.isPrimary;
if (state.content.isEmpty &&
state.enableEdit == false &&
focusWhenInit == false) {
return const SizedBox();
focusWhenInit == false &&
!isTitle) {
return const SizedBox.shrink();
}
final child = state.enableEdit || focusWhenInit
? _buildTextField()
: _buildText(state);
: _buildText(state, isTitle);
return Row(
children: [
if (widget.showNotes) ...[
const FlowySvg(FlowySvgs.notes_s),
const HSpace(4),
return Padding(
padding: CardSizes.cardCellPadding,
child: Row(
children: [
if (widget.showNotes) ...[
const FlowySvg(FlowySvgs.notes_s),
const HSpace(4),
],
Expanded(child: child),
],
Expanded(child: child),
],
),
);
},
),
@ -157,47 +166,46 @@ class _TextCellState extends State<TextCardCell> {
super.dispose();
}
double _fontSize() {
if (widget.style != null) {
return widget.style!.fontSize;
}
return 14;
}
Widget _buildText(TextCellState state) {
return Padding(
padding: EdgeInsets.symmetric(
vertical: CardSizes.cardCellVPadding,
),
child: FlowyText.medium(
state.content,
fontSize: _fontSize(),
maxLines: null, // Enable multiple lines
),
Widget _buildText(TextCellState state, bool isTitle) {
final text = state.content.isEmpty
? LocaleKeys.grid_row_titlePlaceholder.tr()
: state.content;
final color = state.content.isEmpty ? Theme.of(context).hintColor : null;
return FlowyText(
text,
fontSize: _fontSize(isTitle),
fontWeight: _fontWeight(isTitle),
color: color,
maxLines: null, // Enable multiple lines
);
}
double _fontSize(bool isTitle) {
return widget.style?.fontSize ?? (isTitle ? 12 : 11);
}
FontWeight _fontWeight(bool isTitle) {
return isTitle ? FontWeight.w500 : FontWeight.w400;
}
Widget _buildTextField() {
return IntrinsicHeight(
child: TextField(
controller: _controller,
focusNode: focusNode,
onChanged: (value) => focusChanged(),
onEditingComplete: () => focusNode.unfocus(),
maxLines: null,
style: Theme.of(context)
.textTheme
.bodyMedium!
.copyWith(fontSize: _fontSize()),
decoration: InputDecoration(
// Magic number 4 makes the textField take up the same space as FlowyText
contentPadding: EdgeInsets.symmetric(
vertical: CardSizes.cardCellVPadding + 4,
),
border: InputBorder.none,
isDense: true,
),
return TextField(
controller: _controller,
focusNode: focusNode,
onChanged: (value) => focusChanged(),
onEditingComplete: () => focusNode.unfocus(),
maxLines: null,
style: Theme.of(context)
.textTheme
.bodyMedium!
.copyWith(fontSize: _fontSize(true)),
decoration: InputDecoration(
contentPadding:
EdgeInsets.symmetric(vertical: CardSizes.cardCellPadding.top),
border: InputBorder.none,
isDense: true,
isCollapsed: true,
hintText: LocaleKeys.grid_row_titlePlaceholder.tr(),
),
);
}

View File

@ -56,12 +56,10 @@ class _TimestampCellState extends State<TimestampCardCell> {
return Align(
alignment: Alignment.centerLeft,
child: Padding(
padding: EdgeInsets.symmetric(
vertical: CardSizes.cardCellVPadding,
),
padding: CardSizes.cardCellPadding,
child: FlowyText.regular(
state.dateStr,
fontSize: 13,
fontSize: 11,
color: Theme.of(context).hintColor,
),
),

View File

@ -1,6 +1,5 @@
import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
import 'package:appflowy/plugins/database_view/widgets/row/cells/url_cell/url_cell_bloc.dart';
import 'package:flowy_infra/size.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@ -48,27 +47,24 @@ class _URLCellState extends State<URLCardCell> {
builder: (context, state) {
if (state.content.isEmpty) {
return const SizedBox();
} else {
return Align(
alignment: Alignment.centerLeft,
child: Padding(
padding: EdgeInsets.symmetric(
vertical: CardSizes.cardCellVPadding,
),
child: RichText(
textAlign: TextAlign.left,
text: TextSpan(
text: state.content,
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
fontSize: widget.style?.fontSize ?? FontSizes.s14,
color: Theme.of(context).colorScheme.primary,
decoration: TextDecoration.underline,
),
),
}
return Align(
alignment: Alignment.centerLeft,
child: Padding(
padding: CardSizes.cardCellPadding,
child: RichText(
textAlign: TextAlign.left,
text: TextSpan(
text: state.content,
style: Theme.of(context).textTheme.bodySmall!.copyWith(
fontSize: widget.style?.fontSize ?? 11,
color: Theme.of(context).colorScheme.primary,
decoration: TextDecoration.underline,
),
),
),
);
}
),
);
},
),
);

View File

@ -26,7 +26,7 @@ class CardAccessoryContainer extends StatelessWidget {
@override
Widget build(BuildContext context) {
final children = accessories.map((accessory) {
final children = accessories.map<Widget>((accessory) {
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
@ -36,32 +36,62 @@ class CardAccessoryContainer extends StatelessWidget {
child: _wrapHover(context, accessory),
);
}).toList();
return _wrapDecoration(context, Row(children: children));
children.insert(
1,
VerticalDivider(
width: 1,
thickness: 1,
color: Theme.of(context).brightness == Brightness.light
? const Color(0xFF1F2329).withOpacity(0.12)
: const Color(0xff59647a),
),
);
return _wrapDecoration(
context,
IntrinsicHeight(child: Row(children: children)),
);
}
FlowyHover _wrapHover(BuildContext context, CardAccessory accessory) {
return FlowyHover(
style: HoverStyle(
backgroundColor: Theme.of(context).colorScheme.surface,
borderRadius: BorderRadius.zero,
),
builder: (_, onHover) => SizedBox(
width: 24,
height: 24,
Widget _wrapHover(BuildContext context, CardAccessory accessory) {
return SizedBox(
width: 24,
height: 22,
child: FlowyHover(
style: HoverStyle(
backgroundColor: Theme.of(context).colorScheme.surface,
borderRadius: BorderRadius.zero,
),
child: accessory,
),
);
}
Widget _wrapDecoration(BuildContext context, Widget child) {
final borderSide = BorderSide(
color: Theme.of(context).dividerColor,
width: 1.0,
);
final decoration = BoxDecoration(
color: Colors.transparent,
border: Border.fromBorderSide(borderSide),
color: Theme.of(context).colorScheme.surface,
borderRadius: const BorderRadius.all(Radius.circular(4)),
border: Border.fromBorderSide(
BorderSide(
color: Theme.of(context).brightness == Brightness.light
? const Color(0xFF1F2329).withOpacity(0.12)
: const Color(0xff59647a),
width: 1.0,
),
),
boxShadow: [
BoxShadow(
blurRadius: 4,
spreadRadius: 0,
color: const Color(0xFF1F2329).withOpacity(0.02),
),
BoxShadow(
blurRadius: 4,
spreadRadius: -2,
color: const Color(0xFF1F2329).withOpacity(0.02),
),
],
);
return Container(
clipBehavior: Clip.hardEdge,

View File

@ -5,7 +5,7 @@ import 'accessory.dart';
class RowCardContainer extends StatelessWidget {
final Widget child;
final CardAccessoryBuilder? accessoryBuilder;
final List<CardAccessory> accessories;
final bool Function()? buildAccessoryWhen;
final void Function(BuildContext) openCard;
final void Function(AccessoryType) openAccessory;
@ -13,7 +13,7 @@ class RowCardContainer extends StatelessWidget {
required this.child,
required this.openCard,
required this.openAccessory,
this.accessoryBuilder,
required this.accessories,
this.buildAccessoryWhen,
Key? key,
}) : super(key: key);
@ -30,15 +30,12 @@ class RowCardContainer extends StatelessWidget {
shouldBuildAccessory = buildAccessoryWhen!.call();
}
if (accessoryBuilder != null && shouldBuildAccessory) {
final accessories = accessoryBuilder!(context);
if (accessories.isNotEmpty) {
container = _CardEnterRegion(
accessories: accessories,
onTapAccessory: openAccessory,
child: container,
);
}
if (shouldBuildAccessory && accessories.isNotEmpty) {
container = _CardEnterRegion(
accessories: accessories,
onTapAccessory: openAccessory,
child: container,
);
}
return GestureDetector(
@ -75,8 +72,8 @@ class _CardEnterRegion extends StatelessWidget {
if (onEnter) {
children.add(
Positioned(
top: 8.0,
right: 8.0,
top: 10.0,
right: 10.0,
child: CardAccessoryContainer(
accessories: accessories,
onTapAccessory: onTapAccessory,

View File

@ -1,3 +1,5 @@
import 'package:flutter/widgets.dart';
class CardSizes {
static double get cardCellVPadding => 6;
static EdgeInsets get cardCellPadding => const EdgeInsets.all(4);
}

View File

@ -113,7 +113,7 @@ class GridChecklistCellState extends GridCellState<GridChecklistCell> {
: LocaleKeys.grid_checklist_hideComplete.tr(),
width: 32,
iconColorOnHover:
Theme.of(context).colorScheme.onPrimary,
Theme.of(context).colorScheme.onSurface,
icon: FlowySvg(
showIncompleteOnly
? FlowySvgs.show_m

View File

@ -106,7 +106,7 @@ class SelectOptionTag extends StatelessWidget {
mainAxisSize: MainAxisSize.min,
children: [
Flexible(
child: FlowyText.medium(
child: FlowyText.regular(
name,
fontSize: FontSizes.s11,
overflow: TextOverflow.ellipsis,
@ -135,11 +135,11 @@ class SelectOptionTagCell extends StatelessWidget {
final void Function(SelectOptionPB) onSelected;
final SelectOptionPB option;
const SelectOptionTagCell({
super.key,
required this.option,
required this.onSelected,
this.children = const [],
Key? key,
}) : super(key: key);
});
@override
Widget build(BuildContext context) {

View File

@ -17,5 +17,6 @@ export 'style_widget/button.dart';
export 'style_widget/icon_button.dart';
export 'style_widget/scrolling/styled_scroll_bar.dart';
export '/widget/spacing.dart';
export '/widget/separated_flex.dart';
export 'style_widget/scrolling/styled_list.dart';
export 'style_widget/color_picker.dart';

View File

@ -0,0 +1,47 @@
import 'package:flutter/material.dart';
typedef SeparatorBuilder = Widget Function();
class SeparatedColumn extends Column {
SeparatedColumn({
super.key,
super.mainAxisAlignment,
super.crossAxisAlignment,
super.mainAxisSize,
super.textBaseline,
super.textDirection,
super.verticalDirection,
required SeparatorBuilder separatorBuilder,
required List<Widget> children,
}) : super(children: _insertSeparators(children, separatorBuilder));
}
class SeparatedRow extends Row {
SeparatedRow({
super.key,
super.mainAxisAlignment,
super.crossAxisAlignment,
super.mainAxisSize,
super.textBaseline,
super.textDirection,
super.verticalDirection,
required SeparatorBuilder separatorBuilder,
required List<Widget> children,
}) : super(children: _insertSeparators(children, separatorBuilder));
}
List<Widget> _insertSeparators(
List<Widget> children,
SeparatorBuilder separatorBuilder,
) {
if (children.length < 2) {
return children;
}
List<Widget> newChildren = [];
for (int i = 0; i < children.length - 1; i++) {
newChildren.add(children[i]);
newChildren.add(separatorBuilder());
}
return newChildren..add(children.last);
}

View File

@ -1,43 +0,0 @@
import 'package:flutter/material.dart';
typedef SeparatorBuilder = Widget Function();
class SeparatedColumn extends StatelessWidget {
final List<Widget> children;
final SeparatorBuilder? separatorBuilder;
final MainAxisAlignment mainAxisAlignment;
final CrossAxisAlignment crossAxisAlignment;
final MainAxisSize mainAxisSize;
final TextBaseline? textBaseline;
final TextDirection? textDirection;
final VerticalDirection verticalDirection;
const SeparatedColumn({
Key? key,
required this.children,
this.separatorBuilder,
this.mainAxisAlignment = MainAxisAlignment.start,
this.crossAxisAlignment = CrossAxisAlignment.center,
this.mainAxisSize = MainAxisSize.max,
this.verticalDirection = VerticalDirection.down,
this.textBaseline,
this.textDirection,
}) : super(key: key);
@override
Widget build(BuildContext context) {
var c = children.toList();
for (var i = c.length; i-- > 0;) {
if (i > 0 && separatorBuilder != null) c.insert(i, separatorBuilder!());
}
return Column(
mainAxisAlignment: mainAxisAlignment,
crossAxisAlignment: crossAxisAlignment,
mainAxisSize: mainAxisSize,
textBaseline: textBaseline,
textDirection: textDirection,
verticalDirection: verticalDirection,
children: c,
);
}
}