Signed-off-by: dom <githubaccount56556@proton.me>
This commit is contained in:
dom
2026-07-20 22:44:09 +08:00
parent db65e7df76
commit 7617bb692a
21 changed files with 279 additions and 280 deletions

View File

@@ -67,7 +67,7 @@ class _ArticlePageState extends CommonDynPageState<ArticlePage> {
child: _buildBottom(),
),
);
return fabAnimWrapper(child);
return fabAnimWrapper(child: child);
}
Widget _buildPage() {

View File

@@ -86,6 +86,14 @@ mixin CommonDynPageMixin<T extends StatefulWidget>
padding = MediaQuery.viewPaddingOf(context);
}
@override
bool onNotification(UserScrollNotification notification) {
if (notification.metrics.axisDirection == .down) {
return super.onNotification(notification);
}
return false;
}
Widget buildReplyHeader() {
final secondary = theme.colorScheme.secondary;
return SliverPinnedHeader(
@@ -331,22 +339,4 @@ mixin CommonDynPageMixin<T extends StatefulWidget>
tooltip: '评论',
child: const Icon(Icons.reply),
);
Widget fabAnimWrapper(Widget child) {
return NotificationListener<UserScrollNotification>(
onNotification: (notification) {
if (notification.metrics.axisDirection == .down) {
switch (notification.direction) {
case .forward:
showFab();
case .reverse:
hideFab();
default:
}
}
return false;
},
child: child,
);
}
}

View File

@@ -34,6 +34,24 @@ mixin BaseFabMixin<T extends StatefulWidget> on State<T>, TickerProvider {
fabAnimationCtr.forward();
}
}
Widget fabAnimWrapper({required Widget child}) {
return NotificationListener<UserScrollNotification>(
onNotification: onNotification,
child: child,
);
}
bool onNotification(UserScrollNotification notification) {
switch (notification.direction) {
case .forward:
showFab();
case .reverse:
hideFab();
default:
}
return false;
}
}
mixin FabMixin<T extends StatefulWidget> on BaseFabMixin<T> {

View File

@@ -4,8 +4,8 @@ import 'package:PiliPlus/common/assets.dart';
import 'package:PiliPlus/common/style.dart';
import 'package:PiliPlus/common/widgets/custom_icon.dart';
import 'package:PiliPlus/common/widgets/dialog/report.dart';
import 'package:PiliPlus/common/widgets/extra_hit_test_widget.dart';
import 'package:PiliPlus/common/widgets/pendant_avatar.dart';
import 'package:PiliPlus/common/widgets/translucent_row.dart';
import 'package:PiliPlus/http/constants.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/http/reply.dart';
@@ -94,49 +94,51 @@ class AuthorPanel extends StatelessWidget {
);
}
}
Widget header = GestureDetector(
onTap: moduleAuthor.type == 'AUTHOR_TYPE_NORMAL'
? () {
feedBack();
Get.toNamed('/member?mid=${moduleAuthor.mid}');
}
: null,
child: ExtraHitTestWidget(
width: 50,
child: Row(
spacing: 10,
final children = [
PendantAvatar(
size: 40,
moduleAuthor.face,
pendantImage: moduleAuthor.pendant?.image,
),
Flexible(
child: Column(
crossAxisAlignment: .start,
children: [
PendantAvatar(
size: 40,
moduleAuthor.face,
pendantImage: moduleAuthor.pendant?.image,
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
moduleAuthor.name!,
maxLines: 1,
overflow: .ellipsis,
style: TextStyle(
color:
moduleAuthor.vip != null &&
moduleAuthor.vip!.status > 0 &&
moduleAuthor.vip!.type == 2
? theme.colorScheme.vipColor
: theme.colorScheme.onSurface,
fontSize: theme.textTheme.titleSmall!.fontSize,
),
),
?pubTs,
],
Text(
moduleAuthor.name!,
maxLines: 1,
overflow: .ellipsis,
style: TextStyle(
color:
moduleAuthor.vip != null &&
moduleAuthor.vip!.status > 0 &&
moduleAuthor.vip!.type == 2
? theme.colorScheme.vipColor
: theme.colorScheme.onSurface,
fontSize: theme.textTheme.titleSmall!.fontSize,
),
),
?pubTs,
],
),
),
);
];
Widget header;
if (moduleAuthor.type == 'AUTHOR_TYPE_NORMAL') {
header = GestureDetector(
onTap: () => {
feedBack(),
Get.toNamed('/member?mid=${moduleAuthor.mid}'),
},
child: TranslucentRow(
spacing: 10,
extraWidth: 50,
children: children,
),
);
} else {
header = Row(spacing: 10, children: children);
}
Widget? moreBtn = isSave
? null
: SizedBox(

View File

@@ -506,7 +506,7 @@ class _DynamicDetailPageState
} else {
child = _buildHorizontal(padding);
}
return fabAnimWrapper(child);
return fabAnimWrapper(child: child);
}
Widget _buildBottom() {

View File

@@ -65,16 +65,7 @@ class _DynTopicPageState extends State<DynTopicPage>
children: [
refreshIndicator(
onRefresh: _controller.onRefresh,
child: NotificationListener<UserScrollNotification>(
onNotification: (notification) {
final direction = notification.direction;
if (direction == .forward) {
showFab();
} else if (direction == .reverse) {
hideFab();
}
return false;
},
child: fabAnimWrapper(
child: CustomScrollView(
controller: _controller.scrollController,
physics: const AlwaysScrollableScrollPhysics(),

View File

@@ -112,18 +112,7 @@ class _FollowChildPageState extends State<FollowChildPage>
return Stack(
clipBehavior: Clip.none,
children: [
NotificationListener<UserScrollNotification>(
onNotification: (notification) {
final direction = notification.direction;
if (direction == .forward) {
showFab();
} else if (direction == .reverse) {
hideFab();
}
return false;
},
child: child,
),
fabAnimWrapper(child: child),
Positioned(
right: kFloatingActionButtonMargin + padding.right,
bottom: 0,

View File

@@ -60,16 +60,7 @@ class _MainReplyPageState extends State<MainReplyPage>
return Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(title: const Text('查看评论')),
body: NotificationListener<UserScrollNotification>(
onNotification: (notification) {
final direction = notification.direction;
if (direction == .forward) {
showFab();
} else if (direction == .reverse) {
hideFab();
}
return false;
},
body: fabAnimWrapper(
child: refreshIndicator(
onRefresh: _controller.onRefresh,
child: Padding(

View File

@@ -62,7 +62,7 @@ class _MatchInfoPageState extends CommonDynPageState<MatchInfoPage> {
child: fabButton,
),
);
return fabAnimWrapper(child);
return fabAnimWrapper(child: child);
}
Widget _buildInfo(LoadingState<MatchContest?> infoState) {

View File

@@ -59,16 +59,7 @@ class _MemberOpusState extends State<MemberOpus>
children: [
refreshIndicator(
onRefresh: _controller.onRefresh,
child: NotificationListener<UserScrollNotification>(
onNotification: (notification) {
final direction = notification.direction;
if (direction == .forward) {
showFab();
} else if (direction == .reverse) {
hideFab();
}
return false;
},
child: fabAnimWrapper(
child: CustomScrollView(
physics: const AlwaysScrollableScrollPhysics(),
slivers: [

View File

@@ -119,18 +119,7 @@ class _MemberVideoState extends State<MemberVideo>
return Stack(
clipBehavior: Clip.none,
children: [
NotificationListener<UserScrollNotification>(
onNotification: (notification) {
final direction = notification.direction;
if (direction == .forward) {
showFab();
} else if (direction == .reverse) {
hideFab();
}
return false;
},
child: child,
),
fabAnimWrapper(child: child),
Obx(
() => !_controller.isLocating.value
? Positioned(

View File

@@ -67,7 +67,7 @@ class _MusicDetailPageState extends CommonDynPageState<MusicDetailPage> {
: _buildBody(),
),
);
return fabAnimWrapper(child);
return fabAnimWrapper(child: child);
}
PreferredSizeWidget _buildAppBar() => AppBar(

View File

@@ -68,17 +68,7 @@ class _VideoReplyPanelState extends State<VideoReplyPanel>
@override
Widget build(BuildContext context) {
super.build(context);
final child = NotificationListener<UserScrollNotification>(
onNotification: (notification) {
switch (notification.direction) {
case .forward:
showFab();
case .reverse:
hideFab();
case _:
}
return false;
},
final child = fabAnimWrapper(
child: refreshIndicator(
onRefresh: _videoReplyController.onRefresh,
isClampingScrollPhysics: widget.isNested,

View File

@@ -7,13 +7,13 @@ import 'package:PiliPlus/common/widgets/badge.dart';
import 'package:PiliPlus/common/widgets/custom_icon.dart';
import 'package:PiliPlus/common/widgets/dialog/dialog.dart';
import 'package:PiliPlus/common/widgets/dialog/report.dart';
import 'package:PiliPlus/common/widgets/extra_hit_test_widget.dart';
import 'package:PiliPlus/common/widgets/flutter/text/text.dart' as custom_text;
import 'package:PiliPlus/common/widgets/gesture/tap_gesture_recognizer.dart';
import 'package:PiliPlus/common/widgets/image/network_img_layer.dart';
import 'package:PiliPlus/common/widgets/image_grid/image_grid_view.dart';
import 'package:PiliPlus/common/widgets/pendant_avatar.dart';
import 'package:PiliPlus/common/widgets/selection_text.dart';
import 'package:PiliPlus/common/widgets/translucent_row.dart';
import 'package:PiliPlus/grpc/bilibili/main/community/reply/v1.pb.dart'
show ReplyInfo, ReplyControl, Content, Url, ReplyControl_VoteOption, Emote;
import 'package:PiliPlus/grpc/reply.dart';
@@ -32,7 +32,6 @@ import 'package:PiliPlus/utils/app_scheme.dart';
import 'package:PiliPlus/utils/bili_utils.dart';
import 'package:PiliPlus/utils/color_utils.dart';
import 'package:PiliPlus/utils/danmaku_utils.dart';
import 'package:PiliPlus/utils/date_utils.dart';
import 'package:PiliPlus/utils/duration_utils.dart';
import 'package:PiliPlus/utils/extension/context_ext.dart';
import 'package:PiliPlus/utils/extension/iterable_ext.dart';
@@ -153,105 +152,87 @@ class ReplyItemGrpc extends StatelessWidget {
feedBack();
Get.toNamed('/member?mid=${replyItem.mid}');
},
child: ExtraHitTestWidget(
width: 46,
child: Row(
crossAxisAlignment: .center,
spacing: 12,
children: [
PendantAvatar(
member.face,
size: 34,
badgeSize: 14,
vipStatus: member.vipStatus.toInt(),
officialType: member.officialVerifyType.toInt(),
pendantImage: member.hasGarbPendantImage()
? member.garbPendantImage
: null,
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Row(
spacing: 6,
children: [
Flexible(
child: Text(
member.name,
maxLines: 1,
overflow: .ellipsis,
style: TextStyle(
color: (member.vipStatus > 0 && member.vipType == 2)
? colorScheme.vipColor
: colorScheme.outline,
fontSize: 13,
),
),
),
BiliUtils.levelPicture(
member.level.toInt(),
isSeniorMember: member.isSeniorMember == 1,
height: 11,
),
if (replyItem.mid == upMid)
const PBadge(
text: 'UP',
size: PBadgeSize.small,
isStack: false,
fontSize: 9,
)
else if (GlobalData().showMedal &&
member.hasFansMedalLevel())
MedalWidget(
medalName: member.fansMedalName,
level: member.fansMedalLevel.toInt(),
backgroundColor: DmUtils.decimalToColor(
member.fansMedalColor.toInt(),
),
nameColor: DmUtils.decimalToColor(
member.fansMedalColorName.toInt(),
),
padding: const .symmetric(
horizontal: 6,
vertical: 1.5,
),
),
],
),
Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
replyLevel == 0
? DateFormatUtils.format(
replyItem.ctime.toInt(),
format: DateFormatUtils.longFormatDs,
)
: DateFormatUtils.dateFormat(
replyItem.ctime.toInt(),
),
child: TranslucentRow(
spacing: 12,
extraWidth: 46,
children: [
PendantAvatar(
member.face,
size: 34,
badgeSize: 14,
vipStatus: member.vipStatus.toInt(),
officialType: member.officialVerifyType.toInt(),
pendantImage: member.hasGarbPendantImage()
? member.garbPendantImage
: null,
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Row(
spacing: 6,
children: [
Flexible(
child: Text(
member.name,
maxLines: 1,
overflow: .ellipsis,
style: TextStyle(
fontSize: 11,
color: colorScheme.outline,
color: (member.vipStatus > 0 && member.vipType == 2)
? colorScheme.vipColor
: colorScheme.outline,
fontSize: 13,
),
),
if (replyItem.replyControl.hasLocation())
Text(
'${replyItem.replyControl.location}',
style: TextStyle(
fontSize: 11,
color: colorScheme.outline,
),
),
BiliUtils.levelPicture(
member.level.toInt(),
isSeniorMember: member.isSeniorMember == 1,
height: 11,
),
if (replyItem.mid == upMid)
const PBadge(
text: 'UP',
size: PBadgeSize.small,
isStack: false,
fontSize: 9,
)
else if (GlobalData().showMedal &&
member.hasFansMedalLevel())
MedalWidget(
medalName: member.fansMedalName,
level: member.fansMedalLevel.toInt(),
backgroundColor: DmUtils.decimalToColor(
member.fansMedalColor.toInt(),
),
],
),
],
),
nameColor: DmUtils.decimalToColor(
member.fansMedalColorName.toInt(),
),
padding: const .symmetric(
horizontal: 6,
vertical: 1.5,
),
),
],
),
Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
'${replyItem.replyControl.location}',
style: TextStyle(
fontSize: 11,
color: colorScheme.outline,
),
),
],
),
],
),
],
),
),
],
),
);
if (PendantAvatar.showDecorate) {