Merge branch 'main' into design

This commit is contained in:
guozhigq
2024-09-23 00:14:27 +08:00
29 changed files with 728 additions and 326 deletions

View File

@ -1,5 +1,6 @@
import UIKit import UIKit
import Flutter import Flutter
import AVFoundation
@UIApplicationMain @UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate { @objc class AppDelegate: FlutterAppDelegate {
@ -8,6 +9,14 @@ import Flutter
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool { ) -> Bool {
GeneratedPluginRegistrant.register(with: self) GeneratedPluginRegistrant.register(with: self)
//
do {
try AVAudioSession.sharedInstance().setCategory(.playback, options: [.duckOthers])
} catch {
print("Failed to set audio session category: \(error)")
}
return super.application(application, didFinishLaunchingWithOptions: launchOptions) return super.application(application, didFinishLaunchingWithOptions: launchOptions)
} }
} }

View File

@ -2,7 +2,7 @@ import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:pilipala/utils/extension.dart'; import 'package:pilipala/utils/extension.dart';
import 'package:pilipala/utils/global_data.dart'; import 'package:pilipala/utils/global_data_cache.dart';
import '../../utils/storage.dart'; import '../../utils/storage.dart';
import '../constants.dart'; import '../constants.dart';
@ -33,7 +33,7 @@ class NetworkImgLayer extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final int defaultImgQuality = GlobalData().imgQuality; final int defaultImgQuality = GlobalDataCache().imgQuality;
if (src == '' || src == null) { if (src == '' || src == null) {
return placeholder(context); return placeholder(context);
} }

View File

@ -571,4 +571,8 @@ class Api {
/// 直播间发送弹幕 /// 直播间发送弹幕
static const String sendLiveMsg = '${HttpString.liveBaseUrl}/msg/send'; static const String sendLiveMsg = '${HttpString.liveBaseUrl}/msg/send';
/// 我的关注 - 正在直播
static const String getFollowingLive =
'${HttpString.liveBaseUrl}/xlive/web-ucenter/user/following';
} }

View File

@ -46,7 +46,8 @@ class ApiInterceptor extends Interceptor {
// 处理网络请求错误 // 处理网络请求错误
// handler.next(err); // handler.next(err);
String url = err.requestOptions.uri.toString(); String url = err.requestOptions.uri.toString();
if (!url.contains('heartbeat')) { final excludedPatterns = RegExp(r'heartbeat|seg\.so|online/total');
if (!excludedPatterns.hasMatch(url)) {
SmartDialog.showToast( SmartDialog.showToast(
await dioError(err), await dioError(err),
displayType: SmartToastType.onlyRefresh, displayType: SmartToastType.onlyRefresh,

View File

@ -1,3 +1,5 @@
import 'package:pilipala/models/live/follow.dart';
import '../models/live/item.dart'; import '../models/live/item.dart';
import '../models/live/room_info.dart'; import '../models/live/room_info.dart';
import '../models/live/room_info_h5.dart'; import '../models/live/room_info_h5.dart';
@ -117,4 +119,27 @@ class LiveHttp {
}; };
} }
} }
// 我的关注 正在直播
static Future liveFollowing({int? pn, int? ps}) async {
var res = await Request().get(Api.getFollowingLive, data: {
'page': pn,
'page_size': ps,
'platform': 'web',
'ignoreRecord': 1,
'hit_ab': true,
});
if (res.data['code'] == 0) {
return {
'status': true,
'data': LiveFollowingModel.fromJson(res.data['data'])
};
} else {
return {
'status': false,
'data': [],
'msg': res.data['message'],
};
}
}
} }

View File

@ -20,7 +20,7 @@ import 'package:pilipala/pages/main/view.dart';
import 'package:pilipala/services/service_locator.dart'; import 'package:pilipala/services/service_locator.dart';
import 'package:pilipala/utils/app_scheme.dart'; import 'package:pilipala/utils/app_scheme.dart';
import 'package:pilipala/utils/data.dart'; import 'package:pilipala/utils/data.dart';
import 'package:pilipala/utils/global_data.dart'; import 'package:pilipala/utils/global_data_cache.dart';
import 'package:pilipala/utils/storage.dart'; import 'package:pilipala/utils/storage.dart';
import 'package:media_kit/media_kit.dart'; import 'package:media_kit/media_kit.dart';
import 'package:pilipala/utils/recommend_filter.dart'; import 'package:pilipala/utils/recommend_filter.dart';
@ -33,7 +33,6 @@ void main() async {
await SystemChrome.setPreferredOrientations( await SystemChrome.setPreferredOrientations(
[DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]);
await GStrorage.init(); await GStrorage.init();
await setupServiceLocator();
clearLogs(); clearLogs();
Request(); Request();
await Request.setCookie(); await Request.setCookie();
@ -65,6 +64,7 @@ void main() async {
} }
PiliSchame.init(); PiliSchame.init();
await GlobalDataCache().initialize();
} }
class MyApp extends StatelessWidget { class MyApp extends StatelessWidget {
@ -266,10 +266,10 @@ class BuildMainApp extends StatelessWidget {
VideoDetailPage.routeObserver, VideoDetailPage.routeObserver,
SearchPage.routeObserver, SearchPage.routeObserver,
], ],
onInit: () { onReady: () async {
RecommendFilter(); RecommendFilter();
Data.init(); Data.init();
GlobalData(); setupServiceLocator();
}, },
); );
} }

126
lib/models/live/follow.dart Normal file
View File

@ -0,0 +1,126 @@
class LiveFollowingModel {
int? count;
List<LiveFollowingItemModel>? list;
int? liveCount;
int? neverLivedCount;
List? neverLivedFaces;
int? pageSize;
String? title;
int? totalPage;
LiveFollowingModel({
this.count,
this.list,
this.liveCount,
this.neverLivedCount,
this.neverLivedFaces,
this.pageSize,
this.title,
this.totalPage,
});
LiveFollowingModel.fromJson(Map<String, dynamic> json) {
count = json['count'];
if (json['list'] != null) {
list = <LiveFollowingItemModel>[];
json['list'].forEach((v) {
list!.add(LiveFollowingItemModel.fromJson(v));
});
}
liveCount = json['live_count'];
neverLivedCount = json['never_lived_count'];
if (json['never_lived_faces'] != null) {
neverLivedFaces = <dynamic>[];
json['never_lived_faces'].forEach((v) {
neverLivedFaces!.add(v);
});
}
pageSize = json['pageSize'];
title = json['title'];
totalPage = json['totalPage'];
}
}
class LiveFollowingItemModel {
int? roomId;
int? uid;
String? uname;
String? title;
String? face;
int? liveStatus;
int? recordNum;
String? recentRecordId;
int? isAttention;
int? clipNum;
int? fansNum;
String? areaName;
String? areaValue;
String? tags;
String? recentRecordIdV2;
int? recordNumV2;
int? recordLiveTime;
String? areaNameV2;
String? roomNews;
String? watchIcon;
String? textSmall;
String? roomCover;
String? pic;
int? parentAreaId;
int? areaId;
LiveFollowingItemModel({
this.roomId,
this.uid,
this.uname,
this.title,
this.face,
this.liveStatus,
this.recordNum,
this.recentRecordId,
this.isAttention,
this.clipNum,
this.fansNum,
this.areaName,
this.areaValue,
this.tags,
this.recentRecordIdV2,
this.recordNumV2,
this.recordLiveTime,
this.areaNameV2,
this.roomNews,
this.watchIcon,
this.textSmall,
this.roomCover,
this.pic,
this.parentAreaId,
this.areaId,
});
LiveFollowingItemModel.fromJson(Map<String, dynamic> json) {
roomId = json['roomid'];
uid = json['uid'];
uname = json['uname'];
title = json['title'];
face = json['face'];
liveStatus = json['live_status'];
recordNum = json['record_num'];
recentRecordId = json['recent_record_id'];
isAttention = json['is_attention'];
clipNum = json['clipnum'];
fansNum = json['fans_num'];
areaName = json['area_name'];
areaValue = json['area_value'];
tags = json['tags'];
recentRecordIdV2 = json['recent_record_id_v2'];
recordNumV2 = json['record_num_v2'];
recordLiveTime = json['record_live_time'];
areaNameV2 = json['area_name_v2'];
roomNews = json['room_news'];
watchIcon = json['watch_icon'];
textSmall = json['text_small'];
roomCover = json['room_cover'];
pic = json['room_cover'];
parentAreaId = json['parent_area_id'];
areaId = json['area_id'];
}
}

View File

@ -1,11 +1,13 @@
class RoomInfoModel { class RoomInfoModel {
RoomInfoModel({ RoomInfoModel({
this.roomId, this.roomId,
this.isPortrait,
this.liveStatus, this.liveStatus,
this.liveTime, this.liveTime,
this.playurlInfo, this.playurlInfo,
}); });
int? roomId; int? roomId;
bool? isPortrait;
int? liveStatus; int? liveStatus;
int? liveTime; int? liveTime;
PlayurlInfo? playurlInfo; PlayurlInfo? playurlInfo;
@ -13,6 +15,7 @@ class RoomInfoModel {
RoomInfoModel.fromJson(Map<String, dynamic> json) { RoomInfoModel.fromJson(Map<String, dynamic> json) {
roomId = json['room_id']; roomId = json['room_id'];
liveStatus = json['live_status']; liveStatus = json['live_status'];
isPortrait = json['is_portrait'];
liveTime = json['live_time']; liveTime = json['live_time'];
playurlInfo = PlayurlInfo.fromJson(json['playurl_info']); playurlInfo = PlayurlInfo.fromJson(json['playurl_info']);
} }

View File

@ -48,7 +48,7 @@ class FollowSearchController extends GetxController {
return {'status': true, 'data': <FollowItemModel>[].obs}; return {'status': true, 'data': <FollowItemModel>[].obs};
} }
if (type == 'init') { if (type == 'init') {
ps = 1; pn = 1;
} }
var res = await MemberHttp.getfollowSearch( var res = await MemberHttp.getfollowSearch(
mid: mid, mid: mid,

View File

@ -2,6 +2,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/http/live.dart'; import 'package:pilipala/http/live.dart';
import 'package:pilipala/models/live/follow.dart';
import 'package:pilipala/models/live/item.dart'; import 'package:pilipala/models/live/item.dart';
import 'package:pilipala/utils/storage.dart'; import 'package:pilipala/utils/storage.dart';
@ -11,6 +12,8 @@ class LiveController extends GetxController {
int _currentPage = 1; int _currentPage = 1;
RxInt crossAxisCount = 2.obs; RxInt crossAxisCount = 2.obs;
RxList<LiveItemModel> liveList = <LiveItemModel>[].obs; RxList<LiveItemModel> liveList = <LiveItemModel>[].obs;
RxList<LiveFollowingItemModel> liveFollowingList =
<LiveFollowingItemModel>[].obs;
bool flag = false; bool flag = false;
OverlayEntry? popupDialog; OverlayEntry? popupDialog;
Box setting = GStrorage.setting; Box setting = GStrorage.setting;
@ -44,6 +47,7 @@ class LiveController extends GetxController {
// 下拉刷新 // 下拉刷新
Future onRefresh() async { Future onRefresh() async {
queryLiveList('init'); queryLiveList('init');
fetchLiveFollowing();
} }
// 上拉加载 // 上拉加载
@ -61,4 +65,17 @@ class LiveController extends GetxController {
duration: const Duration(milliseconds: 500), curve: Curves.easeInOut); duration: const Duration(milliseconds: 500), curve: Curves.easeInOut);
} }
} }
//
Future fetchLiveFollowing() async {
var res = await LiveHttp.liveFollowing(pn: 1, ps: 20);
if (res['status']) {
liveFollowingList.value =
(res['data'].list as List<LiveFollowingItemModel>)
.where((LiveFollowingItemModel item) =>
item.liveStatus == 1 && item.recordLiveTime == 0) // 根据条件过滤
.toList();
}
return res;
}
} }

View File

@ -6,6 +6,8 @@ import 'package:get/get.dart';
import 'package:pilipala/common/constants.dart'; import 'package:pilipala/common/constants.dart';
import 'package:pilipala/common/skeleton/video_card_v.dart'; import 'package:pilipala/common/skeleton/video_card_v.dart';
import 'package:pilipala/common/widgets/http_error.dart'; import 'package:pilipala/common/widgets/http_error.dart';
import 'package:pilipala/common/widgets/network_img_layer.dart';
import 'package:pilipala/models/live/follow.dart';
import 'package:pilipala/utils/main_stream.dart'; import 'package:pilipala/utils/main_stream.dart';
import 'controller.dart'; import 'controller.dart';
@ -22,6 +24,7 @@ class _LivePageState extends State<LivePage>
with AutomaticKeepAliveClientMixin { with AutomaticKeepAliveClientMixin {
final LiveController _liveController = Get.put(LiveController()); final LiveController _liveController = Get.put(LiveController());
late Future _futureBuilderFuture; late Future _futureBuilderFuture;
late Future _futureBuilderFuture2;
late ScrollController scrollController; late ScrollController scrollController;
@override @override
@ -31,6 +34,7 @@ class _LivePageState extends State<LivePage>
void initState() { void initState() {
super.initState(); super.initState();
_futureBuilderFuture = _liveController.queryLiveList('init'); _futureBuilderFuture = _liveController.queryLiveList('init');
_futureBuilderFuture2 = _liveController.fetchLiveFollowing();
scrollController = _liveController.scrollController; scrollController = _liveController.scrollController;
scrollController.addListener( scrollController.addListener(
() { () {
@ -69,6 +73,7 @@ class _LivePageState extends State<LivePage>
child: CustomScrollView( child: CustomScrollView(
controller: _liveController.scrollController, controller: _liveController.scrollController,
slivers: [ slivers: [
buildFollowingList(),
SliverPadding( SliverPadding(
// 单列布局 EdgeInsets.zero // 单列布局 EdgeInsets.zero
padding: padding:
@ -147,4 +152,148 @@ class _LivePageState extends State<LivePage>
), ),
); );
} }
// 关注的up直播
Widget buildFollowingList() {
return SliverPadding(
padding: const EdgeInsets.only(top: 16),
sliver: SliverToBoxAdapter(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Obx(
() => Text.rich(
TextSpan(
children: [
const TextSpan(
text: ' 我的关注 ',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 15,
),
),
TextSpan(
text: ' ${_liveController.liveFollowingList.length}',
style: TextStyle(
fontSize: 12,
color: Theme.of(context).colorScheme.primary,
),
),
TextSpan(
text: '人正在直播',
style: TextStyle(
fontSize: 12,
color: Theme.of(context).colorScheme.outline,
),
),
],
),
),
),
FutureBuilder(
future: _futureBuilderFuture2,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.data == null) {
return const SizedBox();
}
Map? data = snapshot.data;
if (data?['status']) {
RxList list = _liveController.liveFollowingList;
// ignore: invalid_use_of_protected_member
return Obx(() => LiveFollowingListView(list: list.value));
} else {
return SizedBox(
height: 80,
child: Center(
child: Text(
data?['msg'] ?? '',
style: TextStyle(
color: Theme.of(context).colorScheme.outline,
fontSize: 12,
),
),
),
);
}
} else {
return const SizedBox();
}
},
),
],
),
),
);
}
}
class LiveFollowingListView extends StatelessWidget {
final List list;
const LiveFollowingListView({super.key, required this.list});
@override
Widget build(BuildContext context) {
return SizedBox(
height: 100,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
final LiveFollowingItemModel item = list[index];
return Padding(
padding: const EdgeInsets.fromLTRB(3, 12, 3, 0),
child: Column(
children: [
InkWell(
onTap: () {
Get.toNamed(
'/liveRoom?roomid=${item.roomId}',
arguments: {
'liveItem': item,
'heroTag': item.roomId.toString()
},
);
},
child: Container(
width: 54,
height: 54,
padding: const EdgeInsets.all(2),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(27),
border: Border.all(
color: Theme.of(context).colorScheme.primary,
width: 1.5,
),
),
child: NetworkImgLayer(
width: 50,
height: 50,
type: 'avatar',
src: list[index].face,
),
),
),
const SizedBox(height: 6),
SizedBox(
width: 62,
child: Text(
list[index].uname,
maxLines: 1,
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.center,
style: const TextStyle(
fontSize: 12,
),
),
),
],
),
);
},
itemCount: list.length,
),
);
}
} }

View File

@ -48,6 +48,7 @@ class LiveRoomController extends GetxController {
// 直播间弹幕开关 默认打开 // 直播间弹幕开关 默认打开
RxBool danmakuSwitch = true.obs; RxBool danmakuSwitch = true.obs;
late String buvid; late String buvid;
RxBool isPortrait = false.obs;
@override @override
void onInit() { void onInit() {
@ -58,11 +59,12 @@ class LiveRoomController extends GetxController {
if (Get.arguments != null) { if (Get.arguments != null) {
liveItem = Get.arguments['liveItem']; liveItem = Get.arguments['liveItem'];
heroTag = Get.arguments['heroTag'] ?? ''; heroTag = Get.arguments['heroTag'] ?? '';
if (liveItem != null && liveItem.pic != null && liveItem.pic != '') { if (liveItem != null) {
cover = liveItem.pic; cover = (liveItem.pic != null && liveItem.pic != '')
} ? liveItem.pic
if (liveItem != null && liveItem.cover != null && liveItem.cover != '') { : (liveItem.cover != null && liveItem.cover != '')
cover = liveItem.cover; ? liveItem.cover
: null;
} }
Request.getBuvid().then((value) => buvid = value); Request.getBuvid().then((value) => buvid = value);
} }
@ -100,6 +102,7 @@ class LiveRoomController extends GetxController {
Future queryLiveInfo() async { Future queryLiveInfo() async {
var res = await LiveHttp.liveRoomInfo(roomId: roomId, qn: currentQn); var res = await LiveHttp.liveRoomInfo(roomId: roomId, qn: currentQn);
if (res['status']) { if (res['status']) {
isPortrait.value = res['data'].isPortrait;
List<CodecItem> codec = List<CodecItem> codec =
res['data'].playurlInfo.playurl.stream.first.format.first.codec; res['data'].playurlInfo.playurl.stream.first.format.first.codec;
CodecItem item = codec.first; CodecItem item = codec.first;

View File

@ -115,6 +115,9 @@ class _LiveRoomPageState extends State<LiveRoomPage>
plPlayerController = _liveRoomController.plPlayerController; plPlayerController = _liveRoomController.plPlayerController;
return PLVideoPlayer( return PLVideoPlayer(
controller: plPlayerController, controller: plPlayerController,
alignment: _liveRoomController.isPortrait.value
? Alignment.topCenter
: Alignment.center,
bottomControl: BottomControl( bottomControl: BottomControl(
controller: plPlayerController, controller: plPlayerController,
liveRoomCtr: _liveRoomController, liveRoomCtr: _liveRoomController,
@ -178,64 +181,18 @@ class _LiveRoomPageState extends State<LiveRoomPage>
), ),
), ),
), ),
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
AppBar( Obx(
centerTitle: false, () => SizedBox(
titleSpacing: 0, height: MediaQuery.of(context).padding.top +
backgroundColor: Colors.transparent, (_liveRoomController.isPortrait.value ||
foregroundColor: Colors.white, MediaQuery.of(context).orientation ==
toolbarHeight: Orientation.landscape
MediaQuery.of(context).orientation == Orientation.portrait ? 0
? 56 : kToolbarHeight),
: 0,
title: FutureBuilder(
future: _futureBuilder,
builder: (context, snapshot) {
if (snapshot.data == null) {
return const SizedBox();
}
Map data = snapshot.data as Map;
if (data['status']) {
return Obx(
() => Row(
children: [
NetworkImgLayer(
width: 34,
height: 34,
type: 'avatar',
src: _liveRoomController
.roomInfoH5.value.anchorInfo!.baseInfo!.face,
),
const SizedBox(width: 10),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
_liveRoomController.roomInfoH5.value
.anchorInfo!.baseInfo!.uname!,
style: const TextStyle(fontSize: 14),
),
const SizedBox(height: 1),
if (_liveRoomController
.roomInfoH5.value.watchedShow !=
null)
Text(
_liveRoomController.roomInfoH5.value
.watchedShow!['text_large'] ??
'',
style: const TextStyle(fontSize: 12),
),
],
),
],
),
);
} else {
return const SizedBox();
}
},
), ),
), ),
PopScope( PopScope(
@ -249,66 +206,141 @@ class _LiveRoomPageState extends State<LiveRoomPage>
verticalScreen(); verticalScreen();
} }
}, },
child: SizedBox( child: Obx(
width: Get.size.width, () => Container(
height: MediaQuery.of(context).orientation == width: Get.size.width,
Orientation.landscape height: MediaQuery.of(context).orientation ==
? Get.size.height Orientation.landscape
: Get.size.width * 9 / 16, ? Get.size.height
child: videoPlayerPanel, : !_liveRoomController.isPortrait.value
? Get.size.width * 9 / 16
: Get.size.height -
MediaQuery.of(context).padding.top,
clipBehavior: Clip.hardEdge,
decoration: const BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(6)),
),
child: videoPlayerPanel,
),
), ),
), ),
// 显示消息的列表 ],
buildMessageListUI( ),
// 定位 快速滑动到底部
Positioned(
right: 20,
bottom: MediaQuery.of(context).padding.bottom + 80,
child: SlideTransition(
position: Tween<Offset>(
begin: const Offset(0, 4),
end: const Offset(0, 0),
).animate(CurvedAnimation(
parent: fabAnimationCtr,
curve: Curves.easeInOut,
)),
child: ElevatedButton.icon(
onPressed: () {
_scrollToBottom();
},
icon: const Icon(Icons.keyboard_arrow_down), // 图标
label: const Text('新消息'), // 文字
style: ElevatedButton.styleFrom(
// primary: Colors.blue, // 按钮背景颜色
// onPrimary: Colors.white, // 按钮文字颜色
padding: const EdgeInsets.fromLTRB(14, 12, 20, 12), // 按钮内边距
),
),
),
),
// 顶栏
Positioned(
top: 0,
left: 0,
right: 0,
child: AppBar(
centerTitle: false,
titleSpacing: 0,
backgroundColor: Colors.transparent,
foregroundColor: Colors.white,
toolbarHeight:
MediaQuery.of(context).orientation == Orientation.portrait
? 56
: 0,
title: FutureBuilder(
future: _futureBuilder,
builder: (context, snapshot) {
if (snapshot.data == null) {
return const SizedBox();
}
Map data = snapshot.data as Map;
if (data['status']) {
return Obx(
() => Row(
children: [
NetworkImgLayer(
width: 34,
height: 34,
type: 'avatar',
src: _liveRoomController
.roomInfoH5.value.anchorInfo!.baseInfo!.face,
),
const SizedBox(width: 10),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
_liveRoomController.roomInfoH5.value.anchorInfo!
.baseInfo!.uname!,
style: const TextStyle(fontSize: 14),
),
const SizedBox(height: 1),
if (_liveRoomController
.roomInfoH5.value.watchedShow !=
null)
Text(
_liveRoomController.roomInfoH5.value
.watchedShow!['text_large'] ??
'',
style: const TextStyle(fontSize: 12),
),
],
),
],
),
);
} else {
return const SizedBox();
}
},
),
),
),
// 消息列表
Obx(
() => Positioned(
top: MediaQuery.of(context).padding.top +
kToolbarHeight +
(_liveRoomController.isPortrait.value
? Get.size.width
: Get.size.width * 9 / 16),
bottom: 90 + MediaQuery.of(context).padding.bottom,
left: 0,
right: 0,
child: buildMessageListUI(
context, context,
_liveRoomController, _liveRoomController,
_scrollController, _scrollController,
), ),
// Container( ),
// padding: const EdgeInsets.only( ),
// left: 14, right: 14, top: 4, bottom: 4), // 消息输入框
// margin: const EdgeInsets.only( Visibility(
// bottom: 6, visible: MediaQuery.of(context).orientation == Orientation.portrait,
// left: 14, child: Positioned(
// ), bottom: 0,
// decoration: BoxDecoration( left: 0,
// color: Colors.grey.withOpacity(0.1), right: 0,
// borderRadius: const BorderRadius.all(Radius.circular(20)), child: Container(
// ),
// child: Obx(
// () => AnimatedSwitcher(
// duration: const Duration(milliseconds: 300),
// transitionBuilder:
// (Widget child, Animation<double> animation) {
// return FadeTransition(opacity: animation, child: child);
// },
// child: Text.rich(
// key:
// ValueKey(_liveRoomController.joinRoomTip['userName']),
// TextSpan(
// style: const TextStyle(color: Colors.white),
// children: [
// TextSpan(
// text:
// '${_liveRoomController.joinRoomTip['userName']} ',
// style: TextStyle(
// color: Colors.white.withOpacity(0.6),
// ),
// ),
// TextSpan(
// text:
// '${_liveRoomController.joinRoomTip['message']}',
// style: const TextStyle(color: Colors.white),
// ),
// ],
// ),
// ),
// ),
// ),
// ),
const SizedBox(height: 10),
// 弹幕输入框
Container(
padding: EdgeInsets.only( padding: EdgeInsets.only(
left: 14, left: 14,
right: 14, right: 14,
@ -384,32 +416,6 @@ class _LiveRoomPageState extends State<LiveRoomPage>
], ],
), ),
), ),
],
),
// 定位 快速滑动到底部
Positioned(
right: 20,
bottom: MediaQuery.of(context).padding.bottom + 80,
child: SlideTransition(
position: Tween<Offset>(
begin: const Offset(0, 4),
end: const Offset(0, 0),
).animate(CurvedAnimation(
parent: fabAnimationCtr,
curve: Curves.easeInOut,
)),
child: ElevatedButton.icon(
onPressed: () {
_scrollToBottom();
},
icon: const Icon(Icons.keyboard_arrow_down), // 图标
label: const Text('新消息'), // 文字
style: ElevatedButton.styleFrom(
// primary: Colors.blue, // 按钮背景颜色
// onPrimary: Colors.white, // 按钮文字颜色
padding: const EdgeInsets.fromLTRB(14, 12, 20, 12), // 按钮内边距
),
),
), ),
), ),
], ],
@ -467,7 +473,9 @@ Widget buildMessageListUI(
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.grey.withOpacity(0.1), color: liveRoomController.isPortrait.value
? Colors.black.withOpacity(0.3)
: Colors.grey.withOpacity(0.1),
borderRadius: const BorderRadius.all(Radius.circular(20)), borderRadius: const BorderRadius.all(Radius.circular(20)),
), ),
margin: EdgeInsets.only( margin: EdgeInsets.only(

View File

@ -10,7 +10,6 @@ import 'package:pilipala/pages/media/index.dart';
import 'package:pilipala/pages/rank/index.dart'; import 'package:pilipala/pages/rank/index.dart';
import 'package:pilipala/utils/event_bus.dart'; import 'package:pilipala/utils/event_bus.dart';
import 'package:pilipala/utils/feed_back.dart'; import 'package:pilipala/utils/feed_back.dart';
import 'package:pilipala/utils/global_data.dart';
import 'package:pilipala/utils/storage.dart'; import 'package:pilipala/utils/storage.dart';
import './controller.dart'; import './controller.dart';
@ -30,6 +29,7 @@ class _MainAppState extends State<MainApp> with SingleTickerProviderStateMixin {
int? _lastSelectTime; //上次点击时间 int? _lastSelectTime; //上次点击时间
Box setting = GStrorage.setting; Box setting = GStrorage.setting;
late bool enableMYBar;
@override @override
void initState() { void initState() {
@ -37,6 +37,7 @@ class _MainAppState extends State<MainApp> with SingleTickerProviderStateMixin {
_lastSelectTime = DateTime.now().millisecondsSinceEpoch; _lastSelectTime = DateTime.now().millisecondsSinceEpoch;
_mainController.pageController = _mainController.pageController =
PageController(initialPage: _mainController.selectedIndex); PageController(initialPage: _mainController.selectedIndex);
enableMYBar = setting.get(SettingBoxKey.enableMYBar, defaultValue: true);
} }
void setIndex(int value) async { void setIndex(int value) async {
@ -171,7 +172,7 @@ class _MainAppState extends State<MainApp> with SingleTickerProviderStateMixin {
curve: Curves.easeInOutCubicEmphasized, curve: Curves.easeInOutCubicEmphasized,
duration: const Duration(milliseconds: 500), duration: const Duration(milliseconds: 500),
offset: Offset(0, snapshot.data ? 0 : 1), offset: Offset(0, snapshot.data ? 0 : 1),
child: GlobalData().enableMYBar child: enableMYBar
? Obx( ? Obx(
() => NavigationBar( () => NavigationBar(
onDestinationSelected: (value) => setIndex(value), onDestinationSelected: (value) => setIndex(value),

View File

@ -406,7 +406,7 @@ class _MemberPageState extends State<MemberPage>
? '个人认证:' ? '个人认证:'
: '企业认证:', : '企业认证:',
style: TextStyle( style: TextStyle(
color: Theme.of(context).primaryColor, color: Theme.of(context).colorScheme.primary,
), ),
children: [ children: [
TextSpan( TextSpan(

View File

@ -27,10 +27,13 @@ class MemberArchiveController extends GetxController {
// 获取用户投稿 // 获取用户投稿
Future getMemberArchive(type) async { Future getMemberArchive(type) async {
if (isLoading.value) {
return;
}
isLoading.value = true;
if (type == 'init') { if (type == 'init') {
pn = 1; pn = 1;
archivesList.clear(); archivesList.clear();
isLoading.value = true;
} }
var res = await MemberHttp.memberArchive( var res = await MemberHttp.memberArchive(
mid: mid, mid: mid,

View File

@ -21,7 +21,7 @@ class MemberSeasonsController extends GetxController {
mid = int.parse(Get.parameters['mid']!); mid = int.parse(Get.parameters['mid']!);
category = Get.parameters['category']!; category = Get.parameters['category']!;
if (category == '0') { if (category == '0') {
seasonId = int.parse(Get.parameters['seriesId']!); seasonId = int.parse(Get.parameters['seasonId']!);
} }
if (category == '1') { if (category == '1') {
seriesId = int.parse(Get.parameters['seriesId']!); seriesId = int.parse(Get.parameters['seriesId']!);

View File

@ -203,9 +203,9 @@ class LikeItem extends StatelessWidget {
Text.rich(TextSpan(children: [ Text.rich(TextSpan(children: [
TextSpan(text: nickNameList.join('')), TextSpan(text: nickNameList.join('')),
const TextSpan(text: ' '), const TextSpan(text: ' '),
if (item.users!.length > 1) if (item.counts! > 1)
TextSpan( TextSpan(
text: '等总计${item.users!.length}', text: '等总计${item.counts}',
style: TextStyle(color: outline), style: TextStyle(color: outline),
), ),
TextSpan( TextSpan(

View File

@ -261,90 +261,97 @@ class VideoPanelController extends GetxController {
onShowFilterSheet(searchPanelCtr) { onShowFilterSheet(searchPanelCtr) {
showModalBottomSheet( showModalBottomSheet(
context: Get.context!, context: Get.context!,
isScrollControlled: true,
builder: (context) { builder: (context) {
return StatefulBuilder( return StatefulBuilder(
builder: (context, StateSetter setState) { builder: (context, StateSetter setState) {
return Container( return Padding(
color: Theme.of(Get.context!).colorScheme.surface, padding: EdgeInsets.only(
padding: const EdgeInsets.only(top: 12), top: 12, bottom: MediaQuery.of(context).padding.bottom + 20),
child: Column( child: Wrap(
crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
const ListTile( Column(
title: Text('内容时长'), crossAxisAlignment: CrossAxisAlignment.start,
), children: [
Padding( const ListTile(
padding: const EdgeInsets.only( title: Text('内容时长'),
left: 14, ),
right: 14, Padding(
bottom: 14, padding: const EdgeInsets.only(
), left: 14,
child: Wrap( right: 14,
spacing: 10, bottom: 14,
runSpacing: 10, ),
direction: Axis.horizontal, child: Wrap(
textDirection: TextDirection.ltr, spacing: 10,
children: [ runSpacing: 10,
for (var i in timeFiltersList) direction: Axis.horizontal,
Obx( textDirection: TextDirection.ltr,
() => SearchText( children: [
searchText: i['label'], for (var i in timeFiltersList)
searchTextIdx: i['value'], Obx(
isSelect: () => SearchText(
currentTimeFilterval.value == i['value'], searchText: i['label'],
onSelect: (value) async { searchTextIdx: i['value'],
currentTimeFilterval.value = i['value']; isSelect:
setState(() {}); currentTimeFilterval.value == i['value'],
SmartDialog.showToast("${i['label']}」的筛选结果"); onSelect: (value) async {
SearchPanelController ctr = currentTimeFilterval.value = i['value'];
Get.find<SearchPanelController>( setState(() {});
SmartDialog.showToast(
"${i['label']}」的筛选结果");
SearchPanelController ctr = Get.find<
SearchPanelController>(
tag: 'video${searchPanelCtr.keyword!}'); tag: 'video${searchPanelCtr.keyword!}');
ctr.duration.value = i['value']; ctr.duration.value = i['value'];
Get.back(); Get.back();
SmartDialog.showLoading(msg: '获取中'); SmartDialog.showLoading(msg: '获取中');
await ctr.onRefresh(); await ctr.onRefresh();
SmartDialog.dismiss(); SmartDialog.dismiss();
}, },
onLongSelect: (value) => {}, onLongSelect: (value) => {},
), ),
) )
], ],
), ),
), ),
const ListTile( const ListTile(
title: Text('内容分区'), title: Text('内容分区'),
), ),
Padding( Padding(
padding: const EdgeInsets.only(left: 14, right: 14), padding: const EdgeInsets.only(left: 14, right: 14),
child: Wrap( child: Wrap(
spacing: 10, spacing: 10,
runSpacing: 10, runSpacing: 10,
direction: Axis.horizontal, direction: Axis.horizontal,
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
children: [ children: [
for (var i in partFiltersList) for (var i in partFiltersList)
SearchText( SearchText(
searchText: i['label'], searchText: i['label'],
searchTextIdx: i['value'], searchTextIdx: i['value'],
isSelect: currentPartFilterval.value == i['value'], isSelect:
onSelect: (value) async { currentPartFilterval.value == i['value'],
currentPartFilterval.value = i['value']; onSelect: (value) async {
setState(() {}); currentPartFilterval.value = i['value'];
SmartDialog.showToast("${i['label']}」的筛选结果"); setState(() {});
SearchPanelController ctr = SmartDialog.showToast("${i['label']}」的筛选结果");
Get.find<SearchPanelController>( SearchPanelController ctr = Get.find<
SearchPanelController>(
tag: 'video${searchPanelCtr.keyword!}'); tag: 'video${searchPanelCtr.keyword!}');
ctr.tids.value = i['value']; ctr.tids.value = i['value'];
Get.back(); Get.back();
SmartDialog.showLoading(msg: '获取中'); SmartDialog.showLoading(msg: '获取中');
await ctr.onRefresh(); await ctr.onRefresh();
SmartDialog.dismiss(); SmartDialog.dismiss();
}, },
onLongSelect: (value) => {}, onLongSelect: (value) => {},
) )
], ],
), ),
) )
],
),
], ],
), ),
); );

View File

@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:pilipala/models/common/action_type.dart'; import 'package:pilipala/models/common/action_type.dart';
import 'package:pilipala/utils/global_data.dart'; import 'package:pilipala/utils/global_data_cache.dart';
import '../../../utils/storage.dart'; import '../../../utils/storage.dart';
class ActionMenuSetPage extends StatefulWidget { class ActionMenuSetPage extends StatefulWidget {
@ -38,7 +38,7 @@ class _ActionMenuSetPageState extends State<ActionMenuSetPage> {
.map<String>((i) => (i['value'] as ActionType).value) .map<String>((i) => (i['value'] as ActionType).value)
.toList(); .toList();
setting.put(SettingBoxKey.actionTypeSort, sortedTabbar); setting.put(SettingBoxKey.actionTypeSort, sortedTabbar);
GlobalData().actionTypeSort = sortedTabbar; GlobalDataCache().actionTypeSort = sortedTabbar;
SmartDialog.showToast('操作成功'); SmartDialog.showToast('操作成功');
} }

View File

@ -1,6 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:pilipala/utils/global_data.dart'; import 'package:pilipala/utils/global_data_cache.dart';
import '../../../models/common/gesture_mode.dart'; import '../../../models/common/gesture_mode.dart';
import '../../../utils/storage.dart'; import '../../../utils/storage.dart';
@ -64,11 +64,11 @@ class _PlayGesturePageState extends State<PlayGesturePage> {
}, },
); );
if (result != null) { if (result != null) {
GlobalData().fullScreenGestureMode = FullScreenGestureMode GlobalDataCache().fullScreenGestureMode = FullScreenGestureMode
.values .values
.firstWhere((element) => element.values == result); .firstWhere((element) => element.values == result);
fullScreenGestureMode = fullScreenGestureMode =
GlobalData().fullScreenGestureMode.index; GlobalDataCache().fullScreenGestureMode.index;
setting.put( setting.put(
SettingBoxKey.fullScreenGestureMode, fullScreenGestureMode); SettingBoxKey.fullScreenGestureMode, fullScreenGestureMode);
setState(() {}); setState(() {});

View File

@ -9,7 +9,7 @@ import 'package:pilipala/models/video/play/quality.dart';
import 'package:pilipala/pages/setting/widgets/select_dialog.dart'; import 'package:pilipala/pages/setting/widgets/select_dialog.dart';
import 'package:pilipala/plugin/pl_player/index.dart'; import 'package:pilipala/plugin/pl_player/index.dart';
import 'package:pilipala/services/service_locator.dart'; import 'package:pilipala/services/service_locator.dart';
import 'package:pilipala/utils/global_data.dart'; import 'package:pilipala/utils/global_data_cache.dart';
import 'package:pilipala/utils/storage.dart'; import 'package:pilipala/utils/storage.dart';
import '../../models/live/quality.dart'; import '../../models/live/quality.dart';
@ -162,7 +162,7 @@ class _PlaySettingState extends State<PlaySetting> {
setKey: SettingBoxKey.enablePlayerControlAnimation, setKey: SettingBoxKey.enablePlayerControlAnimation,
defaultVal: true, defaultVal: true,
callFn: (bool val) { callFn: (bool val) {
GlobalData().enablePlayerControlAnimation = val; GlobalDataCache().enablePlayerControlAnimation = val;
}), }),
SetSwitchItem( SetSwitchItem(
title: '港澳台模式', title: '港澳台模式',

View File

@ -8,7 +8,7 @@ import 'package:pilipala/models/common/theme_type.dart';
import 'package:pilipala/pages/setting/pages/color_select.dart'; import 'package:pilipala/pages/setting/pages/color_select.dart';
import 'package:pilipala/pages/setting/widgets/select_dialog.dart'; import 'package:pilipala/pages/setting/widgets/select_dialog.dart';
import 'package:pilipala/pages/setting/widgets/slide_dialog.dart'; import 'package:pilipala/pages/setting/widgets/slide_dialog.dart';
import 'package:pilipala/utils/global_data.dart'; import 'package:pilipala/utils/global_data_cache.dart';
import 'package:pilipala/utils/storage.dart'; import 'package:pilipala/utils/storage.dart';
import '../../models/common/dynamic_badge_mode.dart'; import '../../models/common/dynamic_badge_mode.dart';
@ -176,7 +176,7 @@ class _StyleSettingState extends State<StyleSetting> {
SettingBoxKey.defaultPicQa, picQuality); SettingBoxKey.defaultPicQa, picQuality);
Get.back(); Get.back();
settingController.picQuality.value = picQuality; settingController.picQuality.value = picQuality;
GlobalData().imgQuality = picQuality; GlobalDataCache().imgQuality = picQuality;
SmartDialog.showToast('设置成功'); SmartDialog.showToast('设置成功');
}, },
child: const Text('确定'), child: const Text('确定'),

View File

@ -20,7 +20,7 @@ import 'package:pilipala/models/video_detail_res.dart';
import 'package:pilipala/pages/video/detail/introduction/controller.dart'; import 'package:pilipala/pages/video/detail/introduction/controller.dart';
import 'package:pilipala/pages/video/detail/widgets/ai_detail.dart'; import 'package:pilipala/pages/video/detail/widgets/ai_detail.dart';
import 'package:pilipala/utils/feed_back.dart'; import 'package:pilipala/utils/feed_back.dart';
import 'package:pilipala/utils/global_data.dart'; import 'package:pilipala/utils/global_data_cache.dart';
import 'package:pilipala/utils/storage.dart'; import 'package:pilipala/utils/storage.dart';
import 'package:pilipala/utils/utils.dart'; import 'package:pilipala/utils/utils.dart';
import '../../../../http/user.dart'; import '../../../../http/user.dart';
@ -570,7 +570,7 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
} }
Widget actionGrid(BuildContext context, videoIntroController) { Widget actionGrid(BuildContext context, videoIntroController) {
final actionTypeSort = GlobalData().actionTypeSort; final actionTypeSort = GlobalDataCache().actionTypeSort;
Widget progressWidget(progress) { Widget progressWidget(progress) {
return SizedBox( return SizedBox(

View File

@ -18,6 +18,7 @@ import 'package:pilipala/plugin/pl_player/index.dart';
import 'package:pilipala/plugin/pl_player/models/play_repeat.dart'; import 'package:pilipala/plugin/pl_player/models/play_repeat.dart';
import 'package:pilipala/services/service_locator.dart'; import 'package:pilipala/services/service_locator.dart';
import 'package:pilipala/utils/feed_back.dart'; import 'package:pilipala/utils/feed_back.dart';
import 'package:pilipala/utils/global_data_cache.dart';
import 'package:pilipala/utils/storage.dart'; import 'package:pilipala/utils/storage.dart';
import 'package:screen_brightness/screen_brightness.dart'; import 'package:screen_brightness/screen_brightness.dart';
import 'package:status_bar_control/status_bar_control.dart'; import 'package:status_bar_control/status_bar_control.dart';
@ -277,50 +278,19 @@ class PlPlayerController {
// 添加一个私有构造函数 // 添加一个私有构造函数
PlPlayerController._internal(this.videoType) { PlPlayerController._internal(this.videoType) {
isOpenDanmu.value = final cache = GlobalDataCache();
setting.get(SettingBoxKey.enableShowDanmaku, defaultValue: false); isOpenDanmu.value = cache.isOpenDanmu;
blockTypes = blockTypes = cache.blockTypes;
localCache.get(LocalCacheKey.danmakuBlockType, defaultValue: []); showArea = cache.showArea;
showArea = localCache.get(LocalCacheKey.danmakuShowArea, defaultValue: 0.5); opacityVal = cache.opacityVal;
// 不透明度 fontSizeVal = cache.fontSizeVal;
opacityVal = danmakuDurationVal = cache.danmakuDurationVal;
localCache.get(LocalCacheKey.danmakuOpacity, defaultValue: 1.0); strokeWidth = cache.strokeWidth;
// 字体大小 playRepeat = cache.playRepeat;
fontSizeVal = _playbackSpeed.value = cache.playbackSpeed;
localCache.get(LocalCacheKey.danmakuFontScale, defaultValue: 1.0); enableAutoLongPressSpeed = cache.enableAutoLongPressSpeed;
// 弹幕时间 _longPressSpeed.value = cache.longPressSpeed;
danmakuDurationVal = speedsList = cache.speedsList;
localCache.get(LocalCacheKey.danmakuDuration, defaultValue: 4.0);
// 描边粗细
strokeWidth = localCache.get(LocalCacheKey.strokeWidth, defaultValue: 1.5);
playRepeat = PlayRepeat.values.toList().firstWhere(
(e) =>
e.value ==
videoStorage.get(VideoBoxKey.playRepeat,
defaultValue: PlayRepeat.pause.value),
);
_playbackSpeed.value =
videoStorage.get(VideoBoxKey.playSpeedDefault, defaultValue: 1.0);
enableAutoLongPressSpeed = setting
.get(SettingBoxKey.enableAutoLongPressSpeed, defaultValue: false);
if (!enableAutoLongPressSpeed) {
_longPressSpeed.value = videoStorage
.get(VideoBoxKey.longPressSpeedDefault, defaultValue: 2.0);
}
// 自定义倍速集合
speedsList = List<double>.from(videoStorage
.get(VideoBoxKey.customSpeedsList, defaultValue: <double>[]));
// 默认倍速
speedsList = List<double>.from(videoStorage
.get(VideoBoxKey.customSpeedsList, defaultValue: <double>[]));
//playSpeedSystem
final List<double> playSpeedSystem =
videoStorage.get(VideoBoxKey.playSpeedSystem, defaultValue: playSpeed);
// for (final PlaySpeed i in PlaySpeed.values) {
speedsList.addAll(playSpeedSystem);
// }
// _playerEventSubs = onPlayerStatusChanged.listen((PlayerStatus status) { // _playerEventSubs = onPlayerStatusChanged.listen((PlayerStatus status) {
// if (status == PlayerStatus.playing) { // if (status == PlayerStatus.playing) {
// WakelockPlus.enable(); // WakelockPlus.enable();

View File

@ -19,7 +19,7 @@ import 'package:pilipala/utils/feed_back.dart';
import 'package:pilipala/utils/storage.dart'; import 'package:pilipala/utils/storage.dart';
import 'package:screen_brightness/screen_brightness.dart'; import 'package:screen_brightness/screen_brightness.dart';
import '../../utils/global_data.dart'; import '../../utils/global_data_cache.dart';
import 'models/bottom_control_type.dart'; import 'models/bottom_control_type.dart';
import 'models/bottom_progress_behavior.dart'; import 'models/bottom_progress_behavior.dart';
import 'widgets/app_bar_ani.dart'; import 'widgets/app_bar_ani.dart';
@ -41,6 +41,7 @@ class PLVideoPlayer extends StatefulWidget {
this.customWidgets, this.customWidgets,
this.showEposideCb, this.showEposideCb,
this.fullScreenCb, this.fullScreenCb,
this.alignment = Alignment.center,
super.key, super.key,
}); });
@ -55,6 +56,7 @@ class PLVideoPlayer extends StatefulWidget {
final List<Widget>? customWidgets; final List<Widget>? customWidgets;
final Function? showEposideCb; final Function? showEposideCb;
final Function? fullScreenCb; final Function? fullScreenCb;
final Alignment? alignment;
@override @override
State<PLVideoPlayer> createState() => _PLVideoPlayerState(); State<PLVideoPlayer> createState() => _PLVideoPlayerState();
@ -88,7 +90,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
late bool enableBackgroundPlay; late bool enableBackgroundPlay;
late double screenWidth; late double screenWidth;
final FullScreenGestureMode fullScreenGestureMode = final FullScreenGestureMode fullScreenGestureMode =
GlobalData().fullScreenGestureMode; GlobalDataCache().fullScreenGestureMode;
// 用于记录上一次全屏切换手势触发时间,避免误触 // 用于记录上一次全屏切换手势触发时间,避免误触
DateTime? lastFullScreenToggleTime; DateTime? lastFullScreenToggleTime;
@ -133,7 +135,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
screenWidth = Get.size.width; screenWidth = Get.size.width;
animationController = AnimationController( animationController = AnimationController(
vsync: this, vsync: this,
duration: GlobalData().enablePlayerControlAnimation duration: GlobalDataCache().enablePlayerControlAnimation
? const Duration(milliseconds: 150) ? const Duration(milliseconds: 150)
: const Duration(milliseconds: 10), : const Duration(milliseconds: 10),
); );
@ -393,6 +395,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
key: ValueKey(_.videoFit.value), key: ValueKey(_.videoFit.value),
controller: videoController, controller: videoController,
controls: NoVideoControls, controls: NoVideoControls,
alignment: widget.alignment!,
pauseUponEnteringBackgroundMode: !enableBackgroundPlay, pauseUponEnteringBackgroundMode: !enableBackgroundPlay,
resumeUponEnteringForegroundMode: true, resumeUponEnteringForegroundMode: true,
subtitleViewConfiguration: const SubtitleViewConfiguration( subtitleViewConfiguration: const SubtitleViewConfiguration(

View File

@ -1,24 +0,0 @@
import 'package:hive/hive.dart';
import 'package:pilipala/utils/storage.dart';
import '../models/common/index.dart';
Box setting = GStrorage.setting;
class GlobalData {
int imgQuality = 10;
FullScreenGestureMode fullScreenGestureMode =
FullScreenGestureMode.values.last;
bool enablePlayerControlAnimation = true;
final bool enableMYBar =
setting.get(SettingBoxKey.enableMYBar, defaultValue: true);
List<String> actionTypeSort = setting.get(SettingBoxKey.actionTypeSort,
defaultValue: ['like', 'coin', 'collect', 'watchLater', 'share']);
// 私有构造函数
GlobalData._();
// 单例实例
static final GlobalData _instance = GlobalData._();
// 获取全局实例
factory GlobalData() => _instance;
}

View File

@ -0,0 +1,106 @@
import 'package:hive/hive.dart';
import 'package:pilipala/models/user/info.dart';
import 'package:pilipala/plugin/pl_player/models/play_repeat.dart';
import 'package:pilipala/plugin/pl_player/models/play_speed.dart';
import 'package:pilipala/utils/storage.dart';
import '../models/common/index.dart';
Box setting = GStrorage.setting;
Box localCache = GStrorage.localCache;
Box videoStorage = GStrorage.video;
Box userInfoCache = GStrorage.userInfo;
class GlobalDataCache {
late int imgQuality;
late FullScreenGestureMode fullScreenGestureMode;
late bool enablePlayerControlAnimation;
late List<String> actionTypeSort;
/// 播放器相关
// 弹幕开关
late bool isOpenDanmu;
// 弹幕屏蔽类型
late List<dynamic> blockTypes;
// 弹幕展示区域
late double showArea;
// 弹幕透明度
late double opacityVal;
// 弹幕字体大小
late double fontSizeVal;
// 弹幕显示时间
late double danmakuDurationVal;
// 弹幕描边宽度
late double strokeWidth;
// 播放器循环模式
late PlayRepeat playRepeat;
// 播放器默认播放速度
late double playbackSpeed;
// 播放器自动长按速度
late bool enableAutoLongPressSpeed;
// 播放器长按速度
late double longPressSpeed;
// 播放器速度列表
late List<double> speedsList;
// 用户信息
UserInfoData? userInfo;
// 私有构造函数
GlobalDataCache._();
// 单例实例
static final GlobalDataCache _instance = GlobalDataCache._();
// 获取全局实例
factory GlobalDataCache() => _instance;
// 异步初始化方法
Future<void> initialize() async {
imgQuality = await setting.get(SettingBoxKey.defaultPicQa,
defaultValue: 10); // 设置全局变量
fullScreenGestureMode = FullScreenGestureMode.values[setting.get(
SettingBoxKey.fullScreenGestureMode,
defaultValue: FullScreenGestureMode.values.last.index) as int];
enablePlayerControlAnimation = setting
.get(SettingBoxKey.enablePlayerControlAnimation, defaultValue: true);
actionTypeSort = await setting.get(SettingBoxKey.actionTypeSort,
defaultValue: ['like', 'coin', 'collect', 'watchLater', 'share']);
isOpenDanmu =
await setting.get(SettingBoxKey.enableShowDanmaku, defaultValue: false);
blockTypes =
await localCache.get(LocalCacheKey.danmakuBlockType, defaultValue: []);
showArea =
await localCache.get(LocalCacheKey.danmakuShowArea, defaultValue: 0.5);
opacityVal =
await localCache.get(LocalCacheKey.danmakuOpacity, defaultValue: 1.0);
fontSizeVal =
await localCache.get(LocalCacheKey.danmakuFontScale, defaultValue: 1.0);
danmakuDurationVal =
await localCache.get(LocalCacheKey.danmakuDuration, defaultValue: 4.0);
strokeWidth =
await localCache.get(LocalCacheKey.strokeWidth, defaultValue: 1.5);
var defaultPlayRepeat = await videoStorage.get(VideoBoxKey.playRepeat,
defaultValue: PlayRepeat.pause.value);
playRepeat = PlayRepeat.values
.toList()
.firstWhere((e) => e.value == defaultPlayRepeat);
playbackSpeed =
await videoStorage.get(VideoBoxKey.playSpeedDefault, defaultValue: 1.0);
enableAutoLongPressSpeed = await setting
.get(SettingBoxKey.enableAutoLongPressSpeed, defaultValue: false);
if (!enableAutoLongPressSpeed) {
longPressSpeed = await videoStorage.get(VideoBoxKey.longPressSpeedDefault,
defaultValue: 2.0);
} else {
longPressSpeed = 2.0;
}
speedsList = List<double>.from(await videoStorage
.get(VideoBoxKey.customSpeedsList, defaultValue: <double>[]));
final List<double> playSpeedSystem = await videoStorage
.get(VideoBoxKey.playSpeedSystem, defaultValue: playSpeed);
speedsList.addAll(playSpeedSystem);
userInfo = userInfoCache.get('userInfoCache');
}
}

View File

@ -2,8 +2,6 @@ import 'dart:io';
import 'package:hive_flutter/hive_flutter.dart'; import 'package:hive_flutter/hive_flutter.dart';
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
import 'package:pilipala/models/user/info.dart'; import 'package:pilipala/models/user/info.dart';
import '../models/common/gesture_mode.dart';
import 'global_data.dart';
class GStrorage { class GStrorage {
static late final Box<dynamic> userInfo; static late final Box<dynamic> userInfo;
@ -42,13 +40,6 @@ class GStrorage {
); );
// 视频设置 // 视频设置
video = await Hive.openBox('video'); video = await Hive.openBox('video');
GlobalData().imgQuality =
setting.get(SettingBoxKey.defaultPicQa, defaultValue: 10); // 设置全局变量
GlobalData().fullScreenGestureMode = FullScreenGestureMode.values[
setting.get(SettingBoxKey.fullScreenGestureMode,
defaultValue: FullScreenGestureMode.values.last.index) as int];
GlobalData().enablePlayerControlAnimation = setting
.get(SettingBoxKey.enablePlayerControlAnimation, defaultValue: true);
} }
static void regAdapter() { static void regAdapter() {