Files
2026-09-15 15:44:13 +07:00

337 lines
10 KiB
Dart

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:hgdj/assets_tool/images.dart';
import 'package:hgdj/hj_page/live/live_item_widget.dart';
import 'package:hgdj/hj_page/live/live_model.dart';
import 'package:hgdj/hj_utils/screen.dart';
import 'package:hgdj/hj_utils/sliver_delegate.dart';
import 'package:hgdj/tools_base/banner/ads_grid_view_widget.dart';
import 'package:hgdj/tools_base/loading/loading_center_widget.dart';
import 'package:hgdj/tools_base/refresh/pull_refresh.dart';
import 'package:hgdj/tools_base/widget/net_image_widget.dart';
import 'package:video_player/video_player.dart';
import '../video/video_full_page.dart';
import 'live_detail_logic.dart';
//直播详情页
class LiveDetailPage extends StatefulWidget {
final LiveAnchor? anchor;
const LiveDetailPage({super.key, this.anchor});
@override
State<LiveDetailPage> createState() => _LiveDetailPageState();
}
class _LiveDetailPageState extends State<LiveDetailPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: GetBuilder<LiveDetailLogic>(
init: LiveDetailLogic(anchor: widget.anchor),
builder: (logic) => Stack(
children: [
_buildBody(logic),
Positioned(left: 10, top: 10, child: _buildBack()),
],
),
),
),
);
}
//页面框架
Widget _buildBody(LiveDetailLogic logic) {
return pullYsRefresh(
enablePullDown: false,
onInit: (c) => logic.controller = c,
onLoading: (c) => logic.loadMoreData(),
child: CustomScrollView(
slivers: [
SliverPersistentHeader(
pinned: true,
delegate: MySliverDelegate(
forceRefresh: true,
maxHeight: Get.width / (logic.aspectRatio ?? 1),
minHeight: logic.isVerticalVideo
? Get.width / (logic.aspectRatio ?? 1)
: Get.height / 3 - 60,
child: ClipRRect(
//部分机型会超出比例,裁剪掉多余部分
child: Container(color: Colors.black, child: _buildPlayer()),
),
),
),
SliverToBoxAdapter(child: _buildAnchorInfo(logic)),
SliverToBoxAdapter(child: _buildAds()),
10.sliverSizeBoxH,
_buildDivider(),
SliverToBoxAdapter(
child: Container(
padding: const EdgeInsets.fromLTRB(16, 18, 16, 12),
child: const Text(
'热门直播',
style: TextStyle(
fontSize: 16,
color: Colors.white,
fontWeight: FontWeight.w500),
),
),
),
_buildRecommend(),
18.sliverSizeBoxH,
_buildDivider(),
],
),
);
}
//视频播放区
Widget _buildPlayer() {
return GetBuilder<LiveDetailLogic>(
id: 'player',
builder: (logic) => Stack(
alignment: Alignment.center,
children: [
if (logic.loadingUserInfo) ...[
//1.加载用户直播权益信息
AspectRatio(
aspectRatio: logic.aspectRatio ?? 1, child: _buildCover(logic)),
const LoadingCenterWidget(),
] else if (!logic.canWatchLive) ...[
//2.无权限
_buildNoPermission(logic),
] else if (logic.anchor?.isOnline != true) ...[
//3.主播离线
_buildOffline(logic),
] else ...[
//4.主播在线
Hero(
tag: 'player',
child: AspectRatio(
aspectRatio: logic.aspectRatio ?? 1,
child: logic.initedVideoController
? VideoPlayer(logic.playerController!)
: _buildCover(logic),
),
),
if (logic.initedVideoController)
Positioned(
right: 12,
bottom: 6,
child: GestureDetector(
onTap: () => Get.to(() => VideoFullPage(
playCtr: logic.playerController!, showMenu: false)),
child: Image.asset("full_icon.png".videoPath,
width: 26, height: 26),
),
),
Obx(() => Offstage(
offstage: !logic.isLoading.value,
child: const LoadingCenterWidget())),
],
],
),
);
}
//无权限
Widget _buildNoPermission(LiveDetailLogic logic) {
return Container(
color: Colors.black,
child: Stack(
fit: StackFit.expand,
children: [
_buildCover(logic),
Container(
color: Colors.black.withValues(alpha: .7),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
'温馨提示',
style: TextStyle(
fontSize: 14,
color: Colors.white,
fontWeight: FontWeight.w500),
),
12.sizeBoxH,
const Text('开通直播卡全站直播骚货任选~',
style: TextStyle(fontSize: 12, color: Colors.white)),
18.sizeBoxH,
GestureDetector(
onTap: logic.onChargeAction,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(3),
gradient: const LinearGradient(
begin: Alignment.centerLeft,
end: Alignment.centerRight,
colors: [Color(0xffffe8be), Color(0xffe5b764)],
),
),
padding:
const EdgeInsets.symmetric(horizontal: 8, vertical: 6),
child: const Text('立即开通直播卡',
style:
TextStyle(fontSize: 14, color: Color(0xFF7b0000))),
),
),
],
),
),
],
),
);
}
//主播离线
Widget _buildOffline(LiveDetailLogic logic) {
return Container(
color: Colors.black,
child: Stack(
fit: StackFit.expand,
children: [
_buildCover(logic),
Container(
color: Colors.black.withValues(alpha: .7),
alignment: Alignment.center,
child: const Text('当前主播离线,请前往观看其她热门主播喔~',
style: TextStyle(fontSize: 14, color: Colors.white)),
),
],
),
);
}
//封面图
Widget _buildCover(LiveDetailLogic logic) {
return NetworkImageLoader(
imageUrl: logic.anchor?.coverImg ?? '',
encrypt: false,
borderRadius: 0,
width: Get.width,
);
}
//热门直播推荐列表
Widget _buildRecommend() {
return GetBuilder<LiveDetailLogic>(
id: 'recommend',
builder: (logic) {
if (logic.loading) {
return const SliverToBoxAdapter(child: LoadingWidget());
}
if (logic.recommendList.isEmpty) {
return const SliverToBoxAdapter(
child: SizedBox(height: 300, child: CErrorWidget()));
}
return SliverPadding(
padding: const EdgeInsets.symmetric(horizontal: 16),
sliver: SliverGrid(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: 12,
crossAxisSpacing: 7,
childAspectRatio: 168 / 105,
),
delegate: SliverChildBuilderDelegate(
(context, index) {
final anchor = logic.recommendList[index];
return LiveItemWidget(
showType: 5,
anchor: anchor,
action: () => logic.onChangeLiveAction(anchor),
);
},
childCount: logic.recommendList.length,
),
),
);
},
);
}
//返回按钮
Widget _buildBack() {
return GestureDetector(
onTap: () => Get.back(),
child: Container(
padding: const EdgeInsets.only(left: 10, right: 2, top: 2, bottom: 2),
decoration:
const BoxDecoration(color: Colors.grey, shape: BoxShape.circle),
child: Icon(Icons.arrow_back_ios,
color: Colors.black.withValues(alpha: 0.8)),
),
);
}
//主播信息
Widget _buildAnchorInfo(LiveDetailLogic logic) {
return Padding(
padding: const EdgeInsets.fromLTRB(16, 12, 16, 0),
child: Column(
children: [
Row(
children: [
NetworkImageLoader(
imageUrl: logic.anchor?.coverImg ?? '',
width: 36,
height: 36,
borderRadius: 18,
encrypt: false,
),
4.sizeBoxW,
Text(logic.anchor?.name ?? '',
style: const TextStyle(fontSize: 14, color: Colors.white)),
],
),
18.sizeBoxH,
Row(
children: [
Text(
'${logic.anchor?.viewCount}人观众',
style: const TextStyle(fontSize: 12, color: Color(0xff999999)),
),
const Spacer(),
GestureDetector(
onTap: () => logic.onShareAction(),
child: Row(
children: [
Image.asset('live_share.png'.livePath, width: 24),
2.sizeBoxW,
const Text('分享',
style:
TextStyle(fontSize: 12, color: Color(0xff999999))),
],
),
),
],
),
],
),
);
}
//广告位
Widget _buildAds() {
return AdsGridViewWidget(
36,
accordingAdsType: true,
padding: const EdgeInsets.fromLTRB(16, 18, 0, 0),
);
}
//分割线
Widget _buildDivider() {
return SliverToBoxAdapter(
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 16),
height: .5,
color: Colors.black.withValues(alpha: .1),
),
);
}
}