chore: grid setting list
@ -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 |
Before Width: | Height: | Size: 238 B After Width: | Height: | Size: 238 B |
Before Width: | Height: | Size: 281 B After Width: | Height: | Size: 281 B |
Before Width: | Height: | Size: 512 B After Width: | Height: | Size: 512 B |
Before Width: | Height: | Size: 499 B After Width: | Height: | Size: 499 B |
@ -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 |
4
frontend/app_flowy/assets/images/grid/setting/sort.svg
Normal 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 |
@ -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",
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
|
@ -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(
|
||||||
|
@ -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';
|
||||||
|
@ -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,
|
||||||
|
}
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -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),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -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 {
|
||||||
|
@ -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(
|
||||||
|
@ -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,
|
||||||
);
|
);
|
||||||
|
@ -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,
|
||||||
|
@ -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(),
|
||||||
|
@ -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"),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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"),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -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),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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) {
|
||||||
|
@ -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"),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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(
|
||||||
|
@ -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(
|
||||||
|
@ -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),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -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),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -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),
|
||||||
|
@ -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),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
@ -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()),
|
||||||
),
|
),
|
||||||
|
@ -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),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -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(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -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) {
|
||||||
|
@ -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"),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
|
||||||
|