From 3daa06a198633107d9503c11a4c65f78ebd791db Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sat, 16 Sep 2023 21:47:27 +0800 Subject: [PATCH 01/29] =?UTF-8?q?feat:=20=E4=B8=93=E6=A0=8F=E6=96=87?= =?UTF-8?q?=E7=AB=A0=E6=B8=B2=E6=9F=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/common/widgets/html_render.dart | 120 ++--- lib/common/widgets/video_card_v.dart | 9 + lib/http/html.dart | 49 +- lib/http/init.dart | 29 +- lib/pages/dynamics/controller.dart | 28 +- .../dynamics/widgets/rich_node_panel.dart | 6 +- lib/pages/html/controller.dart | 97 +++- lib/pages/html/view.dart | 480 +++++++++++++++--- 8 files changed, 649 insertions(+), 169 deletions(-) diff --git a/lib/common/widgets/html_render.dart b/lib/common/widgets/html_render.dart index 6733d7cb..2e97ceed 100644 --- a/lib/common/widgets/html_render.dart +++ b/lib/common/widgets/html_render.dart @@ -1,7 +1,7 @@ -import 'package:cached_network_image/cached_network_image.dart'; import 'package:get/get.dart'; import 'package:flutter/material.dart'; import 'package:flutter_html/flutter_html.dart'; +import 'package:pilipala/common/widgets/network_img_layer.dart'; // ignore: must_be_immutable class HtmlRender extends StatelessWidget { @@ -20,35 +20,47 @@ class HtmlRender extends StatelessWidget { Widget build(BuildContext context) { return Html( data: htmlContent, - // tagsList: Html.tags..addAll(["form", "label", "input"]), onLinkTap: (url, buildContext, attributes) => {}, extensions: [ TagExtension( tagsToExtend: {"img"}, builder: (extensionContext) { - String? imgUrl = extensionContext.attributes['src']; - if (imgUrl!.startsWith('//')) { - imgUrl = 'https:$imgUrl'; + try { + Map attributes = extensionContext.attributes; + List key = attributes.keys.toList(); + String? imgUrl = key.contains('src') + ? attributes['src'] + : attributes['data-src']; + if (imgUrl!.startsWith('//')) { + imgUrl = 'https:$imgUrl'; + } + if (imgUrl.startsWith('http://')) { + imgUrl = imgUrl.replaceAll('http://', 'https://'); + } + imgUrl = imgUrl.contains('@') ? imgUrl.split('@').first : imgUrl; + bool isEmote = imgUrl.contains('/emote/'); + bool isMall = imgUrl.contains('/mall/'); + if (isMall) { + return const SizedBox(); + } + // bool inTable = + // extensionContext.element!.previousElementSibling == null || + // extensionContext.element!.nextElementSibling == null; + // imgUrl = Utils().imageUrl(imgUrl!); + // return Image.network( + // imgUrl, + // width: isEmote ? 22 : null, + // height: isEmote ? 22 : null, + // ); + return NetworkImgLayer( + width: isEmote ? 22 : Get.size.width - 24, + height: isEmote ? 22 : 200, + src: imgUrl, + ); + } catch (err) { + print(err); + return const SizedBox(); } - if (imgUrl.startsWith('http://')) { - imgUrl = imgUrl.replaceAll('http://', 'https://'); - } - - print(imgUrl); - bool isEmote = imgUrl.contains('/emote/'); - bool isMall = imgUrl.contains('/mall/'); - if (isMall) { - return SizedBox(); - } - // bool inTable = - // extensionContext.element!.previousElementSibling == null || - // extensionContext.element!.nextElementSibling == null; - // imgUrl = Utils().imageUrl(imgUrl!); - return Image.network( - imgUrl, - width: isEmote ? 22 : null, - height: isEmote ? 22 : null, - ); }, ), ], @@ -63,11 +75,13 @@ class HtmlRender extends StatelessWidget { textDecoration: TextDecoration.none, ), "p": Style( - margin: Margins.only(bottom: 0), + margin: Margins.only(bottom: 10), ), "span": Style( fontSize: FontSize.medium, + height: Height(1.65), ), + "div": Style(height: Height.auto()), "li > p": Style( display: Display.inline, ), @@ -75,61 +89,7 @@ class HtmlRender extends StatelessWidget { padding: HtmlPaddings.only(bottom: 4), textAlign: TextAlign.justify, ), - "image": Style(margin: Margins.only(top: 4, bottom: 4)), - "p > img": Style(margin: Margins.only(top: 4, bottom: 4)), - "code": Style( - backgroundColor: Theme.of(context).colorScheme.onInverseSurface), - "code > span": Style(textAlign: TextAlign.start), - "hr": Style( - margin: Margins.zero, - padding: HtmlPaddings.zero, - border: Border( - top: BorderSide( - width: 1.0, - color: - Theme.of(context).colorScheme.onBackground.withOpacity(0.3), - ), - ), - ), - 'table': Style( - border: Border( - right: BorderSide( - width: 0.5, - color: - Theme.of(context).colorScheme.onBackground.withOpacity(0.3), - ), - bottom: BorderSide( - width: 0.5, - color: - Theme.of(context).colorScheme.onBackground.withOpacity(0.3), - ), - ), - ), - 'tr': Style( - border: Border( - top: BorderSide( - width: 1.0, - color: - Theme.of(context).colorScheme.onBackground.withOpacity(0.3), - ), - left: BorderSide( - width: 1.0, - color: - Theme.of(context).colorScheme.onBackground.withOpacity(0.3), - ), - ), - ), - 'thead': Style( - backgroundColor: Theme.of(context).colorScheme.background, - ), - 'th': Style( - padding: HtmlPaddings.only(left: 3, right: 3), - ), - 'td': Style( - padding: HtmlPaddings.all(4.0), - alignment: Alignment.center, - textAlign: TextAlign.center, - ), + "img": Style(margin: Margins.only(top: 4, bottom: 4)), }, ); } diff --git a/lib/common/widgets/video_card_v.dart b/lib/common/widgets/video_card_v.dart index cc23f110..9e34cbcb 100644 --- a/lib/common/widgets/video_card_v.dart +++ b/lib/common/widgets/video_card_v.dart @@ -62,6 +62,15 @@ class VideoCardV extends StatelessWidget { 'heroTag': heroTag, }); break; + // 动态 + case 'picture': + Get.toNamed('/htmlRender', parameters: { + 'url': videoItem.uri, + 'title': videoItem.title, + 'id': videoItem.param.toString(), + 'dynamicType': 'picture' + }); + break; default: SmartDialog.showToast(videoItem.goto); Get.toNamed( diff --git a/lib/http/html.dart b/lib/http/html.dart index ec92bcfa..4a922e8f 100644 --- a/lib/http/html.dart +++ b/lib/http/html.dart @@ -3,8 +3,12 @@ import 'package:html/parser.dart'; import 'package:pilipala/http/index.dart'; class HtmlHttp { - static Future reqHtml(id) async { - var response = await Request().get("https://www.bilibili.com/opus/$id"); + // article + static Future reqHtml(id, dynamicType) async { + var response = await Request().get( + "https://www.bilibili.com/opus/$id", + extra: {'ua': 'pc'}, + ); Document rootTree = parse(response.data); Element body = rootTree.body!; Element appDom = body.querySelector('#app')!; @@ -34,7 +38,46 @@ class HtmlHttp { 'uname': uname, 'updateTime': updateTime, 'content': opusContent, - 'commentId': commentId + 'commentId': int.parse(commentId) + }; + } + + // read + static Future reqReadHtml(id, dynamicType) async { + var response = await Request().get( + "https://www.bilibili.com/$dynamicType/$id/", + extra: {'ua': 'pc'}, + ); + Document rootTree = parse(response.data); + Element body = rootTree.body!; + Element appDom = body.querySelector('#app')!; + Element authorHeader = appDom.querySelector('.up-left')!; + // 头像 + // String avatar = + // authorHeader.querySelector('.bili-avatar-img')!.attributes['data-src']!; + // print(avatar); + // avatar = 'https:${avatar.split('@')[0]}'; + String uname = authorHeader.querySelector('.up-name')!.text.trim(); + // 动态详情 + Element opusDetail = appDom.querySelector('.article-content')!; + // 发布时间 + // String updateTime = + // opusDetail.querySelector('.opus-module-author__pub__text')!.text; + // print(updateTime); + + // + String opusContent = + opusDetail.querySelector('#read-article-holder')!.innerHtml; + RegExp digitRegExp = RegExp(r'\d+'); + Iterable matches = digitRegExp.allMatches(id); + String number = matches.first.group(0)!; + return { + 'status': true, + 'avatar': '', + 'uname': uname, + 'updateTime': '', + 'content': opusContent, + 'commentId': int.parse(number) }; } } diff --git a/lib/http/init.dart b/lib/http/init.dart index f927e2e5..4af20cae 100644 --- a/lib/http/init.dart +++ b/lib/http/init.dart @@ -130,11 +130,19 @@ class Request { Response response; Options options; ResponseType resType = ResponseType.json; - if (extra != null) { - resType = extra!['resType'] ?? ResponseType.json; - } + options = Options(); options.responseType = resType; + + if (extra != null) { + options.responseType = extra!['resType'] ?? ResponseType.json; + if (extra['ua'] != null) { + print(options.headers); + options.headers = {'user-agent': headerUa(type: extra['ua'])}; + // options.headers!['user-agent'] = headerUa(type: extra['ua']); + } + } + try { response = await dio.get( url, @@ -201,14 +209,19 @@ class Request { token.cancel("cancelled"); } - String headerUa() { + String headerUa({type = 'mob'}) { String headerUa = ''; - if (Platform.isIOS) { - headerUa = - 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1 Mobile/15E148 Safari/604.1'; + if (type == 'mob') { + if (Platform.isIOS) { + headerUa = + 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1 Mobile/15E148 Safari/604.1'; + } else { + headerUa = + 'Mozilla/5.0 (Linux; Android 10; SM-G975F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.101 Mobile Safari/537.36'; + } } else { headerUa = - 'Mozilla/5.0 (Linux; Android 10; SM-G975F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.101 Mobile Safari/537.36'; + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.2 Safari/605.1.15'; } return headerUa; } diff --git a/lib/pages/dynamics/controller.dart b/lib/pages/dynamics/controller.dart index 5b524510..26ba2b22 100644 --- a/lib/pages/dynamics/controller.dart +++ b/lib/pages/dynamics/controller.dart @@ -149,10 +149,30 @@ class DynamicsController extends GetxController { case 'DYNAMIC_TYPE_ARTICLE': String title = item.modules.moduleDynamic.major.opus.title; String url = item.modules.moduleDynamic.major.opus.jumpUrl; - Get.toNamed( - '/webview', - parameters: {'url': 'https:$url', 'type': 'note', 'pageTitle': title}, - ); + if (url.contains('opus') || url.contains('read')) { + RegExp digitRegExp = RegExp(r'\d+'); + Iterable matches = digitRegExp.allMatches(url); + String number = matches.first.group(0)!; + if (url.contains('read')) { + number = 'cv$number'; + } + Get.toNamed('/htmlRender', parameters: { + 'url': url.startsWith('//') ? url.split('//').last : url, + 'title': title, + 'id': number, + 'dynamicType': url.split('//').last.split('/')[1] + }); + } else { + Get.toNamed( + '/webview', + parameters: { + 'url': 'https:$url', + 'type': 'note', + 'pageTitle': title + }, + ); + } + break; case 'DYNAMIC_TYPE_PGC': print('番剧'); diff --git a/lib/pages/dynamics/widgets/rich_node_panel.dart b/lib/pages/dynamics/widgets/rich_node_panel.dart index 61422ceb..27820b27 100644 --- a/lib/pages/dynamics/widgets/rich_node_panel.dart +++ b/lib/pages/dynamics/widgets/rich_node_panel.dart @@ -225,8 +225,10 @@ InlineSpan richNode(item, context) { width: box.maxWidth / 2, height: box.maxWidth * 0.5 * - pictureItem.height! / - pictureItem.width!, + (pictureItem.height != null && + pictureItem.width != null + ? pictureItem.height! / pictureItem.width! + : 1), ), ), ); diff --git a/lib/pages/html/controller.dart b/lib/pages/html/controller.dart index 2ec55621..f3187828 100644 --- a/lib/pages/html/controller.dart +++ b/lib/pages/html/controller.dart @@ -1,19 +1,112 @@ +import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:hive/hive.dart'; import 'package:pilipala/http/html.dart'; +import 'package:pilipala/http/reply.dart'; +import 'package:pilipala/models/common/reply_sort_type.dart'; +import 'package:pilipala/models/video/reply/item.dart'; +import 'package:pilipala/utils/feed_back.dart'; +import 'package:pilipala/utils/storage.dart'; class HtmlRenderController extends GetxController { late String id; + late String dynamicType; + late int type; + RxInt oid = (-1).obs; late Map response; + int? floor; + int currentPage = 0; + bool isLoadingMore = false; + RxString noMore = ''.obs; + RxList replyList = [].obs; + RxInt acount = 0.obs; + final ScrollController scrollController = ScrollController(); + + ReplySortType _sortType = ReplySortType.time; + RxString sortTypeTitle = ReplySortType.time.titles.obs; + RxString sortTypeLabel = ReplySortType.time.labels.obs; + Box setting = GStrorage.setting; @override void onInit() { super.onInit(); id = Get.parameters['id']!; + dynamicType = Get.parameters['dynamicType']!; + type = dynamicType == 'picture' ? 11 : 12; } - Future reqHtml() async { - var res = await HtmlHttp.reqHtml(id); + // 请求动态内容 + Future reqHtml(id) async { + late dynamic res; + if (dynamicType == 'opus' || dynamicType == 'picture') { + res = await HtmlHttp.reqHtml(id, dynamicType); + } else { + res = await HtmlHttp.reqReadHtml(id, dynamicType); + } response = res; + oid.value = res['commentId']; return res; } + + // 请求评论 + Future queryReplyList({reqType = 'init'}) async { + var res = await ReplyHttp.replyList( + oid: oid.value, + pageNum: currentPage + 1, + type: type, + sort: _sortType.index, + ); + if (res['status']) { + List replies = res['data'].replies; + acount.value = res['data'].page.acount; + if (replies.isNotEmpty) { + currentPage++; + noMore.value = '加载中...'; + if (replies.length < 20) { + noMore.value = '没有更多了'; + } + } else { + noMore.value = currentPage == 0 ? '还没有评论' : '没有更多了'; + } + if (reqType == 'init') { + // 添加置顶回复 + if (res['data'].upper.top != null) { + bool flag = res['data'] + .topReplies + .any((reply) => reply.rpid == res['data'].upper.top.rpid); + if (!flag) { + replies.insert(0, res['data'].upper.top); + } + } + replies.insertAll(0, res['data'].topReplies); + replyList.value = replies; + } else { + replyList.addAll(replies); + } + } + isLoadingMore = false; + return res; + } + + // 排序搜索评论 + queryBySort() { + feedBack(); + switch (_sortType) { + case ReplySortType.time: + _sortType = ReplySortType.like; + break; + case ReplySortType.like: + _sortType = ReplySortType.reply; + break; + case ReplySortType.reply: + _sortType = ReplySortType.time; + break; + default: + } + sortTypeTitle.value = _sortType.titles; + sortTypeLabel.value = _sortType.labels; + currentPage = 0; + replyList.clear(); + queryReplyList(reqType: 'init'); + } } diff --git a/lib/pages/html/view.dart b/lib/pages/html/view.dart index f8572b14..d5e4556d 100644 --- a/lib/pages/html/view.dart +++ b/lib/pages/html/view.dart @@ -1,7 +1,19 @@ +import 'package:easy_debounce/easy_throttle.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; +import 'package:pilipala/common/skeleton/video_reply.dart'; import 'package:pilipala/common/widgets/html_render.dart'; +import 'package:pilipala/common/widgets/http_error.dart'; import 'package:pilipala/common/widgets/network_img_layer.dart'; +import 'package:pilipala/models/common/reply_type.dart'; +import 'package:pilipala/pages/mine/index.dart'; +import 'package:pilipala/pages/video/detail/reply/widgets/reply_item.dart'; +import 'package:pilipala/pages/video/detail/replyNew/index.dart'; +import 'package:pilipala/pages/video/detail/replyReply/index.dart'; +import 'package:pilipala/utils/feed_back.dart'; import 'controller.dart'; @@ -12,16 +24,104 @@ class HtmlRenderPage extends StatefulWidget { State createState() => _HtmlRenderPageState(); } -class _HtmlRenderPageState extends State { - HtmlRenderController htmlRenderCtr = Get.put(HtmlRenderController()); +class _HtmlRenderPageState extends State + with TickerProviderStateMixin { + final HtmlRenderController _htmlRenderCtr = Get.put(HtmlRenderController()); late String title; late String id; + late String url; + late String dynamicType; + late int type; + bool _isFabVisible = true; + late Future _futureBuilderFuture; + late ScrollController scrollController; + late AnimationController fabAnimationCtr; @override void initState() { super.initState(); title = Get.parameters['title']!; id = Get.parameters['id']!; + url = Get.parameters['url']!; + dynamicType = Get.parameters['dynamicType']!; + type = dynamicType == 'picture' ? 11 : 12; + _futureBuilderFuture = _htmlRenderCtr.reqHtml(id); + fabAnimationCtr = AnimationController( + vsync: this, + duration: const Duration(milliseconds: 300), + ); + scrollListener(); + } + + void scrollListener() { + scrollController = _htmlRenderCtr.scrollController; + scrollController.addListener( + () { + // 分页加载 + if (scrollController.position.pixels >= + scrollController.position.maxScrollExtent - 300) { + EasyThrottle.throttle('replylist', const Duration(seconds: 2), () { + _htmlRenderCtr.queryReplyList(reqType: 'onLoad'); + }); + } + + // 标题 + // if (scrollController.offset > 55 && !_visibleTitle) { + // _visibleTitle = true; + // titleStreamC.add(true); + // } else if (scrollController.offset <= 55 && _visibleTitle) { + // _visibleTitle = false; + // titleStreamC.add(false); + // } + + // fab按钮 + final ScrollDirection direction = + scrollController.position.userScrollDirection; + if (direction == ScrollDirection.forward) { + _showFab(); + } else if (direction == ScrollDirection.reverse) { + _hideFab(); + } + }, + ); + } + + void _showFab() { + if (!_isFabVisible) { + _isFabVisible = true; + fabAnimationCtr.forward(); + } + } + + void _hideFab() { + if (_isFabVisible) { + _isFabVisible = false; + fabAnimationCtr.reverse(); + } + } + + void replyReply(replyItem) { + int oid = replyItem.oid; + int rpid = replyItem.rpid!; + Get.to( + () => Scaffold( + appBar: AppBar( + titleSpacing: 0, + centerTitle: false, + title: Text( + '评论详情', + style: Theme.of(context).textTheme.titleMedium, + ), + ), + body: VideoReplyReplyPanel( + oid: oid, + rpid: rpid, + source: 'dynamic', + replyType: ReplyType.values[type], + firstFloor: replyItem, + ), + ), + ); } @override @@ -29,88 +129,328 @@ class _HtmlRenderPageState extends State { return Scaffold( appBar: AppBar( centerTitle: false, - title: Text(title), + titleSpacing: 0, + title: Text( + title, + style: Theme.of(context).textTheme.titleMedium, + ), + actions: [ + const SizedBox(width: 4), + IconButton( + onPressed: () { + Get.toNamed('/webview', parameters: { + 'url': 'https:$url', + 'type': 'url', + 'pageTitle': title, + }); + }, + icon: const Icon(Icons.open_in_browser_outlined, size: 19), + ), + PopupMenuButton( + icon: const Icon(Icons.more_vert), + itemBuilder: (BuildContext context) => [ + PopupMenuItem( + onTap: () => { + Clipboard.setData(ClipboardData(text: url)), + SmartDialog.showToast('已复制'), + }, + child: const Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(Icons.copy_rounded, size: 19), + SizedBox(width: 10), + Text('复制链接'), + ], + ), + ), + PopupMenuItem( + onTap: () => {}, + child: const Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(Icons.share_outlined, size: 19), + SizedBox(width: 10), + Text('分享'), + ], + ), + ), + ], + ), + const SizedBox(width: 6) + ], ), - body: SingleChildScrollView( - child: Column( - children: [ - FutureBuilder( - future: htmlRenderCtr.reqHtml(), - builder: (context, snapshot) { - if (snapshot.connectionState == ConnectionState.done) { - var data = snapshot.data; - if (data['status']) { - return Column( - children: [ - Padding( - padding: const EdgeInsets.fromLTRB(12, 12, 12, 8), - child: Row( - children: [ - NetworkImgLayer( - width: 40, - height: 40, - type: 'avatar', - src: htmlRenderCtr.response['avatar']!, - ), - const SizedBox(width: 10), - Column( - crossAxisAlignment: CrossAxisAlignment.start, + body: Stack( + children: [ + SingleChildScrollView( + controller: scrollController, + child: Column( + children: [ + FutureBuilder( + future: _futureBuilderFuture, + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.done) { + var data = snapshot.data; + fabAnimationCtr.forward(); + if (data['status']) { + return Column( + children: [ + Padding( + padding: const EdgeInsets.fromLTRB(12, 12, 12, 8), + child: Row( children: [ - Text(htmlRenderCtr.response['uname'], - style: TextStyle( - fontSize: Theme.of(context) - .textTheme - .titleSmall! - .fontSize, - )), - Text( - htmlRenderCtr.response['updateTime'], - style: TextStyle( - color: - Theme.of(context).colorScheme.outline, - fontSize: Theme.of(context) - .textTheme - .labelSmall! - .fontSize, - ), + NetworkImgLayer( + width: 40, + height: 40, + type: 'avatar', + src: _htmlRenderCtr.response['avatar']!, ), + const SizedBox(width: 10), + Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Text(_htmlRenderCtr.response['uname'], + style: TextStyle( + fontSize: Theme.of(context) + .textTheme + .titleSmall! + .fontSize, + )), + Text( + _htmlRenderCtr.response['updateTime'], + style: TextStyle( + color: Theme.of(context) + .colorScheme + .outline, + fontSize: Theme.of(context) + .textTheme + .labelSmall! + .fontSize, + ), + ), + ], + ), + const Spacer(), ], ), - const Spacer(), - ], - ), - ), - Padding( - padding: const EdgeInsets.fromLTRB(12, 12, 12, 8), - child: HtmlRender( - htmlContent: htmlRenderCtr.response['content'], - ), - ), - Container( + ), + Padding( + padding: const EdgeInsets.fromLTRB(12, 8, 12, 8), + child: HtmlRender( + htmlContent: _htmlRenderCtr.response['content'], + ), + ), + Container( + decoration: BoxDecoration( + border: Border( + bottom: BorderSide( + width: 8, + color: Theme.of(context) + .dividerColor + .withOpacity(0.05), + ), + ), + ), + ), + ], + ); + } else { + return const Text('error'); + } + } else { + // 骨架屏 + return const SizedBox(); + } + }, + ), + Obx( + () => _htmlRenderCtr.oid.value != -1 + ? Container( decoration: BoxDecoration( + color: Theme.of(context).colorScheme.surface, border: Border( - bottom: BorderSide( - width: 8, + top: BorderSide( + width: 0.6, color: Theme.of(context) .dividerColor .withOpacity(0.05), ), ), ), - ), - ], - ); - } else { - return Text('error'); - } - } else { - // 骨架屏 - return const SizedBox(); - } - }, + height: 45, + padding: const EdgeInsets.only(left: 12, right: 6), + child: Row( + children: [ + const Text('回复'), + const Spacer(), + SizedBox( + height: 35, + child: TextButton.icon( + onPressed: () => _htmlRenderCtr.queryBySort(), + icon: const Icon(Icons.sort, size: 16), + label: Obx( + () => Text( + _htmlRenderCtr.sortTypeLabel.value, + style: const TextStyle(fontSize: 13), + ), + ), + ), + ) + ], + ), + ) + : const SizedBox(), + ), + Obx( + () => _htmlRenderCtr.oid.value != -1 + ? FutureBuilder( + future: _htmlRenderCtr.queryReplyList(), + builder: (context, snapshot) { + if (snapshot.connectionState == + ConnectionState.done) { + Map data = snapshot.data as Map; + if (snapshot.data['status']) { + // 请求成功 + return Obx( + () => _htmlRenderCtr.replyList.isEmpty && + _htmlRenderCtr.isLoadingMore + ? ListView.builder( + itemCount: 5, + shrinkWrap: true, + physics: + const NeverScrollableScrollPhysics(), + itemBuilder: (context, index) { + return const VideoReplySkeleton(); + }, + ) + : ListView.builder( + shrinkWrap: true, + physics: + const NeverScrollableScrollPhysics(), + itemCount: + _htmlRenderCtr.replyList.length + + 1, + itemBuilder: (context, index) { + if (index == + _htmlRenderCtr + .replyList.length) { + return Container( + padding: EdgeInsets.only( + bottom: + MediaQuery.of(context) + .padding + .bottom), + height: MediaQuery.of(context) + .padding + .bottom + + 100, + child: Center( + child: Obx( + () => Text( + _htmlRenderCtr + .noMore.value, + style: TextStyle( + fontSize: 12, + color: Theme.of(context) + .colorScheme + .outline, + ), + ), + ), + ), + ); + } else { + return ReplyItem( + replyItem: _htmlRenderCtr + .replyList[index], + showReplyRow: true, + replyLevel: '1', + replyReply: (replyItem) => + replyReply(replyItem), + replyType: + ReplyType.values[type], + addReply: (replyItem) { + _htmlRenderCtr + .replyList[index].replies! + .add(replyItem); + }, + ); + } + }, + ), + ); + } else { + // 请求错误 + return CustomScrollView( + slivers: [ + HttpError( + errMsg: data['msg'], + fn: () => setState(() {}), + ) + ], + ); + } + } else { + // 骨架屏 + return ListView.builder( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemCount: 5, + itemBuilder: (context, index) { + return const VideoReplySkeleton(); + }, + ); + } + }, + ) + : const SizedBox(), + ) + ], ), - ], - ), + ), + Positioned( + bottom: MediaQuery.of(context).padding.bottom + 14, + right: 14, + child: SlideTransition( + position: Tween( + begin: const Offset(0, 2), + end: const Offset(0, 0), + ).animate(CurvedAnimation( + parent: fabAnimationCtr, + curve: Curves.easeInOut, + )), + child: FloatingActionButton( + heroTag: null, + onPressed: () { + feedBack(); + showModalBottomSheet( + context: context, + isScrollControlled: true, + builder: (BuildContext context) { + return VideoReplyNewDialog( + oid: _htmlRenderCtr.oid.value, + root: 0, + parent: 0, + replyType: ReplyType.values[type], + ); + }, + ).then( + (value) => { + // 完成评论,数据添加 + if (value != null && value['data'] != null) + { + _htmlRenderCtr.replyList.add(value['data']), + _htmlRenderCtr.acount.value++ + } + }, + ); + }, + tooltip: '评论动态', + child: const Icon(Icons.reply), + ), + ), + ), + ], ), ); } From e9095932edc07d4256b713e6af9d8e7517c44ad8 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sat, 16 Sep 2023 22:51:04 +0800 Subject: [PATCH 02/29] =?UTF-8?q?fix:=20=E8=A7=86=E9=A2=91=E7=AE=80?= =?UTF-8?q?=E4=BB=8B=E6=B8=B2=E6=9F=93=E5=BC=82=E5=B8=B8=E3=80=81=E4=BA=8C?= =?UTF-8?q?=E6=A5=BC=E6=96=B0=E5=9B=9E=E5=A4=8D=E7=9A=84=E8=AF=84=E8=AE=BA?= =?UTF-8?q?=E6=B8=B2=E6=9F=93=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/video/detail/introduction/view.dart | 38 +++++++++++-------- .../video/detail/replyReply/controller.dart | 11 +++--- lib/pages/video/detail/replyReply/view.dart | 7 ++-- lib/pages/video/detail/view.dart | 11 ++++-- 4 files changed, 38 insertions(+), 29 deletions(-) diff --git a/lib/pages/video/detail/introduction/view.dart b/lib/pages/video/detail/introduction/view.dart index 410c14c6..e961f135 100644 --- a/lib/pages/video/detail/introduction/view.dart +++ b/lib/pages/video/detail/introduction/view.dart @@ -199,6 +199,9 @@ class _VideoInfoState extends State with TickerProviderStateMixin { // 视频介绍 showIntroDetail() { + if (loadingStatus) { + return; + } feedBack(); showBottomSheet( context: context, @@ -254,22 +257,25 @@ class _VideoInfoState extends State with TickerProviderStateMixin { ), ), const SizedBox(width: 20), - SizedBox( - width: 34, - height: 34, - child: IconButton( - style: ButtonStyle( - padding: - MaterialStateProperty.all(EdgeInsets.zero), - backgroundColor: - MaterialStateProperty.resolveWith((states) { - return t.highlightColor.withOpacity(0.2); - }), - ), - onPressed: showIntroDetail, - icon: Icon( - Icons.more_horiz, - color: Theme.of(context).colorScheme.primary, + Opacity( + opacity: loadingStatus ? 0 : 1, + child: SizedBox( + width: 34, + height: 34, + child: IconButton( + style: ButtonStyle( + padding: + MaterialStateProperty.all(EdgeInsets.zero), + backgroundColor: + MaterialStateProperty.resolveWith((states) { + return t.highlightColor.withOpacity(0.2); + }), + ), + onPressed: showIntroDetail, + icon: Icon( + Icons.more_horiz, + color: Theme.of(context).colorScheme.primary, + ), ), ), ), diff --git a/lib/pages/video/detail/replyReply/controller.dart b/lib/pages/video/detail/replyReply/controller.dart index bd5cfd1f..6ce3722f 100644 --- a/lib/pages/video/detail/replyReply/controller.dart +++ b/lib/pages/video/detail/replyReply/controller.dart @@ -26,11 +26,6 @@ class VideoReplyReplyController extends GetxController { currentPage = 0; } - // 上拉加载 - Future onLoad() async { - queryReplyList(type: 'onLoad'); - } - Future queryReplyList({type = 'init'}) async { if (type == 'init') { currentPage = 0; @@ -49,11 +44,11 @@ class VideoReplyReplyController extends GetxController { if (replyList.length == res['data'].page.count) { noMore.value = '没有更多了'; } + currentPage++; } else { // 未登录状态replies可能返回null noMore.value = currentPage == 0 ? '还没有评论' : '没有更多了'; } - currentPage++; if (type == 'init') { // List replies = res['data'].replies; // 添加置顶回复 @@ -72,6 +67,10 @@ class VideoReplyReplyController extends GetxController { // res['data'].replies = replies; replyList.value = replies; } else { + // 每次回复之后,翻页请求有且只有相同的一条回复数据 + if (replies.length == 1 && replies.last.rpid == replyList.last.rpid) { + return; + } replyList.addAll(replies); // res['data'].replies.addAll(replyList); } diff --git a/lib/pages/video/detail/replyReply/view.dart b/lib/pages/video/detail/replyReply/view.dart index 0d86cb5b..f2a72faf 100644 --- a/lib/pages/video/detail/replyReply/view.dart +++ b/lib/pages/video/detail/replyReply/view.dart @@ -1,3 +1,4 @@ +import 'package:easy_debounce/easy_throttle.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:hive/hive.dart'; @@ -54,9 +55,9 @@ class _VideoReplyReplyPanelState extends State { () { if (scrollController.position.pixels >= scrollController.position.maxScrollExtent - 300) { - if (!_videoReplyReplyController.isLoadingMore) { - _videoReplyReplyController.onLoad(); - } + EasyThrottle.throttle('replylist', const Duration(seconds: 2), () { + _videoReplyReplyController.queryReplyList(type: 'onLoad'); + }); } }, ); diff --git a/lib/pages/video/detail/view.dart b/lib/pages/video/detail/view.dart index 79ac16d2..37c023ca 100644 --- a/lib/pages/video/detail/view.dart +++ b/lib/pages/video/detail/view.dart @@ -99,10 +99,13 @@ class _VideoDetailPageState extends State plPlayerController!.triggerFullScreen(status: false); } // 播放完展示控制栏 - PiPStatus currentStatus = await videoDetailController.floating!.pipStatus; - if (currentStatus == PiPStatus.disabled) { - plPlayerController!.onLockControl(false); - } + try { + PiPStatus currentStatus = + await videoDetailController.floating!.pipStatus; + if (currentStatus == PiPStatus.disabled) { + plPlayerController!.onLockControl(false); + } + } catch (_) {} } } From 1d9372b4f14f6570e5a6c90ce031e4cf77773fcf Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sat, 16 Sep 2023 23:14:11 +0800 Subject: [PATCH 03/29] =?UTF-8?q?fix:=20=E4=B8=AA=E4=BA=BA=E4=B8=BB?= =?UTF-8?q?=E9=A1=B5=E3=80=81=E5=85=B3=E6=B3=A8=E3=80=81=E7=B2=89=E4=B8=9D?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2=E6=B8=B2=E6=9F=93=E5=BC=82=E5=B8=B8issues=20?= =?UTF-8?q?#91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/fan/view.dart | 5 +++- lib/pages/follow/view.dart | 5 +++- lib/pages/member/controller.dart | 1 + lib/pages/member/view.dart | 43 ++++++++++++++++----------- lib/pages/member/widgets/profile.dart | 14 +++++---- 5 files changed, 43 insertions(+), 25 deletions(-) diff --git a/lib/pages/fan/view.dart b/lib/pages/fan/view.dart index 6a0af3c6..3eea5093 100644 --- a/lib/pages/fan/view.dart +++ b/lib/pages/fan/view.dart @@ -16,13 +16,16 @@ class FansPage extends StatefulWidget { } class _FansPageState extends State { - final FansController _fansController = Get.put(FansController()); + late String mid; + late FansController _fansController; final ScrollController scrollController = ScrollController(); Future? _futureBuilderFuture; @override void initState() { super.initState(); + mid = Get.parameters['mid']!; + _fansController = Get.put(FansController(), tag: mid); _futureBuilderFuture = _fansController.queryFans('init'); scrollController.addListener( () async { diff --git a/lib/pages/follow/view.dart b/lib/pages/follow/view.dart index 9e290f0f..0a8cc0ef 100644 --- a/lib/pages/follow/view.dart +++ b/lib/pages/follow/view.dart @@ -16,13 +16,16 @@ class FollowPage extends StatefulWidget { } class _FollowPageState extends State { - final FollowController _followController = Get.put(FollowController()); + late String mid; + late FollowController _followController; final ScrollController scrollController = ScrollController(); Future? _futureBuilderFuture; @override void initState() { super.initState(); + mid = Get.parameters['mid']!; + _followController = Get.put(FollowController(), tag: mid); _futureBuilderFuture = _followController.queryFollowings('init'); scrollController.addListener( () async { diff --git a/lib/pages/member/controller.dart b/lib/pages/member/controller.dart index df1ecf43..4a19d9ca 100644 --- a/lib/pages/member/controller.dart +++ b/lib/pages/member/controller.dart @@ -110,6 +110,7 @@ class MemberController extends GetxController { // 关系查询 Future relationSearch() async { if (userInfo == null) return; + if (mid == ownerMid) return; var res = await UserHttp.relationSearch(mid); if (res['status']) { attribute.value = res['data']['relation']['attribute']; diff --git a/lib/pages/member/view.dart b/lib/pages/member/view.dart index c5130206..9cc1672a 100644 --- a/lib/pages/member/view.dart +++ b/lib/pages/member/view.dart @@ -20,7 +20,8 @@ class MemberPage extends StatefulWidget { class _MemberPageState extends State with SingleTickerProviderStateMixin { - final MemberController _memberController = Get.put(MemberController()); + late String heroTag; + late MemberController _memberController; Future? _futureBuilderFuture; final ScrollController _extendNestCtr = ScrollController(); late TabController _tabController; @@ -29,6 +30,8 @@ class _MemberPageState extends State @override void initState() { super.initState(); + heroTag = Get.arguments['heroTag']; + _memberController = Get.put(MemberController(), tag: heroTag); _tabController = TabController(length: 3, vsync: this, initialIndex: 2); _futureBuilderFuture = _memberController.getInfo(); _extendNestCtr.addListener( @@ -105,27 +108,33 @@ class _MemberPageState extends State PopupMenuButton( icon: const Icon(Icons.more_vert), itemBuilder: (BuildContext context) => [ + if (_memberController.ownerMid != + _memberController.mid) ...[ + PopupMenuItem( + onTap: () => _memberController.blockUser(), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + const Icon(Icons.block, size: 19), + const SizedBox(width: 10), + Text(_memberController.attribute.value != 128 + ? '加入黑名单' + : '移除黑名单'), + ], + ), + ) + ], PopupMenuItem( - onTap: () => _memberController.blockUser(), + onTap: () => _memberController.shareUser(), child: Row( mainAxisSize: MainAxisSize.min, children: [ - const Icon(Icons.block, size: 19), + const Icon(Icons.share_outlined, size: 19), const SizedBox(width: 10), - Text(_memberController.attribute.value != 128 - ? '加入黑名单' - : '移除黑名单'), - ], - ), - ), - PopupMenuItem( - onTap: () => _memberController.shareUser(), - child: const Row( - mainAxisSize: MainAxisSize.min, - children: [ - Icon(Icons.share_outlined, size: 19), - SizedBox(width: 10), - Text('分享UP主'), + Text(_memberController.ownerMid != + _memberController.mid + ? '分享UP主' + : '分享我的主页'), ], ), ), diff --git a/lib/pages/member/widgets/profile.dart b/lib/pages/member/widgets/profile.dart index 2574c9ae..853fd8b3 100644 --- a/lib/pages/member/widgets/profile.dart +++ b/lib/pages/member/widgets/profile.dart @@ -123,12 +123,14 @@ Widget profile(ctr, {loadingStatus = false}) { : '-', style: const TextStyle( fontWeight: FontWeight.bold)), - Text('粉丝', - style: TextStyle( - fontSize: Theme.of(context) - .textTheme - .labelMedium! - .fontSize)) + Text( + '粉丝', + style: TextStyle( + fontSize: Theme.of(context) + .textTheme + .labelMedium! + .fontSize), + ) ], ), ), From c91cfedfe2e95c3fcd52ce60050ddae0cca9bc60 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 17 Sep 2023 12:53:37 +0800 Subject: [PATCH 04/29] =?UTF-8?q?mod:=20=E7=9B=B4=E6=92=AD=E5=88=97?= =?UTF-8?q?=E8=A1=A8=E5=88=B7=E6=96=B0=E9=80=BB=E8=BE=91&=E6=A0=B7?= =?UTF-8?q?=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/live/controller.dart | 6 +++--- lib/pages/live/view.dart | 12 ++++++++---- lib/pages/live/widgets/live_item.dart | 4 ++-- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/lib/pages/live/controller.dart b/lib/pages/live/controller.dart index 8cdf53a7..28c34f3e 100644 --- a/lib/pages/live/controller.dart +++ b/lib/pages/live/controller.dart @@ -25,9 +25,9 @@ class LiveController extends GetxController { // 获取推荐 Future queryLiveList(type) async { - if (type == 'init') { - _currentPage = 1; - } + // if (type == 'init') { + // _currentPage = 1; + // } var res = await LiveHttp.liveList( pn: _currentPage, ); diff --git a/lib/pages/live/view.dart b/lib/pages/live/view.dart index 2698c2db..fc29dea7 100644 --- a/lib/pages/live/view.dart +++ b/lib/pages/live/view.dart @@ -21,11 +21,15 @@ class LivePage extends StatefulWidget { State createState() => _LivePageState(); } -class _LivePageState extends State { +class _LivePageState extends State + with AutomaticKeepAliveClientMixin { final LiveController _liveController = Get.put(LiveController()); late Future _futureBuilderFuture; late ScrollController scrollController; + @override + bool get wantKeepAlive => true; + @override void initState() { super.initState(); @@ -37,7 +41,7 @@ class _LivePageState extends State { () { if (scrollController.position.pixels >= scrollController.position.maxScrollExtent - 200) { - EasyThrottle.throttle('my-throttler', const Duration(seconds: 1), () { + EasyThrottle.throttle('liveList', const Duration(seconds: 1), () { _liveController.isLoadingMore = true; _liveController.onLoad(); }); @@ -144,9 +148,9 @@ class _LivePageState extends State { return SliverGrid( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( // 行间距 - mainAxisSpacing: StyleString.cardSpace + 4, + mainAxisSpacing: StyleString.safeSpace, // 列间距 - crossAxisSpacing: StyleString.cardSpace + 4, + crossAxisSpacing: StyleString.safeSpace, // 列数 crossAxisCount: crossAxisCount, mainAxisExtent: diff --git a/lib/pages/live/widgets/live_item.dart b/lib/pages/live/widgets/live_item.dart index 48a4356e..6160d721 100644 --- a/lib/pages/live/widgets/live_item.dart +++ b/lib/pages/live/widgets/live_item.dart @@ -24,7 +24,7 @@ class LiveCardV extends StatelessWidget { Widget build(BuildContext context) { String heroTag = Utils.makeHeroTag(liveItem.roomId); return Card( - elevation: crossAxisCount == 1 ? 0 : 1, + elevation: 0, clipBehavior: Clip.hardEdge, margin: EdgeInsets.zero, child: GestureDetector( @@ -102,7 +102,7 @@ class LiveContent extends StatelessWidget { child: Padding( padding: crossAxisCount == 1 ? const EdgeInsets.fromLTRB(9, 9, 9, 4) - : const EdgeInsets.fromLTRB(9, 8, 9, 8), + : const EdgeInsets.fromLTRB(5, 8, 5, 4), child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.spaceBetween, From 5c68772f7bddfcf5e8166ffb824dbab8befa1b8d Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 17 Sep 2023 14:20:11 +0800 Subject: [PATCH 05/29] =?UTF-8?q?fix:=20toast=E6=98=BE=E7=A4=BA=E3=80=81se?= =?UTF-8?q?ek=E5=90=8E=E5=8E=86=E5=8F=B2=E8=AE=B0=E5=BD=95=E4=B8=8D?= =?UTF-8?q?=E8=AF=B7=E6=B1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/http/interceptor.dart | 5 ++++- lib/plugin/pl_player/controller.dart | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/http/interceptor.dart b/lib/http/interceptor.dart index 4b9e8770..7b398caa 100644 --- a/lib/http/interceptor.dart +++ b/lib/http/interceptor.dart @@ -46,7 +46,10 @@ class ApiInterceptor extends Interceptor { void onError(DioException err, ErrorInterceptorHandler handler) async { // 处理网络请求错误 // handler.next(err); - SmartDialog.showToast(await dioError(err)); + SmartDialog.showToast( + await dioError(err), + displayType: SmartToastType.onlyRefresh, + ); super.onError(err, handler); } diff --git a/lib/plugin/pl_player/controller.dart b/lib/plugin/pl_player/controller.dart index 4478e8d0..f47d3963 100644 --- a/lib/plugin/pl_player/controller.dart +++ b/lib/plugin/pl_player/controller.dart @@ -510,6 +510,7 @@ class PlPlayerController { position = Duration.zero; } _position.value = position; + _heartDuration = position.inSeconds; if (duration.value.inSeconds != 0) { if (type != 'slider') { /// 拖动进度条调节时,不等待第一帧,防止抖动 @@ -878,7 +879,7 @@ class PlPlayerController { } // 记录播放记录 - Future makeHeartBeat(progress, {type = 'playing'}) async { + Future makeHeartBeat(int progress, {type = 'playing'}) async { if (!_enableHeart) { return false; } From 41df90561bc9d29f17c0d03dce4b19278f73c22c Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 17 Sep 2023 14:32:07 +0800 Subject: [PATCH 06/29] =?UTF-8?q?fix:=20=E8=AE=B0=E5=BD=95=E5=BC=B9?= =?UTF-8?q?=E5=B9=95=E5=B1=8F=E8=94=BD=E8=AE=BE=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/danmaku/view.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/pages/danmaku/view.dart b/lib/pages/danmaku/view.dart index 750851d2..640a4744 100644 --- a/lib/pages/danmaku/view.dart +++ b/lib/pages/danmaku/view.dart @@ -152,6 +152,9 @@ class _PlDanmakuState extends State { fontSize: 15 * fontSizeVal, area: showArea, opacity: opacityVal, + hideTop: blockTypes.contains(5), + hideScroll: blockTypes.contains(2), + hideBottom: blockTypes.contains(4), duration: danmakuSpeedVal * widget.playerController.playbackSpeed, ), statusChanged: (isPlaying) {}, From 7fa7152245371cfb2956569d81db77ced11ce5dc Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 17 Sep 2023 20:07:26 +0800 Subject: [PATCH 07/29] =?UTF-8?q?fix:=20=E7=94=A8=E6=88=B7=E9=A1=B5?= =?UTF-8?q?=E5=BC=82=E5=B8=B8&=E5=A4=B4=E5=83=8F=E6=B8=B2=E6=9F=93?= =?UTF-8?q?=E3=80=81=E6=90=9C=E7=B4=A2=E5=BB=BA=E8=AE=AE=E8=AF=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/member/controller.dart | 7 +-- lib/pages/member/view.dart | 76 +++++++++++++++------------ lib/pages/member/widgets/profile.dart | 2 +- lib/pages/search/controller.dart | 2 +- 4 files changed, 48 insertions(+), 39 deletions(-) diff --git a/lib/pages/member/controller.dart b/lib/pages/member/controller.dart index 4a19d9ca..0d40ec65 100644 --- a/lib/pages/member/controller.dart +++ b/lib/pages/member/controller.dart @@ -14,7 +14,7 @@ class MemberController extends GetxController { late int mid; Rx memberInfo = MemberInfoModel().obs; Map? userStat; - String? face; + RxString face = ''.obs; String? heroTag; Box userInfoCache = GStrorage.userInfo; late int ownerMid; @@ -30,7 +30,7 @@ class MemberController extends GetxController { mid = int.parse(Get.parameters['mid']!); userInfo = userInfoCache.get('userInfoCache'); ownerMid = userInfo != null ? userInfo.mid : -1; - face = Get.arguments['face'] ?? ''; + face.value = Get.arguments['face'] ?? ''; heroTag = Get.arguments['heroTag'] ?? ''; relationSearch(); } @@ -41,6 +41,7 @@ class MemberController extends GetxController { var res = await MemberHttp.memberInfo(mid: mid); if (res['status']) { memberInfo.value = res['data']; + face.value = res['data'].face; } return res; } @@ -118,7 +119,7 @@ class MemberController extends GetxController { ? '关注' : attribute.value == 2 ? '已关注' - : attribute.value == 2 + : attribute.value == 6 ? '已互粉' : '已拉黑'; } diff --git a/lib/pages/member/view.dart b/lib/pages/member/view.dart index 9cc1672a..a29bd545 100644 --- a/lib/pages/member/view.dart +++ b/lib/pages/member/view.dart @@ -8,6 +8,7 @@ import 'package:pilipala/common/widgets/network_img_layer.dart'; import 'package:pilipala/pages/member/archive/view.dart'; import 'package:pilipala/pages/member/dynamic/index.dart'; import 'package:pilipala/pages/member/index.dart'; +import 'package:pilipala/utils/utils.dart'; import 'widgets/profile.dart'; @@ -30,7 +31,8 @@ class _MemberPageState extends State @override void initState() { super.initState(); - heroTag = Get.arguments['heroTag']; + heroTag = + Get.arguments['heroTag'] ?? Utils.makeHeroTag(Get.parameters['mid']); _memberController = Get.put(MemberController(), tag: heroTag); _tabController = TabController(length: 3, vsync: this, initialIndex: 2); _futureBuilderFuture = _memberController.getInfo(); @@ -80,11 +82,13 @@ class _MemberPageState extends State children: [ Row( children: [ - NetworkImgLayer( - width: 35, - height: 35, - type: 'avatar', - src: _memberController.face ?? '', + Obx( + () => NetworkImgLayer( + width: 35, + height: 35, + type: 'avatar', + src: _memberController.face.value, + ), ), const SizedBox(width: 10), Obx( @@ -145,34 +149,38 @@ class _MemberPageState extends State flexibleSpace: FlexibleSpaceBar( background: Stack( children: [ - if (_memberController.face != null) - Positioned.fill( - bottom: 10, - child: Container( - decoration: BoxDecoration( - image: DecorationImage( - fit: BoxFit.fitWidth, - image: NetworkImage(_memberController.face!), - alignment: Alignment.topCenter, - isAntiAlias: true, - ), - ), - foregroundDecoration: BoxDecoration( - gradient: LinearGradient( - colors: [ - Theme.of(context) - .colorScheme - .background - .withOpacity(0.44), - Theme.of(context).colorScheme.background, - ], - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - stops: const [0.0, 0.46], - ), - ), - ), - ), + Obx( + () => _memberController.face.value != '' + ? Positioned.fill( + bottom: 10, + child: Container( + decoration: BoxDecoration( + image: DecorationImage( + fit: BoxFit.fitWidth, + image: NetworkImage( + _memberController.face.value), + alignment: Alignment.topCenter, + isAntiAlias: true, + ), + ), + foregroundDecoration: BoxDecoration( + gradient: LinearGradient( + colors: [ + Theme.of(context) + .colorScheme + .background + .withOpacity(0.44), + Theme.of(context).colorScheme.background, + ], + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + stops: const [0.0, 0.46], + ), + ), + ), + ) + : const SizedBox(), + ), Positioned( left: 0, right: 0, diff --git a/lib/pages/member/widgets/profile.dart b/lib/pages/member/widgets/profile.dart index 853fd8b3..22e88106 100644 --- a/lib/pages/member/widgets/profile.dart +++ b/lib/pages/member/widgets/profile.dart @@ -22,7 +22,7 @@ Widget profile(ctr, {loadingStatus = false}) { width: 90, height: 90, type: 'avatar', - src: !loadingStatus ? memberInfo.face : ctr.face, + src: !loadingStatus ? memberInfo.face : ctr.face.value, ), if (!loadingStatus && memberInfo.liveRoom != null && diff --git a/lib/pages/search/controller.dart b/lib/pages/search/controller.dart index 36d6a189..b95b048b 100644 --- a/lib/pages/search/controller.dart +++ b/lib/pages/search/controller.dart @@ -105,7 +105,7 @@ class SSearchController extends GetxController { Future querySearchSuggest(String value) async { var result = await SearchHttp.searchSuggest(term: value); if (result['status']) { - if (result['data'].isNotEmpty) { + if (result['data'] is SearchSuggestModel) { searchSuggestList.value = result['data'].tag; } } From dd9763649418ea3c35538057888a78b57f9b2b12 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 17 Sep 2023 22:30:22 +0800 Subject: [PATCH 08/29] =?UTF-8?q?fix:=20=E5=BC=B9=E5=B9=95=E6=95=B0?= =?UTF-8?q?=E9=87=8F=E5=B0=91=E4=BA=8E=E5=AE=9E=E9=99=85=E6=95=B0=E9=87=8F?= =?UTF-8?q?&=E4=BC=98=E5=8C=96=E5=BC=B9=E5=B9=95=E8=AF=B7=E6=B1=82=20issue?= =?UTF-8?q?s=20#78?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/http/danmaku.dart | 18 ++++------- lib/pages/danmaku/controller.dart | 28 ++++++++++------ lib/pages/danmaku/view.dart | 53 +++++++++++++++++++------------ 3 files changed, 58 insertions(+), 41 deletions(-) diff --git a/lib/http/danmaku.dart b/lib/http/danmaku.dart index 020c89ea..87f08d8b 100644 --- a/lib/http/danmaku.dart +++ b/lib/http/danmaku.dart @@ -17,17 +17,11 @@ class DanmakaHttp { 'oid': cid, 'segment_index': segmentIndex, }; - - // 计算函数 - Future computeTask(Map params) async { - var response = await Request().get( - Api.webDanmaku, - data: params, - extra: {'resType': ResponseType.bytes}, - ); - return DmSegMobileReply.fromBuffer(response.data); - } - - return await compute(computeTask, params); + var response = await Request().get( + Api.webDanmaku, + data: params, + extra: {'resType': ResponseType.bytes}, + ); + return DmSegMobileReply.fromBuffer(response.data); } } diff --git a/lib/pages/danmaku/controller.dart b/lib/pages/danmaku/controller.dart index ebe7712d..576d4f3c 100644 --- a/lib/pages/danmaku/controller.dart +++ b/lib/pages/danmaku/controller.dart @@ -10,22 +10,32 @@ class PlDanmakuController { // 按 6min 分段 int segCount = 0; List dmSegList = []; - int currentSegIndex = 0; + int currentSegIndex = 1; int currentDmIndex = 0; void calcSegment() { + dmSegList.clear(); + // 视频分段数 segCount = (videoDuration.inSeconds / (60 * 6)).ceil(); + dmSegList = List.generate( + segCount < 1 ? 1 : segCount, (index) => DmSegMobileReply()); + // 当前分段 + try { + currentSegIndex = + (playerController.position.value.inSeconds / (60 * 6)).ceil(); + currentSegIndex = currentSegIndex < 1 ? 1 : currentSegIndex; + } catch (_) {} } Future> queryDanmaku() async { - dmSegList.clear(); - for (int segIndex = 1; segIndex <= segCount; segIndex++) { - DmSegMobileReply result = - await DanmakaHttp.queryDanmaku(cid: cid, segmentIndex: segIndex); - if (result.elems.isNotEmpty) { - result.elems.sort((a, b) => (a.progress).compareTo(b.progress)); - dmSegList.add(result); - } + // dmSegList.clear(); + DmSegMobileReply result = + await DanmakaHttp.queryDanmaku(cid: cid, segmentIndex: currentSegIndex); + if (result.elems.isNotEmpty) { + result.elems.sort((a, b) => (a.progress).compareTo(b.progress)); + // dmSegList.add(result); + currentSegIndex = currentSegIndex < 1 ? 1 : currentSegIndex; + dmSegList[currentSegIndex - 1] = result; } if (dmSegList.isNotEmpty) { findClosestPositionIndex(playerController.position.value.inMilliseconds); diff --git a/lib/pages/danmaku/view.dart b/lib/pages/danmaku/view.dart index 640a4744..5a5d8a11 100644 --- a/lib/pages/danmaku/view.dart +++ b/lib/pages/danmaku/view.dart @@ -1,3 +1,4 @@ +import 'package:easy_debounce/easy_throttle.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:hive/hive.dart'; @@ -88,7 +89,15 @@ class _PlDanmakuState extends State { PlDanmakuController ctr = _plDanmakuController; int currentPosition = position.inMilliseconds; blockTypes = playerController.blockTypes; - + // 根据position判断是否有已缓存弹幕。没有则请求对应段 + int segIndex = (currentPosition / (6 * 60 * 1000)).ceil(); + segIndex = segIndex < 1 ? 1 : segIndex; + if (ctr.dmSegList[segIndex - 1].elems.isEmpty) { + ctr.currentSegIndex = segIndex; + EasyThrottle.throttle('follow', const Duration(seconds: 1), () { + ctr.queryDanmaku(); + }); + } if (!playerController.isOpenDanmu.value) { return; } @@ -140,26 +149,30 @@ class _PlDanmakuState extends State { @override Widget build(BuildContext context) { - return Obx( - () => AnimatedOpacity( - opacity: playerController.isOpenDanmu.value ? 1 : 0, - duration: const Duration(milliseconds: 100), - child: DanmakuView( - createdController: (DanmakuController e) async { - widget.playerController.danmakuController = _controller = e; - }, - option: DanmakuOption( - fontSize: 15 * fontSizeVal, - area: showArea, - opacity: opacityVal, - hideTop: blockTypes.contains(5), - hideScroll: blockTypes.contains(2), - hideBottom: blockTypes.contains(4), - duration: danmakuSpeedVal * widget.playerController.playbackSpeed, + return LayoutBuilder(builder: (context, box) { + double initDuration = box.maxWidth / 12; + return Obx( + () => AnimatedOpacity( + opacity: playerController.isOpenDanmu.value ? 1 : 0, + duration: const Duration(milliseconds: 100), + child: DanmakuView( + createdController: (DanmakuController e) async { + widget.playerController.danmakuController = _controller = e; + }, + option: DanmakuOption( + fontSize: 15 * fontSizeVal, + area: showArea, + opacity: opacityVal, + hideTop: blockTypes.contains(5), + hideScroll: blockTypes.contains(2), + hideBottom: blockTypes.contains(4), + duration: initDuration / + (danmakuSpeedVal * widget.playerController.playbackSpeed), + ), + statusChanged: (isPlaying) {}, ), - statusChanged: (isPlaying) {}, ), - ), - ); + ); + }); } } From 7db9d290f5efcae7d3911120f82516b01d1bee55 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 17 Sep 2023 22:41:04 +0800 Subject: [PATCH 09/29] =?UTF-8?q?fix:=20=E6=9C=AA=E5=BC=80=E5=90=AF?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E6=92=AD=E6=94=BE=E6=97=B6=E5=8E=86=E5=8F=B2?= =?UTF-8?q?=E8=AE=B0=E5=BD=9500:00?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/video/detail/view.dart | 10 ++++++---- lib/plugin/pl_player/controller.dart | 4 +++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/pages/video/detail/view.dart b/lib/pages/video/detail/view.dart index 37c023ca..048876d6 100644 --- a/lib/pages/video/detail/view.dart +++ b/lib/pages/video/detail/view.dart @@ -143,10 +143,12 @@ class _VideoDetailPageState extends State if (setting.get(SettingBoxKey.enableAutoBrightness, defaultValue: false)) { videoDetailController.brightness = plPlayerController!.brightness.value; } - videoDetailController.defaultST = plPlayerController!.position.value; - videoIntroController.isPaused = true; - plPlayerController!.removeStatusLister(playerListener); - plPlayerController!.pause(); + if (plPlayerController != null) { + videoDetailController.defaultST = plPlayerController!.position.value; + videoIntroController.isPaused = true; + plPlayerController!.removeStatusLister(playerListener); + plPlayerController!.pause(); + } super.didPushNext(); } diff --git a/lib/plugin/pl_player/controller.dart b/lib/plugin/pl_player/controller.dart index f47d3963..9121c963 100644 --- a/lib/plugin/pl_player/controller.dart +++ b/lib/plugin/pl_player/controller.dart @@ -449,7 +449,9 @@ class PlPlayerController { for (var element in _statusListeners) { element(event ? PlayerStatus.playing : PlayerStatus.paused); } - makeHeartBeat(_position.value.inSeconds, type: 'status'); + if (videoPlayerController!.state.position.inSeconds != 0) { + makeHeartBeat(_position.value.inSeconds, type: 'status'); + } }), videoPlayerController!.stream.completed.listen((event) { if (event) { From 83b27e7231932f739f0d2b5d2d0cb95291de0cfc Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 17 Sep 2023 22:57:54 +0800 Subject: [PATCH 10/29] =?UTF-8?q?fix:=20=E9=80=80=E5=87=BApip=E8=AF=84?= =?UTF-8?q?=E8=AE=BA=E7=A9=BA=E7=99=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/video/detail/reply/view.dart | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/pages/video/detail/reply/view.dart b/lib/pages/video/detail/reply/view.dart index d5469d92..3f42c558 100644 --- a/lib/pages/video/detail/reply/view.dart +++ b/lib/pages/video/detail/reply/view.dart @@ -39,6 +39,7 @@ class _VideoReplyPanelState extends State Future? _futureBuilderFuture; bool _isFabVisible = true; String replyLevel = '1'; + late String heroTag; // 添加页面缓存 @override @@ -46,16 +47,17 @@ class _VideoReplyPanelState extends State @override void initState() { - int oid = widget.bvid != null ? IdUtils.bv2av(widget.bvid!) : 0; super.initState(); + int oid = widget.bvid != null ? IdUtils.bv2av(widget.bvid!) : 0; + heroTag = Get.arguments['heroTag']; replyLevel = widget.replyLevel ?? '1'; if (replyLevel == '2') { _videoReplyController = Get.put( VideoReplyController(oid, widget.rpid.toString(), replyLevel), tag: widget.rpid.toString()); } else { - _videoReplyController = Get.put(VideoReplyController(oid, '', replyLevel), - tag: Get.arguments['heroTag']); + _videoReplyController = + Get.put(VideoReplyController(oid, '', replyLevel), tag: heroTag); } fabAnimationCtr = AnimationController( @@ -106,7 +108,7 @@ class _VideoReplyPanelState extends State // 展示二级回复 void replyReply(replyItem) { VideoDetailController videoDetailCtr = - Get.find(tag: Get.arguments['heroTag']); + Get.find(tag: heroTag); if (replyItem != null) { videoDetailCtr.oid = replyItem.oid; videoDetailCtr.fRpid = replyItem.rpid!; From 427bd2eb79ca4298b900f46a34a1f498ff0f4793 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 17 Sep 2023 23:37:17 +0800 Subject: [PATCH 11/29] =?UTF-8?q?fix:=20=E8=87=AA=E5=8A=A8=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E8=AF=B7=E6=B1=82=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/http/init.dart | 27 +++++++++++++++------------ lib/pages/about/index.dart | 2 +- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/lib/http/init.dart b/lib/http/init.dart index f927e2e5..1e33365d 100644 --- a/lib/http/init.dart +++ b/lib/http/init.dart @@ -89,11 +89,7 @@ class Request { //响应流上前后两次接受到数据的间隔,单位为毫秒。 receiveTimeout: const Duration(milliseconds: 12000), //Http请求头. - headers: { - 'keep-alive': 'true', - 'user-agent': headerUa(), - }, - persistentConnection: true, + headers: {}, ); dio = Dio(options) @@ -128,12 +124,14 @@ class Request { */ get(url, {data, options, cancelToken, extra}) async { Response response; - Options options; + Options options = Options(); ResponseType resType = ResponseType.json; if (extra != null) { resType = extra!['resType'] ?? ResponseType.json; + if (extra['ua'] != null) { + options.headers = {'user-agent': headerUa(type: extra['ua'])}; + } } - options = Options(); options.responseType = resType; try { response = await dio.get( @@ -201,14 +199,19 @@ class Request { token.cancel("cancelled"); } - String headerUa() { + String headerUa({type = 'mob'}) { String headerUa = ''; - if (Platform.isIOS) { - headerUa = - 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1 Mobile/15E148 Safari/604.1'; + if (type == 'mob') { + if (Platform.isIOS) { + headerUa = + 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1 Mobile/15E148 Safari/604.1'; + } else { + headerUa = + 'Mozilla/5.0 (Linux; Android 10; SM-G975F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.101 Mobile Safari/537.36'; + } } else { headerUa = - 'Mozilla/5.0 (Linux; Android 10; SM-G975F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.101 Mobile Safari/537.36'; + 'Mozilla/5.0 (MaciMozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36'; } return headerUa; } diff --git a/lib/pages/about/index.dart b/lib/pages/about/index.dart index 76173fae..31808e1c 100644 --- a/lib/pages/about/index.dart +++ b/lib/pages/about/index.dart @@ -184,7 +184,7 @@ class AboutController extends GetxController { // 获取远程版本 Future getRemoteApp() async { - var result = await Request().get(Api.latestApp); + var result = await Request().get(Api.latestApp, extra: {'ua': 'pc'}); data = LatestDataModel.fromJson(result.data); remoteAppInfo = data; remoteVersion.value = data.tagName!; From 9de9b885bcdbd1f7227830a3a72383658e5e8575 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 17 Sep 2023 23:49:34 +0800 Subject: [PATCH 12/29] =?UTF-8?q?mod:=20=E9=9A=90=E8=97=8F=E6=90=9C?= =?UTF-8?q?=E7=B4=A2=E4=B8=93=E6=A0=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/http/search.dart | 6 +++--- lib/models/common/search_type.dart | 2 +- lib/pages/searchPanel/view.dart | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/http/search.dart b/lib/http/search.dart index 8583b271..e35b2da3 100644 --- a/lib/http/search.dart +++ b/lib/http/search.dart @@ -89,9 +89,9 @@ class SearchHttp { case SearchType.media_bangumi: data = SearchMBangumiModel.fromJson(res.data['data']); break; - case SearchType.article: - data = SearchArticleModel.fromJson(res.data['data']); - break; + // case SearchType.article: + // data = SearchArticleModel.fromJson(res.data['data']); + // break; } return { 'status': true, diff --git a/lib/models/common/search_type.dart b/lib/models/common/search_type.dart index d7d13aec..c535e9f4 100644 --- a/lib/models/common/search_type.dart +++ b/lib/models/common/search_type.dart @@ -17,7 +17,7 @@ enum SearchType { // 用户:bili_user bili_user, // 专栏:article - article, + // article, // 相簿:photo // photo } diff --git a/lib/pages/searchPanel/view.dart b/lib/pages/searchPanel/view.dart index 9fd37b7e..45c5f22f 100644 --- a/lib/pages/searchPanel/view.dart +++ b/lib/pages/searchPanel/view.dart @@ -91,8 +91,8 @@ class _SearchPanelState extends State return searchUserPanel(context, ctr, list); case SearchType.live_room: return searchLivePanel(context, ctr, list); - case SearchType.article: - return searchArticlePanel(context, ctr, list); + // case SearchType.article: + // return searchArticlePanel(context, ctr, list); default: return const SizedBox(); } From 93383a5c6518817985ed81179e3eb7324c49fb81 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 17 Sep 2023 23:51:14 +0800 Subject: [PATCH 13/29] =?UTF-8?q?v1.0.8=20=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- change_log/1.0.8.0917.md | 24 ++++++++++++++++++++++++ pubspec.yaml | 2 +- 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 change_log/1.0.8.0917.md diff --git a/change_log/1.0.8.0917.md b/change_log/1.0.8.0917.md new file mode 100644 index 00000000..2dc1758e --- /dev/null +++ b/change_log/1.0.8.0917.md @@ -0,0 +1,24 @@ +## 1.0.8 + +直播弹幕、循环播放等功能开发中 + +### 新功能 ++ 用户拉黑功能 ++ gif图片保存 ++ 删除已看历史记录 + +### 修复 ++ 弹幕数量较少 ++ 弹幕屏蔽设置自动记忆 ++ 动态页面渲染 ++ 用户主页数据错乱 ++ 大家都在搜空白 ++ 默认自动全屏,顶部操作栏丢失 + + +### 优化 ++ 全屏状态栏区域显示优化 ++ 图片保存至PiliPala文件夹 + +更多更新日志可在Github上查看 +问题反馈、功能建议请查看「关于」页面。 diff --git a/pubspec.yaml b/pubspec.yaml index ce9547e4..22d91b26 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -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 # 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. -version: 1.0.7 +version: 1.0.8 environment: sdk: ">=2.19.6 <3.0.0" From f543be562a498f4286f9dfdcd16dd5e71519278c Mon Sep 17 00:00:00 2001 From: guozhigq Date: Mon, 18 Sep 2023 07:18:07 +0800 Subject: [PATCH 14/29] =?UTF-8?q?fix:=20=E5=85=B3=E6=B3=A8/=E7=B2=89?= =?UTF-8?q?=E4=B8=9D/=E5=85=A8=E9=83=A8=E8=B7=B3=E8=BD=AC=E5=BC=82?= =?UTF-8?q?=E5=B8=B8=E3=80=81=E4=B8=AA=E4=BA=BA=E4=B8=BB=E9=A1=B5=E8=AF=B7?= =?UTF-8?q?=E6=B1=82=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/http/member.dart | 2 ++ lib/pages/dynamics/widgets/up_panel.dart | 5 ++++- lib/pages/mine/view.dart | 6 ++++-- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/lib/http/member.dart b/lib/http/member.dart index 995ccc23..5cf3f1ee 100644 --- a/lib/http/member.dart +++ b/lib/http/member.dart @@ -18,6 +18,7 @@ class MemberHttp { var res = await Request().get( Api.memberInfo, data: params, + extra: {'ua': 'pc'}, ); if (res.data['code'] == 0) { return { @@ -83,6 +84,7 @@ class MemberHttp { var res = await Request().get( Api.memberArchive, data: params, + extra: {'ua': 'pc'}, ); if (res.data['code'] == 0) { return { diff --git a/lib/pages/dynamics/widgets/up_panel.dart b/lib/pages/dynamics/widgets/up_panel.dart index a12956a5..3db6c357 100644 --- a/lib/pages/dynamics/widgets/up_panel.dart +++ b/lib/pages/dynamics/widgets/up_panel.dart @@ -91,7 +91,10 @@ class _UpPanelState extends State { ), Material( child: InkWell( - onTap: () => {feedBack(), Get.toNamed('/follow')}, + onTap: () => { + feedBack(), + Get.toNamed('/follow?mid=${userInfo.mid}') + }, child: Container( height: 100, padding: const EdgeInsets.only(left: 10, right: 10), diff --git a/lib/pages/mine/view.dart b/lib/pages/mine/view.dart index 4093b92c..96e36cf9 100644 --- a/lib/pages/mine/view.dart +++ b/lib/pages/mine/view.dart @@ -264,7 +264,8 @@ class _MinePageState extends State { ), ), InkWell( - onTap: () => Get.toNamed('/follow'), + onTap: () => Get.toNamed( + '/follow?mid=${_mineController.userInfo.value.mid}'), borderRadius: StyleString.mdRadius, child: Column( mainAxisAlignment: MainAxisAlignment.center, @@ -294,7 +295,8 @@ class _MinePageState extends State { ), ), InkWell( - onTap: () => Get.toNamed('/fan'), + onTap: () => Get.toNamed( + '/fan?mid=${_mineController.userInfo.value.mid}'), borderRadius: StyleString.mdRadius, child: Column( mainAxisAlignment: MainAxisAlignment.center, From 8f9743166597c0eb01371196bfa99aadbb3c61cc Mon Sep 17 00:00:00 2001 From: guozhigq Date: Mon, 18 Sep 2023 07:39:56 +0800 Subject: [PATCH 15/29] =?UTF-8?q?fix:=20=E8=A7=86=E9=A2=91=E5=85=A8?= =?UTF-8?q?=E5=B1=8F=E6=97=B6=E7=9A=84=E5=AE=89=E5=85=A8=E5=8C=BA=E5=9F=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/plugin/pl_player/controller.dart | 10 +++--- lib/plugin/pl_player/view.dart | 46 +++++++++++++++------------- 2 files changed, 31 insertions(+), 25 deletions(-) diff --git a/lib/plugin/pl_player/controller.dart b/lib/plugin/pl_player/controller.dart index 9121c963..01476ade 100644 --- a/lib/plugin/pl_player/controller.dart +++ b/lib/plugin/pl_player/controller.dart @@ -817,6 +817,10 @@ class PlPlayerController { } toggleFullScreen(true); + bool isValid = + direction.value == 'vertical' || mode == FullScreenMode.vertical + ? true + : false; var result = await showDialog( context: Get.context!, useSafeArea: false, @@ -824,12 +828,10 @@ class PlPlayerController { backgroundColor: Colors.black, child: SafeArea( // 忽略手机安全区域 + top: isValid, left: false, right: false, - bottom: - direction.value == 'vertical' || mode == FullScreenMode.vertical - ? true - : false, + bottom: isValid, child: PLVideoPlayer( controller: this, headerControl: headerControl, diff --git a/lib/plugin/pl_player/view.dart b/lib/plugin/pl_player/view.dart index b3905b24..2a8311a5 100644 --- a/lib/plugin/pl_player/view.dart +++ b/lib/plugin/pl_player/view.dart @@ -547,34 +547,38 @@ class _PLVideoPlayerState extends State ), // 头部、底部控制条 - Obx( - () => Column( - children: [ - if (widget.headerControl != null || _.headerControl != null) + SafeArea( + top: false, + bottom: false, + child: Obx( + () => Column( + children: [ + if (widget.headerControl != null || _.headerControl != null) + ClipRect( + clipBehavior: Clip.hardEdge, + child: AppBarAni( + controller: animationController, + visible: !_.controlsLock.value && _.showControls.value, + position: 'top', + child: widget.headerControl ?? _.headerControl!, + ), + ), + const Spacer(), ClipRect( clipBehavior: Clip.hardEdge, child: AppBarAni( controller: animationController, visible: !_.controlsLock.value && _.showControls.value, - position: 'top', - child: widget.headerControl ?? _.headerControl!, + position: 'bottom', + child: widget.bottomControl ?? + BottomControl( + controller: widget.controller, + triggerFullScreen: + widget.controller.triggerFullScreen), ), ), - const Spacer(), - ClipRect( - clipBehavior: Clip.hardEdge, - child: AppBarAni( - controller: animationController, - visible: !_.controlsLock.value && _.showControls.value, - position: 'bottom', - child: widget.bottomControl ?? - BottomControl( - controller: widget.controller, - triggerFullScreen: - widget.controller.triggerFullScreen), - ), - ), - ], + ], + ), ), ), From 4c49f466dbf8aa67bb353a4eea5b56d6f34833fe Mon Sep 17 00:00:00 2001 From: guozhigq Date: Mon, 18 Sep 2023 07:46:35 +0800 Subject: [PATCH 16/29] update .lock --- ios/Podfile.lock | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index b00a1fff..3e0ed4ca 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1,6 +1,8 @@ PODS: - appscheme (1.0.4): - Flutter + - auto_orientation (0.0.1): + - Flutter - connectivity_plus (0.0.1): - Flutter - ReachabilitySwift @@ -12,8 +14,6 @@ PODS: - FMDB (2.7.5): - FMDB/standard (= 2.7.5) - FMDB/standard (2.7.5) - - image_gallery_saver (2.0.2): - - Flutter - media_kit_libs_ios_video (1.0.4): - Flutter - media_kit_native_event_loop (1.0.0): @@ -28,6 +28,8 @@ PODS: - permission_handler_apple (9.1.1): - Flutter - ReachabilitySwift (5.0.0) + - saver_gallery (0.0.1): + - Flutter - screen_brightness_ios (0.1.0): - Flutter - share_plus (0.0.1): @@ -52,17 +54,18 @@ PODS: DEPENDENCIES: - appscheme (from `.symlinks/plugins/appscheme/ios`) + - auto_orientation (from `.symlinks/plugins/auto_orientation/ios`) - connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`) - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`) - Flutter (from `Flutter`) - flutter_volume_controller (from `.symlinks/plugins/flutter_volume_controller/ios`) - - image_gallery_saver (from `.symlinks/plugins/image_gallery_saver/ios`) - media_kit_libs_ios_video (from `.symlinks/plugins/media_kit_libs_ios_video/ios`) - media_kit_native_event_loop (from `.symlinks/plugins/media_kit_native_event_loop/ios`) - media_kit_video (from `.symlinks/plugins/media_kit_video/ios`) - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) - permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`) + - saver_gallery (from `.symlinks/plugins/saver_gallery/ios`) - screen_brightness_ios (from `.symlinks/plugins/screen_brightness_ios/ios`) - share_plus (from `.symlinks/plugins/share_plus/ios`) - sqflite (from `.symlinks/plugins/sqflite/ios`) @@ -82,6 +85,8 @@ SPEC REPOS: EXTERNAL SOURCES: appscheme: :path: ".symlinks/plugins/appscheme/ios" + auto_orientation: + :path: ".symlinks/plugins/auto_orientation/ios" connectivity_plus: :path: ".symlinks/plugins/connectivity_plus/ios" device_info_plus: @@ -90,8 +95,6 @@ EXTERNAL SOURCES: :path: Flutter flutter_volume_controller: :path: ".symlinks/plugins/flutter_volume_controller/ios" - image_gallery_saver: - :path: ".symlinks/plugins/image_gallery_saver/ios" media_kit_libs_ios_video: :path: ".symlinks/plugins/media_kit_libs_ios_video/ios" media_kit_native_event_loop: @@ -104,6 +107,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/path_provider_foundation/darwin" permission_handler_apple: :path: ".symlinks/plugins/permission_handler_apple/ios" + saver_gallery: + :path: ".symlinks/plugins/saver_gallery/ios" screen_brightness_ios: :path: ".symlinks/plugins/screen_brightness_ios/ios" share_plus: @@ -127,12 +132,12 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: appscheme: b1c3f8862331cb20430cf9e0e4af85dbc1572ad8 + auto_orientation: 102ed811a5938d52c86520ddd7ecd3a126b5d39d connectivity_plus: 07c49e96d7fc92bc9920617b83238c4d178b446a device_info_plus: 7545d84d8d1b896cb16a4ff98c19f07ec4b298ea Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 flutter_volume_controller: e4d5832f08008180f76e30faf671ffd5a425e529 FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a - image_gallery_saver: cb43cc43141711190510e92c460eb1655cd343cb media_kit_libs_ios_video: a5fe24bc7875ccd6378a0978c13185e1344651c1 media_kit_native_event_loop: e6b2ab20cf0746eb1c33be961fcf79667304fa2a media_kit_video: 5da63f157170e5bf303bf85453b7ef6971218a2e @@ -140,6 +145,7 @@ SPEC CHECKSUMS: path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943 permission_handler_apple: e76247795d700c14ea09e3a2d8855d41ee80a2e6 ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825 + saver_gallery: 2b4e584106fde2407ab51560f3851564963e6b78 screen_brightness_ios: 715ca807df953bf676d339f11464e438143ee625 share_plus: 599aa54e4ea31d4b4c0e9c911bcc26c55e791028 sqflite: 31f7eba61e3074736dff8807a9b41581e4f7f15a From 566f75f760fb47e8c36b6022b89d4aaf5253a396 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Mon, 18 Sep 2023 07:55:31 +0800 Subject: [PATCH 17/29] =?UTF-8?q?mod:=20=E4=BC=98=E5=8C=96=E6=9C=AA?= =?UTF-8?q?=E7=99=BB=E5=BD=95=E6=97=B6=E7=94=A8=E6=88=B7=E8=B7=B3=E8=BD=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/mine/controller.dart | 17 +++++++++++++++++ lib/pages/mine/view.dart | 6 ++---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/lib/pages/mine/controller.dart b/lib/pages/mine/controller.dart index 66813091..772ba06a 100644 --- a/lib/pages/mine/controller.dart +++ b/lib/pages/mine/controller.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:hive/hive.dart'; import 'package:pilipala/http/user.dart'; @@ -111,4 +112,20 @@ class MineController extends GetxController { } Get.forceAppUpdate(); } + + pushFollow() { + if (!userLogin.value) { + SmartDialog.showToast('账号未登录'); + return; + } + Get.toNamed('/follow?mid=${userInfo.value.mid}'); + } + + pushFans() { + if (!userLogin.value) { + SmartDialog.showToast('账号未登录'); + return; + } + Get.toNamed('/fan?mid=${userInfo.value.mid}'); + } } diff --git a/lib/pages/mine/view.dart b/lib/pages/mine/view.dart index 96e36cf9..371b96ce 100644 --- a/lib/pages/mine/view.dart +++ b/lib/pages/mine/view.dart @@ -264,8 +264,7 @@ class _MinePageState extends State { ), ), InkWell( - onTap: () => Get.toNamed( - '/follow?mid=${_mineController.userInfo.value.mid}'), + onTap: () => _mineController.pushFollow(), borderRadius: StyleString.mdRadius, child: Column( mainAxisAlignment: MainAxisAlignment.center, @@ -295,8 +294,7 @@ class _MinePageState extends State { ), ), InkWell( - onTap: () => Get.toNamed( - '/fan?mid=${_mineController.userInfo.value.mid}'), + onTap: () => _mineController.pushFollow(), borderRadius: StyleString.mdRadius, child: Column( mainAxisAlignment: MainAxisAlignment.center, From 7181db66bd4d991693af9797c145f8c2911ca2d3 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Mon, 18 Sep 2023 23:29:17 +0800 Subject: [PATCH 18/29] =?UTF-8?q?fix:=20=E6=88=91=E7=9A=84=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2=E8=B7=B3=E8=BD=AC=E7=B2=89=E4=B8=9D=E9=A1=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/mine/view.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pages/mine/view.dart b/lib/pages/mine/view.dart index 371b96ce..274572af 100644 --- a/lib/pages/mine/view.dart +++ b/lib/pages/mine/view.dart @@ -294,7 +294,7 @@ class _MinePageState extends State { ), ), InkWell( - onTap: () => _mineController.pushFollow(), + onTap: () => _mineController.pushFans(), borderRadius: StyleString.mdRadius, child: Column( mainAxisAlignment: MainAxisAlignment.center, From afcc5a9a02cb15f9fd7d905a48edc05e2d3b5e68 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Mon, 18 Sep 2023 23:44:35 +0800 Subject: [PATCH 19/29] =?UTF-8?q?fix:=20=E5=88=A0=E9=99=A4=E4=B8=93?= =?UTF-8?q?=E6=A0=8F=E3=80=81=E7=9B=B4=E6=92=AD=E7=9A=84=E5=8E=86=E5=8F=B2?= =?UTF-8?q?=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/http/user.dart | 2 +- lib/pages/history/controller.dart | 14 ++++-- lib/pages/history/widgets/item.dart | 67 +++++++++++++++-------------- 3 files changed, 46 insertions(+), 37 deletions(-) diff --git a/lib/http/user.dart b/lib/http/user.dart index b27cfde1..705fbec3 100644 --- a/lib/http/user.dart +++ b/lib/http/user.dart @@ -238,7 +238,7 @@ class UserHttp { var res = await Request().post( Api.delHistory, queryParameters: { - 'kid': 'archive_$kid', + 'kid': kid, 'jsonp': 'jsonp', 'csrf': await Request.getCsrf(), }, diff --git a/lib/pages/history/controller.dart b/lib/pages/history/controller.dart index d6475d32..2152c161 100644 --- a/lib/pages/history/controller.dart +++ b/lib/pages/history/controller.dart @@ -123,8 +123,15 @@ class HistoryController extends GetxController { } // 删除某条历史记录 - Future delHistory(kid) async { - var res = await UserHttp.delHistory(kid); + Future delHistory(kid, business) async { + String resKid = 'archive_$kid'; + if (business == 'live') { + resKid = 'live_$kid'; + } else if (business.contains('article')) { + resKid = 'article_$kid'; + } + + var res = await UserHttp.delHistory(resKid); if (res['status']) { historyList.removeWhere((e) => e.kid == kid); SmartDialog.showToast(res['msg']); @@ -136,7 +143,8 @@ class HistoryController extends GetxController { List result = historyList.where((e) => e.progress == -1).toList(); for (HisListItem i in result) { - await UserHttp.delHistory(i.kid); + String resKid = 'archive_${i.kid}'; + await UserHttp.delHistory(resKid); historyList.removeWhere((e) => e.kid == i.kid); } SmartDialog.showToast('操作完成'); diff --git a/lib/pages/history/widgets/item.dart b/lib/pages/history/widgets/item.dart index 3500febe..81c100a7 100644 --- a/lib/pages/history/widgets/item.dart +++ b/lib/pages/history/widgets/item.dart @@ -247,26 +247,26 @@ class VideoContent extends StatelessWidget { Theme.of(context).textTheme.labelMedium!.fontSize, color: Theme.of(context).colorScheme.outline), ), - if (videoItem.badge != '番剧' && - !videoItem.tagName.contains('动画') && - videoItem.history.business != 'live' && - !videoItem.history.business.contains('article')) - SizedBox( - width: 24, - height: 24, - child: PopupMenuButton( - padding: EdgeInsets.zero, - tooltip: '功能菜单', - icon: Icon( - Icons.more_vert_outlined, - color: Theme.of(context).colorScheme.outline, - size: 14, - ), - position: PopupMenuPosition.under, - // constraints: const BoxConstraints(maxHeight: 35), - onSelected: (String type) {}, - itemBuilder: (BuildContext context) => - >[ + SizedBox( + width: 24, + height: 24, + child: PopupMenuButton( + padding: EdgeInsets.zero, + tooltip: '功能菜单', + icon: Icon( + Icons.more_vert_outlined, + color: Theme.of(context).colorScheme.outline, + size: 14, + ), + position: PopupMenuPosition.under, + // constraints: const BoxConstraints(maxHeight: 35), + onSelected: (String type) {}, + itemBuilder: (BuildContext context) => + >[ + if (videoItem.badge != '番剧' && + !videoItem.tagName.contains('动画') && + videoItem.history.business != 'live' && + !videoItem.history.business.contains('article')) PopupMenuItem( onTap: () async { var res = await UserHttp.toViewLater( @@ -283,21 +283,22 @@ class VideoContent extends StatelessWidget { ], ), ), - PopupMenuItem( - onTap: () => ctr!.delHistory(videoItem.kid), - value: 'pause', - height: 35, - child: const Row( - children: [ - Icon(Icons.close_outlined, size: 16), - SizedBox(width: 6), - Text('删除记录', style: TextStyle(fontSize: 13)) - ], - ), + PopupMenuItem( + onTap: () => ctr!.delHistory( + videoItem.kid, videoItem.history.business), + value: 'pause', + height: 35, + child: const Row( + children: [ + Icon(Icons.close_outlined, size: 16), + SizedBox(width: 6), + Text('删除记录', style: TextStyle(fontSize: 13)) + ], ), - ], - ), + ), + ], ), + ), ], ), ], From 97fa047c60fff61693f20ad02a6ffe5cab7aa788 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Tue, 19 Sep 2023 00:06:00 +0800 Subject: [PATCH 20/29] =?UTF-8?q?feat:=20=E6=90=9C=E7=B4=A2=E4=B8=93?= =?UTF-8?q?=E6=A0=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/http/search.dart | 6 +++--- lib/models/common/search_type.dart | 2 +- lib/models/search/result.dart | 3 +++ lib/pages/searchPanel/view.dart | 4 ++-- lib/pages/searchPanel/widgets/article_panel.dart | 10 +++++++++- 5 files changed, 18 insertions(+), 7 deletions(-) diff --git a/lib/http/search.dart b/lib/http/search.dart index e35b2da3..8583b271 100644 --- a/lib/http/search.dart +++ b/lib/http/search.dart @@ -89,9 +89,9 @@ class SearchHttp { case SearchType.media_bangumi: data = SearchMBangumiModel.fromJson(res.data['data']); break; - // case SearchType.article: - // data = SearchArticleModel.fromJson(res.data['data']); - // break; + case SearchType.article: + data = SearchArticleModel.fromJson(res.data['data']); + break; } return { 'status': true, diff --git a/lib/models/common/search_type.dart b/lib/models/common/search_type.dart index c535e9f4..d7d13aec 100644 --- a/lib/models/common/search_type.dart +++ b/lib/models/common/search_type.dart @@ -17,7 +17,7 @@ enum SearchType { // 用户:bili_user bili_user, // 专栏:article - // article, + article, // 相簿:photo // photo } diff --git a/lib/models/search/result.dart b/lib/models/search/result.dart index 9f4d067f..7aec24dd 100644 --- a/lib/models/search/result.dart +++ b/lib/models/search/result.dart @@ -397,6 +397,7 @@ class SearchArticleItemModel { this.pubTime, this.like, this.title, + this.subTitle, this.rankOffset, this.mid, this.imageUrls, @@ -414,6 +415,7 @@ class SearchArticleItemModel { int? pubTime; int? like; List? title; + String? subTitle; int? rankOffset; int? mid; List? imageUrls; @@ -431,6 +433,7 @@ class SearchArticleItemModel { pubTime = json['pub_time']; like = json['like']; title = Em.regTitle(json['title']); + subTitle = json['title'].replaceAll(RegExp(r'<[^>]*>'), ''); rankOffset = json['rank_offset']; mid = json['mid']; imageUrls = json['image_urls']; diff --git a/lib/pages/searchPanel/view.dart b/lib/pages/searchPanel/view.dart index 45c5f22f..9fd37b7e 100644 --- a/lib/pages/searchPanel/view.dart +++ b/lib/pages/searchPanel/view.dart @@ -91,8 +91,8 @@ class _SearchPanelState extends State return searchUserPanel(context, ctr, list); case SearchType.live_room: return searchLivePanel(context, ctr, list); - // case SearchType.article: - // return searchArticlePanel(context, ctr, list); + case SearchType.article: + return searchArticlePanel(context, ctr, list); default: return const SizedBox(); } diff --git a/lib/pages/searchPanel/widgets/article_panel.dart b/lib/pages/searchPanel/widgets/article_panel.dart index 141a1b31..6e73151a 100644 --- a/lib/pages/searchPanel/widgets/article_panel.dart +++ b/lib/pages/searchPanel/widgets/article_panel.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:get/get.dart'; import 'package:pilipala/common/constants.dart'; import 'package:pilipala/common/widgets/network_img_layer.dart'; import 'package:pilipala/utils/utils.dart'; @@ -12,7 +13,14 @@ Widget searchArticlePanel(BuildContext context, ctr, list) { itemCount: list.length, itemBuilder: (context, index) { return InkWell( - onTap: () {}, + onTap: () { + Get.toNamed('/htmlRender', parameters: { + 'url': 'www.bilibili.com/read/cv${list[index].id}', + 'title': list[index].subTitle, + 'id': 'cv${list[index].id}', + 'dynamicType': 'read' + }); + }, child: Padding( padding: const EdgeInsets.fromLTRB( StyleString.safeSpace, 5, StyleString.safeSpace, 5), From 7458c33173e959f61d4ad3237643250200aeef12 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Tue, 19 Sep 2023 23:39:00 +0800 Subject: [PATCH 21/29] =?UTF-8?q?fix:=20=E5=B1=8F=E5=B9=95=E5=B8=A7?= =?UTF-8?q?=E7=8E=87=20issues=20#99=20#115?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/main.dart | 20 ++++++++++++++++++++ lib/pages/setting/pages/display_mode.dart | 21 ++++++++++++++++++--- lib/utils/storage.dart | 1 + 3 files changed, 39 insertions(+), 3 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 5040edca..dd87ed44 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,4 +1,7 @@ +import 'dart:io'; + import 'package:flutter/services.dart'; +import 'package:flutter_displaymode/flutter_displaymode.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; @@ -61,6 +64,23 @@ class MyApp extends StatelessWidget { double textScale = setting.get(SettingBoxKey.defaultTextScale, defaultValue: 1.0); + // 强制设置高帧率 + if (Platform.isAndroid) { + try { + late List modes; + FlutterDisplayMode.supported.then((value) { + modes = value; + var storageDisplay = setting.get(SettingBoxKey.displayMode); + DisplayMode f = DisplayMode.auto; + if (storageDisplay != null) { + f = modes.firstWhere((e) => e.toString() == storageDisplay); + } + DisplayMode preferred = modes.toList().firstWhere((el) => el == f); + FlutterDisplayMode.setPreferredMode(preferred); + }); + } catch (_) {} + } + return DynamicColorBuilder( builder: ((ColorScheme? lightDynamic, ColorScheme? darkDynamic) { ColorScheme? lightColorScheme; diff --git a/lib/pages/setting/pages/display_mode.dart b/lib/pages/setting/pages/display_mode.dart index 4e84e956..0dcf1958 100644 --- a/lib/pages/setting/pages/display_mode.dart +++ b/lib/pages/setting/pages/display_mode.dart @@ -2,6 +2,8 @@ import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter/services.dart'; import 'package:flutter_displaymode/flutter_displaymode.dart'; +import 'package:hive/hive.dart'; +import 'package:pilipala/utils/storage.dart'; class SetDiaplayMode extends StatefulWidget { const SetDiaplayMode({super.key}); @@ -14,6 +16,7 @@ class _SetDiaplayModeState extends State { List modes = []; DisplayMode? active; DisplayMode? preferred; + Box setting = GStrorage.setting; final ValueNotifier page = ValueNotifier(0); late final PageController controller = PageController() @@ -29,24 +32,36 @@ class _SetDiaplayModeState extends State { }); } + // 获取所有的mode Future fetchAll() async { preferred = await FlutterDisplayMode.preferred; active = await FlutterDisplayMode.active; - // GStorage().setDisplayModeType(preferred!); + await setting.put(SettingBoxKey.displayMode, preferred.toString()); setState(() {}); } + // 初始化mode/手动设置 Future init() async { try { modes = await FlutterDisplayMode.supported; } on PlatformException catch (e) { print(e); } - // var res = await GStorage().getDisplayModeType(); - // preferred = modes.toList().firstWhere((el) => el == res); + var res = await getDisplayModeType(modes); + + preferred = modes.toList().firstWhere((el) => el == res); FlutterDisplayMode.setPreferredMode(preferred!); } + Future getDisplayModeType(modes) async { + var value = setting.get(SettingBoxKey.displayMode); + DisplayMode f = DisplayMode.auto; + if (value != null) { + f = modes.firstWhere((e) => e.toString() == value); + } + return f; + } + @override Widget build(BuildContext context) { return Scaffold( diff --git a/lib/utils/storage.dart b/lib/utils/storage.dart index 6ecd6083..8a8dbc40 100644 --- a/lib/utils/storage.dart +++ b/lib/utils/storage.dart @@ -129,6 +129,7 @@ class SettingBoxKey { static const String customColor = 'customColor'; // 自定义主题色 static const String iosTransition = 'iosTransition'; // ios路由 static const String enableSingleRow = 'enableSingleRow'; // 首页单列 + static const String displayMode = 'displayMode'; } class LocalCacheKey { From a48d15ee7358f0c2632a9e69ad5295ef75daef0b Mon Sep 17 00:00:00 2001 From: guozhigq Date: Tue, 19 Sep 2023 23:58:30 +0800 Subject: [PATCH 22/29] =?UTF-8?q?feat:=20=E8=BD=AC=E5=8F=91=E7=9A=84?= =?UTF-8?q?=E6=8A=95=E7=A8=BF=E5=8A=A8=E6=80=81=E8=B7=B3=E8=BD=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dynamics/widgets/additional_panel.dart | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/lib/pages/dynamics/widgets/additional_panel.dart b/lib/pages/dynamics/widgets/additional_panel.dart index e283fcf9..f25b913e 100644 --- a/lib/pages/dynamics/widgets/additional_panel.dart +++ b/lib/pages/dynamics/widgets/additional_panel.dart @@ -1,5 +1,8 @@ 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/http/search.dart'; /// TODO 点击跳转 Widget addWidget(item, context, type, {floor = 1}) { @@ -19,8 +22,27 @@ Widget addWidget(item, context, type, {floor = 1}) { : Theme.of(context).colorScheme.background; switch (type) { case 'ADDITIONAL_TYPE_UGC': + // 转发的投稿 return InkWell( - onTap: () {}, + onTap: () async { + String text = dynamicProperty[type].jumpUrl; + RegExp bvRegex = RegExp(r'BV[0-9A-Za-z]{10}', caseSensitive: false); + Iterable matches = bvRegex.allMatches(text); + if (matches.isNotEmpty) { + Match match = matches.first; + String bvid = match.group(0)!; + String cover = dynamicProperty[type].cover; + try { + int cid = await SearchHttp.ab2c(bvid: bvid); + Get.toNamed('/video?bvid=$bvid&cid=$cid', + arguments: {'pic': cover, 'heroTag': bvid}); + } catch (err) { + SmartDialog.showToast(err.toString()); + } + } else { + print("No match found."); + } + }, child: Container( padding: const EdgeInsets.only(left: 12, top: 8, right: 12, bottom: 8), From ba815bccdafce38996594e038607d40d7965a860 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Wed, 20 Sep 2023 23:26:03 +0800 Subject: [PATCH 23/29] =?UTF-8?q?feat:=20=E8=A7=86=E9=A2=91=E7=AE=80?= =?UTF-8?q?=E4=BB=8B=E9=93=BE=E6=8E=A5=E5=8C=B9=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../introduction/widgets/intro_detail.dart | 46 ++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/lib/pages/video/detail/introduction/widgets/intro_detail.dart b/lib/pages/video/detail/introduction/widgets/intro_detail.dart index d9846b19..1db23a1d 100644 --- a/lib/pages/video/detail/introduction/widgets/intro_detail.dart +++ b/lib/pages/video/detail/introduction/widgets/intro_detail.dart @@ -1,5 +1,6 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:hive/hive.dart'; import 'package:pilipala/common/widgets/stat/danmu.dart'; @@ -129,7 +130,50 @@ class IntroDetail extends StatelessWidget { final currentDesc = descV2[index]; switch (currentDesc.type) { case 1: - return TextSpan(text: currentDesc.rawText); + List spanChildren = []; + RegExp urlRegExp = RegExp(r'https?://\S+\b'); + Iterable matches = urlRegExp.allMatches(currentDesc.rawText); + + int previousEndIndex = 0; + for (Match match in matches) { + if (match.start > previousEndIndex) { + spanChildren.add(TextSpan( + text: currentDesc.rawText + .substring(previousEndIndex, match.start))); + } + spanChildren.add( + TextSpan( + text: match.group(0), + style: TextStyle( + color: Theme.of(context).colorScheme.primary), // 设置颜色为蓝色 + recognizer: TapGestureRecognizer() + ..onTap = () { + // 处理点击事件 + try { + Get.toNamed( + '/webview', + parameters: { + 'url': match.group(0)!, + 'type': 'url', + 'pageTitle': match.group(0)!, + }, + ); + } catch (err) { + SmartDialog.showToast(err.toString()); + } + }, + ), + ); + previousEndIndex = match.end; + } + + if (previousEndIndex < currentDesc.rawText.length) { + spanChildren.add(TextSpan( + text: currentDesc.rawText.substring(previousEndIndex))); + } + + TextSpan result = TextSpan(children: spanChildren); + return result; case 2: final colorSchemePrimary = Theme.of(context).colorScheme.primary; final heroTag = Utils.makeHeroTag(currentDesc.bizId); From d1272efad4f15dd168cf395e9a9e84b2647747c0 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Wed, 20 Sep 2023 23:31:11 +0800 Subject: [PATCH 24/29] =?UTF-8?q?mod:=20=E8=A1=A5=E5=85=85=E9=93=BE?= =?UTF-8?q?=E6=8E=A5=E6=89=93=E5=BC=80=E5=BD=A2=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/webview/view.dart | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/lib/pages/webview/view.dart b/lib/pages/webview/view.dart index 301b1dfa..8edd2189 100644 --- a/lib/pages/webview/view.dart +++ b/lib/pages/webview/view.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:url_launcher/url_launcher.dart'; import 'controller.dart'; import 'package:webview_flutter/webview_flutter.dart'; @@ -24,11 +25,20 @@ class _WebviewPageState extends State { style: Theme.of(context).textTheme.titleMedium, ), actions: [ - TextButton( + const SizedBox(width: 4), + IconButton( onPressed: () { _webviewController.controller.reload(); }, - child: const Text('刷新'), + icon: Icon(Icons.refresh_outlined, + color: Theme.of(context).colorScheme.primary), + ), + IconButton( + onPressed: () { + launchUrl(Uri.parse(_webviewController.url)); + }, + icon: Icon(Icons.open_in_browser_outlined, + color: Theme.of(context).colorScheme.primary), ), Obx( () => _webviewController.type.value == 'login' @@ -38,7 +48,7 @@ class _WebviewPageState extends State { ) : const SizedBox(), ), - const SizedBox(width: 10) + const SizedBox(width: 12) ], ), body: Column( From 97268c36dc0a71184dc50fce5554d10fe0c00ce0 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Wed, 20 Sep 2023 23:52:04 +0800 Subject: [PATCH 25/29] =?UTF-8?q?feat:=20=E9=A6=96=E9=A1=B5=E5=88=B7?= =?UTF-8?q?=E6=96=B0=E9=80=BB=E8=BE=91=20issues=20#133?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/rcmd/controller.dart | 9 ++++++++- lib/pages/setting/extra_setting.dart | 6 ++++++ lib/utils/storage.dart | 1 + 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/lib/pages/rcmd/controller.dart b/lib/pages/rcmd/controller.dart index 1f21ab0d..f3acb67d 100644 --- a/lib/pages/rcmd/controller.dart +++ b/lib/pages/rcmd/controller.dart @@ -14,6 +14,7 @@ class RcmdController extends GetxController { Box recVideo = GStrorage.recVideo; Box setting = GStrorage.setting; RxInt crossAxisCount = 2.obs; + late bool enableSaveLastData; @override void onInit() { @@ -28,6 +29,8 @@ class RcmdController extends GetxController { } videoList.value = list; } + enableSaveLastData = + setting.get(SettingBoxKey.enableSaveLastData, defaultValue: false); } // 获取推荐 @@ -49,7 +52,11 @@ class RcmdController extends GetxController { videoList.value = res['data']; } } else if (type == 'onRefresh') { - videoList.value = res['data']; + if (enableSaveLastData) { + videoList.insertAll(0, res['data']); + } else { + videoList.value = res['data']; + } } else if (type == 'onLoad') { videoList.addAll(res['data']); } diff --git a/lib/pages/setting/extra_setting.dart b/lib/pages/setting/extra_setting.dart index f56029e6..4bbb841c 100644 --- a/lib/pages/setting/extra_setting.dart +++ b/lib/pages/setting/extra_setting.dart @@ -79,6 +79,12 @@ 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), diff --git a/lib/utils/storage.dart b/lib/utils/storage.dart index 6ecd6083..fdf0fb0a 100644 --- a/lib/utils/storage.dart +++ b/lib/utils/storage.dart @@ -121,6 +121,7 @@ class SettingBoxKey { static const String enableWordRe = 'enableWordRe'; static const String enableSearchWord = 'enableSearchWord'; static const String enableRcmdDynamic = 'enableRcmdDynamic'; + static const String enableSaveLastData = 'enableSaveLastData'; /// 外观 static const String themeMode = 'themeMode'; From f79e4765c2c43f8a4261f58ff494bdcca0aad0df Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sat, 23 Sep 2023 00:48:22 +0800 Subject: [PATCH 26/29] =?UTF-8?q?feat:=20UP=E4=B8=BB=E6=8A=95=E7=A8=BF?= =?UTF-8?q?=E6=8E=92=E5=BA=8F=E6=9F=A5=E8=AF=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/member/archive/controller.dart | 20 ++++++- lib/pages/member/archive/view.dart | 72 +++++++++++++++++++++++- pubspec.lock | 8 +-- pubspec.yaml | 2 +- 4 files changed, 94 insertions(+), 8 deletions(-) diff --git a/lib/pages/member/archive/controller.dart b/lib/pages/member/archive/controller.dart index e893a07d..9a15d4fc 100644 --- a/lib/pages/member/archive/controller.dart +++ b/lib/pages/member/archive/controller.dart @@ -5,20 +5,38 @@ class ArchiveController extends GetxController { int? mid; int pn = 1; int count = 0; + RxMap currentOrder = {}.obs; + List> orderList = [ + {'type': 'pubdate', 'label': '最新发布'}, + {'type': 'click', 'label': '最多播放'}, + {'type': 'stow', 'label': '最多收藏'}, + ]; @override void onInit() { super.onInit(); mid = int.parse(Get.parameters['mid']!); + currentOrder.value = orderList.first; } // 获取用户投稿 Future getMemberArchive() async { - var res = await MemberHttp.memberArchive(mid: mid, pn: pn); + var res = await MemberHttp.memberArchive( + mid: mid, pn: pn, order: currentOrder['type']!); if (res['status']) { count = res['data'].page['count']; pn += 1; } return res; } + + toggleSort() async { + pn = 1; + int index = orderList.indexOf(currentOrder.value); + if (index == orderList.length - 1) { + currentOrder.value = orderList.first; + } else { + currentOrder.value = orderList[index + 1]; + } + } } diff --git a/lib/pages/member/archive/view.dart b/lib/pages/member/archive/view.dart index 430f5ede..f387a557 100644 --- a/lib/pages/member/archive/view.dart +++ b/lib/pages/member/archive/view.dart @@ -18,6 +18,8 @@ class _ArchivePanelState extends State with AutomaticKeepAliveClientMixin { DateTime lastRefreshTime = DateTime.now(); late final LoadMoreListSource source = LoadMoreListSource(); + final ArchiveController _archiveController = + Get.put(ArchiveController(), tag: Get.arguments['heroTag']); @override bool get wantKeepAlive => true; @@ -40,14 +42,63 @@ class _ArchivePanelState extends State // return PullToRefreshHeader(info, lastRefreshTime); // }, // ), - const SizedBox(height: 4), + Padding( + padding: + const EdgeInsets.only(left: 14, top: 8, bottom: 8, right: 8), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Text('排序方式'), + SizedBox( + height: 35, + width: 85, + child: TextButton( + style: ButtonStyle( + padding: MaterialStateProperty.all(EdgeInsets.zero), + ), + onPressed: () { + // _archiveController.order = 'click'; + // _archiveController.pn = 1; + _archiveController.toggleSort(); + source.refresh(true); + // LoadMoreListSource().loadData(); + }, + child: Obx( + () => AnimatedSwitcher( + duration: const Duration(milliseconds: 400), + transitionBuilder: + (Widget child, Animation animation) { + return ScaleTransition( + scale: animation, child: child); + }, + child: Text( + _archiveController.currentOrder['label']!, + key: ValueKey( + _archiveController.currentOrder['label']!), + ), + ), + ), + ), + ), + ], + ), + ), Expanded( child: LoadingMoreList( ListConfig( sourceList: source, itemBuilder: (BuildContext c, VListItemModel item, int index) { - return VideoCardH(videoItem: item); + if (index == 0) { + return Column( + children: [ + const SizedBox(height: 6), + VideoCardH(videoItem: item) + ], + ); + } else { + return VideoCardH(videoItem: item); + } }, indicatorBuilder: _buildIndicator, ), @@ -144,12 +195,16 @@ class _ArchivePanelState extends State class LoadMoreListSource extends LoadingMoreBase { final ArchiveController _archiveController = Get.put(ArchiveController(), tag: Get.arguments['heroTag']); + bool forceRefresh = false; @override Future loadData([bool isloadMoreAction = false]) async { bool isSuccess = false; var res = await _archiveController.getMemberArchive(); if (res['status']) { + if (_archiveController.pn == 2) { + clear(); + } addAll(res['data'].list.vlist); } if (length < res['data'].page['count']) { @@ -159,4 +214,17 @@ class LoadMoreListSource extends LoadingMoreBase { } return isSuccess; } + + @override + Future refresh([bool clearBeforeRequest = false]) async { + // _hasMore = true; + // pageindex = 1; + // //force to refresh list when you don't want clear list before request + // //for the case, if your list already has 20 items. + forceRefresh = !clearBeforeRequest; + var result = await super.refresh(clearBeforeRequest); + + forceRefresh = false; + return result; + } } diff --git a/pubspec.lock b/pubspec.lock index a80f40cb..c1af42ef 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -721,18 +721,18 @@ packages: dependency: "direct main" description: name: loading_more_list - sha256: aa680edc81cf024c394dccfa7ba1db701a5efb23ec1b8c657308428ce9da11d1 + sha256: "6b49eb935345d6cf291e0367d3c238ef0a525a08b671ee41e09ee67d41888a7a" url: "https://pub.dev" source: hosted - version: "5.0.3" + version: "6.0.0" loading_more_list_library: dependency: transitive description: name: loading_more_list_library - sha256: "31348925a98748ffe04f661e4b47df37103fabad39442064fcf59148a5fee2dd" + sha256: de6b57edbab83022180f053ec3f598dd5e1192cfd6a285882b8155e3cb5dc581 url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "3.0.0" logging: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 22d91b26..e6497778 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -70,7 +70,7 @@ dependencies: # 解决sliver滑动不同步 extended_nested_scroll_view: ^6.1.2 # 上拉加载 - loading_more_list: ^5.0.3 + loading_more_list: ^6.0.0 # 下拉刷新 pull_to_refresh_notification: ^3.0.1 # 图标 From 7ad6b25abe6a7dc9b14cb8b482511b030b2ab5fb Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 24 Sep 2023 00:34:20 +0800 Subject: [PATCH 27/29] =?UTF-8?q?feat:=20UP=E4=B8=BB=E6=8A=95=E7=A8=BF?= =?UTF-8?q?=E6=90=9C=E7=B4=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/http/api.dart | 3 + lib/http/member.dart | 27 +++- lib/pages/member/view.dart | 5 + lib/pages/member_search/controller.dart | 90 +++++++++++ lib/pages/member_search/index.dart | 4 + lib/pages/member_search/view.dart | 195 ++++++++++++++++++++++++ lib/router/app_pages.dart | 2 + 7 files changed, 324 insertions(+), 2 deletions(-) create mode 100644 lib/pages/member_search/controller.dart create mode 100644 lib/pages/member_search/index.dart create mode 100644 lib/pages/member_search/view.dart diff --git a/lib/http/api.dart b/lib/http/api.dart index ef9fe94a..288f0b2b 100644 --- a/lib/http/api.dart +++ b/lib/http/api.dart @@ -245,6 +245,9 @@ class Api { // wts=1689767832 static const String memberArchive = '/x/space/wbi/arc/search'; + // 用户动态搜索 + static const String memberDynamicSearch = '/x/space/dynamic/search'; + // 用户动态 static const String memberDynamic = '/x/polymer/web-dynamic/v1/feed/space'; diff --git a/lib/http/member.dart b/lib/http/member.dart index 5cf3f1ee..a9c158da 100644 --- a/lib/http/member.dart +++ b/lib/http/member.dart @@ -66,7 +66,7 @@ class MemberHttp { int ps = 30, int tid = 0, int? pn, - String keyword = '', + String? keyword, String order = 'pubdate', bool orderAvoided = true, }) async { @@ -75,7 +75,7 @@ class MemberHttp { 'ps': ps, 'tid': tid, 'pn': pn, - 'keyword': keyword, + 'keyword': keyword ?? '', 'order': order, 'platform': 'web', 'web_location': 1550101, @@ -121,4 +121,27 @@ class MemberHttp { }; } } + + // 搜索用户动态 + static Future memberDynamicSearch({int? pn, int? ps, int? mid}) async { + var res = await Request().get(Api.memberDynamic, data: { + 'keyword': '海拔', + 'mid': mid, + 'pn': pn, + 'ps': ps, + 'platform': 'web' + }); + if (res.data['code'] == 0) { + return { + 'status': true, + 'data': DynamicsDataModel.fromJson(res.data['data']), + }; + } else { + return { + 'status': false, + 'data': [], + 'msg': res.data['message'], + }; + } + } } diff --git a/lib/pages/member/view.dart b/lib/pages/member/view.dart index a29bd545..66db7ec8 100644 --- a/lib/pages/member/view.dart +++ b/lib/pages/member/view.dart @@ -109,6 +109,11 @@ class _MemberPageState extends State }, ), actions: [ + IconButton( + onPressed: () => Get.toNamed( + '/memberSearch?mid=${Get.parameters['mid']}&uname=${_memberController.memberInfo.value.name!}'), + icon: const Icon(Icons.search_outlined), + ), PopupMenuButton( icon: const Icon(Icons.more_vert), itemBuilder: (BuildContext context) => [ diff --git a/lib/pages/member_search/controller.dart b/lib/pages/member_search/controller.dart new file mode 100644 index 00000000..be4f5b1a --- /dev/null +++ b/lib/pages/member_search/controller.dart @@ -0,0 +1,90 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:pilipala/http/member.dart'; +import 'package:pilipala/models/member/archive.dart'; + +class MemberSearchController extends GetxController { + final ScrollController scrollController = ScrollController(); + Rx controller = TextEditingController().obs; + final FocusNode searchFocusNode = FocusNode(); + RxString searchKeyWord = ''.obs; + String hintText = '搜索'; + RxString loadingStatus = 'init'.obs; + RxString loadingText = '加载中...'.obs; + bool hasRequest = false; + late int mid; + RxString uname = ''.obs; + int archivePn = 1; + int archiveCount = 0; + RxList archiveList = [].obs; + int dynamic_pn = 1; + RxList dynamicList = [].obs; + + int ps = 30; + + @override + void onInit() { + super.onInit(); + mid = int.parse(Get.parameters['mid']!); + uname.value = Get.parameters['uname']!; + } + + // 清空搜索 + void onClear() { + if (searchKeyWord.value.isNotEmpty && controller.value.text != '') { + controller.value.clear(); + searchKeyWord.value = ''; + } else { + Get.back(); + } + } + + void onChange(value) { + searchKeyWord.value = value; + } + + // 提交搜索内容 + void submit() { + loadingStatus.value = 'loading'; + if (hasRequest) { + archivePn = 1; + searchArchives(); + } + } + + // 搜索视频 + Future searchArchives({type = 'init'}) async { + if (type == 'onLoad' && loadingText.value == '没有更多了') { + return; + } + var res = await MemberHttp.memberArchive( + mid: mid, + pn: archivePn, + keyword: controller.value.text, + order: 'pubdate', + ); + if (res['status']) { + if (type == 'init' || archivePn == 1) { + archiveList.value = res['data'].list.vlist; + } else { + archiveList.addAll(res['data'].list.vlist); + } + archiveCount = res['data'].page['count']; + if (archiveList.length == archiveCount) { + loadingText.value = '没有更多了'; + } + archivePn += 1; + hasRequest = true; + } + // loadingStatus.value = 'finish'; + return res; + } + + // 搜索动态 + Future searchDynamic() async {} + + // + onLoad() { + searchArchives(type: 'onLoad'); + } +} diff --git a/lib/pages/member_search/index.dart b/lib/pages/member_search/index.dart new file mode 100644 index 00000000..4f10617b --- /dev/null +++ b/lib/pages/member_search/index.dart @@ -0,0 +1,4 @@ +library member_search; + +export './controller.dart'; +export './view.dart'; diff --git a/lib/pages/member_search/view.dart b/lib/pages/member_search/view.dart new file mode 100644 index 00000000..ff0553a2 --- /dev/null +++ b/lib/pages/member_search/view.dart @@ -0,0 +1,195 @@ +import 'package:easy_debounce/easy_throttle.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:pilipala/common/skeleton/video_card_h.dart'; +import 'package:pilipala/common/widgets/http_error.dart'; +import 'package:pilipala/common/widgets/no_data.dart'; +import 'package:pilipala/common/widgets/video_card_h.dart'; + +import 'controller.dart'; + +class MemberSearchPage extends StatefulWidget { + const MemberSearchPage({super.key}); + + @override + State createState() => _MemberSearchPageState(); +} + +class _MemberSearchPageState extends State + with SingleTickerProviderStateMixin { + final MemberSearchController _memberSearchCtr = + Get.put(MemberSearchController()); + late ScrollController scrollController; + + @override + void initState() { + super.initState(); + scrollController = _memberSearchCtr.scrollController; + scrollController.addListener( + () { + if (scrollController.position.pixels >= + scrollController.position.maxScrollExtent - 300) { + EasyThrottle.throttle('history', const Duration(seconds: 1), () { + _memberSearchCtr.onLoad(); + }); + } + }, + ); + // _tabController = TabController(length: 2, vsync: this); + } + + @override + void dispose() { + // _tabController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + titleSpacing: 0, + actions: [ + IconButton( + onPressed: () => _memberSearchCtr.submit(), + icon: const Icon(CupertinoIcons.search, size: 22)), + const SizedBox(width: 10) + ], + title: Obx( + () => TextField( + autofocus: true, + focusNode: _memberSearchCtr.searchFocusNode, + controller: _memberSearchCtr.controller.value, + textInputAction: TextInputAction.search, + onChanged: (value) => _memberSearchCtr.onChange(value), + decoration: InputDecoration( + hintText: _memberSearchCtr.hintText, + border: InputBorder.none, + suffixIcon: IconButton( + icon: Icon( + Icons.clear, + size: 22, + color: Theme.of(context).colorScheme.outline, + ), + onPressed: () => _memberSearchCtr.onClear(), + ), + ), + onSubmitted: (String value) => _memberSearchCtr.submit(), + ), + ), + ), + body: Obx( + () => Column( + children: _memberSearchCtr.loadingStatus.value == 'init' + ? [ + Expanded( + child: Center( + child: Text('搜索「${_memberSearchCtr.uname.value}」的动态、视频'), + ), + ), + ] + : [ + // TabBar( + // controller: _tabController, + // tabs: const [ + // Tab(text: "视频"), + // Tab(text: "动态"), + // ], + // ), + Expanded( + child: + // TabBarView( + // controller: _tabController, + // children: [ + FutureBuilder( + future: _memberSearchCtr.searchArchives(), + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.done) { + Map data = snapshot.data as Map; + if (data['status']) { + return Obx( + () => _memberSearchCtr.archiveList.isNotEmpty + ? ListView.builder( + controller: scrollController, + itemCount: + _memberSearchCtr.archiveList.length + + 1, + itemBuilder: (context, index) { + if (index == + _memberSearchCtr + .archiveList.length) { + return Container( + height: MediaQuery.of(context) + .padding + .bottom + + 60, + padding: EdgeInsets.only( + bottom: MediaQuery.of(context) + .padding + .bottom), + child: Center( + child: Obx( + () => Text( + _memberSearchCtr + .loadingText.value, + style: TextStyle( + color: Theme.of(context) + .colorScheme + .outline, + fontSize: 13), + ), + ), + ), + ); + } else { + return VideoCardH( + videoItem: _memberSearchCtr + .archiveList[index]); + } + }, + ) + : _memberSearchCtr.loadingStatus.value == + 'loading' + ? ListView.builder( + itemCount: 10, + itemBuilder: (context, index) { + return const VideoCardHSkeleton(); + }, + ) + : const CustomScrollView( + slivers: [ + NoData(), + ], + ), + ); + } else { + return CustomScrollView( + slivers: [ + HttpError( + errMsg: data['msg'], + fn: () => setState(() {}), + ) + ], + ); + } + } else { + // 骨架屏 + return ListView.builder( + itemCount: 10, + itemBuilder: (context, index) { + return const VideoCardHSkeleton(); + }, + ); + } + }, + ), + // ], + // ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/router/app_pages.dart b/lib/router/app_pages.dart index fd6db614..4b90fcd1 100644 --- a/lib/router/app_pages.dart +++ b/lib/router/app_pages.dart @@ -18,6 +18,7 @@ import 'package:pilipala/pages/html/index.dart'; import 'package:pilipala/pages/later/index.dart'; import 'package:pilipala/pages/liveRoom/view.dart'; import 'package:pilipala/pages/member/index.dart'; +import 'package:pilipala/pages/member_search/index.dart'; import 'package:pilipala/pages/preview/index.dart'; import 'package:pilipala/pages/search/index.dart'; import 'package:pilipala/pages/searchResult/index.dart'; @@ -86,6 +87,7 @@ class Routes { CustomGetPage(name: '/liveRoom', page: () => const LiveRoomPage()), // 用户中心 CustomGetPage(name: '/member', page: () => const MemberPage()), + CustomGetPage(name: '/memberSearch', page: () => const MemberSearchPage()), // 二级回复 CustomGetPage( name: '/replyReply', page: () => const VideoReplyReplyPanel()), From 3f50aab12d549ba2e4993cef3fecd5df6e554901 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 24 Sep 2023 00:47:45 +0800 Subject: [PATCH 28/29] =?UTF-8?q?mod:=20=E5=85=B3=E9=97=AD=E5=BC=B9?= =?UTF-8?q?=E5=B9=95=E6=97=B6=E5=81=9C=E6=AD=A2=E5=88=A4=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/danmaku/view.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/pages/danmaku/view.dart b/lib/pages/danmaku/view.dart index 5a5d8a11..ae699b1c 100644 --- a/lib/pages/danmaku/view.dart +++ b/lib/pages/danmaku/view.dart @@ -86,6 +86,9 @@ class _PlDanmakuState extends State { _controller!.onResume(); danmuPlayStatus = true; } + if (!playerController.isOpenDanmu.value) { + return; + } PlDanmakuController ctr = _plDanmakuController; int currentPosition = position.inMilliseconds; blockTypes = playerController.blockTypes; @@ -98,9 +101,6 @@ class _PlDanmakuState extends State { ctr.queryDanmaku(); }); } - if (!playerController.isOpenDanmu.value) { - return; - } // 超出分段数返回 if (ctr.currentSegIndex >= ctr.dmSegList.length) { return; From d6b6df3eeddf63935cb6314d1afee79ca80be77f Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 24 Sep 2023 00:56:55 +0800 Subject: [PATCH 29/29] fix: issues #157 --- lib/http/reply.dart | 2 +- lib/pages/video/detail/reply/controller.dart | 2 +- lib/pages/video/detail/reply/view.dart | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/http/reply.dart b/lib/http/reply.dart index 5dcbce6e..790a017f 100644 --- a/lib/http/reply.dart +++ b/lib/http/reply.dart @@ -26,7 +26,7 @@ class ReplyHttp { Map errMap = { -400: '请求错误', -404: '无此项', - 12002: '当前页面评论功能已关闭"', + 12002: '当前页面评论功能已关闭', 12009: '评论主体的type不合法', 12061: 'UP主已关闭评论区', }; diff --git a/lib/pages/video/detail/reply/controller.dart b/lib/pages/video/detail/reply/controller.dart index 207eb856..6bd0866f 100644 --- a/lib/pages/video/detail/reply/controller.dart +++ b/lib/pages/video/detail/reply/controller.dart @@ -96,8 +96,8 @@ class VideoReplyController extends GetxController { } else { replyList.addAll(replies); } + count.value = res['data'].page.count; } - count.value = res['data'].page.count; isLoadingMore = false; return res; } diff --git a/lib/pages/video/detail/reply/view.dart b/lib/pages/video/detail/reply/view.dart index 3f42c558..827fc3f9 100644 --- a/lib/pages/video/detail/reply/view.dart +++ b/lib/pages/video/detail/reply/view.dart @@ -195,7 +195,7 @@ class _VideoReplyPanelState extends State future: _futureBuilderFuture, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.done) { - Map data = snapshot.data as Map; + var data = snapshot.data; if (data['status']) { // 请求成功 return Obx(