Files
video/app/lib/screens/feed/widgets/feed_video_page.dart
T
2026-10-15 20:36:59 +08:00

130 lines
3.8 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import '../../../core/player/feed_player_pool.dart';
import '../../../models/video_item.dart';
import '../../../providers/auth_provider.dart';
import 'feed_overlays.dart';
import 'interaction_bar.dart';
import 'video_info_section.dart';
import 'video_player_view.dart';
/// Feed 单页:播放器 + 手势层 + 互动栏 + 信息区 + 双击爱心动画
/// 手势(《01-开发文档》5.3):单击暂停/继续,双击点赞
class FeedVideoPage extends ConsumerStatefulWidget {
const FeedVideoPage({
super.key,
required this.item,
required this.slotIndex,
required this.pool,
required this.isCurrent,
required this.onLike,
this.onFavorite,
this.onComment,
this.onShare,
});
final VideoItem item;
final int slotIndex;
final FeedPlayerPool pool;
final bool isCurrent;
/// 点赞回调(由上层接 feedProvider.toggleLike,内部判登录态)
final void Function(int videoId) onLike;
/// 收藏回调(由上层接 feedProvider.toggleFavorite)
final void Function(int videoId)? onFavorite;
/// 评论入口(打开评论弹层)
final void Function(VideoItem item)? onComment;
/// 分享入口(系统分享面板)
final void Function(VideoItem item)? onShare;
@override
ConsumerState<FeedVideoPage> createState() => _FeedVideoPageState();
}
class _FeedVideoPageState extends ConsumerState<FeedVideoPage> {
int _likeBurstTrigger = 0;
void _onDoubleTap() {
// 游客双击:与点赞按钮一致守卫登录(《01-开发文档》2.1.1 游客不可点赞)
if (!ref.read(authProvider).isLoggedIn) {
context.go('/login');
return;
}
setState(() => _likeBurstTrigger++);
// 双击:未点赞等同点赞;已点赞只播动画不改状态
if (!widget.item.isLiked) {
widget.onLike(widget.item.videoId);
}
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: widget.pool.toggleCurrent,
onDoubleTap: _onDoubleTap,
child: Container(
color: Colors.black,
child: Stack(
fit: StackFit.expand,
children: [
// 底部渐变(提升文字可读性)
const Positioned(
left: 0,
right: 0,
bottom: 0,
height: 160,
child: IgnorePointer(
child: DecoratedBox(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [Colors.transparent, Colors.black54],
),
),
),
),
),
// 播放器
VideoPlayerView(
controller: widget.pool.controllerAt(widget.slotIndex),
coverUrl: widget.item.coverUrl,
playing: widget.isCurrent && widget.pool.isCurrentPlaying,
),
// 双击爱心动画
IgnorePointer(child: LikeBurst(trigger: _likeBurstTrigger)),
// 右侧互动栏
Positioned(
right: 8,
bottom: 96,
child: InteractionBar(
item: widget.item,
onLike: widget.onLike,
onFavorite: widget.onFavorite,
onComment: widget.onComment,
onShare: widget.onShare,
),
),
// 左下信息区
Positioned(
left: 12,
right: 88,
bottom: 24,
child: VideoInfoSection(item: widget.item),
),
],
),
),
);
}
}