From cf66d3be4c04eb0810576eae0ead9b14e3d007dc Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sat, 21 Sep 2024 15:14:38 +0800 Subject: [PATCH 01/26] =?UTF-8?q?feat:=20=E7=A8=8D=E5=90=8E=E5=86=8D?= =?UTF-8?q?=E7=9C=8B&=E6=94=B6=E8=97=8F=E5=A4=B9=E6=92=AD=E6=94=BE?= =?UTF-8?q?=E5=85=A8=E9=83=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/http/api.dart | 3 + lib/http/user.dart | 108 +++++++ lib/models/video/later.dart | 270 ++++++++++++++++++ lib/pages/fav_detail/controller.dart | 22 +- lib/pages/fav_detail/view.dart | 9 + lib/pages/later/controller.dart | 20 +- lib/pages/later/view.dart | 9 + lib/pages/video/detail/controller.dart | 127 +++++++- .../video/detail/introduction/controller.dart | 4 +- lib/pages/video/detail/introduction/view.dart | 17 +- lib/pages/video/detail/view.dart | 80 ++++++ .../detail/widgets/watch_later_list.dart | 229 +++++++++++++++ 12 files changed, 880 insertions(+), 18 deletions(-) create mode 100644 lib/models/video/later.dart create mode 100644 lib/pages/video/detail/widgets/watch_later_list.dart diff --git a/lib/http/api.dart b/lib/http/api.dart index 93226946..f24918b3 100644 --- a/lib/http/api.dart +++ b/lib/http/api.dart @@ -565,4 +565,7 @@ class Api { /// 直播间发送弹幕 static const String sendLiveMsg = '${HttpString.liveBaseUrl}/msg/send'; + + /// 稍后再看&收藏夹视频列表 + static const String mediaList = '/x/v2/medialist/resource/list'; } diff --git a/lib/http/user.dart b/lib/http/user.dart index 972acfdd..333c4038 100644 --- a/lib/http/user.dart +++ b/lib/http/user.dart @@ -1,4 +1,9 @@ +import 'dart:convert'; +import 'dart:developer'; + import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; +import 'package:html/parser.dart'; +import 'package:pilipala/models/video/later.dart'; import '../common/constants.dart'; import '../models/model_hot_video_item.dart'; import '../models/user/fav_detail.dart'; @@ -428,4 +433,107 @@ class UserHttp { return {'status': false, 'msg': res.data['message']}; } } + + // 稍后再看播放全部 + // static Future toViewPlayAll({required int oid, required String bvid}) async { + // var res = await Request().get( + // Api.watchLaterHtml, + // data: { + // 'oid': oid, + // 'bvid': bvid, + // }, + // ); + // String scriptContent = + // extractScriptContents(parse(res.data).body!.outerHtml)[0]; + // int startIndex = scriptContent.indexOf('{'); + // int endIndex = scriptContent.lastIndexOf('};'); + // String jsonContent = scriptContent.substring(startIndex, endIndex + 1); + // // 解析JSON字符串为Map + // Map jsonData = json.decode(jsonContent); + // // 输出解析后的数据 + // return { + // 'status': true, + // 'data': jsonData['resourceList'] + // .map((e) => MediaVideoItemModel.fromJson(e)) + // .toList() + // }; + // } + + static List extractScriptContents(String htmlContent) { + RegExp scriptRegExp = RegExp(r''); + if (headContent != null) { + final match = regex.firstMatch(headContent); + if (match != null && match.groupCount >= 1) { + final content = match.group(1); + String decodedString = Uri.decodeComponent(content!); + Map map = jsonDecode(decodedString); + return {'status': true, 'data': map['access_id']}; + } else { + return {'status': false, 'data': '请检查登录状态'}; + } + } + return {'status': false, 'data': '请检查登录状态'}; + } + + // 获取用户专栏 + static Future getMemberArticle({ + required int mid, + required int pn, + required String wWebid, + String? offset, + }) async { + Map params = await WbiSign().makSign({ + 'host_mid': mid, + 'page': pn, + 'offset': offset, + 'web_location': 333.999, + 'w_webid': wWebid, + }); + var res = await Request().get(Api.opusList, data: { + 'host_mid': mid, + 'page': pn, + 'offset': offset, + 'web_location': 333.999, + 'w_webid': wWebid, + 'w_rid': params['w_rid'], + 'wts': params['wts'], + }); + if (res.data['code'] == 0) { + return { + 'status': true, + 'data': MemberArticleDataModel.fromJson(res.data['data']) + }; + } else { + return { + 'status': false, + 'data': [], + 'msg': res.data['message'] ?? '请求异常', + }; + } + } } diff --git a/lib/models/member/article.dart b/lib/models/member/article.dart new file mode 100644 index 00000000..8489385e --- /dev/null +++ b/lib/models/member/article.dart @@ -0,0 +1,46 @@ +class MemberArticleDataModel { + MemberArticleDataModel({ + this.hasMore, + this.items, + this.offset, + this.updateNum, + }); + + bool? hasMore; + List? items; + String? offset; + int? updateNum; + + MemberArticleDataModel.fromJson(Map json) { + hasMore = json['has_more']; + items = json['items'] + .map((e) => MemberArticleItemModel.fromJson(e)) + .toList(); + offset = json['offset']; + updateNum = json['update_num']; + } +} + +class MemberArticleItemModel { + MemberArticleItemModel({ + this.content, + this.cover, + this.jumpUrl, + this.opusId, + this.stat, + }); + + String? content; + Map? cover; + String? jumpUrl; + String? opusId; + Map? stat; + + MemberArticleItemModel.fromJson(Map json) { + content = json['content']; + cover = json['cover']; + jumpUrl = json['jump_url']; + opusId = json['opus_id']; + stat = json['stat']; + } +} diff --git a/lib/pages/member/controller.dart b/lib/pages/member/controller.dart index ada869b5..3b7f24a4 100644 --- a/lib/pages/member/controller.dart +++ b/lib/pages/member/controller.dart @@ -240,4 +240,6 @@ class MemberController extends GetxController { } void pushfavPage() => Get.toNamed('/fav?mid=$mid'); + // 跳转图文专栏 + void pushArticlePage() => Get.toNamed('/memberArticle?mid=$mid'); } diff --git a/lib/pages/member/view.dart b/lib/pages/member/view.dart index be0ddedc..2939628c 100644 --- a/lib/pages/member/view.dart +++ b/lib/pages/member/view.dart @@ -170,32 +170,44 @@ class _MemberPageState extends State ), /// 视频 - Obx(() => ListTile( - onTap: _memberController.pushArchivesPage, - title: Text( - '${_memberController.isOwner.value ? '我' : 'Ta'}的投稿'), - trailing: const Icon(Icons.arrow_forward_outlined, - size: 19), - )), + Obx( + () => ListTile( + onTap: _memberController.pushArchivesPage, + title: Text( + '${_memberController.isOwner.value ? '我' : 'Ta'}的投稿'), + trailing: + const Icon(Icons.arrow_forward_outlined, size: 19), + ), + ), /// 他的收藏夹 - Obx(() => ListTile( - onTap: _memberController.pushfavPage, - title: Text( - '${_memberController.isOwner.value ? '我' : 'Ta'}的收藏'), - trailing: const Icon(Icons.arrow_forward_outlined, - size: 19), - )), + Obx( + () => ListTile( + onTap: _memberController.pushfavPage, + title: Text( + '${_memberController.isOwner.value ? '我' : 'Ta'}的收藏'), + trailing: + const Icon(Icons.arrow_forward_outlined, size: 19), + ), + ), /// 专栏 - Obx(() => ListTile( + Obx( + () => ListTile( + onTap: _memberController.pushArticlePage, title: Text( - '${_memberController.isOwner.value ? '我' : 'Ta'}的专栏'))), + '${_memberController.isOwner.value ? '我' : 'Ta'}的专栏'), + trailing: + const Icon(Icons.arrow_forward_outlined, size: 19), + ), + ), /// 合集 - Obx(() => ListTile( - title: Text( - '${_memberController.isOwner.value ? '我' : 'Ta'}的合集'))), + Obx( + () => ListTile( + title: Text( + '${_memberController.isOwner.value ? '我' : 'Ta'}的合集')), + ), MediaQuery.removePadding( removeTop: true, removeBottom: true, diff --git a/lib/pages/member_article/controller.dart b/lib/pages/member_article/controller.dart new file mode 100644 index 00000000..cffce2fe --- /dev/null +++ b/lib/pages/member_article/controller.dart @@ -0,0 +1,68 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; +import 'package:get/get.dart'; +import 'package:pilipala/http/member.dart'; +import 'package:pilipala/models/member/article.dart'; + +class MemberArticleController extends GetxController { + final ScrollController scrollController = ScrollController(); + late int mid; + int pn = 1; + String? offset; + bool hasMore = true; + String? wWebid; + RxBool isLoading = false.obs; + RxList articleList = [].obs; + + @override + void onInit() { + super.onInit(); + mid = int.parse(Get.parameters['mid']!); + } + + // 获取wWebid + Future getWWebid() async { + var res = await MemberHttp.getWWebid(mid: mid); + if (res['status']) { + wWebid = res['data']; + } else { + wWebid = '-1'; + SmartDialog.showToast(res['msg']); + } + } + + Future getMemberArticle(type) async { + if (isLoading.value) { + return; + } + isLoading.value = true; + if (wWebid == null) { + await getWWebid(); + } + if (type == 'init') { + pn = 1; + articleList.clear(); + } + var res = await MemberHttp.getMemberArticle( + mid: mid, + pn: pn, + offset: offset, + wWebid: wWebid!, + ); + if (res['status']) { + offset = res['data'].offset; + hasMore = res['data'].hasMore!; + if (type == 'init') { + articleList.value = res['data'].items; + } + if (type == 'onLoad') { + articleList.addAll(res['data'].items); + } + pn += 1; + } else { + SmartDialog.showToast(res['msg']); + } + isLoading.value = false; + return res; + } +} diff --git a/lib/pages/member_article/index.dart b/lib/pages/member_article/index.dart new file mode 100644 index 00000000..bfc2f344 --- /dev/null +++ b/lib/pages/member_article/index.dart @@ -0,0 +1,4 @@ +library member_article; + +export './controller.dart'; +export './view.dart'; diff --git a/lib/pages/member_article/view.dart b/lib/pages/member_article/view.dart new file mode 100644 index 00000000..e23e208d --- /dev/null +++ b/lib/pages/member_article/view.dart @@ -0,0 +1,176 @@ +import 'package:easy_debounce/easy_throttle.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:pilipala/common/skeleton/skeleton.dart'; +import 'package:pilipala/common/widgets/http_error.dart'; +import 'package:pilipala/common/widgets/network_img_layer.dart'; +import 'package:pilipala/common/widgets/no_data.dart'; +import 'package:pilipala/utils/utils.dart'; + +import 'controller.dart'; + +class MemberArticlePage extends StatefulWidget { + const MemberArticlePage({super.key}); + + @override + State createState() => _MemberArticlePageState(); +} + +class _MemberArticlePageState extends State { + late MemberArticleController _memberArticleController; + late Future _futureBuilderFuture; + late ScrollController scrollController; + late int mid; + + @override + void initState() { + super.initState(); + mid = int.parse(Get.parameters['mid']!); + final String heroTag = Utils.makeHeroTag(mid); + _memberArticleController = Get.put(MemberArticleController(), tag: heroTag); + _futureBuilderFuture = _memberArticleController.getMemberArticle('init'); + scrollController = _memberArticleController.scrollController; + + scrollController.addListener(_scrollListener); + } + + void _scrollListener() { + if (scrollController.position.pixels >= + scrollController.position.maxScrollExtent - 200) { + EasyThrottle.throttle( + 'member_archives', const Duration(milliseconds: 500), () { + _memberArticleController.getMemberArticle('onLoad'); + }); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + titleSpacing: 0, + centerTitle: false, + title: const Text('Ta的图文', style: TextStyle(fontSize: 16)), + ), + body: FutureBuilder( + future: _futureBuilderFuture, + builder: (BuildContext context, snapshot) { + if (snapshot.connectionState == ConnectionState.done) { + if (snapshot.data != null) { + return _buildContent(snapshot.data as Map); + } else { + return _buildError(snapshot.data['msg']); + } + } else { + return ListView.builder( + itemCount: 10, + itemBuilder: (BuildContext context, int index) { + return _buildSkeleton(); + }, + ); + } + }, + ), + ); + } + + Widget _buildContent(Map data) { + RxList list = _memberArticleController.articleList; + if (data['status']) { + return Obx( + () => list.isNotEmpty + ? ListView.separated( + controller: scrollController, + itemCount: list.length, + separatorBuilder: (BuildContext context, int index) { + return Divider( + height: 10, + color: Theme.of(context).dividerColor.withOpacity(0.15), + ); + }, + itemBuilder: (BuildContext context, int index) { + return _buildListItem(list[index]); + }, + ) + : const CustomScrollView( + physics: NeverScrollableScrollPhysics(), + slivers: [ + NoData(), + ], + ), + ); + } else { + return _buildError(data['msg']); + } + } + + Widget _buildListItem(dynamic item) { + return ListTile( + onTap: () { + Get.toNamed('/opus', parameters: { + 'title': item.content, + 'id': item.opusId, + 'articleType': 'opus', + }); + }, + leading: NetworkImgLayer( + width: 50, + height: 50, + type: 'emote', + src: item.cover['url'], + ), + title: Text( + item.content, + maxLines: 2, + overflow: TextOverflow.ellipsis, + ), + subtitle: Padding( + padding: const EdgeInsets.only(top: 4), + child: Text( + '${item.stat["like"]}人点赞', + style: TextStyle( + fontSize: 12, + color: Theme.of(context).colorScheme.outline, + ), + ), + ), + ); + } + + Widget _buildError(String errMsg) { + return CustomScrollView( + physics: const NeverScrollableScrollPhysics(), + slivers: [ + SliverToBoxAdapter( + child: HttpError( + errMsg: errMsg, + fn: () {}, + ), + ), + ], + ); + } + + Widget _buildSkeleton() { + return Skeleton( + child: ListTile( + leading: Container( + width: 50, + height: 50, + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.onInverseSurface, + borderRadius: BorderRadius.circular(4), + ), + ), + title: Container( + height: 16, + color: Theme.of(context).colorScheme.onInverseSurface, + ), + subtitle: Container( + height: 11, + color: Theme.of(context).colorScheme.onInverseSurface, + ), + ), + ); + } +} diff --git a/lib/router/app_pages.dart b/lib/router/app_pages.dart index 136de91f..a679fd79 100644 --- a/lib/router/app_pages.dart +++ b/lib/router/app_pages.dart @@ -5,6 +5,7 @@ import 'package:get/get.dart'; import 'package:hive/hive.dart'; import 'package:pilipala/pages/fav_edit/index.dart'; import 'package:pilipala/pages/follow_search/view.dart'; +import 'package:pilipala/pages/member_article/index.dart'; import 'package:pilipala/pages/message/at/index.dart'; import 'package:pilipala/pages/message/like/index.dart'; import 'package:pilipala/pages/message/reply/index.dart'; @@ -186,6 +187,9 @@ class Routes { name: '/messageSystem', page: () => const MessageSystemPage()), // 收藏夹编辑 CustomGetPage(name: '/favEdit', page: () => const FavEditPage()), + // 用户专栏 + CustomGetPage( + name: '/memberArticle', page: () => const MemberArticlePage()), ]; } From aa6b5af05df17894541511be4dbfd6dc3b4a72b9 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sat, 28 Sep 2024 17:24:23 +0800 Subject: [PATCH 14/26] =?UTF-8?q?fix:=20=E9=87=8D=E5=AE=9A=E5=90=91cv?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/http/read.dart | 25 +++++++++++++++++++++++++ lib/pages/opus/controller.dart | 11 ++++++++++- lib/pages/opus/view.dart | 3 +++ 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/lib/http/read.dart b/lib/http/read.dart index 4fff4547..cc522505 100644 --- a/lib/http/read.dart +++ b/lib/http/read.dart @@ -20,6 +20,29 @@ class ReadHttp { var res = await Request().get('https://www.bilibili.com/opus/$id', extra: { 'ua': 'pc', }); + String? headContent = parse(res.data).head?.outerHtml; + var document = parse(headContent); + var linkTags = document.getElementsByTagName('link'); + bool isCv = false; + String cvId = ''; + for (var linkTag in linkTags) { + var attributes = linkTag.attributes; + if (attributes.containsKey('rel') && + attributes['rel'] == 'canonical' && + attributes.containsKey('data-vue-meta') && + attributes['data-vue-meta'] == 'true') { + final String cvHref = linkTag.attributes['href']!; + RegExp regex = RegExp(r'cv(\d+)'); + RegExpMatch? match = regex.firstMatch(cvHref); + if (match != null) { + cvId = match.group(1)!; + } else { + print('No match found.'); + } + isCv = true; + break; + } + } String scriptContent = extractScriptContents(parse(res.data).body!.outerHtml)[0]; int startIndex = scriptContent.indexOf('{'); @@ -30,6 +53,8 @@ class ReadHttp { return { 'status': true, 'data': OpusDataModel.fromJson(jsonData), + 'isCv': isCv, + 'cvId': cvId, }; } } diff --git a/lib/pages/opus/controller.dart b/lib/pages/opus/controller.dart index f5c35770..86dd67a5 100644 --- a/lib/pages/opus/controller.dart +++ b/lib/pages/opus/controller.dart @@ -31,7 +31,16 @@ class OpusController extends GetxController { Future fetchOpusData() async { var res = await ReadHttp.parseArticleOpus(id: id); if (res['status']) { - opusData.value = res['data']; + List keys = res.keys.toList(); + if (keys.contains('isCv') && res['isCv']) { + Get.offNamed('/read', parameters: { + 'id': res['cvId'], + 'title': title.value, + 'articleType': 'cv', + }); + } else { + opusData.value = res['data']; + } } return res; } diff --git a/lib/pages/opus/view.dart b/lib/pages/opus/view.dart index a36b4813..8535230f 100644 --- a/lib/pages/opus/view.dart +++ b/lib/pages/opus/view.dart @@ -107,6 +107,9 @@ class _OpusPageState extends State { } Widget _buildContent(OpusDataModel opusData) { + if (opusData.detail == null) { + return const SizedBox(); + } final modules = opusData.detail!.modules!; late ModuleContent moduleContent; // 获取所有的图片链接 From 26a57336750d08a48813650f202d6fdd180e6b4a Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sat, 28 Sep 2024 18:22:42 +0800 Subject: [PATCH 15/26] =?UTF-8?q?feat:=20cv=E4=B8=93=E6=A0=8F=E8=AE=B0?= =?UTF-8?q?=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/http/api.dart | 3 +++ lib/http/read.dart | 39 ++++++++++++++++++++++++++++++++-- lib/pages/read/controller.dart | 5 +++++ 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/lib/http/api.dart b/lib/http/api.dart index 42819d7d..ff49b314 100644 --- a/lib/http/api.dart +++ b/lib/http/api.dart @@ -578,4 +578,7 @@ class Api { /// 稍后再看&收藏夹视频列表 static const String mediaList = '/x/v2/medialist/resource/list'; + + /// + static const String getViewInfo = '/x/article/viewinfo'; } diff --git a/lib/http/read.dart b/lib/http/read.dart index 22ca3503..558985b4 100644 --- a/lib/http/read.dart +++ b/lib/http/read.dart @@ -1,9 +1,9 @@ import 'dart:convert'; -import 'dart:developer'; import 'package:html/parser.dart'; import 'package:pilipala/models/read/opus.dart'; import 'package:pilipala/models/read/read.dart'; -import 'init.dart'; +import 'package:pilipala/utils/wbi_sign.dart'; +import 'index.dart'; class ReadHttp { static List extractScriptContents(String htmlContent) { @@ -53,4 +53,39 @@ class ReadHttp { 'data': ReadDataModel.fromJson(jsonData), }; } + + // + static Future getViewInfo({required String id}) async { + Map params = await WbiSign().makSign({ + 'id': id, + 'mobi_app': 'pc', + 'from': 'web', + 'gaia_source': 'main_web', + 'web_location': 333.976, + }); + var res = await Request().get( + Api.getViewInfo, + data: { + 'id': id, + 'mobi_app': 'pc', + 'from': 'web', + 'gaia_source': 'main_web', + 'web_location': 333.976, + 'w_rid': params['w_rid'], + 'wts': params['wts'], + }, + ); + if (res.data['code'] == 0) { + return { + 'status': true, + 'data': res.data['data'], + }; + } else { + return { + 'status': false, + 'data': [], + 'msg': res.data['message'], + }; + } + } } diff --git a/lib/pages/read/controller.dart b/lib/pages/read/controller.dart index d2e942fc..a0e4ef8e 100644 --- a/lib/pages/read/controller.dart +++ b/lib/pages/read/controller.dart @@ -23,6 +23,7 @@ class ReadPageController extends GetxController { id = Get.parameters['id']!; articleType = Get.parameters['articleType']!; scrollController.addListener(_scrollListener); + fetchViewInfo(); } Future fetchCvData() async { @@ -80,6 +81,10 @@ class ReadPageController extends GetxController { ); } + void fetchViewInfo() { + ReadHttp.getViewInfo(id: id); + } + @override void onClose() { scrollController.removeListener(_scrollListener); From b34fc2ff1f9b796c1e399335c4f71b7d307d263c Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sat, 28 Sep 2024 23:16:00 +0800 Subject: [PATCH 16/26] =?UTF-8?q?mod:=20=E7=B3=BB=E7=BB=9F=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/http/api.dart | 4 +++ lib/http/msg.dart | 23 +++++++++++++ lib/models/msg/system.dart | 15 +++++++-- lib/pages/message/system/controller.dart | 43 +++++++++++++++++++----- lib/pages/message/system/view.dart | 7 ++-- 5 files changed, 78 insertions(+), 14 deletions(-) diff --git a/lib/http/api.dart b/lib/http/api.dart index 6c5374dd..588bd058 100644 --- a/lib/http/api.dart +++ b/lib/http/api.dart @@ -555,6 +555,10 @@ class Api { static const String messageSystemAPi = '${HttpString.messageBaseUrl}/x/sys-msg/query_unified_notify'; + /// 系统通知 个人 + static const String userMessageSystemAPi = + '${HttpString.messageBaseUrl}/x/sys-msg/query_user_notify'; + /// 系统通知标记已读 static const String systemMarkRead = '${HttpString.messageBaseUrl}/x/sys-msg/update_cursor'; diff --git a/lib/http/msg.dart b/lib/http/msg.dart index 2de9cd49..869b5a28 100644 --- a/lib/http/msg.dart +++ b/lib/http/msg.dart @@ -330,4 +330,27 @@ class MsgHttp { }; } } + + static Future messageSystemAccount() async { + var res = await Request().get(Api.userMessageSystemAPi, data: { + 'csrf': await Request.getCsrf(), + 'page_size': 20, + 'build': 0, + 'mobi_app': 'web', + }); + if (res.data['code'] == 0) { + try { + return { + 'status': true, + 'data': res.data['data']['system_notify_list'] + .map((e) => MessageSystemModel.fromJson(e)) + .toList(), + }; + } catch (err) { + return {'status': false, 'date': [], 'msg': err.toString()}; + } + } else { + return {'status': false, 'date': [], 'msg': res.data['message']}; + } + } } diff --git a/lib/models/msg/system.dart b/lib/models/msg/system.dart index 20427707..12b1ac77 100644 --- a/lib/models/msg/system.dart +++ b/lib/models/msg/system.dart @@ -5,7 +5,7 @@ class MessageSystemModel { int? cursor; int? type; String? title; - Map? content; + dynamic content; Source? source; String? timeAt; int? cardType; @@ -45,7 +45,9 @@ class MessageSystemModel { cursor: jsons["cursor"], type: jsons["type"], title: jsons["title"], - content: json.decode(jsons["content"]), + content: isValidJson(jsons["content"]) + ? json.decode(jsons["content"]) + : jsons["content"], source: Source.fromJson(jsons["source"]), timeAt: jsons["time_at"], cardType: jsons["card_type"], @@ -75,3 +77,12 @@ class Source { logo: json["logo"], ); } + +bool isValidJson(String str) { + try { + json.decode(str); + } catch (e) { + return false; + } + return true; +} diff --git a/lib/pages/message/system/controller.dart b/lib/pages/message/system/controller.dart index f63a659a..c4731120 100644 --- a/lib/pages/message/system/controller.dart +++ b/lib/pages/message/system/controller.dart @@ -1,3 +1,4 @@ +import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:pilipala/http/msg.dart'; import 'package:pilipala/models/msg/system.dart'; @@ -5,18 +6,44 @@ import 'package:pilipala/models/msg/system.dart'; class MessageSystemController extends GetxController { RxList systemItems = [].obs; - Future queryMessageSystem({String type = 'init'}) async { - var res = await MsgHttp.messageSystem(); - if (res['status']) { - if (type == 'init') { - systemItems.value = res['data']; - } else { - systemItems.addAll(res['data']); - } + Future queryAndProcessMessages({String type = 'init'}) async { + // 并行调用两个接口 + var results = await Future.wait([ + queryMessageSystem(type: type), + queryMessageSystemAccount(type: type), + ]); + + // 对返回的数据进行处理 + var systemRes = results[0]; + var accountRes = results[1]; + + if (systemRes['status'] || accountRes['status']) { + // 处理返回的数据 + List combinedData = [ + ...systemRes['data'], + ...accountRes['data'] + ]; + combinedData.sort((a, b) => b.cursor!.compareTo(a.cursor!)); + systemItems.addAll(combinedData); + systemItems.refresh(); if (systemItems.isNotEmpty) { systemMarkRead(systemItems.first.cursor!); } + } else { + SmartDialog.showToast(systemRes['msg'] ?? accountRes['msg']); } + return systemRes; + } + + // 获取系统消息 + Future queryMessageSystem({String type = 'init'}) async { + var res = await MsgHttp.messageSystem(); + return res; + } + + // 获取系统消息 个人 + Future queryMessageSystemAccount({String type = 'init'}) async { + var res = await MsgHttp.messageSystemAccount(); return res; } diff --git a/lib/pages/message/system/view.dart b/lib/pages/message/system/view.dart index f7b94e5a..ee10b639 100644 --- a/lib/pages/message/system/view.dart +++ b/lib/pages/message/system/view.dart @@ -20,7 +20,7 @@ class _MessageSystemPageState extends State { @override void initState() { super.initState(); - _futureBuilderFuture = _messageSystemCtr.queryMessageSystem(); + _futureBuilderFuture = _messageSystemCtr.queryAndProcessMessages(); } @override @@ -31,7 +31,7 @@ class _MessageSystemPageState extends State { ), body: RefreshIndicator( onRefresh: () async { - await _messageSystemCtr.queryMessageSystem(); + await _messageSystemCtr.queryAndProcessMessages(); }, child: FutureBuilder( future: _futureBuilderFuture, @@ -42,7 +42,6 @@ class _MessageSystemPageState extends State { } if (snapshot.data['status']) { final systemItems = _messageSystemCtr.systemItems; - print(systemItems.length); return Obx( () => ListView.separated( controller: scrollController, @@ -115,7 +114,7 @@ class SystemItem extends StatelessWidget { style: TextStyle(color: Theme.of(context).colorScheme.outline), ), const SizedBox(height: 6), - Text(item.content!['web']), + Text(item.content is String ? item.content : item.content!['web']), ], ), ); From 166dceb1bd6a04ea92cb5ae8845d5805a9cf3436 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sat, 28 Sep 2024 23:21:17 +0800 Subject: [PATCH 17/26] typo --- lib/pages/setting/style_setting.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pages/setting/style_setting.dart b/lib/pages/setting/style_setting.dart index 5fca0c86..64e4bdb8 100644 --- a/lib/pages/setting/style_setting.dart +++ b/lib/pages/setting/style_setting.dart @@ -103,7 +103,7 @@ class _StyleSettingState extends State { needReboot: true, ), const SetSwitchItem( - title: '首页底栏背景渐变', + title: '首页顶部背景渐变', setKey: SettingBoxKey.enableGradientBg, defaultVal: true, needReboot: true, From ec5cc6ff91d42a89759a1d6b06568c7ee96ebaa4 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 29 Sep 2024 01:01:45 +0800 Subject: [PATCH 18/26] =?UTF-8?q?feat:=20=E7=9B=B4=E6=92=AD=E9=97=B4?= =?UTF-8?q?=E5=8E=86=E5=8F=B2=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/http/api.dart | 4 ++++ lib/http/live.dart | 11 +++++++++++ lib/pages/live_room/controller.dart | 13 +++++++++++++ 3 files changed, 28 insertions(+) diff --git a/lib/http/api.dart b/lib/http/api.dart index 93226946..9cff2644 100644 --- a/lib/http/api.dart +++ b/lib/http/api.dart @@ -565,4 +565,8 @@ class Api { /// 直播间发送弹幕 static const String sendLiveMsg = '${HttpString.liveBaseUrl}/msg/send'; + + /// 直播间记录 + static const String liveRoomEntry = + '${HttpString.liveBaseUrl}/xlive/web-room/v1/index/roomEntryAction'; } diff --git a/lib/http/live.dart b/lib/http/live.dart index f6fc4ea4..3935f154 100644 --- a/lib/http/live.dart +++ b/lib/http/live.dart @@ -117,4 +117,15 @@ class LiveHttp { }; } } + + // 直播历史记录 + static Future liveRoomEntry({required int roomId}) async { + await Request().post(Api.liveRoomEntry, queryParameters: { + 'room_id': roomId, + 'platform': 'pc', + 'csrf_token': await Request.getCsrf(), + 'csrf': await Request.getCsrf(), + 'visit_id': '', + }); + } } diff --git a/lib/pages/live_room/controller.dart b/lib/pages/live_room/controller.dart index 5d4e2b67..fdc25216 100644 --- a/lib/pages/live_room/controller.dart +++ b/lib/pages/live_room/controller.dart @@ -95,6 +95,7 @@ class LiveRoomController extends GetxController { autoplay: true, ); plPlayerController.isOpenDanmu.value = danmakuSwitch.value; + heartBeat(); } Future queryLiveInfo() async { @@ -278,8 +279,20 @@ class LiveRoomController extends GetxController { } } + // 历史记录 + void heartBeat() { + LiveHttp.liveRoomEntry(roomId: roomId); + } + + String encodeToBase64(String input) { + List bytes = utf8.encode(input); + String base64Str = base64.encode(bytes); + return base64Str; + } + @override void onClose() { + heartBeat(); plSocket?.onClose(); super.onClose(); } From 79c148adebce3dc4dff3512f75daf6e964420c55 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 29 Sep 2024 01:12:43 +0800 Subject: [PATCH 19/26] =?UTF-8?q?fix:=20=E9=93=BE=E6=8E=A5=E5=85=9C?= =?UTF-8?q?=E5=BA=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/webview/controller.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pages/webview/controller.dart b/lib/pages/webview/controller.dart index e0ff113c..0fa24dea 100644 --- a/lib/pages/webview/controller.dart +++ b/lib/pages/webview/controller.dart @@ -95,6 +95,6 @@ class WebviewController extends GetxController { }, ), ) - ..loadRequest(Uri.parse(url)); + ..loadRequest(Uri.parse(url.startsWith('http') ? url : 'https://$url')); } } From 11aa465a8f9aee7fdc63476df59d4e42d7d2d724 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 29 Sep 2024 14:01:26 +0800 Subject: [PATCH 20/26] =?UTF-8?q?feat:=20=E7=A7=81=E4=BF=A1=E5=9B=BE?= =?UTF-8?q?=E7=89=87=E6=9F=A5=E7=9C=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/whisper/view.dart | 17 +++--- lib/pages/whisper_detail/controller.dart | 13 +++++ lib/pages/whisper_detail/view.dart | 28 ++++------ .../whisper_detail/widget/chat_item.dart | 54 +++++++++++++++++-- 4 files changed, 83 insertions(+), 29 deletions(-) diff --git a/lib/pages/whisper/view.dart b/lib/pages/whisper/view.dart index 7082619f..e97aa79b 100644 --- a/lib/pages/whisper/view.dart +++ b/lib/pages/whisper/view.dart @@ -217,6 +217,7 @@ class SessionItem extends StatelessWidget { final String heroTag = Utils.makeHeroTag(sessionItem.accountInfo?.mid ?? 0); final content = sessionItem.lastMsg.content; final msgStatus = sessionItem.lastMsg.msgStatus; + final int msgType = sessionItem.lastMsg.msgType; return ListTile( onTap: () { @@ -251,13 +252,15 @@ class SessionItem extends StatelessWidget { subtitle: Text( msgStatus == 1 ? '你撤回了一条消息' - : content != null && content != '' - ? (content['text'] ?? - content['content'] ?? - content['title'] ?? - content['reply_content'] ?? - '不支持的消息类型') - : '不支持的消息类型', + : msgType == 2 + ? '[图片]' + : content != null && content != '' + ? (content['text'] ?? + content['content'] ?? + content['title'] ?? + content['reply_content'] ?? + '不支持的消息类型') + : '不支持的消息类型', maxLines: 1, overflow: TextOverflow.ellipsis, style: Theme.of(context) diff --git a/lib/pages/whisper_detail/controller.dart b/lib/pages/whisper_detail/controller.dart index 32e0ceb0..ec828afb 100644 --- a/lib/pages/whisper_detail/controller.dart +++ b/lib/pages/whisper_detail/controller.dart @@ -22,6 +22,7 @@ class WhisperDetailController extends GetxController { final TextEditingController replyContentController = TextEditingController(); Box userInfoCache = GStrorage.userInfo; List emoteList = []; + List picList = []; @override void onInit() { @@ -41,6 +42,18 @@ class WhisperDetailController extends GetxController { var res = await MsgHttp.sessionMsg(talkerId: talkerId); if (res['status']) { messageList.value = res['data'].messages; + // 找出图片 + try { + for (var item in messageList) { + if (item.msgType == 2) { + picList.add(item.content['url']); + } + } + picList = picList.reversed.toList(); + } catch (e) { + print('e: $e'); + } + if (messageList.isNotEmpty) { ackSessionMsg(); if (res['data'].eInfos != null) { diff --git a/lib/pages/whisper_detail/view.dart b/lib/pages/whisper_detail/view.dart index 912b5dc5..3ea59343 100644 --- a/lib/pages/whisper_detail/view.dart +++ b/lib/pages/whisper_detail/view.dart @@ -193,27 +193,21 @@ class _WhisperDetailPageState extends State ? const SizedBox() : Align( alignment: Alignment.topCenter, - child: ListView.builder( + child: ListView.separated( itemCount: messageList.length, shrinkWrap: true, reverse: true, itemBuilder: (_, int i) { - if (i == 0) { - return Column( - children: [ - ChatItem( - item: messageList[i], - e_infos: _whisperDetailController - .eInfos), - const SizedBox(height: 20), - ], - ); - } else { - return ChatItem( - item: messageList[i], - e_infos: - _whisperDetailController.eInfos); - } + return ChatItem( + item: messageList[i], + e_infos: _whisperDetailController.eInfos, + ctr: _whisperDetailController, + ); + }, + separatorBuilder: (_, int i) { + return i == 0 + ? const SizedBox(height: 20) + : const SizedBox.shrink(); }, ), ), diff --git a/lib/pages/whisper_detail/widget/chat_item.dart b/lib/pages/whisper_detail/widget/chat_item.dart index 94347aff..7ddd1d83 100644 --- a/lib/pages/whisper_detail/widget/chat_item.dart +++ b/lib/pages/whisper_detail/widget/chat_item.dart @@ -2,14 +2,18 @@ // ignore_for_file: constant_identifier_names import 'dart:convert'; +import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:pilipala/common/widgets/network_img_layer.dart'; +import 'package:pilipala/plugin/pl_gallery/hero_dialog_route.dart'; +import 'package:pilipala/plugin/pl_gallery/interactiveviewer_gallery.dart'; import 'package:pilipala/utils/route_push.dart'; import 'package:pilipala/utils/utils.dart'; import 'package:pilipala/utils/storage.dart'; import '../../../http/search.dart'; +import '../controller.dart'; enum MsgType { invalid(value: 0, label: "空空的~"), @@ -42,10 +46,12 @@ enum MsgType { class ChatItem extends StatelessWidget { dynamic item; List? e_infos; + WhisperDetailController ctr; ChatItem({ super.key, - this.item, + required this.item, + required this.ctr, this.e_infos, }); @@ -157,10 +163,48 @@ class ChatItem extends StatelessWidget { case MsgType.text: return richTextMessage(context); case MsgType.pic: - return NetworkImgLayer( - width: 220, - height: 220 * content['height'] / content['width'], - src: content['url'], + return InkWell( + onTap: () { + Navigator.of(context).push( + HeroDialogRoute( + builder: (BuildContext context) => InteractiveviewerGallery( + sources: ctr.picList, + initIndex: ctr.picList.indexOf(content['url']), + itemBuilder: ( + BuildContext context, + int index, + bool isFocus, + bool enablePageView, + ) { + return GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + if (enablePageView) { + Navigator.of(context).pop(); + } + }, + child: Center( + child: Hero( + tag: ctr.picList[index], + child: CachedNetworkImage( + fadeInDuration: const Duration(milliseconds: 0), + imageUrl: ctr.picList[index], + fit: BoxFit.contain, + ), + ), + ), + ); + }, + onPageChanged: (int pageIndex) {}, + ), + ), + ); + }, + child: NetworkImgLayer( + width: 220, + height: 220 * content['height'] / content['width'], + src: content['url'], + ), ); case MsgType.share_v2: return Column( From b6390ea626f3aaa0e02b17761b867f17095cd612 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 29 Sep 2024 14:07:21 +0800 Subject: [PATCH 21/26] =?UTF-8?q?fix:=20read=E4=B8=93=E6=A0=8F=E5=9B=BE?= =?UTF-8?q?=E7=89=87=E6=B5=8F=E8=A7=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/common/widgets/html_render.dart | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/common/widgets/html_render.dart b/lib/common/widgets/html_render.dart index c626978e..b2aa75ff 100644 --- a/lib/common/widgets/html_render.dart +++ b/lib/common/widgets/html_render.dart @@ -1,11 +1,9 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:flutter_html/flutter_html.dart'; -import 'package:get/get.dart'; import 'package:pilipala/plugin/pl_gallery/hero_dialog_route.dart'; import 'package:pilipala/plugin/pl_gallery/interactiveviewer_gallery.dart'; import 'package:pilipala/utils/highlight.dart'; -import 'network_img_layer.dart'; // ignore: must_be_immutable class HtmlRender extends StatelessWidget { @@ -85,11 +83,11 @@ class HtmlRender extends StatelessWidget { }, child: Center( child: Hero( - tag: imgUrl, + tag: imgList?[index] ?? imgUrl, child: CachedNetworkImage( fadeInDuration: const Duration(milliseconds: 0), - imageUrl: imgUrl, + imageUrl: imgList?[index] ?? imgUrl, fit: BoxFit.contain, ), ), From c3d23dfdba23325ec3b93c79054bfc0f656580c3 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 29 Sep 2024 15:29:08 +0800 Subject: [PATCH 22/26] typo --- lib/pages/video/detail/controller.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/pages/video/detail/controller.dart b/lib/pages/video/detail/controller.dart index c8be4f43..d7b1529a 100644 --- a/lib/pages/video/detail/controller.dart +++ b/lib/pages/video/detail/controller.dart @@ -115,7 +115,7 @@ class VideoDetailController extends GetxController ].obs; RxDouble sheetHeight = 0.0.obs; RxString archiveSourceType = 'dash'.obs; - ScrollController? replyScrillController; + ScrollController? replyScrollController; List mediaList = []; RxBool isWatchLaterVisible = false.obs; RxString watchLaterTitle = ''.obs; @@ -574,12 +574,12 @@ class VideoDetailController extends GetxController } void onControllerCreated(ScrollController controller) { - replyScrillController = controller; + replyScrollController = controller; } void onTapTabbar(int index) { if (index == 1 && tabCtr.index == 1) { - replyScrillController?.animateTo(0, + replyScrollController?.animateTo(0, duration: const Duration(milliseconds: 300), curve: Curves.ease); } } From ed9a75ecd3c46bf91af15fbe30b264f2f6ebcc5c Mon Sep 17 00:00:00 2001 From: guozhigq Date: Mon, 30 Sep 2024 11:23:40 +0800 Subject: [PATCH 23/26] =?UTF-8?q?fix:=20=E8=A7=86=E9=A2=91=E6=80=BB?= =?UTF-8?q?=E7=BB=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/models/video/ai.dart | 8 ++++---- .../video/detail/introduction/controller.dart | 4 ++-- lib/pages/video/detail/widgets/ai_detail.dart | 19 +++++++++++-------- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/lib/models/video/ai.dart b/lib/models/video/ai.dart index a06fa79d..0816c09d 100644 --- a/lib/models/video/ai.dart +++ b/lib/models/video/ai.dart @@ -39,11 +39,11 @@ class ModelResult { ModelResult.fromJson(Map json) { resultType = json['result_type']; summary = json['summary']; - outline = json['result_type'] == 2 - ? json['outline'] + outline = json['result_type'] == 0 + ? [] + : json['outline'] .map((e) => OutlineItem.fromJson(e)) - .toList() - : []; + .toList(); } } diff --git a/lib/pages/video/detail/introduction/controller.dart b/lib/pages/video/detail/introduction/controller.dart index 04a1249a..c0f6eebb 100644 --- a/lib/pages/video/detail/introduction/controller.dart +++ b/lib/pages/video/detail/introduction/controller.dart @@ -541,7 +541,7 @@ class VideoIntroController extends GetxController { // ai总结 Future aiConclusion() async { - SmartDialog.showLoading(msg: '正在生产ai总结'); + SmartDialog.showLoading(msg: '正在生成ai总结'); final res = await VideoHttp.aiConclusion( bvid: bvid, cid: lastPlayCid.value, @@ -551,7 +551,7 @@ class VideoIntroController extends GetxController { if (res['status']) { modelResult = res['data'].modelResult; } else { - SmartDialog.showToast("当前视频可能暂不支持AI视频总结"); + SmartDialog.showToast("当前视频暂不支持AI视频总结"); } return res; } diff --git a/lib/pages/video/detail/widgets/ai_detail.dart b/lib/pages/video/detail/widgets/ai_detail.dart index 37d51106..b71b026d 100644 --- a/lib/pages/video/detail/widgets/ai_detail.dart +++ b/lib/pages/video/detail/widgets/ai_detail.dart @@ -49,15 +49,18 @@ class AiDetail extends StatelessWidget { child: SingleChildScrollView( child: Column( children: [ - SelectableText( - modelResult!.summary!, - style: const TextStyle( - fontSize: 15, - fontWeight: FontWeight.bold, - height: 1.5, + if (modelResult!.resultType != 0 && + modelResult!.summary != '') ...[ + SelectableText( + modelResult!.summary!, + style: const TextStyle( + fontSize: 15, + fontWeight: FontWeight.bold, + height: 1.5, + ), ), - ), - const SizedBox(height: 20), + const SizedBox(height: 20), + ], ListView.builder( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), From 66d2ac9777bb3038e792d3d6e0ef7cc0c5eac921 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Mon, 30 Sep 2024 11:38:39 +0800 Subject: [PATCH 24/26] =?UTF-8?q?fix:=20=20=E7=B2=89=E4=B8=9D=E4=B8=8D?= =?UTF-8?q?=E5=8F=AF=E8=A7=81=E6=97=B6=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/fan/controller.dart | 1 - lib/pages/fan/view.dart | 14 +++++++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/lib/pages/fan/controller.dart b/lib/pages/fan/controller.dart index c1c2a427..6661d9fe 100644 --- a/lib/pages/fan/controller.dart +++ b/lib/pages/fan/controller.dart @@ -49,7 +49,6 @@ class FansController extends GetxController { } else if (type == 'onLoad') { fansList.addAll(res['data'].list); } - print(total); if ((pn == 1 && total < ps) || res['data'].list.isEmpty) { loadingText.value = '没有更多了'; } diff --git a/lib/pages/fan/view.dart b/lib/pages/fan/view.dart index 47372057..5d5c02a7 100644 --- a/lib/pages/fan/view.dart +++ b/lib/pages/fan/view.dart @@ -103,9 +103,17 @@ class _FansPageState extends State { ), ); } else { - return HttpError( - errMsg: data['msg'], - fn: () => _fansController.queryFans('init'), + return CustomScrollView( + physics: const NeverScrollableScrollPhysics(), + slivers: [ + HttpError( + errMsg: data['msg'], + fn: () { + _futureBuilderFuture = + _fansController.queryFans('init'); + }, + ) + ], ); } } else { From 19866fe08054fe16b418f49017b41dff27a5c82a Mon Sep 17 00:00:00 2001 From: guozhigq Date: Mon, 30 Sep 2024 12:00:30 +0800 Subject: [PATCH 25/26] =?UTF-8?q?fix:=20=E8=A7=86=E9=A2=91=E8=AF=84?= =?UTF-8?q?=E8=AE=BA=E5=9B=9E=E9=A1=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/video/detail/controller.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pages/video/detail/controller.dart b/lib/pages/video/detail/controller.dart index d7b1529a..a57ec1de 100644 --- a/lib/pages/video/detail/controller.dart +++ b/lib/pages/video/detail/controller.dart @@ -578,7 +578,7 @@ class VideoDetailController extends GetxController } void onTapTabbar(int index) { - if (index == 1 && tabCtr.index == 1) { + if (tabCtr.animation!.isCompleted && index == 1 && tabCtr.index == 1) { replyScrollController?.animateTo(0, duration: const Duration(milliseconds: 300), curve: Curves.ease); } From 877eeded37c0f0cc5d08db915a1933e3b687433c Mon Sep 17 00:00:00 2001 From: guozhigq Date: Mon, 30 Sep 2024 13:09:40 +0800 Subject: [PATCH 26/26] =?UTF-8?q?fix:=20=E9=BB=91=E5=90=8D=E5=8D=95?= =?UTF-8?q?=E5=B1=95=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/blacklist/index.dart | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/pages/blacklist/index.dart b/lib/pages/blacklist/index.dart index 402790f5..fb7e0891 100644 --- a/lib/pages/blacklist/index.dart +++ b/lib/pages/blacklist/index.dart @@ -61,7 +61,7 @@ class _BlackListPageState extends State { centerTitle: false, title: Obx( () => Text( - '黑名单管理 - ${_blackListController.total.value}', + '黑名单管理 ${_blackListController.total.value == 0 ? '' : '- ${_blackListController.total.value}'}', style: Theme.of(context).textTheme.titleMedium, ), ), @@ -76,8 +76,12 @@ class _BlackListPageState extends State { if (data['status']) { List list = _blackListController.blackList; return Obx( - () => list.length == 1 - ? const SizedBox() + () => list.isEmpty + ? CustomScrollView( + slivers: [ + HttpError(errMsg: '你没有拉黑任何人哦~_~', fn: () => {}) + ], + ) : ListView.builder( controller: scrollController, itemCount: list.length,