diff --git a/lib/pages/member/widget/header_layout_widget.dart b/lib/pages/member/widget/header_layout_widget.dart new file mode 100644 index 000000000..bf444ccf9 --- /dev/null +++ b/lib/pages/member/widget/header_layout_widget.dart @@ -0,0 +1,117 @@ +/* + * This file is part of PiliPlus + * + * PiliPlus is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PiliPlus is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with PiliPlus. If not, see . + */ + +import 'dart:math' as math; + +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart' + show + ContainerRenderObjectMixin, + MultiChildLayoutParentData, + RenderBoxContainerDefaultsMixin, + BoxHitTestResult; + +const double kHeaderHeight = 135.0; + +const double kAvatarSize = 80.0; +const double _kAvatarLeftPadding = 20.0; +const double _kAvatarTopPadding = 110.0; +const double _kAvatarEffectiveHeight = + kAvatarSize - (kHeaderHeight - _kAvatarTopPadding); + +const double _kActionsTopPadding = 140.0; +const double _kActionsLeftPadding = 160.0; +const double _kActionsRightPadding = 15.0; + +enum HeaderType { header, avatar, actions } + +class HeaderLayoutWidget extends MultiChildRenderObjectWidget { + const HeaderLayoutWidget({ + super.key, + super.children, + }); + + @override + RenderObject createRenderObject(BuildContext context) { + return RenderHeaderWidget(); + } +} + +class RenderHeaderWidget extends RenderBox + with + ContainerRenderObjectMixin, + RenderBoxContainerDefaultsMixin { + @override + void setupParentData(RenderBox child) { + if (child.parentData is! MultiChildLayoutParentData) { + child.parentData = MultiChildLayoutParentData(); + } + } + + @override + void performLayout() { + double height = kHeaderHeight; + RenderBox? child = firstChild; + final maxWidth = constraints.maxWidth; + while (child != null) { + final childParentData = child.parentData! as MultiChildLayoutParentData; + + switch (childParentData.id as HeaderType) { + case HeaderType.header: + child.layout(constraints); + childParentData.offset = .zero; + case HeaderType.avatar: + child.layout(constraints); + childParentData.offset = const Offset( + _kAvatarLeftPadding, + _kAvatarTopPadding, + ); + case HeaderType.actions: + final childSize = + (child..layout( + BoxConstraints( + maxWidth: + maxWidth - + _kActionsLeftPadding - + _kActionsRightPadding, + ), + parentUsesSize: true, + )) + .size; + height += (math.max(_kAvatarEffectiveHeight, childSize.height)) + 5.0; + childParentData.offset = Offset( + maxWidth - childSize.width - _kActionsRightPadding, + _kActionsTopPadding, + ); + } + + child = childParentData.nextSibling; + } + + size = constraints.constrainDimensions(maxWidth, height); + } + + @override + void paint(PaintingContext context, Offset offset) { + defaultPaint(context, offset); + } + + @override + bool hitTestChildren(BoxHitTestResult result, {required Offset position}) { + return defaultHitTestChildren(result, position: position); + } +} diff --git a/lib/pages/member/widget/user_info_card.dart b/lib/pages/member/widget/user_info_card.dart index 13fb5ceb3..b6b0a5e19 100644 --- a/lib/pages/member/widget/user_info_card.dart +++ b/lib/pages/member/widget/user_info_card.dart @@ -12,6 +12,7 @@ import 'package:PiliPlus/models_new/space/space/pr_info.dart'; import 'package:PiliPlus/pages/fan/view.dart'; import 'package:PiliPlus/pages/follow/view.dart'; import 'package:PiliPlus/pages/follow_type/followed/view.dart'; +import 'package:PiliPlus/pages/member/widget/header_layout_widget.dart'; import 'package:PiliPlus/utils/accounts.dart'; import 'package:PiliPlus/utils/app_scheme.dart'; import 'package:PiliPlus/utils/extension/context_ext.dart'; @@ -128,7 +129,7 @@ class UserInfoCard extends StatelessWidget { tag: imgUrl, child: CachedNetworkImage( fit: .cover, - height: 135, + height: kHeaderHeight, width: width, memCacheWidth: width.cacheSize(context), imageUrl: ImageUtils.thumbnailUrl(imgUrl), @@ -457,7 +458,7 @@ class UserInfoCard extends StatelessWidget { tag: card.face ?? '', child: PendantAvatar( avatar: card.face, - size: 80, + size: kAvatarSize, badgeSize: 20, officialType: card.officialVerify?.type, isVip: (card.vip?.status ?? -1) > 0, @@ -478,29 +479,18 @@ class UserInfoCard extends StatelessWidget { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - Stack( - clipBehavior: Clip.none, + HeaderLayoutWidget( children: [ - Column( - crossAxisAlignment: .stretch, - mainAxisSize: MainAxisSize.min, - children: [ - _buildHeader(context, colorScheme, isLight, width), - SizedBox( - height: MediaQuery.textScalerOf(context).scale(30) + 60, - ), - ], + LayoutId( + id: HeaderType.header, + child: _buildHeader(context, colorScheme, isLight, width), ), - Positioned( - top: 110, - left: 20, + LayoutId( + id: HeaderType.avatar, child: _buildAvatar, ), - Positioned( - left: 160, - top: 140, - right: 15, - bottom: 0, + LayoutId( + id: HeaderType.actions, child: _buildRight(colorScheme), ), ],