From 720fd269359ead392bc284e6fec37fcf64b4f577 Mon Sep 17 00:00:00 2001 From: Zhou Weidong <502333560@qq.com> Date: Tue, 20 Oct 2026 15:15:27 +0800 Subject: [PATCH] =?UTF-8?q?fix(flutter):=20=E5=89=A7=E5=9C=BA=E4=B8=8E?= =?UTF-8?q?=E6=A6=9C=E5=8D=95=E5=8D=A1=E7=89=87=E7=9B=B4=E6=8E=A5=E8=BF=9B?= =?UTF-8?q?=E6=92=AD=E6=94=BE=E9=A1=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/discover/discover_view.dart | 8 ++-- lib/pages/home/home_logic.dart | 30 +------------- lib/pages/new_releases/new_releases_page.dart | 11 +++-- lib/pages/player/open_player.dart | 41 +++++++++++++++++++ lib/pages/ranking/ranking_page.dart | 12 +++--- test/discover/theater_pages_test.dart | 17 +++++++- 6 files changed, 72 insertions(+), 47 deletions(-) create mode 100644 lib/pages/player/open_player.dart diff --git a/lib/pages/discover/discover_view.dart b/lib/pages/discover/discover_view.dart index a74cb56..e83b882 100644 --- a/lib/pages/discover/discover_view.dart +++ b/lib/pages/discover/discover_view.dart @@ -1,5 +1,7 @@ // Author: fruit.com.cn +import 'dart:async'; + import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:provider/provider.dart'; @@ -14,8 +16,8 @@ import '../../core/theme/app_theme.dart'; import '../../core/widgets/app_bottom_nav.dart'; import '../../core/widgets/empty_state.dart'; import '../../l10n/app_localizations.dart'; -import '../drama_detail/drama_detail_view.dart'; import '../new_releases/new_releases_page.dart'; +import '../player/open_player.dart'; import '../ranking/ranking_page.dart'; import '../reserve/reserve_page.dart'; import 'discover_binding.dart'; @@ -489,9 +491,7 @@ class _DiscoverPageState extends State { callback(drama); return; } - Navigator.of(context).push( - MaterialPageRoute(builder: (_) => DramaDetailPage(drama: drama)), - ); + unawaited(playDramaFromCatalog(context, drama)); } Widget _bottomNav(AppLocalizations l10n) => AppBottomNav( diff --git a/lib/pages/home/home_logic.dart b/lib/pages/home/home_logic.dart index f8b5110..ae4310f 100644 --- a/lib/pages/home/home_logic.dart +++ b/lib/pages/home/home_logic.dart @@ -1,17 +1,13 @@ // Author: fruit.com.cn import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; 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 '../discover/discover_types.dart'; import '../drama_detail/drama_detail_view.dart'; import '../favorites/favorites_page.dart'; import '../mine/mine_types.dart'; -import '../player/player_view.dart'; +import '../player/open_player.dart'; import '../watch_records/watch_records_page.dart'; class HomeLogic extends ChangeNotifier { @@ -73,29 +69,7 @@ class HomeLogic extends ChangeNotifier { BuildContext context, Drama drama, { String? episodeId, - }) async { - // 列表卡片只有一集预览,进入播放前补齐完整剧集,否则选集列表是空的。 - var playable = drama; - try { - playable = await context.read().requireDetail(drama); - } catch (_) { - // 取详情失败就用卡片自带的那一集起播。 - } - if (!context.mounted) return; - final index = episodeId == null - ? 0 - : playable.episodes.indexWhere((episode) => episode.id == episodeId); - await Navigator.of(context).push( - MaterialPageRoute( - builder: (_) => PlayerPage( - drama: playable, - initialIndex: index < 0 ? 0 : index, - wallet: context.read(), - downloads: context.read(), - ), - ), - ); - } + }) => playDramaFromCatalog(context, drama, episodeId: episodeId); void openProfile() => select(3); diff --git a/lib/pages/new_releases/new_releases_page.dart b/lib/pages/new_releases/new_releases_page.dart index d10e4a8..ec9aee8 100644 --- a/lib/pages/new_releases/new_releases_page.dart +++ b/lib/pages/new_releases/new_releases_page.dart @@ -1,5 +1,7 @@ // Author: fruit.com.cn +import 'dart:async'; + import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; @@ -8,7 +10,7 @@ import '../../core/widgets/empty_state.dart'; import '../../core/widgets/plain_page_scaffold.dart'; import '../../l10n/app_localizations.dart'; import '../discover/widgets/drama_grid.dart'; -import '../drama_detail/drama_detail_view.dart'; +import '../player/open_player.dart'; /// 剧场新剧页:按 id 倒序展示最新上架短剧。 class NewReleasesPage extends StatelessWidget { @@ -31,11 +33,8 @@ class NewReleasesPage extends StatelessWidget { child: DramaGrid( l10n: l10n, dramas: dramas, - onOpen: (drama) => Navigator.of(context).push( - MaterialPageRoute( - builder: (_) => DramaDetailPage(drama: drama), - ), - ), + onOpen: (drama) => + unawaited(playDramaFromCatalog(context, drama)), ), ), ); diff --git a/lib/pages/player/open_player.dart b/lib/pages/player/open_player.dart new file mode 100644 index 0000000..af7ea66 --- /dev/null +++ b/lib/pages/player/open_player.dart @@ -0,0 +1,41 @@ +// Author: fruit.com.cn + +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +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 'player_view.dart'; + +/// 目录卡片统一入口:补齐详情后直接进入全屏播放页。 +Future playDramaFromCatalog( + BuildContext context, + Drama drama, { + String? episodeId, +}) async { + final catalog = context.read(); + final wallet = context.read(); + final downloads = context.read(); + var playable = drama; + try { + playable = await catalog.requireDetail(drama); + } catch (_) { + // 取详情失败就用卡片自带的可播预览集起播。 + } + if (!context.mounted) return; + final index = episodeId == null + ? 0 + : playable.episodes.indexWhere((episode) => episode.id == episodeId); + await Navigator.of(context).push( + MaterialPageRoute( + builder: (_) => PlayerPage( + drama: playable, + initialIndex: index < 0 ? 0 : index, + wallet: wallet, + downloads: downloads, + ), + ), + ); +} diff --git a/lib/pages/ranking/ranking_page.dart b/lib/pages/ranking/ranking_page.dart index 5e8be44..0e34da9 100644 --- a/lib/pages/ranking/ranking_page.dart +++ b/lib/pages/ranking/ranking_page.dart @@ -1,5 +1,7 @@ // Author: fruit.com.cn +import 'dart:async'; + import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; @@ -12,7 +14,7 @@ import '../../core/widgets/empty_state.dart'; import '../../core/widgets/plain_page_scaffold.dart'; import '../../core/widgets/remote_image.dart'; import '../../l10n/app_localizations.dart'; -import '../drama_detail/drama_detail_view.dart'; +import '../player/open_player.dart'; const int _topCount = 50; const double _podiumGap = 8; @@ -134,9 +136,7 @@ class _PodiumCard extends StatelessWidget { @override Widget build(BuildContext context) { return GestureDetector( - onTap: () => Navigator.of(context).push( - MaterialPageRoute(builder: (_) => DramaDetailPage(drama: drama)), - ), + onTap: () => unawaited(playDramaFromCatalog(context, drama)), child: Column( mainAxisSize: MainAxisSize.min, children: [ @@ -246,9 +246,7 @@ class _RankingRow extends StatelessWidget { clipBehavior: Clip.antiAlias, child: InkWell( key: Key('ranking-row-$index'), - onTap: () => Navigator.of(context).push( - MaterialPageRoute(builder: (_) => DramaDetailPage(drama: drama)), - ), + onTap: () => unawaited(playDramaFromCatalog(context, drama)), child: Padding( padding: const EdgeInsets.all(10), child: Row( diff --git a/test/discover/theater_pages_test.dart b/test/discover/theater_pages_test.dart index e0fc3dc..ddb4580 100644 --- a/test/discover/theater_pages_test.dart +++ b/test/discover/theater_pages_test.dart @@ -8,7 +8,6 @@ import 'package:fruitshorts/core/data/repositories/favorite_repository.dart'; import 'package:fruitshorts/core/data/repositories/playback_repository.dart'; import 'package:fruitshorts/core/data/repositories/watch_history_repository.dart'; import 'package:fruitshorts/pages/discover/widgets/drama_grid.dart'; -import 'package:fruitshorts/pages/drama_detail/drama_detail_view.dart'; import 'package:shared_preferences_platform_interface/in_memory_shared_preferences_async.dart'; import 'package:shared_preferences_platform_interface/shared_preferences_async_platform_interface.dart'; @@ -38,7 +37,7 @@ void main() { await tester.tap(find.byKey(const Key('ranking-top-1'))); await tester.pumpAndSettle(); - expect(find.byType(DramaDetailPage), findsOneWidget); + expect(find.byKey(const Key('player-scaffold')), findsOneWidget); }); testWidgets('should_open_new_releases_sorted_by_id', (tester) async { @@ -115,6 +114,20 @@ void main() { expect(find.byKey(const Key('ranking-top-3')), findsNothing); }); + testWidgets('should_open_player_from_new_releases_card', (tester) async { + await _pumpTheater(tester); + await tester.tap(find.byKey(const Key('theater-toolbar-new'))); + await tester.pumpAndSettle(); + + final card = find.byKey(const Key('home-drama-card-the-signal-demo')); + await tester.ensureVisible(card); + await tester.pumpAndSettle(); + await tester.tap(card); + await tester.pumpAndSettle(); + + expect(find.byKey(const Key('player-scaffold')), findsOneWidget); + }); + testWidgets('should_go_back_to_theater_from_ranking_page', (tester) async { await _pumpTheater(tester); await tester.tap(find.byKey(const Key('theater-toolbar-ranking')));