From f6ebf0f67b6e24ac30aa77a46ecdb19c215458ef Mon Sep 17 00:00:00 2001 From: lucinhu <1543498474@qq.com> Date: Sat, 25 Mar 2023 00:34:15 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E8=A7=86=E9=A2=91?= =?UTF-8?q?=E6=8A=95=E5=B8=81&=E5=88=86=E4=BA=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/main.yml | 2 +- lib/common/api/video_info_api.dart | 4 +- lib/common/api/video_operation_api.dart | 73 +++++++++++++++---- .../local/video/click_add_coin_result.dart | 7 ++ .../local/video/click_add_share_result.dart | 11 +++ lib/common/models/local/video/video_info.dart | 10 ++- lib/common/utils/cookie_util.dart | 16 ++++ .../widgets/introduction/controller.dart | 60 +++++++++++++-- .../bili_video/widgets/introduction/view.dart | 17 +++-- macos/Flutter/GeneratedPluginRegistrant.swift | 2 + pubspec.lock | 24 ++++++ pubspec.yaml | 11 ++- .../flutter/generated_plugin_registrant.cc | 3 + windows/flutter/generated_plugins.cmake | 1 + 14 files changed, 207 insertions(+), 34 deletions(-) create mode 100644 lib/common/models/local/video/click_add_coin_result.dart create mode 100644 lib/common/models/local/video/click_add_share_result.dart create mode 100644 lib/common/utils/cookie_util.dart diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 6542b1d2..8f2ada50 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -32,7 +32,7 @@ jobs: - name: Flutter action uses: subosito/flutter-action@v2 with: - flutter-version: 3.9.0-12.0.pre.18 + flutter-version: 3.9.0-17.0.pre.6 channel: master - name: Decode keystore diff --git a/lib/common/api/video_info_api.dart b/lib/common/api/video_info_api.dart index f85b2f5c..6ebc1fc8 100644 --- a/lib/common/api/video_info_api.dart +++ b/lib/common/api/video_info_api.dart @@ -59,7 +59,9 @@ class VideoInfoApi { ownerMid: response.data!.owner?.mid ?? 0, ownerName: response.data!.owner?.name ?? "", parts: parts, - hasLike: await VideoOperationApi.hasLike(bvid: bvid)); + hasLike: await VideoOperationApi.hasLike(bvid: bvid), + hasAddCoin: await VideoOperationApi.hasAddCoin(bvid: bvid), + hasFavourite: await VideoOperationApi.hasFavourite(bvid: bvid)); } static Future _requestVideoParts( diff --git a/lib/common/api/video_operation_api.dart b/lib/common/api/video_operation_api.dart index 5819b577..3902f124 100644 --- a/lib/common/api/video_operation_api.dart +++ b/lib/common/api/video_operation_api.dart @@ -1,5 +1,8 @@ import 'package:bili_you/common/api/index.dart'; +import 'package:bili_you/common/models/local/video/click_add_coin_result.dart'; +import 'package:bili_you/common/models/local/video/click_add_share_result.dart'; import 'package:bili_you/common/models/local/video/click_like_result.dart'; +import 'package:bili_you/common/utils/cookie_util.dart'; import 'package:bili_you/common/utils/index.dart'; import 'package:dio/dio.dart'; @@ -11,20 +14,11 @@ class VideoOperationApi { //点赞还是取消赞 required bool likeOrCancelLike, }) async { - String csrf = ""; - //从cookie中获取csrf需要的数据 - for (var i in (await MyDio.cookieManager.cookieJar - .loadForRequest(Uri.parse(ApiConstants.bilibiliBase)))) { - if (i.name == 'bili_jct') { - csrf = i.value; - break; - } - } var response = await MyDio.dio.post(ApiConstants.like, queryParameters: { 'bvid': bvid, 'like': likeOrCancelLike ? 1 : 2, - 'csrf': csrf + 'csrf': await CookieUtils.getCsrf() }, options: Options(responseType: ResponseType.json)); return ClickLikeResult( @@ -38,9 +32,62 @@ class VideoOperationApi { ///true已点赞 ///false未点赞 static Future hasLike({required String bvid}) async { - var response = await MyDio.dio.get(ApiConstants.hasLike, - queryParameters: {'bvid': bvid}, - options: Options(responseType: ResponseType.json)); + var response = await MyDio.dio.get( + ApiConstants.hasLike, + queryParameters: {'bvid': bvid}, + ); return response.data['data'] == 1; } + + ///判断是否已投币 + static Future hasAddCoin({required String bvid}) async { + var response = await MyDio.dio + .get(ApiConstants.hasAddCoin, queryParameters: {'bvid': bvid}); + return (response.data?['data']?['multiply'] ?? 0) > 0; + } + + ///投币 + static Future addCoin( + {required String bvid, int? num}) async { + var response = await MyDio.dio.post(ApiConstants.addCoin, queryParameters: { + 'bvid': bvid, + 'multiply': num ?? 1, + 'csrf': await CookieUtils.getCsrf() + }); + if (response.data['code'] == 0) { + return ClickAddCoinResult(isSuccess: true, error: ''); + } else { + return ClickAddCoinResult( + isSuccess: false, error: response.data['message']); + } + } + + ///判断是否已收藏 + static Future hasFavourite({required String bvid}) async { + var response = await MyDio.dio + .get(ApiConstants.hasFavourite, queryParameters: {'bvid': bvid}); + return response.data?['data']?['favoured'] == true; + } + + ///收藏 + // static Future<> addFavourite({required String rid}) async{ + + // } + + ///分享 + static Future share({required String bvid}) async { + var response = await MyDio.dio.post(ApiConstants.share, + queryParameters: {'bvid': bvid, 'csrf': await CookieUtils.getCsrf()}); + if (response.data['code'] == 0) { + return ClickAddShareResult( + isSuccess: true, + error: '', + currentShareNum: response.data['data'] ?? 0); + } else { + return ClickAddShareResult( + isSuccess: false, + error: response.data['message'], + currentShareNum: response.data['data'] ?? 0); + } + } } diff --git a/lib/common/models/local/video/click_add_coin_result.dart b/lib/common/models/local/video/click_add_coin_result.dart new file mode 100644 index 00000000..455e08d5 --- /dev/null +++ b/lib/common/models/local/video/click_add_coin_result.dart @@ -0,0 +1,7 @@ +class ClickAddCoinResult { + ClickAddCoinResult({required this.isSuccess, required this.error}); + static ClickAddCoinResult get zero => + ClickAddCoinResult(isSuccess: false, error: ''); + bool isSuccess; + String error; +} diff --git a/lib/common/models/local/video/click_add_share_result.dart b/lib/common/models/local/video/click_add_share_result.dart new file mode 100644 index 00000000..54ded215 --- /dev/null +++ b/lib/common/models/local/video/click_add_share_result.dart @@ -0,0 +1,11 @@ +class ClickAddShareResult { + ClickAddShareResult( + {required this.isSuccess, + required this.error, + required this.currentShareNum}); + static ClickAddShareResult get zero => + ClickAddShareResult(isSuccess: false, error: '', currentShareNum: 0); + bool isSuccess; + String error; + int currentShareNum; +} diff --git a/lib/common/models/local/video/video_info.dart b/lib/common/models/local/video/video_info.dart index 49002c91..d5118e93 100644 --- a/lib/common/models/local/video/video_info.dart +++ b/lib/common/models/local/video/video_info.dart @@ -18,7 +18,9 @@ class VideoInfo { required this.ownerMid, required this.ownerName, required this.parts, - required this.hasLike}); + required this.hasLike, + required this.hasAddCoin, + required this.hasFavourite}); static VideoInfo get zero => VideoInfo( title: "", describe: "", @@ -36,7 +38,9 @@ class VideoInfo { ownerMid: 0, ownerName: "", parts: [], - hasLike: false); + hasLike: false, + hasAddCoin: false, + hasFavourite: false); String title; String describe; String bvid; @@ -54,4 +58,6 @@ class VideoInfo { int ownerMid; List parts; bool hasLike; + bool hasAddCoin; + bool hasFavourite; } diff --git a/lib/common/utils/cookie_util.dart b/lib/common/utils/cookie_util.dart new file mode 100644 index 00000000..d784f388 --- /dev/null +++ b/lib/common/utils/cookie_util.dart @@ -0,0 +1,16 @@ +import 'package:bili_you/common/api/api_constants.dart'; + +import 'my_dio.dart'; + +class CookieUtils { + static Future getCsrf() async { +//从cookie中获取csrf需要的数据 + for (var i in (await MyDio.cookieManager.cookieJar + .loadForRequest(Uri.parse(ApiConstants.bilibiliBase)))) { + if (i.name == 'bili_jct') { + return i.value; + } + } + return ''; + } +} diff --git a/lib/pages/bili_video/widgets/introduction/controller.dart b/lib/pages/bili_video/widgets/introduction/controller.dart index 04e37a33..467a8efb 100644 --- a/lib/pages/bili_video/widgets/introduction/controller.dart +++ b/lib/pages/bili_video/widgets/introduction/controller.dart @@ -1,10 +1,11 @@ import 'dart:developer'; -import 'package:bili_you/common/api/bangumi_api.dart'; -import 'package:bili_you/common/api/related_video_api.dart'; -import 'package:bili_you/common/api/video_info_api.dart'; +import 'package:bili_you/common/api/index.dart'; import 'package:bili_you/common/api/video_operation_api.dart'; import 'package:bili_you/common/models/local/related_video/related_video_info.dart'; +import 'package:bili_you/common/models/local/video/click_add_coin_result.dart'; +import 'package:bili_you/common/models/local/video/click_add_share_result.dart'; +import 'package:bili_you/common/models/local/video/click_like_result.dart'; import 'package:bili_you/common/models/local/video/video_info.dart'; import 'package:bili_you/common/utils/string_format_utils.dart'; import 'package:bili_you/common/values/cache_keys.dart'; @@ -13,6 +14,7 @@ import 'package:bili_you/pages/bili_video/view.dart'; import 'package:flutter/material.dart'; import 'package:flutter_cache_manager/flutter_cache_manager.dart'; import 'package:get/get.dart'; +import 'package:share_plus/share_plus.dart'; class IntroductionController extends GetxController { IntroductionController( @@ -150,8 +152,18 @@ class IntroductionController extends GetxController { ///点赞按钮点击时 Future onLikePressed() async { - var result = await VideoOperationApi.clickLike( - bvid: videoInfo.bvid, likeOrCancelLike: !videoInfo.hasLike); + late ClickLikeResult result; + try { + result = await VideoOperationApi.clickLike( + bvid: videoInfo.bvid, likeOrCancelLike: !videoInfo.hasLike); + } catch (e) { + Get.showSnackbar(GetSnackBar( + message: "失败:${result.error}", + duration: const Duration(milliseconds: 1000), + )); + return; + } + if (result.isSuccess) { videoInfo.hasLike = result.haslike; if (result.haslike) { @@ -175,6 +187,44 @@ class IntroductionController extends GetxController { // )); } + Future onAddCoinPressed() async { + late ClickAddCoinResult result; + try { + result = await VideoOperationApi.addCoin(bvid: bvid); + if (result.isSuccess) { + videoInfo.hasAddCoin = result.isSuccess; + videoInfo.coinNum++; + refreshOperationButton!.call(); + } else { + Get.showSnackbar(GetSnackBar( + message: "失败:${result.error}", + duration: const Duration(milliseconds: 1000), + )); + } + } catch (e) { + log('onAddCoinPressed$e'); + Get.showSnackbar(GetSnackBar( + message: "失败:${result.error}", + duration: const Duration(milliseconds: 1000), + )); + } + } + + Future onAddSharePressed() async { + try { + ClickAddShareResult result = await VideoOperationApi.share(bvid: bvid); + if (result.isSuccess) { + Share.share('${ApiConstants.bilibiliBase}/video/$bvid'); + videoInfo.shareNum = result.currentShareNum; + } else { + Get.rawSnackbar(message: '分享失败:${result.error}'); + } + } catch (e) { + Get.rawSnackbar(message: '分享失败:$e'); + } + refreshOperationButton!.call(); + } + // @override // void onInit() { // super.onInit(); diff --git a/lib/pages/bili_video/widgets/introduction/view.dart b/lib/pages/bili_video/widgets/introduction/view.dart index b1ea2b07..949e2b1c 100644 --- a/lib/pages/bili_video/widgets/introduction/view.dart +++ b/lib/pages/bili_video/widgets/introduction/view.dart @@ -204,18 +204,19 @@ class _IntroductionPageState extends State width: buttonWidth, height: buttonHeight, child: IconTextButton( - icon: const Icon(Icons.circle_rounded), - text: Text( - StringFormatUtils.numFormat( - controller.videoInfo.coinNum), - style: operationButtonTextStyle), - onPressed: () {}, - )), + selected: controller.videoInfo.hasAddCoin, + icon: const Icon(Icons.circle_rounded), + text: Text( + StringFormatUtils.numFormat( + controller.videoInfo.coinNum), + style: operationButtonTextStyle), + onPressed: controller.onAddCoinPressed)), const Spacer(), SizedBox( width: buttonWidth, height: buttonHeight, child: IconTextButton( + selected: controller.videoInfo.hasFavourite, icon: const Icon(Icons.star_rounded), text: Text( StringFormatUtils.numFormat( @@ -233,7 +234,7 @@ class _IntroductionPageState extends State StringFormatUtils.numFormat( controller.videoInfo.shareNum), style: operationButtonTextStyle), - onPressed: () {}, + onPressed: controller.onAddSharePressed, )), const Spacer(), ], diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 82ed5756..5b5aa32e 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -9,6 +9,7 @@ import device_info_plus import dynamic_color import package_info_plus import path_provider_foundation +import share_plus import sqflite import url_launcher_macos import wakelock_macos @@ -18,6 +19,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { DynamicColorPlugin.register(with: registry.registrar(forPlugin: "DynamicColorPlugin")) FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) + SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin")) SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) WakelockMacosPlugin.register(with: registry.registrar(forPlugin: "WakelockMacosPlugin")) diff --git a/pubspec.lock b/pubspec.lock index 2cea2b5f..8604ef2e 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -217,6 +217,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.6.3" + cross_file: + dependency: transitive + description: + name: cross_file + sha256: "0b0036e8cccbfbe0555fd83c1d31a6f30b77a96b598b35a5d36dd41f718695e9" + url: "https://pub.dev" + source: hosted + version: "0.3.3+4" crypto: dependency: transitive description: @@ -761,6 +769,22 @@ packages: url: "https://pub.dev" source: hosted version: "0.27.7" + share_plus: + dependency: "direct main" + description: + name: share_plus + sha256: "8c6892037b1824e2d7e8f59d54b3105932899008642e6372e5079c6939b4b625" + url: "https://pub.dev" + source: hosted + version: "6.3.1" + share_plus_platform_interface: + dependency: transitive + description: + name: share_plus_platform_interface + sha256: "82ddd4ab9260c295e6e39612d4ff00390b9a7a21f1bb1da771e2f232d80ab8a1" + url: "https://pub.dev" + source: hosted + version: "3.2.0" shelf: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 39ab9fdf..2e1a98d8 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -17,7 +17,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.6 +version: 1.0.7 environment: sdk: '>=2.19.0-444.2<4.0.0' @@ -65,8 +65,11 @@ dependencies: git: url: https://github.com/xiaoyaocz/flutter_ns_danmaku.git cached_network_image: ^3.2.3 + photo_view: ^0.14.0 # webview + webview_cookie_manager: ^2.0.6 + webview_flutter: ^4.0.7 # 保持常亮 wakelock: ^0.6.2 @@ -81,9 +84,9 @@ dependencies: # hive hive: ^2.2.3 hive_flutter: ^1.1.0 - webview_cookie_manager: ^2.0.6 - webview_flutter: ^4.0.7 - photo_view: ^0.14.0 + + # 分享 + share_plus: ^6.3.1 diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 5ec53c0b..1a40a844 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -7,11 +7,14 @@ #include "generated_plugin_registrant.h" #include +#include #include void RegisterPlugins(flutter::PluginRegistry* registry) { DynamicColorPluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("DynamicColorPluginCApi")); + SharePlusWindowsPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("SharePlusWindowsPluginCApi")); UrlLauncherWindowsRegisterWithRegistrar( registry->GetRegistrarForPlugin("UrlLauncherWindows")); } diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index a311f667..9feb0426 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -4,6 +4,7 @@ list(APPEND FLUTTER_PLUGIN_LIST dynamic_color + share_plus url_launcher_windows )