fix: offset row actions by cover height (#6390)

This commit is contained in:
Mathias Mogensen 2024-09-24 14:33:23 +02:00 committed by GitHub
parent 5fbd07e96a
commit e125e9493a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 91 additions and 48 deletions

View File

@ -39,7 +39,11 @@ import 'package:universal_platform/universal_platform.dart';
import '../../../document/presentation/editor_plugins/plugins.dart'; import '../../../document/presentation/editor_plugins/plugins.dart';
const _coverHeight = 250.0; /// We have the cover height as public as it is used in the row_detail.dart file
/// Used to determine the position of the row actions depending on if there is a cover or not.
///
const rowCoverHeight = 250.0;
const _iconHeight = 60.0; const _iconHeight = 60.0;
const _toolbarHeight = 40.0; const _toolbarHeight = 40.0;
@ -181,11 +185,11 @@ class _RowBannerState extends State<RowBanner> {
double _calculateOverallHeight(bool hasIcon, bool hasCover) { double _calculateOverallHeight(bool hasIcon, bool hasCover) {
switch ((hasIcon, hasCover)) { switch ((hasIcon, hasCover)) {
case (true, true): case (true, true):
return _coverHeight + _toolbarHeight; return rowCoverHeight + _toolbarHeight;
case (true, false): case (true, false):
return 50 + _iconHeight + _toolbarHeight; return 50 + _iconHeight + _toolbarHeight;
case (false, true): case (false, true):
return _coverHeight + _toolbarHeight; return rowCoverHeight + _toolbarHeight;
case (false, false): case (false, false):
return _toolbarHeight; return _toolbarHeight;
} }
@ -224,7 +228,7 @@ class _RowCoverState extends State<RowCover> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return SizedBox( return SizedBox(
height: _coverHeight, height: rowCoverHeight,
child: MouseRegion( child: MouseRegion(
onEnter: (_) => setState(() => isOverlayButtonsHidden = false), onEnter: (_) => setState(() => isOverlayButtonsHidden = false),
onExit: (_) => setState(() => isOverlayButtonsHidden = true), onExit: (_) => setState(() => isOverlayButtonsHidden = true),
@ -364,7 +368,7 @@ class _DesktopRowCoverState extends State<DesktopRowCover> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
if (cover.coverType == CoverTypePB.FileCover) { if (cover.coverType == CoverTypePB.FileCover) {
return SizedBox( return SizedBox(
height: _coverHeight, height: rowCoverHeight,
width: double.infinity, width: double.infinity,
child: AFImage( child: AFImage(
url: cover.data, url: cover.data,
@ -376,7 +380,7 @@ class _DesktopRowCoverState extends State<DesktopRowCover> {
if (cover.coverType == CoverTypePB.AssetCover) { if (cover.coverType == CoverTypePB.AssetCover) {
return SizedBox( return SizedBox(
height: _coverHeight, height: rowCoverHeight,
width: double.infinity, width: double.infinity,
child: Image.asset( child: Image.asset(
PageStyleCoverImageType.builtInImagePath(cover.data), PageStyleCoverImageType.builtInImagePath(cover.data),
@ -389,7 +393,7 @@ class _DesktopRowCoverState extends State<DesktopRowCover> {
final color = FlowyTint.fromId(cover.data)?.color(context) ?? final color = FlowyTint.fromId(cover.data)?.color(context) ??
cover.data.tryToColor(); cover.data.tryToColor();
return Container( return Container(
height: _coverHeight, height: rowCoverHeight,
width: double.infinity, width: double.infinity,
color: color, color: color,
); );
@ -397,7 +401,7 @@ class _DesktopRowCoverState extends State<DesktopRowCover> {
if (cover.coverType == CoverTypePB.GradientCover) { if (cover.coverType == CoverTypePB.GradientCover) {
return Container( return Container(
height: _coverHeight, height: rowCoverHeight,
width: double.infinity, width: double.infinity,
decoration: BoxDecoration( decoration: BoxDecoration(
gradient: FlowyGradientColor.fromId(cover.data).linear, gradient: FlowyGradientColor.fromId(cover.data).linear,

View File

@ -1,3 +1,4 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart'; import 'package:appflowy/generated/flowy_svgs.g.dart';
@ -41,13 +42,26 @@ class RowDetailPage extends StatefulWidget with FlowyOverlayDelegate {
} }
class _RowDetailPageState extends State<RowDetailPage> { class _RowDetailPageState extends State<RowDetailPage> {
final scrollController = ScrollController();
late final cellBuilder = EditableCellBuilder( late final cellBuilder = EditableCellBuilder(
databaseController: widget.databaseController, databaseController: widget.databaseController,
); );
late final ScrollController scrollController;
double scrollOffset = 0;
@override
void initState() {
super.initState();
scrollController = ScrollController(
onAttach: (_) => attachScrollListener(),
);
}
void attachScrollListener() => scrollController.addListener(onScrollChanged);
@override @override
void dispose() { void dispose() {
scrollController.removeListener(onScrollChanged);
scrollController.dispose(); scrollController.dispose();
super.dispose(); super.dispose();
} }
@ -65,53 +79,78 @@ class _RowDetailPageState extends State<RowDetailPage> {
), ),
BlocProvider.value(value: getIt<ReminderBloc>()), BlocProvider.value(value: getIt<ReminderBloc>()),
], ],
child: Stack( child: BlocBuilder<RowDetailBloc, RowDetailState>(
children: [ builder: (context, state) => Stack(
ListView( children: [
controller: scrollController, ListView(
children: [ controller: scrollController,
RowBanner( physics: const ClampingScrollPhysics(),
databaseController: widget.databaseController, children: [
rowController: widget.rowController, RowBanner(
cellBuilder: cellBuilder, databaseController: widget.databaseController,
allowOpenAsFullPage: widget.allowOpenAsFullPage, rowController: widget.rowController,
userProfile: widget.userProfile,
),
const VSpace(16),
Padding(
padding: const EdgeInsets.only(left: 40, right: 60),
child: RowPropertyList(
cellBuilder: cellBuilder, cellBuilder: cellBuilder,
viewId: widget.databaseController.viewId, allowOpenAsFullPage: widget.allowOpenAsFullPage,
fieldController: widget.databaseController.fieldController, userProfile: widget.userProfile,
), ),
), const VSpace(16),
const VSpace(20), Padding(
const Padding( padding: const EdgeInsets.only(left: 40, right: 60),
padding: EdgeInsets.symmetric(horizontal: 60), child: RowPropertyList(
child: Divider(height: 1.0), cellBuilder: cellBuilder,
), viewId: widget.databaseController.viewId,
const VSpace(20), fieldController:
RowDocument( widget.databaseController.fieldController,
viewId: widget.rowController.viewId, ),
rowId: widget.rowController.rowId, ),
), const VSpace(20),
], const Padding(
), padding: EdgeInsets.symmetric(horizontal: 60),
Positioned( child: Divider(height: 1.0),
top: 12, ),
right: 12, const VSpace(20),
child: Row( RowDocument(
children: _actions(context), viewId: widget.rowController.viewId,
rowId: widget.rowController.rowId,
),
],
), ),
), Positioned(
], top: calculateActionsOffset(
state.rowMeta.cover.data.isNotEmpty,
),
right: 12,
child: Row(
children: actions(context),
),
),
],
),
), ),
), ),
); );
} }
List<Widget> _actions(BuildContext context) { void onScrollChanged() {
if (scrollOffset != scrollController.offset) {
setState(() => scrollOffset = scrollController.offset);
}
}
double calculateActionsOffset(bool hasCover) {
if (!hasCover) {
return 12;
}
final offsetByScroll = clampDouble(
rowCoverHeight - scrollOffset,
0,
rowCoverHeight,
);
return 12 + offsetByScroll;
}
List<Widget> actions(BuildContext context) {
return [ return [
if (widget.allowOpenAsFullPage) ...[ if (widget.allowOpenAsFullPage) ...[
FlowyTooltip( FlowyTooltip(