From 85eeacebb82265aff08052f1d63ad645063a3f2c Mon Sep 17 00:00:00 2001 From: guozhigq Date: Mon, 24 Jul 2023 22:02:03 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=8A=A8=E6=80=81=E7=82=B9=E8=B5=9E/?= =?UTF-8?q?=E5=8F=96=E6=B6=88=E8=B5=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/http/api.dart | 4 + lib/http/constants.dart | 1 + lib/http/dynamics.dart | 27 +++ lib/http/init.dart | 10 +- lib/pages/dynamics/controller.dart | 6 +- lib/pages/dynamics/view.dart | 2 +- lib/pages/dynamics/widgets/action_panel.dart | 155 ++++++++++++------ lib/pages/dynamics/widgets/dynamic_panel.dart | 2 +- lib/pages/webview/controller.dart | 7 +- 9 files changed, 160 insertions(+), 54 deletions(-) diff --git a/lib/http/api.dart b/lib/http/api.dart index 65b70e11..0f29db31 100644 --- a/lib/http/api.dart +++ b/lib/http/api.dart @@ -145,6 +145,10 @@ class Api { // https://api.bilibili.com/x/polymer/web-dynamic/v1/feed/all?host_mid=548196587&offset=&page=1&features=itemOpusStyle static const String followDynamic = '/x/polymer/web-dynamic/v1/feed/all'; + // 动态点赞 + static const String likeDynamic = + 'https://api.vc.bilibili.com/dynamic_like/v1/dynamic_like/thumb'; + // 获取稍后再看 static const String seeYouLater = '/x/v2/history/toview'; diff --git a/lib/http/constants.dart b/lib/http/constants.dart index 619060a4..1f5319fb 100644 --- a/lib/http/constants.dart +++ b/lib/http/constants.dart @@ -1,4 +1,5 @@ class HttpString { static const String baseUrl = 'https://www.bilibili.com'; static const String baseApiUrl = 'https://api.bilibili.com'; + static const String tUrl = 'https://api.vc.bilibili.com'; } diff --git a/lib/http/dynamics.dart b/lib/http/dynamics.dart index 510e0ff2..8ec7bc3d 100644 --- a/lib/http/dynamics.dart +++ b/lib/http/dynamics.dart @@ -50,4 +50,31 @@ class DynamicsHttp { }; } } + + // 动态点赞 + static Future likeDynamic({ + required String? dynamicId, + required int? up, + }) async { + var res = await Request().post( + Api.likeDynamic, + queryParameters: { + 'dynamic_id': dynamicId, + 'up': up, + 'csrf': await Request.getCsrf(), + }, + ); + if (res.data['code'] == 0) { + return { + 'status': true, + 'data': res.data['data'], + }; + } else { + return { + 'status': false, + 'data': [], + 'msg': res.data['message'], + }; + } + } } diff --git a/lib/http/init.dart b/lib/http/init.dart index 08c73b39..b8fb87de 100644 --- a/lib/http/init.dart +++ b/lib/http/init.dart @@ -38,6 +38,8 @@ class Request { dio.interceptors.add(cookieManager); var cookie = await cookieManager.cookieJar .loadForRequest(Uri.parse(HttpString.baseUrl)); + var cookie2 = await cookieManager.cookieJar + .loadForRequest(Uri.parse(HttpString.tUrl)); if (cookie.isEmpty) { try { await Request().get(HttpString.baseUrl); @@ -45,6 +47,13 @@ class Request { log("setCookie, ${e.toString()}"); } } + if (cookie2.isEmpty) { + try { + await Request().get(HttpString.tUrl); + } catch (e) { + log("setCookie, ${e.toString()}"); + } + } } // 移除cookie @@ -99,7 +108,6 @@ class Request { options.headers['x-bili-mid'] = user.get(UserBoxKey.userMid).toString(); } dio.options = options; - //添加拦截器 dio.interceptors ..add(ApiInterceptor()) diff --git a/lib/pages/dynamics/controller.dart b/lib/pages/dynamics/controller.dart index 4f291454..c5297c1d 100644 --- a/lib/pages/dynamics/controller.dart +++ b/lib/pages/dynamics/controller.dart @@ -46,9 +46,9 @@ class DynamicsController extends GetxController { RxInt initialValue = 1.obs; Future queryFollowDynamic({type = 'init'}) async { - // if (type == 'init') { - // dynamicsList!.value = []; - // } + if (type == 'init') { + dynamicsList.clear(); + } var res = await DynamicsHttp.followDynamic( page: type == 'init' ? 1 : page, type: dynamicsType.value.values, diff --git a/lib/pages/dynamics/view.dart b/lib/pages/dynamics/view.dart index 0319f59b..b8165176 100644 --- a/lib/pages/dynamics/view.dart +++ b/lib/pages/dynamics/view.dart @@ -236,7 +236,7 @@ class _DynamicsPageState extends State List list = _dynamicsController.dynamicsList; return Obx( - () => list.length == 1 + () => list.isEmpty ? skeleton() : SliverList( delegate: diff --git a/lib/pages/dynamics/widgets/action_panel.dart b/lib/pages/dynamics/widgets/action_panel.dart index 2c737f08..82bd096a 100644 --- a/lib/pages/dynamics/widgets/action_panel.dart +++ b/lib/pages/dynamics/widgets/action_panel.dart @@ -1,55 +1,118 @@ // 操作栏 import 'package:flutter/material.dart'; +import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:get/get.dart'; +import 'package:pilipala/http/dynamics.dart'; import 'package:pilipala/models/dynamics/result.dart'; import 'package:pilipala/pages/dynamics/index.dart'; -final DynamicsController _dynamicsController = Get.put(DynamicsController()); +class ActionPanel extends StatefulWidget { + ActionPanel({ + super.key, + this.item, + }); + var item; -Widget action(item, context) { - ModuleStatModel stat = item.modules.moduleStat; - - return Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - TextButton.icon( - onPressed: () {}, - icon: const Icon( - FontAwesomeIcons.shareFromSquare, - size: 16, - ), - style: TextButton.styleFrom( - padding: const EdgeInsets.fromLTRB(15, 0, 15, 0), - foregroundColor: Theme.of(context).colorScheme.outline, - ), - label: Text(stat.forward!.count ?? '转发'), - ), - TextButton.icon( - onPressed: () => - _dynamicsController.pushDetail(item, 1, action: 'comment'), - icon: const Icon( - FontAwesomeIcons.comment, - size: 16, - ), - style: TextButton.styleFrom( - padding: const EdgeInsets.fromLTRB(15, 0, 15, 0), - foregroundColor: Theme.of(context).colorScheme.outline, - ), - label: Text(stat.comment!.count ?? '评论'), - ), - TextButton.icon( - onPressed: () {}, - icon: const Icon( - FontAwesomeIcons.thumbsUp, - size: 16, - ), - style: TextButton.styleFrom( - padding: const EdgeInsets.fromLTRB(15, 0, 15, 0), - foregroundColor: Theme.of(context).colorScheme.outline, - ), - label: Text(stat.like!.count ?? '点赞'), - ) - ], - ); + @override + State createState() => _ActionPanelState(); +} + +class _ActionPanelState extends State { + final DynamicsController _dynamicsController = Get.put(DynamicsController()); + late ModuleStatModel stat; + + @override + void initState() { + super.initState(); + stat = widget.item!.modules.moduleStat; + } + + // 动态点赞 + onLikeDynamic() async { + var item = widget.item!; + String dynamicId = item.idStr!; + // 1 已点赞 2 不喜欢 0 未操作 + Like like = item.modules.moduleStat.like; + int count = int.parse(like.count!); + bool status = like.status!; + int up = status ? 2 : 1; + var res = await DynamicsHttp.likeDynamic(dynamicId: dynamicId, up: up); + if (res['status']) { + SmartDialog.showToast(!status ? '点赞成功' : '取消赞'); + if (up == 1) { + item.modules.moduleStat.like.count = (count + 1).toString(); + item.modules.moduleStat.like.status = true; + } else { + item.modules.moduleStat.like.count = (count - 1).toString(); + item.modules.moduleStat.like.status = false; + } + setState(() {}); + } else { + SmartDialog.showToast(res['msg']); + } + } + + @override + Widget build(BuildContext context) { + var color = Theme.of(context).colorScheme.outline; + var primary = Theme.of(context).colorScheme.primary; + return Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + TextButton.icon( + onPressed: () {}, + icon: const Icon( + FontAwesomeIcons.shareFromSquare, + size: 16, + ), + style: TextButton.styleFrom( + padding: const EdgeInsets.fromLTRB(15, 0, 15, 0), + foregroundColor: Theme.of(context).colorScheme.outline, + ), + label: Text(stat.forward!.count ?? '转发'), + ), + TextButton.icon( + onPressed: () => + _dynamicsController.pushDetail(widget.item, 1, action: 'comment'), + icon: const Icon( + FontAwesomeIcons.comment, + size: 16, + ), + style: TextButton.styleFrom( + padding: const EdgeInsets.fromLTRB(15, 0, 15, 0), + foregroundColor: Theme.of(context).colorScheme.outline, + ), + label: Text(stat.comment!.count ?? '评论'), + ), + TextButton.icon( + onPressed: () => onLikeDynamic(), + icon: Icon( + stat.like!.status! + ? FontAwesomeIcons.solidThumbsUp + : FontAwesomeIcons.thumbsUp, + size: 16, + color: stat.like!.status! ? primary : color, + ), + style: TextButton.styleFrom( + padding: const EdgeInsets.fromLTRB(15, 0, 15, 0), + foregroundColor: Theme.of(context).colorScheme.outline, + ), + label: AnimatedSwitcher( + duration: const Duration(milliseconds: 400), + transitionBuilder: (Widget child, Animation animation) { + return ScaleTransition(scale: animation, child: child); + }, + child: Text( + stat.like!.count ?? '点赞', + key: ValueKey(stat.like!.count!), + style: TextStyle( + color: stat.like!.status! ? primary : color, + ), + ), + ), + ) + ], + ); + } } diff --git a/lib/pages/dynamics/widgets/dynamic_panel.dart b/lib/pages/dynamics/widgets/dynamic_panel.dart index 5fa50afd..3dcf2315 100644 --- a/lib/pages/dynamics/widgets/dynamic_panel.dart +++ b/lib/pages/dynamics/widgets/dynamic_panel.dart @@ -42,7 +42,7 @@ class DynamicPanel extends StatelessWidget { content(item, context, source), forWard(item, context, _dynamicsController, source), const SizedBox(height: 2), - if (source == null) action(item, context), + if (source == null) ActionPanel(item: item), ], ), ), diff --git a/lib/pages/webview/controller.dart b/lib/pages/webview/controller.dart index 0186feb0..d9e555af 100644 --- a/lib/pages/webview/controller.dart +++ b/lib/pages/webview/controller.dart @@ -58,10 +58,13 @@ class WebviewController extends GetxController { try { var cookies = await WebviewCookieManager().getCookies(HttpString.baseUrl); - var apiCookies = - await WebviewCookieManager().getCookies(HttpString.baseUrl); + var apiCookies = await WebviewCookieManager() + .getCookies(HttpString.baseApiUrl); + var tCookies = + await WebviewCookieManager().getCookies(HttpString.tUrl); await SetCookie.onSet(cookies, HttpString.baseUrl); await SetCookie.onSet(apiCookies, HttpString.baseApiUrl); + await SetCookie.onSet(tCookies, HttpString.tUrl); await UserHttp.userInfo(); var result = await UserHttp.userInfo(); print('网页登录: $result');