fix: sidebar issues on Windows and Linux (#5431)

* fix: workspace icon overflow

* fix: notification button doesn't have same effect as settings button

* fix: open-sidebar button wasn't replaced in the Windows title bar

* fix: workspace name overflow on Linux

* fix: appflowy logo align issue
This commit is contained in:
Lucas.Xu 2024-05-29 22:05:20 +08:00 committed by GitHub
parent b8b7a10b33
commit 0bfe071caf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 127 additions and 81 deletions

View File

@ -3,12 +3,13 @@ import 'dart:io';
import 'package:appflowy/generated/flowy_svgs.g.dart'; import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/shared/window_title_bar.dart'; import 'package:appflowy/shared/window_title_bar.dart';
import 'package:appflowy/util/theme_extension.dart';
import 'package:appflowy/workspace/application/home/home_setting_bloc.dart'; import 'package:appflowy/workspace/application/home/home_setting_bloc.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/style_widget/icon_button.dart'; import 'package:flowy_infra_ui/style_widget/icon_button.dart';
import 'package:flowy_infra_ui/widget/flowy_tooltip.dart'; import 'package:flowy_infra_ui/widget/flowy_tooltip.dart';
import 'package:flutter/services.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
class CocoaWindowChannel { class CocoaWindowChannel {
@ -102,13 +103,25 @@ class MoveWindowDetectorState extends State<MoveWindowDetector> {
return const SizedBox.shrink(); return const SizedBox.shrink();
} }
return FlowyTooltip( final color = Theme.of(context).isLightMode ? Colors.white : Colors.black;
richMessage: TextSpan( final textSpan = TextSpan(
children: [ children: [
TextSpan(text: '${LocaleKeys.sideBar_closeSidebar.tr()}\n'), TextSpan(
const TextSpan(text: 'Ctrl+\\'), text: '${LocaleKeys.sideBar_openSidebar.tr()}\n',
], style: Theme.of(context).textTheme.bodyMedium!.copyWith(color: color),
), ),
TextSpan(
text: Platform.isMacOS ? '⌘+.' : 'Ctrl+\\',
style: Theme.of(context)
.textTheme
.bodyMedium!
.copyWith(color: Theme.of(context).hintColor),
),
],
);
return FlowyTooltip(
richMessage: textSpan,
child: FlowyIconButton( child: FlowyIconButton(
hoverColor: Colors.transparent, hoverColor: Colors.transparent,
onPressed: () => context onPressed: () => context

View File

@ -3,6 +3,7 @@ import 'dart:io' show Platform;
import 'package:appflowy/core/frameless_window.dart'; import 'package:appflowy/core/frameless_window.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart'; import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/util/theme_extension.dart';
import 'package:appflowy/workspace/application/home/home_setting_bloc.dart'; import 'package:appflowy/workspace/application/home/home_setting_bloc.dart';
import 'package:appflowy/workspace/application/menu/sidebar_sections_bloc.dart'; import 'package:appflowy/workspace/application/menu/sidebar_sections_bloc.dart';
import 'package:appflowy/workspace/presentation/home/home_sizes.dart'; import 'package:appflowy/workspace/presentation/home/home_sizes.dart';
@ -51,22 +52,23 @@ class SidebarTopMenu extends StatelessWidget {
? FlowySvgs.flowy_logo_dark_mode_xl ? FlowySvgs.flowy_logo_dark_mode_xl
: FlowySvgs.flowy_logo_text_xl; : FlowySvgs.flowy_logo_text_xl;
return FlowySvg( return Padding(
padding: const EdgeInsets.only(top: 12.0, left: 4),
child: FlowySvg(
svgData, svgData,
size: const Size(92, 17), size: const Size(92, 17),
blendMode: null, blendMode: null,
),
); );
} }
Widget _buildCollapseMenuButton(BuildContext context) { Widget _buildCollapseMenuButton(BuildContext context) {
final color = Theme.of(context).isLightMode ? Colors.white : Colors.black;
final textSpan = TextSpan( final textSpan = TextSpan(
children: [ children: [
TextSpan( TextSpan(
text: '${LocaleKeys.sideBar_closeSidebar.tr()}\n', text: '${LocaleKeys.sideBar_closeSidebar.tr()}\n',
style: Theme.of(context) style: Theme.of(context).textTheme.bodyMedium!.copyWith(color: color),
.textTheme
.bodyMedium!
.copyWith(color: Colors.white),
), ),
TextSpan( TextSpan(
text: Platform.isMacOS ? '⌘+.' : 'Ctrl+\\', text: Platform.isMacOS ? '⌘+.' : 'Ctrl+\\',

View File

@ -38,7 +38,6 @@ class SidebarUser extends StatelessWidget {
const HSpace(10), const HSpace(10),
Expanded(child: _buildUserName(context, state)), Expanded(child: _buildUserName(context, state)),
UserSettingButton(userProfile: state.userProfile), UserSettingButton(userProfile: state.userProfile),
const HSpace(4),
const NotificationButton(), const NotificationButton(),
], ],
), ),

View File

@ -224,7 +224,7 @@ class _SidebarState extends State<_Sidebar> {
// user or workspace, setting // user or workspace, setting
Container( Container(
height: HomeSizes.workspaceSectionHeight, height: HomeSizes.workspaceSectionHeight,
padding: menuHorizontalInset, padding: menuHorizontalInset - const EdgeInsets.only(right: 6),
child: child:
// if the workspaces are empty, show the user profile instead // if the workspaces are empty, show the user profile instead
userState.isCollabWorkspaceOn && userState.workspaces.isNotEmpty userState.isCollabWorkspaceOn && userState.workspaces.isNotEmpty

View File

@ -44,7 +44,7 @@ class _WorkspaceIconState extends State<WorkspaceIcon> {
: Container( : Container(
alignment: Alignment.center, alignment: Alignment.center,
width: widget.iconSize, width: widget.iconSize,
height: max(widget.iconSize, 26), height: min(widget.iconSize, 26),
decoration: BoxDecoration( decoration: BoxDecoration(
color: ColorGenerator(widget.workspace.name).toColor(), color: ColorGenerator(widget.workspace.name).toColor(),
borderRadius: BorderRadius.circular(4), borderRadius: BorderRadius.circular(4),

View File

@ -128,7 +128,7 @@ class _WorkspaceMenuItemState extends State<WorkspaceMenuItem> {
// cause the popover dismiss intermediately when click the right icon. // cause the popover dismiss intermediately when click the right icon.
// so using the stack to put the right icon on the flowy button. // so using the stack to put the right icon on the flowy button.
return SizedBox( return SizedBox(
height: 40, height: 44,
child: MouseRegion( child: MouseRegion(
onEnter: (_) => isHovered.value = true, onEnter: (_) => isHovered.value = true,
onExit: (_) => isHovered.value = false, onExit: (_) => isHovered.value = false,
@ -250,7 +250,6 @@ class _WorkspaceInfo extends StatelessWidget {
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
withTooltip: true, withTooltip: true,
), ),
const VSpace(2.0),
// workspace members count // workspace members count
FlowyText.regular( FlowyText.regular(
state.isLoading state.isLoading

View File

@ -49,9 +49,7 @@ class _SidebarWorkspaceState extends State<SidebarWorkspace> {
), ),
), ),
UserSettingButton(userProfile: widget.userProfile), UserSettingButton(userProfile: widget.userProfile),
const HSpace(8),
const NotificationButton(), const NotificationButton(),
const HSpace(4),
], ],
); );
}, },
@ -201,12 +199,12 @@ class _SidebarSwitchWorkspaceButtonState
}, },
child: FlowyButton( child: FlowyButton(
margin: EdgeInsets.zero, margin: EdgeInsets.zero,
text: Row( text: SizedBox(
height: 30,
child: Row(
children: [ children: [
const HSpace(6.0), const HSpace(6.0),
SizedBox( WorkspaceIcon(
width: 16.0,
child: WorkspaceIcon(
workspace: widget.currentWorkspace, workspace: widget.currentWorkspace,
iconSize: 16, iconSize: 16,
fontSize: 10, fontSize: 10,
@ -218,7 +216,6 @@ class _SidebarSwitchWorkspaceButtonState
), ),
), ),
), ),
),
const HSpace(10), const HSpace(10),
Flexible( Flexible(
child: FlowyText.medium( child: FlowyText.medium(
@ -239,6 +236,7 @@ class _SidebarSwitchWorkspaceButtonState
], ],
), ),
), ),
),
); );
} }
} }

View File

@ -422,6 +422,10 @@ class _SingleInnerViewItemState extends State<SingleInnerViewItem> {
// icon // icon
_buildViewIconButton(), _buildViewIconButton(),
const HSpace(6), const HSpace(6),
// const SizedBox(
// width: 6.0,
// height: 1,
// ),
// title // title
Expanded( Expanded(
child: FlowyText.regular( child: FlowyText.regular(

View File

@ -1,17 +1,17 @@
import 'dart:io'; import 'dart:io';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:flutter/material.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart'; import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/util/theme_extension.dart';
import 'package:appflowy/workspace/application/home/home_setting_bloc.dart'; import 'package:appflowy/workspace/application/home/home_setting_bloc.dart';
import 'package:appflowy/workspace/presentation/home/home_stack.dart'; import 'package:appflowy/workspace/presentation/home/home_stack.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/size.dart'; import 'package:flowy_infra/size.dart';
import 'package:flowy_infra_ui/style_widget/icon_button.dart'; import 'package:flowy_infra_ui/style_widget/icon_button.dart';
import 'package:flowy_infra_ui/style_widget/text.dart'; import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flowy_infra_ui/widget/flowy_tooltip.dart'; import 'package:flowy_infra_ui/widget/flowy_tooltip.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:styled_widget/styled_widget.dart'; import 'package:styled_widget/styled_widget.dart';
@ -65,23 +65,39 @@ class FlowyNavigation extends StatelessWidget {
buildWhen: (p, c) => p.isMenuCollapsed != c.isMenuCollapsed, buildWhen: (p, c) => p.isMenuCollapsed != c.isMenuCollapsed,
builder: (context, state) { builder: (context, state) {
if (!PlatformExtension.isWindows && state.isMenuCollapsed) { if (!PlatformExtension.isWindows && state.isMenuCollapsed) {
return RotationTransition( final color =
Theme.of(context).isLightMode ? Colors.white : Colors.black;
final textSpan = TextSpan(
children: [
TextSpan(
text: '${LocaleKeys.sideBar_openSidebar.tr()}\n',
style: Theme.of(context)
.textTheme
.bodyMedium!
.copyWith(color: color),
),
TextSpan(
text: Platform.isMacOS ? '⌘+.' : 'Ctrl+\\',
style: Theme.of(context)
.textTheme
.bodyMedium!
.copyWith(color: Theme.of(context).hintColor),
),
],
);
return Padding(
padding: const EdgeInsets.only(right: 8.0),
child: RotationTransition(
turns: const AlwaysStoppedAnimation(180 / 360), turns: const AlwaysStoppedAnimation(180 / 360),
child: FlowyTooltip( child: FlowyTooltip(
richMessage: sidebarTooltipTextSpan( richMessage: textSpan,
context,
LocaleKeys.sideBar_openSidebar.tr(),
),
child: FlowyIconButton( child: FlowyIconButton(
width: 24, width: 24,
hoverColor: Colors.transparent,
onPressed: () => context onPressed: () => context
.read<HomeSettingBloc>() .read<HomeSettingBloc>()
.add(const HomeSettingEvent.collapseMenu()), .add(const HomeSettingEvent.collapseMenu()),
iconPadding: const EdgeInsets.fromLTRB(2, 2, 2, 2), iconPadding: const EdgeInsets.all(2),
icon: FlowySvg( icon: const FlowySvg(FlowySvgs.hide_menu_s),
FlowySvgs.hide_menu_m,
color: Theme.of(context).iconTheme.color,
), ),
), ),
), ),

View File

@ -3,6 +3,7 @@ import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/startup/startup.dart'; import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/user/application/reminder/reminder_bloc.dart'; import 'package:appflowy/user/application/reminder/reminder_bloc.dart';
import 'package:appflowy/workspace/application/menu/sidebar_sections_bloc.dart'; import 'package:appflowy/workspace/application/menu/sidebar_sections_bloc.dart';
import 'package:appflowy/workspace/presentation/home/home_sizes.dart';
import 'package:appflowy/workspace/presentation/notifications/notification_dialog.dart'; import 'package:appflowy/workspace/presentation/notifications/notification_dialog.dart';
import 'package:appflowy_popover/appflowy_popover.dart'; import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
@ -27,17 +28,19 @@ class NotificationButton extends StatelessWidget {
child: BlocBuilder<ReminderBloc, ReminderState>( child: BlocBuilder<ReminderBloc, ReminderState>(
builder: (context, state) => FlowyTooltip( builder: (context, state) => FlowyTooltip(
message: LocaleKeys.notificationHub_title.tr(), message: LocaleKeys.notificationHub_title.tr(),
child: MouseRegion(
cursor: SystemMouseCursors.click,
child: AppFlowyPopover( child: AppFlowyPopover(
mutex: mutex, mutex: mutex,
direction: PopoverDirection.bottomWithLeftAligned, direction: PopoverDirection.bottomWithLeftAligned,
constraints: const BoxConstraints(maxHeight: 500, maxWidth: 425), constraints: const BoxConstraints(maxHeight: 500, maxWidth: 425),
windowPadding: EdgeInsets.zero, windowPadding: EdgeInsets.zero,
margin: EdgeInsets.zero, margin: EdgeInsets.zero,
popupBuilder: (_) => popupBuilder: (_) => NotificationDialog(views: views, mutex: mutex),
NotificationDialog(views: views, mutex: mutex), child: SizedBox.square(
child: _buildNotificationIcon(context, state.hasUnreads), dimension: HomeSizes.workspaceSectionHeight,
child: FlowyButton(
useIntrinsicWidth: true,
text: _buildNotificationIcon(context, state.hasUnreads),
),
), ),
), ),
), ),

View File

@ -167,6 +167,7 @@ class _ViewTitleState extends State<_ViewTitle> {
onPointerDown: (_) => context.read<TabsBloc>().openPlugin(widget.view), onPointerDown: (_) => context.read<TabsBloc>().openPlugin(widget.view),
child: FlowyButton( child: FlowyButton(
useIntrinsicWidth: true, useIntrinsicWidth: true,
margin: const EdgeInsets.symmetric(horizontal: 6.0),
onTap: () {}, onTap: () {},
text: _buildIconAndName(state), text: _buildIconAndName(state),
), ),

View File

@ -2,6 +2,8 @@ import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
const String _emojiFontFamily = 'noto color emoji';
class FlowyText extends StatelessWidget { class FlowyText extends StatelessWidget {
final String text; final String text;
final TextOverflow? overflow; final TextOverflow? overflow;
@ -119,13 +121,19 @@ class FlowyText extends StatelessWidget {
this.withTooltip = false, this.withTooltip = false,
this.strutStyle = const StrutStyle(forceStrutHeight: true), this.strutStyle = const StrutStyle(forceStrutHeight: true),
}) : fontWeight = FontWeight.w400, }) : fontWeight = FontWeight.w400,
fontFamily = 'noto color emoji', fontFamily = _emojiFontFamily,
fallbackFontFamily = null; fallbackFontFamily = null;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
Widget child; Widget child;
double fontSize =
this.fontSize ?? Theme.of(context).textTheme.bodyMedium!.fontSize!;
if (Platform.isLinux && fontFamily == _emojiFontFamily) {
fontSize = fontSize * 0.8;
}
final textStyle = Theme.of(context).textTheme.bodyMedium!.copyWith( final textStyle = Theme.of(context).textTheme.bodyMedium!.copyWith(
fontSize: fontSize, fontSize: fontSize,
fontWeight: fontWeight, fontWeight: fontWeight,

View File

@ -22,8 +22,13 @@ class FlowyTooltip extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final isLightMode = Theme.of(context).brightness == Brightness.light;
return Tooltip( return Tooltip(
margin: margin, margin: margin,
decoration: BoxDecoration(
color: isLightMode ? const Color(0xE5171717) : const Color(0xE5E5E5E5),
borderRadius: BorderRadius.circular(8.0),
),
waitDuration: _tooltipWaitDuration, waitDuration: _tooltipWaitDuration,
message: message, message: message,
richMessage: richMessage, richMessage: richMessage,

View File

@ -1,6 +1,4 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10 5L13 8L10 11" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/> <path d="M9.75 14.25L15 9L9.75 3.75" stroke="#171717" stroke-width="1.2" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
<rect x="3" y="5" width="4" height="1" rx="0.5" fill="#333333"/> <path d="M3.5625 14.25L8.8125 9L3.5625 3.75" stroke="#171717" stroke-width="1.2" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
<rect x="3" y="7.5" width="6" height="1" rx="0.5" fill="#333333"/>
<rect x="3" y="10" width="4" height="1" rx="0.5" fill="#333333"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 394 B

After

Width:  |  Height:  |  Size: 401 B