mirror of
https://github.com/HChaZZY/PiliPlus.git
synced 2025-12-06 09:13:48 +08:00
refa: video bottom sheet
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
@@ -126,8 +126,6 @@ class VideoDetailController extends GetxController
|
||||
PlayerStatus? playerStatus;
|
||||
StreamSubscription<Duration>? positionSubscription;
|
||||
|
||||
PersistentBottomSheetController? bsController;
|
||||
|
||||
bool imageStatus = false;
|
||||
|
||||
void onViewImage() {
|
||||
@@ -1229,9 +1227,9 @@ class VideoDetailController extends GetxController
|
||||
);
|
||||
}
|
||||
if (plPlayerController.isFullScreen.value) {
|
||||
bsController = scaffoldKey.currentState?.showBottomSheet(
|
||||
enableDrag: false,
|
||||
(context) => _postPanel(false),
|
||||
Utils.showFSSheet(
|
||||
child: _postPanel(),
|
||||
isFullScreen: plPlayerController.isFullScreen.value,
|
||||
);
|
||||
} else {
|
||||
childKey.currentState?.showBottomSheet(
|
||||
@@ -1241,7 +1239,7 @@ class VideoDetailController extends GetxController
|
||||
}
|
||||
}
|
||||
|
||||
Widget _postPanel([bool isChild = true]) => StatefulBuilder(
|
||||
Widget _postPanel() => StatefulBuilder(
|
||||
builder: (context, setState) {
|
||||
void updateSegment({
|
||||
required bool isFirst,
|
||||
@@ -1361,378 +1359,358 @@ class VideoDetailController extends GetxController
|
||||
];
|
||||
}
|
||||
|
||||
return SizedBox(
|
||||
height: isChild ? null : Utils.getSheetHeight(context),
|
||||
child: Scaffold(
|
||||
resizeToAvoidBottomInset: false,
|
||||
appBar: AppBar(
|
||||
automaticallyImplyLeading: false,
|
||||
titleSpacing: 16,
|
||||
title: const Text('提交片段'),
|
||||
actions: [
|
||||
iconButton(
|
||||
context: context,
|
||||
tooltip: '添加片段',
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
list?.insert(
|
||||
0,
|
||||
PostSegmentModel(
|
||||
segment: Pair(
|
||||
first: 0,
|
||||
second: plPlayerController.positionSeconds.value,
|
||||
),
|
||||
category: SegmentType.sponsor,
|
||||
actionType: ActionType.skip,
|
||||
return Scaffold(
|
||||
resizeToAvoidBottomInset: false,
|
||||
appBar: AppBar(
|
||||
automaticallyImplyLeading: false,
|
||||
titleSpacing: 16,
|
||||
title: const Text('提交片段'),
|
||||
actions: [
|
||||
iconButton(
|
||||
context: context,
|
||||
tooltip: '添加片段',
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
list?.insert(
|
||||
0,
|
||||
PostSegmentModel(
|
||||
segment: Pair(
|
||||
first: 0,
|
||||
second: plPlayerController.positionSeconds.value,
|
||||
),
|
||||
);
|
||||
});
|
||||
},
|
||||
icon: Icons.add,
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
iconButton(
|
||||
context: context,
|
||||
tooltip: '关闭',
|
||||
onPressed: () {
|
||||
if (bsController != null) {
|
||||
bsController!.close();
|
||||
bsController = null;
|
||||
} else {
|
||||
Get.back();
|
||||
}
|
||||
},
|
||||
icon: Icons.close,
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
],
|
||||
),
|
||||
body: list?.isNotEmpty == true
|
||||
? Stack(
|
||||
children: [
|
||||
SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
...List.generate(
|
||||
list!.length,
|
||||
(index) => Stack(
|
||||
children: [
|
||||
Container(
|
||||
margin: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
vertical: 5,
|
||||
),
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onInverseSurface,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (list![index].actionType !=
|
||||
ActionType.full) ...[
|
||||
Row(
|
||||
children: [
|
||||
...segmentWidget(
|
||||
isFirst: true,
|
||||
index: index,
|
||||
),
|
||||
if (list![index].category !=
|
||||
SegmentType
|
||||
.poi_highlight) ...[
|
||||
const SizedBox(width: 16),
|
||||
...segmentWidget(
|
||||
isFirst: false,
|
||||
index: index,
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
],
|
||||
category: SegmentType.sponsor,
|
||||
actionType: ActionType.skip,
|
||||
),
|
||||
);
|
||||
});
|
||||
},
|
||||
icon: Icons.add,
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
iconButton(
|
||||
context: context,
|
||||
tooltip: '关闭',
|
||||
onPressed: Get.back,
|
||||
icon: Icons.close,
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
],
|
||||
),
|
||||
body: list?.isNotEmpty == true
|
||||
? Stack(
|
||||
children: [
|
||||
SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
...List.generate(
|
||||
list!.length,
|
||||
(index) => Stack(
|
||||
children: [
|
||||
Container(
|
||||
margin: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
vertical: 5,
|
||||
),
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onInverseSurface,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (list![index].actionType !=
|
||||
ActionType.full) ...[
|
||||
Row(
|
||||
children: [
|
||||
const Text('分类: '),
|
||||
PopupMenuButton(
|
||||
initialValue:
|
||||
list![index].category,
|
||||
onSelected: (item) async {
|
||||
list![index].category = item;
|
||||
List<ActionType>
|
||||
constraintList =
|
||||
_segmentType2ActionType(
|
||||
item);
|
||||
if (constraintList
|
||||
.contains(list![index]
|
||||
.actionType)
|
||||
.not) {
|
||||
list![index].actionType =
|
||||
constraintList.first;
|
||||
}
|
||||
switch (item) {
|
||||
case SegmentType
|
||||
.poi_highlight:
|
||||
updateSegment(
|
||||
isFirst: false,
|
||||
index: index,
|
||||
value: list![index]
|
||||
.segment
|
||||
.first,
|
||||
);
|
||||
break;
|
||||
case SegmentType
|
||||
.exclusive_access:
|
||||
updateSegment(
|
||||
isFirst: true,
|
||||
index: index,
|
||||
value: 0,
|
||||
);
|
||||
break;
|
||||
case _:
|
||||
}
|
||||
setState(() {});
|
||||
},
|
||||
itemBuilder: (context) =>
|
||||
SegmentType.values
|
||||
.map((item) =>
|
||||
PopupMenuItem<
|
||||
SegmentType>(
|
||||
value: item,
|
||||
child: Text(
|
||||
item.title),
|
||||
))
|
||||
.toList(),
|
||||
child: Row(
|
||||
mainAxisSize:
|
||||
MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
list![index]
|
||||
.category
|
||||
.title,
|
||||
style: TextStyle(
|
||||
height: 1,
|
||||
fontSize: 14,
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.secondary,
|
||||
),
|
||||
strutStyle: StrutStyle(
|
||||
height: 1,
|
||||
leading: 0,
|
||||
),
|
||||
),
|
||||
Icon(
|
||||
MdiIcons
|
||||
.unfoldMoreHorizontal,
|
||||
size: MediaQuery
|
||||
.textScalerOf(
|
||||
context)
|
||||
.scale(14),
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.secondary,
|
||||
),
|
||||
],
|
||||
),
|
||||
...segmentWidget(
|
||||
isFirst: true,
|
||||
index: index,
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
const Text('行为类别: '),
|
||||
PopupMenuButton(
|
||||
initialValue:
|
||||
list![index].actionType,
|
||||
onSelected: (item) async {
|
||||
if (list![index].category !=
|
||||
SegmentType
|
||||
.poi_highlight) ...[
|
||||
const SizedBox(width: 16),
|
||||
...segmentWidget(
|
||||
isFirst: false,
|
||||
index: index,
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
],
|
||||
Row(
|
||||
children: [
|
||||
const Text('分类: '),
|
||||
PopupMenuButton(
|
||||
initialValue:
|
||||
list![index].category,
|
||||
onSelected: (item) async {
|
||||
list![index].category = item;
|
||||
List<ActionType>
|
||||
constraintList =
|
||||
_segmentType2ActionType(
|
||||
item);
|
||||
if (constraintList
|
||||
.contains(
|
||||
list![index].actionType)
|
||||
.not) {
|
||||
list![index].actionType =
|
||||
item;
|
||||
if (item == ActionType.full) {
|
||||
constraintList.first;
|
||||
}
|
||||
switch (item) {
|
||||
case SegmentType
|
||||
.poi_highlight:
|
||||
updateSegment(
|
||||
isFirst: false,
|
||||
index: index,
|
||||
value: list![index]
|
||||
.segment
|
||||
.first,
|
||||
);
|
||||
break;
|
||||
case SegmentType
|
||||
.exclusive_access:
|
||||
updateSegment(
|
||||
isFirst: true,
|
||||
index: index,
|
||||
value: 0,
|
||||
);
|
||||
}
|
||||
setState(() {});
|
||||
},
|
||||
itemBuilder: (context) =>
|
||||
ActionType.values
|
||||
.map(
|
||||
(item) =>
|
||||
PopupMenuItem<
|
||||
ActionType>(
|
||||
enabled: _segmentType2ActionType(
|
||||
list![index]
|
||||
.category)
|
||||
.contains(item),
|
||||
break;
|
||||
case _:
|
||||
}
|
||||
setState(() {});
|
||||
},
|
||||
itemBuilder: (context) =>
|
||||
SegmentType.values
|
||||
.map((item) =>
|
||||
PopupMenuItem<
|
||||
SegmentType>(
|
||||
value: item,
|
||||
child: Text(
|
||||
item.title),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
child: Row(
|
||||
mainAxisSize:
|
||||
MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
list![index]
|
||||
.actionType
|
||||
.title,
|
||||
style: TextStyle(
|
||||
height: 1,
|
||||
fontSize: 14,
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.secondary,
|
||||
),
|
||||
strutStyle: StrutStyle(
|
||||
height: 1,
|
||||
leading: 0,
|
||||
),
|
||||
),
|
||||
Icon(
|
||||
MdiIcons
|
||||
.unfoldMoreHorizontal,
|
||||
size: MediaQuery
|
||||
.textScalerOf(
|
||||
context)
|
||||
.scale(14),
|
||||
))
|
||||
.toList(),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
list![index].category.title,
|
||||
style: TextStyle(
|
||||
height: 1,
|
||||
fontSize: 14,
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.secondary,
|
||||
),
|
||||
],
|
||||
),
|
||||
strutStyle: StrutStyle(
|
||||
height: 1,
|
||||
leading: 0,
|
||||
),
|
||||
),
|
||||
Icon(
|
||||
MdiIcons
|
||||
.unfoldMoreHorizontal,
|
||||
size:
|
||||
MediaQuery.textScalerOf(
|
||||
context)
|
||||
.scale(14),
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.secondary,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
top: 10,
|
||||
right: 21,
|
||||
child: iconButton(
|
||||
context: context,
|
||||
size: 26,
|
||||
tooltip: '移除',
|
||||
icon: Icons.clear,
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
list!.removeAt(index);
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height:
|
||||
88 + MediaQuery.paddingOf(context).bottom,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
right: 16,
|
||||
bottom: 16 + MediaQuery.paddingOf(context).bottom,
|
||||
child: FloatingActionButton(
|
||||
tooltip: '提交',
|
||||
onPressed: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('确定无误再提交'),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: Get.back,
|
||||
child: Text(
|
||||
'取消',
|
||||
style: TextStyle(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.outline,
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
const Text('行为类别: '),
|
||||
PopupMenuButton(
|
||||
initialValue:
|
||||
list![index].actionType,
|
||||
onSelected: (item) async {
|
||||
list![index].actionType = item;
|
||||
if (item == ActionType.full) {
|
||||
updateSegment(
|
||||
isFirst: true,
|
||||
index: index,
|
||||
value: 0,
|
||||
);
|
||||
}
|
||||
setState(() {});
|
||||
},
|
||||
itemBuilder: (context) =>
|
||||
ActionType.values
|
||||
.map(
|
||||
(item) => PopupMenuItem<
|
||||
ActionType>(
|
||||
enabled: _segmentType2ActionType(
|
||||
list![index]
|
||||
.category)
|
||||
.contains(item),
|
||||
value: item,
|
||||
child:
|
||||
Text(item.title),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
list![index]
|
||||
.actionType
|
||||
.title,
|
||||
style: TextStyle(
|
||||
height: 1,
|
||||
fontSize: 14,
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.secondary,
|
||||
),
|
||||
strutStyle: StrutStyle(
|
||||
height: 1,
|
||||
leading: 0,
|
||||
),
|
||||
),
|
||||
Icon(
|
||||
MdiIcons
|
||||
.unfoldMoreHorizontal,
|
||||
size:
|
||||
MediaQuery.textScalerOf(
|
||||
context)
|
||||
.scale(14),
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.secondary,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
top: 10,
|
||||
right: 21,
|
||||
child: iconButton(
|
||||
context: context,
|
||||
size: 26,
|
||||
tooltip: '移除',
|
||||
icon: Icons.clear,
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
list!.removeAt(index);
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 88 + MediaQuery.paddingOf(context).bottom,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
right: 16,
|
||||
bottom: 16 + MediaQuery.paddingOf(context).bottom,
|
||||
child: FloatingActionButton(
|
||||
tooltip: '提交',
|
||||
onPressed: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('确定无误再提交'),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: Get.back,
|
||||
child: Text(
|
||||
'取消',
|
||||
style: TextStyle(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.outline,
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Get.back();
|
||||
Request()
|
||||
.post(
|
||||
'${GStorage.blockServer}/api/skipSegments',
|
||||
queryParameters: {
|
||||
'videoID': bvid,
|
||||
'cid': cid.value,
|
||||
'userID': GStorage.blockUserID,
|
||||
'userAgent': Constants.userAgent,
|
||||
'videoDuration': plPlayerController
|
||||
.durationSeconds
|
||||
.value
|
||||
.inSeconds,
|
||||
},
|
||||
data: {
|
||||
'segments': list!
|
||||
.map(
|
||||
(item) => {
|
||||
'segment': [
|
||||
item.segment.first,
|
||||
item.segment.second,
|
||||
],
|
||||
'category':
|
||||
item.category.name,
|
||||
'actionType':
|
||||
item.actionType.name,
|
||||
},
|
||||
)
|
||||
.toList(),
|
||||
},
|
||||
options: _options,
|
||||
)
|
||||
.then(
|
||||
(res) {
|
||||
if (res.statusCode == 200) {
|
||||
Get.back();
|
||||
SmartDialog.showToast('提交成功');
|
||||
list?.clear();
|
||||
_handleSBData(res);
|
||||
plPlayerController
|
||||
.segmentList.value =
|
||||
_segmentProgressList ??
|
||||
<Segment>[];
|
||||
if (positionSubscription ==
|
||||
null) {
|
||||
_initSkip();
|
||||
}
|
||||
} else {
|
||||
SmartDialog.showToast(
|
||||
'提交失败: ${{
|
||||
400: '参数错误',
|
||||
403: '被自动审核机制拒绝',
|
||||
429: '重复提交太快',
|
||||
409: '重复提交'
|
||||
}[res.statusCode]}',
|
||||
);
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Get.back();
|
||||
Request()
|
||||
.post(
|
||||
'${GStorage.blockServer}/api/skipSegments',
|
||||
queryParameters: {
|
||||
'videoID': bvid,
|
||||
'cid': cid.value,
|
||||
'userID': GStorage.blockUserID,
|
||||
'userAgent': Constants.userAgent,
|
||||
'videoDuration': plPlayerController
|
||||
.durationSeconds.value.inSeconds,
|
||||
},
|
||||
data: {
|
||||
'segments': list!
|
||||
.map(
|
||||
(item) => {
|
||||
'segment': [
|
||||
item.segment.first,
|
||||
item.segment.second,
|
||||
],
|
||||
'category':
|
||||
item.category.name,
|
||||
'actionType':
|
||||
item.actionType.name,
|
||||
},
|
||||
)
|
||||
.toList(),
|
||||
},
|
||||
options: _options,
|
||||
)
|
||||
.then(
|
||||
(res) {
|
||||
if (res.statusCode == 200) {
|
||||
Get.back();
|
||||
SmartDialog.showToast('提交成功');
|
||||
list?.clear();
|
||||
_handleSBData(res);
|
||||
plPlayerController
|
||||
.segmentList.value =
|
||||
_segmentProgressList ??
|
||||
<Segment>[];
|
||||
if (positionSubscription == null) {
|
||||
_initSkip();
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
child: const Text('确定提交'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Icon(Icons.check),
|
||||
),
|
||||
)
|
||||
],
|
||||
)
|
||||
: errorWidget(),
|
||||
),
|
||||
} else {
|
||||
SmartDialog.showToast(
|
||||
'提交失败: ${{
|
||||
400: '参数错误',
|
||||
403: '被自动审核机制拒绝',
|
||||
429: '重复提交太快',
|
||||
409: '重复提交'
|
||||
}[res.statusCode]}',
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
child: const Text('确定提交'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Icon(Icons.check),
|
||||
),
|
||||
)
|
||||
],
|
||||
)
|
||||
: errorWidget(),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -1803,14 +1803,7 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
||||
videoDetailController.videoType == SearchType.media_bangumi
|
||||
? bangumiIntroController.changeSeasonOrbangu
|
||||
: videoIntroController.changeSeasonOrbangu,
|
||||
onClose: () {
|
||||
if (videoDetailController.bsController != null) {
|
||||
videoDetailController.bsController!.close();
|
||||
videoDetailController.bsController = null;
|
||||
} else {
|
||||
Get.back();
|
||||
}
|
||||
},
|
||||
onClose: Get.back,
|
||||
onReverse: () {
|
||||
Get.back();
|
||||
onReversePlay(
|
||||
@@ -1821,10 +1814,7 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
||||
},
|
||||
);
|
||||
if (isFullScreen) {
|
||||
videoDetailController.bsController =
|
||||
videoDetailController.scaffoldKey.currentState?.showBottomSheet(
|
||||
(context) => listSheetContent(),
|
||||
);
|
||||
Utils.showFSSheet(child: listSheetContent(), isFullScreen: isFullScreen);
|
||||
} else {
|
||||
videoDetailController.childKey.currentState?.showBottomSheet(
|
||||
(context) => listSheetContent(),
|
||||
@@ -1903,157 +1893,138 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
||||
}
|
||||
|
||||
void showViewPoints() {
|
||||
Widget listSheetContent(context, [bool isFS = false]) {
|
||||
Widget listSheetContent() {
|
||||
int currentIndex = -1;
|
||||
return StatefulBuilder(
|
||||
builder: (context, setState) => SizedBox(
|
||||
height: isFS ? Utils.getSheetHeight(context) : null,
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
automaticallyImplyLeading: false,
|
||||
titleSpacing: 16,
|
||||
title: const Text('分段信息'),
|
||||
actions: [
|
||||
Text(
|
||||
'分段进度条',
|
||||
style: TextStyle(fontSize: 16),
|
||||
),
|
||||
Obx(
|
||||
() => Transform.scale(
|
||||
alignment: Alignment.centerLeft,
|
||||
scale: 0.8,
|
||||
child: Switch(
|
||||
thumbIcon:
|
||||
WidgetStateProperty.resolveWith<Icon?>((states) {
|
||||
if (states.isNotEmpty &&
|
||||
states.first == WidgetState.selected) {
|
||||
return const Icon(Icons.done);
|
||||
}
|
||||
return null;
|
||||
}),
|
||||
value:
|
||||
videoDetailController.plPlayerController.showVP.value,
|
||||
onChanged: (value) {
|
||||
videoDetailController.plPlayerController.showVP.value =
|
||||
value;
|
||||
},
|
||||
),
|
||||
builder: (context, setState) => Scaffold(
|
||||
appBar: AppBar(
|
||||
automaticallyImplyLeading: false,
|
||||
titleSpacing: 16,
|
||||
title: const Text('分段信息'),
|
||||
actions: [
|
||||
Text(
|
||||
'分段进度条',
|
||||
style: TextStyle(fontSize: 16),
|
||||
),
|
||||
Obx(
|
||||
() => Transform.scale(
|
||||
alignment: Alignment.centerLeft,
|
||||
scale: 0.8,
|
||||
child: Switch(
|
||||
thumbIcon: WidgetStateProperty.resolveWith<Icon?>((states) {
|
||||
if (states.isNotEmpty &&
|
||||
states.first == WidgetState.selected) {
|
||||
return const Icon(Icons.done);
|
||||
}
|
||||
return null;
|
||||
}),
|
||||
value:
|
||||
videoDetailController.plPlayerController.showVP.value,
|
||||
onChanged: (value) {
|
||||
videoDetailController.plPlayerController.showVP.value =
|
||||
value;
|
||||
},
|
||||
),
|
||||
),
|
||||
iconButton(
|
||||
context: context,
|
||||
size: 30,
|
||||
icon: Icons.clear,
|
||||
tooltip: '关闭',
|
||||
onPressed: () {
|
||||
if (videoDetailController.bsController != null) {
|
||||
videoDetailController.bsController!.close();
|
||||
videoDetailController.bsController = null;
|
||||
} else {
|
||||
Get.back();
|
||||
}
|
||||
},
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
],
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
...List.generate(
|
||||
videoDetailController.viewPointList.length * 2 - 1,
|
||||
(rawIndex) {
|
||||
if (rawIndex % 2 == 1) {
|
||||
return Divider(
|
||||
height: 1,
|
||||
color: Theme.of(context).dividerColor.withOpacity(0.1),
|
||||
);
|
||||
}
|
||||
int index = rawIndex ~/ 2;
|
||||
Segment segment =
|
||||
videoDetailController.viewPointList[index];
|
||||
if (currentIndex == -1 &&
|
||||
segment.from != null &&
|
||||
segment.to != null) {
|
||||
if (videoDetailController
|
||||
.plPlayerController.positionSeconds.value >=
|
||||
segment.from! &&
|
||||
videoDetailController
|
||||
.plPlayerController.positionSeconds.value <
|
||||
segment.to!) {
|
||||
currentIndex = index;
|
||||
}
|
||||
}
|
||||
return ListTile(
|
||||
dense: true,
|
||||
onTap: segment.from != null
|
||||
? () {
|
||||
currentIndex = index;
|
||||
plPlayerController?.danmakuController?.clear();
|
||||
plPlayerController?.videoPlayerController
|
||||
?.seek(Duration(seconds: segment.from!));
|
||||
if (videoDetailController.bsController != null) {
|
||||
videoDetailController.bsController!.close();
|
||||
videoDetailController.bsController = null;
|
||||
} else {
|
||||
Get.back();
|
||||
// setState(() {});
|
||||
}
|
||||
}
|
||||
: null,
|
||||
leading: segment.url?.isNotEmpty == true
|
||||
? Container(
|
||||
margin: const EdgeInsets.symmetric(vertical: 6),
|
||||
decoration: currentIndex == index
|
||||
? BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
border: Border.all(
|
||||
width: 1.8,
|
||||
strokeAlign:
|
||||
BorderSide.strokeAlignOutside,
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.primary,
|
||||
),
|
||||
)
|
||||
: null,
|
||||
child: LayoutBuilder(
|
||||
builder: (context, constraints) =>
|
||||
NetworkImgLayer(
|
||||
radius: 6,
|
||||
src: segment.url,
|
||||
width: constraints.maxHeight *
|
||||
StyleString.aspectRatio,
|
||||
height: constraints.maxHeight,
|
||||
),
|
||||
),
|
||||
)
|
||||
: null,
|
||||
title: Text(
|
||||
segment.title ?? '',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight:
|
||||
currentIndex == index ? FontWeight.bold : null,
|
||||
color: currentIndex == index
|
||||
? Theme.of(context).colorScheme.primary
|
||||
: null,
|
||||
),
|
||||
),
|
||||
subtitle: Text(
|
||||
'${segment.from != null ? Utils.timeFormat(segment.from) : ''} - ${segment.to != null ? Utils.timeFormat(segment.to) : ''}',
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: currentIndex == index
|
||||
? Theme.of(context).colorScheme.primary
|
||||
: Theme.of(context).colorScheme.outline,
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
SizedBox(height: 25 + MediaQuery.paddingOf(context).bottom),
|
||||
],
|
||||
),
|
||||
iconButton(
|
||||
context: context,
|
||||
size: 30,
|
||||
icon: Icons.clear,
|
||||
tooltip: '关闭',
|
||||
onPressed: Get.back,
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
],
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
...List.generate(
|
||||
videoDetailController.viewPointList.length * 2 - 1,
|
||||
(rawIndex) {
|
||||
if (rawIndex % 2 == 1) {
|
||||
return Divider(
|
||||
height: 1,
|
||||
color: Theme.of(context).dividerColor.withOpacity(0.1),
|
||||
);
|
||||
}
|
||||
int index = rawIndex ~/ 2;
|
||||
Segment segment = videoDetailController.viewPointList[index];
|
||||
if (currentIndex == -1 &&
|
||||
segment.from != null &&
|
||||
segment.to != null) {
|
||||
if (videoDetailController
|
||||
.plPlayerController.positionSeconds.value >=
|
||||
segment.from! &&
|
||||
videoDetailController
|
||||
.plPlayerController.positionSeconds.value <
|
||||
segment.to!) {
|
||||
currentIndex = index;
|
||||
}
|
||||
}
|
||||
return ListTile(
|
||||
dense: true,
|
||||
onTap: segment.from != null
|
||||
? () {
|
||||
currentIndex = index;
|
||||
plPlayerController?.danmakuController?.clear();
|
||||
plPlayerController?.videoPlayerController
|
||||
?.seek(Duration(seconds: segment.from!));
|
||||
Get.back();
|
||||
}
|
||||
: null,
|
||||
leading: segment.url?.isNotEmpty == true
|
||||
? Container(
|
||||
margin: const EdgeInsets.symmetric(vertical: 6),
|
||||
decoration: currentIndex == index
|
||||
? BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
border: Border.all(
|
||||
width: 1.8,
|
||||
strokeAlign:
|
||||
BorderSide.strokeAlignOutside,
|
||||
color:
|
||||
Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
)
|
||||
: null,
|
||||
child: LayoutBuilder(
|
||||
builder: (context, constraints) =>
|
||||
NetworkImgLayer(
|
||||
radius: 6,
|
||||
src: segment.url,
|
||||
width: constraints.maxHeight *
|
||||
StyleString.aspectRatio,
|
||||
height: constraints.maxHeight,
|
||||
),
|
||||
),
|
||||
)
|
||||
: null,
|
||||
title: Text(
|
||||
segment.title ?? '',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight:
|
||||
currentIndex == index ? FontWeight.bold : null,
|
||||
color: currentIndex == index
|
||||
? Theme.of(context).colorScheme.primary
|
||||
: null,
|
||||
),
|
||||
),
|
||||
subtitle: Text(
|
||||
'${segment.from != null ? Utils.timeFormat(segment.from) : ''} - ${segment.to != null ? Utils.timeFormat(segment.to) : ''}',
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: currentIndex == index
|
||||
? Theme.of(context).colorScheme.primary
|
||||
: Theme.of(context).colorScheme.outline,
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
SizedBox(height: 25 + MediaQuery.paddingOf(context).bottom),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -2061,23 +2032,15 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
||||
}
|
||||
|
||||
if (isFullScreen) {
|
||||
videoDetailController.bsController =
|
||||
videoDetailController.scaffoldKey.currentState?.showBottomSheet(
|
||||
(context) => listSheetContent(context, true),
|
||||
);
|
||||
Utils.showFSSheet(child: listSheetContent(), isFullScreen: isFullScreen);
|
||||
} else {
|
||||
videoDetailController.childKey.currentState?.showBottomSheet(
|
||||
(context) => listSheetContent(context),
|
||||
(context) => listSheetContent(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void _onPopInvokedWithResult(didPop, result) {
|
||||
if (videoDetailController.bsController != null) {
|
||||
videoDetailController.bsController!.close();
|
||||
videoDetailController.bsController = null;
|
||||
return;
|
||||
}
|
||||
if (plPlayerController?.controlsLock.value == true) {
|
||||
plPlayerController?.onLockControl(false);
|
||||
return;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user