Merge branch 'main' into design
This commit is contained in:
2
.github/workflows/beta_ci.yml
vendored
2
.github/workflows/beta_ci.yml
vendored
@ -206,4 +206,4 @@ jobs:
|
|||||||
method: sendFile
|
method: sendFile
|
||||||
path: Pilipala-Beta/*
|
path: Pilipala-Beta/*
|
||||||
parse_mode: Markdown
|
parse_mode: Markdown
|
||||||
context: "*Beta版本: v${{ needs.update_version.outputs.new_version }}*\n更新内容: [${{ needs.update_version.outputs.last_commit }}](${{ github.event.head_commit.url }})"
|
context: "*Beta版本: v${{ needs.update_version.outputs.new_version }}*\n更新内容: [${{ needs.update_version.outputs.last_commit }}]"
|
||||||
|
|||||||
@ -130,27 +130,10 @@ class MyApp extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final SnackBarThemeData snackBarThemeData = SnackBarThemeData(
|
|
||||||
actionTextColor: darkColorScheme.primary,
|
|
||||||
backgroundColor: darkColorScheme.secondaryContainer,
|
|
||||||
closeIconColor: darkColorScheme.secondary,
|
|
||||||
contentTextStyle: TextStyle(color: darkColorScheme.secondary),
|
|
||||||
elevation: 20,
|
|
||||||
);
|
|
||||||
|
|
||||||
ThemeData themeData = ThemeData(
|
ThemeData themeData = ThemeData(
|
||||||
// fontFamily: 'HarmonyOS',
|
|
||||||
colorScheme: currentThemeValue == ThemeType.dark
|
colorScheme: currentThemeValue == ThemeType.dark
|
||||||
? darkColorScheme
|
? darkColorScheme
|
||||||
: lightColorScheme,
|
: lightColorScheme,
|
||||||
snackBarTheme: snackBarThemeData,
|
|
||||||
pageTransitionsTheme: const PageTransitionsTheme(
|
|
||||||
builders: <TargetPlatform, PageTransitionsBuilder>{
|
|
||||||
TargetPlatform.android: ZoomPageTransitionsBuilder(
|
|
||||||
allowEnterRouteSnapshotting: false,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// 小白条、导航栏沉浸
|
// 小白条、导航栏沉浸
|
||||||
@ -171,9 +154,38 @@ class MyApp extends StatelessWidget {
|
|||||||
// 图片缓存
|
// 图片缓存
|
||||||
// PaintingBinding.instance.imageCache.maximumSizeBytes = 1000 << 20;
|
// PaintingBinding.instance.imageCache.maximumSizeBytes = 1000 << 20;
|
||||||
return GetMaterialApp(
|
return GetMaterialApp(
|
||||||
title: 'PiLiPaLa',
|
title: 'PiliPala',
|
||||||
theme: themeData,
|
theme: ThemeData(
|
||||||
darkTheme: themeData,
|
colorScheme: currentThemeValue == ThemeType.dark
|
||||||
|
? darkColorScheme
|
||||||
|
: lightColorScheme,
|
||||||
|
snackBarTheme: SnackBarThemeData(
|
||||||
|
actionTextColor: lightColorScheme.primary,
|
||||||
|
backgroundColor: lightColorScheme.secondaryContainer,
|
||||||
|
closeIconColor: lightColorScheme.secondary,
|
||||||
|
contentTextStyle: TextStyle(color: lightColorScheme.secondary),
|
||||||
|
elevation: 20,
|
||||||
|
),
|
||||||
|
pageTransitionsTheme: const PageTransitionsTheme(
|
||||||
|
builders: <TargetPlatform, PageTransitionsBuilder>{
|
||||||
|
TargetPlatform.android: ZoomPageTransitionsBuilder(
|
||||||
|
allowEnterRouteSnapshotting: false,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
darkTheme: ThemeData(
|
||||||
|
colorScheme: currentThemeValue == ThemeType.light
|
||||||
|
? lightColorScheme
|
||||||
|
: darkColorScheme,
|
||||||
|
snackBarTheme: SnackBarThemeData(
|
||||||
|
actionTextColor: darkColorScheme.primary,
|
||||||
|
backgroundColor: darkColorScheme.secondaryContainer,
|
||||||
|
closeIconColor: darkColorScheme.secondary,
|
||||||
|
contentTextStyle: TextStyle(color: darkColorScheme.secondary),
|
||||||
|
elevation: 20,
|
||||||
|
),
|
||||||
|
),
|
||||||
localizationsDelegates: const [
|
localizationsDelegates: const [
|
||||||
GlobalCupertinoLocalizations.delegate,
|
GlobalCupertinoLocalizations.delegate,
|
||||||
GlobalMaterialLocalizations.delegate,
|
GlobalMaterialLocalizations.delegate,
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
|
||||||
import 'package:pilipala/pages/rank/zone/index.dart';
|
import 'package:pilipala/pages/rank/zone/index.dart';
|
||||||
|
|
||||||
enum RandType {
|
enum RandType {
|
||||||
@ -74,7 +73,6 @@ List tabsConfig = [
|
|||||||
),
|
),
|
||||||
'label': '全站',
|
'label': '全站',
|
||||||
'type': RandType.all,
|
'type': RandType.all,
|
||||||
'ctr': Get.put<ZoneController>,
|
|
||||||
'page': const ZonePage(rid: 0),
|
'page': const ZonePage(rid: 0),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -84,7 +82,6 @@ List tabsConfig = [
|
|||||||
),
|
),
|
||||||
'label': '国创相关',
|
'label': '国创相关',
|
||||||
'type': RandType.creation,
|
'type': RandType.creation,
|
||||||
'ctr': Get.put<ZoneController>,
|
|
||||||
'page': const ZonePage(rid: 168),
|
'page': const ZonePage(rid: 168),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -94,7 +91,6 @@ List tabsConfig = [
|
|||||||
),
|
),
|
||||||
'label': '动画',
|
'label': '动画',
|
||||||
'type': RandType.animation,
|
'type': RandType.animation,
|
||||||
'ctr': Get.put<ZoneController>,
|
|
||||||
'page': const ZonePage(rid: 1),
|
'page': const ZonePage(rid: 1),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -104,7 +100,6 @@ List tabsConfig = [
|
|||||||
),
|
),
|
||||||
'label': '音乐',
|
'label': '音乐',
|
||||||
'type': RandType.music,
|
'type': RandType.music,
|
||||||
'ctr': Get.put<ZoneController>,
|
|
||||||
'page': const ZonePage(rid: 3),
|
'page': const ZonePage(rid: 3),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -114,7 +109,6 @@ List tabsConfig = [
|
|||||||
),
|
),
|
||||||
'label': '舞蹈',
|
'label': '舞蹈',
|
||||||
'type': RandType.dance,
|
'type': RandType.dance,
|
||||||
'ctr': Get.put<ZoneController>,
|
|
||||||
'page': const ZonePage(rid: 129),
|
'page': const ZonePage(rid: 129),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -124,7 +118,6 @@ List tabsConfig = [
|
|||||||
),
|
),
|
||||||
'label': '游戏',
|
'label': '游戏',
|
||||||
'type': RandType.game,
|
'type': RandType.game,
|
||||||
'ctr': Get.put<ZoneController>,
|
|
||||||
'page': const ZonePage(rid: 4),
|
'page': const ZonePage(rid: 4),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -134,7 +127,6 @@ List tabsConfig = [
|
|||||||
),
|
),
|
||||||
'label': '知识',
|
'label': '知识',
|
||||||
'type': RandType.knowledge,
|
'type': RandType.knowledge,
|
||||||
'ctr': Get.put<ZoneController>,
|
|
||||||
'page': const ZonePage(rid: 36),
|
'page': const ZonePage(rid: 36),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -144,7 +136,6 @@ List tabsConfig = [
|
|||||||
),
|
),
|
||||||
'label': '科技',
|
'label': '科技',
|
||||||
'type': RandType.technology,
|
'type': RandType.technology,
|
||||||
'ctr': Get.put<ZoneController>,
|
|
||||||
'page': const ZonePage(rid: 188),
|
'page': const ZonePage(rid: 188),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -154,7 +145,6 @@ List tabsConfig = [
|
|||||||
),
|
),
|
||||||
'label': '运动',
|
'label': '运动',
|
||||||
'type': RandType.sport,
|
'type': RandType.sport,
|
||||||
'ctr': Get.put<ZoneController>,
|
|
||||||
'page': const ZonePage(rid: 234),
|
'page': const ZonePage(rid: 234),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -164,7 +154,6 @@ List tabsConfig = [
|
|||||||
),
|
),
|
||||||
'label': '汽车',
|
'label': '汽车',
|
||||||
'type': RandType.car,
|
'type': RandType.car,
|
||||||
'ctr': Get.put<ZoneController>,
|
|
||||||
'page': const ZonePage(rid: 223),
|
'page': const ZonePage(rid: 223),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -174,7 +163,6 @@ List tabsConfig = [
|
|||||||
),
|
),
|
||||||
'label': '生活',
|
'label': '生活',
|
||||||
'type': RandType.life,
|
'type': RandType.life,
|
||||||
'ctr': Get.put<ZoneController>,
|
|
||||||
'page': const ZonePage(rid: 160),
|
'page': const ZonePage(rid: 160),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -184,7 +172,6 @@ List tabsConfig = [
|
|||||||
),
|
),
|
||||||
'label': '美食',
|
'label': '美食',
|
||||||
'type': RandType.food,
|
'type': RandType.food,
|
||||||
'ctr': Get.put<ZoneController>,
|
|
||||||
'page': const ZonePage(rid: 211),
|
'page': const ZonePage(rid: 211),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -194,7 +181,6 @@ List tabsConfig = [
|
|||||||
),
|
),
|
||||||
'label': '动物圈',
|
'label': '动物圈',
|
||||||
'type': RandType.animal,
|
'type': RandType.animal,
|
||||||
'ctr': Get.put<ZoneController>,
|
|
||||||
'page': const ZonePage(rid: 217),
|
'page': const ZonePage(rid: 217),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -204,7 +190,6 @@ List tabsConfig = [
|
|||||||
),
|
),
|
||||||
'label': '鬼畜',
|
'label': '鬼畜',
|
||||||
'type': RandType.madness,
|
'type': RandType.madness,
|
||||||
'ctr': Get.put<ZoneController>,
|
|
||||||
'page': const ZonePage(rid: 119),
|
'page': const ZonePage(rid: 119),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -214,7 +199,6 @@ List tabsConfig = [
|
|||||||
),
|
),
|
||||||
'label': '时尚',
|
'label': '时尚',
|
||||||
'type': RandType.fashion,
|
'type': RandType.fashion,
|
||||||
'ctr': Get.put<ZoneController>,
|
|
||||||
'page': const ZonePage(rid: 155),
|
'page': const ZonePage(rid: 155),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -224,7 +208,6 @@ List tabsConfig = [
|
|||||||
),
|
),
|
||||||
'label': '娱乐',
|
'label': '娱乐',
|
||||||
'type': RandType.entertainment,
|
'type': RandType.entertainment,
|
||||||
'ctr': Get.put<ZoneController>,
|
|
||||||
'page': const ZonePage(rid: 5),
|
'page': const ZonePage(rid: 5),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -234,7 +217,6 @@ List tabsConfig = [
|
|||||||
),
|
),
|
||||||
'label': '影视',
|
'label': '影视',
|
||||||
'type': RandType.film,
|
'type': RandType.film,
|
||||||
'ctr': Get.put<ZoneController>,
|
|
||||||
'page': const ZonePage(rid: 181),
|
'page': const ZonePage(rid: 181),
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|||||||
@ -5,6 +5,10 @@ enum SubtitleType {
|
|||||||
aizh,
|
aizh,
|
||||||
// 英语(自动生成)
|
// 英语(自动生成)
|
||||||
aien,
|
aien,
|
||||||
|
// 中文(简体)
|
||||||
|
zhHans,
|
||||||
|
// 英文(美国)
|
||||||
|
enUS,
|
||||||
}
|
}
|
||||||
|
|
||||||
extension SubtitleTypeExtension on SubtitleType {
|
extension SubtitleTypeExtension on SubtitleType {
|
||||||
@ -16,6 +20,10 @@ extension SubtitleTypeExtension on SubtitleType {
|
|||||||
return '中文(自动翻译)';
|
return '中文(自动翻译)';
|
||||||
case SubtitleType.aien:
|
case SubtitleType.aien:
|
||||||
return '英语(自动生成)';
|
return '英语(自动生成)';
|
||||||
|
case SubtitleType.zhHans:
|
||||||
|
return '中文(简体)';
|
||||||
|
case SubtitleType.enUS:
|
||||||
|
return '英文(美国)';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -29,6 +37,10 @@ extension SubtitleIdExtension on SubtitleType {
|
|||||||
return 'ai-zh';
|
return 'ai-zh';
|
||||||
case SubtitleType.aien:
|
case SubtitleType.aien:
|
||||||
return 'ai-en';
|
return 'ai-en';
|
||||||
|
case SubtitleType.zhHans:
|
||||||
|
return 'zh-Hans';
|
||||||
|
case SubtitleType.enUS:
|
||||||
|
return 'en-US';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -42,6 +54,10 @@ extension SubtitleCodeExtension on SubtitleType {
|
|||||||
return 2;
|
return 2;
|
||||||
case SubtitleType.aien:
|
case SubtitleType.aien:
|
||||||
return 3;
|
return 3;
|
||||||
|
case SubtitleType.zhHans:
|
||||||
|
return 4;
|
||||||
|
case SubtitleType.enUS:
|
||||||
|
return 5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -56,6 +56,7 @@ class BangumiIntroController extends GetxController {
|
|||||||
RxMap followStatus = {}.obs;
|
RxMap followStatus = {}.obs;
|
||||||
int _tempThemeValue = -1;
|
int _tempThemeValue = -1;
|
||||||
var userInfo;
|
var userInfo;
|
||||||
|
PersistentBottomSheetController? bottomSheetController;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onInit() {
|
void onInit() {
|
||||||
@ -320,4 +321,8 @@ class BangumiIntroController extends GetxController {
|
|||||||
).buildShowContent(Get.context!),
|
).buildShowContent(Get.context!),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hiddenEpisodeBottomSheet() {
|
||||||
|
bottomSheetController?.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -325,6 +325,7 @@ class _BangumiInfoState extends State<BangumiInfo> {
|
|||||||
changeFuc: (bvid, cid, aid) =>
|
changeFuc: (bvid, cid, aid) =>
|
||||||
bangumiIntroController.changeSeasonOrbangu(bvid, cid, aid),
|
bangumiIntroController.changeSeasonOrbangu(bvid, cid, aid),
|
||||||
bangumiDetail: bangumiIntroController.bangumiDetail.value,
|
bangumiDetail: bangumiIntroController.bangumiDetail.value,
|
||||||
|
bangumiIntroController: bangumiIntroController,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import 'package:pilipala/utils/storage.dart';
|
|||||||
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
|
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
|
||||||
import '../../../common/pages_bottom_sheet.dart';
|
import '../../../common/pages_bottom_sheet.dart';
|
||||||
import '../../../models/common/video_episode_type.dart';
|
import '../../../models/common/video_episode_type.dart';
|
||||||
|
import '../introduction/controller.dart';
|
||||||
|
|
||||||
class BangumiPanel extends StatefulWidget {
|
class BangumiPanel extends StatefulWidget {
|
||||||
const BangumiPanel({
|
const BangumiPanel({
|
||||||
@ -19,6 +20,7 @@ class BangumiPanel extends StatefulWidget {
|
|||||||
this.sheetHeight,
|
this.sheetHeight,
|
||||||
this.changeFuc,
|
this.changeFuc,
|
||||||
this.bangumiDetail,
|
this.bangumiDetail,
|
||||||
|
this.bangumiIntroController,
|
||||||
});
|
});
|
||||||
|
|
||||||
final List<EpisodeItem> pages;
|
final List<EpisodeItem> pages;
|
||||||
@ -26,6 +28,7 @@ class BangumiPanel extends StatefulWidget {
|
|||||||
final double? sheetHeight;
|
final double? sheetHeight;
|
||||||
final Function? changeFuc;
|
final Function? changeFuc;
|
||||||
final BangumiInfoModel? bangumiDetail;
|
final BangumiInfoModel? bangumiDetail;
|
||||||
|
final BangumiIntroController? bangumiIntroController;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<BangumiPanel> createState() => _BangumiPanelState();
|
State<BangumiPanel> createState() => _BangumiPanelState();
|
||||||
@ -136,7 +139,8 @@ class _BangumiPanelState extends State<BangumiPanel> {
|
|||||||
padding: MaterialStateProperty.all(EdgeInsets.zero),
|
padding: MaterialStateProperty.all(EdgeInsets.zero),
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
_bottomSheetController = EpisodeBottomSheet(
|
widget.bangumiIntroController?.bottomSheetController =
|
||||||
|
_bottomSheetController = EpisodeBottomSheet(
|
||||||
currentCid: cid,
|
currentCid: cid,
|
||||||
episodes: widget.pages,
|
episodes: widget.pages,
|
||||||
changeFucCall: changeFucCall,
|
changeFucCall: changeFucCall,
|
||||||
|
|||||||
@ -16,6 +16,7 @@ import 'package:pilipala/pages/video/detail/reply_reply/index.dart';
|
|||||||
import 'package:pilipala/utils/feed_back.dart';
|
import 'package:pilipala/utils/feed_back.dart';
|
||||||
import 'package:pilipala/utils/id_utils.dart';
|
import 'package:pilipala/utils/id_utils.dart';
|
||||||
|
|
||||||
|
import '../../../models/video/reply/item.dart';
|
||||||
import '../widgets/dynamic_panel.dart';
|
import '../widgets/dynamic_panel.dart';
|
||||||
|
|
||||||
class DynamicDetailPage extends StatefulWidget {
|
class DynamicDetailPage extends StatefulWidget {
|
||||||
@ -210,208 +211,194 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
|
|||||||
onRefresh: () async {
|
onRefresh: () async {
|
||||||
await _dynamicDetailController.queryReplyList();
|
await _dynamicDetailController.queryReplyList();
|
||||||
},
|
},
|
||||||
child: Stack(
|
child: CustomScrollView(
|
||||||
children: [
|
controller: scrollController,
|
||||||
CustomScrollView(
|
slivers: [
|
||||||
controller: scrollController,
|
if (action != 'comment')
|
||||||
slivers: [
|
SliverToBoxAdapter(
|
||||||
if (action != 'comment')
|
child: DynamicPanel(
|
||||||
SliverToBoxAdapter(
|
item: _dynamicDetailController.item,
|
||||||
child: DynamicPanel(
|
source: 'detail',
|
||||||
item: _dynamicDetailController.item,
|
),
|
||||||
source: 'detail',
|
),
|
||||||
|
SliverPersistentHeader(
|
||||||
|
delegate: _MySliverPersistentHeaderDelegate(
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Theme.of(context).colorScheme.surface,
|
||||||
|
border: Border(
|
||||||
|
top: BorderSide(
|
||||||
|
width: 0.6,
|
||||||
|
color: Theme.of(context).dividerColor.withOpacity(0.05),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SliverPersistentHeader(
|
height: 45,
|
||||||
delegate: _MySliverPersistentHeaderDelegate(
|
padding: const EdgeInsets.only(left: 12, right: 6),
|
||||||
child: Container(
|
child: Row(
|
||||||
decoration: BoxDecoration(
|
children: [
|
||||||
color: Theme.of(context).colorScheme.surface,
|
Obx(
|
||||||
border: Border(
|
() => AnimatedSwitcher(
|
||||||
top: BorderSide(
|
duration: const Duration(milliseconds: 400),
|
||||||
width: 0.6,
|
transitionBuilder:
|
||||||
color: Theme.of(context)
|
(Widget child, Animation<double> animation) {
|
||||||
.dividerColor
|
return ScaleTransition(
|
||||||
.withOpacity(0.05),
|
scale: animation, child: child);
|
||||||
|
},
|
||||||
|
child: Text(
|
||||||
|
'${_dynamicDetailController.acount.value}',
|
||||||
|
key: ValueKey<int>(
|
||||||
|
_dynamicDetailController.acount.value),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
height: 45,
|
const Text('条回复'),
|
||||||
padding: const EdgeInsets.only(left: 12, right: 6),
|
const Spacer(),
|
||||||
child: Row(
|
SizedBox(
|
||||||
children: [
|
height: 35,
|
||||||
Obx(
|
child: TextButton.icon(
|
||||||
() => AnimatedSwitcher(
|
onPressed: () =>
|
||||||
duration: const Duration(milliseconds: 400),
|
_dynamicDetailController.queryBySort(),
|
||||||
transitionBuilder:
|
icon: const Icon(Icons.sort, size: 16),
|
||||||
(Widget child, Animation<double> animation) {
|
label: Obx(() => Text(
|
||||||
return ScaleTransition(
|
_dynamicDetailController.sortTypeLabel.value,
|
||||||
scale: animation, child: child);
|
style: const TextStyle(fontSize: 13),
|
||||||
},
|
)),
|
||||||
child: Text(
|
),
|
||||||
'${_dynamicDetailController.acount.value}',
|
)
|
||||||
key: ValueKey<int>(
|
],
|
||||||
_dynamicDetailController.acount.value),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const Text('条回复'),
|
|
||||||
const Spacer(),
|
|
||||||
SizedBox(
|
|
||||||
height: 35,
|
|
||||||
child: TextButton.icon(
|
|
||||||
onPressed: () =>
|
|
||||||
_dynamicDetailController.queryBySort(),
|
|
||||||
icon: const Icon(Icons.sort, size: 16),
|
|
||||||
label: Obx(() => Text(
|
|
||||||
_dynamicDetailController
|
|
||||||
.sortTypeLabel.value,
|
|
||||||
style: const TextStyle(fontSize: 13),
|
|
||||||
)),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
pinned: true,
|
|
||||||
),
|
|
||||||
FutureBuilder(
|
|
||||||
future: _futureBuilderFuture,
|
|
||||||
builder: (context, snapshot) {
|
|
||||||
if (snapshot.connectionState == ConnectionState.done) {
|
|
||||||
Map data = snapshot.data as Map;
|
|
||||||
if (snapshot.data['status']) {
|
|
||||||
// 请求成功
|
|
||||||
return Obx(
|
|
||||||
() => _dynamicDetailController.replyList.isEmpty &&
|
|
||||||
_dynamicDetailController.isLoadingMore
|
|
||||||
? SliverList(
|
|
||||||
delegate: SliverChildBuilderDelegate(
|
|
||||||
(context, index) {
|
|
||||||
return const VideoReplySkeleton();
|
|
||||||
}, childCount: 8),
|
|
||||||
)
|
|
||||||
: SliverList(
|
|
||||||
delegate: SliverChildBuilderDelegate(
|
|
||||||
(context, index) {
|
|
||||||
if (index ==
|
|
||||||
_dynamicDetailController
|
|
||||||
.replyList.length) {
|
|
||||||
return Container(
|
|
||||||
padding: EdgeInsets.only(
|
|
||||||
bottom: MediaQuery.of(context)
|
|
||||||
.padding
|
|
||||||
.bottom),
|
|
||||||
height: MediaQuery.of(context)
|
|
||||||
.padding
|
|
||||||
.bottom +
|
|
||||||
100,
|
|
||||||
child: Center(
|
|
||||||
child: Obx(
|
|
||||||
() => Text(
|
|
||||||
_dynamicDetailController
|
|
||||||
.noMore.value,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 12,
|
|
||||||
color: Theme.of(context)
|
|
||||||
.colorScheme
|
|
||||||
.outline,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return ReplyItem(
|
|
||||||
replyItem: _dynamicDetailController
|
|
||||||
.replyList[index],
|
|
||||||
showReplyRow: true,
|
|
||||||
replyLevel: '1',
|
|
||||||
replyReply: (replyItem) =>
|
|
||||||
replyReply(replyItem),
|
|
||||||
replyType:
|
|
||||||
ReplyType.values[replyType],
|
|
||||||
addReply: (replyItem) {
|
|
||||||
_dynamicDetailController
|
|
||||||
.replyList[index].replies!
|
|
||||||
.add(replyItem);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
childCount: _dynamicDetailController
|
|
||||||
.replyList.length +
|
|
||||||
1,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// 请求错误
|
|
||||||
return HttpError(
|
|
||||||
errMsg: data['msg'],
|
|
||||||
fn: () => setState(() {}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 骨架屏
|
|
||||||
return SliverList(
|
|
||||||
delegate: SliverChildBuilderDelegate((context, index) {
|
|
||||||
return const VideoReplySkeleton();
|
|
||||||
}, childCount: 8),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Positioned(
|
|
||||||
bottom: MediaQuery.of(context).padding.bottom + 14,
|
|
||||||
right: 14,
|
|
||||||
child: SlideTransition(
|
|
||||||
position: Tween<Offset>(
|
|
||||||
begin: const Offset(0, 2),
|
|
||||||
end: const Offset(0, 0),
|
|
||||||
).animate(CurvedAnimation(
|
|
||||||
parent: fabAnimationCtr,
|
|
||||||
curve: Curves.easeInOut,
|
|
||||||
)),
|
|
||||||
child: FloatingActionButton(
|
|
||||||
heroTag: null,
|
|
||||||
onPressed: () {
|
|
||||||
feedBack();
|
|
||||||
showModalBottomSheet(
|
|
||||||
context: context,
|
|
||||||
isScrollControlled: true,
|
|
||||||
builder: (BuildContext context) {
|
|
||||||
return VideoReplyNewDialog(
|
|
||||||
oid: _dynamicDetailController.oid ??
|
|
||||||
IdUtils.bv2av(Get.parameters['bvid']!),
|
|
||||||
root: 0,
|
|
||||||
parent: 0,
|
|
||||||
replyType: ReplyType.values[replyType],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
).then(
|
|
||||||
(value) => {
|
|
||||||
// 完成评论,数据添加
|
|
||||||
if (value != null && value['data'] != null)
|
|
||||||
{
|
|
||||||
_dynamicDetailController.replyList
|
|
||||||
.add(value['data']),
|
|
||||||
_dynamicDetailController.acount.value++
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
tooltip: '评论动态',
|
|
||||||
child: const Icon(Icons.reply),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
pinned: true,
|
||||||
),
|
),
|
||||||
|
FutureBuilder(
|
||||||
|
future: _futureBuilderFuture,
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
if (snapshot.connectionState == ConnectionState.done) {
|
||||||
|
Map data = snapshot.data as Map;
|
||||||
|
if (snapshot.data['status']) {
|
||||||
|
RxList<ReplyItemModel> replyList =
|
||||||
|
_dynamicDetailController.replyList;
|
||||||
|
// 请求成功
|
||||||
|
return Obx(
|
||||||
|
() => replyList.isEmpty &&
|
||||||
|
_dynamicDetailController.isLoadingMore
|
||||||
|
? SliverList(
|
||||||
|
delegate:
|
||||||
|
SliverChildBuilderDelegate((context, index) {
|
||||||
|
return const VideoReplySkeleton();
|
||||||
|
}, childCount: 8),
|
||||||
|
)
|
||||||
|
: SliverList(
|
||||||
|
delegate: SliverChildBuilderDelegate(
|
||||||
|
(context, index) {
|
||||||
|
if (index == replyList.length) {
|
||||||
|
return Container(
|
||||||
|
padding: EdgeInsets.only(
|
||||||
|
bottom: MediaQuery.of(context)
|
||||||
|
.padding
|
||||||
|
.bottom),
|
||||||
|
height: MediaQuery.of(context)
|
||||||
|
.padding
|
||||||
|
.bottom +
|
||||||
|
100,
|
||||||
|
child: Center(
|
||||||
|
child: Obx(
|
||||||
|
() => Text(
|
||||||
|
_dynamicDetailController
|
||||||
|
.noMore.value,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
color: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.outline,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return ReplyItem(
|
||||||
|
replyItem: replyList[index],
|
||||||
|
showReplyRow: true,
|
||||||
|
replyLevel: '1',
|
||||||
|
replyReply: (replyItem) =>
|
||||||
|
replyReply(replyItem),
|
||||||
|
replyType: ReplyType.values[replyType],
|
||||||
|
addReply: (replyItem) {
|
||||||
|
replyList[index]
|
||||||
|
.replies!
|
||||||
|
.add(replyItem);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
childCount: replyList.length + 1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// 请求错误
|
||||||
|
return HttpError(
|
||||||
|
errMsg: data['msg'],
|
||||||
|
fn: () => setState(() {}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 骨架屏
|
||||||
|
return SliverList(
|
||||||
|
delegate: SliverChildBuilderDelegate((context, index) {
|
||||||
|
return const VideoReplySkeleton();
|
||||||
|
}, childCount: 8),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
floatingActionButton: SlideTransition(
|
||||||
|
position: Tween<Offset>(
|
||||||
|
begin: const Offset(0, 2),
|
||||||
|
end: const Offset(0, 0),
|
||||||
|
).animate(
|
||||||
|
CurvedAnimation(
|
||||||
|
parent: fabAnimationCtr,
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: FloatingActionButton(
|
||||||
|
heroTag: null,
|
||||||
|
onPressed: () {
|
||||||
|
feedBack();
|
||||||
|
showModalBottomSheet(
|
||||||
|
context: context,
|
||||||
|
isScrollControlled: true,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return VideoReplyNewDialog(
|
||||||
|
oid: _dynamicDetailController.oid ??
|
||||||
|
IdUtils.bv2av(Get.parameters['bvid']!),
|
||||||
|
root: 0,
|
||||||
|
parent: 0,
|
||||||
|
replyType: ReplyType.values[replyType],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
).then(
|
||||||
|
(value) => {
|
||||||
|
// 完成评论,数据添加
|
||||||
|
if (value != null && value['data'] != null)
|
||||||
|
{
|
||||||
|
_dynamicDetailController.replyList.add(value['data']),
|
||||||
|
_dynamicDetailController.acount.value++
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
tooltip: '评论动态',
|
||||||
|
child: const Icon(Icons.reply),
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:pilipala/models/common/rank_type.dart';
|
import 'package:pilipala/models/common/rank_type.dart';
|
||||||
|
import 'package:pilipala/pages/rank/zone/index.dart';
|
||||||
import 'package:pilipala/utils/storage.dart';
|
import 'package:pilipala/utils/storage.dart';
|
||||||
|
|
||||||
class RankController extends GetxController with GetTickerProviderStateMixin {
|
class RankController extends GetxController with GetTickerProviderStateMixin {
|
||||||
@ -29,20 +30,22 @@ class RankController extends GetxController with GetTickerProviderStateMixin {
|
|||||||
|
|
||||||
void onRefresh() {
|
void onRefresh() {
|
||||||
int index = tabController.index;
|
int index = tabController.index;
|
||||||
var ctr = tabsCtrList[index];
|
final ZoneController ctr = tabsCtrList[index];
|
||||||
ctr().onRefresh();
|
ctr.onRefresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
void animateToTop() {
|
void animateToTop() {
|
||||||
int index = tabController.index;
|
int index = tabController.index;
|
||||||
var ctr = tabsCtrList[index];
|
final ZoneController ctr = tabsCtrList[index];
|
||||||
ctr().animateToTop();
|
ctr.animateToTop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setTabConfig() async {
|
void setTabConfig() async {
|
||||||
tabs.value = tabsConfig;
|
tabs.value = tabsConfig;
|
||||||
initialIndex.value = 0;
|
initialIndex.value = 0;
|
||||||
tabsCtrList = tabs.map((e) => e['ctr']).toList();
|
tabsCtrList = tabs
|
||||||
|
.map((e) => Get.put(ZoneController(), tag: e['rid'].toString()))
|
||||||
|
.toList();
|
||||||
tabsPageList = tabs.map<Widget>((e) => e['page']).toList();
|
tabsPageList = tabs.map<Widget>((e) => e['page']).toList();
|
||||||
|
|
||||||
tabController = TabController(
|
tabController = TabController(
|
||||||
|
|||||||
@ -102,7 +102,7 @@ class _RankPageState extends State<RankPage>
|
|||||||
onTap: (value) {
|
onTap: (value) {
|
||||||
feedBack();
|
feedBack();
|
||||||
if (_rankController.initialIndex.value == value) {
|
if (_rankController.initialIndex.value == value) {
|
||||||
_rankController.tabsCtrList[value]().animateToTop();
|
_rankController.tabsCtrList[value].animateToTop();
|
||||||
}
|
}
|
||||||
_rankController.initialIndex.value = value;
|
_rankController.initialIndex.value = value;
|
||||||
},
|
},
|
||||||
|
|||||||
@ -42,12 +42,15 @@ class ZoneController extends GetxController {
|
|||||||
|
|
||||||
// 返回顶部并刷新
|
// 返回顶部并刷新
|
||||||
void animateToTop() async {
|
void animateToTop() async {
|
||||||
if (scrollController.offset >=
|
if (scrollController.hasClients) {
|
||||||
MediaQuery.of(Get.context!).size.height * 5) {
|
if (scrollController.offset >=
|
||||||
scrollController.jumpTo(0);
|
MediaQuery.of(Get.context!).size.height * 5) {
|
||||||
} else {
|
scrollController.jumpTo(0);
|
||||||
await scrollController.animateTo(0,
|
} else {
|
||||||
duration: const Duration(milliseconds: 500), curve: Curves.easeInOut);
|
await scrollController.animateTo(0,
|
||||||
|
duration: const Duration(milliseconds: 500),
|
||||||
|
curve: Curves.easeInOut);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -58,6 +58,7 @@ class VideoIntroController extends GetxController {
|
|||||||
String heroTag = '';
|
String heroTag = '';
|
||||||
late ModelResult modelResult;
|
late ModelResult modelResult;
|
||||||
PersistentBottomSheetController? bottomSheetController;
|
PersistentBottomSheetController? bottomSheetController;
|
||||||
|
late bool enableRelatedVideo;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onInit() {
|
void onInit() {
|
||||||
@ -74,6 +75,8 @@ class VideoIntroController extends GetxController {
|
|||||||
queryOnlineTotal();
|
queryOnlineTotal();
|
||||||
startTimer(); // 在页面加载时启动定时器
|
startTimer(); // 在页面加载时启动定时器
|
||||||
}
|
}
|
||||||
|
enableRelatedVideo =
|
||||||
|
setting.get(SettingBoxKey.enableRelatedVideo, defaultValue: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取视频简介&分p
|
// 获取视频简介&分p
|
||||||
@ -447,15 +450,18 @@ class VideoIntroController extends GetxController {
|
|||||||
// 重新获取视频资源
|
// 重新获取视频资源
|
||||||
final VideoDetailController videoDetailCtr =
|
final VideoDetailController videoDetailCtr =
|
||||||
Get.find<VideoDetailController>(tag: heroTag);
|
Get.find<VideoDetailController>(tag: heroTag);
|
||||||
final ReleatedController releatedCtr =
|
if (enableRelatedVideo) {
|
||||||
Get.find<ReleatedController>(tag: heroTag);
|
final ReleatedController releatedCtr =
|
||||||
|
Get.find<ReleatedController>(tag: heroTag);
|
||||||
|
releatedCtr.bvid = bvid;
|
||||||
|
releatedCtr.queryRelatedVideo();
|
||||||
|
}
|
||||||
|
|
||||||
videoDetailCtr.bvid = bvid;
|
videoDetailCtr.bvid = bvid;
|
||||||
videoDetailCtr.oid.value = aid ?? IdUtils.bv2av(bvid);
|
videoDetailCtr.oid.value = aid ?? IdUtils.bv2av(bvid);
|
||||||
videoDetailCtr.cid.value = cid;
|
videoDetailCtr.cid.value = cid;
|
||||||
videoDetailCtr.danmakuCid.value = cid;
|
videoDetailCtr.danmakuCid.value = cid;
|
||||||
videoDetailCtr.queryVideoUrl();
|
videoDetailCtr.queryVideoUrl();
|
||||||
releatedCtr.bvid = bvid;
|
|
||||||
releatedCtr.queryRelatedVideo();
|
|
||||||
// 重新请求评论
|
// 重新请求评论
|
||||||
try {
|
try {
|
||||||
/// 未渲染回复组件时可能异常
|
/// 未渲染回复组件时可能异常
|
||||||
|
|||||||
@ -180,11 +180,20 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
|||||||
plPlayerController?.isFullScreen.listen((bool isFullScreen) {
|
plPlayerController?.isFullScreen.listen((bool isFullScreen) {
|
||||||
if (isFullScreen) {
|
if (isFullScreen) {
|
||||||
vdCtr.hiddenReplyReplyPanel();
|
vdCtr.hiddenReplyReplyPanel();
|
||||||
videoIntroController.hiddenEpisodeBottomSheet();
|
if (vdCtr.videoType == SearchType.video) {
|
||||||
if (videoIntroController.videoDetail.value.ugcSeason != null ||
|
videoIntroController.hiddenEpisodeBottomSheet();
|
||||||
(videoIntroController.videoDetail.value.pages != null &&
|
if (videoIntroController.videoDetail.value.ugcSeason != null ||
|
||||||
videoIntroController.videoDetail.value.pages!.length > 1)) {
|
(videoIntroController.videoDetail.value.pages != null &&
|
||||||
vdCtr.bottomList.insert(3, BottomControlType.episode);
|
videoIntroController.videoDetail.value.pages!.length > 1)) {
|
||||||
|
vdCtr.bottomList.insert(3, BottomControlType.episode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (vdCtr.videoType == SearchType.media_bangumi) {
|
||||||
|
bangumiIntroController.hiddenEpisodeBottomSheet();
|
||||||
|
if (bangumiIntroController.bangumiDetail.value.episodes != null &&
|
||||||
|
bangumiIntroController.bangumiDetail.value.episodes!.length > 1) {
|
||||||
|
vdCtr.bottomList.insert(3, BottomControlType.episode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (vdCtr.bottomList.contains(BottomControlType.episode)) {
|
if (vdCtr.bottomList.contains(BottomControlType.episode)) {
|
||||||
@ -395,27 +404,41 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
|||||||
width: 38,
|
width: 38,
|
||||||
height: 38,
|
height: 38,
|
||||||
child: Obx(
|
child: Obx(
|
||||||
() => IconButton(
|
() => !vdCtr.isShowCover.value
|
||||||
onPressed: () {
|
? IconButton(
|
||||||
plPlayerController?.isOpenDanmu.value =
|
onPressed: () {
|
||||||
!(plPlayerController?.isOpenDanmu.value ??
|
plPlayerController?.isOpenDanmu.value =
|
||||||
false);
|
!(plPlayerController
|
||||||
},
|
?.isOpenDanmu.value ??
|
||||||
icon: !(plPlayerController?.isOpenDanmu.value ??
|
false);
|
||||||
false)
|
},
|
||||||
? SvgPicture.asset(
|
icon:
|
||||||
|
!(plPlayerController?.isOpenDanmu.value ??
|
||||||
|
false)
|
||||||
|
? SvgPicture.asset(
|
||||||
|
'assets/images/video/danmu_close.svg',
|
||||||
|
// ignore: deprecated_member_use
|
||||||
|
color: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.outline,
|
||||||
|
)
|
||||||
|
: SvgPicture.asset(
|
||||||
|
'assets/images/video/danmu_open.svg',
|
||||||
|
// ignore: deprecated_member_use
|
||||||
|
color: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.primary,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: IconButton(
|
||||||
|
icon: SvgPicture.asset(
|
||||||
'assets/images/video/danmu_close.svg',
|
'assets/images/video/danmu_close.svg',
|
||||||
// ignore: deprecated_member_use
|
// ignore: deprecated_member_use
|
||||||
color:
|
color:
|
||||||
Theme.of(context).colorScheme.outline,
|
Theme.of(context).colorScheme.outline,
|
||||||
)
|
|
||||||
: SvgPicture.asset(
|
|
||||||
'assets/images/video/danmu_open.svg',
|
|
||||||
// ignore: deprecated_member_use
|
|
||||||
color:
|
|
||||||
Theme.of(context).colorScheme.primary,
|
|
||||||
),
|
),
|
||||||
),
|
onPressed: () {},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 18),
|
const SizedBox(width: 18),
|
||||||
|
|||||||
@ -1306,20 +1306,6 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
],
|
],
|
||||||
|
|
||||||
/// 字幕
|
/// 字幕
|
||||||
// SizedBox(
|
|
||||||
// width: 34,
|
|
||||||
// height: 34,
|
|
||||||
// child: IconButton(
|
|
||||||
// style: ButtonStyle(
|
|
||||||
// padding: MaterialStateProperty.all(EdgeInsets.zero),
|
|
||||||
// ),
|
|
||||||
// onPressed: () => showSubtitleDialog(),
|
|
||||||
// icon: const Icon(
|
|
||||||
// Icons.closed_caption_off,
|
|
||||||
// size: 22,
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
ComBtn(
|
ComBtn(
|
||||||
icon: const Icon(
|
icon: const Icon(
|
||||||
Icons.closed_caption_off,
|
Icons.closed_caption_off,
|
||||||
|
|||||||
@ -473,17 +473,17 @@ class PlPlayerController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 字幕
|
// 字幕
|
||||||
if (dataSource.subFiles != '' && dataSource.subFiles != null) {
|
// if (dataSource.subFiles != '' && dataSource.subFiles != null) {
|
||||||
await pp.setProperty(
|
// await pp.setProperty(
|
||||||
'sub-files',
|
// 'sub-files',
|
||||||
UniversalPlatform.isWindows
|
// UniversalPlatform.isWindows
|
||||||
? dataSource.subFiles!.replaceAll(';', '\\;')
|
// ? dataSource.subFiles!.replaceAll(';', '\\;')
|
||||||
: dataSource.subFiles!.replaceAll(':', '\\:'),
|
// : dataSource.subFiles!.replaceAll(':', '\\:'),
|
||||||
);
|
// );
|
||||||
await pp.setProperty("subs-with-matching-audio", "no");
|
// await pp.setProperty("subs-with-matching-audio", "no");
|
||||||
await pp.setProperty("sub-forced-only", "yes");
|
// await pp.setProperty("sub-forced-only", "yes");
|
||||||
await pp.setProperty("blend-subtitles", "video");
|
// await pp.setProperty("blend-subtitles", "video");
|
||||||
}
|
// }
|
||||||
|
|
||||||
_videoController = _videoController ??
|
_videoController = _videoController ??
|
||||||
VideoController(
|
VideoController(
|
||||||
@ -522,7 +522,22 @@ class PlPlayerController {
|
|||||||
Duration seekTo = Duration.zero,
|
Duration seekTo = Duration.zero,
|
||||||
Duration? duration,
|
Duration? duration,
|
||||||
}) async {
|
}) async {
|
||||||
// 设置倍速
|
getVideoFit();
|
||||||
|
// if (_looping) {
|
||||||
|
// await setLooping(_looping);
|
||||||
|
// }
|
||||||
|
|
||||||
|
/// 跳转播放
|
||||||
|
if (seekTo != Duration.zero) {
|
||||||
|
await this.seekTo(seekTo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 自动播放
|
||||||
|
if (_autoPlay) {
|
||||||
|
await play(duration: duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 设置倍速
|
||||||
if (videoType.value == 'live') {
|
if (videoType.value == 'live') {
|
||||||
await setPlaybackSpeed(1.0);
|
await setPlaybackSpeed(1.0);
|
||||||
} else {
|
} else {
|
||||||
@ -532,20 +547,6 @@ class PlPlayerController {
|
|||||||
await setPlaybackSpeed(1.0);
|
await setPlaybackSpeed(1.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
getVideoFit();
|
|
||||||
// if (_looping) {
|
|
||||||
// await setLooping(_looping);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// 跳转播放
|
|
||||||
if (seekTo != Duration.zero) {
|
|
||||||
await this.seekTo(seekTo);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 自动播放
|
|
||||||
if (_autoPlay) {
|
|
||||||
await play(duration: duration);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
List<StreamSubscription> subscriptions = [];
|
List<StreamSubscription> subscriptions = [];
|
||||||
@ -603,7 +604,9 @@ class PlPlayerController {
|
|||||||
makeHeartBeat(event.inSeconds);
|
makeHeartBeat(event.inSeconds);
|
||||||
}),
|
}),
|
||||||
videoPlayerController!.stream.duration.listen((event) {
|
videoPlayerController!.stream.duration.listen((event) {
|
||||||
duration.value = event;
|
if (event > Duration.zero) {
|
||||||
|
duration.value = event;
|
||||||
|
}
|
||||||
}),
|
}),
|
||||||
videoPlayerController!.stream.buffer.listen((event) {
|
videoPlayerController!.stream.buffer.listen((event) {
|
||||||
_buffered.value = event;
|
_buffered.value = event;
|
||||||
@ -646,32 +649,38 @@ class PlPlayerController {
|
|||||||
|
|
||||||
/// 跳转至指定位置
|
/// 跳转至指定位置
|
||||||
Future<void> seekTo(Duration position, {type = 'seek'}) async {
|
Future<void> seekTo(Duration position, {type = 'seek'}) async {
|
||||||
if (position < Duration.zero) {
|
try {
|
||||||
position = Duration.zero;
|
if (position < Duration.zero) {
|
||||||
}
|
position = Duration.zero;
|
||||||
_position.value = position;
|
|
||||||
updatePositionSecond();
|
|
||||||
_heartDuration = position.inSeconds;
|
|
||||||
if (duration.value.inSeconds != 0) {
|
|
||||||
if (type != 'slider') {
|
|
||||||
/// 拖动进度条调节时,不等待第一帧,防止抖动
|
|
||||||
await _videoPlayerController?.stream.buffer.first;
|
|
||||||
}
|
}
|
||||||
await _videoPlayerController?.seek(position);
|
_position.value = position;
|
||||||
} else {
|
updatePositionSecond();
|
||||||
_timerForSeek?.cancel();
|
_heartDuration = position.inSeconds;
|
||||||
_timerForSeek ??=
|
if (duration.value.inSeconds != 0) {
|
||||||
Timer.periodic(const Duration(milliseconds: 200), (Timer t) async {
|
if (type != 'slider') {
|
||||||
if (duration.value.inSeconds != 0) {
|
await _videoPlayerController?.stream.buffer.first;
|
||||||
await _videoPlayerController!.stream.buffer.first;
|
|
||||||
await _videoPlayerController?.seek(position);
|
|
||||||
t.cancel();
|
|
||||||
_timerForSeek = null;
|
|
||||||
}
|
}
|
||||||
});
|
await _videoPlayerController?.seek(position);
|
||||||
|
} else {
|
||||||
|
_timerForSeek?.cancel();
|
||||||
|
_timerForSeek ??= _startSeekTimer(position);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
print('Error while seeking: $err');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Timer? _startSeekTimer(Duration position) {
|
||||||
|
return Timer.periodic(const Duration(milliseconds: 200), (Timer t) async {
|
||||||
|
if (duration.value.inSeconds != 0) {
|
||||||
|
await _videoPlayerController!.stream.buffer.first;
|
||||||
|
await _videoPlayerController?.seek(position);
|
||||||
|
t.cancel();
|
||||||
|
_timerForSeek = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/// 设置倍速
|
/// 设置倍速
|
||||||
Future<void> setPlaybackSpeed(double speed) async {
|
Future<void> setPlaybackSpeed(double speed) async {
|
||||||
/// TODO _duration.value丢失
|
/// TODO _duration.value丢失
|
||||||
@ -708,11 +717,10 @@ class PlPlayerController {
|
|||||||
await seekTo(Duration.zero);
|
await seekTo(Duration.zero);
|
||||||
}
|
}
|
||||||
await _videoPlayerController?.play();
|
await _videoPlayerController?.play();
|
||||||
|
playerStatus.status.value = PlayerStatus.playing;
|
||||||
await getCurrentVolume();
|
await getCurrentVolume();
|
||||||
await getCurrentBrightness();
|
await getCurrentBrightness();
|
||||||
|
|
||||||
playerStatus.status.value = PlayerStatus.playing;
|
|
||||||
// screenManager.setOverlays(false);
|
// screenManager.setOverlays(false);
|
||||||
|
|
||||||
/// 临时fix _duration.value丢失
|
/// 临时fix _duration.value丢失
|
||||||
|
|||||||
@ -5,8 +5,8 @@ class SubTitleUtils {
|
|||||||
|
|
||||||
for (int i = 0; i < jsonData.length; i++) {
|
for (int i = 0; i < jsonData.length; i++) {
|
||||||
final item = jsonData[i];
|
final item = jsonData[i];
|
||||||
double from = item['from'] as double;
|
double from = double.parse(item['from'].toString());
|
||||||
double to = item['to'] as double;
|
double to = double.parse(item['to'].toString());
|
||||||
int sid = (item['sid'] ?? 0) as int;
|
int sid = (item['sid'] ?? 0) as int;
|
||||||
String content = item['content'] as String;
|
String content = item['content'] as String;
|
||||||
|
|
||||||
|
|||||||
@ -210,15 +210,18 @@ class Utils {
|
|||||||
int minDiff = 127;
|
int minDiff = 127;
|
||||||
int closestNumber = 0; // 初始化为0,表示没有找到比目标值小的整数
|
int closestNumber = 0; // 初始化为0,表示没有找到比目标值小的整数
|
||||||
|
|
||||||
|
if (numbers.contains(target)) {
|
||||||
|
return target;
|
||||||
|
}
|
||||||
// 向下查找
|
// 向下查找
|
||||||
try {
|
try {
|
||||||
for (int number in numbers) {
|
for (int number in numbers) {
|
||||||
if (number < target) {
|
if (number < target) {
|
||||||
int diff = target - number; // 计算目标值与当前整数的差值
|
int diff = target - number; // 计算目标值与当前整数的差值
|
||||||
|
|
||||||
if (diff < minDiff) {
|
if (diff < minDiff) {
|
||||||
minDiff = diff;
|
minDiff = diff;
|
||||||
closestNumber = number;
|
closestNumber = number;
|
||||||
|
return closestNumber;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user