fix(flutter): feed 长按加速与刷新转圈

This commit is contained in:
Zhou Weidong committed 2026-10-20 14:19:14 +08:00
1 parent 564c0dbbef
commit ea9ea6e606
5 files changed
+317 -103

No files matched your search

+96 -12
View File
@@ -27,6 +27,9 @@ const double _tagFontSize = 11;
const double _fullBarHeight = 44;
const double _progressHeight = 2;
const double _progressHitHeight = 24;
const List<Shadow> _boostTextShadows = [
Shadow(color: Colors.black54, blurRadius: 5, offset: Offset(0, 1)),
];
const int _maxTags = 4;
final RegExp _tagSplitter = RegExp(r'[,/、·]');
@@ -40,6 +43,8 @@ class HomeFeedOverlay extends StatefulWidget {
required this.controller,
required this.liked,
required this.saved,
required this.visible,
required this.boosting,
required this.onLike,
required this.onSave,
required this.onComments,
@@ -51,6 +56,9 @@ class HomeFeedOverlay extends StatefulWidget {
required this.onDownload,
required this.onClear,
required this.onSearch,
required this.onTogglePlay,
required this.onBoostStart,
required this.onBoostEnd,
this.onScrubStart,
this.onSeek,
this.likeCount,
@@ -70,6 +78,8 @@ class HomeFeedOverlay extends StatefulWidget {
final int? commentCount;
final bool saved;
final String authorNote;
final bool visible;
final bool boosting;
final VoidCallback onLike;
final VoidCallback onSave;
final VoidCallback onComments;
@@ -77,13 +87,16 @@ class HomeFeedOverlay extends StatefulWidget {
final VoidCallback onEpisodes;
final VoidCallback onDetail;
final VoidCallback onOpenFullPlayer;
final VoidCallback onRefreshFeed;
final Future<bool> Function() onRefreshFeed;
final VoidCallback onDownload;
final VoidCallback onClear;
final VoidCallback onSearch;
final VoidCallback onTogglePlay;
final VoidCallback? onPip;
final VoidCallback? onScrubStart;
final ValueChanged<Duration>? onSeek;
final VoidCallback onBoostStart;
final VoidCallback onBoostEnd;
@override
State<HomeFeedOverlay> createState() => _HomeFeedOverlayState();
@@ -91,30 +104,100 @@ class HomeFeedOverlay extends StatefulWidget {
class _HomeFeedOverlayState extends State<HomeFeedOverlay> {
_FeedTab _tab = _FeedTab.recommend;
bool _refreshing = false;
@override
Widget build(BuildContext context) {
return SafeArea(
bottom: false,
child: Column(
child: Stack(
children: [
_header(context),
Expanded(
child: Align(
alignment: const Alignment(1.0, 0.68),
child: Padding(
padding: const EdgeInsets.fromLTRB(0, 0, 10, 16),
child: _rail(),
Positioned.fill(
child: LayoutBuilder(
builder: (context, constraints) => Listener(
onPointerUp: (_) => widget.onBoostEnd(),
onPointerCancel: (_) => widget.onBoostEnd(),
child: GestureDetector(
key: const Key('home-feed-gesture'),
behavior: HitTestBehavior.opaque,
onTap: widget.onTogglePlay,
onLongPressStart: (details) =>
_handleLongPressStart(details, constraints.maxWidth),
onLongPressEnd: (_) => widget.onBoostEnd(),
onLongPressCancel: widget.onBoostEnd,
),
),
),
),
_bottomInfo(),
_fullSeriesBar(),
if (widget.boosting)
Column(children: [const Spacer(), _boostHint(), _fullSeriesBar()])
else if (widget.visible)
Column(
children: [
_header(context),
Expanded(
child: Align(
alignment: const Alignment(1.0, 0.80),
child: Padding(
padding: const EdgeInsets.fromLTRB(0, 0, 10, 16),
child: _rail(),
),
),
),
_bottomInfo(),
_fullSeriesBar(),
],
),
],
),
);
}
void _handleLongPressStart(LongPressStartDetails details, double width) {
final third = width / 3;
final dx = details.localPosition.dx;
if (dx < third || dx > width - third) {
widget.onBoostStart();
return;
}
_openMore(context);
}
Widget _boostHint() {
return Padding(
key: const Key('home-feed-speed-boost-hint'),
padding: const EdgeInsets.only(bottom: 8),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(
Icons.play_arrow_rounded,
color: AppColors.blue,
size: 16,
shadows: _boostTextShadows,
),
const SizedBox(width: 4),
Text(
widget.l10n.speedBoosting('2.0'),
style: const TextStyle(
color: AppColors.blue,
fontSize: 13,
fontWeight: FontWeight.w700,
shadows: _boostTextShadows,
),
),
],
),
);
}
Future<void> _refresh() async {
if (_refreshing) return;
setState(() => _refreshing = true);
await widget.onRefreshFeed();
if (mounted) setState(() => _refreshing = false);
}
Widget _header(BuildContext context) {
return Padding(
padding: const EdgeInsets.fromLTRB(8, 6, 8, 4),
@@ -124,7 +207,8 @@ class _HomeFeedOverlayState extends State<HomeFeedOverlay> {
tooltip: widget.l10n.retry,
dimension: _topIconSize,
glyphSize: _topIconGlyph,
onTap: widget.onRefreshFeed,
refreshing: _refreshing,
onTap: _refresh,
onLongPress: () => _openMore(context),
),
Expanded(