diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/home/home_sizes.dart b/frontend/appflowy_flutter/lib/workspace/presentation/home/home_sizes.dart index 1e6265d9c199..4badd079aa1c 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/home/home_sizes.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/home/home_sizes.dart @@ -4,6 +4,7 @@ class HomeSizes { static const double editPanelTopBarHeight = 60; static const double editPanelWidth = 400; static const double tabBarHeight = 40; + static const double readOnlyBannerHeight = 24; static const double tabWidth = 200; static const double resizeBarThickness = 2; } diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/home/home_stack.dart b/frontend/appflowy_flutter/lib/workspace/presentation/home/home_stack.dart index d4e2c32a738d..53189440bca1 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/home/home_stack.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/home/home_stack.dart @@ -250,7 +250,11 @@ class PageManager { selector: (context, notifier) => notifier.titleWidget, builder: (context, widget, child) { return MoveWindowDetector( - child: HomeTopBar(layout: layout, paneId: paneId), + child: HomeTopBar( + layout: layout, + paneId: paneId, + notifier: notifier, + ), ); }, ), @@ -276,55 +280,88 @@ class PageManager { } class HomeTopBar extends StatelessWidget { - const HomeTopBar({super.key, required this.layout, required this.paneId}); + const HomeTopBar({ + super.key, + required this.layout, + required this.paneId, + required this.notifier, + }); + final PageNotifier notifier; final HomeLayout layout; final String paneId; @override Widget build(BuildContext context) { - return Container( - color: Theme.of(context).colorScheme.onSecondaryContainer, - height: HomeSizes.topBarHeight, - child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: HomeInsets.topBarTitlePadding, + return Column( + children: [ + Container( + color: Theme.of(context).colorScheme.onSecondaryContainer, + height: HomeSizes.topBarHeight, + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: HomeInsets.topBarTitlePadding, + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + HSpace(layout.menuSpacing), + FlowyNavigation(currentPaneId: paneId), + const HSpace(16), + ChangeNotifierProvider.value( + value: Provider.of(context, listen: false), + child: Consumer( + builder: (_, PageNotifier notifier, __) => + notifier.plugin.widgetBuilder.rightBarItem ?? + const SizedBox.shrink(), + ), + ), + BlocBuilder( + builder: (context, state) { + if (state.count <= 1) { + return const SizedBox.shrink(); + } + + return Padding( + padding: const EdgeInsets.all(2), + child: FlowyIconButton( + iconColorOnHover: + Theme.of(context).colorScheme.onSurface, + onPressed: () => context + .read() + .add(ClosePane(paneId: paneId)), + icon: const FlowySvg(FlowySvgs.close_s), + ), + ); + }, + ), + ], + ), + ).bottomBorder(color: Theme.of(context).dividerColor), ), + if (notifier.readOnly) _buildReadOnlyBanner(context), + ], + ); + } + + Widget _buildReadOnlyBanner(BuildContext context) { + final colorScheme = Theme.of(context).colorScheme; + return Container( + width: double.infinity, + color: colorScheme.primary, + child: FittedBox( + alignment: Alignment.center, + fit: BoxFit.scaleDown, child: Row( - crossAxisAlignment: CrossAxisAlignment.center, children: [ - HSpace(layout.menuSpacing), - FlowyNavigation(currentPaneId: paneId), - const HSpace(16), - ChangeNotifierProvider.value( - value: Provider.of(context, listen: false), - child: Consumer( - builder: (_, PageNotifier notifier, __) => - notifier.plugin.widgetBuilder.rightBarItem ?? - const SizedBox(), - ), - ), - BlocBuilder( - builder: (context, state) { - if (state.count <= 1) { - return const SizedBox.shrink(); - } - - return Padding( - padding: const EdgeInsets.all(2), - child: FlowyIconButton( - iconColorOnHover: Theme.of(context).colorScheme.onSurface, - onPressed: () => context - .read() - .add(ClosePane(paneId: paneId)), - icon: const FlowySvg(FlowySvgs.close_s), - ), - ); - }, + FlowyText.medium( + LocaleKeys.readOnlyViewText.tr(), + fontSize: 14, + color: Theme.of(context).colorScheme.onSurface, ), ], ), - ).bottomBorder(color: Theme.of(context).dividerColor), + ), ); } } @@ -358,41 +395,36 @@ class _HomeBodyState extends State { if (widget.notifier.readOnly) { return ValueListenableBuilder( valueListenable: absorbTapsNotifier, - builder: (_, value, __) => Stack( - children: [ - GestureDetector( - child: Listener( - behavior: HitTestBehavior.translucent, - onPointerPanZoomUpdate: (event) { - absorbTapsNotifier.value = false; - _timer?.cancel(); - }, - onPointerPanZoomEnd: (event) { - _timer?.cancel(); - _applyTimer(); - }, - onPointerPanZoomStart: (event) { - absorbTapsNotifier.value = false; - _timer?.cancel(); - }, - onPointerSignal: (signal) { - if (signal is PointerScrollEvent) { - absorbTapsNotifier.value = false; - _timer?.cancel(); - _applyTimer(); - } - }, - child: IgnorePointer( - ignoring: value, - child: Opacity( - opacity: 0.5, - child: _buildWidgetStack(onDeleted: widget.onDeleted), - ), - ), + builder: (_, value, __) => GestureDetector( + child: Listener( + behavior: HitTestBehavior.translucent, + onPointerPanZoomUpdate: (event) { + absorbTapsNotifier.value = false; + _timer?.cancel(); + }, + onPointerPanZoomEnd: (event) { + _timer?.cancel(); + _applyTimer(); + }, + onPointerPanZoomStart: (event) { + absorbTapsNotifier.value = false; + _timer?.cancel(); + }, + onPointerSignal: (signal) { + if (signal is PointerScrollEvent) { + absorbTapsNotifier.value = false; + _timer?.cancel(); + _applyTimer(); + } + }, + child: IgnorePointer( + ignoring: value, + child: Opacity( + opacity: 0.5, + child: _buildWidgetStack(onDeleted: widget.onDeleted), ), ), - Positioned(child: _buildReadOnlyBanner(context)), - ], + ), ), ); } @@ -430,27 +462,4 @@ class _HomeBodyState extends State { ).toList(), ); } - - Widget _buildReadOnlyBanner(BuildContext context) { - final colorScheme = Theme.of(context).colorScheme; - return ConstrainedBox( - constraints: const BoxConstraints(minHeight: 20), - child: Container( - width: double.infinity, - color: colorScheme.primary, - child: FittedBox( - alignment: Alignment.center, - fit: BoxFit.scaleDown, - child: Row( - children: [ - FlowyText.medium( - LocaleKeys.readOnlyViewText.tr(), - fontSize: 14, - ), - ], - ), - ), - ), - ); - } } diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/home/panes/flowy_pane.dart b/frontend/appflowy_flutter/lib/workspace/presentation/home/panes/flowy_pane.dart index fcb6a8dd5180..a182bdb6ed8b 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/home/panes/flowy_pane.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/home/panes/flowy_pane.dart @@ -46,10 +46,14 @@ class _FlowyPaneState extends State { create: (context) => widget.node.tabsController, child: Consumer( builder: (_, value, __) { - final topHeight = value.pages == 1 + double topHeight = value.pages == 1 ? HomeSizes.topBarHeight : HomeSizes.topBarHeight + HomeSizes.tabBarHeight; + if (value.currentPageManager.readOnly) { + topHeight += HomeSizes.readOnlyBannerHeight; + } + return DraggablePaneTarget( size: Size( widget.paneLayout.childPaneWidth,