diff --git a/frontend/appflowy_flutter/integration_test/util/database_test_op.dart b/frontend/appflowy_flutter/integration_test/util/database_test_op.dart index ce9eb37896..c6e64ff41c 100644 --- a/frontend/appflowy_flutter/integration_test/util/database_test_op.dart +++ b/frontend/appflowy_flutter/integration_test/util/database_test_op.dart @@ -31,7 +31,7 @@ import 'package:appflowy/plugins/database_view/grid/presentation/widgets/sort/so import 'package:appflowy/plugins/database_view/grid/presentation/widgets/toolbar/filter_button.dart'; import 'package:appflowy/plugins/database_view/grid/presentation/widgets/toolbar/grid_layout.dart'; import 'package:appflowy/plugins/database_view/grid/presentation/widgets/toolbar/sort_button.dart'; -import 'package:appflowy/plugins/database_view/tar_bar/tab_bar_view.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/widgets/database_layout_ext.dart'; import 'package:appflowy/plugins/database_view/widgets/row/accessory/cell_accessory.dart'; diff --git a/frontend/appflowy_flutter/lib/plugins/database_view/board/presentation/toolbar/board_setting_bar.dart b/frontend/appflowy_flutter/lib/plugins/database_view/board/presentation/toolbar/board_setting_bar.dart index f3c357749d..0944e5e5d7 100644 --- a/frontend/appflowy_flutter/lib/plugins/database_view/board/presentation/toolbar/board_setting_bar.dart +++ b/frontend/appflowy_flutter/lib/plugins/database_view/board/presentation/toolbar/board_setting_bar.dart @@ -12,10 +12,10 @@ class BoardSettingBar extends StatelessWidget { @override Widget build(BuildContext context) { return SizedBox( - height: 40, + height: 20, child: Row( + mainAxisAlignment: MainAxisAlignment.end, children: [ - const Spacer(), SettingButton(databaseController: databaseController), ], ), diff --git a/frontend/appflowy_flutter/lib/plugins/database_view/calendar/presentation/calendar_page.dart b/frontend/appflowy_flutter/lib/plugins/database_view/calendar/presentation/calendar_page.dart index a8a9ecd123..4cec3ee78a 100644 --- a/frontend/appflowy_flutter/lib/plugins/database_view/calendar/presentation/calendar_page.dart +++ b/frontend/appflowy_flutter/lib/plugins/database_view/calendar/presentation/calendar_page.dart @@ -1,7 +1,6 @@ import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/plugins/database_view/application/database_controller.dart'; import 'package:appflowy/plugins/database_view/calendar/application/calendar_bloc.dart'; -import 'package:appflowy/plugins/database_view/grid/presentation/layout/sizes.dart'; import 'package:appflowy/plugins/database_view/tar_bar/tab_bar_view.dart'; import 'package:appflowy_backend/protobuf/flowy-database2/calendar_entities.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart'; @@ -166,14 +165,13 @@ class _CalendarPageState extends State { return const Center( child: CircularProgressIndicator.adaptive(), ); - } else { - return _buildCalendar( - context, - _eventController, - state.settings - .foldLeft(0, (previous, a) => a.firstDayOfWeek), - ); } + return _buildCalendar( + context, + _eventController, + state.settings + .foldLeft(0, (previous, a) => a.firstDayOfWeek), + ); }, ); }, @@ -189,7 +187,7 @@ class _CalendarPageState extends State { int firstDayOfWeek, ) { return Padding( - padding: GridSize.contentInsets, + padding: CalendarSize.contentInsets, child: LayoutBuilder( // must specify MonthView width for useAvailableVerticalSpace to work properly builder: (context, constraints) => MonthView( diff --git a/frontend/appflowy_flutter/lib/plugins/database_view/calendar/presentation/layout/sizes.dart b/frontend/appflowy_flutter/lib/plugins/database_view/calendar/presentation/layout/sizes.dart index 958cbd8d67..3840f7133e 100644 --- a/frontend/appflowy_flutter/lib/plugins/database_view/calendar/presentation/layout/sizes.dart +++ b/frontend/appflowy_flutter/lib/plugins/database_view/calendar/presentation/layout/sizes.dart @@ -1,8 +1,18 @@ +import 'package:appflowy/plugins/database_view/grid/presentation/layout/sizes.dart'; import 'package:flutter/widgets.dart'; class CalendarSize { static double scale = 1; + static double get headerContainerPadding => 12 * scale; + + static EdgeInsets get contentInsets => EdgeInsets.fromLTRB( + GridSize.leadingHeaderPadding, + CalendarSize.headerContainerPadding, + GridSize.leadingHeaderPadding, + CalendarSize.headerContainerPadding, + ); + static double get scrollBarSize => 8 * scale; static double get navigatorButtonWidth => 20 * scale; static double get navigatorButtonHeight => 25 * scale; diff --git a/frontend/appflowy_flutter/lib/plugins/database_view/calendar/presentation/toolbar/calendar_setting_bar.dart b/frontend/appflowy_flutter/lib/plugins/database_view/calendar/presentation/toolbar/calendar_setting_bar.dart index ec74f739e6..c244e8d9a7 100644 --- a/frontend/appflowy_flutter/lib/plugins/database_view/calendar/presentation/toolbar/calendar_setting_bar.dart +++ b/frontend/appflowy_flutter/lib/plugins/database_view/calendar/presentation/toolbar/calendar_setting_bar.dart @@ -8,6 +8,7 @@ import 'package:appflowy/plugins/database_view/widgets/setting/setting_button.da import 'package:appflowy_backend/protobuf/flowy-database2/calendar_entities.pb.dart'; import 'package:appflowy_popover/appflowy_popover.dart'; import 'package:easy_localization/easy_localization.dart'; +import 'package:flowy_infra/size.dart'; import 'package:flowy_infra/theme_extension.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flutter/material.dart'; @@ -23,11 +24,12 @@ class CalendarSettingBar extends StatelessWidget { @override Widget build(BuildContext context) { return SizedBox( - height: 40, + height: 20, child: Row( mainAxisAlignment: MainAxisAlignment.end, children: [ UnscheduleEventsButton(databaseController: databaseController), + const HSpace(2), SettingButton( databaseController: databaseController, ), @@ -82,9 +84,14 @@ class _UnscheduleEventsButtonState extends State { builder: (context, state) { return FlowyTextButton( "${LocaleKeys.calendar_settings_noDateTitle.tr()} (${state.unscheduleEvents.length})", + fontSize: FontSizes.s11, + fontColor: AFThemeExtension.of(context).textColor, + fontWeight: FontWeight.w400, fillColor: Colors.transparent, hoverColor: AFThemeExtension.of(context).lightGreyHover, - padding: GridSize.typeOptionContentInsets, + padding: GridSize.toolbarSettingButtonInsets, + radius: Corners.s4Border, + onPressed: () => _popoverController.show(), ); }, ), diff --git a/frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/layout/sizes.dart b/frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/layout/sizes.dart index 672e0f7507..1acb6eccdc 100755 --- a/frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/layout/sizes.dart +++ b/frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/layout/sizes.dart @@ -30,6 +30,9 @@ class GridSize { static EdgeInsets get typeOptionContentInsets => const EdgeInsets.all(4); + static EdgeInsets get toolbarSettingButtonInsets => + const EdgeInsets.symmetric(horizontal: 8, vertical: 2); + static EdgeInsets get footerContentInsets => EdgeInsets.fromLTRB( GridSize.leadingHeaderPadding, GridSize.headerContainerPadding, diff --git a/frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/toolbar/filter_button.dart b/frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/toolbar/filter_button.dart index 8d32ff981f..fd4fdc0960 100644 --- a/frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/toolbar/filter_button.dart +++ b/frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/toolbar/filter_button.dart @@ -2,6 +2,7 @@ import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/plugins/database_view/grid/application/filter/filter_menu_bloc.dart'; import 'package:appflowy_popover/appflowy_popover.dart'; import 'package:easy_localization/easy_localization.dart'; +import 'package:flowy_infra/size.dart'; import 'package:flowy_infra/theme_extension.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flutter/material.dart'; @@ -30,23 +31,23 @@ class _FilterButtonState extends State { return _wrapPopover( context, - SizedBox( - height: 26, - child: FlowyTextButton( - LocaleKeys.grid_settings_filter.tr(), - fontColor: textColor, - fillColor: Colors.transparent, - hoverColor: AFThemeExtension.of(context).lightGreyHover, - padding: GridSize.typeOptionContentInsets, - onPressed: () { - final bloc = context.read(); - if (bloc.state.filters.isEmpty) { - _popoverController.show(); - } else { - bloc.add(const GridFilterMenuEvent.toggleMenu()); - } - }, - ), + FlowyTextButton( + LocaleKeys.grid_settings_filter.tr(), + fontColor: textColor, + fontSize: FontSizes.s11, + fontWeight: FontWeight.w400, + fillColor: Colors.transparent, + hoverColor: AFThemeExtension.of(context).lightGreyHover, + padding: GridSize.toolbarSettingButtonInsets, + radius: Corners.s4Border, + onPressed: () { + final bloc = context.read(); + if (bloc.state.filters.isEmpty) { + _popoverController.show(); + } else { + bloc.add(const GridFilterMenuEvent.toggleMenu()); + } + }, ), ); }, diff --git a/frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/toolbar/grid_setting_bar.dart b/frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/toolbar/grid_setting_bar.dart index 960d2ba102..aa48f2992a 100644 --- a/frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/toolbar/grid_setting_bar.dart +++ b/frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/toolbar/grid_setting_bar.dart @@ -2,8 +2,8 @@ import 'package:appflowy/plugins/database_view/application/database_controller.d import 'package:appflowy/plugins/database_view/grid/application/filter/filter_menu_bloc.dart'; import 'package:appflowy/plugins/database_view/grid/application/sort/sort_menu_bloc.dart'; import 'package:appflowy/plugins/database_view/grid/presentation/grid_page.dart'; -import 'package:appflowy/plugins/database_view/grid/presentation/layout/sizes.dart'; import 'package:appflowy/plugins/database_view/widgets/setting/setting_button.dart'; +import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -52,23 +52,22 @@ class GridSettingBar extends StatelessWidget { builder: (context, value, child) { if (value) { return const SizedBox.shrink(); - } else { - return SizedBox( - height: 40, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - SizedBox(width: GridSize.leadingHeaderPadding), - const Spacer(), - const FilterButton(), - const SortButton(), - SettingButton( - databaseController: controller, - ), - ], - ), - ); } + return SizedBox( + height: 20, + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + const FilterButton(), + const HSpace(2), + const SortButton(), + const HSpace(2), + SettingButton( + databaseController: controller, + ), + ], + ), + ); }, ), ), diff --git a/frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/toolbar/sort_button.dart b/frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/toolbar/sort_button.dart index c86982db15..0a3b62a762 100644 --- a/frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/toolbar/sort_button.dart +++ b/frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/toolbar/sort_button.dart @@ -2,6 +2,7 @@ import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/plugins/database_view/grid/application/sort/sort_menu_bloc.dart'; import 'package:appflowy_popover/appflowy_popover.dart'; import 'package:easy_localization/easy_localization.dart'; +import 'package:flowy_infra/size.dart'; import 'package:flowy_infra/theme_extension.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flutter/material.dart'; @@ -30,23 +31,23 @@ class _SortButtonState extends State { return wrapPopover( context, - SizedBox( - height: 26, - child: FlowyTextButton( - LocaleKeys.grid_settings_sort.tr(), - fontColor: textColor, - fillColor: Colors.transparent, - hoverColor: AFThemeExtension.of(context).lightGreyHover, - padding: GridSize.typeOptionContentInsets, - onPressed: () { - final bloc = context.read(); - if (bloc.state.sortInfos.isEmpty) { - _popoverController.show(); - } else { - bloc.add(const SortMenuEvent.toggleMenu()); - } - }, - ), + FlowyTextButton( + LocaleKeys.grid_settings_sort.tr(), + fontColor: textColor, + fontSize: FontSizes.s11, + fontWeight: FontWeight.w400, + fillColor: Colors.transparent, + hoverColor: AFThemeExtension.of(context).lightGreyHover, + padding: GridSize.toolbarSettingButtonInsets, + radius: Corners.s4Border, + onPressed: () { + final bloc = context.read(); + if (bloc.state.sortInfos.isEmpty) { + _popoverController.show(); + } else { + bloc.add(const SortMenuEvent.toggleMenu()); + } + }, ), ); }, diff --git a/frontend/appflowy_flutter/lib/plugins/database_view/tar_bar/setting_menu.dart b/frontend/appflowy_flutter/lib/plugins/database_view/tar_bar/setting_menu.dart index 0defa34026..c884f91467 100644 --- a/frontend/appflowy_flutter/lib/plugins/database_view/tar_bar/setting_menu.dart +++ b/frontend/appflowy_flutter/lib/plugins/database_view/tar_bar/setting_menu.dart @@ -1,7 +1,6 @@ import 'package:appflowy/plugins/database_view/application/database_controller.dart'; import 'package:appflowy/plugins/database_view/grid/application/grid_accessory_bloc.dart'; import 'package:appflowy/plugins/database_view/grid/presentation/grid_page.dart'; -import 'package:flowy_infra/theme_extension.dart'; import 'package:flowy_infra_ui/widget/spacing.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -38,7 +37,7 @@ class DatabaseViewSettingExtension extends StatelessWidget { ), ); } else { - return const SizedBox(); + return const SizedBox.shrink(); } }, ), @@ -58,29 +57,18 @@ class _DatabaseViewSettingContent extends StatelessWidget { return BlocBuilder( builder: (context, state) { - final children = [ - Divider( - height: 1.0, - color: AFThemeExtension.of(context).toggleOffFill, - ), - const VSpace(6), - IntrinsicHeight( - child: Row( - children: [ - SortMenu( - fieldController: fieldController, - ), - const HSpace(6), - FilterMenu( - fieldController: fieldController, - ), - ], - ), - ) - ]; - return _wrapPadding( - Column(children: children), + Row( + children: [ + SortMenu( + fieldController: fieldController, + ), + const HSpace(6), + FilterMenu( + fieldController: fieldController, + ), + ], + ), ); }, ); @@ -90,7 +78,7 @@ class _DatabaseViewSettingContent extends StatelessWidget { return Padding( padding: EdgeInsets.symmetric( horizontal: GridSize.leadingHeaderPadding, - vertical: 6, + vertical: 8, ), child: child, ); diff --git a/frontend/appflowy_flutter/lib/plugins/database_view/tar_bar/tab_bar_header.dart b/frontend/appflowy_flutter/lib/plugins/database_view/tar_bar/tab_bar_header.dart new file mode 100644 index 0000000000..9129eebae9 --- /dev/null +++ b/frontend/appflowy_flutter/lib/plugins/database_view/tar_bar/tab_bar_header.dart @@ -0,0 +1,286 @@ +import 'package:appflowy/generated/locale_keys.g.dart'; +import 'package:appflowy/workspace/application/view/view_ext.dart'; +import 'package:appflowy/workspace/presentation/widgets/dialogs.dart'; +import 'package:appflowy/workspace/presentation/widgets/pop_up_action.dart'; +import 'package:appflowy_backend/protobuf/flowy-folder2/protobuf.dart'; +import 'package:appflowy_popover/appflowy_popover.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:flowy_infra/image.dart'; +import 'package:flowy_infra/size.dart'; +import 'package:flowy_infra/theme_extension.dart'; +import 'package:flowy_infra_ui/flowy_infra_ui.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +import '../application/tar_bar_bloc.dart'; +import 'tar_bar_add_button.dart'; + +class TabBarHeader extends StatefulWidget { + const TabBarHeader({super.key}); + + @override + State createState() => _TabBarHeaderState(); +} + +class _TabBarHeaderState extends State { + @override + Widget build(BuildContext context) { + return Stack( + children: [ + Positioned( + bottom: 0, + left: 0, + right: 0, + child: Divider( + color: Theme.of(context).dividerColor, + height: 1, + thickness: 1, + ), + ), + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + BlocBuilder( + builder: (context, state) { + return const Flexible( + child: DatabaseTabBar(), + ); + }, + ), + BlocBuilder( + builder: (context, state) { + return SizedBox( + width: 200, + child: Column( + children: [ + const VSpace(3), + pageSettingBarFromState(state), + ], + ), + ); + }, + ), + ], + ), + ], + ); + } + + Widget pageSettingBarFromState(GridTabBarState state) { + if (state.tabBars.length < state.selectedIndex) { + return const SizedBox.shrink(); + } + final tarBar = state.tabBars[state.selectedIndex]; + final controller = + state.tabBarControllerByViewId[tarBar.viewId]!.controller; + return tarBar.builder.settingBar( + context, + controller, + ); + } +} + +class DatabaseTabBar extends StatefulWidget { + const DatabaseTabBar({super.key}); + + @override + State createState() => _DatabaseTabBarState(); +} + +class _DatabaseTabBarState extends State { + final _scrollController = ScrollController(); + + @override + Widget build(BuildContext context) { + return BlocBuilder( + builder: (context, state) { + final children = state.tabBars.indexed.map((indexed) { + final isSelected = state.selectedIndex == indexed.$1; + final tabBar = indexed.$2; + return DatabaseTabBarItem( + key: ValueKey(tabBar.viewId), + view: tabBar.view, + isSelected: isSelected, + onTap: (selectedView) { + context.read().add( + GridTabBarEvent.selectView(selectedView.id), + ); + }, + ); + }).toList(); + + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Flexible( + child: ListView( + controller: _scrollController, + scrollDirection: Axis.horizontal, + shrinkWrap: true, + children: children, + ), + ), + AddDatabaseViewButton( + onTap: (action) async { + context.read().add( + GridTabBarEvent.createView(action), + ); + }, + ), + ], + ); + }, + ); + } +} + +class DatabaseTabBarItem extends StatelessWidget { + final bool isSelected; + final ViewPB view; + final Function(ViewPB) onTap; + const DatabaseTabBarItem({ + required this.view, + required this.isSelected, + required this.onTap, + super.key, + }); + + @override + Widget build(BuildContext context) { + return ConstrainedBox( + constraints: const BoxConstraints(maxWidth: 160), + child: Stack( + children: [ + SizedBox( + height: 26, + child: TabBarItemButton( + view: view, + isSelected: isSelected, + onTap: () => onTap(view), + ), + ), + if (isSelected) + Positioned( + bottom: 0, + left: 0, + right: 0, + child: Divider( + height: 2, + thickness: 2, + color: Theme.of(context).colorScheme.primary, + ), + ), + ], + ), + ); + } +} + +class TabBarItemButton extends StatelessWidget { + final ViewPB view; + final bool isSelected; + final VoidCallback onTap; + const TabBarItemButton({ + required this.view, + required this.onTap, + super.key, + required this.isSelected, + }); + + @override + Widget build(BuildContext context) { + return PopoverActionList( + direction: PopoverDirection.bottomWithCenterAligned, + actions: TabBarViewAction.values, + buildChild: (controller) { + Color? color; + if (!isSelected) { + color = Theme.of(context).hintColor; + } + if (Theme.of(context).brightness == Brightness.dark) { + color = null; + } + return IntrinsicWidth( + child: FlowyButton( + radius: Corners.s6Border, + hoverColor: AFThemeExtension.of(context).greyHover, + onTap: onTap, + onSecondaryTap: () { + controller.show(); + }, + leftIcon: FlowySvg( + name: view.iconName, + size: const Size(14, 14), + color: color, + ), + text: FlowyText( + view.name, + fontSize: FontSizes.s11, + textAlign: TextAlign.center, + overflow: TextOverflow.ellipsis, + color: color, + fontWeight: isSelected ? null : FontWeight.w400, + ), + ), + ); + }, + onSelected: (action, controller) { + switch (action) { + case TabBarViewAction.rename: + NavigatorTextFieldDialog( + title: LocaleKeys.menuAppHeader_renameDialog.tr(), + value: view.name, + confirm: (newValue) { + context.read().add( + GridTabBarEvent.renameView(view.id, newValue), + ); + }, + ).show(context); + break; + case TabBarViewAction.delete: + NavigatorAlertDialog( + title: LocaleKeys.grid_deleteView.tr(), + confirm: () { + context.read().add( + GridTabBarEvent.deleteView(view.id), + ); + }, + ).show(context); + + break; + } + controller.close(); + }, + ); + } +} + +enum TabBarViewAction implements ActionCell { + rename, + delete; + + @override + String get name { + switch (this) { + case TabBarViewAction.rename: + return LocaleKeys.disclosureAction_rename.tr(); + case TabBarViewAction.delete: + return LocaleKeys.disclosureAction_delete.tr(); + } + } + + Widget icon(Color iconColor) { + switch (this) { + case TabBarViewAction.rename: + return const FlowySvg(name: 'editor/edit'); + case TabBarViewAction.delete: + return const FlowySvg(name: 'editor/delete'); + } + } + + @override + Widget? leftIcon(Color iconColor) => icon(iconColor); + + @override + Widget? rightIcon(Color iconColor) => null; +} diff --git a/frontend/appflowy_flutter/lib/plugins/database_view/tar_bar/tab_bar_view.dart b/frontend/appflowy_flutter/lib/plugins/database_view/tar_bar/tab_bar_view.dart index 0b639cca90..cafc372d8b 100644 --- a/frontend/appflowy_flutter/lib/plugins/database_view/tar_bar/tab_bar_view.dart +++ b/frontend/appflowy_flutter/lib/plugins/database_view/tar_bar/tab_bar_view.dart @@ -1,26 +1,16 @@ -import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/plugins/database_view/application/tar_bar_bloc.dart'; import 'package:appflowy/plugins/util.dart'; import 'package:appflowy/startup/plugin/plugin.dart'; -import 'package:appflowy/workspace/application/view/view_ext.dart'; import 'package:appflowy/workspace/presentation/home/home_stack.dart'; -import 'package:appflowy/workspace/presentation/widgets/dialogs.dart'; import 'package:appflowy/workspace/presentation/widgets/left_bar_item.dart'; -import 'package:appflowy/workspace/presentation/widgets/pop_up_action.dart'; import 'package:appflowy/workspace/presentation/widgets/tab_bar_item.dart'; import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart'; -import 'package:appflowy_popover/appflowy_popover.dart'; -import 'package:easy_localization/easy_localization.dart'; -import 'package:flowy_infra/image.dart'; -import 'package:flowy_infra/size.dart'; -import 'package:flowy_infra/theme_extension.dart'; -import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import '../application/database_controller.dart'; import '../grid/presentation/layout/sizes.dart'; -import 'tar_bar_add_button.dart'; +import 'tab_bar_header.dart'; abstract class DatabaseTabBarItemBuilder { const DatabaseTabBarItemBuilder(); @@ -103,33 +93,16 @@ class _DatabaseTabBarViewState extends State { builder: (_, value, ___) { if (value) { return const SizedBox.shrink(); - } else { - return Row( - children: [ - BlocBuilder( - builder: (context, state) { - return const Flexible( - child: Padding( - padding: EdgeInsets.only(left: 50), - child: DatabaseTabBar(), - ), - ); - }, - ), - BlocBuilder( - builder: (context, state) { - return SizedBox( - width: 300, - child: Padding( - padding: const EdgeInsets.only(right: 50), - child: pageSettingBarFromState(state), - ), - ); - }, - ), - ], - ); } + return SizedBox( + height: 30, + child: Padding( + padding: EdgeInsets.symmetric( + horizontal: GridSize.leadingHeaderPadding, + ), + child: const TabBarHeader(), + ), + ); }, ); }, @@ -170,19 +143,6 @@ class _DatabaseTabBarViewState extends State { }).toList(); } - Widget pageSettingBarFromState(GridTabBarState state) { - if (state.tabBars.length < state.selectedIndex) { - return const SizedBox.shrink(); - } - final tarBar = state.tabBars[state.selectedIndex]; - final controller = - state.tabBarControllerByViewId[tarBar.viewId]!.controller; - return tarBar.builder.settingBar( - context, - controller, - ); - } - Widget pageSettingBarExtensionFromState(GridTabBarState state) { if (state.tabBars.length < state.selectedIndex) { return const SizedBox.shrink(); @@ -253,188 +213,3 @@ class DatabasePluginWidgetBuilder extends PluginWidgetBuilder { @override List get navigationItems => [this]; } - -class DatabaseTabBar extends StatefulWidget { - const DatabaseTabBar({super.key}); - - @override - State createState() => _DatabaseTabBarState(); -} - -class _DatabaseTabBarState extends State { - final _scrollController = ScrollController(); - - @override - Widget build(BuildContext context) { - return BlocBuilder( - builder: (context, state) { - final children = state.tabBars.indexed.map((indexed) { - final isSelected = state.selectedIndex == indexed.$1; - final tabBar = indexed.$2; - return DatabaseTabBarItem( - key: ValueKey(tabBar.viewId), - view: tabBar.view, - isSelected: isSelected, - onTap: (selectedView) { - context.read().add( - GridTabBarEvent.selectView(selectedView.id), - ); - }, - ); - }).toList(); - - return Row( - children: [ - Flexible( - child: SingleChildScrollView( - controller: _scrollController, - scrollDirection: Axis.horizontal, - child: IntrinsicWidth( - child: Row(children: children), - ), - ), - ), - AddDatabaseViewButton( - onTap: (action) async { - context.read().add( - GridTabBarEvent.createView(action), - ); - }, - ), - ], - ); - }, - ); - } -} - -class DatabaseTabBarItem extends StatelessWidget { - final bool isSelected; - final ViewPB view; - final Function(ViewPB) onTap; - const DatabaseTabBarItem({ - required this.view, - required this.isSelected, - required this.onTap, - super.key, - }); - - @override - Widget build(BuildContext context) { - return ConstrainedBox( - constraints: const BoxConstraints(minWidth: 80, maxWidth: 160), - child: IntrinsicWidth( - child: Column( - children: [ - TabBarItemButton( - view: view, - onTap: () => onTap(view), - ), - if (isSelected) - Divider( - height: 1, - thickness: 2, - color: Theme.of(context).colorScheme.secondary, - ), - ], - ), - ), - ); - } -} - -class TabBarItemButton extends StatelessWidget { - final ViewPB view; - final VoidCallback onTap; - const TabBarItemButton({ - required this.view, - required this.onTap, - super.key, - }); - - @override - Widget build(BuildContext context) { - return PopoverActionList( - direction: PopoverDirection.bottomWithCenterAligned, - actions: TabBarViewAction.values, - buildChild: (controller) { - return FlowyButton( - radius: Corners.s5Border, - hoverColor: AFThemeExtension.of(context).greyHover, - onTap: onTap, - onSecondaryTap: () { - controller.show(); - }, - text: FlowyText.medium( - view.name, - maxLines: 1, - textAlign: TextAlign.center, - overflow: TextOverflow.ellipsis, - ), - margin: GridSize.cellContentInsets, - leftIcon: svgWidget( - view.iconName, - color: Theme.of(context).iconTheme.color, - ), - ); - }, - onSelected: (action, controller) { - switch (action) { - case TabBarViewAction.rename: - NavigatorTextFieldDialog( - title: LocaleKeys.menuAppHeader_renameDialog.tr(), - value: view.name, - confirm: (newValue) { - context.read().add( - GridTabBarEvent.renameView(view.id, newValue), - ); - }, - ).show(context); - break; - case TabBarViewAction.delete: - NavigatorAlertDialog( - title: LocaleKeys.grid_deleteView.tr(), - confirm: () { - context.read().add( - GridTabBarEvent.deleteView(view.id), - ); - }, - ).show(context); - - break; - } - controller.close(); - }, - ); - } -} - -enum TabBarViewAction implements ActionCell { - rename, - delete; - - @override - String get name { - switch (this) { - case TabBarViewAction.rename: - return LocaleKeys.disclosureAction_rename.tr(); - case TabBarViewAction.delete: - return LocaleKeys.disclosureAction_delete.tr(); - } - } - - Widget icon(Color iconColor) { - switch (this) { - case TabBarViewAction.rename: - return const FlowySvg(name: 'editor/edit'); - case TabBarViewAction.delete: - return const FlowySvg(name: 'editor/delete'); - } - } - - @override - Widget? leftIcon(Color iconColor) => icon(iconColor); - - @override - Widget? rightIcon(Color iconColor) => null; -} diff --git a/frontend/appflowy_flutter/lib/plugins/database_view/tar_bar/tar_bar_add_button.dart b/frontend/appflowy_flutter/lib/plugins/database_view/tar_bar/tar_bar_add_button.dart index 10d13878c7..0bee6d7fe2 100644 --- a/frontend/appflowy_flutter/lib/plugins/database_view/tar_bar/tar_bar_add_button.dart +++ b/frontend/appflowy_flutter/lib/plugins/database_view/tar_bar/tar_bar_add_button.dart @@ -4,6 +4,7 @@ import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart'; import 'package:appflowy_popover/appflowy_popover.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flowy_infra/image.dart'; +import 'package:flowy_infra/size.dart'; import 'package:flowy_infra/theme_extension.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flowy_infra_ui/style_widget/extension.dart'; @@ -32,13 +33,27 @@ class _AddDatabaseViewButtonState extends State { offset: const Offset(0, 8), margin: EdgeInsets.zero, triggerActions: PopoverTriggerFlags.none, - child: FlowyIconButton( - iconPadding: const EdgeInsets.all(4), - hoverColor: AFThemeExtension.of(context).greyHover, - onPressed: () => popoverController.show(), - icon: svgWidget( - 'home/add', - color: Theme.of(context).colorScheme.tertiary, + child: SizedBox( + height: 26, + child: Row( + children: [ + VerticalDivider( + width: 1.0, + thickness: 1.0, + indent: 4.0, + endIndent: 4.0, + color: Theme.of(context).dividerColor, + ), + FlowyIconButton( + width: 26, + iconPadding: const EdgeInsets.all(5), + hoverColor: AFThemeExtension.of(context).greyHover, + onPressed: () => popoverController.show(), + radius: Corners.s4Border, + icon: const FlowySvg(name: 'home/add'), + iconColorOnHover: Theme.of(context).colorScheme.onSurface, + ), + ], ), ), popupBuilder: (BuildContext context) { diff --git a/frontend/appflowy_flutter/lib/plugins/database_view/widgets/setting/setting_button.dart b/frontend/appflowy_flutter/lib/plugins/database_view/widgets/setting/setting_button.dart index 7e9f3754c8..ed3d2deb38 100644 --- a/frontend/appflowy_flutter/lib/plugins/database_view/widgets/setting/setting_button.dart +++ b/frontend/appflowy_flutter/lib/plugins/database_view/widgets/setting/setting_button.dart @@ -6,6 +6,7 @@ import 'package:appflowy_backend/protobuf/flowy-database2/calendar_entities.pb.d import 'package:appflowy_backend/protobuf/flowy-database2/setting_entities.pbenum.dart'; import 'package:appflowy_popover/appflowy_popover.dart'; import 'package:easy_localization/easy_localization.dart'; +import 'package:flowy_infra/size.dart'; import 'package:flowy_infra/theme_extension.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flutter/material.dart'; @@ -32,29 +33,29 @@ class _SettingButtonState extends State { @override Widget build(BuildContext context) { - return SizedBox( - height: 26, - child: AppFlowyPopover( - controller: _popoverController, - constraints: BoxConstraints.loose(const Size(200, 400)), - direction: PopoverDirection.bottomWithLeftAligned, - offset: const Offset(0, 8), - margin: EdgeInsets.zero, - triggerActions: PopoverTriggerFlags.none, - child: FlowyTextButton( - LocaleKeys.settings_title.tr(), - fontColor: AFThemeExtension.of(context).textColor, - fillColor: Colors.transparent, - hoverColor: AFThemeExtension.of(context).lightGreyHover, - padding: GridSize.typeOptionContentInsets, - onPressed: () => _popoverController.show(), - ), - popupBuilder: (BuildContext context) { - return _DatabaseSettingListPopover( - databaseController: widget.databaseController, - ); - }, + return AppFlowyPopover( + controller: _popoverController, + constraints: BoxConstraints.loose(const Size(200, 400)), + direction: PopoverDirection.bottomWithCenterAligned, + offset: const Offset(0, 8), + margin: EdgeInsets.zero, + triggerActions: PopoverTriggerFlags.none, + child: FlowyTextButton( + LocaleKeys.settings_title.tr(), + fontColor: AFThemeExtension.of(context).textColor, + fontSize: FontSizes.s11, + fontWeight: FontWeight.w400, + fillColor: Colors.transparent, + hoverColor: AFThemeExtension.of(context).lightGreyHover, + padding: GridSize.toolbarSettingButtonInsets, + radius: Corners.s4Border, + onPressed: () => _popoverController.show(), ), + popupBuilder: (BuildContext context) { + return _DatabaseSettingListPopover( + databaseController: widget.databaseController, + ); + }, ); } } diff --git a/frontend/appflowy_flutter/lib/workspace/application/view/view_ext.dart b/frontend/appflowy_flutter/lib/workspace/application/view/view_ext.dart index 9d5caa4c3a..f8d189220a 100644 --- a/frontend/appflowy_flutter/lib/workspace/application/view/view_ext.dart +++ b/frontend/appflowy_flutter/lib/workspace/application/view/view_ext.dart @@ -118,7 +118,7 @@ extension ViewLayoutExtension on ViewLayoutPB { case ViewLayoutPB.Board: return 'editor/board'; case ViewLayoutPB.Calendar: - return 'editor/calendar'; + return 'editor/date'; case ViewLayoutPB.Document: return 'editor/documents'; default: diff --git a/frontend/appflowy_flutter/packages/flowy_infra/lib/size.dart b/frontend/appflowy_flutter/packages/flowy_infra/lib/size.dart index 9141b471bc..b66d836bb3 100644 --- a/frontend/appflowy_flutter/packages/flowy_infra/lib/size.dart +++ b/frontend/appflowy_flutter/packages/flowy_infra/lib/size.dart @@ -65,6 +65,9 @@ class Corners { static const BorderRadius s3Border = BorderRadius.all(s3Radius); static const Radius s3Radius = Radius.circular(3); + static const BorderRadius s4Border = BorderRadius.all(s4Radius); + static const Radius s4Radius = Radius.circular(4); + static const BorderRadius s5Border = BorderRadius.all(s5Radius); static const Radius s5Radius = Radius.circular(5); diff --git a/frontend/appflowy_flutter/packages/flowy_infra_ui/lib/style_widget/button.dart b/frontend/appflowy_flutter/packages/flowy_infra_ui/lib/style_widget/button.dart index d388c962a5..1a043d48ab 100644 --- a/frontend/appflowy_flutter/packages/flowy_infra_ui/lib/style_widget/button.dart +++ b/frontend/appflowy_flutter/packages/flowy_infra_ui/lib/style_widget/button.dart @@ -148,7 +148,7 @@ class FlowyTextButton extends StatelessWidget { this.radius, this.mainAxisAlignment = MainAxisAlignment.start, this.tooltip, - this.constraints = const BoxConstraints(minWidth: 58.0, minHeight: 30.0), + this.constraints = const BoxConstraints(minWidth: 0.0, minHeight: 0.0), this.decoration, this.fontFamily, }) : super(key: key); @@ -173,17 +173,13 @@ class FlowyTextButton extends StatelessWidget { ), ); - Widget child = Padding( - padding: padding, - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: mainAxisAlignment, - children: children, - ), + Widget child = Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: mainAxisAlignment, + children: children, ); child = RawMaterialButton( - visualDensity: VisualDensity.compact, hoverElevation: 0, highlightElevation: 0, shape: RoundedRectangleBorder(borderRadius: radius ?? Corners.s6Border), @@ -196,12 +192,8 @@ class FlowyTextButton extends StatelessWidget { elevation: 0, constraints: constraints, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, - onPressed: () {}, - child: child, - ); - - child = IgnoreParentGestureWidget( - onPress: onPressed, + padding: padding, + onPressed: onPressed, child: child, );