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 createState() => _LiveDetailPageState(); } class _LiveDetailPageState extends State { @override Widget build(BuildContext context) { return Scaffold( body: SafeArea( child: GetBuilder( 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( 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( 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), ), ); } }