mirror of
				https://github.com/AppFlowy-IO/AppFlowy.git
				synced 2025-10-31 01:54:37 +00:00 
			
		
		
		
	feat: improve immersive cover style (#5241)
This commit is contained in:
		
							parent
							
								
									a971f3c6d2
								
							
						
					
					
						commit
						6bfac6b80a
					
				| @ -37,6 +37,7 @@ class FlowyAppBar extends AppBar { | |||||||
|     Widget? title, |     Widget? title, | ||||||
|     String? titleText, |     String? titleText, | ||||||
|     FlowyAppBarLeadingType leadingType = FlowyAppBarLeadingType.back, |     FlowyAppBarLeadingType leadingType = FlowyAppBarLeadingType.back, | ||||||
|  |     Widget? leading, | ||||||
|     super.centerTitle, |     super.centerTitle, | ||||||
|     VoidCallback? onTapLeading, |     VoidCallback? onTapLeading, | ||||||
|     bool showDivider = true, |     bool showDivider = true, | ||||||
| @ -50,7 +51,7 @@ class FlowyAppBar extends AppBar { | |||||||
|               ), |               ), | ||||||
|           titleSpacing: 0, |           titleSpacing: 0, | ||||||
|           elevation: 0, |           elevation: 0, | ||||||
|           leading: leadingType.getWidget(onTapLeading), |           leading: leading ?? leadingType.getWidget(onTapLeading), | ||||||
|           leadingWidth: leadingType.width, |           leadingWidth: leadingType.width, | ||||||
|           toolbarHeight: 44.0, |           toolbarHeight: 44.0, | ||||||
|           bottom: showDivider |           bottom: showDivider | ||||||
|  | |||||||
| @ -16,6 +16,7 @@ import 'package:appflowy/user/application/reminder/reminder_bloc.dart'; | |||||||
| import 'package:appflowy/workspace/application/favorite/favorite_bloc.dart'; | import 'package:appflowy/workspace/application/favorite/favorite_bloc.dart'; | ||||||
| import 'package:appflowy/workspace/application/view/view_bloc.dart'; | import 'package:appflowy/workspace/application/view/view_bloc.dart'; | ||||||
| import 'package:appflowy/workspace/application/view/view_ext.dart'; | import 'package:appflowy/workspace/application/view/view_ext.dart'; | ||||||
|  | import 'package:appflowy/workspace/application/view/view_listener.dart'; | ||||||
| import 'package:appflowy/workspace/application/view/view_service.dart'; | import 'package:appflowy/workspace/application/view/view_service.dart'; | ||||||
| import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart'; | import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart'; | ||||||
| import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart'; | import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart'; | ||||||
| @ -50,8 +51,14 @@ class _MobileViewPageState extends State<MobileViewPage> { | |||||||
| 
 | 
 | ||||||
|   // used to determine if the user has scrolled down and show the app bar in immersive mode |   // used to determine if the user has scrolled down and show the app bar in immersive mode | ||||||
|   ScrollNotificationObserverState? _scrollNotificationObserver; |   ScrollNotificationObserverState? _scrollNotificationObserver; | ||||||
|  | 
 | ||||||
|  |   // control the app bar opacity when in immersive mode | ||||||
|   final ValueNotifier<double> _appBarOpacity = ValueNotifier(0.0); |   final ValueNotifier<double> _appBarOpacity = ValueNotifier(0.0); | ||||||
| 
 | 
 | ||||||
|  |   // only enable immersive mode for document layout | ||||||
|  |   final ValueNotifier<bool> _isImmersiveMode = ValueNotifier(false); | ||||||
|  |   ViewListener? viewListener; | ||||||
|  | 
 | ||||||
|   @override |   @override | ||||||
|   void initState() { |   void initState() { | ||||||
|     super.initState(); |     super.initState(); | ||||||
| @ -61,6 +68,8 @@ class _MobileViewPageState extends State<MobileViewPage> { | |||||||
|   @override |   @override | ||||||
|   void dispose() { |   void dispose() { | ||||||
|     _appBarOpacity.dispose(); |     _appBarOpacity.dispose(); | ||||||
|  |     _isImmersiveMode.dispose(); | ||||||
|  |     viewListener?.stop(); | ||||||
|     _scrollNotificationObserver = null; |     _scrollNotificationObserver = null; | ||||||
|     super.dispose(); |     super.dispose(); | ||||||
|   } |   } | ||||||
| @ -87,6 +96,12 @@ class _MobileViewPageState extends State<MobileViewPage> { | |||||||
|         } else { |         } else { | ||||||
|           body = state.data!.fold((view) { |           body = state.data!.fold((view) { | ||||||
|             viewPB = view; |             viewPB = view; | ||||||
|  |             _updateImmersiveMode(view); | ||||||
|  |             viewListener?.stop(); | ||||||
|  |             viewListener = ViewListener(viewId: view.id) | ||||||
|  |               ..start( | ||||||
|  |                 onViewUpdated: _updateImmersiveMode, | ||||||
|  |               ); | ||||||
| 
 | 
 | ||||||
|             actions.addAll([ |             actions.addAll([ | ||||||
|               if (FeatureFlag.syncDocument.isOn) ...[ |               if (FeatureFlag.syncDocument.isOn) ...[ | ||||||
| @ -195,6 +210,15 @@ class _MobileViewPageState extends State<MobileViewPage> { | |||||||
|                   AppBarTheme.of(context).backgroundColor?.withOpacity(opacity), |                   AppBarTheme.of(context).backgroundColor?.withOpacity(opacity), | ||||||
|               showDivider: false, |               showDivider: false, | ||||||
|               title: Opacity(opacity: opacity >= 0.99 ? 1.0 : 0, child: title), |               title: Opacity(opacity: opacity >= 0.99 ? 1.0 : 0, child: title), | ||||||
|  |               leading: Padding( | ||||||
|  |                 padding: | ||||||
|  |                     const EdgeInsets.symmetric(horizontal: 2.0, vertical: 4.0), | ||||||
|  |                 child: AppBarButton( | ||||||
|  |                   padding: EdgeInsets.zero, | ||||||
|  |                   onTap: (context) => context.pop(), | ||||||
|  |                   child: _buildImmersiveAppBarIcon(FlowySvgs.m_app_bar_back_s), | ||||||
|  |                 ), | ||||||
|  |               ), | ||||||
|               actions: actions, |               actions: actions, | ||||||
|             ), |             ), | ||||||
|           ), |           ), | ||||||
| @ -230,7 +254,7 @@ class _MobileViewPageState extends State<MobileViewPage> { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return AppBarButton( |     return AppBarButton( | ||||||
|       padding: const EdgeInsets.symmetric(horizontal: 8), |       padding: const EdgeInsets.symmetric(vertical: 2.0), | ||||||
|       onTap: (context) { |       onTap: (context) { | ||||||
|         EditorNotification.exitEditing().post(); |         EditorNotification.exitEditing().post(); | ||||||
| 
 | 
 | ||||||
| @ -250,13 +274,13 @@ class _MobileViewPageState extends State<MobileViewPage> { | |||||||
|           ), |           ), | ||||||
|         ); |         ); | ||||||
|       }, |       }, | ||||||
|       child: const FlowySvg(FlowySvgs.m_layout_s), |       child: _buildImmersiveAppBarIcon(FlowySvgs.m_layout_s), | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   Widget _buildAppBarMoreButton(ViewPB view) { |   Widget _buildAppBarMoreButton(ViewPB view) { | ||||||
|     return AppBarButton( |     return AppBarButton( | ||||||
|       padding: const EdgeInsets.only(left: 8, right: 16), |       padding: const EdgeInsets.only(left: 8, right: 16, top: 2, bottom: 2), | ||||||
|       onTap: (context) { |       onTap: (context) { | ||||||
|         EditorNotification.exitEditing().post(); |         EditorNotification.exitEditing().post(); | ||||||
| 
 | 
 | ||||||
| @ -268,7 +292,49 @@ class _MobileViewPageState extends State<MobileViewPage> { | |||||||
|           builder: (_) => _buildAppBarMoreBottomSheet(context), |           builder: (_) => _buildAppBarMoreBottomSheet(context), | ||||||
|         ); |         ); | ||||||
|       }, |       }, | ||||||
|       child: const FlowySvg(FlowySvgs.m_app_bar_more_s), |       child: _buildImmersiveAppBarIcon(FlowySvgs.m_app_bar_more_s), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   Widget _buildImmersiveAppBarIcon(FlowySvgData icon) { | ||||||
|  |     return ValueListenableBuilder( | ||||||
|  |       valueListenable: _isImmersiveMode, | ||||||
|  |       builder: (context, isImmersiveMode, child) { | ||||||
|  |         return ValueListenableBuilder( | ||||||
|  |           valueListenable: _appBarOpacity, | ||||||
|  |           builder: (context, appBarOpacity, child) { | ||||||
|  |             Color? color; | ||||||
|  | 
 | ||||||
|  |             // if there's no cover or the cover is not immersive, | ||||||
|  |             //  make sure the app bar is always visible | ||||||
|  |             if (!isImmersiveMode) { | ||||||
|  |               color = null; | ||||||
|  |             } else if (appBarOpacity < 0.99) { | ||||||
|  |               color = Colors.white; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             Widget child = Container( | ||||||
|  |               margin: const EdgeInsets.symmetric(horizontal: 8, vertical: 6), | ||||||
|  |               child: FlowySvg( | ||||||
|  |                 icon, | ||||||
|  |                 color: color, | ||||||
|  |               ), | ||||||
|  |             ); | ||||||
|  | 
 | ||||||
|  |             if (isImmersiveMode && appBarOpacity <= 0.99) { | ||||||
|  |               child = DecoratedBox( | ||||||
|  |                 decoration: BoxDecoration( | ||||||
|  |                   borderRadius: BorderRadius.circular(22), | ||||||
|  |                   color: Colors.black.withOpacity(0.2), | ||||||
|  |                 ), | ||||||
|  |                 child: child, | ||||||
|  |               ); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             return child; | ||||||
|  |           }, | ||||||
|  |         ); | ||||||
|  |       }, | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| @ -331,6 +397,7 @@ class _MobileViewPageState extends State<MobileViewPage> { | |||||||
|     if (_scrollNotificationObserver == null) { |     if (_scrollNotificationObserver == null) { | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     if (notification is ScrollUpdateNotification && |     if (notification is ScrollUpdateNotification && | ||||||
|         defaultScrollNotificationPredicate(notification)) { |         defaultScrollNotificationPredicate(notification)) { | ||||||
|       final ScrollMetrics metrics = notification.metrics; |       final ScrollMetrics metrics = notification.metrics; | ||||||
| @ -344,4 +411,16 @@ class _MobileViewPageState extends State<MobileViewPage> { | |||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   void _updateImmersiveMode(ViewPB view) { | ||||||
|  |     final cover = view.cover; | ||||||
|  |     if (cover == null || cover.type == PageStyleCoverImageType.none) { | ||||||
|  |       _isImmersiveMode.value = false; | ||||||
|  |     } else if (view.layout != ViewLayoutPB.Document) { | ||||||
|  |       // only support immersive mode for document layout | ||||||
|  |       _isImmersiveMode.value = false; | ||||||
|  |     } else { | ||||||
|  |       _isImmersiveMode.value = true; | ||||||
|  |     } | ||||||
|  |   } | ||||||
| } | } | ||||||
|  | |||||||
| @ -103,13 +103,16 @@ class _DocumentImmersiveCoverState extends State<DocumentImmersiveCover> { | |||||||
|             _buildIcon(context, icon), |             _buildIcon(context, icon), | ||||||
|             const HSpace(8.0), |             const HSpace(8.0), | ||||||
|           ], |           ], | ||||||
|           Expanded(child: _buildTitle(context)), |           Expanded(child: _buildTitle(context, state)), | ||||||
|         ], |         ], | ||||||
|       ), |       ), | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   Widget _buildTitle(BuildContext context) { |   Widget _buildTitle( | ||||||
|  |     BuildContext context, | ||||||
|  |     DocumentImmersiveCoverState state, | ||||||
|  |   ) { | ||||||
|     String? fontFamily = builtInFontFamily(); |     String? fontFamily = builtInFontFamily(); | ||||||
|     final documentFontFamily = |     final documentFontFamily = | ||||||
|         context.read<DocumentPageStyleBloc>().state.fontFamily; |         context.read<DocumentPageStyleBloc>().state.fontFamily; | ||||||
| @ -131,6 +134,9 @@ class _DocumentImmersiveCoverState extends State<DocumentImmersiveCover> { | |||||||
|         fontSize: 28.0, |         fontSize: 28.0, | ||||||
|         fontWeight: FontWeight.w700, |         fontWeight: FontWeight.w700, | ||||||
|         fontFamily: fontFamily, |         fontFamily: fontFamily, | ||||||
|  |         color: state.cover.type == PageStyleCoverImageType.none | ||||||
|  |             ? null | ||||||
|  |             : Colors.white, | ||||||
|       ), |       ), | ||||||
|       onSubmitted: (value) { |       onSubmitted: (value) { | ||||||
|         scrollController.position.jumpTo(0); |         scrollController.position.jumpTo(0); | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Lucas.Xu
						Lucas.Xu