mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
chore: improve setting tab bar dropdown (#3756)
* chore: improve setting tab bar dropdown * test: fix integration tests
This commit is contained in:
parent
d51c7f382f
commit
b16a102f85
@ -38,7 +38,7 @@ import 'package:appflowy/plugins/database_view/grid/presentation/widgets/toolbar
|
|||||||
import 'package:appflowy/plugins/database_view/tar_bar/tab_bar_header.dart';
|
import 'package:appflowy/plugins/database_view/tar_bar/tab_bar_header.dart';
|
||||||
import 'package:appflowy/plugins/database_view/tar_bar/tar_bar_add_button.dart';
|
import 'package:appflowy/plugins/database_view/tar_bar/tar_bar_add_button.dart';
|
||||||
import 'package:appflowy/plugins/database_view/widgets/database_layout_ext.dart';
|
import 'package:appflowy/plugins/database_view/widgets/database_layout_ext.dart';
|
||||||
import 'package:appflowy/plugins/database_view/widgets/field/grid_property.dart';
|
import 'package:appflowy/plugins/database_view/widgets/setting/setting_property_list.dart';
|
||||||
import 'package:appflowy/plugins/database_view/widgets/row/accessory/cell_accessory.dart';
|
import 'package:appflowy/plugins/database_view/widgets/row/accessory/cell_accessory.dart';
|
||||||
import 'package:appflowy/plugins/database_view/widgets/row/cells/cells.dart';
|
import 'package:appflowy/plugins/database_view/widgets/row/cells/cells.dart';
|
||||||
import 'package:appflowy/plugins/database_view/widgets/row/cells/checklist_cell/checklist_cell_editor.dart';
|
import 'package:appflowy/plugins/database_view/widgets/row/cells/checklist_cell/checklist_cell_editor.dart';
|
||||||
@ -52,7 +52,6 @@ import 'package:appflowy/plugins/database_view/widgets/row/row_banner.dart';
|
|||||||
import 'package:appflowy/plugins/database_view/widgets/row/row_detail.dart';
|
import 'package:appflowy/plugins/database_view/widgets/row/row_detail.dart';
|
||||||
import 'package:appflowy/plugins/database_view/widgets/row/row_document.dart';
|
import 'package:appflowy/plugins/database_view/widgets/row/row_document.dart';
|
||||||
import 'package:appflowy/plugins/database_view/widgets/row/row_property.dart';
|
import 'package:appflowy/plugins/database_view/widgets/row/row_property.dart';
|
||||||
import 'package:appflowy/plugins/database_view/widgets/setting/database_setting.dart';
|
|
||||||
import 'package:appflowy/plugins/database_view/widgets/setting/setting_button.dart';
|
import 'package:appflowy/plugins/database_view/widgets/setting/setting_button.dart';
|
||||||
import 'package:appflowy/workspace/presentation/settings/widgets/emoji_picker/emoji_menu_item.dart';
|
import 'package:appflowy/workspace/presentation/settings/widgets/emoji_picker/emoji_menu_item.dart';
|
||||||
import 'package:appflowy/workspace/presentation/widgets/dialogs.dart';
|
import 'package:appflowy/workspace/presentation/widgets/dialogs.dart';
|
||||||
@ -1132,7 +1131,7 @@ extension AppFlowyDatabaseTest on WidgetTester {
|
|||||||
|
|
||||||
/// Should call [tapDatabaseSettingButton] first.
|
/// Should call [tapDatabaseSettingButton] first.
|
||||||
Future<void> tapViewPropertiesButton() async {
|
Future<void> tapViewPropertiesButton() async {
|
||||||
final findSettingItem = find.byType(DatabaseSettingItem);
|
final findSettingItem = find.byType(DatabaseSettingListPopover);
|
||||||
final findLayoutButton = find.byWidgetPredicate(
|
final findLayoutButton = find.byWidgetPredicate(
|
||||||
(widget) =>
|
(widget) =>
|
||||||
widget is FlowyText &&
|
widget is FlowyText &&
|
||||||
@ -1149,7 +1148,7 @@ extension AppFlowyDatabaseTest on WidgetTester {
|
|||||||
|
|
||||||
/// Should call [tapDatabaseSettingButton] first.
|
/// Should call [tapDatabaseSettingButton] first.
|
||||||
Future<void> tapDatabaseLayoutButton() async {
|
Future<void> tapDatabaseLayoutButton() async {
|
||||||
final findSettingItem = find.byType(DatabaseSettingItem);
|
final findSettingItem = find.byType(DatabaseSettingListPopover);
|
||||||
final findLayoutButton = find.byWidgetPredicate(
|
final findLayoutButton = find.byWidgetPredicate(
|
||||||
(widget) =>
|
(widget) =>
|
||||||
widget is FlowyText &&
|
widget is FlowyText &&
|
||||||
@ -1165,7 +1164,7 @@ extension AppFlowyDatabaseTest on WidgetTester {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> tapCalendarLayoutSettingButton() async {
|
Future<void> tapCalendarLayoutSettingButton() async {
|
||||||
final findSettingItem = find.byType(DatabaseSettingItem);
|
final findSettingItem = find.byType(DatabaseSettingListPopover);
|
||||||
final findLayoutButton = find.byWidgetPredicate(
|
final findLayoutButton = find.byWidgetPredicate(
|
||||||
(widget) =>
|
(widget) =>
|
||||||
widget is FlowyText &&
|
widget is FlowyText &&
|
||||||
@ -1505,7 +1504,7 @@ extension AppFlowyDatabaseTest on WidgetTester {
|
|||||||
) async {
|
) async {
|
||||||
final field = find.byWidgetPredicate(
|
final field = find.byWidgetPredicate(
|
||||||
(widget) =>
|
(widget) =>
|
||||||
widget is GridPropertyCell && widget.fieldInfo.name == fieldName,
|
widget is DatabasePropertyCell && widget.fieldInfo.name == fieldName,
|
||||||
);
|
);
|
||||||
final toggleVisibilityButton =
|
final toggleVisibilityButton =
|
||||||
find.descendant(of: field, matching: find.byType(FlowyIconButton));
|
find.descendant(of: field, matching: find.byType(FlowyIconButton));
|
||||||
|
@ -25,34 +25,44 @@ class DatabasePropertyBloc
|
|||||||
) {
|
) {
|
||||||
on<DatabasePropertyEvent>(
|
on<DatabasePropertyEvent>(
|
||||||
(event, emit) async {
|
(event, emit) async {
|
||||||
await event.map(
|
await event.when(
|
||||||
initial: (_Initial value) {
|
initial: () {
|
||||||
_startListening();
|
_startListening();
|
||||||
},
|
},
|
||||||
setFieldVisibility: (_SetFieldVisibility value) async {
|
setFieldVisibility: (fieldId, visibility) async {
|
||||||
final fieldSettingsSvc = FieldSettingsBackendService(
|
final fieldSettingsSvc = FieldSettingsBackendService(
|
||||||
viewId: viewId,
|
viewId: viewId,
|
||||||
);
|
);
|
||||||
|
|
||||||
final result = await fieldSettingsSvc.updateFieldSettings(
|
final result = await fieldSettingsSvc.updateFieldSettings(
|
||||||
fieldId: value.fieldId,
|
fieldId: fieldId,
|
||||||
fieldVisibility: value.visibility,
|
fieldVisibility: visibility,
|
||||||
);
|
);
|
||||||
|
|
||||||
result.fold((l) => null, (err) => Log.error(err));
|
result.fold((l) => null, (err) => Log.error(err));
|
||||||
},
|
},
|
||||||
didReceiveFieldUpdate: (_DidReceiveFieldUpdate value) {
|
didReceiveFieldUpdate: (fields) {
|
||||||
emit(state.copyWith(fieldContexts: value.fields));
|
emit(state.copyWith(fieldContexts: fields));
|
||||||
},
|
},
|
||||||
moveField: (_MoveField value) async {
|
moveField: (fieldId, fromIndex, toIndex) async {
|
||||||
|
if (fromIndex < toIndex) {
|
||||||
|
toIndex--;
|
||||||
|
}
|
||||||
|
final fieldContexts = List<FieldInfo>.from(state.fieldContexts);
|
||||||
|
fieldContexts.insert(
|
||||||
|
toIndex,
|
||||||
|
fieldContexts.removeAt(fromIndex),
|
||||||
|
);
|
||||||
|
emit(state.copyWith(fieldContexts: fieldContexts));
|
||||||
|
|
||||||
final fieldBackendService = FieldBackendService(
|
final fieldBackendService = FieldBackendService(
|
||||||
viewId: viewId,
|
viewId: viewId,
|
||||||
fieldId: value.fieldId,
|
fieldId: fieldId,
|
||||||
);
|
);
|
||||||
|
|
||||||
final result = await fieldBackendService.moveField(
|
final result = await fieldBackendService.moveField(
|
||||||
value.fromIndex,
|
fromIndex,
|
||||||
value.toIndex,
|
toIndex,
|
||||||
);
|
);
|
||||||
|
|
||||||
result.fold((l) => null, (r) => Log.error(r));
|
result.fold((l) => null, (r) => Log.error(r));
|
||||||
|
@ -228,6 +228,7 @@ class LayoutDateField extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return AppFlowyPopover(
|
return AppFlowyPopover(
|
||||||
direction: PopoverDirection.leftWithTopAligned,
|
direction: PopoverDirection.leftWithTopAligned,
|
||||||
|
triggerActions: PopoverTriggerFlags.hover | PopoverTriggerFlags.click,
|
||||||
constraints: BoxConstraints.loose(const Size(300, 400)),
|
constraints: BoxConstraints.loose(const Size(300, 400)),
|
||||||
mutex: popoverMutex,
|
mutex: popoverMutex,
|
||||||
offset: const Offset(-16, 0),
|
offset: const Offset(-16, 0),
|
||||||
@ -346,6 +347,7 @@ class FirstDayOfWeek extends StatelessWidget {
|
|||||||
return AppFlowyPopover(
|
return AppFlowyPopover(
|
||||||
direction: PopoverDirection.leftWithTopAligned,
|
direction: PopoverDirection.leftWithTopAligned,
|
||||||
constraints: BoxConstraints.loose(const Size(300, 400)),
|
constraints: BoxConstraints.loose(const Size(300, 400)),
|
||||||
|
triggerActions: PopoverTriggerFlags.hover | PopoverTriggerFlags.click,
|
||||||
mutex: popoverMutex,
|
mutex: popoverMutex,
|
||||||
offset: const Offset(-16, 0),
|
offset: const Offset(-16, 0),
|
||||||
popupBuilder: (context) {
|
popupBuilder: (context) {
|
||||||
|
@ -1,75 +0,0 @@
|
|||||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
|
||||||
import 'package:appflowy/plugins/database_view/application/database_controller.dart';
|
|
||||||
import 'package:flowy_infra/theme_extension.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 '../../grid/presentation/layout/sizes.dart';
|
|
||||||
import 'setting_button.dart';
|
|
||||||
|
|
||||||
class DatabaseSettingList extends StatelessWidget {
|
|
||||||
final DatabaseController databaseContoller;
|
|
||||||
final Function(DatabaseSettingAction, DatabaseController) onAction;
|
|
||||||
const DatabaseSettingList({
|
|
||||||
required this.databaseContoller,
|
|
||||||
required this.onAction,
|
|
||||||
Key? key,
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final cells = actionsForDatabaseLayout(databaseContoller.databaseLayout)
|
|
||||||
.map((action) {
|
|
||||||
return DatabaseSettingItem(
|
|
||||||
action: action,
|
|
||||||
onAction: (action) => onAction(action, databaseContoller),
|
|
||||||
);
|
|
||||||
}).toList();
|
|
||||||
|
|
||||||
return 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 DatabaseSettingItem extends StatelessWidget {
|
|
||||||
final DatabaseSettingAction action;
|
|
||||||
final Function(DatabaseSettingAction) onAction;
|
|
||||||
|
|
||||||
const DatabaseSettingItem({
|
|
||||||
required this.action,
|
|
||||||
required this.onAction,
|
|
||||||
Key? key,
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return SizedBox(
|
|
||||||
height: GridSize.popoverItemHeight,
|
|
||||||
child: FlowyButton(
|
|
||||||
hoverColor: AFThemeExtension.of(context).lightGreyHover,
|
|
||||||
text: FlowyText.medium(
|
|
||||||
action.title(),
|
|
||||||
color: AFThemeExtension.of(context).textColor,
|
|
||||||
),
|
|
||||||
onTap: () => onAction(action),
|
|
||||||
leftIcon: FlowySvg(
|
|
||||||
action.iconData(),
|
|
||||||
color: Theme.of(context).iconTheme.color,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -11,12 +11,10 @@ import 'package:flowy_infra/size.dart';
|
|||||||
import 'package:flowy_infra/theme_extension.dart';
|
import 'package:flowy_infra/theme_extension.dart';
|
||||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
|
||||||
|
|
||||||
import '../../grid/presentation/layout/sizes.dart';
|
import '../../grid/presentation/layout/sizes.dart';
|
||||||
import '../../grid/presentation/widgets/toolbar/grid_layout.dart';
|
import '../../grid/presentation/widgets/toolbar/grid_layout.dart';
|
||||||
import '../field/grid_property.dart';
|
import 'setting_property_list.dart';
|
||||||
import 'database_setting.dart';
|
|
||||||
|
|
||||||
class SettingButton extends StatefulWidget {
|
class SettingButton extends StatefulWidget {
|
||||||
final DatabaseController databaseController;
|
final DatabaseController databaseController;
|
||||||
@ -39,7 +37,6 @@ class _SettingButtonState extends State<SettingButton> {
|
|||||||
constraints: BoxConstraints.loose(const Size(200, 400)),
|
constraints: BoxConstraints.loose(const Size(200, 400)),
|
||||||
direction: PopoverDirection.bottomWithCenterAligned,
|
direction: PopoverDirection.bottomWithCenterAligned,
|
||||||
offset: const Offset(0, 8),
|
offset: const Offset(0, 8),
|
||||||
margin: EdgeInsets.zero,
|
|
||||||
triggerActions: PopoverTriggerFlags.none,
|
triggerActions: PopoverTriggerFlags.none,
|
||||||
child: FlowyTextButton(
|
child: FlowyTextButton(
|
||||||
LocaleKeys.settings_title.tr(),
|
LocaleKeys.settings_title.tr(),
|
||||||
@ -53,7 +50,7 @@ class _SettingButtonState extends State<SettingButton> {
|
|||||||
onPressed: () => _popoverController.show(),
|
onPressed: () => _popoverController.show(),
|
||||||
),
|
),
|
||||||
popupBuilder: (BuildContext context) {
|
popupBuilder: (BuildContext context) {
|
||||||
return _DatabaseSettingListPopover(
|
return DatabaseSettingListPopover(
|
||||||
databaseController: widget.databaseController,
|
databaseController: widget.databaseController,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -61,10 +58,10 @@ class _SettingButtonState extends State<SettingButton> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _DatabaseSettingListPopover extends StatefulWidget {
|
class DatabaseSettingListPopover extends StatefulWidget {
|
||||||
final DatabaseController databaseController;
|
final DatabaseController databaseController;
|
||||||
|
|
||||||
const _DatabaseSettingListPopover({
|
const DatabaseSettingListPopover({
|
||||||
required this.databaseController,
|
required this.databaseController,
|
||||||
Key? key,
|
Key? key,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
@ -74,59 +71,40 @@ class _DatabaseSettingListPopover extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _DatabaseSettingListPopoverState
|
class _DatabaseSettingListPopoverState
|
||||||
extends State<_DatabaseSettingListPopover> {
|
extends State<DatabaseSettingListPopover> {
|
||||||
DatabaseSettingAction? _action;
|
late final PopoverMutex popoverMutex;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
popoverMutex = PopoverMutex();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
if (_action == null) {
|
final cells =
|
||||||
return DatabaseSettingList(
|
actionsForDatabaseLayout(widget.databaseController.databaseLayout)
|
||||||
databaseContoller: widget.databaseController,
|
.map(
|
||||||
onAction: (action, settingContext) {
|
(action) => action.build(
|
||||||
setState(() {
|
context,
|
||||||
_action = action;
|
widget.databaseController,
|
||||||
});
|
popoverMutex,
|
||||||
},
|
|
||||||
).padding(all: 6.0);
|
|
||||||
} else {
|
|
||||||
switch (_action!) {
|
|
||||||
case DatabaseSettingAction.showLayout:
|
|
||||||
return DatabaseLayoutList(
|
|
||||||
viewId: widget.databaseController.viewId,
|
|
||||||
currentLayout: widget.databaseController.databaseLayout,
|
|
||||||
);
|
|
||||||
case DatabaseSettingAction.showGroup:
|
|
||||||
return DatabaseGroupList(
|
|
||||||
viewId: widget.databaseController.viewId,
|
|
||||||
fieldController: widget.databaseController.fieldController,
|
|
||||||
onDismissed: () {
|
|
||||||
// widget.popoverController.close();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
case DatabaseSettingAction.showProperties:
|
|
||||||
return Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
DatabasePropertyList(
|
|
||||||
viewId: widget.databaseController.viewId,
|
|
||||||
fieldController: widget.databaseController.fieldController,
|
|
||||||
),
|
),
|
||||||
FlowyText.regular(
|
)
|
||||||
LocaleKeys.grid_settings_reorderPropertiesTooltip.tr(),
|
.toList();
|
||||||
),
|
|
||||||
const VSpace(8),
|
return ListView.separated(
|
||||||
],
|
shrinkWrap: true,
|
||||||
);
|
controller: ScrollController(),
|
||||||
case DatabaseSettingAction.showCalendarLayout:
|
itemCount: cells.length,
|
||||||
return CalendarLayoutSetting(
|
separatorBuilder: (context, index) {
|
||||||
viewId: widget.databaseController.viewId,
|
return VSpace(GridSize.typeOptionSeparatorHeight);
|
||||||
fieldController: widget.databaseController.fieldController,
|
},
|
||||||
calendarSettingController: ICalendarSettingImpl(
|
physics: StyledScrollPhysics(),
|
||||||
widget.databaseController,
|
itemBuilder: (BuildContext context, int index) {
|
||||||
),
|
return cells[index];
|
||||||
);
|
},
|
||||||
}
|
);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,6 +157,58 @@ extension DatabaseSettingActionExtension on DatabaseSettingAction {
|
|||||||
return LocaleKeys.calendar_settings_name.tr();
|
return LocaleKeys.calendar_settings_name.tr();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget build(
|
||||||
|
BuildContext context,
|
||||||
|
DatabaseController databaseController,
|
||||||
|
PopoverMutex popoverMutex,
|
||||||
|
) {
|
||||||
|
final popover = switch (this) {
|
||||||
|
DatabaseSettingAction.showLayout => DatabaseLayoutList(
|
||||||
|
viewId: databaseController.viewId,
|
||||||
|
currentLayout: databaseController.databaseLayout,
|
||||||
|
),
|
||||||
|
DatabaseSettingAction.showGroup => DatabaseGroupList(
|
||||||
|
viewId: databaseController.viewId,
|
||||||
|
fieldController: databaseController.fieldController,
|
||||||
|
onDismissed: () {},
|
||||||
|
),
|
||||||
|
DatabaseSettingAction.showProperties => DatabasePropertyList(
|
||||||
|
viewId: databaseController.viewId,
|
||||||
|
fieldController: databaseController.fieldController,
|
||||||
|
),
|
||||||
|
DatabaseSettingAction.showCalendarLayout => CalendarLayoutSetting(
|
||||||
|
viewId: databaseController.viewId,
|
||||||
|
fieldController: databaseController.fieldController,
|
||||||
|
calendarSettingController: ICalendarSettingImpl(
|
||||||
|
databaseController,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
return AppFlowyPopover(
|
||||||
|
triggerActions: PopoverTriggerFlags.hover | PopoverTriggerFlags.click,
|
||||||
|
direction: PopoverDirection.leftWithTopAligned,
|
||||||
|
mutex: popoverMutex,
|
||||||
|
margin: EdgeInsets.zero,
|
||||||
|
offset: const Offset(-16, 0),
|
||||||
|
child: SizedBox(
|
||||||
|
height: GridSize.popoverItemHeight,
|
||||||
|
child: FlowyButton(
|
||||||
|
hoverColor: AFThemeExtension.of(context).lightGreyHover,
|
||||||
|
text: FlowyText.medium(
|
||||||
|
title(),
|
||||||
|
color: AFThemeExtension.of(context).textColor,
|
||||||
|
),
|
||||||
|
leftIcon: FlowySvg(
|
||||||
|
iconData(),
|
||||||
|
color: Theme.of(context).iconTheme.color,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
popupBuilder: (context) => popover,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the list of actions that should be shown for the given database layout.
|
/// Returns the list of actions that should be shown for the given database layout.
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||||
import 'package:appflowy/plugins/database_view/application/field/field_controller.dart';
|
import 'package:appflowy/plugins/database_view/application/field/field_controller.dart';
|
||||||
import 'package:appflowy/plugins/database_view/application/field/field_info.dart';
|
import 'package:appflowy/plugins/database_view/application/field/field_info.dart';
|
||||||
@ -7,12 +9,12 @@ import 'package:appflowy/plugins/database_view/grid/presentation/widgets/header/
|
|||||||
import 'package:appflowy/startup/startup.dart';
|
import 'package:appflowy/startup/startup.dart';
|
||||||
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
|
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
|
||||||
import 'package:appflowy_popover/appflowy_popover.dart';
|
import 'package:appflowy_popover/appflowy_popover.dart';
|
||||||
|
import 'package:collection/collection.dart';
|
||||||
|
|
||||||
import 'package:flowy_infra/theme_extension.dart';
|
import 'package:flowy_infra/theme_extension.dart';
|
||||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:reorderables/reorderables.dart';
|
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
|
|
||||||
import '../../grid/presentation/layout/sizes.dart';
|
import '../../grid/presentation/layout/sizes.dart';
|
||||||
@ -44,29 +46,43 @@ class _DatabasePropertyListState extends State<DatabasePropertyList> {
|
|||||||
)..add(const DatabasePropertyEvent.initial()),
|
)..add(const DatabasePropertyEvent.initial()),
|
||||||
child: BlocBuilder<DatabasePropertyBloc, DatabasePropertyState>(
|
child: BlocBuilder<DatabasePropertyBloc, DatabasePropertyState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
final cells = state.fieldContexts.map((field) {
|
final cells = state.fieldContexts.mapIndexed((index, field) {
|
||||||
return GridPropertyCell(
|
return DatabasePropertyCell(
|
||||||
key: ValueKey(field.id),
|
key: ValueKey(field.id),
|
||||||
viewId: widget.viewId,
|
viewId: widget.viewId,
|
||||||
fieldInfo: field,
|
fieldInfo: field,
|
||||||
popoverMutex: _popoverMutex,
|
popoverMutex: _popoverMutex,
|
||||||
|
index: index,
|
||||||
);
|
);
|
||||||
}).toList();
|
}).toList();
|
||||||
|
|
||||||
return ReorderableColumn(
|
return ReorderableListView(
|
||||||
needsLongPressDraggable: false,
|
proxyDecorator: (child, index, _) => Material(
|
||||||
buildDraggableFeedback: (context, constraints, child) =>
|
color: Colors.transparent,
|
||||||
ConstrainedBox(
|
child: Stack(
|
||||||
constraints: constraints,
|
children: [
|
||||||
child: Material(color: Colors.transparent, child: child),
|
child,
|
||||||
),
|
MouseRegion(
|
||||||
onReorder: (from, to) => context.read<DatabasePropertyBloc>().add(
|
cursor: Platform.isWindows
|
||||||
DatabasePropertyEvent.moveField(
|
? SystemMouseCursors.click
|
||||||
fieldId: cells[from].fieldInfo.id,
|
: SystemMouseCursors.grabbing,
|
||||||
fromIndex: from,
|
child: const SizedBox.expand(),
|
||||||
toIndex: to,
|
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
buildDefaultDragHandles: false,
|
||||||
|
shrinkWrap: true,
|
||||||
|
onReorder: (from, to) {
|
||||||
|
context.read<DatabasePropertyBloc>().add(
|
||||||
|
DatabasePropertyEvent.moveField(
|
||||||
|
fieldId: cells[from].fieldInfo.id,
|
||||||
|
fromIndex: from,
|
||||||
|
toIndex: to,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
onReorderStart: (_) => _popoverMutex.close(),
|
||||||
padding: const EdgeInsets.symmetric(vertical: 6.0),
|
padding: const EdgeInsets.symmetric(vertical: 6.0),
|
||||||
children: cells,
|
children: cells,
|
||||||
);
|
);
|
||||||
@ -77,23 +93,25 @@ class _DatabasePropertyListState extends State<DatabasePropertyList> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@visibleForTesting
|
@visibleForTesting
|
||||||
class GridPropertyCell extends StatefulWidget {
|
class DatabasePropertyCell extends StatefulWidget {
|
||||||
final FieldInfo fieldInfo;
|
final FieldInfo fieldInfo;
|
||||||
final String viewId;
|
final String viewId;
|
||||||
final PopoverMutex popoverMutex;
|
final PopoverMutex popoverMutex;
|
||||||
|
final int index;
|
||||||
|
|
||||||
const GridPropertyCell({
|
const DatabasePropertyCell({
|
||||||
super.key,
|
super.key,
|
||||||
required this.fieldInfo,
|
required this.fieldInfo,
|
||||||
required this.viewId,
|
required this.viewId,
|
||||||
required this.popoverMutex,
|
required this.popoverMutex,
|
||||||
|
required this.index,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<GridPropertyCell> createState() => _GridPropertyCellState();
|
State<DatabasePropertyCell> createState() => _DatabasePropertyCellState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _GridPropertyCellState extends State<GridPropertyCell> {
|
class _DatabasePropertyCellState extends State<DatabasePropertyCell> {
|
||||||
final PopoverController _popoverController = PopoverController();
|
final PopoverController _popoverController = PopoverController();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -109,7 +127,7 @@ class _GridPropertyCellState extends State<GridPropertyCell> {
|
|||||||
return AppFlowyPopover(
|
return AppFlowyPopover(
|
||||||
mutex: widget.popoverMutex,
|
mutex: widget.popoverMutex,
|
||||||
controller: _popoverController,
|
controller: _popoverController,
|
||||||
offset: const Offset(8, 0),
|
offset: const Offset(-8, 0),
|
||||||
direction: PopoverDirection.leftWithTopAligned,
|
direction: PopoverDirection.leftWithTopAligned,
|
||||||
constraints: BoxConstraints.loose(const Size(240, 400)),
|
constraints: BoxConstraints.loose(const Size(240, 400)),
|
||||||
triggerActions: PopoverTriggerFlags.none,
|
triggerActions: PopoverTriggerFlags.none,
|
||||||
@ -122,9 +140,31 @@ class _GridPropertyCellState extends State<GridPropertyCell> {
|
|||||||
widget.fieldInfo.name,
|
widget.fieldInfo.name,
|
||||||
color: AFThemeExtension.of(context).textColor,
|
color: AFThemeExtension.of(context).textColor,
|
||||||
),
|
),
|
||||||
leftIcon: FlowySvg(
|
leftIconSize: const Size(36, 18),
|
||||||
widget.fieldInfo.fieldType.icon(),
|
leftIcon: Row(
|
||||||
color: Theme.of(context).iconTheme.color,
|
children: [
|
||||||
|
ReorderableDragStartListener(
|
||||||
|
index: widget.index,
|
||||||
|
child: MouseRegion(
|
||||||
|
cursor: Platform.isWindows
|
||||||
|
? SystemMouseCursors.click
|
||||||
|
: SystemMouseCursors.grab,
|
||||||
|
child: SizedBox(
|
||||||
|
width: 14,
|
||||||
|
height: 14,
|
||||||
|
child: FlowySvg(
|
||||||
|
FlowySvgs.drag_element_s,
|
||||||
|
color: Theme.of(context).iconTheme.color,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const HSpace(6.0),
|
||||||
|
FlowySvg(
|
||||||
|
widget.fieldInfo.fieldType.icon(),
|
||||||
|
color: Theme.of(context).iconTheme.color,
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
rightIcon: FlowyIconButton(
|
rightIcon: FlowyIconButton(
|
||||||
hoverColor: Colors.transparent,
|
hoverColor: Colors.transparent,
|
Loading…
Reference in New Issue
Block a user