feat: improve immersive cover style (#5241)

This commit is contained in:
Lucas.Xu 2024-05-01 22:24:55 +08:00 committed by GitHub
parent a971f3c6d2
commit 6bfac6b80a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 93 additions and 7 deletions

View File

@ -37,6 +37,7 @@ class FlowyAppBar extends AppBar {
Widget? title,
String? titleText,
FlowyAppBarLeadingType leadingType = FlowyAppBarLeadingType.back,
Widget? leading,
super.centerTitle,
VoidCallback? onTapLeading,
bool showDivider = true,
@ -50,7 +51,7 @@ class FlowyAppBar extends AppBar {
),
titleSpacing: 0,
elevation: 0,
leading: leadingType.getWidget(onTapLeading),
leading: leading ?? leadingType.getWidget(onTapLeading),
leadingWidth: leadingType.width,
toolbarHeight: 44.0,
bottom: showDivider

View File

@ -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/view/view_bloc.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_backend/protobuf/flowy-error/errors.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
ScrollNotificationObserverState? _scrollNotificationObserver;
// control the app bar opacity when in immersive mode
final ValueNotifier<double> _appBarOpacity = ValueNotifier(0.0);
// only enable immersive mode for document layout
final ValueNotifier<bool> _isImmersiveMode = ValueNotifier(false);
ViewListener? viewListener;
@override
void initState() {
super.initState();
@ -61,6 +68,8 @@ class _MobileViewPageState extends State<MobileViewPage> {
@override
void dispose() {
_appBarOpacity.dispose();
_isImmersiveMode.dispose();
viewListener?.stop();
_scrollNotificationObserver = null;
super.dispose();
}
@ -87,6 +96,12 @@ class _MobileViewPageState extends State<MobileViewPage> {
} else {
body = state.data!.fold((view) {
viewPB = view;
_updateImmersiveMode(view);
viewListener?.stop();
viewListener = ViewListener(viewId: view.id)
..start(
onViewUpdated: _updateImmersiveMode,
);
actions.addAll([
if (FeatureFlag.syncDocument.isOn) ...[
@ -195,6 +210,15 @@ class _MobileViewPageState extends State<MobileViewPage> {
AppBarTheme.of(context).backgroundColor?.withOpacity(opacity),
showDivider: false,
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,
),
),
@ -230,7 +254,7 @@ class _MobileViewPageState extends State<MobileViewPage> {
}
return AppBarButton(
padding: const EdgeInsets.symmetric(horizontal: 8),
padding: const EdgeInsets.symmetric(vertical: 2.0),
onTap: (context) {
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) {
return AppBarButton(
padding: const EdgeInsets.only(left: 8, right: 16),
padding: const EdgeInsets.only(left: 8, right: 16, top: 2, bottom: 2),
onTap: (context) {
EditorNotification.exitEditing().post();
@ -268,7 +292,49 @@ class _MobileViewPageState extends State<MobileViewPage> {
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) {
return;
}
if (notification is ScrollUpdateNotification &&
defaultScrollNotificationPredicate(notification)) {
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;
}
}
}

View File

@ -103,13 +103,16 @@ class _DocumentImmersiveCoverState extends State<DocumentImmersiveCover> {
_buildIcon(context, icon),
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();
final documentFontFamily =
context.read<DocumentPageStyleBloc>().state.fontFamily;
@ -131,6 +134,9 @@ class _DocumentImmersiveCoverState extends State<DocumentImmersiveCover> {
fontSize: 28.0,
fontWeight: FontWeight.w700,
fontFamily: fontFamily,
color: state.cover.type == PageStyleCoverImageType.none
? null
: Colors.white,
),
onSubmitted: (value) {
scrollController.position.jumpTo(0);