2025-09-17 18:13:57 +08:00

275 lines
10 KiB
Dart

import 'package:easy_refresh/easy_refresh.dart';
import 'package:flutter/material.dart';
import 'package:flutter_kinetra/kt_utils/kt_string_extend.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:video_player/video_player.dart';
import 'package:visibility_detector/visibility_detector.dart';
import '../../kt_model/kt_short_video_bean.dart';
import '../../kt_widgets/kt_network_image.dart';
import '../../kt_widgets/kt_status_widget.dart';
import '../kt_routes.dart';
import 'logic.dart';
class KtExplorePage extends StatefulWidget {
const KtExplorePage({super.key});
@override
State<KtExplorePage> createState() => _KtExplorePageState();
}
class _KtExplorePageState extends State<KtExplorePage>
with AutomaticKeepAliveClientMixin {
final logic = Get.put(KtExploreLogic());
final state = Get.find<KtExploreLogic>().state;
@override
Widget build(BuildContext context) {
super.build(context);
return GetBuilder<KtExploreLogic>(
builder: (ctrl) {
if (state.loadStatus == KtLoadStatusType.loadNoData ||
state.loadStatus == KtLoadStatusType.loadFailed) {
return KtStatusWidget(
type: KtErrorStatusType.nothingYet,
onPressed: logic.fetchDiscoverList,
);
}
return Container(
width: ScreenUtil().screenWidth,
height: ScreenUtil().screenHeight,
padding: EdgeInsets.only(
top: ScreenUtil().statusBarHeight,
left: 18.w,
right: 18.w,
),
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('explore_bg.png'.ktIcon),
fit: BoxFit.fill,
),
),
child: Stack(
clipBehavior: Clip.none,
children: [
Column(
children: [
SizedBox(height: 40.w),
Expanded(
child: EasyRefresh(
controller: logic.refreshCtrl,
header: MaterialHeader(),
footer: MaterialFooter(),
onRefresh: () => logic.fetchDiscoverList(refresh: true),
child: PageView.builder(
scrollDirection: Axis.vertical,
itemCount: state.videoList.length,
controller: logic.pageController,
onPageChanged: (index) => logic.onPageChanged(index),
itemBuilder: (_, index) =>
videoPlayerItem(index: index),
),
),
),
],
),
Row(
children: [
Stack(
clipBehavior: Clip.none,
children: [
Image.asset('ic_explore_ip.png'.ktIcon, width: 56.8.w),
Positioned(
top: 0.w,
right: -2.w,
child: Image.asset(
'ic_explore_tv.png'.ktIcon,
width: 19.w,
),
),
],
),
SizedBox(width: 12.w),
Text(
"Unlock Your Next Binge\nObsession",
style: TextStyle(
fontSize: 18.sp,
color: Colors.black,
fontStyle: FontStyle.italic,
fontWeight: FontWeight.w800,
),
),
],
),
],
),
);
},
);
}
Widget videoPlayerItem({int index = 0}) {
return GetBuilder<KtExploreLogic>(
builder: (ctrl) {
if (state.controllers.isEmpty) return Container();
final VideoPlayerController? videoPlayerController =
state.controllers[index];
if (videoPlayerController == null ||
!videoPlayerController.value.isInitialized) {
return Stack(
children: [
KtNetworkImage(
imageUrl: state.videoList[index].imageUrl!,
width: ScreenUtil().screenWidth - 36.w,
height: 540.w,
fit: BoxFit.cover,
borderRadius: BorderRadius.circular(16.w),
),
Center(child: CircularProgressIndicator()),
],
);
}
KtShortVideoBean item = state.videoList[index];
return Container(
margin: EdgeInsets.only(bottom: 18.w),
alignment: Alignment.topCenter,
child: GestureDetector(
onTap: () {
videoPlayerController.value.isPlaying
? videoPlayerController.pause()
: videoPlayerController.play();
setState(() {});
},
child: Stack(
alignment: Alignment.bottomCenter,
children: [
Positioned.fill(
child: VisibilityDetector(
key: ValueKey(
'discover-video-${state.videoList[index].id}',
),
onVisibilityChanged: (info) {
if (info.visibleFraction > 0.85 &&
state.currentPage == index &&
!videoPlayerController.value.isPlaying) {
videoPlayerController.play();
logic.update();
}
if (info.visibleFraction < 0.09 &&
videoPlayerController.value.isPlaying) {
videoPlayerController.pause();
logic.update();
}
},
child: ClipRRect(
borderRadius: BorderRadius.circular(16.w),
child: SizedBox(
width: ScreenUtil().screenWidth - 36.w,
height: 540.w,
child: VideoPlayer(videoPlayerController),
),
),
),
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.end,
children: [
Container(
width: ScreenUtil().screenWidth - 56.w,
margin: EdgeInsets.only(left: 12.w),
child: Text(
item.name ?? '',
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 16.sp,
color: Colors.white,
fontWeight: FontWeight.w500,
),
),
),
SizedBox(height: 11.w),
GestureDetector(
onTap: () {
Get.toNamed(
KtRoutes.shortVideo,
arguments: {
'shortPlayId': item.shortPlayId,
'imageUrl': item.imageUrl,
'isFromDiscover': true,
},
)?.then((v) {
videoPlayerController.play();
setState(() {});
});
},
child: Container(
width: ScreenUtil().screenWidth - 60.w,
margin: EdgeInsets.symmetric(horizontal: 12.w),
padding: EdgeInsets.symmetric(
horizontal: 12.w,
vertical: 9.w,
),
decoration: BoxDecoration(
color: Color(0xFF1E1E20).withValues(alpha: .3),
borderRadius: BorderRadius.circular(100),
),
child: Row(
children: [
Image.asset('ic_ep.png'.ktIcon, width: 16.w),
SizedBox(width: 6.w),
Text(
'Watch the complete series',
style: TextStyle(
fontSize: 12.sp,
color: Colors.white,
fontWeight: FontWeight.w400,
),
),
const Spacer(),
Image.asset(
'ic_right_white.png'.ktIcon,
width: 10.w,
),
],
),
),
),
SizedBox(height: 16.w),
// if (state.controllers[state.currentPage] != null)
// DrVideoProgressBar(
// controller: state.controllers[state.currentPage]!,
// width: ScreenUtil().screenWidth,
// ),
],
),
if (!videoPlayerController.value.isPlaying)
Positioned(
top: 240.h,
child: GestureDetector(
onTap: () {
videoPlayerController.value.isPlaying
? videoPlayerController.pause()
: videoPlayerController.play();
setState(() {});
},
child: Image.asset('ic_play.png'.ktIcon, width: 62.w),
),
),
],
),
),
);
},
);
}
@override
bool get wantKeepAlive => true;
}