fix(player): 调整双击飘心动画
This commit is contained in:
1 parent
63296d2a92
commit
bea50ab32f
8 files changed
+52
-20
No files matched your search
@@ -639,6 +639,7 @@ class _PlayerPageState extends State<PlayerPage>
|
|||||||
);
|
);
|
||||||
return Stack(
|
return Stack(
|
||||||
fit: StackFit.expand,
|
fit: StackFit.expand,
|
||||||
|
clipBehavior: Clip.none,
|
||||||
children: [
|
children: [
|
||||||
PlayerRenderStack(
|
PlayerRenderStack(
|
||||||
pageController: _pageController,
|
pageController: _pageController,
|
||||||
@@ -662,6 +663,7 @@ class _PlayerPageState extends State<PlayerPage>
|
|||||||
);
|
);
|
||||||
final body = Stack(
|
final body = Stack(
|
||||||
fit: StackFit.expand,
|
fit: StackFit.expand,
|
||||||
|
clipBehavior: Clip.none,
|
||||||
children: [
|
children: [
|
||||||
content,
|
content,
|
||||||
if (widget.homeMode &&
|
if (widget.homeMode &&
|
||||||
@@ -971,6 +973,7 @@ class _PlayerPageState extends State<PlayerPage>
|
|||||||
|
|
||||||
return Stack(
|
return Stack(
|
||||||
fit: StackFit.expand,
|
fit: StackFit.expand,
|
||||||
|
clipBehavior: Clip.none,
|
||||||
children: [
|
children: [
|
||||||
if (selected &&
|
if (selected &&
|
||||||
!entryLoading &&
|
!entryLoading &&
|
||||||
|
|||||||
@@ -126,6 +126,7 @@ class _HomeFeedOverlayState extends State<HomeFeedOverlay> {
|
|||||||
return SafeArea(
|
return SafeArea(
|
||||||
bottom: false,
|
bottom: false,
|
||||||
child: Stack(
|
child: Stack(
|
||||||
|
clipBehavior: Clip.none,
|
||||||
children: [
|
children: [
|
||||||
Positioned.fill(
|
Positioned.fill(
|
||||||
child: PlayerTapGestureRegion(
|
child: PlayerTapGestureRegion(
|
||||||
|
|||||||
@@ -4,31 +4,32 @@ import 'package:flutter/material.dart';
|
|||||||
|
|
||||||
import '../../../core/theme/app_colors.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 _heartPopPortion = 0.18;
|
||||||
const double _heartStartScale = 0.7;
|
const double _heartStartScale = 0.7;
|
||||||
const double _heartHoldPortion = 0.45;
|
const double _heartHoldPortion = 0.65;
|
||||||
|
|
||||||
const List<_HeartParticle> _hearts = [
|
const List<_HeartParticle> _hearts = [
|
||||||
_HeartParticle(
|
_HeartParticle(
|
||||||
delay: 0,
|
delay: 0,
|
||||||
travel: 108,
|
travel: 175,
|
||||||
drift: 0,
|
drift: 0,
|
||||||
size: 48,
|
size: 44,
|
||||||
color: AppColors.doubleTapHeartRed,
|
color: AppColors.doubleTapHeartRed,
|
||||||
),
|
),
|
||||||
_HeartParticle(
|
_HeartParticle(
|
||||||
delay: 50,
|
delay: 110,
|
||||||
travel: 96,
|
travel: 150,
|
||||||
drift: -28,
|
drift: -32,
|
||||||
size: 36,
|
size: 34,
|
||||||
color: AppColors.doubleTapHeartPink,
|
color: AppColors.doubleTapHeartPink,
|
||||||
),
|
),
|
||||||
_HeartParticle(
|
_HeartParticle(
|
||||||
delay: 90,
|
delay: _lastHeartDelayMs,
|
||||||
travel: 118,
|
travel: 165,
|
||||||
drift: 26,
|
drift: 30,
|
||||||
size: 40,
|
size: 38,
|
||||||
color: AppColors.doubleTapHeartRed,
|
color: AppColors.doubleTapHeartRed,
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
@@ -38,6 +39,10 @@ class PlayerDoubleTapHeartBurst extends StatefulWidget {
|
|||||||
const PlayerDoubleTapHeartBurst({super.key, required this.onCompleted});
|
const PlayerDoubleTapHeartBurst({super.key, required this.onCompleted});
|
||||||
|
|
||||||
static const int particleCount = 3;
|
static const int particleCount = 3;
|
||||||
|
static const int singleHeartDurationMs = _heartDurationMs;
|
||||||
|
static const Duration animationDuration = Duration(
|
||||||
|
milliseconds: _lastHeartDelayMs + _heartDurationMs,
|
||||||
|
);
|
||||||
|
|
||||||
final VoidCallback onCompleted;
|
final VoidCallback onCompleted;
|
||||||
|
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ class PlayerPlaybackOverlay extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return SafeArea(
|
return SafeArea(
|
||||||
child: Stack(
|
child: Stack(
|
||||||
|
clipBehavior: Clip.none,
|
||||||
children: [
|
children: [
|
||||||
Positioned.fill(
|
Positioned.fill(
|
||||||
child: PlayerTapGestureRegion(
|
child: PlayerTapGestureRegion(
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ class _PlayerTapGestureRegionState extends State<PlayerTapGestureRegion> {
|
|||||||
onPointerDown: _handlePointerDown,
|
onPointerDown: _handlePointerDown,
|
||||||
child: Stack(
|
child: Stack(
|
||||||
fit: StackFit.expand,
|
fit: StackFit.expand,
|
||||||
|
clipBehavior: Clip.none,
|
||||||
children: [
|
children: [
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
key: widget.gestureKey,
|
key: widget.gestureKey,
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ void main() {
|
|||||||
await tester.tapAt(center);
|
await tester.tapAt(center);
|
||||||
await tester.pump();
|
await tester.pump();
|
||||||
expect(repository.likeTargets, hasLength(1));
|
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));
|
clock.advance(const Duration(milliseconds: 500));
|
||||||
await tester.pump(const Duration(milliseconds: 500));
|
await tester.pump(const Duration(milliseconds: 500));
|
||||||
|
|||||||
@@ -13,12 +13,33 @@ void main() {
|
|||||||
home: Scaffold(body: PlayerDoubleTapHeartBurst(onCompleted: _noop)),
|
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(find.byIcon(Icons.favorite_rounded), findsNWidgets(3));
|
||||||
expect(_size(tester, 0), 48);
|
expect(_size(tester, 0), 44);
|
||||||
expect(_size(tester, 1), 36);
|
expect(_size(tester, 1), 34);
|
||||||
expect(_size(tester, 2), 40);
|
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);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -679,7 +679,7 @@ void main() {
|
|||||||
await tester.tapAt(position);
|
await tester.tapAt(position);
|
||||||
}
|
}
|
||||||
await tester.pump();
|
await tester.pump();
|
||||||
await tester.pump(const Duration(milliseconds: 100));
|
await tester.pump(const Duration(milliseconds: 300));
|
||||||
|
|
||||||
expect(logic.session.userWantsPlay, isTrue);
|
expect(logic.session.userWantsPlay, isTrue);
|
||||||
expect(find.byKey(const Key('player-play-toggle')), findsNothing);
|
expect(find.byKey(const Key('player-play-toggle')), findsNothing);
|
||||||
@@ -699,7 +699,7 @@ void main() {
|
|||||||
AppColors.doubleTapHeartRed,
|
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(find.byKey(const Key('double-tap-heart-0')), findsNothing);
|
||||||
expect(logic.session.userWantsPlay, isTrue);
|
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.tapAt(const Offset(80, 300));
|
await tester.tapAt(const Offset(80, 300));
|
||||||
await tester.pump();
|
await tester.pump();
|
||||||
await tester.pump(const Duration(milliseconds: 100));
|
await tester.pump(const Duration(milliseconds: 300));
|
||||||
|
|
||||||
expect(logic.session.userWantsPlay, isTrue);
|
expect(logic.session.userWantsPlay, isTrue);
|
||||||
expect(interactions.likeTargets, hasLength(1));
|
expect(interactions.likeTargets, hasLength(1));
|
||||||
|
|||||||
Reference in new issue
Block a user