fix: 弹幕停留

This commit is contained in:
guozhigq
2023-08-30 13:58:54 +08:00
14 changed files with 259 additions and 94 deletions

View File

@ -112,7 +112,7 @@ class _PlDanmakuState extends State<PlDanmaku> {
duration: const Duration(milliseconds: 100),
child: DanmakuView(
createdController: (DanmakuController e) async {
_controller = e;
widget.playerController.danmakuController = _controller = e;
},
option: DanmakuOption(
fontSize: 15,

View File

@ -23,29 +23,38 @@ class LaterController extends GetxController {
return res;
}
Future toViewDel() async {
Future toViewDel({int? aid}) async {
SmartDialog.show(
useSystem: true,
animationType: SmartAnimationType.centerFade_otherSlide,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('提示'),
content: const Text('即将删除所有已观看视频,此操作不可恢复。确定是否删除?'),
content: Text(
aid != null ? '即将移除该视频,确定是否移除' : '即将删除所有已观看视频,此操作不可恢复。确定是否删除?'),
actions: [
TextButton(
onPressed: () => SmartDialog.dismiss(),
child: const Text('取消')),
onPressed: () => SmartDialog.dismiss(),
child: Text(
'取消',
style: TextStyle(color: Theme.of(context).colorScheme.outline),
),
),
TextButton(
onPressed: () async {
var res = await UserHttp.toViewDel();
var res = await UserHttp.toViewDel(aid: aid);
if (res['status']) {
laterList.clear();
queryLaterList();
if (aid != null) {
laterList.removeWhere((e) => e.aid == aid);
} else {
laterList.clear();
queryLaterList();
}
}
SmartDialog.dismiss();
SmartDialog.showToast(res['msg']);
},
child: const Text('确认删除'),
child: Text(aid != null ? '确认移除' : '确认删除'),
)
],
);
@ -64,8 +73,12 @@ class LaterController extends GetxController {
content: const Text('确定要清空你的稍后再看列表吗?'),
actions: [
TextButton(
onPressed: () => SmartDialog.dismiss(),
child: const Text('取消')),
onPressed: () => SmartDialog.dismiss(),
child: Text(
'取消',
style: TextStyle(color: Theme.of(context).colorScheme.outline),
),
),
TextButton(
onPressed: () async {
var res = await UserHttp.toViewClear();

View File

@ -80,10 +80,12 @@ class _LaterPageState extends State<LaterPage> {
? SliverList(
delegate:
SliverChildBuilderDelegate((context, index) {
var videoItem = _laterController.laterList[index];
return VideoCardH(
videoItem: _laterController.laterList[index],
source: 'later',
);
videoItem: videoItem,
source: 'later',
longPress: () => _laterController.toViewDel(
aid: videoItem.aid));
}, childCount: _laterController.laterList.length),
)
: _laterController.isLoading.value

View File

@ -1,5 +1,6 @@
import 'dart:async';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
@ -53,6 +54,7 @@ class MainController extends GetxController {
final StreamController<bool> bottomBarStream =
StreamController<bool>.broadcast();
Box setting = GStrorage.setting;
DateTime? _lastPressedAt;
@override
void onInit() {
@ -61,4 +63,16 @@ class MainController extends GetxController {
Utils.checkUpdata();
}
}
Future<bool> onBackPressed(BuildContext context) {
if (_lastPressedAt == null ||
DateTime.now().difference(_lastPressedAt!) >
const Duration(seconds: 2)) {
// 两次点击时间间隔超过2秒重新记录时间戳
_lastPressedAt = DateTime.now();
SmartDialog.showToast("再按一次退出Pili");
return Future.value(false); // 不退出应用
}
return Future.value(true); // 退出应用
}
}

View File

@ -110,55 +110,58 @@ class _MainAppState extends State<MainApp> with SingleTickerProviderStateMixin {
MediaQuery.of(context).size.width * 9 / 16;
localCache.put('sheetHeight', sheetHeight);
localCache.put('statusBarHeight', statusBarHeight);
return Scaffold(
extendBody: true,
body: FadeTransition(
opacity: _fadeAnimation!,
child: SlideTransition(
position: Tween<Offset>(
begin: const Offset(0, 0.5),
end: Offset.zero,
).animate(
CurvedAnimation(
parent: _slideAnimation!,
curve: Curves.fastOutSlowIn,
reverseCurve: Curves.linear,
return WillPopScope(
onWillPop: () => _mainController.onBackPressed(context),
child: Scaffold(
extendBody: true,
body: FadeTransition(
opacity: _fadeAnimation!,
child: SlideTransition(
position: Tween<Offset>(
begin: const Offset(0, 0.5),
end: Offset.zero,
).animate(
CurvedAnimation(
parent: _slideAnimation!,
curve: Curves.fastOutSlowIn,
reverseCurve: Curves.linear,
),
),
child: PageView(
physics: const NeverScrollableScrollPhysics(),
controller: _pageController,
onPageChanged: (index) {
selectedIndex = index;
setState(() {});
},
children: _mainController.pages,
),
),
child: PageView(
physics: const NeverScrollableScrollPhysics(),
controller: _pageController,
onPageChanged: (index) {
selectedIndex = index;
setState(() {});
},
children: _mainController.pages,
),
),
),
bottomNavigationBar: StreamBuilder(
stream: _mainController.bottomBarStream.stream,
initialData: true,
builder: (context, AsyncSnapshot snapshot) {
return AnimatedSlide(
curve: Curves.easeInOutCubicEmphasized,
duration: const Duration(milliseconds: 1000),
offset: Offset(0, snapshot.data ? 0 : 1),
child: NavigationBar(
onDestinationSelected: (value) => setIndex(value),
selectedIndex: selectedIndex,
destinations: <Widget>[
..._mainController.navigationBars.map((e) {
return NavigationDestination(
icon: e['icon'],
selectedIcon: e['selectIcon'],
label: e['label'],
);
}).toList(),
],
),
);
},
bottomNavigationBar: StreamBuilder(
stream: _mainController.bottomBarStream.stream,
initialData: true,
builder: (context, AsyncSnapshot snapshot) {
return AnimatedSlide(
curve: Curves.easeInOutCubicEmphasized,
duration: const Duration(milliseconds: 1000),
offset: Offset(0, snapshot.data ? 0 : 1),
child: NavigationBar(
onDestinationSelected: (value) => setIndex(value),
selectedIndex: selectedIndex,
destinations: <Widget>[
..._mainController.navigationBars.map((e) {
return NavigationDestination(
icon: e['icon'],
selectedIcon: e['selectIcon'],
label: e['label'],
);
}).toList(),
],
),
);
},
),
),
);
}

View File

@ -55,6 +55,12 @@ class _ExtraSettingState extends State<ExtraSetting> {
defaultVal: true,
callFn: (val) => {SmartDialog.showToast('下次启动时生效')},
),
const SetSwitchItem(
title: '快速收藏',
subTitle: '点按收藏至默认,长按选择文件夹',
setKey: SettingBoxKey.enableQuickFav,
defaultVal: false,
),
ListTile(
dense: false,
title: Text('评论展示', style: titleStyle),

View File

@ -60,6 +60,18 @@ class _PlaySettingState extends State<PlaySetting> {
setKey: SettingBoxKey.autoPlayEnable,
defaultVal: true,
),
const SetSwitchItem(
title: '自动全屏',
subTitle: '视频开始播放时进入全屏',
setKey: SettingBoxKey.enableAutoEnter,
defaultVal: false,
),
const SetSwitchItem(
title: '自动退出',
subTitle: '视频结束播放时退出全屏',
setKey: SettingBoxKey.enableAutoExit,
defaultVal: false,
),
const SetSwitchItem(
title: '开启硬解',
subTitle: '以较低功耗播放视频',
@ -90,6 +102,12 @@ class _PlaySettingState extends State<PlaySetting> {
setKey: SettingBoxKey.enableAutoExit,
defaultVal: false,
),
const SetSwitchItem(
title: '双击快退/快进',
subTitle: '左侧双击快退,右侧双击快进',
setKey: SettingBoxKey.enableQuickDouble,
defaultVal: true,
),
ListTile(
dense: false,
title: Text('默认画质', style: titleStyle),

View File

@ -144,6 +144,8 @@ class VideoIntroController extends GetxController {
// 获取收藏状态
Future queryHasFavVideo() async {
/// fix 延迟查询
await Future.delayed(const Duration(milliseconds: 200));
var result = await VideoHttp.hasFavVideo(aid: IdUtils.bv2av(bvid));
if (result['status']) {
hasFav.value = result["data"]['favoured'];
@ -275,7 +277,27 @@ class VideoIntroController extends GetxController {
}
// (取消)收藏
Future actionFavVideo() async {
Future actionFavVideo({type = 'choose'}) async {
// 收藏至默认文件夹
if (type == 'default') {
await queryVideoInFolder();
int defaultFolderId = favFolderData.value.list!.first.id!;
int favStatus = favFolderData.value.list!.first.favState!;
print('favStatus: $favStatus');
var result = await VideoHttp.favVideo(
aid: IdUtils.bv2av(bvid),
addIds: favStatus == 0 ? '$defaultFolderId' : '',
delIds: favStatus == 1 ? '$defaultFolderId' : '',
);
if (result['status']) {
if (result['data']['prompt']) {
// 重新获取收藏状态
await queryHasFavVideo();
SmartDialog.showToast('✅ 操作成功');
}
}
return;
}
try {
for (var i in favFolderData.value.list!.toList()) {
if (i.favState == 1) {
@ -288,17 +310,19 @@ class VideoIntroController extends GetxController {
// ignore: avoid_print
print(e);
}
SmartDialog.showLoading(msg: '请求中');
var result = await VideoHttp.favVideo(
aid: IdUtils.bv2av(bvid),
addIds: addMediaIdsNew.join(','),
delIds: delMediaIdsNew.join(','));
SmartDialog.dismiss();
if (result['status']) {
if (result['data']['prompt']) {
addMediaIdsNew = [];
delMediaIdsNew = [];
Get.back();
// 重新获取收藏状态
queryHasFavVideo();
await queryHasFavVideo();
SmartDialog.showToast('✅ 操作成功');
}
}

View File

@ -122,6 +122,7 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
late final Map<dynamic, dynamic> videoItem;
Box localCache = GStrorage.localCache;
Box setting = GStrorage.setting;
late double sheetHeight;
late final bool loadingStatus; // 加载状态
@ -150,19 +151,50 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
}
// 收藏
showFavBottomSheet() {
showFavBottomSheet({type = 'tap'}) {
if (videoIntroController.userInfo == null) {
SmartDialog.showToast('账号未登录');
return;
}
showModalBottomSheet(
context: context,
useRootNavigator: true,
isScrollControlled: true,
builder: (context) {
return FavPanel(ctr: videoIntroController);
},
);
bool enableDragQuickFav =
setting.get(SettingBoxKey.enableQuickFav, defaultValue: false);
// 快速收藏 &
// 点按 收藏至默认文件夹
// 长按选择文件夹
if (enableDragQuickFav) {
if (type == 'tap') {
if (!videoIntroController.hasFav.value) {
videoIntroController.actionFavVideo(type: 'default');
} else {
showModalBottomSheet(
context: context,
useRootNavigator: true,
isScrollControlled: true,
builder: (context) {
return FavPanel(ctr: videoIntroController);
},
);
}
} else {
showModalBottomSheet(
context: context,
useRootNavigator: true,
isScrollControlled: true,
builder: (context) {
return FavPanel(ctr: videoIntroController);
},
);
}
} else if (type != 'longPress') {
showModalBottomSheet(
context: context,
useRootNavigator: true,
isScrollControlled: true,
builder: (context) {
return FavPanel(ctr: videoIntroController);
},
);
}
}
// 视频介绍
@ -510,6 +542,7 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
() => ActionRowItem(
icon: const Icon(FontAwesomeIcons.heart),
onTap: () => showFavBottomSheet(),
onLongPress: () => showFavBottomSheet(type: 'longPress'),
selectStatus: videoIntroController.hasFav.value,
loadingStatus: loadingStatus,
text: !loadingStatus

View File

@ -8,6 +8,7 @@ class ActionRowItem extends StatelessWidget {
final bool? loadingStatus;
final String? text;
final bool selectStatus;
final Function? onLongPress;
const ActionRowItem({
Key? key,
@ -17,6 +18,7 @@ class ActionRowItem extends StatelessWidget {
this.loadingStatus,
this.text,
this.selectStatus = false,
this.onLongPress,
}) : super(key: key);
@override
@ -32,6 +34,12 @@ class ActionRowItem extends StatelessWidget {
feedBack(),
onTap!(),
},
onLongPress: () {
feedBack();
if (onLongPress != null) {
onLongPress!();
}
},
child: Padding(
padding: const EdgeInsets.fromLTRB(15, 7, 15, 7),
child: Row(