275 lines
10 KiB
Dart
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;
|
|
}
|