初始化
This commit is contained in:
@@ -0,0 +1,336 @@
|
||||
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),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user