mirror of
https://github.com/bggRGjQaUbCoE/PiliPlus.git
synced 2026-07-25 21:10:13 +08:00
@@ -67,7 +67,7 @@ class _ArticlePageState extends CommonDynPageState<ArticlePage> {
|
||||
child: _buildBottom(),
|
||||
),
|
||||
);
|
||||
return fabAnimWrapper(child);
|
||||
return fabAnimWrapper(child: child);
|
||||
}
|
||||
|
||||
Widget _buildPage() {
|
||||
|
||||
@@ -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,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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> {
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -506,7 +506,7 @@ class _DynamicDetailPageState
|
||||
} else {
|
||||
child = _buildHorizontal(padding);
|
||||
}
|
||||
return fabAnimWrapper(child);
|
||||
return fabAnimWrapper(child: child);
|
||||
}
|
||||
|
||||
Widget _buildBottom() {
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -62,7 +62,7 @@ class _MatchInfoPageState extends CommonDynPageState<MatchInfoPage> {
|
||||
child: fabButton,
|
||||
),
|
||||
);
|
||||
return fabAnimWrapper(child);
|
||||
return fabAnimWrapper(child: child);
|
||||
}
|
||||
|
||||
Widget _buildInfo(LoadingState<MatchContest?> infoState) {
|
||||
|
||||
@@ -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: [
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -67,7 +67,7 @@ class _MusicDetailPageState extends CommonDynPageState<MusicDetailPage> {
|
||||
: _buildBody(),
|
||||
),
|
||||
);
|
||||
return fabAnimWrapper(child);
|
||||
return fabAnimWrapper(child: child);
|
||||
}
|
||||
|
||||
PreferredSizeWidget _buildAppBar() => AppBar(
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user