Merge branch 'main' into design
This commit is contained in:
@ -1,5 +1,6 @@
|
||||
import UIKit
|
||||
import Flutter
|
||||
import AVFoundation
|
||||
|
||||
@UIApplicationMain
|
||||
@objc class AppDelegate: FlutterAppDelegate {
|
||||
@ -8,6 +9,14 @@ import Flutter
|
||||
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
|
||||
) -> Bool {
|
||||
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)
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@ import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hive/hive.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 '../constants.dart';
|
||||
|
||||
@ -33,7 +33,7 @@ class NetworkImgLayer extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final int defaultImgQuality = GlobalData().imgQuality;
|
||||
final int defaultImgQuality = GlobalDataCache().imgQuality;
|
||||
if (src == '' || src == null) {
|
||||
return placeholder(context);
|
||||
}
|
||||
|
@ -571,4 +571,8 @@ class Api {
|
||||
|
||||
/// 直播间发送弹幕
|
||||
static const String sendLiveMsg = '${HttpString.liveBaseUrl}/msg/send';
|
||||
|
||||
/// 我的关注 - 正在直播
|
||||
static const String getFollowingLive =
|
||||
'${HttpString.liveBaseUrl}/xlive/web-ucenter/user/following';
|
||||
}
|
||||
|
@ -46,7 +46,8 @@ class ApiInterceptor extends Interceptor {
|
||||
// 处理网络请求错误
|
||||
// handler.next(err);
|
||||
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(
|
||||
await dioError(err),
|
||||
displayType: SmartToastType.onlyRefresh,
|
||||
|
@ -1,3 +1,5 @@
|
||||
import 'package:pilipala/models/live/follow.dart';
|
||||
|
||||
import '../models/live/item.dart';
|
||||
import '../models/live/room_info.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'],
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ import 'package:pilipala/pages/main/view.dart';
|
||||
import 'package:pilipala/services/service_locator.dart';
|
||||
import 'package:pilipala/utils/app_scheme.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:media_kit/media_kit.dart';
|
||||
import 'package:pilipala/utils/recommend_filter.dart';
|
||||
@ -33,7 +33,6 @@ void main() async {
|
||||
await SystemChrome.setPreferredOrientations(
|
||||
[DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]);
|
||||
await GStrorage.init();
|
||||
await setupServiceLocator();
|
||||
clearLogs();
|
||||
Request();
|
||||
await Request.setCookie();
|
||||
@ -65,6 +64,7 @@ void main() async {
|
||||
}
|
||||
|
||||
PiliSchame.init();
|
||||
await GlobalDataCache().initialize();
|
||||
}
|
||||
|
||||
class MyApp extends StatelessWidget {
|
||||
@ -266,10 +266,10 @@ class BuildMainApp extends StatelessWidget {
|
||||
VideoDetailPage.routeObserver,
|
||||
SearchPage.routeObserver,
|
||||
],
|
||||
onInit: () {
|
||||
onReady: () async {
|
||||
RecommendFilter();
|
||||
Data.init();
|
||||
GlobalData();
|
||||
setupServiceLocator();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
126
lib/models/live/follow.dart
Normal file
126
lib/models/live/follow.dart
Normal 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'];
|
||||
}
|
||||
}
|
@ -1,11 +1,13 @@
|
||||
class RoomInfoModel {
|
||||
RoomInfoModel({
|
||||
this.roomId,
|
||||
this.isPortrait,
|
||||
this.liveStatus,
|
||||
this.liveTime,
|
||||
this.playurlInfo,
|
||||
});
|
||||
int? roomId;
|
||||
bool? isPortrait;
|
||||
int? liveStatus;
|
||||
int? liveTime;
|
||||
PlayurlInfo? playurlInfo;
|
||||
@ -13,6 +15,7 @@ class RoomInfoModel {
|
||||
RoomInfoModel.fromJson(Map<String, dynamic> json) {
|
||||
roomId = json['room_id'];
|
||||
liveStatus = json['live_status'];
|
||||
isPortrait = json['is_portrait'];
|
||||
liveTime = json['live_time'];
|
||||
playurlInfo = PlayurlInfo.fromJson(json['playurl_info']);
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ class FollowSearchController extends GetxController {
|
||||
return {'status': true, 'data': <FollowItemModel>[].obs};
|
||||
}
|
||||
if (type == 'init') {
|
||||
ps = 1;
|
||||
pn = 1;
|
||||
}
|
||||
var res = await MemberHttp.getfollowSearch(
|
||||
mid: mid,
|
||||
|
@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:pilipala/http/live.dart';
|
||||
import 'package:pilipala/models/live/follow.dart';
|
||||
import 'package:pilipala/models/live/item.dart';
|
||||
import 'package:pilipala/utils/storage.dart';
|
||||
|
||||
@ -11,6 +12,8 @@ class LiveController extends GetxController {
|
||||
int _currentPage = 1;
|
||||
RxInt crossAxisCount = 2.obs;
|
||||
RxList<LiveItemModel> liveList = <LiveItemModel>[].obs;
|
||||
RxList<LiveFollowingItemModel> liveFollowingList =
|
||||
<LiveFollowingItemModel>[].obs;
|
||||
bool flag = false;
|
||||
OverlayEntry? popupDialog;
|
||||
Box setting = GStrorage.setting;
|
||||
@ -44,6 +47,7 @@ class LiveController extends GetxController {
|
||||
// 下拉刷新
|
||||
Future onRefresh() async {
|
||||
queryLiveList('init');
|
||||
fetchLiveFollowing();
|
||||
}
|
||||
|
||||
// 上拉加载
|
||||
@ -61,4 +65,17 @@ class LiveController extends GetxController {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,8 @@ import 'package:get/get.dart';
|
||||
import 'package:pilipala/common/constants.dart';
|
||||
import 'package:pilipala/common/skeleton/video_card_v.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 'controller.dart';
|
||||
@ -22,6 +24,7 @@ class _LivePageState extends State<LivePage>
|
||||
with AutomaticKeepAliveClientMixin {
|
||||
final LiveController _liveController = Get.put(LiveController());
|
||||
late Future _futureBuilderFuture;
|
||||
late Future _futureBuilderFuture2;
|
||||
late ScrollController scrollController;
|
||||
|
||||
@override
|
||||
@ -31,6 +34,7 @@ class _LivePageState extends State<LivePage>
|
||||
void initState() {
|
||||
super.initState();
|
||||
_futureBuilderFuture = _liveController.queryLiveList('init');
|
||||
_futureBuilderFuture2 = _liveController.fetchLiveFollowing();
|
||||
scrollController = _liveController.scrollController;
|
||||
scrollController.addListener(
|
||||
() {
|
||||
@ -69,6 +73,7 @@ class _LivePageState extends State<LivePage>
|
||||
child: CustomScrollView(
|
||||
controller: _liveController.scrollController,
|
||||
slivers: [
|
||||
buildFollowingList(),
|
||||
SliverPadding(
|
||||
// 单列布局 EdgeInsets.zero
|
||||
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,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -48,6 +48,7 @@ class LiveRoomController extends GetxController {
|
||||
// 直播间弹幕开关 默认打开
|
||||
RxBool danmakuSwitch = true.obs;
|
||||
late String buvid;
|
||||
RxBool isPortrait = false.obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
@ -58,11 +59,12 @@ class LiveRoomController extends GetxController {
|
||||
if (Get.arguments != null) {
|
||||
liveItem = Get.arguments['liveItem'];
|
||||
heroTag = Get.arguments['heroTag'] ?? '';
|
||||
if (liveItem != null && liveItem.pic != null && liveItem.pic != '') {
|
||||
cover = liveItem.pic;
|
||||
}
|
||||
if (liveItem != null && liveItem.cover != null && liveItem.cover != '') {
|
||||
cover = liveItem.cover;
|
||||
if (liveItem != null) {
|
||||
cover = (liveItem.pic != null && liveItem.pic != '')
|
||||
? liveItem.pic
|
||||
: (liveItem.cover != null && liveItem.cover != '')
|
||||
? liveItem.cover
|
||||
: null;
|
||||
}
|
||||
Request.getBuvid().then((value) => buvid = value);
|
||||
}
|
||||
@ -100,6 +102,7 @@ class LiveRoomController extends GetxController {
|
||||
Future queryLiveInfo() async {
|
||||
var res = await LiveHttp.liveRoomInfo(roomId: roomId, qn: currentQn);
|
||||
if (res['status']) {
|
||||
isPortrait.value = res['data'].isPortrait;
|
||||
List<CodecItem> codec =
|
||||
res['data'].playurlInfo.playurl.stream.first.format.first.codec;
|
||||
CodecItem item = codec.first;
|
||||
|
@ -115,6 +115,9 @@ class _LiveRoomPageState extends State<LiveRoomPage>
|
||||
plPlayerController = _liveRoomController.plPlayerController;
|
||||
return PLVideoPlayer(
|
||||
controller: plPlayerController,
|
||||
alignment: _liveRoomController.isPortrait.value
|
||||
? Alignment.topCenter
|
||||
: Alignment.center,
|
||||
bottomControl: BottomControl(
|
||||
controller: plPlayerController,
|
||||
liveRoomCtr: _liveRoomController,
|
||||
@ -178,10 +181,83 @@ class _LiveRoomPageState extends State<LiveRoomPage>
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
AppBar(
|
||||
Obx(
|
||||
() => SizedBox(
|
||||
height: MediaQuery.of(context).padding.top +
|
||||
(_liveRoomController.isPortrait.value ||
|
||||
MediaQuery.of(context).orientation ==
|
||||
Orientation.landscape
|
||||
? 0
|
||||
: kToolbarHeight),
|
||||
),
|
||||
),
|
||||
PopScope(
|
||||
canPop: plPlayerController.isFullScreen.value != true,
|
||||
onPopInvoked: (bool didPop) {
|
||||
if (plPlayerController.isFullScreen.value == true) {
|
||||
plPlayerController.triggerFullScreen(status: false);
|
||||
}
|
||||
if (MediaQuery.of(context).orientation ==
|
||||
Orientation.landscape) {
|
||||
verticalScreen();
|
||||
}
|
||||
},
|
||||
child: Obx(
|
||||
() => Container(
|
||||
width: Get.size.width,
|
||||
height: MediaQuery.of(context).orientation ==
|
||||
Orientation.landscape
|
||||
? Get.size.height
|
||||
: !_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,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
// 定位 快速滑动到底部
|
||||
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,
|
||||
@ -213,8 +289,8 @@ class _LiveRoomPageState extends State<LiveRoomPage>
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
_liveRoomController.roomInfoH5.value
|
||||
.anchorInfo!.baseInfo!.uname!,
|
||||
_liveRoomController.roomInfoH5.value.anchorInfo!
|
||||
.baseInfo!.uname!,
|
||||
style: const TextStyle(fontSize: 14),
|
||||
),
|
||||
const SizedBox(height: 1),
|
||||
@ -238,77 +314,33 @@ class _LiveRoomPageState extends State<LiveRoomPage>
|
||||
},
|
||||
),
|
||||
),
|
||||
PopScope(
|
||||
canPop: plPlayerController.isFullScreen.value != true,
|
||||
onPopInvoked: (bool didPop) {
|
||||
if (plPlayerController.isFullScreen.value == true) {
|
||||
plPlayerController.triggerFullScreen(status: false);
|
||||
}
|
||||
if (MediaQuery.of(context).orientation ==
|
||||
Orientation.landscape) {
|
||||
verticalScreen();
|
||||
}
|
||||
},
|
||||
child: SizedBox(
|
||||
width: Get.size.width,
|
||||
height: MediaQuery.of(context).orientation ==
|
||||
Orientation.landscape
|
||||
? Get.size.height
|
||||
: Get.size.width * 9 / 16,
|
||||
child: videoPlayerPanel,
|
||||
),
|
||||
),
|
||||
// 显示消息的列表
|
||||
buildMessageListUI(
|
||||
// 消息列表
|
||||
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,
|
||||
_liveRoomController,
|
||||
_scrollController,
|
||||
),
|
||||
// Container(
|
||||
// padding: const EdgeInsets.only(
|
||||
// left: 14, right: 14, top: 4, bottom: 4),
|
||||
// margin: const EdgeInsets.only(
|
||||
// bottom: 6,
|
||||
// left: 14,
|
||||
// ),
|
||||
// decoration: BoxDecoration(
|
||||
// color: Colors.grey.withOpacity(0.1),
|
||||
// borderRadius: const BorderRadius.all(Radius.circular(20)),
|
||||
// ),
|
||||
// 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(
|
||||
),
|
||||
),
|
||||
// 消息输入框
|
||||
Visibility(
|
||||
visible: MediaQuery.of(context).orientation == Orientation.portrait,
|
||||
child: Positioned(
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(
|
||||
left: 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,
|
||||
child: Container(
|
||||
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)),
|
||||
),
|
||||
margin: EdgeInsets.only(
|
||||
|
@ -10,7 +10,6 @@ import 'package:pilipala/pages/media/index.dart';
|
||||
import 'package:pilipala/pages/rank/index.dart';
|
||||
import 'package:pilipala/utils/event_bus.dart';
|
||||
import 'package:pilipala/utils/feed_back.dart';
|
||||
import 'package:pilipala/utils/global_data.dart';
|
||||
import 'package:pilipala/utils/storage.dart';
|
||||
import './controller.dart';
|
||||
|
||||
@ -30,6 +29,7 @@ class _MainAppState extends State<MainApp> with SingleTickerProviderStateMixin {
|
||||
|
||||
int? _lastSelectTime; //上次点击时间
|
||||
Box setting = GStrorage.setting;
|
||||
late bool enableMYBar;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@ -37,6 +37,7 @@ class _MainAppState extends State<MainApp> with SingleTickerProviderStateMixin {
|
||||
_lastSelectTime = DateTime.now().millisecondsSinceEpoch;
|
||||
_mainController.pageController =
|
||||
PageController(initialPage: _mainController.selectedIndex);
|
||||
enableMYBar = setting.get(SettingBoxKey.enableMYBar, defaultValue: true);
|
||||
}
|
||||
|
||||
void setIndex(int value) async {
|
||||
@ -171,7 +172,7 @@ class _MainAppState extends State<MainApp> with SingleTickerProviderStateMixin {
|
||||
curve: Curves.easeInOutCubicEmphasized,
|
||||
duration: const Duration(milliseconds: 500),
|
||||
offset: Offset(0, snapshot.data ? 0 : 1),
|
||||
child: GlobalData().enableMYBar
|
||||
child: enableMYBar
|
||||
? Obx(
|
||||
() => NavigationBar(
|
||||
onDestinationSelected: (value) => setIndex(value),
|
||||
|
@ -406,7 +406,7 @@ class _MemberPageState extends State<MemberPage>
|
||||
? '个人认证:'
|
||||
: '企业认证:',
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).primaryColor,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
children: [
|
||||
TextSpan(
|
||||
|
@ -27,10 +27,13 @@ class MemberArchiveController extends GetxController {
|
||||
|
||||
// 获取用户投稿
|
||||
Future getMemberArchive(type) async {
|
||||
if (isLoading.value) {
|
||||
return;
|
||||
}
|
||||
isLoading.value = true;
|
||||
if (type == 'init') {
|
||||
pn = 1;
|
||||
archivesList.clear();
|
||||
isLoading.value = true;
|
||||
}
|
||||
var res = await MemberHttp.memberArchive(
|
||||
mid: mid,
|
||||
|
@ -21,7 +21,7 @@ class MemberSeasonsController extends GetxController {
|
||||
mid = int.parse(Get.parameters['mid']!);
|
||||
category = Get.parameters['category']!;
|
||||
if (category == '0') {
|
||||
seasonId = int.parse(Get.parameters['seriesId']!);
|
||||
seasonId = int.parse(Get.parameters['seasonId']!);
|
||||
}
|
||||
if (category == '1') {
|
||||
seriesId = int.parse(Get.parameters['seriesId']!);
|
||||
|
@ -203,9 +203,9 @@ class LikeItem extends StatelessWidget {
|
||||
Text.rich(TextSpan(children: [
|
||||
TextSpan(text: nickNameList.join('、')),
|
||||
const TextSpan(text: ' '),
|
||||
if (item.users!.length > 1)
|
||||
if (item.counts! > 1)
|
||||
TextSpan(
|
||||
text: '等总计${item.users!.length}人',
|
||||
text: '等总计${item.counts}人',
|
||||
style: TextStyle(color: outline),
|
||||
),
|
||||
TextSpan(
|
||||
|
@ -261,13 +261,16 @@ class VideoPanelController extends GetxController {
|
||||
onShowFilterSheet(searchPanelCtr) {
|
||||
showModalBottomSheet(
|
||||
context: Get.context!,
|
||||
isScrollControlled: true,
|
||||
builder: (context) {
|
||||
return StatefulBuilder(
|
||||
builder: (context, StateSetter setState) {
|
||||
return Container(
|
||||
color: Theme.of(Get.context!).colorScheme.surface,
|
||||
padding: const EdgeInsets.only(top: 12),
|
||||
child: Column(
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(
|
||||
top: 12, bottom: MediaQuery.of(context).padding.bottom + 20),
|
||||
child: Wrap(
|
||||
children: [
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const ListTile(
|
||||
@ -295,9 +298,10 @@ class VideoPanelController extends GetxController {
|
||||
onSelect: (value) async {
|
||||
currentTimeFilterval.value = i['value'];
|
||||
setState(() {});
|
||||
SmartDialog.showToast("「${i['label']}」的筛选结果");
|
||||
SearchPanelController ctr =
|
||||
Get.find<SearchPanelController>(
|
||||
SmartDialog.showToast(
|
||||
"「${i['label']}」的筛选结果");
|
||||
SearchPanelController ctr = Get.find<
|
||||
SearchPanelController>(
|
||||
tag: 'video${searchPanelCtr.keyword!}');
|
||||
ctr.duration.value = i['value'];
|
||||
Get.back();
|
||||
@ -326,13 +330,14 @@ class VideoPanelController extends GetxController {
|
||||
SearchText(
|
||||
searchText: i['label'],
|
||||
searchTextIdx: i['value'],
|
||||
isSelect: currentPartFilterval.value == i['value'],
|
||||
isSelect:
|
||||
currentPartFilterval.value == i['value'],
|
||||
onSelect: (value) async {
|
||||
currentPartFilterval.value = i['value'];
|
||||
setState(() {});
|
||||
SmartDialog.showToast("「${i['label']}」的筛选结果");
|
||||
SearchPanelController ctr =
|
||||
Get.find<SearchPanelController>(
|
||||
SearchPanelController ctr = Get.find<
|
||||
SearchPanelController>(
|
||||
tag: 'video${searchPanelCtr.keyword!}');
|
||||
ctr.tids.value = i['value'];
|
||||
Get.back();
|
||||
@ -347,6 +352,8 @@ class VideoPanelController extends GetxController {
|
||||
)
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
import 'package:hive/hive.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';
|
||||
|
||||
class ActionMenuSetPage extends StatefulWidget {
|
||||
@ -38,7 +38,7 @@ class _ActionMenuSetPageState extends State<ActionMenuSetPage> {
|
||||
.map<String>((i) => (i['value'] as ActionType).value)
|
||||
.toList();
|
||||
setting.put(SettingBoxKey.actionTypeSort, sortedTabbar);
|
||||
GlobalData().actionTypeSort = sortedTabbar;
|
||||
GlobalDataCache().actionTypeSort = sortedTabbar;
|
||||
SmartDialog.showToast('操作成功');
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import 'package:flutter/material.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 '../../../utils/storage.dart';
|
||||
@ -64,11 +64,11 @@ class _PlayGesturePageState extends State<PlayGesturePage> {
|
||||
},
|
||||
);
|
||||
if (result != null) {
|
||||
GlobalData().fullScreenGestureMode = FullScreenGestureMode
|
||||
GlobalDataCache().fullScreenGestureMode = FullScreenGestureMode
|
||||
.values
|
||||
.firstWhere((element) => element.values == result);
|
||||
fullScreenGestureMode =
|
||||
GlobalData().fullScreenGestureMode.index;
|
||||
GlobalDataCache().fullScreenGestureMode.index;
|
||||
setting.put(
|
||||
SettingBoxKey.fullScreenGestureMode, fullScreenGestureMode);
|
||||
setState(() {});
|
||||
|
@ -9,7 +9,7 @@ import 'package:pilipala/models/video/play/quality.dart';
|
||||
import 'package:pilipala/pages/setting/widgets/select_dialog.dart';
|
||||
import 'package:pilipala/plugin/pl_player/index.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 '../../models/live/quality.dart';
|
||||
@ -162,7 +162,7 @@ class _PlaySettingState extends State<PlaySetting> {
|
||||
setKey: SettingBoxKey.enablePlayerControlAnimation,
|
||||
defaultVal: true,
|
||||
callFn: (bool val) {
|
||||
GlobalData().enablePlayerControlAnimation = val;
|
||||
GlobalDataCache().enablePlayerControlAnimation = val;
|
||||
}),
|
||||
SetSwitchItem(
|
||||
title: '港澳台模式',
|
||||
|
@ -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/widgets/select_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 '../../models/common/dynamic_badge_mode.dart';
|
||||
@ -176,7 +176,7 @@ class _StyleSettingState extends State<StyleSetting> {
|
||||
SettingBoxKey.defaultPicQa, picQuality);
|
||||
Get.back();
|
||||
settingController.picQuality.value = picQuality;
|
||||
GlobalData().imgQuality = picQuality;
|
||||
GlobalDataCache().imgQuality = picQuality;
|
||||
SmartDialog.showToast('设置成功');
|
||||
},
|
||||
child: const Text('确定'),
|
||||
|
@ -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/widgets/ai_detail.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/utils.dart';
|
||||
import '../../../../http/user.dart';
|
||||
@ -570,7 +570,7 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
|
||||
}
|
||||
|
||||
Widget actionGrid(BuildContext context, videoIntroController) {
|
||||
final actionTypeSort = GlobalData().actionTypeSort;
|
||||
final actionTypeSort = GlobalDataCache().actionTypeSort;
|
||||
|
||||
Widget progressWidget(progress) {
|
||||
return SizedBox(
|
||||
|
@ -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/services/service_locator.dart';
|
||||
import 'package:pilipala/utils/feed_back.dart';
|
||||
import 'package:pilipala/utils/global_data_cache.dart';
|
||||
import 'package:pilipala/utils/storage.dart';
|
||||
import 'package:screen_brightness/screen_brightness.dart';
|
||||
import 'package:status_bar_control/status_bar_control.dart';
|
||||
@ -277,50 +278,19 @@ class PlPlayerController {
|
||||
|
||||
// 添加一个私有构造函数
|
||||
PlPlayerController._internal(this.videoType) {
|
||||
isOpenDanmu.value =
|
||||
setting.get(SettingBoxKey.enableShowDanmaku, defaultValue: false);
|
||||
blockTypes =
|
||||
localCache.get(LocalCacheKey.danmakuBlockType, defaultValue: []);
|
||||
showArea = localCache.get(LocalCacheKey.danmakuShowArea, defaultValue: 0.5);
|
||||
// 不透明度
|
||||
opacityVal =
|
||||
localCache.get(LocalCacheKey.danmakuOpacity, defaultValue: 1.0);
|
||||
// 字体大小
|
||||
fontSizeVal =
|
||||
localCache.get(LocalCacheKey.danmakuFontScale, defaultValue: 1.0);
|
||||
// 弹幕时间
|
||||
danmakuDurationVal =
|
||||
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);
|
||||
// }
|
||||
|
||||
final cache = GlobalDataCache();
|
||||
isOpenDanmu.value = cache.isOpenDanmu;
|
||||
blockTypes = cache.blockTypes;
|
||||
showArea = cache.showArea;
|
||||
opacityVal = cache.opacityVal;
|
||||
fontSizeVal = cache.fontSizeVal;
|
||||
danmakuDurationVal = cache.danmakuDurationVal;
|
||||
strokeWidth = cache.strokeWidth;
|
||||
playRepeat = cache.playRepeat;
|
||||
_playbackSpeed.value = cache.playbackSpeed;
|
||||
enableAutoLongPressSpeed = cache.enableAutoLongPressSpeed;
|
||||
_longPressSpeed.value = cache.longPressSpeed;
|
||||
speedsList = cache.speedsList;
|
||||
// _playerEventSubs = onPlayerStatusChanged.listen((PlayerStatus status) {
|
||||
// if (status == PlayerStatus.playing) {
|
||||
// WakelockPlus.enable();
|
||||
|
@ -19,7 +19,7 @@ import 'package:pilipala/utils/feed_back.dart';
|
||||
import 'package:pilipala/utils/storage.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_progress_behavior.dart';
|
||||
import 'widgets/app_bar_ani.dart';
|
||||
@ -41,6 +41,7 @@ class PLVideoPlayer extends StatefulWidget {
|
||||
this.customWidgets,
|
||||
this.showEposideCb,
|
||||
this.fullScreenCb,
|
||||
this.alignment = Alignment.center,
|
||||
super.key,
|
||||
});
|
||||
|
||||
@ -55,6 +56,7 @@ class PLVideoPlayer extends StatefulWidget {
|
||||
final List<Widget>? customWidgets;
|
||||
final Function? showEposideCb;
|
||||
final Function? fullScreenCb;
|
||||
final Alignment? alignment;
|
||||
|
||||
@override
|
||||
State<PLVideoPlayer> createState() => _PLVideoPlayerState();
|
||||
@ -88,7 +90,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
late bool enableBackgroundPlay;
|
||||
late double screenWidth;
|
||||
final FullScreenGestureMode fullScreenGestureMode =
|
||||
GlobalData().fullScreenGestureMode;
|
||||
GlobalDataCache().fullScreenGestureMode;
|
||||
|
||||
// 用于记录上一次全屏切换手势触发时间,避免误触
|
||||
DateTime? lastFullScreenToggleTime;
|
||||
@ -133,7 +135,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
screenWidth = Get.size.width;
|
||||
animationController = AnimationController(
|
||||
vsync: this,
|
||||
duration: GlobalData().enablePlayerControlAnimation
|
||||
duration: GlobalDataCache().enablePlayerControlAnimation
|
||||
? const Duration(milliseconds: 150)
|
||||
: const Duration(milliseconds: 10),
|
||||
);
|
||||
@ -393,6 +395,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
key: ValueKey(_.videoFit.value),
|
||||
controller: videoController,
|
||||
controls: NoVideoControls,
|
||||
alignment: widget.alignment!,
|
||||
pauseUponEnteringBackgroundMode: !enableBackgroundPlay,
|
||||
resumeUponEnteringForegroundMode: true,
|
||||
subtitleViewConfiguration: const SubtitleViewConfiguration(
|
||||
|
@ -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;
|
||||
}
|
106
lib/utils/global_data_cache.dart
Normal file
106
lib/utils/global_data_cache.dart
Normal 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');
|
||||
}
|
||||
}
|
@ -2,8 +2,6 @@ import 'dart:io';
|
||||
import 'package:hive_flutter/hive_flutter.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:pilipala/models/user/info.dart';
|
||||
import '../models/common/gesture_mode.dart';
|
||||
import 'global_data.dart';
|
||||
|
||||
class GStrorage {
|
||||
static late final Box<dynamic> userInfo;
|
||||
@ -42,13 +40,6 @@ class GStrorage {
|
||||
);
|
||||
// 视频设置
|
||||
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() {
|
||||
|
Reference in New Issue
Block a user