From 41ddeab41aeecca0b1bb966c0e734110db487566 Mon Sep 17 00:00:00 2001 From: orz12 Date: Sat, 20 Jan 2024 15:14:52 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=A8=A1=E6=8B=9F=E6=9C=AA?= =?UTF-8?q?=E7=99=BB=E5=BD=95=E6=8E=A8=E8=8D=90=EF=BC=8C=E7=8B=AC=E7=AB=8B?= =?UTF-8?q?=E6=8E=A8=E8=8D=90=E8=AE=BE=E7=BD=AE=EF=BC=8C=E6=96=B0=E5=A2=9E?= =?UTF-8?q?accesskey=E9=A3=8E=E6=8E=A7=E8=AD=A6=E5=91=8A=EF=BC=8C=E7=BB=9F?= =?UTF-8?q?=E4=B8=80=E6=8E=A8=E8=8D=90=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/http/video.dart | 18 ++- lib/models/common/rcmd_type.dart | 6 +- lib/pages/rcmd/controller.dart | 91 ++++++--------- lib/pages/rcmd/view.dart | 60 ++-------- lib/pages/setting/extra_setting.dart | 62 ---------- lib/pages/setting/recommend_setting.dart | 137 +++++++++++++++++++++++ lib/pages/setting/view.dart | 5 + lib/router/app_pages.dart | 4 +- lib/utils/storage.dart | 8 +- 9 files changed, 210 insertions(+), 181 deletions(-) create mode 100644 lib/pages/setting/recommend_setting.dart diff --git a/lib/http/video.dart b/lib/http/video.dart index 923e93a2..39c961cd 100644 --- a/lib/http/video.dart +++ b/lib/http/video.dart @@ -46,7 +46,9 @@ class VideoHttp { setting.get(SettingBoxKey.blackMidsList, defaultValue: [-1]); for (var i in res.data['data']['item']) { //过滤掉live与ad,以及拉黑用户 - if (i['goto'] == 'av' && !blackMidsList.contains(i['owner']['mid'])) { + if (i['goto'] == 'av' && + (i['owner'] != null && + !blackMidsList.contains(i['owner']['mid']))) { list.add(RecVideoItemModel.fromJson(i)); } } @@ -59,7 +61,9 @@ class VideoHttp { } } - static Future rcmdVideoListApp({int? ps, required int freshIdx}) async { + // 添加额外的loginState变量模拟未登录状态 + static Future rcmdVideoListApp( + {bool loginStatus = true, required int freshIdx}) async { try { var res = await Request().get( Api.recommendListApp, @@ -72,9 +76,11 @@ class VideoHttp { 'device_name': 'vivo', 'pull': freshIdx == 0 ? 'true' : 'false', 'appkey': Constants.appKey, - 'access_key': localCache - .get(LocalCacheKey.accessKey, defaultValue: {})['value'] ?? - '' + 'access_key': loginStatus + ? (localCache.get(LocalCacheKey.accessKey, + defaultValue: {})['value'] ?? + '') + : '' }, ); if (res.data['code'] == 0) { @@ -92,7 +98,7 @@ class VideoHttp { } return {'status': true, 'data': list}; } else { - return {'status': false, 'data': [], 'msg': ''}; + return {'status': false, 'data': [], 'msg': res.data['message']}; } } catch (err) { return {'status': false, 'data': [], 'msg': err.toString()}; diff --git a/lib/models/common/rcmd_type.dart b/lib/models/common/rcmd_type.dart index dbb64b15..5af18d77 100644 --- a/lib/models/common/rcmd_type.dart +++ b/lib/models/common/rcmd_type.dart @@ -1,7 +1,7 @@ // 首页推荐类型 -enum RcmdType { web, app } +enum RcmdType { web, app, notLogin } extension RcmdTypeExtension on RcmdType { - String get values => ['web', 'app'][index]; - String get labels => ['web端', 'app端'][index]; + String get values => ['web', 'app', 'notLogin'][index]; + String get labels => ['web端', 'app端', '模拟未登录'][index]; } diff --git a/lib/pages/rcmd/controller.dart b/lib/pages/rcmd/controller.dart index 4ed1ade1..ed98606a 100644 --- a/lib/pages/rcmd/controller.dart +++ b/lib/pages/rcmd/controller.dart @@ -9,8 +9,8 @@ import 'package:pilipala/utils/storage.dart'; class RcmdController extends GetxController { final ScrollController scrollController = ScrollController(); int _currentPage = 0; - RxList appVideoList = [].obs; - RxList webVideoList = [].obs; + // RxList appVideoList = [].obs; + // RxList webVideoList = [].obs; bool isLoadingMore = true; OverlayEntry? popupDialog; Box recVideo = GStrorage.recVideo; @@ -18,6 +18,7 @@ class RcmdController extends GetxController { RxInt crossAxisCount = 2.obs; late bool enableSaveLastData; late String defaultRcmdType = 'web'; + late RxList videoList; @override void onInit() { @@ -37,85 +38,59 @@ class RcmdController extends GetxController { setting.get(SettingBoxKey.enableSaveLastData, defaultValue: false); defaultRcmdType = setting.get(SettingBoxKey.defaultRcmdType, defaultValue: 'web'); + if (defaultRcmdType == 'web'){ + videoList = [].obs; + } else { + videoList = [].obs; + } } // 获取推荐 Future queryRcmdFeed(type) async { - print(defaultRcmdType); - if (defaultRcmdType == 'app') { - return await queryRcmdFeedApp(type); - } - if (defaultRcmdType == 'web') { - return await queryRcmdFeedWeb(type); - } - } - - // 获取app端推荐 - Future queryRcmdFeedApp(type) async { if (isLoadingMore == false) { return; } if (type == 'onRefresh') { _currentPage = 0; } - var res = await VideoHttp.rcmdVideoListApp( - freshIdx: _currentPage, - ); + late final Map res; + switch (defaultRcmdType) { + case 'app': case 'notLogin': + res = await VideoHttp.rcmdVideoListApp( + loginStatus: defaultRcmdType != 'notLogin', + freshIdx: _currentPage, + ); + break; + default: //'web' + res = await VideoHttp.rcmdVideoList( + freshIdx: _currentPage, + ps: 20, + ); + } if (res['status']) { if (type == 'init') { - if (appVideoList.isNotEmpty) { - appVideoList.addAll(res['data']); + if (videoList.isNotEmpty) { + videoList.addAll(res['data']); } else { - appVideoList.value = res['data']; + videoList.value = res['data']; } } else if (type == 'onRefresh') { if (enableSaveLastData) { - appVideoList.insertAll(0, res['data']); + videoList.insertAll(0, res['data']); } else { - appVideoList.value = res['data']; + videoList.value = res['data']; } } else if (type == 'onLoad') { - appVideoList.addAll(res['data']); + videoList.addAll(res['data']); } - recVideo.put('cacheList', res['data']); - _currentPage += 1; - } - isLoadingMore = false; - return res; - } - - // 获取web端推荐 - Future queryRcmdFeedWeb(type) async { - if (isLoadingMore == false) { - return; - } - if (type == 'onRefresh') { - _currentPage = 0; - } - var res = await VideoHttp.rcmdVideoList( - ps: 20, - freshIdx: _currentPage, - ); - if (res['status']) { - if (type == 'init') { - if (webVideoList.isNotEmpty) { - webVideoList.addAll(res['data']); - } else { - webVideoList.value = res['data']; - } - } else if (type == 'onRefresh') { - if (enableSaveLastData) { - webVideoList.insertAll(0, res['data']); - } else { - webVideoList.value = res['data']; - } - } else if (type == 'onLoad') { - webVideoList.addAll(res['data']); + if (defaultRcmdType != 'web') { + recVideo.put('cacheList', res['data']); } _currentPage += 1; + } else { + Get.snackbar('提示', res['msg']); } isLoadingMore = false; - return res; } // 下拉刷新 @@ -129,7 +104,7 @@ class RcmdController extends GetxController { queryRcmdFeed('onLoad'); } - // 返回顶部并刷新 + // 返回顶部 void animateToTop() async { if (scrollController.offset >= MediaQuery.of(Get.context!).size.height * 5) { diff --git a/lib/pages/rcmd/view.dart b/lib/pages/rcmd/view.dart index bc3c4a00..0a345511 100644 --- a/lib/pages/rcmd/view.dart +++ b/lib/pages/rcmd/view.dart @@ -91,54 +91,18 @@ class _RcmdPageState extends State SliverPadding( padding: const EdgeInsets.fromLTRB(0, StyleString.safeSpace, 0, 0), - sliver: FutureBuilder( - future: _futureBuilderFuture, - builder: (context, snapshot) { - if (snapshot.connectionState == ConnectionState.done) { - Map data = snapshot.data as Map; - if (data['status']) { - return Platform.isAndroid || Platform.isIOS - ? Obx( - () => contentGrid( - _rcmdController, - _rcmdController.defaultRcmdType == 'web' - ? _rcmdController.webVideoList - : _rcmdController.appVideoList), - ) - : SliverLayoutBuilder( - builder: (context, boxConstraints) { - return Obx( - () => contentGrid( - _rcmdController, - _rcmdController.defaultRcmdType == 'web' - ? _rcmdController.webVideoList - : _rcmdController.appVideoList), - ); - }); - } else { - return HttpError( - errMsg: data['msg'], - fn: () { - setState(() { - _futureBuilderFuture = - _rcmdController.queryRcmdFeed('init'); - }); - }, - ); - } - } else { - // 缓存数据 - // if (_rcmdController.videoList.isNotEmpty) { - // return contentGrid( - // _rcmdController, _rcmdController.videoList); - // } - // // 骨架屏 - // else { - return contentGrid(_rcmdController, []); - // } - } - }, - ), + sliver: Obx(() { + // 使用Obx来监听数据的变化 + if (_rcmdController.isLoadingMore) { + // 如果正在加载,则显示骨架屏 + return contentGrid(_rcmdController, []); + } else { + // 显示视频列表 + return contentGrid( + _rcmdController, + _rcmdController.videoList); + } + }), ), LoadingMore(ctr: _rcmdController) ], diff --git a/lib/pages/setting/extra_setting.dart b/lib/pages/setting/extra_setting.dart index b4275815..b32a06f5 100644 --- a/lib/pages/setting/extra_setting.dart +++ b/lib/pages/setting/extra_setting.dart @@ -1,9 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:hive/hive.dart'; -import 'package:pilipala/http/member.dart'; import 'package:pilipala/models/common/dynamics_type.dart'; -import 'package:pilipala/models/common/rcmd_type.dart'; import 'package:pilipala/models/common/reply_sort_type.dart'; import 'package:pilipala/pages/setting/widgets/select_dialog.dart'; import 'package:pilipala/utils/storage.dart'; @@ -20,23 +18,16 @@ class ExtraSetting extends StatefulWidget { class _ExtraSettingState extends State { Box setting = GStrorage.setting; static Box localCache = GStrorage.localCache; - late dynamic defaultRcmdType; late dynamic defaultReplySort; late dynamic defaultDynamicType; late dynamic enableSystemProxy; late String defaultSystemProxyHost; late String defaultSystemProxyPort; - Box userInfoCache = GStrorage.userInfo; - var userInfo; bool userLogin = false; - var accessKeyInfo; @override void initState() { super.initState(); - // 首页默认推荐类型 - defaultRcmdType = - setting.get(SettingBoxKey.defaultRcmdType, defaultValue: 'web'); // 默认优先显示最新评论 defaultReplySort = setting.get(SettingBoxKey.replySortType, defaultValue: 0); @@ -49,9 +40,6 @@ class _ExtraSettingState extends State { localCache.get(LocalCacheKey.systemProxyHost, defaultValue: ''); defaultSystemProxyPort = localCache.get(LocalCacheKey.systemProxyPort, defaultValue: ''); - userInfo = userInfoCache.get('userInfoCache'); - userLogin = userInfo != null; - accessKeyInfo = localCache.get(LocalCacheKey.accessKey, defaultValue: null); } // 设置代理 @@ -159,12 +147,6 @@ class _ExtraSettingState extends State { setKey: SettingBoxKey.enableSearchWord, defaultVal: true, ), - const SetSwitchItem( - title: '推荐动态', - subTitle: '是否在推荐内容中展示动态', - setKey: SettingBoxKey.enableRcmdDynamic, - defaultVal: true, - ), const SetSwitchItem( title: '快速收藏', subTitle: '点按收藏至默认,长按选择文件夹', @@ -177,50 +159,6 @@ class _ExtraSettingState extends State { setKey: SettingBoxKey.enableWordRe, defaultVal: false, ), - const SetSwitchItem( - title: '首页推荐刷新', - subTitle: '下拉刷新时保留上次内容', - setKey: SettingBoxKey.enableSaveLastData, - defaultVal: false, - ), - ListTile( - dense: false, - title: Text('首页推荐类型', style: titleStyle), - subtitle: Text( - '当前使用「$defaultRcmdType端」推荐', - style: subTitleStyle, - ), - onTap: () async { - String? result = await showDialog( - context: context, - builder: (context) { - return SelectDialog( - title: '推荐类型', - value: defaultRcmdType, - values: RcmdType.values.map((e) { - return {'title': e.labels, 'value': e.values}; - }).toList(), - ); - }, - ); - if (result != null) { - if (result == 'app') { - // app端推荐需要access_key - if (accessKeyInfo == null) { - if (!userLogin) { - SmartDialog.showToast('请先登录'); - return; - } - await MemberHttp.cookieToKey(); - } - } - defaultRcmdType = result; - setting.put(SettingBoxKey.defaultRcmdType, result); - SmartDialog.showToast('下次启动时生效'); - setState(() {}); - } - }, - ), const SetSwitchItem( title: '启用ai总结', subTitle: '视频详情页开启ai总结', diff --git a/lib/pages/setting/recommend_setting.dart b/lib/pages/setting/recommend_setting.dart new file mode 100644 index 00000000..8e049bc4 --- /dev/null +++ b/lib/pages/setting/recommend_setting.dart @@ -0,0 +1,137 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; +import 'package:hive/hive.dart'; +import 'package:pilipala/http/member.dart'; +import 'package:pilipala/models/common/rcmd_type.dart'; +import 'package:pilipala/pages/setting/widgets/select_dialog.dart'; +import 'package:pilipala/utils/storage.dart'; + +import 'widgets/switch_item.dart'; + +class RecommendSetting extends StatefulWidget { + const RecommendSetting({super.key}); + + @override + State createState() => _RecommendSettingState(); +} + +class _RecommendSettingState extends State { + Box setting = GStrorage.setting; + static Box localCache = GStrorage.localCache; + late dynamic defaultRcmdType; + Box userInfoCache = GStrorage.userInfo; + late dynamic userInfo; + bool userLogin = false; + late dynamic accessKeyInfo; + + @override + void initState() { + super.initState(); + // 首页默认推荐类型 + defaultRcmdType = + setting.get(SettingBoxKey.defaultRcmdType, defaultValue: 'web'); + userInfo = userInfoCache.get('userInfoCache'); + userLogin = userInfo != null; + accessKeyInfo = localCache.get(LocalCacheKey.accessKey, defaultValue: null); + } + + @override + Widget build(BuildContext context) { + TextStyle titleStyle = Theme.of(context).textTheme.titleMedium!; + TextStyle subTitleStyle = Theme.of(context) + .textTheme + .labelMedium! + .copyWith(color: Theme.of(context).colorScheme.outline); + return Scaffold( + appBar: AppBar( + centerTitle: false, + titleSpacing: 0, + title: Text( + '推荐设置', + style: Theme.of(context).textTheme.titleMedium, + ), + ), + body: ListView( + children: [ + const SetSwitchItem( + title: '推荐动态', + subTitle: '是否在推荐内容中展示动态', + setKey: SettingBoxKey.enableRcmdDynamic, + defaultVal: true, + ), + const SetSwitchItem( + title: '首页推荐刷新', + subTitle: '下拉刷新时保留上次内容', + setKey: SettingBoxKey.enableSaveLastData, + defaultVal: false, + ), + ListTile( + dense: false, + title: Text('首页推荐类型', style: titleStyle), + subtitle: Text( + '当前使用「$defaultRcmdType端」推荐', + style: subTitleStyle, + ), + onTap: () async { + String? result = await showDialog( + context: context, + builder: (context) { + return SelectDialog( + title: '推荐类型', + value: defaultRcmdType, + values: RcmdType.values.map((e) { + return {'title': e.labels, 'value': e.values}; + }).toList(), + ); + }, + ); + if (result != null) { + if (result == 'app') { + // app端推荐需要access_key + if (accessKeyInfo == null) { + if (!userLogin) { + SmartDialog.showToast('请先登录'); + return; + } + // 显示一个确认框,告知用户可能会导致账号被风控 + SmartDialog.show( + animationType: SmartAnimationType.centerFade_otherSlide, + builder: (context) { + return AlertDialog( + title: const Text('提示'), + content: const Text( + '使用app端推荐需获取access_key,有小概率触发风控导致账号退出(在官方app重新登录即可解除),是否继续?'), + actions: [ + TextButton( + onPressed: () { + result = null; + SmartDialog.dismiss(); + }, + child: const Text('取消'), + ), + TextButton( + onPressed: () async { + SmartDialog.dismiss(); + await MemberHttp.cookieToKey(); + }, + child: const Text('确定'), + ), + ], + ); + }); + } + } + if (result != null) { + defaultRcmdType = result; + setting.put(SettingBoxKey.defaultRcmdType, result); + SmartDialog.showToast('下次启动时生效'); + setState(() {}); + } + } + }, + ), + ], + ), + ); + } +} diff --git a/lib/pages/setting/view.dart b/lib/pages/setting/view.dart index 677a4546..19cdedaf 100644 --- a/lib/pages/setting/view.dart +++ b/lib/pages/setting/view.dart @@ -24,6 +24,11 @@ class SettingPage extends StatelessWidget { dense: false, title: const Text('隐私设置'), ), + ListTile( + onTap: () => Get.toNamed('/recommendSetting'), + dense: false, + title: const Text('推荐设置'), + ), ListTile( onTap: () => Get.toNamed('/playSetting'), dense: false, diff --git a/lib/router/app_pages.dart b/lib/router/app_pages.dart index 996869be..d6b2f9a9 100644 --- a/lib/router/app_pages.dart +++ b/lib/router/app_pages.dart @@ -37,6 +37,7 @@ import '../pages/setting/pages/color_select.dart'; import '../pages/setting/pages/display_mode.dart'; import '../pages/setting/pages/font_size_select.dart'; import '../pages/setting/pages/play_speed_set.dart'; +import '../pages/setting/recommend_setting.dart'; import '../pages/setting/play_setting.dart'; import '../pages/setting/privacy_setting.dart'; import '../pages/setting/style_setting.dart'; @@ -100,7 +101,8 @@ class Routes { // 二级回复 CustomGetPage( name: '/replyReply', page: () => const VideoReplyReplyPanel()), - + // 推荐设置 + CustomGetPage(name: '/recommendSetting', page: () => const RecommendSetting()), // 播放设置 CustomGetPage(name: '/playSetting', page: () => const PlaySetting()), // 外观设置 diff --git a/lib/utils/storage.dart b/lib/utils/storage.dart index f59a7bc1..c412606f 100644 --- a/lib/utils/storage.dart +++ b/lib/utils/storage.dart @@ -120,17 +120,19 @@ class SettingBoxKey { /// 隐私 blackMidsList = 'blackMidsList', + /// 推荐 + enableRcmdDynamic = 'enableRcmdDynamic', + defaultRcmdType = 'defaultRcmdType', + enableSaveLastData = 'enableSaveLastData', + /// 其他 autoUpdate = 'autoUpdate', - defaultRcmdType = 'defaultRcmdType', replySortType = 'replySortType', defaultDynamicType = 'defaultDynamicType', enableHotKey = 'enableHotKey', enableQuickFav = 'enableQuickFav', enableWordRe = 'enableWordRe', enableSearchWord = 'enableSearchWord', - enableRcmdDynamic = 'enableRcmdDynamic', - enableSaveLastData = 'enableSaveLastData', enableSystemProxy = 'enableSystemProxy', enableAi = 'enableAi';