feat(player): 重做播放页信息层级与互动栏点击动效
This commit is contained in:
1 parent
aed9ee2b01
commit
fd2ba0bf43
15 files changed
+2074
-551
No files matched your search
@@ -0,0 +1,171 @@
|
||||
// Author: fruit.com.cn
|
||||
// 职责:验证真实主题及素材在同步状态刷新和保留状态重组后的点击绘制。
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:fruitshorts/core/theme/app_colors.dart';
|
||||
import 'package:fruitshorts/core/theme/app_theme.dart';
|
||||
import 'package:fruitshorts/pages/player/widgets/interaction_rail.dart';
|
||||
import 'package:fruitshorts/pages/player/widgets/interaction_rail_burst.dart';
|
||||
|
||||
const _itemKey = Key('asset-like');
|
||||
const _burstKey = Key('rail-tap-burst');
|
||||
const _buttonSize = 48.0;
|
||||
const _iconSize = 36.0;
|
||||
const _motionFrame = Duration(milliseconds: 130);
|
||||
const _asset = 'assets/icon/rail/rail_like.png';
|
||||
const _epsilon = 0.01;
|
||||
const _rayLimit = 26.4;
|
||||
const _rayLengthLimit = 3.5;
|
||||
const _burstPhases = [0.2, 0.5, 0.8];
|
||||
|
||||
Finder get _button => find.descendant(
|
||||
of: find.byKey(_itemKey),
|
||||
matching: find.byType(IconButton),
|
||||
);
|
||||
|
||||
Finder get _image =>
|
||||
find.descendant(of: find.byKey(_itemKey), matching: find.byType(Image));
|
||||
|
||||
double _paintedWidth(WidgetTester tester) {
|
||||
final icon = tester.renderObject<RenderBox>(_image);
|
||||
final rail = tester.renderObject<RenderBox>(find.byKey(_itemKey));
|
||||
return MatrixUtils.transformRect(
|
||||
icon.getTransformTo(rail),
|
||||
Offset.zero & icon.size,
|
||||
).width;
|
||||
}
|
||||
|
||||
Future<void> _pumpAssetRail(
|
||||
WidgetTester tester,
|
||||
ValueNotifier<bool> selected,
|
||||
) => tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: AppTheme.dark(),
|
||||
home: Scaffold(
|
||||
body: Center(
|
||||
child: ValueListenableBuilder<bool>(
|
||||
valueListenable: selected,
|
||||
builder: (context, value, _) => InteractionRail(
|
||||
buttonSize: _buttonSize,
|
||||
iconSize: _iconSize,
|
||||
items: [
|
||||
InteractionRailItem(
|
||||
key: _itemKey,
|
||||
label: 'Like',
|
||||
asset: _asset,
|
||||
selected: value,
|
||||
selectedColor: AppColors.brandRed,
|
||||
animateTap: true,
|
||||
onTap: () => selected.value = !selected.value,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
void main() {
|
||||
testWidgets('should_not_show_ink_or_shadow_when_button_is_pressed', (
|
||||
tester,
|
||||
) async {
|
||||
final selected = ValueNotifier(false);
|
||||
addTearDown(selected.dispose);
|
||||
await _pumpAssetRail(tester, selected);
|
||||
final button = tester.widget<IconButton>(_button);
|
||||
const pressed = {WidgetState.pressed};
|
||||
expect(button.style?.overlayColor?.resolve(pressed), AppColors.transparent);
|
||||
expect(button.style?.shadowColor?.resolve(pressed), AppColors.transparent);
|
||||
expect(button.style?.splashFactory, NoSplash.splashFactory);
|
||||
expect(button.style?.elevation?.resolve(pressed), 0);
|
||||
});
|
||||
|
||||
for (final contracting in [false, true]) {
|
||||
testWidgets('should_keep_rays_compact_when_contracting_$contracting', (
|
||||
tester,
|
||||
) async {
|
||||
for (final progress in _burstPhases) {
|
||||
await tester.pumpWidget(
|
||||
Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: Center(
|
||||
child: SizedBox.square(
|
||||
dimension: _buttonSize,
|
||||
child: RailTapBurst(
|
||||
progress: progress,
|
||||
color: AppColors.brandRed,
|
||||
contracting: contracting,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
final paint = tester.renderObject(find.byType(CustomPaint));
|
||||
expect(paint, paintsExactlyCountTimes(#drawCircle, 0));
|
||||
expect(paint, paintsExactlyCountTimes(#drawLine, 8));
|
||||
expect(paint, paints..everything(_isCompactRay));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
testWidgets('should_paint_feedback_at_button_size_when_asset_is_tapped', (
|
||||
tester,
|
||||
) async {
|
||||
final selected = ValueNotifier(false);
|
||||
addTearDown(selected.dispose);
|
||||
await _pumpAssetRail(tester, selected);
|
||||
final touchRect = tester.getRect(_button);
|
||||
await tester.tap(_button);
|
||||
await tester.pump();
|
||||
await tester.pump(_motionFrame);
|
||||
expect(selected.value, isTrue);
|
||||
expect(_paintedWidth(tester), greaterThan(_iconSize));
|
||||
expect(
|
||||
tester.getSize(find.byKey(_burstKey)),
|
||||
const Size.square(_buttonSize),
|
||||
);
|
||||
expect(tester.getRect(_button), touchRect);
|
||||
await tester.pumpAndSettle();
|
||||
expect(_paintedWidth(tester), closeTo(_iconSize, _epsilon));
|
||||
expect(tester.takeException(), isNull);
|
||||
});
|
||||
|
||||
testWidgets(
|
||||
'should_paint_opposite_directions_after_preserved_state_reassembly',
|
||||
(tester) async {
|
||||
final selected = ValueNotifier(false);
|
||||
addTearDown(selected.dispose);
|
||||
await _pumpAssetRail(tester, selected);
|
||||
unawaited(tester.binding.reassembleApplication());
|
||||
await tester.pump();
|
||||
for (final cancelling in [false, true]) {
|
||||
await tester.tap(_button);
|
||||
await tester.pump();
|
||||
await tester.pump(_motionFrame);
|
||||
expect(
|
||||
_paintedWidth(tester),
|
||||
cancelling ? lessThan(_iconSize) : greaterThan(_iconSize),
|
||||
);
|
||||
final feedback = tester.widget<RailTapBurst>(find.byKey(_burstKey));
|
||||
expect(feedback.contracting, cancelling);
|
||||
expect(selected.value, !cancelling);
|
||||
await tester.pumpAndSettle();
|
||||
expect(_paintedWidth(tester), closeTo(_iconSize, _epsilon));
|
||||
}
|
||||
expect(tester.takeException(), isNull);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
bool _isCompactRay(Symbol method, List<dynamic> arguments) {
|
||||
if (method != #drawLine) return true;
|
||||
const center = Offset(_buttonSize / 2, _buttonSize / 2);
|
||||
final start = arguments[0] as Offset;
|
||||
final end = arguments[1] as Offset;
|
||||
return (start - center).distance <= _rayLimit &&
|
||||
(end - center).distance <= _rayLimit &&
|
||||
(end - start).distance <= _rayLengthLimit;
|
||||
}
|
||||
Reference in new issue
Block a user