mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
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:
parent
9d18e9de40
commit
7cdd47757b
@ -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';
|
||||
|
@ -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),
|
||||
],
|
||||
),
|
||||
|
@ -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(
|
||||
|
@ -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;
|
||||
|
@ -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(),
|
||||
);
|
||||
},
|
||||
),
|
||||
|
@ -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,
|
||||
|
@ -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());
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
|
@ -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,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
|
@ -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());
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
|
@ -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,
|
||||
);
|
||||
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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,
|
||||
);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user