This commit is contained in:
lz_db
2026-10-25 11:46:44 +08:00
parent 893dfed0ed
commit 494f667719
63 changed files with 5213 additions and 239 deletions
+45 -5
View File
@@ -3,8 +3,11 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import '../../core/media/cover_cache.dart';
import '../../core/log/action_logger.dart';
import '../../core/theme/app_theme.dart';
import '../../models/video_item.dart';
import '../../providers/feed_provider.dart';
import '../../providers/search_provider.dart';
/// 搜索页(《01-开发文档》2.5.8):
@@ -24,12 +27,22 @@ class _SearchScreenState extends ConsumerState<SearchScreen> {
@override
void initState() {
super.initState();
ActionLogger.I.log('route_enter', page: '/search');
// 打开搜索页挂起首页 Feed:保存当前播放断点 + 停所有槽位。
// 用 suspend 而非 stopAll——stopAll 会清掉断点导致返回时从头播,
// suspend 会把当前槽位置存到 _resumePosition,rebindCurrent 时经 mpv start 续播
WidgetsBinding.instance.addPostFrameCallback((_) {
final strategy = ref.read(activeFeedStrategyProvider);
ref.read(feedProvider(strategy).notifier).pool.suspend();
});
ref.read(searchProvider.notifier).loadHot();
_scrollController.addListener(_onScroll);
}
@override
void dispose() {
ActionLogger.I.log('route_exit', page: '/search');
// 首页恢复播放改由 FeedScreen 通过 RouteObserver.didPopNext 感知,这里不再处理
_inputController.dispose();
_scrollController.dispose();
super.dispose();
@@ -283,7 +296,11 @@ class _SearchScreenState extends ConsumerState<SearchScreen> {
),
);
}
return VideoGridCard(item: state.items[index]);
return VideoGridCard(
item: state.items[index],
allItems: state.items,
initialIndex: index,
);
},
),
),
@@ -293,15 +310,37 @@ class _SearchScreenState extends ConsumerState<SearchScreen> {
}
/// 视频网格卡片:封面 + 标题 + 作者 + 播放量(搜索结果 / 标签视频页共用)
class VideoGridCard extends StatelessWidget {
const VideoGridCard({super.key, required this.item});
/// 点击行为:把当前列表注入到 feedProvider(FeedStrategy.search),跳 /search/feed
/// 进入全屏 Feed 播放,支持上下滑切换上/下一个视频
class VideoGridCard extends ConsumerWidget {
const VideoGridCard({
super.key,
required this.item,
required this.allItems,
required this.initialIndex,
});
final VideoItem item;
/// 当前列表的所有视频(搜索结果/标签结果)
final List<VideoItem> allItems;
/// 当前点击的视频在列表中的下标
final int initialIndex;
@override
Widget build(BuildContext context) {
Widget build(BuildContext context, WidgetRef ref) {
return GestureDetector(
onTap: () => context.push('/search/play', extra: item),
// 宿主页(SearchScreen / TagVideosScreen)已在进入时挂起首页 Feed,
// 这里只负责把列表注入 search 策略池并跳转;首页池恢复由宿主页 dispose 统一处理
onTap: () async {
final searchFeedNotifier =
ref.read(feedProvider(FeedStrategy.search).notifier);
await searchFeedNotifier.injectItems(allItems, initialIndex);
if (!context.mounted) return;
context.push('/search/feed');
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@@ -315,6 +354,7 @@ class VideoGridCard extends StatelessWidget {
child: item.coverUrl.isNotEmpty
? CachedNetworkImage(
imageUrl: item.coverUrl,
cacheManager: CoverCacheManager.I,
fit: BoxFit.cover,
errorWidget: (_, __, ___) => const Icon(
Icons.play_circle_outline,