From 8c04099d975fff7a33486634ffc013713de7c9eb Mon Sep 17 00:00:00 2001 From: Zhou Weidong <502333560@qq.com> Date: Wed, 21 Oct 2026 09:23:30 +0800 Subject: [PATCH] =?UTF-8?q?feat(player):=20=E9=A6=96=E9=A1=B5=E8=BF=9B?= =?UTF-8?q?=E8=AF=A6=E6=83=85=E4=B8=8E=E6=92=AD=E6=94=BE=E9=A1=B5=E6=94=B9?= =?UTF-8?q?=E4=B8=BA=E6=B7=A1=E5=85=A5=E8=BD=AC=E5=9C=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/core/navigation/fade_page_route.dart | 17 ++++++++ lib/pages/player/open_player.dart | 3 +- lib/pages/player/player_logic.dart | 5 ++- test/navigation/fade_page_route_test.dart | 50 +++++++++++++++++++++++ 4 files changed, 72 insertions(+), 3 deletions(-) create mode 100644 lib/core/navigation/fade_page_route.dart create mode 100644 test/navigation/fade_page_route_test.dart diff --git a/lib/core/navigation/fade_page_route.dart b/lib/core/navigation/fade_page_route.dart new file mode 100644 index 0000000..8b1c0fd --- /dev/null +++ b/lib/core/navigation/fade_page_route.dart @@ -0,0 +1,17 @@ +// Author: fruit.com.cn + +import 'package:flutter/widgets.dart'; + +/// 无位移的短促淡入转场。 +class FadePageRoute extends PageRouteBuilder { + FadePageRoute({required WidgetBuilder builder, super.settings}) + : super( + transitionDuration: const Duration(milliseconds: 220), + reverseTransitionDuration: const Duration(milliseconds: 180), + pageBuilder: (context, _, _) => builder(context), + transitionsBuilder: (context, animation, _, child) => FadeTransition( + opacity: CurvedAnimation(parent: animation, curve: Curves.easeOut), + child: child, + ), + ); +} diff --git a/lib/pages/player/open_player.dart b/lib/pages/player/open_player.dart index af7ea66..9d2ac32 100644 --- a/lib/pages/player/open_player.dart +++ b/lib/pages/player/open_player.dart @@ -7,6 +7,7 @@ import '../../core/data/models/drama.dart'; import '../../core/data/services/catalog_controller.dart'; import '../../core/data/services/download_controller.dart'; import '../../core/data/services/wallet_controller.dart'; +import '../../core/navigation/fade_page_route.dart'; import 'player_view.dart'; /// 目录卡片统一入口:补齐详情后直接进入全屏播放页。 @@ -29,7 +30,7 @@ Future playDramaFromCatalog( ? 0 : playable.episodes.indexWhere((episode) => episode.id == episodeId); await Navigator.of(context).push( - MaterialPageRoute( + FadePageRoute( builder: (_) => PlayerPage( drama: playable, initialIndex: index < 0 ? 0 : index, diff --git a/lib/pages/player/player_logic.dart b/lib/pages/player/player_logic.dart index 2ab8cca..1f887e5 100644 --- a/lib/pages/player/player_logic.dart +++ b/lib/pages/player/player_logic.dart @@ -21,6 +21,7 @@ import '../../core/data/services/playback_session.dart'; import '../../core/data/services/video_player_port.dart'; import '../../core/data/services/wallet_controller.dart'; import '../../core/formatting/localized_content.dart'; +import '../../core/navigation/fade_page_route.dart'; import '../../l10n/app_localizations.dart'; import '../discover/discover_types.dart'; import '../discover/discover_view.dart'; @@ -625,7 +626,7 @@ class PlayerLogic extends ChangeNotifier { try { if (!context.mounted) return; await Navigator.of(context).push( - MaterialPageRoute( + FadePageRoute( builder: (_) => DramaDetailPage(drama: queue.entryAt(session.currentIndex).drama), ), @@ -646,7 +647,7 @@ class PlayerLogic extends ChangeNotifier { await saveCurrentProgress(); if (!context.mounted) return; await Navigator.of(context).push( - MaterialPageRoute( + FadePageRoute( builder: (_) => PlayerPage( drama: drama, initialIndex: index, diff --git a/test/navigation/fade_page_route_test.dart b/test/navigation/fade_page_route_test.dart new file mode 100644 index 0000000..739e16d --- /dev/null +++ b/test/navigation/fade_page_route_test.dart @@ -0,0 +1,50 @@ +// Author: fruit.com.cn + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:fruitshorts/core/navigation/fade_page_route.dart'; + +void main() { + testWidgets('should_fade_in_without_slide_and_use_short_transitions', ( + tester, + ) async { + final navigatorKey = GlobalKey(); + var routePushed = false; + final route = FadePageRoute( + builder: (_) => + const Scaffold(key: Key('fade-route-page'), body: SizedBox.expand()), + ); + + expect(route.transitionDuration, const Duration(milliseconds: 220)); + expect(route.reverseTransitionDuration, const Duration(milliseconds: 180)); + expect(route.opaque, isTrue); + + await tester.pumpWidget( + MaterialApp( + navigatorKey: navigatorKey, + home: Builder( + builder: (context) => Scaffold( + body: TextButton( + onPressed: () { + navigatorKey.currentState!.push(route); + routePushed = true; + }, + child: const Text('Open'), + ), + ), + ), + ), + ); + + await tester.tap(find.text('Open')); + await tester.pump(); + await tester.pump(const Duration(milliseconds: 100)); + + expect(routePushed, isTrue); + expect(find.byKey(const Key('fade-route-page')), findsOneWidget); + final fade = tester.widget( + find.byType(FadeTransition).last, + ); + expect(fade.opacity.value, inExclusiveRange(0, 1)); + }); +}