skywood/lib/pages/home/players/page/drama_detail_page.dart

254 lines
6.8 KiB
Dart

import 'package:flutter/material.dart';
import 'package:skywood/global/client/play_client.dart';
import 'package:skywood/main/lib_file.dart';
import 'package:skywood/pages/home/players/widget/sky_player_view.dart';
import 'package:skywood/utils/models/drama/skywood_detail.dart';
import 'package:skywood/utils/models/drama/skywood_drama.dart';
import 'package:skywood/utils/models/drama/skywood_episode.dart';
import 'package:skywood/utils/tools/app_toast.dart';
import 'package:skywood/utils/tools/widgets/sky_common_widget.dart';
class DramaDetailPage extends StatefulWidget {
const DramaDetailPage({super.key, required this.dramaBean});
final SkywoodDrama dramaBean;
@override
State<StatefulWidget> createState() {
return _DramaDetailPageState();
}
}
class _DramaDetailPageState extends State<DramaDetailPage> {
static const int _preloadCount = 1;
SkywoodDetail? _detailBean;
SkywoodEpisode? _selectedEpisode;
final PageController _pageController = PageController();
int _currentPageIndex = 0;
int? _requestingVideoId;
@override
void initState() {
super.initState();
_getDetailDrama(
shortPlayId: widget.dramaBean.shortPlayId ?? 0,
shortPlayVideoId: widget.dramaBean.shortPlayVideoId ?? 0,
);
}
@override
void dispose() {
_pageController.dispose();
super.dispose();
}
void _getDetailDrama({
required int shortPlayId,
required int shortPlayVideoId,
bool showLoading = true,
}) {
_requestingVideoId = shortPlayVideoId;
if (showLoading) {
AppToast.showLottieLoading();
}
PlayClient.getVideoDetail(
shortPlayId: shortPlayId,
shortPlayVideoId: shortPlayVideoId,
).then((value) {
if (showLoading) {
AppToast.dismiss();
}
if (!mounted) return;
if (_requestingVideoId != shortPlayVideoId) return;
setState(() {
_detailBean = value;
if (value != null) {
_selectedEpisode ??= _resolveCurrentEpisode(value);
_currentPageIndex = _indexOfEpisode(_selectedEpisode);
}
});
_jumpToCurrentPage();
});
}
void _onSelectedEpisode(SkywoodEpisode episode) {
setState(() {
_selectedEpisode = episode;
_currentPageIndex = _indexOfEpisode(episode);
});
_jumpToCurrentPage();
_getDetailDrama(
shortPlayId: episode.shortPlayId,
shortPlayVideoId: episode.shortPlayVideoId,
showLoading: false,
);
}
void _onPageChanged(int index) {
final episodes = _detailBean?.episodeList ?? [];
if (index < 0 || index >= episodes.length) return;
final episode = episodes[index];
if (_selectedEpisode?.shortPlayVideoId == episode.shortPlayVideoId) {
_currentPageIndex = index;
return;
}
setState(() {
_selectedEpisode = episode;
_currentPageIndex = index;
});
_getDetailDrama(
shortPlayId: episode.shortPlayId,
shortPlayVideoId: episode.shortPlayVideoId,
showLoading: false,
);
}
SkywoodEpisode? _resolveCurrentEpisode(SkywoodDetail detail) {
if (detail.episodeList.isEmpty) return null;
final int? episode =
_selectedEpisode?.episode ??
detail.videoInfo?.episode ??
detail.videoInfo?.currentEpisode ??
detail.shortPlayInfo?.episode ??
detail.shortPlayInfo?.currentEpisode ??
widget.dramaBean.currentEpisode ??
widget.dramaBean.episode;
if (episode != null && episode > 0) {
for (final item in detail.episodeList) {
if (item.episode == episode) return item;
}
}
return detail.episodeList.first;
}
int _indexOfEpisode(SkywoodEpisode? episode) {
final episodes = _detailBean?.episodeList ?? [];
if (episode == null || episodes.isEmpty) return 0;
final index = episodes.indexWhere(
(item) => item.shortPlayVideoId == episode.shortPlayVideoId,
);
return index < 0 ? 0 : index;
}
void _jumpToCurrentPage() {
WidgetsBinding.instance.addPostFrameCallback((_) {
if (!mounted || !_pageController.hasClients) return;
final episodes = _detailBean?.episodeList ?? [];
if (episodes.isEmpty) return;
final page = _currentPageIndex.clamp(0, episodes.length - 1);
if ((_pageController.page ?? _pageController.initialPage).round() ==
page) {
return;
}
_pageController.jumpToPage(page);
});
}
@override
Widget build(BuildContext context) {
return Scaffold(backgroundColor: Colors.black, body: _bodyWidget());
}
Widget _bodyWidget() {
return Stack(
children: [
SizedBox(width: double.infinity, height: double.infinity),
if (_detailBean != null)
Positioned(
bottom: 0,
left: 0,
right: 0,
top: 0,
child: _buildPlayerPager(),
),
Positioned(
top: AppScreen.statusBarHeight + 5,
left: 0,
right: 0,
child: _headerWidget(),
),
],
);
}
Widget _buildPlayerPager() {
final detail = _detailBean!;
final episodes = detail.episodeList;
if (episodes.isEmpty) {
return SkyPlayerView(
detailBean: detail,
dramaBean: widget.dramaBean,
currentEpisode: _selectedEpisode?.episode,
onSelectedEpisode: _onSelectedEpisode,
);
}
return PageView.builder(
controller: _pageController,
scrollDirection: Axis.vertical,
allowImplicitScrolling: true,
onPageChanged: _onPageChanged,
itemCount: episodes.length,
itemBuilder: (context, index) {
final episode = episodes[index];
final isCurrent = index == _currentPageIndex;
if (!_shouldBuildPlayer(index)) {
return const ColoredBox(color: Colors.black);
}
return SkyPlayerView(
key: ValueKey(
'${episode.shortPlayVideoId}-$isCurrent-${detail.videoInfo?.shortPlayVideoId}',
),
autoPlay: isCurrent,
detailBean: detail,
dramaBean: widget.dramaBean,
currentEpisode: episode.episode,
onSelectedEpisode: _onSelectedEpisode,
);
},
);
}
bool _shouldBuildPlayer(int index) {
return (index - _currentPageIndex).abs() <= _preloadCount;
}
Widget _headerWidget() {
return Container(
height: 40,
padding: const EdgeInsets.only(right: 15, left: 5),
child: Row(
children: [
IconButton(
icon: HelpImg.asset(ConstImg.back, width: 32),
onPressed: () => HelpNav.back(),
),
Expanded(
child: SkyText(
text: widget.dramaBean.name,
color: Colors.white,
fontSize: 16,
textAlign: TextAlign.center,
fontWeight: FontWeight.bold,
),
),
SizedBox(width: 40),
],
),
);
}
}