chore: grid setting list

This commit is contained in:
appflowy 2022-04-03 10:53:24 +08:00
parent 147e948b35
commit 5d007c5359
50 changed files with 384 additions and 137 deletions

View File

@ -1,3 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11.2304 4.2561H10.0184L8.02638 7.9401H8.00238L5.99838 4.2561H4.78638L7.06638 8.2401H5.43438V8.9601H7.47438L7.48638 8.9841V9.8241H5.43438V10.5321H7.48638V12.5001H8.53038V10.5321H10.4984V9.8241H8.53038V8.9841L8.54238 8.9601H10.4984V8.2401H8.95038L11.2304 4.2561Z" fill="#333333"/>
</svg>

Before

Width:  |  Height:  |  Size: 392 B

View File

Before

Width:  |  Height:  |  Size: 238 B

After

Width:  |  Height:  |  Size: 238 B

View File

Before

Width:  |  Height:  |  Size: 281 B

After

Width:  |  Height:  |  Size: 281 B

View File

Before

Width:  |  Height:  |  Size: 512 B

After

Width:  |  Height:  |  Size: 512 B

View File

Before

Width:  |  Height:  |  Size: 499 B

After

Width:  |  Height:  |  Size: 499 B

View File

@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10.5221 3.21932C11.4366 2.6913 12.5634 2.6913 13.4779 3.21932L18.8653 6.32972C19.7799 6.85774 20.3433 7.83356 20.3433 8.88959V15.1104C20.3433 16.1664 19.7799 17.1423 18.8653 17.6703L13.4779 20.7807C12.5634 21.3087 11.4366 21.3087 10.5221 20.7807L5.13468 17.6703C4.22012 17.1423 3.65673 16.1664 3.65673 15.1104V8.88959C3.65673 7.83356 4.22012 6.85774 5.13467 6.32972L10.5221 3.21932Z" stroke="#333333" stroke-width="1.5"/>
<circle cx="12" cy="12" r="3.75" stroke="#333333" stroke-width="1.5"/>
</svg>

After

Width:  |  Height:  |  Size: 606 B

View File

@ -0,0 +1,4 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="2.5" y="3" width="4" height="10" rx="1" stroke="#333333"/>
<rect x="9.5" y="7" width="4" height="6" rx="1" stroke="#333333"/>
</svg>

After

Width:  |  Height:  |  Size: 238 B

View File

@ -143,6 +143,11 @@
} }
}, },
"grid": { "grid": {
"settings": {
"filter": "Filter",
"sortBy": "Sort by",
"Properties": "Properties"
},
"field": { "field": {
"hide": "Hide", "hide": "Hide",
"insertLeft": "Insert Left", "insertLeft": "Insert Left",

View File

@ -170,8 +170,8 @@ class PasswordTextField extends StatelessWidget {
return RoundedInputField( return RoundedInputField(
obscureText: true, obscureText: true,
style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500), style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
obscureIcon: svg("home/hide"), obscureIcon: svgWidget("home/hide"),
obscureHideIcon: svg("home/show"), obscureHideIcon: svgWidget("home/show"),
hintText: LocaleKeys.signIn_passwordHint.tr(), hintText: LocaleKeys.signIn_passwordHint.tr(),
normalBorderColor: theme.shader4, normalBorderColor: theme.shader4,
errorBorderColor: theme.red, errorBorderColor: theme.red,

View File

@ -134,8 +134,8 @@ class PasswordTextField extends StatelessWidget {
builder: (context, state) { builder: (context, state) {
return RoundedInputField( return RoundedInputField(
obscureText: true, obscureText: true,
obscureIcon: svg("home/hide"), obscureIcon: svgWidget("home/hide"),
obscureHideIcon: svg("home/show"), obscureHideIcon: svgWidget("home/show"),
style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500), style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
hintText: LocaleKeys.signUp_passwordHint.tr(), hintText: LocaleKeys.signUp_passwordHint.tr(),
normalBorderColor: theme.shader4, normalBorderColor: theme.shader4,
@ -162,8 +162,8 @@ class RepeatPasswordTextField extends StatelessWidget {
builder: (context, state) { builder: (context, state) {
return RoundedInputField( return RoundedInputField(
obscureText: true, obscureText: true,
obscureIcon: svg("home/hide"), obscureIcon: svgWidget("home/hide"),
obscureHideIcon: svg("home/show"), obscureHideIcon: svgWidget("home/show"),
style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500), style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
hintText: LocaleKeys.signUp_repeatPasswordHint.tr(), hintText: LocaleKeys.signUp_repeatPasswordHint.tr(),
normalBorderColor: theme.shader4, normalBorderColor: theme.shader4,

View File

@ -44,7 +44,7 @@ class FlowyLogoTitle extends StatelessWidget {
children: [ children: [
SizedBox.fromSize( SizedBox.fromSize(
size: logoSize, size: logoSize,
child: svg("flowy_logo"), child: svgWidget("flowy_logo"),
), ),
const VSpace(30), const VSpace(30),
Text( Text(

View File

@ -23,3 +23,6 @@ export 'cell_bloc/selection_cell_bloc.dart';
export 'cell_bloc/date_cell_bloc.dart'; export 'cell_bloc/date_cell_bloc.dart';
export 'cell_bloc/checkbox_cell_bloc.dart'; export 'cell_bloc/checkbox_cell_bloc.dart';
export 'cell_bloc/cell_service.dart'; export 'cell_bloc/cell_service.dart';
// Setting
export 'setting/setting_bloc.dart';

View File

@ -0,0 +1,47 @@
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'dart:async';
import 'package:dartz/dartz.dart';
part 'setting_bloc.freezed.dart';
class GridSettingBloc extends Bloc<GridSettingEvent, GridSettingState> {
final String gridId;
GridSettingBloc({required this.gridId}) : super(GridSettingState.initial()) {
on<GridSettingEvent>(
(event, emit) async {
event.map(performAction: (_PerformAction value) {
emit(state.copyWith(selectedAction: Some(value.action)));
});
},
);
}
@override
Future<void> close() async {
return super.close();
}
}
@freezed
class GridSettingEvent with _$GridSettingEvent {
const factory GridSettingEvent.performAction(GridSettingAction action) = _PerformAction;
}
@freezed
class GridSettingState with _$GridSettingState {
const factory GridSettingState({
required Option<GridSettingAction> selectedAction,
}) = _GridSettingState;
factory GridSettingState.initial() => GridSettingState(
selectedAction: none(),
);
}
enum GridSettingAction {
filter,
sortBy,
properties,
}

View File

@ -39,7 +39,7 @@ extension ViewExtension on View {
thumbnail = "file_icon"; thumbnail = "file_icon";
} }
final Widget widget = svg(thumbnail, color: iconColor); final Widget widget = svgWidget(thumbnail, color: iconColor);
return widget; return widget;
} }

View File

@ -28,7 +28,7 @@ class AddButton extends StatelessWidget {
onSelected: onSelected, onSelected: onSelected,
).show(context); ).show(context);
}, },
icon: svg("home/add").padding(horizontal: 3, vertical: 3), icon: svgWidget("home/add").padding(horizontal: 3, vertical: 3),
); );
} }
} }

View File

@ -153,9 +153,9 @@ extension AppDisclosureExtension on AppDisclosureAction {
Widget get icon { Widget get icon {
switch (this) { switch (this) {
case AppDisclosureAction.rename: case AppDisclosureAction.rename:
return svg('editor/edit', color: const Color(0xffe5e5e5)); return svgWidget('editor/edit', color: const Color(0xffe5e5e5));
case AppDisclosureAction.delete: case AppDisclosureAction.delete:
return svg('editor/delete', color: const Color(0xffe5e5e5)); return svgWidget('editor/delete', color: const Color(0xffe5e5e5));
} }
} }
} }

View File

@ -32,7 +32,7 @@ class ViewDisclosureButton extends StatelessWidget with ActionList<ViewDisclosur
onTap(); onTap();
show(context); show(context);
}, },
icon: svg("editor/details", color: theme.iconColor), icon: svgWidget("editor/details", color: theme.iconColor),
); );
} }

View File

@ -45,7 +45,7 @@ class ViewSectionItem extends StatelessWidget {
child: FlowyHover( child: FlowyHover(
config: HoverDisplayConfig(hoverColor: theme.bg3), config: HoverDisplayConfig(hoverColor: theme.bg3),
builder: (_, onHover) => _render(context, onHover, state, theme.iconColor), builder: (_, onHover) => _render(context, onHover, state, theme.iconColor),
isOnSelected: () => state.isEditing || isSelected, setSelected: () => state.isEditing || isSelected,
), ),
); );
}, },
@ -126,11 +126,11 @@ extension ViewDisclosureExtension on ViewDisclosureAction {
Widget get icon { Widget get icon {
switch (this) { switch (this) {
case ViewDisclosureAction.rename: case ViewDisclosureAction.rename:
return svg('editor/edit', color: const Color(0xff999999)); return svgWidget('editor/edit', color: const Color(0xff999999));
case ViewDisclosureAction.delete: case ViewDisclosureAction.delete:
return svg('editor/delete', color: const Color(0xff999999)); return svgWidget('editor/delete', color: const Color(0xff999999));
case ViewDisclosureAction.duplicate: case ViewDisclosureAction.duplicate:
return svg('editor/copy', color: const Color(0xff999999)); return svgWidget('editor/copy', color: const Color(0xff999999));
} }
} }
} }

View File

@ -186,7 +186,7 @@ class MenuTopBar extends StatelessWidget {
width: 28, width: 28,
onPressed: () => context.read<MenuBloc>().add(const MenuEvent.collapse()), onPressed: () => context.read<MenuBloc>().add(const MenuEvent.collapse()),
iconPadding: const EdgeInsets.fromLTRB(4, 4, 4, 4), iconPadding: const EdgeInsets.fromLTRB(4, 4, 4, 4),
icon: svg("home/hide_menu", color: theme.iconColor), icon: svgWidget("home/hide_menu", color: theme.iconColor),
) )
], ],
), ),

View File

@ -80,7 +80,7 @@ class MenuUser extends StatelessWidget {
}, },
icon: SizedBox.square( icon: SizedBox.square(
dimension: 20, dimension: 20,
child: svg("home/settings", color: theme.iconColor), child: svgWidget("home/settings", color: theme.iconColor),
), ),
), ),
); );

View File

@ -97,7 +97,7 @@ class FlowyNavigation extends StatelessWidget {
notifier.value = false; notifier.value = false;
}, },
iconPadding: const EdgeInsets.fromLTRB(2, 2, 2, 2), iconPadding: const EdgeInsets.fromLTRB(2, 2, 2, 2),
icon: svg("home/hide_menu", color: theme.iconColor), icon: svgWidget("home/hide_menu", color: theme.iconColor),
), ),
); );
} else { } else {

View File

@ -51,7 +51,7 @@ class _FlowyEditorCheckboxState extends State<FlowyEditorCheckbox> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final icon = isChecked ? svg('editor/editor_check') : svg('editor/editor_uncheck'); final icon = isChecked ? svgWidget('editor/editor_check') : svgWidget('editor/editor_uncheck');
return Align( return Align(
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
child: FlowyIconButton( child: FlowyIconButton(

View File

@ -54,11 +54,11 @@ class _FlowyLinkStyleButtonState extends State<FlowyLinkStyleButton> {
final isEnabled = !widget.controller.selection.isCollapsed; final isEnabled = !widget.controller.selection.isCollapsed;
final pressedHandler = isEnabled ? () => _openLinkDialog(context) : null; final pressedHandler = isEnabled ? () => _openLinkDialog(context) : null;
final icon = isEnabled final icon = isEnabled
? svg( ? svgWidget(
'editor/share', 'editor/share',
color: theme.iconColor, color: theme.iconColor,
) )
: svg( : svgWidget(
'editor/share', 'editor/share',
color: theme.disableIconColor, color: theme.disableIconColor,
); );

View File

@ -29,7 +29,7 @@ class ToolbarIconButton extends StatelessWidget {
iconPadding: const EdgeInsets.symmetric(horizontal: 4, vertical: 4), iconPadding: const EdgeInsets.symmetric(horizontal: 4, vertical: 4),
onPressed: onPressed, onPressed: onPressed,
width: width, width: width,
icon: isToggled == true ? svg(iconName, color: Colors.white) : svg(iconName), icon: isToggled == true ? svgWidget(iconName, color: Colors.white) : svgWidget(iconName),
fillColor: isToggled == true ? theme.main1 : theme.shader6, fillColor: isToggled == true ? theme.main1 : theme.shader6,
hoverColor: isToggled == true ? theme.main1 : theme.shader5, hoverColor: isToggled == true ? theme.main1 : theme.shader5,
tooltipText: tooltipText, tooltipText: tooltipText,

View File

@ -13,6 +13,7 @@ import 'layout/sizes.dart';
import 'widgets/content/grid_row.dart'; import 'widgets/content/grid_row.dart';
import 'widgets/footer/grid_footer.dart'; import 'widgets/footer/grid_footer.dart';
import 'widgets/header/grid_header.dart'; import 'widgets/header/grid_header.dart';
import 'widgets/toolbar/grid_toolbar.dart';
class GridPage extends StatefulWidget { class GridPage extends StatefulWidget {
final View view; final View view;
@ -99,6 +100,7 @@ class _FlowyGridState extends State<FlowyGrid> {
physics: StyledScrollPhysics(), physics: StyledScrollPhysics(),
controller: _scrollController.verticalController, controller: _scrollController.verticalController,
slivers: [ slivers: [
SliverToBoxAdapter(child: GridToolbar(gridId: gridId)),
_buildHeader(gridId), _buildHeader(gridId),
_buildRows(context), _buildRows(context),
const GridFooter(), const GridFooter(),

View File

@ -110,7 +110,7 @@ class AppendRowButton extends StatelessWidget {
width: 22, width: 22,
onPressed: () => context.read<RowBloc>().add(const RowEvent.createRow()), onPressed: () => context.read<RowBloc>().add(const RowEvent.createRow()),
iconPadding: const EdgeInsets.all(3), iconPadding: const EdgeInsets.all(3),
icon: svg("home/add"), icon: svgWidget("home/add"),
); );
} }
} }

View File

@ -39,7 +39,7 @@ class _AddRowButton extends StatelessWidget {
text: const FlowyText.medium('New row', fontSize: 12), text: const FlowyText.medium('New row', fontSize: 12),
hoverColor: theme.hover, hoverColor: theme.hover,
onTap: () => context.read<GridBloc>().add(const GridEvent.createRow()), onTap: () => context.read<GridBloc>().add(const GridEvent.createRow()),
leftIcon: svg("home/add"), leftIcon: svgWidget("home/add"),
); );
} }
} }

View File

@ -1,3 +1,4 @@
import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart';
import 'package:flowy_infra/image.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';
@ -13,14 +14,10 @@ import 'package:flutter_bloc/flutter_bloc.dart';
typedef SelectFieldCallback = void Function(FieldType); typedef SelectFieldCallback = void Function(FieldType);
class FieldTypeList extends StatelessWidget { class FieldTypeList extends StatelessWidget with FlowyOverlayDelegate {
final SelectFieldCallback onSelectField; final SelectFieldCallback onSelectField;
const FieldTypeList({required this.onSelectField, Key? key}) : super(key: key); const FieldTypeList({required this.onSelectField, Key? key}) : super(key: key);
static void hide(BuildContext context) {
FlowyOverlay.of(context).remove(FieldTypeList.identifier());
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final cells = FieldType.values.map((fieldType) { final cells = FieldType.values.map((fieldType) {
@ -40,7 +37,7 @@ class FieldTypeList extends StatelessWidget {
controller: ScrollController(), controller: ScrollController(),
itemCount: cells.length, itemCount: cells.length,
separatorBuilder: (context, index) { separatorBuilder: (context, index) {
return const VSpace(10); return VSpace(GridSize.typeOptionSeparatorHeight);
}, },
physics: StyledScrollPhysics(), physics: StyledScrollPhysics(),
itemBuilder: (BuildContext context, int index) { itemBuilder: (BuildContext context, int index) {
@ -69,12 +66,12 @@ class FieldTypeCell extends StatelessWidget {
final theme = context.watch<AppTheme>(); final theme = context.watch<AppTheme>();
return SizedBox( return SizedBox(
height: 26, height: GridSize.typeOptionItemHeight,
child: FlowyButton( child: FlowyButton(
text: FlowyText.medium(fieldType.title(), fontSize: 12), text: FlowyText.medium(fieldType.title(), fontSize: 12),
hoverColor: theme.hover, hoverColor: theme.hover,
onTap: () => onSelectField(fieldType), onTap: () => onSelectField(fieldType),
leftIcon: svg(fieldType.iconName(), color: theme.iconColor), leftIcon: svgWidget(fieldType.iconName(), color: theme.iconColor),
), ),
); );
} }

View File

@ -9,7 +9,7 @@ import 'package:app_flowy/generated/locale_keys.g.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
class FieldOperationList extends StatelessWidget { class FieldOperationList extends StatelessWidget {
final List<FieldActionItem> actions; final List<FieldActionCell> actions;
const FieldOperationList({required this.actions, Key? key}) : super(key: key); const FieldOperationList({required this.actions, Key? key}) : super(key: key);
@override @override
@ -27,12 +27,12 @@ class FieldOperationList extends StatelessWidget {
} }
} }
class FieldActionItem extends StatelessWidget { class FieldActionCell extends StatelessWidget {
final String fieldId; final String fieldId;
final VoidCallback onTap; final VoidCallback onTap;
final FieldAction action; final FieldAction action;
const FieldActionItem({ const FieldActionCell({
required this.fieldId, required this.fieldId,
required this.action, required this.action,
required this.onTap, required this.onTap,
@ -49,7 +49,7 @@ class FieldActionItem extends StatelessWidget {
action.run(context); action.run(context);
onTap(); onTap();
}, },
leftIcon: svg(action.iconName(), color: theme.iconColor), leftIcon: svgWidget(action.iconName(), color: theme.iconColor),
); );
} }
} }

View File

@ -83,8 +83,8 @@ class _FieldSwitcherState extends State<FieldSwitcher> {
}); });
_showOverlay(context, list); _showOverlay(context, list);
}, },
leftIcon: svg(field.fieldType.iconName(), color: theme.iconColor), leftIcon: svgWidget(field.fieldType.iconName(), color: theme.iconColor),
rightIcon: svg("grid/more", color: theme.iconColor), rightIcon: svgWidget("grid/more", color: theme.iconColor),
), ),
); );
} }

View File

@ -17,16 +17,16 @@ class GridFieldActionSheet extends StatelessWidget with FlowyOverlayDelegate {
final VoidCallback onEdited; final VoidCallback onEdited;
const GridFieldActionSheet({required this.fieldData, required this.onEdited, Key? key}) : super(key: key); const GridFieldActionSheet({required this.fieldData, required this.onEdited, Key? key}) : super(key: key);
static void show(BuildContext overlayContext, GridFieldData fieldData, final VoidCallback onEdited) { void show(BuildContext overlayContext) {
final editor = GridFieldActionSheet(fieldData: fieldData, onEdited: onEdited);
FlowyOverlay.of(overlayContext).insertWithAnchor( FlowyOverlay.of(overlayContext).insertWithAnchor(
widget: OverlayContainer( widget: OverlayContainer(
child: editor, child: this,
constraints: BoxConstraints.loose(const Size(240, 200)), constraints: BoxConstraints.loose(const Size(240, 200)),
), ),
identifier: editor.identifier(), identifier: identifier(),
anchorContext: overlayContext, anchorContext: overlayContext,
anchorDirection: AnchorDirection.bottomWithLeftAligned, anchorDirection: AnchorDirection.bottomWithLeftAligned,
delegate: this,
); );
} }
@ -56,7 +56,9 @@ class GridFieldActionSheet extends StatelessWidget with FlowyOverlayDelegate {
} }
@override @override
bool asBarrier() => true; bool asBarrier() {
return true;
}
} }
class _EditFieldButton extends StatelessWidget { class _EditFieldButton extends StatelessWidget {
@ -90,7 +92,7 @@ class _FieldOperationList extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final actions = FieldAction.values final actions = FieldAction.values
.map( .map(
(action) => FieldActionItem( (action) => FieldActionCell(
fieldId: fieldData.field.id, fieldId: fieldData.field.id,
action: action, action: action,
onTap: onDismissed, onTap: onDismissed,

View File

@ -25,7 +25,7 @@ class FieldEditor extends FlowyOverlayDelegate {
void show(BuildContext context) { void show(BuildContext context) {
FlowyOverlay.of(context).insertWithAnchor( FlowyOverlay.of(context).insertWithAnchor(
widget: OverlayContainer( widget: OverlayContainer(
child: _EditFieldPannelWidget(_fieldEditorBloc), child: _FieldEditorWidget(_fieldEditorBloc),
constraints: BoxConstraints.loose(const Size(220, 400)), constraints: BoxConstraints.loose(const Size(220, 400)),
), ),
identifier: identifier(), identifier: identifier(),
@ -49,9 +49,9 @@ class FieldEditor extends FlowyOverlayDelegate {
bool asBarrier() => true; bool asBarrier() => true;
} }
class _EditFieldPannelWidget extends StatelessWidget { class _FieldEditorWidget extends StatelessWidget {
final FieldEditorBloc editorBloc; final FieldEditorBloc editorBloc;
const _EditFieldPannelWidget(this.editorBloc, {Key? key}) : super(key: key); const _FieldEditorWidget(this.editorBloc, {Key? key}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

View File

@ -121,7 +121,7 @@ class CreateFieldButton extends StatelessWidget {
gridId: gridId, gridId: gridId,
fieldContextLoader: NewFieldContextLoader(gridId: gridId), fieldContextLoader: NewFieldContextLoader(gridId: gridId),
).show(context), ).show(context),
leftIcon: svg("home/add"), leftIcon: svgWidget("home/add"),
); );
} }
} }

View File

@ -19,13 +19,16 @@ class GridHeaderCell extends StatelessWidget {
final theme = context.watch<AppTheme>(); final theme = context.watch<AppTheme>();
final button = FlowyButton( final button = FlowyButton(
hoverColor: theme.hover, hoverColor: theme.hover,
onTap: () => GridFieldActionSheet.show(context, fieldData, () { onTap: () => GridFieldActionSheet(
fieldData: fieldData,
onEdited: () {
FieldEditor( FieldEditor(
gridId: fieldData.gridId, gridId: fieldData.gridId,
fieldContextLoader: FieldContextLoaderAdaptor(fieldData), fieldContextLoader: FieldContextLoaderAdaptor(fieldData),
).show(context); ).show(context);
}), },
rightIcon: svg("editor/details", color: theme.iconColor), ).show(context),
rightIcon: svgWidget("editor/details", color: theme.iconColor),
text: Padding(padding: GridSize.cellContentInsets, child: FlowyText.medium(fieldData.field.name, fontSize: 12)), text: Padding(padding: GridSize.cellContentInsets, child: FlowyText.medium(fieldData.field.name, fontSize: 12)),
); );

View File

@ -1,35 +0,0 @@
enum GridSetting {
filter,
sortBy,
properties,
}
extension _GridSettingExtension on GridSetting {
String iconName() {
switch (this) {
case GridSetting.filter:
// TODO: Handle this case.
break;
case GridSetting.sortBy:
// TODO: Handle this case.
break;
case GridSetting.properties:
// TODO: Handle this case.
break;
}
}
String title() {
switch (this) {
case GridSetting.filter:
// TODO: Handle this case.
break;
case GridSetting.sortBy:
// TODO: Handle this case.
break;
case GridSetting.properties:
// TODO: Handle this case.
break;
}
}
}

View File

@ -75,7 +75,7 @@ class DateTypeOptionWidget extends TypeOptionWidget {
); );
overlayDelegate.showOverlay(context, list); overlayDelegate.showOverlay(context, list);
}, },
rightIcon: svg("grid/more", color: theme.iconColor), rightIcon: svgWidget("grid/more", color: theme.iconColor),
), ),
); );
} }
@ -96,7 +96,7 @@ class DateTypeOptionWidget extends TypeOptionWidget {
}); });
overlayDelegate.showOverlay(context, list); overlayDelegate.showOverlay(context, list);
}, },
rightIcon: svg("grid/more", color: theme.iconColor), rightIcon: svgWidget("grid/more", color: theme.iconColor),
), ),
); );
} }
@ -156,7 +156,7 @@ class DateFormatItem extends StatelessWidget {
final theme = context.watch<AppTheme>(); final theme = context.watch<AppTheme>();
Widget? checkmark; Widget? checkmark;
if (isSelected) { if (isSelected) {
checkmark = svg("grid/checkmark"); checkmark = svgWidget("grid/checkmark");
} }
return SizedBox( return SizedBox(
@ -246,7 +246,7 @@ class TimeFormatItem extends StatelessWidget {
final theme = context.watch<AppTheme>(); final theme = context.watch<AppTheme>();
Widget? checkmark; Widget? checkmark;
if (isSelected) { if (isSelected) {
checkmark = svg("grid/checkmark"); checkmark = svgWidget("grid/checkmark");
} }
return SizedBox( return SizedBox(

View File

@ -79,7 +79,7 @@ class _DeleteTag extends StatelessWidget {
child: FlowyButton( child: FlowyButton(
text: FlowyText.medium(LocaleKeys.grid_selectOption_deleteTag.tr(), fontSize: 12), text: FlowyText.medium(LocaleKeys.grid_selectOption_deleteTag.tr(), fontSize: 12),
hoverColor: theme.hover, hoverColor: theme.hover,
leftIcon: svg("grid/delete", color: theme.iconColor), leftIcon: svgWidget("grid/delete", color: theme.iconColor),
onTap: () { onTap: () {
context.read<EditOptionBloc>().add(const EditOptionEvent.delete()); context.read<EditOptionBloc>().add(const EditOptionEvent.delete());
}, },
@ -110,8 +110,8 @@ class SelectOptionColorList extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final optionItems = SelectOptionColor.values.map((color) { final cells = SelectOptionColor.values.map((color) {
return _SelectOptionColorItem(color: color, isSelected: selectedColor == color); return _SelectOptionColorCell(color: color, isSelected: selectedColor == color);
}).toList(); }).toList();
return Column( return Column(
@ -135,10 +135,10 @@ class SelectOptionColorList extends StatelessWidget {
separatorBuilder: (context, index) { separatorBuilder: (context, index) {
return VSpace(GridSize.typeOptionSeparatorHeight); return VSpace(GridSize.typeOptionSeparatorHeight);
}, },
itemCount: optionItems.length, itemCount: cells.length,
physics: StyledScrollPhysics(), physics: StyledScrollPhysics(),
itemBuilder: (BuildContext context, int index) { itemBuilder: (BuildContext context, int index) {
return optionItems[index]; return cells[index];
}, },
), ),
], ],
@ -146,17 +146,17 @@ class SelectOptionColorList extends StatelessWidget {
} }
} }
class _SelectOptionColorItem extends StatelessWidget { class _SelectOptionColorCell extends StatelessWidget {
final SelectOptionColor color; final SelectOptionColor color;
final bool isSelected; final bool isSelected;
const _SelectOptionColorItem({required this.color, required this.isSelected, Key? key}) : super(key: key); const _SelectOptionColorCell({required this.color, required this.isSelected, Key? key}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = context.watch<AppTheme>(); final theme = context.watch<AppTheme>();
Widget? checkmark; Widget? checkmark;
if (isSelected) { if (isSelected) {
checkmark = svg("grid/checkmark"); checkmark = svgWidget("grid/checkmark");
} }
final colorIcon = SizedBox.square( final colorIcon = SizedBox.square(

View File

@ -59,7 +59,7 @@ class NumberTypeOptionWidget extends TypeOptionWidget {
}); });
overlayDelegate.showOverlay(context, list); overlayDelegate.showOverlay(context, list);
}, },
rightIcon: svg("grid/more", color: theme.iconColor), rightIcon: svgWidget("grid/more", color: theme.iconColor),
); );
}, },
), ),
@ -76,8 +76,8 @@ class NumberFormatList extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final formatItems = NumberFormat.values.map((format) { final cells = NumberFormat.values.map((format) {
return NumberFormatItem( return NumberFormatCell(
format: format, format: format,
onSelected: (format) { onSelected: (format) {
onSelected(format); onSelected(format);
@ -93,9 +93,9 @@ class NumberFormatList extends StatelessWidget {
separatorBuilder: (context, index) { separatorBuilder: (context, index) {
return VSpace(GridSize.typeOptionSeparatorHeight); return VSpace(GridSize.typeOptionSeparatorHeight);
}, },
itemCount: formatItems.length, itemCount: cells.length,
itemBuilder: (BuildContext context, int index) { itemBuilder: (BuildContext context, int index) {
return formatItems[index]; return cells[index];
}, },
), ),
); );
@ -106,10 +106,10 @@ class NumberFormatList extends StatelessWidget {
} }
} }
class NumberFormatItem extends StatelessWidget { class NumberFormatCell extends StatelessWidget {
final NumberFormat format; final NumberFormat format;
final Function(NumberFormat format) onSelected; final Function(NumberFormat format) onSelected;
const NumberFormatItem({required this.format, required this.onSelected, Key? key}) : super(key: key); const NumberFormatCell({required this.format, required this.onSelected, Key? key}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -120,7 +120,7 @@ class NumberFormatItem extends StatelessWidget {
text: FlowyText.medium(format.title(), fontSize: 12), text: FlowyText.medium(format.title(), fontSize: 12),
hoverColor: theme.hover, hoverColor: theme.hover,
onTap: () => onSelected(format), onTap: () => onSelected(format),
leftIcon: svg(format.iconName(), color: theme.iconColor), leftIcon: svgWidget(format.iconName(), color: theme.iconColor),
), ),
); );
} }

View File

@ -132,8 +132,8 @@ class _OptionList extends StatelessWidget {
return previous.options != current.options; return previous.options != current.options;
}, },
builder: (context, state) { builder: (context, state) {
final optionItems = state.options.map((option) { final cells = state.options.map((option) {
return _makeOptionItem(context, option); return _makeOptionCell(context, option);
}).toList(); }).toList();
return ListView.separated( return ListView.separated(
@ -142,17 +142,17 @@ class _OptionList extends StatelessWidget {
separatorBuilder: (context, index) { separatorBuilder: (context, index) {
return VSpace(GridSize.typeOptionSeparatorHeight); return VSpace(GridSize.typeOptionSeparatorHeight);
}, },
itemCount: optionItems.length, itemCount: cells.length,
itemBuilder: (BuildContext context, int index) { itemBuilder: (BuildContext context, int index) {
return optionItems[index]; return cells[index];
}, },
); );
}, },
); );
} }
_OptionItem _makeOptionItem(BuildContext context, SelectOption option) { _OptionCell _makeOptionCell(BuildContext context, SelectOption option) {
return _OptionItem( return _OptionCell(
option: option, option: option,
onEdited: (option) { onEdited: (option) {
final pannel = EditSelectOptionPannel( final pannel = EditSelectOptionPannel(
@ -173,10 +173,10 @@ class _OptionList extends StatelessWidget {
} }
} }
class _OptionItem extends StatelessWidget { class _OptionCell extends StatelessWidget {
final SelectOption option; final SelectOption option;
final Function(SelectOption) onEdited; final Function(SelectOption) onEdited;
const _OptionItem({ const _OptionCell({
required this.option, required this.option,
required this.onEdited, required this.onEdited,
Key? key, Key? key,
@ -191,7 +191,7 @@ class _OptionItem extends StatelessWidget {
text: FlowyText.medium(option.name, fontSize: 12), text: FlowyText.medium(option.name, fontSize: 12),
hoverColor: theme.hover, hoverColor: theme.hover,
onTap: () => onEdited(option), onTap: () => onEdited(option),
rightIcon: svg("grid/details", color: theme.iconColor), rightIcon: svgWidget("grid/details", color: theme.iconColor),
), ),
); );
} }
@ -211,7 +211,7 @@ class _AddOptionButton extends StatelessWidget {
onTap: () { onTap: () {
context.read<OptionPannelBloc>().add(const OptionPannelEvent.beginAddingOption()); context.read<OptionPannelBloc>().add(const OptionPannelEvent.beginAddingOption());
}, },
leftIcon: svg("home/add", color: theme.iconColor), leftIcon: svgWidget("home/add", color: theme.iconColor),
), ),
); );
} }

View File

@ -0,0 +1,19 @@
import 'package:flutter/material.dart';
class GridPropertyList extends StatelessWidget {
const GridPropertyList({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container();
}
}
class _GridPropertyCell extends StatelessWidget {
const _GridPropertyCell({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container();
}
}

View File

@ -0,0 +1,152 @@
import 'package:app_flowy/workspace/application/grid/setting/setting_bloc.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/image.dart';
import 'package:flowy_infra/theme.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.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:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:app_flowy/generated/locale_keys.g.dart';
import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart';
class GridSettingContext {
final String gridId;
GridSettingContext({
required this.gridId,
});
}
class GridSettingList extends StatelessWidget with FlowyOverlayDelegate {
final GridSettingContext settingContext;
const GridSettingList({required this.settingContext, Key? key}) : super(key: key);
void show(BuildContext context) {
FlowyOverlay.of(context).insertWithAnchor(
widget: OverlayContainer(
child: this,
constraints: BoxConstraints.loose(const Size(140, 400)),
),
identifier: identifier(),
anchorContext: context,
anchorDirection: AnchorDirection.bottomRight,
style: FlowyOverlayStyle(blur: false),
delegate: this,
);
}
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => GridSettingBloc(gridId: settingContext.gridId),
child: BlocListener<GridSettingBloc, GridSettingState>(
listenWhen: (previous, current) => previous.selectedAction != current.selectedAction,
listener: (context, state) {
state.selectedAction.foldLeft(null, (_, action) {
switch (action) {
case GridSettingAction.filter:
// TODO: Handle this case.
break;
case GridSettingAction.sortBy:
// TODO: Handle this case.
break;
case GridSettingAction.properties:
// TODO: Handle this case.
break;
}
});
},
child: BlocBuilder<GridSettingBloc, GridSettingState>(
builder: (context, state) {
return _renderList();
},
),
),
);
}
String identifier() {
return toString();
}
Widget _renderList() {
final cells = GridSettingAction.values.map((action) {
return _SettingItem(action: action);
}).toList();
return SizedBox(
width: 140,
child: ListView.separated(
shrinkWrap: true,
controller: ScrollController(),
itemCount: cells.length,
separatorBuilder: (context, index) {
return VSpace(GridSize.typeOptionSeparatorHeight);
},
physics: StyledScrollPhysics(),
itemBuilder: (BuildContext context, int index) {
return cells[index];
},
),
);
}
}
class _SettingItem extends StatelessWidget {
final GridSettingAction action;
const _SettingItem({
required this.action,
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
final theme = context.watch<AppTheme>();
final isSelected = context
.read<GridSettingBloc>()
.state
.selectedAction
.foldLeft(false, (_, selectedAction) => selectedAction == action);
return SizedBox(
height: GridSize.typeOptionItemHeight,
child: FlowyButton(
isSelected: isSelected,
text: FlowyText.medium(action.title(), fontSize: 12),
hoverColor: theme.hover,
onTap: () {
context.read<GridSettingBloc>().add(GridSettingEvent.performAction(action));
},
leftIcon: svgWidget(action.iconName(), color: theme.iconColor),
),
);
}
}
extension _GridSettingExtension on GridSettingAction {
String iconName() {
switch (this) {
case GridSettingAction.filter:
return 'grid/setting/filter';
case GridSettingAction.sortBy:
return 'grid/setting/sort';
case GridSettingAction.properties:
return 'grid/setting/properties';
}
}
String title() {
switch (this) {
case GridSettingAction.filter:
return LocaleKeys.grid_settings_filter.tr();
case GridSettingAction.sortBy:
return LocaleKeys.grid_settings_sortBy.tr();
case GridSettingAction.properties:
return LocaleKeys.grid_settings_Properties.tr();
}
}
}

View File

@ -0,0 +1,44 @@
import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart';
import 'package:flowy_infra_ui/style_widget/extension.dart';
import 'package:flutter/material.dart';
import 'package:flowy_infra/image.dart';
import 'package:flowy_infra/theme.dart';
import 'package:flowy_infra_ui/style_widget/icon_button.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'grid_setting.dart';
class GridToolbar extends StatelessWidget {
final String gridId;
const GridToolbar({required this.gridId, Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return SizedBox(
height: 40,
child: Row(
children: [
SizedBox(width: GridSize.leadingHeaderPadding),
_SettingButton(settingContext: GridSettingContext(gridId: gridId)),
const Spacer(),
],
),
);
}
}
class _SettingButton extends StatelessWidget {
final GridSettingContext settingContext;
const _SettingButton({required this.settingContext, Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final theme = context.watch<AppTheme>();
return FlowyIconButton(
hoverColor: theme.hover,
width: 22,
onPressed: () => GridSettingList(settingContext: settingContext).show(context),
icon: svgWidget("grid/setting/setting").padding(horizontal: 3, vertical: 3),
);
}
}

View File

@ -36,7 +36,7 @@ class MenuTrash extends StatelessWidget {
child: Selector<AppearanceSettingModel, AppTheme>( child: Selector<AppearanceSettingModel, AppTheme>(
selector: (ctx, notifier) => notifier.theme, selector: (ctx, notifier) => notifier.theme,
builder: (ctx, theme, child) => builder: (ctx, theme, child) =>
SizedBox(width: 16, height: 16, child: svg("home/trash", color: theme.iconColor)), SizedBox(width: 16, height: 16, child: svgWidget("home/trash", color: theme.iconColor)),
), ),
), ),
const HSpace(6), const HSpace(6),

View File

@ -29,13 +29,13 @@ class TrashCell extends StatelessWidget {
FlowyIconButton( FlowyIconButton(
width: 16, width: 16,
onPressed: onRestore, onPressed: onRestore,
icon: svg("editor/restore", color: theme.iconColor), icon: svgWidget("editor/restore", color: theme.iconColor),
), ),
const HSpace(20), const HSpace(20),
FlowyIconButton( FlowyIconButton(
width: 16, width: 16,
onPressed: onDelete, onPressed: onDelete,
icon: svg("editor/delete", color: theme.iconColor), icon: svgWidget("editor/delete", color: theme.iconColor),
), ),
], ],
); );

View File

@ -146,7 +146,7 @@ class _TrashPageState extends State<TrashPage> {
size: const Size(102, 30), size: const Size(102, 30),
child: FlowyButton( child: FlowyButton(
text: FlowyText.medium(LocaleKeys.trash_restoreAll.tr(), fontSize: 12), text: FlowyText.medium(LocaleKeys.trash_restoreAll.tr(), fontSize: 12),
leftIcon: svg('editor/restore', color: theme.iconColor), leftIcon: svgWidget('editor/restore', color: theme.iconColor),
hoverColor: theme.hover, hoverColor: theme.hover,
onTap: () => context.read<TrashBloc>().add(const TrashEvent.restoreAll()), onTap: () => context.read<TrashBloc>().add(const TrashEvent.restoreAll()),
), ),
@ -156,7 +156,7 @@ class _TrashPageState extends State<TrashPage> {
size: const Size(102, 30), size: const Size(102, 30),
child: FlowyButton( child: FlowyButton(
text: FlowyText.medium(LocaleKeys.trash_deleteAll.tr(), fontSize: 12), text: FlowyText.medium(LocaleKeys.trash_deleteAll.tr(), fontSize: 12),
leftIcon: svg('editor/delete', color: theme.iconColor), leftIcon: svgWidget('editor/delete', color: theme.iconColor),
hoverColor: theme.hover, hoverColor: theme.hover,
onTap: () => context.read<TrashBloc>().add(const TrashEvent.deleteAll()), onTap: () => context.read<TrashBloc>().add(const TrashEvent.deleteAll()),
), ),

View File

@ -1,7 +1,7 @@
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
Widget svg(String name, {Color? color}) { Widget svgWidget(String name, {Color? color}) {
final Widget svg = SvgPicture.asset('assets/images/$name.svg', color: color); final Widget svg = SvgPicture.asset('assets/images/$name.svg', color: color);
return svg; return svg;
@ -10,6 +10,6 @@ Widget svg(String name, {Color? color}) {
Widget svgWithSize(String name, Size size) { Widget svgWithSize(String name, Size size) {
return SizedBox.fromSize( return SizedBox.fromSize(
size: size, size: size,
child: svg(name), child: svgWidget(name),
); );
} }

View File

@ -11,6 +11,7 @@ class FlowyButton extends StatelessWidget {
final Widget? leftIcon; final Widget? leftIcon;
final Widget? rightIcon; final Widget? rightIcon;
final Color hoverColor; final Color hoverColor;
final bool isSelected;
const FlowyButton({ const FlowyButton({
Key? key, Key? key,
required this.text, required this.text,
@ -19,6 +20,7 @@ class FlowyButton extends StatelessWidget {
this.leftIcon, this.leftIcon,
this.rightIcon, this.rightIcon,
this.hoverColor = Colors.transparent, this.hoverColor = Colors.transparent,
this.isSelected = false,
}) : super(key: key); }) : super(key: key);
@override @override
@ -27,6 +29,7 @@ class FlowyButton extends StatelessWidget {
onTap: onTap, onTap: onTap,
child: FlowyHover( child: FlowyHover(
config: HoverDisplayConfig(borderRadius: Corners.s6Border, hoverColor: hoverColor), config: HoverDisplayConfig(borderRadius: Corners.s6Border, hoverColor: hoverColor),
setSelected: () => isSelected,
builder: (context, onHover) => _render(), builder: (context, onHover) => _render(),
), ),
); );

View File

@ -3,18 +3,17 @@ import 'package:flutter/material.dart';
import 'package:flowy_infra/time/duration.dart'; import 'package:flowy_infra/time/duration.dart';
typedef HoverBuilder = Widget Function(BuildContext context, bool onHover); typedef HoverBuilder = Widget Function(BuildContext context, bool onHover);
typedef IsOnSelected = bool Function();
class FlowyHover extends StatefulWidget { class FlowyHover extends StatefulWidget {
final HoverDisplayConfig config; final HoverDisplayConfig config;
final HoverBuilder builder; final HoverBuilder builder;
final IsOnSelected? isOnSelected; final bool Function()? setSelected;
const FlowyHover({ const FlowyHover({
Key? key, Key? key,
required this.builder, required this.builder,
required this.config, required this.config,
this.isOnSelected, this.setSelected,
}) : super(key: key); }) : super(key: key);
@override @override
@ -36,8 +35,8 @@ class _FlowyHoverState extends State<FlowyHover> {
Widget render() { Widget render() {
var showHover = _onHover; var showHover = _onHover;
if (!showHover && widget.isOnSelected != null) { if (!showHover && widget.setSelected != null) {
showHover = widget.isOnSelected!(); showHover = widget.setSelected!();
} }
if (showHover) { if (showHover) {

View File

@ -77,7 +77,7 @@ class FlowyDropdownButton extends StatelessWidget {
return FlowyIconButton( return FlowyIconButton(
width: 16, width: 16,
onPressed: onPressed, onPressed: onPressed,
icon: svg("home/drop_down_show"), icon: svgWidget("home/drop_down_show"),
); );
} }
} }

View File

@ -113,6 +113,7 @@ flutter:
- assets/images/editor/ - assets/images/editor/
- assets/images/grid/ - assets/images/grid/
- assets/images/grid/field/ - assets/images/grid/field/
- assets/images/grid/setting/
- assets/translations/ - assets/translations/
# - images/a_dot_ham.jpeg # - images/a_dot_ham.jpeg