Merge branch 'main' into opt-videoPlayerControl
This commit is contained in:
@ -1,5 +1,4 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
|
||||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:pilipala/common/constants.dart';
|
import 'package:pilipala/common/constants.dart';
|
||||||
@ -183,7 +182,7 @@ class _PagesBottomSheetState extends State<PagesBottomSheet>
|
|||||||
isFixedHeight: true,
|
isFixedHeight: true,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
_listObserverControllerList![widget.currentEpisodeIndex!]
|
_listObserverControllerList![widget.currentEpisodeIndex ?? 0]
|
||||||
.initialIndexModel = ObserverIndexPositionModel(
|
.initialIndexModel = ObserverIndexPositionModel(
|
||||||
index: currentIndex,
|
index: currentIndex,
|
||||||
isFixedHeight: true,
|
isFixedHeight: true,
|
||||||
|
|||||||
@ -5,6 +5,8 @@ import 'package:pilipala/plugin/pl_gallery/hero_dialog_route.dart';
|
|||||||
import 'package:pilipala/plugin/pl_gallery/interactiveviewer_gallery.dart';
|
import 'package:pilipala/plugin/pl_gallery/interactiveviewer_gallery.dart';
|
||||||
import 'package:pilipala/utils/highlight.dart';
|
import 'package:pilipala/utils/highlight.dart';
|
||||||
|
|
||||||
|
import '../../utils/global_data_cache.dart';
|
||||||
|
|
||||||
// ignore: must_be_immutable
|
// ignore: must_be_immutable
|
||||||
class HtmlRender extends StatelessWidget {
|
class HtmlRender extends StatelessWidget {
|
||||||
const HtmlRender({
|
const HtmlRender({
|
||||||
@ -41,6 +43,8 @@ class HtmlRender extends StatelessWidget {
|
|||||||
TagExtension(
|
TagExtension(
|
||||||
tagsToExtend: <String>{'img'},
|
tagsToExtend: <String>{'img'},
|
||||||
builder: (ExtensionContext extensionContext) {
|
builder: (ExtensionContext extensionContext) {
|
||||||
|
int defaultImgQuality = 10;
|
||||||
|
defaultImgQuality = GlobalDataCache.imgQuality;
|
||||||
try {
|
try {
|
||||||
final Map<String, dynamic> attributes =
|
final Map<String, dynamic> attributes =
|
||||||
extensionContext.attributes;
|
extensionContext.attributes;
|
||||||
@ -99,13 +103,13 @@ class HtmlRender extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
child: CachedNetworkImage(imageUrl: imgUrl),
|
child: ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
child: CachedNetworkImage(
|
||||||
|
imageUrl: '$imgUrl@${defaultImgQuality}q.webp',
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
// return NetworkImgLayer(
|
|
||||||
// width: isEmote ? 22 : Get.size.width - 24,
|
|
||||||
// height: isEmote ? 22 : 200,
|
|
||||||
// src: imgUrl,
|
|
||||||
// );
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return const SizedBox();
|
return const SizedBox();
|
||||||
}
|
}
|
||||||
@ -138,6 +142,14 @@ class HtmlRender extends StatelessWidget {
|
|||||||
textAlign: TextAlign.justify,
|
textAlign: TextAlign.justify,
|
||||||
),
|
),
|
||||||
'img': Style(margin: Margins.only(top: 4, bottom: 4)),
|
'img': Style(margin: Margins.only(top: 4, bottom: 4)),
|
||||||
|
'figcaption': Style(
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
margin: Margins.only(top: 8, bottom: 20),
|
||||||
|
color: Theme.of(context).colorScheme.secondary,
|
||||||
|
),
|
||||||
|
'figure': Style(
|
||||||
|
margin: Margins.zero,
|
||||||
|
),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,7 +20,6 @@ import '../../../models/video/reply/item.dart';
|
|||||||
import '../widgets/dynamic_panel.dart';
|
import '../widgets/dynamic_panel.dart';
|
||||||
|
|
||||||
class DynamicDetailPage extends StatefulWidget {
|
class DynamicDetailPage extends StatefulWidget {
|
||||||
// const DynamicDetailPage({super.key});
|
|
||||||
const DynamicDetailPage({Key? key}) : super(key: key);
|
const DynamicDetailPage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -90,19 +89,22 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
|
|||||||
_dynamicDetailController = Get.put(
|
_dynamicDetailController = Get.put(
|
||||||
DynamicDetailController(oid, replyType),
|
DynamicDetailController(oid, replyType),
|
||||||
tag: opusId.toString());
|
tag: opusId.toString());
|
||||||
|
_futureBuilderFuture = _dynamicDetailController.queryReplyList();
|
||||||
await _dynamicDetailController.reqHtmlByOpusId(opusId!);
|
await _dynamicDetailController.reqHtmlByOpusId(opusId!);
|
||||||
setState(() {});
|
setState(() {});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
oid = moduleDynamic.major!.draw!.id!;
|
oid = moduleDynamic.major!.draw!.id!;
|
||||||
}
|
}
|
||||||
} catch (_) {}
|
} catch (err) {
|
||||||
|
print('err:${err.toString()}');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!isOpusId) {
|
if (!isOpusId) {
|
||||||
_dynamicDetailController =
|
_dynamicDetailController =
|
||||||
Get.put(DynamicDetailController(oid, replyType), tag: oid.toString());
|
Get.put(DynamicDetailController(oid, replyType), tag: oid.toString());
|
||||||
|
_futureBuilderFuture = _dynamicDetailController.queryReplyList();
|
||||||
}
|
}
|
||||||
_futureBuilderFuture = _dynamicDetailController.queryReplyList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查看二级评论
|
// 查看二级评论
|
||||||
@ -132,7 +134,7 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
|
|||||||
// 分页加载
|
// 分页加载
|
||||||
if (scrollController.position.pixels >=
|
if (scrollController.position.pixels >=
|
||||||
scrollController.position.maxScrollExtent - 300) {
|
scrollController.position.maxScrollExtent - 300) {
|
||||||
EasyThrottle.throttle('replylist', const Duration(seconds: 2), () {
|
EasyThrottle.throttle('replyList', const Duration(seconds: 2), () {
|
||||||
_dynamicDetailController.onLoad();
|
_dynamicDetailController.onLoad();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -122,6 +122,7 @@ class LaterController extends GetxController {
|
|||||||
'heroTag': heroTag,
|
'heroTag': heroTag,
|
||||||
'sourceType': 'watchLater',
|
'sourceType': 'watchLater',
|
||||||
'count': laterList.length,
|
'count': laterList.length,
|
||||||
|
'mediaId': userInfo!.mid,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
||||||
import 'package:pilipala/models/read/opus.dart';
|
import 'package:pilipala/models/read/opus.dart';
|
||||||
|
|
||||||
import 'controller.dart';
|
import 'controller.dart';
|
||||||
import 'text_helper.dart';
|
import 'text_helper.dart';
|
||||||
|
|
||||||
@ -26,16 +27,18 @@ class _OpusPageState extends State<OpusPage> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: _buildAppBar(),
|
appBar: _buildAppBar(),
|
||||||
body: SingleChildScrollView(
|
body: CustomScrollView(
|
||||||
controller: controller.scrollController,
|
controller: controller.scrollController,
|
||||||
child: Column(
|
slivers: [
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
SliverList(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
delegate: SliverChildListDelegate(
|
||||||
children: [
|
[
|
||||||
_buildTitle(),
|
_buildTitle(),
|
||||||
_buildFutureContent(),
|
_buildFutureContent(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import 'package:pilipala/models/read/opus.dart';
|
|||||||
import 'package:pilipala/models/read/read.dart';
|
import 'package:pilipala/models/read/read.dart';
|
||||||
import 'package:pilipala/pages/opus/text_helper.dart';
|
import 'package:pilipala/pages/opus/text_helper.dart';
|
||||||
import 'package:pilipala/utils/utils.dart';
|
import 'package:pilipala/utils/utils.dart';
|
||||||
|
|
||||||
import 'controller.dart';
|
import 'controller.dart';
|
||||||
|
|
||||||
class ReadPage extends StatefulWidget {
|
class ReadPage extends StatefulWidget {
|
||||||
@ -38,16 +39,18 @@ class _ReadPageState extends State<ReadPage> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: _buildAppBar(),
|
appBar: _buildAppBar(),
|
||||||
body: SingleChildScrollView(
|
body: CustomScrollView(
|
||||||
controller: controller.scrollController,
|
controller: controller.scrollController,
|
||||||
child: Column(
|
slivers: [
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
SliverList(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
delegate: SliverChildListDelegate(
|
||||||
children: [
|
[
|
||||||
_buildTitle(),
|
_buildTitle(),
|
||||||
_buildFutureContent(),
|
_buildFutureContent(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -487,7 +487,7 @@ class VideoDetailController extends GetxController
|
|||||||
if (result['status']) {
|
if (result['status']) {
|
||||||
if (result['data'].subtitles.isNotEmpty) {
|
if (result['data'].subtitles.isNotEmpty) {
|
||||||
subtitles = result['data'].subtitles;
|
subtitles = result['data'].subtitles;
|
||||||
getDanmaku(subtitles);
|
getSubtitleContent(subtitles);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
headerControl = HeaderControl(
|
headerControl = HeaderControl(
|
||||||
@ -501,8 +501,8 @@ class VideoDetailController extends GetxController
|
|||||||
plPlayerController.setHeaderControl(headerControl);
|
plPlayerController.setHeaderControl(headerControl);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取弹幕
|
// 获取字幕
|
||||||
Future getDanmaku(List subtitles) async {
|
Future getSubtitleContent(List subtitles) async {
|
||||||
if (subtitles.isNotEmpty) {
|
if (subtitles.isNotEmpty) {
|
||||||
for (var i in subtitles) {
|
for (var i in subtitles) {
|
||||||
final Map<String, dynamic> res = await VideoHttp.getSubtitleContent(
|
final Map<String, dynamic> res = await VideoHttp.getSubtitleContent(
|
||||||
|
|||||||
@ -523,7 +523,7 @@ class VideoIntroController extends GetxController {
|
|||||||
Get.find<VideoDetailController>(tag: heroTag);
|
Get.find<VideoDetailController>(tag: heroTag);
|
||||||
|
|
||||||
/// 优先稍后再看、收藏夹
|
/// 优先稍后再看、收藏夹
|
||||||
if (videoDetailCtr.isWatchLaterVisible.value) {
|
if (videoDetailCtr.sourceType.value != 'normal') {
|
||||||
episodes.addAll(videoDetailCtr.mediaList);
|
episodes.addAll(videoDetailCtr.mediaList);
|
||||||
} else if (videoDetail.value.ugcSeason != null) {
|
} else if (videoDetail.value.ugcSeason != null) {
|
||||||
final UgcSeason ugcSeason = videoDetail.value.ugcSeason!;
|
final UgcSeason ugcSeason = videoDetail.value.ugcSeason!;
|
||||||
@ -617,6 +617,7 @@ class VideoIntroController extends GetxController {
|
|||||||
// 播放器底栏 选集 回调
|
// 播放器底栏 选集 回调
|
||||||
void showEposideHandler() {
|
void showEposideHandler() {
|
||||||
late List episodes;
|
late List episodes;
|
||||||
|
int currentEpisodeIndex = 0;
|
||||||
VideoEpidoesType dataType = VideoEpidoesType.videoEpisode;
|
VideoEpidoesType dataType = VideoEpidoesType.videoEpisode;
|
||||||
if (videoDetail.value.ugcSeason != null) {
|
if (videoDetail.value.ugcSeason != null) {
|
||||||
dataType = VideoEpidoesType.videoEpisode;
|
dataType = VideoEpidoesType.videoEpisode;
|
||||||
@ -625,6 +626,7 @@ class VideoIntroController extends GetxController {
|
|||||||
final List<EpisodeItem> episodesList = sections[i].episodes!;
|
final List<EpisodeItem> episodesList = sections[i].episodes!;
|
||||||
for (int j = 0; j < episodesList.length; j++) {
|
for (int j = 0; j < episodesList.length; j++) {
|
||||||
if (episodesList[j].cid == lastPlayCid.value) {
|
if (episodesList[j].cid == lastPlayCid.value) {
|
||||||
|
currentEpisodeIndex = i;
|
||||||
episodes = episodesList;
|
episodes = episodesList;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -644,6 +646,7 @@ class VideoIntroController extends GetxController {
|
|||||||
sheetHeight: Get.size.height,
|
sheetHeight: Get.size.height,
|
||||||
isFullScreen: true,
|
isFullScreen: true,
|
||||||
ugcSeason: ugcSeason,
|
ugcSeason: ugcSeason,
|
||||||
|
currentEpisodeIndex: currentEpisodeIndex,
|
||||||
changeFucCall: (item, index) {
|
changeFucCall: (item, index) {
|
||||||
if (dataType == VideoEpidoesType.videoEpisode) {
|
if (dataType == VideoEpidoesType.videoEpisode) {
|
||||||
changeSeasonOrbangu(
|
changeSeasonOrbangu(
|
||||||
|
|||||||
@ -42,23 +42,14 @@ class _SeasonPanelState extends State<SeasonPanel> {
|
|||||||
_videoDetailController = Get.find<VideoDetailController>(tag: heroTag);
|
_videoDetailController = Get.find<VideoDetailController>(tag: heroTag);
|
||||||
|
|
||||||
/// 根据 cid 找到对应集,找到对应 episodes
|
/// 根据 cid 找到对应集,找到对应 episodes
|
||||||
final List<SectionItem> sections = widget.ugcSeason.sections!;
|
getCurrentEpisodeIndex();
|
||||||
for (int i = 0; i < sections.length; i++) {
|
|
||||||
final List<EpisodeItem> episodesList = sections[i].episodes!;
|
|
||||||
for (int j = 0; j < episodesList.length; j++) {
|
|
||||||
if (episodesList[j].cid == cid) {
|
|
||||||
currentEpisodeIndex = i;
|
|
||||||
episodes = episodesList;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 取对应 season_id 的 episodes
|
/// 取对应 season_id 的 episodes
|
||||||
getCurrentIndex();
|
getCurrentIndex();
|
||||||
_videoDetailController.cid.listen((int p0) {
|
_videoDetailController.cid.listen((int p0) {
|
||||||
cid = p0;
|
cid = p0;
|
||||||
getCurrentIndex();
|
getCurrentIndex();
|
||||||
|
getCurrentEpisodeIndex();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,6 +85,21 @@ class _SeasonPanelState extends State<SeasonPanel> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取currentEpisodeIndex
|
||||||
|
void getCurrentEpisodeIndex() {
|
||||||
|
final List<SectionItem> sections = widget.ugcSeason.sections!;
|
||||||
|
for (int i = 0; i < sections.length; i++) {
|
||||||
|
final List<EpisodeItem> episodesList = sections[i].episodes!;
|
||||||
|
for (int j = 0; j < episodesList.length; j++) {
|
||||||
|
if (episodesList[j].cid == cid) {
|
||||||
|
currentEpisodeIndex = i;
|
||||||
|
episodes = episodesList;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Widget buildEpisodeListItem(
|
Widget buildEpisodeListItem(
|
||||||
EpisodeItem episode,
|
EpisodeItem episode,
|
||||||
int index,
|
int index,
|
||||||
|
|||||||
@ -70,6 +70,13 @@ class VideoReplyController extends GetxController {
|
|||||||
isEnd = res['data'].cursor.isEnd ?? false;
|
isEnd = res['data'].cursor.isEnd ?? false;
|
||||||
nextOffset = res['data'].cursor.paginationReply.nextOffset ?? "";
|
nextOffset = res['data'].cursor.paginationReply.nextOffset ?? "";
|
||||||
if (replies.isNotEmpty) {
|
if (replies.isNotEmpty) {
|
||||||
|
/// 临时修复
|
||||||
|
final bool flag = replyList
|
||||||
|
.any((ReplyItemModel reply) => reply.rpid == replies.first.rpid);
|
||||||
|
if (replies.length == 1 && flag) {
|
||||||
|
replies.clear();
|
||||||
|
isEnd = true;
|
||||||
|
}
|
||||||
noMore.value = isEnd ? '没有更多了' : '加载中...';
|
noMore.value = isEnd ? '没有更多了' : '加载中...';
|
||||||
} else {
|
} else {
|
||||||
noMore.value =
|
noMore.value =
|
||||||
|
|||||||
@ -685,6 +685,11 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
|||||||
canPop:
|
canPop:
|
||||||
plPlayerController?.isFullScreen.value != true,
|
plPlayerController?.isFullScreen.value != true,
|
||||||
onPopInvoked: (bool didPop) {
|
onPopInvoked: (bool didPop) {
|
||||||
|
if (plPlayerController?.controlsLock.value ==
|
||||||
|
true) {
|
||||||
|
plPlayerController?.onLockControl(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (plPlayerController?.isFullScreen.value ==
|
if (plPlayerController?.isFullScreen.value ==
|
||||||
true) {
|
true) {
|
||||||
plPlayerController!
|
plPlayerController!
|
||||||
|
|||||||
@ -85,9 +85,12 @@ class _MediaListPanelState extends State<MediaListPanel> {
|
|||||||
AppBar(
|
AppBar(
|
||||||
toolbarHeight: 45,
|
toolbarHeight: 45,
|
||||||
automaticallyImplyLeading: false,
|
automaticallyImplyLeading: false,
|
||||||
title: Text(
|
title: Padding(
|
||||||
widget.panelTitle ?? '稍后再看',
|
padding: const EdgeInsets.only(left: 12),
|
||||||
style: Theme.of(context).textTheme.titleSmall,
|
child: Text(
|
||||||
|
widget.panelTitle ?? '稍后再看',
|
||||||
|
style: Theme.of(context).textTheme.titleSmall,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
actions: [
|
actions: [
|
||||||
IconButton(
|
IconButton(
|
||||||
|
|||||||
@ -917,7 +917,7 @@ class PlPlayerController {
|
|||||||
if (videoType == 'live') {
|
if (videoType == 'live') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (controlsLock.value) {
|
if (_controlsLock.value) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_doubleSpeedStatus.value = val;
|
_doubleSpeedStatus.value = val;
|
||||||
@ -1093,6 +1093,7 @@ class PlPlayerController {
|
|||||||
videoFitChangedTimer?.cancel();
|
videoFitChangedTimer?.cancel();
|
||||||
// _position.close();
|
// _position.close();
|
||||||
_playerEventSubs?.cancel();
|
_playerEventSubs?.cancel();
|
||||||
|
_controlsLock.value = false;
|
||||||
// _sliderPosition.close();
|
// _sliderPosition.close();
|
||||||
// _sliderTempPosition.close();
|
// _sliderTempPosition.close();
|
||||||
// _isSliderMoving.close();
|
// _isSliderMoving.close();
|
||||||
|
|||||||
Reference in New Issue
Block a user