chore: database tab bar ui improvements (#3093)

* chore: tab bar ui polish

* chore: toolbar buttons ui

* chore: minor padding radius and spacing adjustment

* fix: padding issues

* chore: add view button size and padding

* chore: the carelessness is real

* fix: dark mode colors

* fix: selected icon color
This commit is contained in:
Richard Shiue 2023-08-08 16:57:25 +08:00 committed by GitHub
parent 9d18e9de40
commit 7cdd47757b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 449 additions and 370 deletions

View File

@ -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';

View File

@ -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),
],
),

View File

@ -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<CalendarPage> {
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<CalendarPage> {
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(

View File

@ -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;

View File

@ -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<UnscheduleEventsButton> {
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(),
);
},
),

View File

@ -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,

View File

@ -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<FilterButton> {
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<GridFilterMenuBloc>();
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<GridFilterMenuBloc>();
if (bloc.state.filters.isEmpty) {
_popoverController.show();
} else {
bloc.add(const GridFilterMenuEvent.toggleMenu());
}
},
),
);
},

View File

@ -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,
),
],
),
);
},
),
),

View File

@ -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<SortButton> {
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<SortMenuBloc>();
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<SortMenuBloc>();
if (bloc.state.sortInfos.isEmpty) {
_popoverController.show();
} else {
bloc.add(const SortMenuEvent.toggleMenu());
}
},
),
);
},

View File

@ -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<DatabaseViewSettingExtensionBloc,
DatabaseViewSettingExtensionState>(
builder: (context, state) {
final children = <Widget>[
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,
);

View File

@ -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<TabBarHeader> createState() => _TabBarHeaderState();
}
class _TabBarHeaderState extends State<TabBarHeader> {
@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<GridTabBarBloc, GridTabBarState>(
builder: (context, state) {
return const Flexible(
child: DatabaseTabBar(),
);
},
),
BlocBuilder<GridTabBarBloc, GridTabBarState>(
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<DatabaseTabBar> createState() => _DatabaseTabBarState();
}
class _DatabaseTabBarState extends State<DatabaseTabBar> {
final _scrollController = ScrollController();
@override
Widget build(BuildContext context) {
return BlocBuilder<GridTabBarBloc, GridTabBarState>(
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<GridTabBarBloc>().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<GridTabBarBloc>().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<TabBarViewAction>(
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<GridTabBarBloc>().add(
GridTabBarEvent.renameView(view.id, newValue),
);
},
).show(context);
break;
case TabBarViewAction.delete:
NavigatorAlertDialog(
title: LocaleKeys.grid_deleteView.tr(),
confirm: () {
context.read<GridTabBarBloc>().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;
}

View File

@ -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<DatabaseTabBarView> {
builder: (_, value, ___) {
if (value) {
return const SizedBox.shrink();
} else {
return Row(
children: [
BlocBuilder<GridTabBarBloc, GridTabBarState>(
builder: (context, state) {
return const Flexible(
child: Padding(
padding: EdgeInsets.only(left: 50),
child: DatabaseTabBar(),
),
);
},
),
BlocBuilder<GridTabBarBloc, GridTabBarState>(
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<DatabaseTabBarView> {
}).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<NavigationItem> get navigationItems => [this];
}
class DatabaseTabBar extends StatefulWidget {
const DatabaseTabBar({super.key});
@override
State<DatabaseTabBar> createState() => _DatabaseTabBarState();
}
class _DatabaseTabBarState extends State<DatabaseTabBar> {
final _scrollController = ScrollController();
@override
Widget build(BuildContext context) {
return BlocBuilder<GridTabBarBloc, GridTabBarState>(
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<GridTabBarBloc>().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<GridTabBarBloc>().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<TabBarViewAction>(
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<GridTabBarBloc>().add(
GridTabBarEvent.renameView(view.id, newValue),
);
},
).show(context);
break;
case TabBarViewAction.delete:
NavigatorAlertDialog(
title: LocaleKeys.grid_deleteView.tr(),
confirm: () {
context.read<GridTabBarBloc>().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;
}

View File

@ -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<AddDatabaseViewButton> {
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) {

View File

@ -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<SettingButton> {
@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,
);
},
);
}
}

View File

@ -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:

View File

@ -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);

View File

@ -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,
);