Compare commits
7 Commits
design
...
feature-me
Author | SHA1 | Date | |
---|---|---|---|
b689db16b5 | |||
5cb3e578a8 | |||
8f9fbf5d41 | |||
76784ee664 | |||
2dbef3fee2 | |||
3a66c8c03d | |||
6f62837495 |
@ -34,7 +34,6 @@ void main() async {
|
||||
.then((_) async {
|
||||
await GStrorage.init();
|
||||
await setupServiceLocator();
|
||||
clearLogs();
|
||||
Request();
|
||||
await Request.setCookie();
|
||||
RecommendFilter();
|
||||
|
@ -47,23 +47,18 @@ class Vip {
|
||||
this.status,
|
||||
this.dueDate,
|
||||
this.label,
|
||||
this.nicknameColor,
|
||||
});
|
||||
|
||||
int? type;
|
||||
int? status;
|
||||
int? dueDate;
|
||||
Map? label;
|
||||
int? nicknameColor;
|
||||
|
||||
Vip.fromJson(Map<String, dynamic> json) {
|
||||
type = json['type'];
|
||||
status = json['status'];
|
||||
dueDate = json['due_date'];
|
||||
label = json['label'];
|
||||
nicknameColor = json['nickname_color'] == ''
|
||||
? null
|
||||
: int.parse("0xFF${json['nickname_color'].replaceAll('#', '')}");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -281,8 +281,8 @@ class _MemberPageState extends State<MemberPage>
|
||||
future: _futureBuilderFuture,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.done) {
|
||||
Map? data = snapshot.data;
|
||||
if (data != null && data['status']) {
|
||||
Map data = snapshot.data!;
|
||||
if (data['status']) {
|
||||
return Obx(
|
||||
() => Stack(
|
||||
alignment: AlignmentDirectional.center,
|
||||
@ -302,14 +302,7 @@ class _MemberPageState extends State<MemberPage>
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.titleMedium!
|
||||
.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: _memberController.memberInfo.value
|
||||
.vip!.nicknameColor !=
|
||||
null
|
||||
? Color(_memberController.memberInfo
|
||||
.value.vip!.nicknameColor!)
|
||||
: null),
|
||||
.copyWith(fontWeight: FontWeight.bold),
|
||||
)),
|
||||
const SizedBox(width: 2),
|
||||
if (_memberController.memberInfo.value.sex == '女')
|
||||
|
@ -18,32 +18,45 @@ class MemberSeasonsPanel extends StatelessWidget {
|
||||
itemBuilder: (context, index) {
|
||||
MemberSeasonsList item = data!.seasonsList![index];
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 12),
|
||||
padding: const EdgeInsets.only(bottom: 12, right: 4),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
ListTile(
|
||||
onTap: () => Get.toNamed(
|
||||
'/memberSeasons?mid=${item.meta!.mid}&seasonId=${item.meta!.seasonId}'),
|
||||
title: Text(
|
||||
item.meta!.name!,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: Theme.of(context).textTheme.titleSmall!,
|
||||
),
|
||||
dense: true,
|
||||
leading: PBadge(
|
||||
stack: 'relative',
|
||||
size: 'small',
|
||||
text: item.meta!.total.toString(),
|
||||
),
|
||||
trailing: const Icon(
|
||||
Icons.arrow_forward,
|
||||
size: 20,
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 12, left: 4),
|
||||
child: Row(
|
||||
children: [
|
||||
Text(
|
||||
item.meta!.name!,
|
||||
maxLines: 1,
|
||||
style: Theme.of(context).textTheme.titleSmall!,
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
PBadge(
|
||||
stack: 'relative',
|
||||
size: 'small',
|
||||
text: item.meta!.total.toString(),
|
||||
),
|
||||
const Spacer(),
|
||||
SizedBox(
|
||||
width: 35,
|
||||
height: 35,
|
||||
child: IconButton(
|
||||
onPressed: () => Get.toNamed(
|
||||
'/memberSeasons?mid=${item.meta!.mid}&seasonId=${item.meta!.seasonId}'),
|
||||
style: ButtonStyle(
|
||||
padding: MaterialStateProperty.all(EdgeInsets.zero),
|
||||
),
|
||||
icon: const Icon(
|
||||
Icons.arrow_forward,
|
||||
size: 20,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
LayoutBuilder(
|
||||
builder: (context, boxConstraints) {
|
||||
return GridView.builder(
|
||||
|
@ -44,7 +44,6 @@ class _SelectDialogState<T> extends State<SelectDialog<T>> {
|
||||
setState(() {
|
||||
_tempValue = value as T;
|
||||
});
|
||||
Navigator.pop(context, _tempValue);
|
||||
},
|
||||
),
|
||||
]
|
||||
@ -52,6 +51,19 @@ class _SelectDialogState<T> extends State<SelectDialog<T>> {
|
||||
),
|
||||
);
|
||||
}),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
child: Text(
|
||||
'取消',
|
||||
style: TextStyle(color: Theme.of(context).colorScheme.outline),
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context, _tempValue),
|
||||
child: const Text('确定'),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
import 'package:expandable/expandable.dart';
|
||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:get/get.dart';
|
||||
@ -16,7 +17,6 @@ import 'package:pilipala/utils/feed_back.dart';
|
||||
import 'package:pilipala/utils/storage.dart';
|
||||
import 'package:pilipala/utils/utils.dart';
|
||||
import '../../../../http/user.dart';
|
||||
import '../widgets/expandable_section.dart';
|
||||
import 'widgets/action_item.dart';
|
||||
import 'widgets/fav_panel.dart';
|
||||
import 'widgets/intro_detail.dart';
|
||||
@ -140,6 +140,8 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
|
||||
late bool enableAi;
|
||||
bool isProcessing = false;
|
||||
RxBool isExpand = false.obs;
|
||||
late ExpandableController _expandableCtr;
|
||||
|
||||
void Function()? handleState(Future Function() action) {
|
||||
return isProcessing
|
||||
? null
|
||||
@ -163,6 +165,7 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
|
||||
follower = Utils.numFormat(videoIntroController.userStat['follower']);
|
||||
followStatus = videoIntroController.followStatus;
|
||||
enableAi = setting.get(SettingBoxKey.enableAi, defaultValue: true);
|
||||
_expandableCtr = ExpandableController(initialExpanded: false);
|
||||
}
|
||||
|
||||
// 收藏
|
||||
@ -216,6 +219,7 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
|
||||
showIntroDetail() {
|
||||
feedBack();
|
||||
isExpand.value = !(isExpand.value);
|
||||
_expandableCtr.toggle();
|
||||
}
|
||||
|
||||
// 用户主页
|
||||
@ -239,6 +243,12 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_expandableCtr.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final ThemeData t = Theme.of(context);
|
||||
@ -256,14 +266,34 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
|
||||
GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: () => showIntroDetail(),
|
||||
child: Text(
|
||||
widget.videoDetail!.title!,
|
||||
style: const TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
child: ExpandablePanel(
|
||||
controller: _expandableCtr,
|
||||
collapsed: Text(
|
||||
widget.videoDetail!.title!,
|
||||
softWrap: true,
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
expanded: Text(
|
||||
widget.videoDetail!.title!,
|
||||
softWrap: true,
|
||||
maxLines: 4,
|
||||
style: const TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
theme: const ExpandableThemeData(
|
||||
animationDuration: Duration(milliseconds: 300),
|
||||
scrollAnimationDuration: Duration(milliseconds: 300),
|
||||
crossFadePoint: 0,
|
||||
fadeCurve: Curves.ease,
|
||||
sizeCurve: Curves.linear,
|
||||
),
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
Stack(
|
||||
@ -328,12 +358,16 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
|
||||
),
|
||||
|
||||
/// 视频简介
|
||||
Obx(
|
||||
() => ExpandedSection(
|
||||
expand: isExpand.value,
|
||||
begin: 0,
|
||||
end: 1,
|
||||
child: IntroDetail(videoDetail: widget.videoDetail!),
|
||||
ExpandablePanel(
|
||||
controller: _expandableCtr,
|
||||
collapsed: const SizedBox(height: 0),
|
||||
expanded: IntroDetail(videoDetail: widget.videoDetail!),
|
||||
theme: const ExpandableThemeData(
|
||||
animationDuration: Duration(milliseconds: 300),
|
||||
scrollAnimationDuration: Duration(milliseconds: 300),
|
||||
crossFadePoint: 0,
|
||||
fadeCurve: Curves.ease,
|
||||
sizeCurve: Curves.linear,
|
||||
),
|
||||
),
|
||||
|
||||
|
@ -393,7 +393,13 @@ class PlPlayerController {
|
||||
}
|
||||
// 配置Player 音轨、字幕等等
|
||||
_videoPlayerController = await _createVideoController(
|
||||
dataSource, _looping, enableHA, width, height);
|
||||
dataSource,
|
||||
_looping,
|
||||
enableHA,
|
||||
width,
|
||||
height,
|
||||
seekTo,
|
||||
);
|
||||
// 获取视频时长 00:00
|
||||
_duration.value = duration ?? _videoPlayerController!.state.duration;
|
||||
updateDurationSecond();
|
||||
@ -404,7 +410,7 @@ class PlPlayerController {
|
||||
if (!_listenersInitialized) {
|
||||
startListeners();
|
||||
}
|
||||
await _initializePlayer(seekTo: seekTo, duration: _duration.value);
|
||||
await _initializePlayer(duration: _duration.value);
|
||||
bool autoEnterFullcreen =
|
||||
setting.get(SettingBoxKey.enableAutoEnter, defaultValue: false);
|
||||
if (autoEnterFullcreen && _isFirstTime) {
|
||||
@ -424,6 +430,7 @@ class PlPlayerController {
|
||||
bool enableHA,
|
||||
double? width,
|
||||
double? height,
|
||||
Duration? seekTo,
|
||||
) async {
|
||||
// 每次配置时先移除监听
|
||||
removeListeners();
|
||||
@ -506,7 +513,11 @@ class PlPlayerController {
|
||||
);
|
||||
}
|
||||
player.open(
|
||||
Media(dataSource.videoSource!, httpHeaders: dataSource.httpHeaders),
|
||||
Media(
|
||||
dataSource.videoSource!,
|
||||
httpHeaders: dataSource.httpHeaders,
|
||||
start: seekTo ?? Duration.zero,
|
||||
),
|
||||
play: false,
|
||||
);
|
||||
// 音轨
|
||||
@ -519,7 +530,6 @@ class PlPlayerController {
|
||||
|
||||
// 开始播放
|
||||
Future _initializePlayer({
|
||||
Duration seekTo = Duration.zero,
|
||||
Duration? duration,
|
||||
}) async {
|
||||
// 设置倍速
|
||||
@ -537,11 +547,6 @@ class PlPlayerController {
|
||||
// await setLooping(_looping);
|
||||
// }
|
||||
|
||||
// 跳转播放
|
||||
if (seekTo != Duration.zero) {
|
||||
await this.seekTo(seekTo);
|
||||
}
|
||||
|
||||
// 自动播放
|
||||
if (_autoPlay) {
|
||||
await play(duration: duration);
|
||||
@ -661,21 +666,14 @@ class PlPlayerController {
|
||||
await _videoPlayerController?.stream.buffer.first;
|
||||
}
|
||||
await _videoPlayerController?.seek(position);
|
||||
// if (playerStatus.stopped) {
|
||||
// play();
|
||||
// }
|
||||
} else {
|
||||
print('seek duration else');
|
||||
_timerForSeek?.cancel();
|
||||
_timerForSeek =
|
||||
Timer.periodic(const Duration(milliseconds: 200), (Timer t) async {
|
||||
//_timerForSeek = null;
|
||||
if (duration.value.inSeconds != 0) {
|
||||
await _videoPlayerController!.stream.buffer.first;
|
||||
await _videoPlayerController?.seek(position);
|
||||
// if (playerStatus.status.value == PlayerStatus.paused) {
|
||||
// play();
|
||||
// }
|
||||
t.cancel();
|
||||
_timerForSeek = null;
|
||||
}
|
||||
|
@ -208,16 +208,14 @@ class Utils {
|
||||
|
||||
static int findClosestNumber(int target, List<int> numbers) {
|
||||
int minDiff = 127;
|
||||
int closestNumber = 0; // 初始化为0,表示没有找到比目标值小的整数
|
||||
late int closestNumber;
|
||||
try {
|
||||
for (int number in numbers) {
|
||||
if (number < target) {
|
||||
int diff = target - number; // 计算目标值与当前整数的差值
|
||||
int diff = (number - target).abs();
|
||||
|
||||
if (diff < minDiff) {
|
||||
minDiff = diff;
|
||||
closestNumber = number;
|
||||
}
|
||||
if (diff < minDiff) {
|
||||
minDiff = diff;
|
||||
closestNumber = number;
|
||||
}
|
||||
}
|
||||
} catch (_) {}
|
||||
|
35
pubspec.lock
35
pubspec.lock
@ -433,6 +433,14 @@ packages:
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "5.0.3"
|
||||
expandable:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: expandable
|
||||
sha256: "9604d612d4d1146dafa96c6d8eec9c2ff0994658d6d09fed720ab788c7f5afc2"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "5.0.1"
|
||||
extended_image:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -857,10 +865,11 @@ packages:
|
||||
media_kit:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: media_kit
|
||||
sha256: "3289062540e3b8b9746e5c50d95bd78a9289826b7227e253dff806d002b9e67a"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
path: media_kit
|
||||
ref: HEAD
|
||||
resolved-ref: "77a130b1d7ce733b47d2133b57563716090450d0"
|
||||
url: "https://github.com/media-kit/media-kit.git"
|
||||
source: git
|
||||
version: "1.1.10+1"
|
||||
media_kit_libs_android_video:
|
||||
dependency: transitive
|
||||
@ -897,10 +906,11 @@ packages:
|
||||
media_kit_libs_video:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: media_kit_libs_video
|
||||
sha256: "3688e0c31482074578652bf038ce6301a5d21e1eda6b54fc3117ffeb4bdba067"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
path: "libs/universal/media_kit_libs_video"
|
||||
ref: HEAD
|
||||
resolved-ref: "77a130b1d7ce733b47d2133b57563716090450d0"
|
||||
url: "https://github.com/media-kit/media-kit.git"
|
||||
source: git
|
||||
version: "1.0.4"
|
||||
media_kit_libs_windows_video:
|
||||
dependency: transitive
|
||||
@ -921,10 +931,11 @@ packages:
|
||||
media_kit_video:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: media_kit_video
|
||||
sha256: c048d11a19e379aebbe810647636e3fc6d18374637e2ae12def4ff8a4b99a882
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
path: media_kit_video
|
||||
ref: HEAD
|
||||
resolved-ref: "77a130b1d7ce733b47d2133b57563716090450d0"
|
||||
url: "https://github.com/media-kit/media-kit.git"
|
||||
source: git
|
||||
version: "1.2.4"
|
||||
meta:
|
||||
dependency: transitive
|
||||
|
16
pubspec.yaml
16
pubspec.yaml
@ -142,6 +142,8 @@ dependencies:
|
||||
path: 1.8.3
|
||||
# 电池优化
|
||||
disable_battery_optimization: ^1.1.1
|
||||
# 展开/收起
|
||||
expandable: ^5.0.1
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
@ -161,6 +163,20 @@ dev_dependencies:
|
||||
hive_generator: ^2.0.0
|
||||
build_runner: ^2.4.8
|
||||
|
||||
dependency_overrides:
|
||||
media_kit:
|
||||
git:
|
||||
url: https://github.com/media-kit/media-kit.git
|
||||
path: media_kit
|
||||
media_kit_video:
|
||||
git:
|
||||
url: https://github.com/media-kit/media-kit.git
|
||||
path: media_kit_video
|
||||
media_kit_libs_video:
|
||||
git:
|
||||
url: https://github.com/media-kit/media-kit.git
|
||||
path: libs/universal/media_kit_libs_video
|
||||
|
||||
flutter_launcher_icons:
|
||||
android: true
|
||||
ios: true
|
||||
|
Reference in New Issue
Block a user