Compare commits
18 Commits
v1.0.15.01
...
v1.0.16.01
Author | SHA1 | Date | |
---|---|---|---|
1f6663fa4a | |||
b1e9cd60cf | |||
b7389539d8 | |||
5d51b235e5 | |||
bc7aa8c0b2 | |||
69b2a76e0b | |||
65ab59fa35 | |||
6bdc687082 | |||
4ca021711e | |||
b3f418181d | |||
10a547d0c2 | |||
8d42409691 | |||
9ae0e9284b | |||
061d6e6091 | |||
9c30182480 | |||
c928037e08 | |||
10158a7022 | |||
f5a9a8ad68 |
15
change_log/1.0.16.0102.md
Normal file
15
change_log/1.0.16.0102.md
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
## 1.0.16
|
||||||
|
|
||||||
|
|
||||||
|
### 功能
|
||||||
|
+ toast 背景支持透明度调节
|
||||||
|
|
||||||
|
### 修复
|
||||||
|
+ web端推荐未展示【已关注】
|
||||||
|
+ up主动态页异常
|
||||||
|
+ 未打开自动播放时,视频详情页异常
|
||||||
|
+ 视频暂停状态取消自动ip
|
||||||
|
|
||||||
|
|
||||||
|
更多更新日志可在Github上查看
|
||||||
|
问题反馈、功能建议请查看「关于」页面。
|
@ -1,4 +1,8 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:hive/hive.dart';
|
||||||
|
import 'package:pilipala/utils/storage.dart';
|
||||||
|
|
||||||
|
Box setting = GStrorage.setting;
|
||||||
|
|
||||||
class CustomToast extends StatelessWidget {
|
class CustomToast extends StatelessWidget {
|
||||||
final String msg;
|
final String msg;
|
||||||
@ -6,12 +10,17 @@ class CustomToast extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
double toastOpacity =
|
||||||
|
setting.get(SettingBoxKey.defaultToastOp, defaultValue: 1.0);
|
||||||
return Container(
|
return Container(
|
||||||
margin:
|
margin:
|
||||||
EdgeInsets.only(bottom: MediaQuery.of(context).padding.bottom + 30),
|
EdgeInsets.only(bottom: MediaQuery.of(context).padding.bottom + 30),
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 17, vertical: 10),
|
padding: const EdgeInsets.symmetric(horizontal: 17, vertical: 10),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Theme.of(context).colorScheme.primaryContainer,
|
color: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.primaryContainer
|
||||||
|
.withOpacity(toastOpacity),
|
||||||
borderRadius: BorderRadius.circular(20),
|
borderRadius: BorderRadius.circular(20),
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
|
@ -266,6 +266,14 @@ class VideoContent extends StatelessWidget {
|
|||||||
fs: 9,
|
fs: 9,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
if (videoItem.isFollowed == 1) ...[
|
||||||
|
const PBadge(
|
||||||
|
text: '已关注',
|
||||||
|
stack: 'normal',
|
||||||
|
size: 'small',
|
||||||
|
type: 'color',
|
||||||
|
)
|
||||||
|
],
|
||||||
Expanded(
|
Expanded(
|
||||||
flex: crossAxisCount == 1 ? 0 : 1,
|
flex: crossAxisCount == 1 ? 0 : 1,
|
||||||
child: Text(
|
child: Text(
|
||||||
|
@ -57,14 +57,6 @@ class AuthorPanel extends StatelessWidget {
|
|||||||
fontSize: Theme.of(context).textTheme.titleSmall!.fontSize,
|
fontSize: Theme.of(context).textTheme.titleSmall!.fontSize,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (item.modules.moduleTag != null) ...[
|
|
||||||
const SizedBox(width: 6),
|
|
||||||
PBadge(
|
|
||||||
bottom: 10,
|
|
||||||
right: 10,
|
|
||||||
text: item.modules.moduleTag['text'],
|
|
||||||
)
|
|
||||||
]
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
DefaultTextStyle.merge(
|
DefaultTextStyle.merge(
|
||||||
|
@ -15,6 +15,7 @@ class SettingController extends GetxController {
|
|||||||
|
|
||||||
RxBool userLogin = false.obs;
|
RxBool userLogin = false.obs;
|
||||||
RxBool feedBackEnable = false.obs;
|
RxBool feedBackEnable = false.obs;
|
||||||
|
RxDouble toastOpacity = (1.0).obs;
|
||||||
RxInt picQuality = 10.obs;
|
RxInt picQuality = 10.obs;
|
||||||
Rx<ThemeType> themeType = ThemeType.system.obs;
|
Rx<ThemeType> themeType = ThemeType.system.obs;
|
||||||
var userInfo;
|
var userInfo;
|
||||||
@ -26,6 +27,8 @@ class SettingController extends GetxController {
|
|||||||
userLogin.value = userInfo != null;
|
userLogin.value = userInfo != null;
|
||||||
feedBackEnable.value =
|
feedBackEnable.value =
|
||||||
setting.get(SettingBoxKey.feedBackEnable, defaultValue: false);
|
setting.get(SettingBoxKey.feedBackEnable, defaultValue: false);
|
||||||
|
toastOpacity.value =
|
||||||
|
setting.get(SettingBoxKey.defaultToastOp, defaultValue: 1.0);
|
||||||
picQuality.value =
|
picQuality.value =
|
||||||
setting.get(SettingBoxKey.defaultPicQa, defaultValue: 10);
|
setting.get(SettingBoxKey.defaultPicQa, defaultValue: 10);
|
||||||
themeType.value = ThemeType.values[setting.get(SettingBoxKey.themeMode,
|
themeType.value = ThemeType.values[setting.get(SettingBoxKey.themeMode,
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
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';
|
||||||
@ -95,12 +97,13 @@ class _PlaySettingState extends State<PlaySetting> {
|
|||||||
setKey: SettingBoxKey.enableBackgroundPlay,
|
setKey: SettingBoxKey.enableBackgroundPlay,
|
||||||
defaultVal: false,
|
defaultVal: false,
|
||||||
),
|
),
|
||||||
const SetSwitchItem(
|
if (Platform.isAndroid)
|
||||||
title: '自动PiP播放',
|
const SetSwitchItem(
|
||||||
subTitle: '进入后台时画中画播放',
|
title: '自动PiP播放',
|
||||||
setKey: SettingBoxKey.autoPiP,
|
subTitle: '进入后台时画中画播放',
|
||||||
defaultVal: false,
|
setKey: SettingBoxKey.autoPiP,
|
||||||
),
|
defaultVal: false,
|
||||||
|
),
|
||||||
const SetSwitchItem(
|
const SetSwitchItem(
|
||||||
title: '自动全屏',
|
title: '自动全屏',
|
||||||
subTitle: '视频开始播放时进入全屏',
|
subTitle: '视频开始播放时进入全屏',
|
||||||
@ -154,9 +157,12 @@ class _PlaySettingState extends State<PlaySetting> {
|
|||||||
int? result = await showDialog(
|
int? result = await showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
return SelectDialog<int>(title: '默认画质', value: defaultVideoQa, values: VideoQuality.values.reversed.map((e) {
|
return SelectDialog<int>(
|
||||||
return {'title': e.description, 'value': e.code};
|
title: '默认画质',
|
||||||
}).toList());
|
value: defaultVideoQa,
|
||||||
|
values: VideoQuality.values.reversed.map((e) {
|
||||||
|
return {'title': e.description, 'value': e.code};
|
||||||
|
}).toList());
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
@ -177,9 +183,12 @@ class _PlaySettingState extends State<PlaySetting> {
|
|||||||
int? result = await showDialog(
|
int? result = await showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
return SelectDialog<int>(title: '默认音质', value: defaultAudioQa, values: AudioQuality.values.reversed.map((e) {
|
return SelectDialog<int>(
|
||||||
return {'title': e.description, 'value': e.code};
|
title: '默认音质',
|
||||||
}).toList());
|
value: defaultAudioQa,
|
||||||
|
values: AudioQuality.values.reversed.map((e) {
|
||||||
|
return {'title': e.description, 'value': e.code};
|
||||||
|
}).toList());
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
@ -200,9 +209,12 @@ class _PlaySettingState extends State<PlaySetting> {
|
|||||||
String? result = await showDialog(
|
String? result = await showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
return SelectDialog<String>(title: '默认解码格式', value: defaultDecode, values: VideoDecodeFormats.values.map((e) {
|
return SelectDialog<String>(
|
||||||
return {'title': e.description, 'value': e.code};
|
title: '默认解码格式',
|
||||||
}).toList());
|
value: defaultDecode,
|
||||||
|
values: VideoDecodeFormats.values.map((e) {
|
||||||
|
return {'title': e.description, 'value': e.code};
|
||||||
|
}).toList());
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
@ -223,9 +235,12 @@ class _PlaySettingState extends State<PlaySetting> {
|
|||||||
int? result = await showDialog(
|
int? result = await showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
return SelectDialog<int>(title: '默认全屏方式', value: defaultFullScreenMode, values: FullScreenMode.values.map((e) {
|
return SelectDialog<int>(
|
||||||
return {'title': e.description, 'value': e.code};
|
title: '默认全屏方式',
|
||||||
}).toList());
|
value: defaultFullScreenMode,
|
||||||
|
values: FullScreenMode.values.map((e) {
|
||||||
|
return {'title': e.description, 'value': e.code};
|
||||||
|
}).toList());
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
@ -246,9 +261,12 @@ class _PlaySettingState extends State<PlaySetting> {
|
|||||||
int? result = await showDialog(
|
int? result = await showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
return SelectDialog<int>(title: '底部进度条展示', value: defaultBtmProgressBehavior, values: BtmProgresBehavior.values.map((e) {
|
return SelectDialog<int>(
|
||||||
return {'title': e.description, 'value': e.code};
|
title: '底部进度条展示',
|
||||||
}).toList());
|
value: defaultBtmProgressBehavior,
|
||||||
|
values: BtmProgresBehavior.values.map((e) {
|
||||||
|
return {'title': e.description, 'value': e.code};
|
||||||
|
}).toList());
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:pilipala/models/common/theme_type.dart';
|
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/utils/storage.dart';
|
import 'package:pilipala/utils/storage.dart';
|
||||||
|
|
||||||
import 'controller.dart';
|
import 'controller.dart';
|
||||||
@ -25,6 +27,7 @@ class _StyleSettingState extends State<StyleSetting> {
|
|||||||
|
|
||||||
Box setting = GStrorage.setting;
|
Box setting = GStrorage.setting;
|
||||||
late int picQuality;
|
late int picQuality;
|
||||||
|
late double toastOpacity;
|
||||||
late ThemeType _tempThemeValue;
|
late ThemeType _tempThemeValue;
|
||||||
late dynamic defaultCustomRows;
|
late dynamic defaultCustomRows;
|
||||||
|
|
||||||
@ -32,6 +35,7 @@ class _StyleSettingState extends State<StyleSetting> {
|
|||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
picQuality = setting.get(SettingBoxKey.defaultPicQa, defaultValue: 10);
|
picQuality = setting.get(SettingBoxKey.defaultPicQa, defaultValue: 10);
|
||||||
|
toastOpacity = setting.get(SettingBoxKey.defaultToastOp, defaultValue: 1.0);
|
||||||
_tempThemeValue = settingController.themeType.value;
|
_tempThemeValue = settingController.themeType.value;
|
||||||
defaultCustomRows = setting.get(SettingBoxKey.customRows, defaultValue: 2);
|
defaultCustomRows = setting.get(SettingBoxKey.customRows, defaultValue: 2);
|
||||||
}
|
}
|
||||||
@ -187,6 +191,30 @@ class _StyleSettingState extends State<StyleSetting> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
ListTile(
|
||||||
|
dense: false,
|
||||||
|
onTap: () async {
|
||||||
|
double? result = await showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) {
|
||||||
|
return SlideDialog<double>(
|
||||||
|
title: 'Toast不透明度',
|
||||||
|
value: settingController.toastOpacity.value,
|
||||||
|
min: 0.0,
|
||||||
|
max: 1.0,
|
||||||
|
divisions: 10,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
if (result != null) {
|
||||||
|
settingController.toastOpacity.value = result;
|
||||||
|
SmartDialog.showToast('设置成功');
|
||||||
|
setting.put(SettingBoxKey.defaultToastOp, result);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
title: Text('Toast不透明度', style: titleStyle),
|
||||||
|
subtitle: Text('自定义Toast不透明度', style: subTitleStyle),
|
||||||
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
dense: false,
|
dense: false,
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
|
71
lib/pages/setting/widgets/slide_dialog.dart
Normal file
71
lib/pages/setting/widgets/slide_dialog.dart
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
// import 'package:pilipala/models/common/theme_type.dart';
|
||||||
|
|
||||||
|
class SlideDialog<T extends num> extends StatefulWidget {
|
||||||
|
final T value;
|
||||||
|
final String title;
|
||||||
|
final double min;
|
||||||
|
final double max;
|
||||||
|
final int? divisions;
|
||||||
|
final String? suffix;
|
||||||
|
|
||||||
|
const SlideDialog({
|
||||||
|
super.key,
|
||||||
|
required this.value,
|
||||||
|
required this.title,
|
||||||
|
required this.min,
|
||||||
|
required this.max,
|
||||||
|
this.divisions,
|
||||||
|
this.suffix,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
_SlideDialogState<T> createState() => _SlideDialogState<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _SlideDialogState<T extends num> extends State<SlideDialog<T>> {
|
||||||
|
late double _tempValue;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_tempValue = widget.value.toDouble();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return AlertDialog(
|
||||||
|
title: Text(widget.title),
|
||||||
|
contentPadding:
|
||||||
|
const EdgeInsets.only(top: 20, left: 8, right: 8, bottom: 8),
|
||||||
|
content: SizedBox(
|
||||||
|
height: 40,
|
||||||
|
child: Slider(
|
||||||
|
value: _tempValue,
|
||||||
|
min: widget.min,
|
||||||
|
max: widget.max,
|
||||||
|
divisions: widget.divisions ?? 10,
|
||||||
|
label: '$_tempValue${widget.suffix ?? ''}',
|
||||||
|
onChanged: (double value) {
|
||||||
|
setState(() {
|
||||||
|
_tempValue = value;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Navigator.pop(context),
|
||||||
|
child: Text(
|
||||||
|
'取消',
|
||||||
|
style: TextStyle(color: Theme.of(context).colorScheme.outline),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Navigator.pop(context, _tempValue as T),
|
||||||
|
child: const Text('确定'),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -244,7 +244,10 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
|||||||
void _handleTransition(String name) {
|
void _handleTransition(String name) {
|
||||||
switch (name) {
|
switch (name) {
|
||||||
case 'inactive':
|
case 'inactive':
|
||||||
autoEnterPip();
|
if (plPlayerController != null &&
|
||||||
|
playerStatus == PlayerStatus.playing) {
|
||||||
|
autoEnterPip();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -302,7 +305,10 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
|||||||
return <Widget>[
|
return <Widget>[
|
||||||
Obx(() => SliverAppBar(
|
Obx(() => SliverAppBar(
|
||||||
automaticallyImplyLeading: false,
|
automaticallyImplyLeading: false,
|
||||||
pinned: false,
|
// 假装使用一个非空变量,避免Obx检测不到而罢工
|
||||||
|
pinned: videoDetailController
|
||||||
|
.autoPlay.value ^ false ^ videoDetailController
|
||||||
|
.autoPlay.value,
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
scrolledUnderElevation: 0,
|
scrolledUnderElevation: 0,
|
||||||
forceElevated: innerBoxIsScrolled,
|
forceElevated: innerBoxIsScrolled,
|
||||||
|
@ -3,14 +3,15 @@ enum BtmProgresBehavior {
|
|||||||
alwaysShow,
|
alwaysShow,
|
||||||
alwaysHide,
|
alwaysHide,
|
||||||
onlyShowFullScreen,
|
onlyShowFullScreen,
|
||||||
|
onlyHideFullScreen,
|
||||||
}
|
}
|
||||||
|
|
||||||
extension BtmProgresBehaviorDesc on BtmProgresBehavior {
|
extension BtmProgresBehaviorDesc on BtmProgresBehavior {
|
||||||
String get description => ['始终展示', '始终隐藏', '仅全屏时展示'][index];
|
String get description => ['始终展示', '始终隐藏', '仅全屏时展示', '仅全屏时隐藏'][index];
|
||||||
}
|
}
|
||||||
|
|
||||||
extension BtmProgresBehaviorCode on BtmProgresBehavior {
|
extension BtmProgresBehaviorCode on BtmProgresBehavior {
|
||||||
static final List<int> _codeList = [0, 1, 2];
|
static final List<int> _codeList = [0, 1, 2, 3];
|
||||||
int get code => _codeList[index];
|
int get code => _codeList[index];
|
||||||
|
|
||||||
static BtmProgresBehavior? fromCode(int code) {
|
static BtmProgresBehavior? fromCode(int code) {
|
||||||
|
@ -610,6 +610,10 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
|||||||
BtmProgresBehavior.onlyShowFullScreen.code &&
|
BtmProgresBehavior.onlyShowFullScreen.code &&
|
||||||
!_.isFullScreen.value) {
|
!_.isFullScreen.value) {
|
||||||
return Container();
|
return Container();
|
||||||
|
} else if (defaultBtmProgressBehavior ==
|
||||||
|
BtmProgresBehavior.onlyHideFullScreen.code &&
|
||||||
|
_.isFullScreen.value) {
|
||||||
|
return Container();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_.videoType.value == 'live') {
|
if (_.videoType.value == 'live') {
|
||||||
|
@ -98,6 +98,7 @@ class SettingBoxKey {
|
|||||||
fullScreenMode = 'fullScreenMode',
|
fullScreenMode = 'fullScreenMode',
|
||||||
defaultDecode = 'defaultDecode',
|
defaultDecode = 'defaultDecode',
|
||||||
danmakuEnable = 'danmakuEnable',
|
danmakuEnable = 'danmakuEnable',
|
||||||
|
defaultToastOp = 'defaultToastOp',
|
||||||
defaultPicQa = 'defaultPicQa',
|
defaultPicQa = 'defaultPicQa',
|
||||||
enableHA = 'enableHA',
|
enableHA = 'enableHA',
|
||||||
enableOnlineTotal = 'enableOnlineTotal',
|
enableOnlineTotal = 'enableOnlineTotal',
|
||||||
|
@ -16,7 +16,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev
|
|||||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||||
# In Windows, build-name is used as the major, minor, and patch parts
|
# In Windows, build-name is used as the major, minor, and patch parts
|
||||||
# of the product and file versions while build-number is used as the build suffix.
|
# of the product and file versions while build-number is used as the build suffix.
|
||||||
version: 1.0.15
|
version: 1.0.16
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=2.19.6 <3.0.0"
|
sdk: ">=2.19.6 <3.0.0"
|
||||||
|
Reference in New Issue
Block a user