fix(player): 调整双击飘心动画

This commit is contained in:
Zhou Weidong committed 2026-10-26 18:11:01 +08:00
1 parent 63296d2a92
commit bea50ab32f
8 files changed
+52 -20

No files matched your search

+3
View File
@@ -639,6 +639,7 @@ class _PlayerPageState extends State<PlayerPage>
);
return Stack(
fit: StackFit.expand,
clipBehavior: Clip.none,
children: [
PlayerRenderStack(
pageController: _pageController,
@@ -662,6 +663,7 @@ class _PlayerPageState extends State<PlayerPage>
);
final body = Stack(
fit: StackFit.expand,
clipBehavior: Clip.none,
children: [
content,
if (widget.homeMode &&
@@ -971,6 +973,7 @@ class _PlayerPageState extends State<PlayerPage>
return Stack(
fit: StackFit.expand,
clipBehavior: Clip.none,
children: [
if (selected &&
!entryLoading &&
@@ -126,6 +126,7 @@ class _HomeFeedOverlayState extends State<HomeFeedOverlay> {
return SafeArea(
bottom: false,
child: Stack(
clipBehavior: Clip.none,
children: [
Positioned.fill(
child: PlayerTapGestureRegion(
@@ -4,31 +4,32 @@ import 'package:flutter/material.dart';
import '../../../core/theme/app_colors.dart';
const int _heartDurationMs = 680;
const int _heartDurationMs = 1300;
const int _lastHeartDelayMs = 200;
const double _heartPopPortion = 0.18;
const double _heartStartScale = 0.7;
const double _heartHoldPortion = 0.45;
const double _heartHoldPortion = 0.65;
const List<_HeartParticle> _hearts = [
_HeartParticle(
delay: 0,
travel: 108,
travel: 175,
drift: 0,
size: 48,
size: 44,
color: AppColors.doubleTapHeartRed,
),
_HeartParticle(
delay: 50,
travel: 96,
drift: -28,
size: 36,
delay: 110,
travel: 150,
drift: -32,
size: 34,
color: AppColors.doubleTapHeartPink,
),
_HeartParticle(
delay: 90,
travel: 118,
drift: 26,
size: 40,
delay: _lastHeartDelayMs,
travel: 165,
drift: 30,
size: 38,
color: AppColors.doubleTapHeartRed,
),
];
@@ -38,6 +39,10 @@ class PlayerDoubleTapHeartBurst extends StatefulWidget {
const PlayerDoubleTapHeartBurst({super.key, required this.onCompleted});
static const int particleCount = 3;
static const int singleHeartDurationMs = _heartDurationMs;
static const Duration animationDuration = Duration(
milliseconds: _lastHeartDelayMs + _heartDurationMs,
);
final VoidCallback onCompleted;
@@ -55,6 +55,7 @@ class PlayerPlaybackOverlay extends StatelessWidget {
Widget build(BuildContext context) {
return SafeArea(
child: Stack(
clipBehavior: Clip.none,
children: [
Positioned.fill(
child: PlayerTapGestureRegion(
@@ -70,6 +70,7 @@ class _PlayerTapGestureRegionState extends State<PlayerTapGestureRegion> {
onPointerDown: _handlePointerDown,
child: Stack(
fit: StackFit.expand,
clipBehavior: Clip.none,
children: [
GestureDetector(
key: widget.gestureKey,
+1 -1
View File
@@ -91,7 +91,7 @@ void main() {
await tester.tapAt(center);
await tester.pump();
expect(repository.likeTargets, hasLength(1));
await tester.pump(const Duration(milliseconds: 800));
await tester.pump(const Duration(milliseconds: 1600));
clock.advance(const Duration(milliseconds: 500));
await tester.pump(const Duration(milliseconds: 500));
+25 -4
View File
@@ -13,12 +13,33 @@ void main() {
home: Scaffold(body: PlayerDoubleTapHeartBurst(onCompleted: _noop)),
),
);
await tester.pump(const Duration(milliseconds: 160));
await tester.pump(const Duration(milliseconds: 300));
expect(find.byIcon(Icons.favorite_rounded), findsNWidgets(3));
expect(_size(tester, 0), 48);
expect(_size(tester, 1), 36);
expect(_size(tester, 2), 40);
expect(_size(tester, 0), 44);
expect(_size(tester, 1), 34);
expect(_size(tester, 2), 38);
expect(
tester
.widgetList<Stack>(
find.descendant(
of: find.byType(PlayerDoubleTapHeartBurst),
matching: find.byType(Stack),
),
)
.every((stack) => stack.clipBehavior == Clip.none),
isTrue,
);
});
test('heart burst stays long and sparse', () {
expect(PlayerDoubleTapHeartBurst.singleHeartDurationMs, 1300);
expect(
PlayerDoubleTapHeartBurst.animationDuration,
greaterThanOrEqualTo(const Duration(milliseconds: 1200)),
);
expect(PlayerDoubleTapHeartBurst.particleCount, lessThanOrEqualTo(4));
expect(PlayerDoubleTapHeartBurst.particleCount, 3);
});
}
+3 -3
View File
@@ -679,7 +679,7 @@ void main() {
await tester.tapAt(position);
}
await tester.pump();
await tester.pump(const Duration(milliseconds: 100));
await tester.pump(const Duration(milliseconds: 300));
expect(logic.session.userWantsPlay, isTrue);
expect(find.byKey(const Key('player-play-toggle')), findsNothing);
@@ -699,7 +699,7 @@ void main() {
AppColors.doubleTapHeartRed,
);
await tester.pump(const Duration(milliseconds: 800));
await tester.pump(const Duration(milliseconds: 1600));
expect(find.byKey(const Key('double-tap-heart-0')), findsNothing);
expect(logic.session.userWantsPlay, isTrue);
});
@@ -722,7 +722,7 @@ void main() {
await tester.tapAt(const Offset(80, 300));
await tester.tapAt(const Offset(80, 300));
await tester.pump();
await tester.pump(const Duration(milliseconds: 100));
await tester.pump(const Duration(milliseconds: 300));
expect(logic.session.userWantsPlay, isTrue);
expect(interactions.likeTargets, hasLength(1));