130 lines
3.8 KiB
Dart
130 lines
3.8 KiB
Dart
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),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
);
|
||
}
|
||
}
|