1+ import 'package:flutter/foundation.dart' ;
12import 'package:flutter/material.dart' ;
23
34import 'package:appflowy/generated/flowy_svgs.g.dart' ;
@@ -41,13 +42,26 @@ class RowDetailPage extends StatefulWidget with FlowyOverlayDelegate {
4142}
4243
4344class _RowDetailPageState extends State <RowDetailPage > {
44- final scrollController = ScrollController ();
4545 late final cellBuilder = EditableCellBuilder (
4646 databaseController: widget.databaseController,
4747 );
48+ late final ScrollController scrollController;
49+
50+ double scrollOffset = 0 ;
51+
52+ @override
53+ void initState () {
54+ super .initState ();
55+ scrollController = ScrollController (
56+ onAttach: (_) => attachScrollListener (),
57+ );
58+ }
59+
60+ void attachScrollListener () => scrollController.addListener (onScrollChanged);
4861
4962 @override
5063 void dispose () {
64+ scrollController.removeListener (onScrollChanged);
5165 scrollController.dispose ();
5266 super .dispose ();
5367 }
@@ -65,53 +79,78 @@ class _RowDetailPageState extends State<RowDetailPage> {
6579 ),
6680 BlocProvider .value (value: getIt <ReminderBloc >()),
6781 ],
68- child: Stack (
69- children: [
70- ListView (
71- controller: scrollController,
72- children: [
73- RowBanner (
74- databaseController: widget.databaseController,
75- rowController: widget.rowController,
76- cellBuilder: cellBuilder,
77- allowOpenAsFullPage: widget.allowOpenAsFullPage,
78- userProfile: widget.userProfile,
79- ),
80- const VSpace (16 ),
81- Padding (
82- padding: const EdgeInsets .only (left: 40 , right: 60 ),
83- child: RowPropertyList (
82+ child: BlocBuilder <RowDetailBloc , RowDetailState >(
83+ builder: (context, state) => Stack (
84+ children: [
85+ ListView (
86+ controller: scrollController,
87+ physics: const ClampingScrollPhysics (),
88+ children: [
89+ RowBanner (
90+ databaseController: widget.databaseController,
91+ rowController: widget.rowController,
8492 cellBuilder: cellBuilder,
85- viewId : widget.databaseController.viewId ,
86- fieldController : widget.databaseController.fieldController ,
93+ allowOpenAsFullPage : widget.allowOpenAsFullPage ,
94+ userProfile : widget.userProfile ,
8795 ),
96+ const VSpace (16 ),
97+ Padding (
98+ padding: const EdgeInsets .only (left: 40 , right: 60 ),
99+ child: RowPropertyList (
100+ cellBuilder: cellBuilder,
101+ viewId: widget.databaseController.viewId,
102+ fieldController:
103+ widget.databaseController.fieldController,
104+ ),
105+ ),
106+ const VSpace (20 ),
107+ const Padding (
108+ padding: EdgeInsets .symmetric (horizontal: 60 ),
109+ child: Divider (height: 1.0 ),
110+ ),
111+ const VSpace (20 ),
112+ RowDocument (
113+ viewId: widget.rowController.viewId,
114+ rowId: widget.rowController.rowId,
115+ ),
116+ ],
117+ ),
118+ Positioned (
119+ top: calculateActionsOffset (
120+ state.rowMeta.cover.data.isNotEmpty,
88121 ),
89- const VSpace (20 ),
90- const Padding (
91- padding: EdgeInsets .symmetric (horizontal: 60 ),
92- child: Divider (height: 1.0 ),
93- ),
94- const VSpace (20 ),
95- RowDocument (
96- viewId: widget.rowController.viewId,
97- rowId: widget.rowController.rowId,
122+ right: 12 ,
123+ child: Row (
124+ children: actions (context),
98125 ),
99- ],
100- ),
101- Positioned (
102- top: 12 ,
103- right: 12 ,
104- child: Row (
105- children: _actions (context),
106126 ),
107- ) ,
108- ] ,
127+ ] ,
128+ ) ,
109129 ),
110130 ),
111131 );
112132 }
113133
114- List <Widget > _actions (BuildContext context) {
134+ void onScrollChanged () {
135+ if (scrollOffset != scrollController.offset) {
136+ setState (() => scrollOffset = scrollController.offset);
137+ }
138+ }
139+
140+ double calculateActionsOffset (bool hasCover) {
141+ if (! hasCover) {
142+ return 12 ;
143+ }
144+
145+ final offsetByScroll = clampDouble (
146+ rowCoverHeight - scrollOffset,
147+ 0 ,
148+ rowCoverHeight,
149+ );
150+ return 12 + offsetByScroll;
151+ }
152+
153+ List <Widget > actions (BuildContext context) {
115154 return [
116155 if (widget.allowOpenAsFullPage) ...[
117156 FlowyTooltip (
0 commit comments