feat(player): 右侧互动栏图标按参考图替换并放大

This commit is contained in:
Zhou Weidong committed 2026-10-21 10:52:14 +08:00
1 parent e6a31a60df
commit 4b1aea29c7
5 files changed
+128 -24

No files matched your search

@@ -173,7 +173,7 @@ class _HomeFeedOverlayState extends State<HomeFeedOverlay> {
items: [ items: [
InteractionRailItem( InteractionRailItem(
key: const Key('rail-save'), key: const Key('rail-save'),
icon: Icons.star_border_rounded, icon: Icons.star_rounded,
activeIcon: Icons.star_rounded, activeIcon: Icons.star_rounded,
label: widget.l10n.favorite, label: widget.l10n.favorite,
count: widget.favoriteCount, count: widget.favoriteCount,
@@ -192,7 +192,7 @@ class _HomeFeedOverlayState extends State<HomeFeedOverlay> {
), ),
InteractionRailItem( InteractionRailItem(
key: const Key('rail-like'), key: const Key('rail-like'),
icon: Icons.favorite_border_rounded, icon: Icons.favorite_rounded,
activeIcon: Icons.favorite_rounded, activeIcon: Icons.favorite_rounded,
label: widget.l10n.like, label: widget.l10n.like,
count: widget.likeCount, count: widget.likeCount,
@@ -202,9 +202,10 @@ class _HomeFeedOverlayState extends State<HomeFeedOverlay> {
), ),
InteractionRailItem( InteractionRailItem(
key: const Key('rail-share'), key: const Key('rail-share'),
icon: Icons.ios_share_rounded, icon: Icons.reply_rounded,
activeIcon: Icons.ios_share_rounded, activeIcon: Icons.reply_rounded,
label: widget.l10n.share, label: widget.l10n.share,
mirrorIcon: true,
onTap: widget.onShare, onTap: widget.onShare,
), ),
], ],
+14 -13
View File
@@ -5,10 +5,9 @@ import 'package:flutter/material.dart';
import '../../../core/formatting/count_format.dart'; import '../../../core/formatting/count_format.dart';
import '../../../core/theme/app_colors.dart'; import '../../../core/theme/app_colors.dart';
const double _buttonSize = 34; const double _buttonSize = 44;
const double _iconSize = 24; const double _iconSize = 30;
const double _itemGap = 18; const double _itemGap = 22;
const Color _buttonBackground = Color(0x80000000);
/// 互动栏单项:图标、计数与点击。 /// 互动栏单项:图标、计数与点击。
class InteractionRailItem { class InteractionRailItem {
@@ -21,6 +20,7 @@ class InteractionRailItem {
this.count, this.count,
this.countKey, this.countKey,
this.selected = false, this.selected = false,
this.mirrorIcon = false,
}); });
final Key key; final Key key;
@@ -31,6 +31,7 @@ class InteractionRailItem {
final int? count; final int? count;
final Key? countKey; final Key? countKey;
final bool selected; final bool selected;
final bool mirrorIcon;
} }
/// 播放页与首页 feed 共用的右侧互动栏:收藏/评论/喜欢/分享。 /// 播放页与首页 feed 共用的右侧互动栏:收藏/评论/喜欢/分享。
@@ -60,6 +61,10 @@ class _RailButton extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final icon = Icon(
item.selected ? item.activeIcon : item.icon,
size: _iconSize,
);
return Column( return Column(
key: item.key, key: item.key,
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
@@ -69,14 +74,10 @@ class _RailButton extends StatelessWidget {
child: IconButton( child: IconButton(
onPressed: item.onTap, onPressed: item.onTap,
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
style: IconButton.styleFrom( color: item.selected ? AppColors.blue : Colors.white,
backgroundColor: _buttonBackground, icon: item.mirrorIcon
foregroundColor: item.selected ? AppColors.blue : Colors.white, ? Transform.flip(flipX: true, child: icon)
), : icon,
icon: Icon(
item.selected ? item.activeIcon : item.icon,
size: _iconSize,
),
), ),
), ),
const SizedBox(height: 2), const SizedBox(height: 2),
@@ -88,7 +89,7 @@ class _RailButton extends StatelessWidget {
style: const TextStyle( style: const TextStyle(
color: Colors.white, color: Colors.white,
height: 1, height: 1,
fontSize: 11, fontSize: 12,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
shadows: [Shadow(blurRadius: 6, color: Colors.black)], shadows: [Shadow(blurRadius: 6, color: Colors.black)],
), ),
+6 -5
View File
@@ -141,13 +141,13 @@ class PlayerPlaybackOverlay extends StatelessWidget {
final compact = MediaQuery.sizeOf(context).height < 700; final compact = MediaQuery.sizeOf(context).height < 700;
return Positioned( return Positioned(
right: AppDimens.spaceMd, right: AppDimens.spaceMd,
top: MediaQuery.sizeOf(context).height * (compact ? 0.42 : 0.55), top: MediaQuery.sizeOf(context).height * (compact ? 0.30 : 0.43),
child: InteractionRail( child: InteractionRail(
key: const Key('player-interaction-rail'), key: const Key('player-interaction-rail'),
items: [ items: [
InteractionRailItem( InteractionRailItem(
key: const Key('player-rail-save'), key: const Key('player-rail-save'),
icon: Icons.star_border_rounded, icon: Icons.star_rounded,
activeIcon: Icons.star_rounded, activeIcon: Icons.star_rounded,
label: data.l10n.favorite, label: data.l10n.favorite,
count: data.favoriteCount, count: data.favoriteCount,
@@ -166,7 +166,7 @@ class PlayerPlaybackOverlay extends StatelessWidget {
), ),
InteractionRailItem( InteractionRailItem(
key: const Key('player-rail-like'), key: const Key('player-rail-like'),
icon: Icons.favorite_border_rounded, icon: Icons.favorite_rounded,
activeIcon: Icons.favorite_rounded, activeIcon: Icons.favorite_rounded,
label: data.l10n.like, label: data.l10n.like,
count: data.likeCount, count: data.likeCount,
@@ -176,9 +176,10 @@ class PlayerPlaybackOverlay extends StatelessWidget {
), ),
InteractionRailItem( InteractionRailItem(
key: const Key('player-rail-share'), key: const Key('player-rail-share'),
icon: Icons.ios_share_rounded, icon: Icons.reply_rounded,
activeIcon: Icons.ios_share_rounded, activeIcon: Icons.reply_rounded,
label: data.l10n.share, label: data.l10n.share,
mirrorIcon: true,
onTap: actions.onShare, onTap: actions.onShare,
), ),
], ],
+33
View File
@@ -150,6 +150,39 @@ void main() {
tester.widget<Text>(find.byKey(const Key('rail-comments-count'))).data, tester.widget<Text>(find.byKey(const Key('rail-comments-count'))).data,
'12', '12',
); );
expect(
find.descendant(
of: find.byKey(const Key('rail-save')),
matching: find.byIcon(Icons.star_rounded),
),
findsOneWidget,
);
expect(
find.descendant(
of: find.byKey(const Key('rail-like')),
matching: find.byIcon(Icons.favorite_rounded),
),
findsOneWidget,
);
expect(
find.descendant(
of: find.byKey(const Key('rail-share')),
matching: find.byIcon(Icons.reply_rounded),
),
findsOneWidget,
);
expect(
tester
.widget<Transform>(
find.descendant(
of: find.byKey(const Key('rail-share')),
matching: find.byType(Transform),
),
)
.transform
.storage[0],
-1,
);
expect(find.byKey(const Key('progress-loading')), findsOneWidget); expect(find.byKey(const Key('progress-loading')), findsOneWidget);
expect(find.byKey(const Key('home-feed-progress-thumb')), findsNothing); expect(find.byKey(const Key('home-feed-progress-thumb')), findsNothing);
}); });
+70 -2
View File
@@ -466,7 +466,7 @@ void main() {
expect(bottom.height, lessThanOrEqualTo(200)); expect(bottom.height, lessThanOrEqualTo(200));
expect(bottom.top, greaterThanOrEqualTo(screenHeight * 0.78)); expect(bottom.top, greaterThanOrEqualTo(screenHeight * 0.78));
expect(rail.top, greaterThanOrEqualTo(screenHeight * 0.55 - 2)); expect(rail.top, greaterThanOrEqualTo(screenHeight * 0.40));
expect(rail.bottom, lessThanOrEqualTo(bottom.top)); expect(rail.bottom, lessThanOrEqualTo(bottom.top));
expect(find.byKey(const Key('player-author-note')), findsNothing); expect(find.byKey(const Key('player-author-note')), findsNothing);
expect( expect(
@@ -478,7 +478,7 @@ void main() {
), ),
) )
.width, .width,
24, 30,
); );
await tester.tap(find.byKey(const Key('player-synopsis-toggle'))); await tester.tap(find.byKey(const Key('player-synopsis-toggle')));
@@ -580,6 +580,74 @@ void main() {
expect(railLabel(const Key('player-rail-save')), '3201'); expect(railLabel(const Key('player-rail-save')), '3201');
}); });
testWidgets('should_render_reference_rail_icons_without_background', (
tester,
) async {
await _pumpApp(tester);
await _openSeriesPlayer(tester);
Finder railIcon(Key key, IconData icon) =>
find.descendant(of: find.byKey(key), matching: find.byIcon(icon));
expect(
railIcon(const Key('player-rail-save'), Icons.star_rounded),
findsOneWidget,
);
expect(
railIcon(const Key('player-rail-like'), Icons.favorite_rounded),
findsOneWidget,
);
expect(
railIcon(
const Key('player-rail-comments'),
Icons.chat_bubble_outline_rounded,
),
findsOneWidget,
);
final shareIcon = railIcon(
const Key('player-rail-share'),
Icons.reply_rounded,
);
expect(shareIcon, findsOneWidget);
expect(tester.widget<Icon>(shareIcon).size, 30);
final mirror = tester.widget<Transform>(
find.descendant(
of: find.byKey(const Key('player-rail-share')),
matching: find.byType(Transform),
),
);
expect(mirror.transform.storage[0], -1);
final saveButton = tester.widget<IconButton>(
find.descendant(
of: find.byKey(const Key('player-rail-save')),
matching: find.byType(IconButton),
),
);
expect(saveButton.style?.backgroundColor, isNull);
expect(
tester.getSize(
find.descendant(
of: find.byKey(const Key('player-rail-save')),
matching: find.byType(IconButton),
),
),
const Size(44, 44),
);
expect(
tester
.widget<Text>(
find.descendant(
of: find.byKey(const Key('player-rail-like')),
matching: find.byType(Text),
),
)
.style
?.fontSize,
12,
);
});
testWidgets('should_toggle_synopsis_with_inline_text_button', (tester) async { testWidgets('should_toggle_synopsis_with_inline_text_button', (tester) async {
await _pumpApp(tester); await _pumpApp(tester);
await _openSeriesPlayer(tester); await _openSeriesPlayer(tester);