From 598a293a09560e20d7df384723a76f1b38e9b97f Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sat, 13 May 2023 23:49:39 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=B8=80=E9=94=AE=E4=B8=89=E8=BF=9E?= =?UTF-8?q?=E3=80=81=E8=A7=86=E9=A2=91=E9=A1=B5(=E5=8F=96=E6=B6=88)?= =?UTF-8?q?=E6=94=B6=E8=97=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/images/logo/logo_big.png | Bin 0 -> 45678 bytes lib/common/widgets/video_card_h.dart | 9 +- lib/http/api.dart | 16 +- lib/http/init.dart | 3 +- lib/http/video.dart | 51 +++- lib/models/user/fav_folder.dart | 2 +- lib/pages/favDetail/view.dart | 38 ++- lib/pages/home/controller.dart | 1 - lib/pages/media/view.dart | 187 +++++++------ lib/pages/mine/controller.dart | 3 + lib/pages/mine/view.dart | 1 + .../video/detail/introduction/controller.dart | 115 +++++++- lib/pages/video/detail/introduction/view.dart | 262 ++++++++++-------- lib/pages/video/detail/view.dart | 20 +- lib/pages/webview/controller.dart | 10 +- pubspec.yaml | 1 + 16 files changed, 449 insertions(+), 270 deletions(-) create mode 100644 assets/images/logo/logo_big.png diff --git a/assets/images/logo/logo_big.png b/assets/images/logo/logo_big.png new file mode 100644 index 0000000000000000000000000000000000000000..62370832a6acde823990724fe3bf1dc7370d4c59 GIT binary patch literal 45678 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 literal 0 HcmV?d00001 diff --git a/lib/common/widgets/video_card_h.dart b/lib/common/widgets/video_card_h.dart index fd3c289c..1217e700 100644 --- a/lib/common/widgets/video_card_h.dart +++ b/lib/common/widgets/video_card_h.dart @@ -1,13 +1,13 @@ import 'package:get/get.dart'; import 'package:flutter/material.dart'; import 'package:pilipala/common/constants.dart'; -import 'package:pilipala/common/widgets/stat/up.dart'; import 'package:pilipala/common/widgets/stat/view.dart'; import 'package:pilipala/utils/utils.dart'; import 'package:pilipala/common/widgets/network_img_layer.dart'; // 视频卡片 - 水平布局 class VideoCardH extends StatelessWidget { + // ignore: prefer_typing_uninitialized_variables var videoItem; VideoCardH({Key? key, required this.videoItem}) : super(key: key); @@ -138,13 +138,6 @@ class VideoContent extends StatelessWidget { const SizedBox(height: 4), Row( children: [ - // Image.asset( - // 'assets/images/up_gray.png', - // width: 14, - // height: 12, - // ), - const UpTag(), - const SizedBox(width: 2), Text( videoItem.owner.name, style: TextStyle( diff --git a/lib/http/api.dart b/lib/http/api.dart index b056b7cd..94efb69a 100644 --- a/lib/http/api.dart +++ b/lib/http/api.dart @@ -55,7 +55,7 @@ class Api { // csrf str CSRF Token(位于cookie) Cookie方式必要 // https://api.bilibili.com/medialist/gateway/coll/resource/deal // https://api.bilibili.com/x/v3/fav/resource/deal - static const String favVideo = '/medialist/gateway/coll/resource/deal'; + static const String favVideo = '/x/v3/fav/resource/deal'; // 判断视频是否被收藏(双端)GET /// aid @@ -68,6 +68,20 @@ class Api { // bvid str 稿件bvid 必要(可选) avid与bvid任选一个 // csrf str CSRF Token(位于cookie) 必要 + // 一键三连 + // https://api.bilibili.com/x/web-interface/archive/like/triple + // aid num 稿件avid 必要(可选) avid与bvid任选一个 + // bvid str 稿件bvid 必要(可选) avid与bvid任选一个 + // csrf str CSRF Token(位于cookie) 必要 + static const String oneThree = '/x/web-interface/archive/like/triple'; + + // 获取指定用户创建的所有收藏夹信息 + // 该接口也能查询目标内容id存在于那些收藏夹中 + // up_mid num 目标用户mid 必要 + // type num 目标内容属性 非必要 默认为全部 0:全部 2:视频稿件 + // rid num 目标 视频稿件avid + static const String videoInFolder = '/x/v3/fav/folder/created/list-all'; + // 视频详情页 相关视频 static const String relatedList = '/x/web-interface/archive/related'; diff --git a/lib/http/init.dart b/lib/http/init.dart index eca0a6d4..240251dd 100644 --- a/lib/http/init.dart +++ b/lib/http/init.dart @@ -138,13 +138,14 @@ class Request { /* * post请求 */ - post(url, {data, options, cancelToken, extra}) async { + post(url, {data, queryParameters, options, cancelToken, extra}) async { print('post-data: $data'); Response response; try { response = await dio.post( url, data: data, + queryParameters: queryParameters, options: options, cancelToken: cancelToken, ); diff --git a/lib/http/video.dart b/lib/http/video.dart index 002bff22..d01f6889 100644 --- a/lib/http/video.dart +++ b/lib/http/video.dart @@ -2,6 +2,7 @@ import 'package:pilipala/http/api.dart'; import 'package:pilipala/http/init.dart'; import 'package:pilipala/models/model_hot_video_item.dart'; import 'package:pilipala/models/model_rec_video_item.dart'; +import 'package:pilipala/models/user/fav_folder.dart'; import 'package:pilipala/models/video_detail_res.dart'; /// res.data['code'] == 0 请求正常返回结果 @@ -122,11 +123,26 @@ class VideoHttp { } // 一键三连 + static Future oneThree({required String aid}) async { + var res = await Request().post( + Api.oneThree, + queryParameters: { + 'aid': aid, + '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']}; + } + } + // (取消)点赞 static Future likeVideo({required String aid, required bool type}) async { var res = await Request().post( Api.likeVideo, - data: { + queryParameters: { 'aid': aid, 'like': type ? 1 : 2, 'csrf': await Request.getCsrf(), @@ -141,20 +157,33 @@ class VideoHttp { // (取消)收藏 static Future favVideo( - {required String aid, required bool type, required String ids}) async { - Map data = {'rid': aid, 'type': 2}; - // type true 添加收藏 false 取消收藏 - if (type) { - data['add_media_ids'] = ids; - } else { - data['del_media_ids'] = ids; - } - var res = await Request() - .post(Api.favVideo, data: {'aid': aid, 'like': type ? 1 : 2}); + {required String aid, + required bool type, + required String addIds, + required String delIds}) async { + var res = await Request().post(Api.favVideo, queryParameters: { + 'rid': aid, + 'type': 2, + 'add_media_ids': addIds, + 'del_media_ids': delIds, + 'csrf': await Request.getCsrf(), + }); if (res.data['code'] == 0) { return {'status': true, 'data': res.data['data']}; } else { return {'status': false, 'data': []}; } } + + // 查看视频被收藏在哪个文件夹 + static Future videoInFolder({required int mid, required String rid}) async { + var res = await Request() + .get(Api.videoInFolder, data: {'up_mid': mid, 'rid': rid}); + if (res.data['code'] == 0) { + FavFolderData data = FavFolderData.fromJson(res.data['data']); + return {'status': true, 'data': data}; + } else { + return {'status': false, 'data': []}; + } + } } diff --git a/lib/models/user/fav_folder.dart b/lib/models/user/fav_folder.dart index 0e0e61eb..6d3f9975 100644 --- a/lib/models/user/fav_folder.dart +++ b/lib/models/user/fav_folder.dart @@ -72,7 +72,7 @@ class FavFolderItemData { attr = json['attr']; title = json['title']; cover = json['cover']; - upper = Upper.fromJson(json['upper']); + upper = json['upper'] != null ? Upper.fromJson(json['upper']) : Upper(); coverType = json['cover_type']; intro = json['intro']; ctime = json['ctime']; diff --git a/lib/pages/favDetail/view.dart b/lib/pages/favDetail/view.dart index 1fb48886..e637c6d5 100644 --- a/lib/pages/favDetail/view.dart +++ b/lib/pages/favDetail/view.dart @@ -167,18 +167,27 @@ class _FavDetailPageState extends State { if (snapshot.connectionState == ConnectionState.done) { Map data = snapshot.data; if (data['status']) { - return Obx( - () => SliverList( - delegate: SliverChildBuilderDelegate((context, index) { - return FavVideoCardH( - videoItem: _favDetailController - .favDetailData.value.medias![index], - ); - }, - childCount: _favDetailController - .favDetailData.value.medias!.length), - ), - ); + if (_favDetailController.item!.mediaCount == 0) { + return const SliverToBoxAdapter( + child: SizedBox( + height: 300, + child: Center(child: Text('没有内容')), + ), + ); + } else { + return Obx( + () => SliverList( + delegate: SliverChildBuilderDelegate((context, index) { + return FavVideoCardH( + videoItem: _favDetailController + .favDetailData.value.medias![index], + ); + }, + childCount: _favDetailController + .favDetailData.value.medias!.length), + ), + ); + } } else { return HttpError( errMsg: data['msg'], @@ -187,8 +196,9 @@ class _FavDetailPageState extends State { } } else { return const SliverToBoxAdapter( - child: Center( - child: Text('加载中'), + child: SizedBox( + height: 300, + child: Center(child: Text('加载中')), ), ); } diff --git a/lib/pages/home/controller.dart b/lib/pages/home/controller.dart index c5606c79..7182b134 100644 --- a/lib/pages/home/controller.dart +++ b/lib/pages/home/controller.dart @@ -25,7 +25,6 @@ class HomeController extends GetxController { freshIdx: _currentPage, ); if (res['status']) { - print('type: $type'); if (type == 'init') { videoList.value = res['data']; } else if (type == 'onRefresh') { diff --git a/lib/pages/media/view.dart b/lib/pages/media/view.dart index 6557000c..a18b1e3d 100644 --- a/lib/pages/media/view.dart +++ b/lib/pages/media/view.dart @@ -122,43 +122,56 @@ class _MediaPageState extends State SizedBox( width: double.infinity, height: 170, - child: ListView( - scrollDirection: Axis.horizontal, - children: [ - const SizedBox(width: 20), - FutureBuilder( - future: _futureBuilderFuture, - builder: (context, snapshot) { - if (snapshot.connectionState == ConnectionState.done) { - Map data = snapshot.data; - if (data['status']) { - return Obx(() => Row( - children: [ - if (_mediaController.favFolderData.value.list != - null) ...[ - for (FavFolderItemData i in _mediaController - .favFolderData.value.list!) ...[ - FavFolderItem(item: i), - const SizedBox(width: 14) - ] - ] - ], - )); - } else { - return SizedBox( - height: 160, - child: Center(child: Text(data['msg'])), - ); - } - } else { - // 骨架屏 - return SizedBox(); - } - }), - // for (var i in [1, 2, 3]) ...[const FavFolderItem()], - const SizedBox(width: 10) - ], - ), + child: FutureBuilder( + future: _futureBuilderFuture, + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.done) { + Map data = snapshot.data; + if (data['status']) { + List favFolderList = + _mediaController.favFolderData.value.list!; + int favFolderCount = + _mediaController.favFolderData.value.count!; + bool flag = favFolderCount > favFolderList.length; + return Obx(() => ListView.builder( + itemCount: _mediaController + .favFolderData.value.list!.length + + (flag ? 1 : 0), + itemBuilder: (context, index) { + if (flag && index == favFolderList.length) { + return Padding( + padding: const EdgeInsets.only( + right: 14, bottom: 35), + child: Center( + child: IconButton( + onPressed: () => Get.toNamed('/fav'), + icon: Icon( + Icons.arrow_forward_ios, + size: 18, + color: Theme.of(context).primaryColor, + ), + ), + )); + } else { + return FavFolderItem( + item: _mediaController + .favFolderData.value.list![index], + index: index); + } + }, + scrollDirection: Axis.horizontal, + )); + } else { + return SizedBox( + height: 160, + child: Center(child: Text(data['msg'])), + ); + } + } else { + // 骨架屏 + return SizedBox(); + } + }), ), ], ); @@ -166,59 +179,63 @@ class _MediaPageState extends State } class FavFolderItem extends StatelessWidget { - FavFolderItem({super.key, this.item}); + FavFolderItem({super.key, this.item, this.index}); FavFolderItemData? item; + int? index; @override Widget build(BuildContext context) { - return GestureDetector( - onTap: () => Get.toNamed('/favDetail', arguments: item, parameters: { - 'mediaId': item!.id.toString(), - }), - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const SizedBox(height: 12), - Container( - width: 180, - height: 110, - margin: const EdgeInsets.only(bottom: 8), - clipBehavior: Clip.hardEdge, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(12), - color: Theme.of(context).colorScheme.onInverseSurface, - boxShadow: [ - BoxShadow( - color: Theme.of(context).colorScheme.onInverseSurface, - offset: const Offset(4, -12), // 阴影与容器的距离 - blurRadius: 0.0, // 高斯的标准偏差与盒子的形状卷积。 - spreadRadius: 0.0, // 在应用模糊之前,框应该膨胀的量。 - ), - ], + return Container( + margin: EdgeInsets.only(left: index == 0 ? 20 : 0, right: 14), + child: GestureDetector( + onTap: () => Get.toNamed('/favDetail', arguments: item, parameters: { + 'mediaId': item!.id.toString(), + }), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 12), + Container( + width: 180, + height: 110, + margin: const EdgeInsets.only(bottom: 8), + clipBehavior: Clip.hardEdge, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12), + color: Theme.of(context).colorScheme.onInverseSurface, + boxShadow: [ + BoxShadow( + color: Theme.of(context).colorScheme.onInverseSurface, + offset: const Offset(4, -12), // 阴影与容器的距离 + blurRadius: 0.0, // 高斯的标准偏差与盒子的形状卷积。 + spreadRadius: 0.0, // 在应用模糊之前,框应该膨胀的量。 + ), + ], + ), + child: LayoutBuilder( + builder: (context, BoxConstraints box) { + return NetworkImgLayer( + src: item!.cover, + width: box.maxWidth, + height: box.maxHeight, + ); + }, + ), ), - child: LayoutBuilder( - builder: (context, BoxConstraints box) { - return NetworkImgLayer( - src: item!.cover, - width: box.maxWidth, - height: box.maxHeight, - ); - }, + Text( + ' ${item!.title}', + overflow: TextOverflow.fade, + maxLines: 1, ), - ), - Text( - ' ${item!.title}', - overflow: TextOverflow.fade, - maxLines: 1, - ), - Text( - ' 共${item!.mediaCount}条视频', - style: Theme.of(context) - .textTheme - .labelSmall! - .copyWith(color: Theme.of(context).colorScheme.outline), - ) - ], + Text( + ' 共${item!.mediaCount}条视频', + style: Theme.of(context) + .textTheme + .labelSmall! + .copyWith(color: Theme.of(context).colorScheme.outline), + ) + ], + ), ), ); } diff --git a/lib/pages/mine/controller.dart b/lib/pages/mine/controller.dart index 93b0d1d0..db73fd6f 100644 --- a/lib/pages/mine/controller.dart +++ b/lib/pages/mine/controller.dart @@ -27,6 +27,9 @@ class MineController extends GetxController { } Future queryUserInfo() async { + if (user.get(UserBoxKey.userLogin) == null) { + return {'status': false}; + } var res = await UserHttp.userInfo(); if (res['status']) { if (res['data'].isLogin) { diff --git a/lib/pages/mine/view.dart b/lib/pages/mine/view.dart index 85e43ad0..e0a72d96 100644 --- a/lib/pages/mine/view.dart +++ b/lib/pages/mine/view.dart @@ -64,6 +64,7 @@ class _MinePageState extends State { future: _mineController.queryUserInfo(), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.done) { + print(snapshot.data); if (snapshot.data['status']) { return Obx(() => userInfoBuild()); } else { diff --git a/lib/pages/video/detail/introduction/controller.dart b/lib/pages/video/detail/introduction/controller.dart index c7e7b831..71616423 100644 --- a/lib/pages/video/detail/introduction/controller.dart +++ b/lib/pages/video/detail/introduction/controller.dart @@ -1,10 +1,13 @@ 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'; import 'package:pilipala/http/video.dart'; +import 'package:pilipala/models/user/fav_folder.dart'; import 'package:pilipala/models/video_detail_res.dart'; import 'package:pilipala/pages/video/detail/controller.dart'; +import 'package:pilipala/utils/storage.dart'; class VideoIntroController extends GetxController { // 视频aid @@ -34,6 +37,11 @@ class VideoIntroController extends GetxController { RxBool hasCoin = false.obs; // 是否收藏 RxBool hasFav = false.obs; + Box user = GStrorage.user; + bool userLogin = false; + Rx favFolderData = FavFolderData().obs; + List addMediaIdsNew = []; + List delMediaIdsNew = []; @override void onInit() { @@ -51,6 +59,7 @@ class VideoIntroController extends GetxController { videoItem!['owner'] = args.owner; } } + userLogin = user.get(UserBoxKey.userLogin) != null; } // 获取视频简介 @@ -66,12 +75,14 @@ class VideoIntroController extends GetxController { } // 获取到粉丝数再返回 await queryUserStat(); - // 获取点赞状态 - queryHasLikeVideo(); - // 获取投币状态 - queryHasCoinVideo(); - // 获取收藏状态 - queryHasFavVideo(); + if (userLogin) { + // 获取点赞状态 + queryHasLikeVideo(); + // 获取投币状态 + queryHasCoinVideo(); + // 获取收藏状态 + queryHasFavVideo(); + } return result; } @@ -104,12 +115,54 @@ class VideoIntroController extends GetxController { } // 一键三连 + Future actionOneThree() async { + if (hasLike.value && hasCoin.value && hasFav.value) { + // 已点赞、投币、收藏 + SmartDialog.showToast('🙏 UP已经收到了~'); + return false; + } + SmartDialog.show( + useSystem: true, + animationType: SmartAnimationType.centerFade_otherSlide, + builder: (BuildContext context) { + return AlertDialog( + title: const Text('提示'), + content: const Text('一键三连 给UP送温暖'), + actions: [ + TextButton( + onPressed: () => SmartDialog.dismiss(), + child: const Text('点错了')), + TextButton( + onPressed: () async { + var result = await VideoHttp.oneThree(aid: aid); + if (result['status']) { + hasLike.value = result["data"]["like"]; + hasCoin.value = result["data"]["coin"]; + hasFav.value = result["data"]["fav"]; + SmartDialog.showToast('三连成功 🎉'); + } else { + SmartDialog.showToast(result['msg']); + } + SmartDialog.dismiss(); + }, + child: const Text('确认'), + ) + ], + ); + }, + ); + } // (取消)点赞 Future actionLikeVideo() async { var result = await VideoHttp.likeVideo(aid: aid, type: !hasLike.value); if (result['status']) { hasLike.value = result["data"] == 1 ? true : false; + if (hasLike.value) { + SmartDialog.showToast('已点赞 👍'); + } else { + SmartDialog.showToast('取消赞'); + } } else { SmartDialog.showToast(result['msg']); } @@ -122,12 +175,58 @@ class VideoIntroController extends GetxController { // (取消)收藏 Future actionFavVideo() async { - print('(取消)收藏'); - // var result = await VideoHttp.favVideo(aid: aid, type: true, ids: ''); + try { + for (var i in favFolderData.value.list!.toList()) { + if (i.favState == 1) { + addMediaIdsNew.add(i.id); + } else { + delMediaIdsNew.add(i.id); + } + } + } catch (e) {} + var result = await VideoHttp.favVideo( + aid: aid, + type: true, + addIds: addMediaIdsNew.join(','), + delIds: delMediaIdsNew.join(',')); + if (result['status']) { + if (result['data']['prompt']) { + addMediaIdsNew = []; + delMediaIdsNew = []; + Get.back(); + // 重新获取收藏状态 + queryHasFavVideo(); + SmartDialog.showToast('✅ 操作成功'); + } + } } // 分享视频 Future actionShareVideo() async { print('分享视频'); } + + Future queryVideoInFolder() async { + var result = await VideoHttp.videoInFolder( + mid: user.get(UserBoxKey.userMid), rid: aid); + if (result['status']) { + favFolderData.value = result['data']; + } + return result; + } + + // 选择文件夹 + onChoose(bool checkValue, int index) { + List datalist = favFolderData.value.list!; + for (var i = 0; i < datalist.length; i++) { + if (i == index) { + datalist[i].favState = checkValue == true ? 1 : 0; + datalist[i].mediaCount = checkValue == true + ? datalist[i].mediaCount! + 1 + : datalist[i].mediaCount! - 1; + } + } + favFolderData.value.list = datalist; + favFolderData.refresh(); + } } diff --git a/lib/pages/video/detail/introduction/view.dart b/lib/pages/video/detail/introduction/view.dart index f9027cee..843126ed 100644 --- a/lib/pages/video/detail/introduction/view.dart +++ b/lib/pages/video/detail/introduction/view.dart @@ -54,10 +54,7 @@ class _VideoIntroPanelState extends State if (snapshot.data['status']) { // 请求成功 // return _buildView(context, false, videoDetail); - return VideoInfo( - loadingStatus: false, - videoDetail: videoDetail, - videoIntroController: videoIntroController); + return VideoInfo(loadingStatus: false, videoDetail: videoDetail); } else { // 请求错误 return HttpError( @@ -66,10 +63,7 @@ class _VideoIntroPanelState extends State ); } } else { - return VideoInfo( - loadingStatus: true, - videoDetail: videoDetail, - videoIntroController: videoIntroController); + return VideoInfo(loadingStatus: true, videoDetail: videoDetail); } }, ); @@ -79,13 +73,8 @@ class _VideoIntroPanelState extends State class VideoInfo extends StatefulWidget { bool loadingStatus = false; VideoDetailData? videoDetail; - VideoIntroController? videoIntroController; - VideoInfo( - {Key? key, - required this.loadingStatus, - this.videoDetail, - this.videoIntroController}) + VideoInfo({Key? key, required this.loadingStatus, this.videoDetail}) : super(key: key); @override @@ -94,6 +83,8 @@ class VideoInfo extends StatefulWidget { class _VideoInfoState extends State with TickerProviderStateMixin { Map videoItem = Get.put(VideoIntroController()).videoItem!; + final VideoIntroController videoIntroController = + Get.put(VideoIntroController(), tag: Get.arguments['heroTag']); bool isExpand = false; /// 手动控制动画的控制器 @@ -137,7 +128,7 @@ class _VideoInfoState extends State with TickerProviderStateMixin { ), actions: [ TextButton( - onPressed: () => Get.back(), + onPressed: () => videoIntroController.actionFavVideo(), child: const Text('完成'), ), const SizedBox(width: 6), @@ -146,30 +137,34 @@ class _VideoInfoState extends State with TickerProviderStateMixin { Expanded( child: Material( child: FutureBuilder( - future: _favController.queryFavFolder(), + future: videoIntroController.queryVideoInFolder(), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.done) { Map data = snapshot.data as Map; if (data['status']) { return Obx( () => ListView.builder( - itemCount: _favController + itemCount: videoIntroController .favFolderData.value.list!.length + 1, itemBuilder: (context, index) { if (index == 0) { - return const SizedBox(height: 15); + return const SizedBox(height: 10); } else { return ListTile( - onTap: () {}, + onTap: () => videoIntroController.onChoose( + videoIntroController.favFolderData.value + .list![index - 1].favState != + 1, + index - 1), dense: true, leading: const Icon(Icons.folder_special_outlined), minLeadingWidth: 0, - title: Text(_favController.favFolderData.value - .list![index - 1].title!), + title: Text(videoIntroController.favFolderData + .value.list![index - 1].title!), subtitle: Text( - '${_favController.favFolderData.value.list![index - 1].mediaCount}个内容', + '${videoIntroController.favFolderData.value.list![index - 1].mediaCount}个内容', style: TextStyle( color: Theme.of(context) .colorScheme @@ -182,8 +177,15 @@ class _VideoInfoState extends State with TickerProviderStateMixin { trailing: Transform.scale( scale: 0.9, child: Checkbox( - value: false, - onChanged: (bool? checkValue) {}, + value: videoIntroController + .favFolderData + .value + .list![index - 1] + .favState == + 1, + onChanged: (bool? checkValue) => + videoIntroController.onChoose( + checkValue!, index - 1), ), ), ); @@ -302,65 +304,6 @@ class _VideoInfoState extends State with TickerProviderStateMixin { ], ), ), - const SizedBox(height: 12), - Row( - children: [ - NetworkImgLayer( - type: 'avatar', - src: !widget.loadingStatus - ? widget.videoDetail!.owner!.face - : videoItem['owner'].face, - width: 38, - height: 38, - fadeInDuration: Duration.zero, - fadeOutDuration: Duration.zero, - ), - const SizedBox(width: 14), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(!widget.loadingStatus - ? widget.videoDetail!.owner!.name - : videoItem['owner'].name), - // const SizedBox(width: 10), - Text( - widget.loadingStatus - ? '- 粉丝' - : '${Utils.numFormat(widget.videoIntroController!.userStat['follower'])}粉丝', - style: TextStyle( - fontSize: Theme.of(context) - .textTheme - .labelSmall! - .fontSize, - color: Theme.of(context).colorScheme.outline), - ), - ], - ), - const Spacer(), - AnimatedOpacity( - opacity: widget.loadingStatus ? 0 : 1, - duration: const Duration(milliseconds: 150), - child: SizedBox( - height: 36, - child: ElevatedButton( - onPressed: () {}, - child: Row( - children: const [ - Icon( - CupertinoIcons.plus, - size: 16, - ), - SizedBox(width: 4), - Text('关注'), - ], - ), - ), - ), - ), - const SizedBox(width: 4), - ], - ), - const SizedBox(height: 10), // 简介 默认收起 if (!widget.loadingStatus) ExpandedSection( @@ -392,8 +335,64 @@ class _VideoInfoState extends State with TickerProviderStateMixin { ), ), ), - const SizedBox(height: 5), - _actionGrid(context, widget.videoIntroController), + const SizedBox(height: 8), + _actionGrid(context, videoIntroController), + Divider( + height: 26, + color: Theme.of(context).dividerColor.withOpacity(0.1), + ), + Row( + children: [ + NetworkImgLayer( + type: 'avatar', + src: !widget.loadingStatus + ? widget.videoDetail!.owner!.face + : videoItem['owner'].face, + width: 38, + height: 38, + fadeInDuration: Duration.zero, + fadeOutDuration: Duration.zero, + ), + const SizedBox(width: 14), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(!widget.loadingStatus + ? widget.videoDetail!.owner!.name + : videoItem['owner'].name), + // const SizedBox(width: 10), + Text( + widget.loadingStatus + ? '- 粉丝' + : '${Utils.numFormat(videoIntroController.userStat['follower'])}粉丝', + style: TextStyle( + fontSize: Theme.of(context) + .textTheme + .labelSmall! + .fontSize, + color: Theme.of(context).colorScheme.outline), + ), + ], + ), + const Spacer(), + AnimatedOpacity( + opacity: widget.loadingStatus ? 0 : 1, + duration: const Duration(milliseconds: 150), + child: SizedBox( + height: 36, + child: ElevatedButton( + onPressed: () {}, + child: const Text('关注'), + ), + ), + ), + ], + ), + Divider( + height: 26, + color: Theme.of(context).dividerColor.withOpacity(0.1), + ), + // const SizedBox(height: 10), ], ) : const Center(child: CircularProgressIndicator()), @@ -412,6 +411,29 @@ class _VideoInfoState extends State with TickerProviderStateMixin { crossAxisCount: 5, childAspectRatio: 1.25, children: [ + // ActionItem( + // icon: const Icon(FontAwesomeIcons.s), + // selectIcon: const Icon(FontAwesomeIcons.s), + // onTap: () => {}, + // selectStatus: true, + // loadingStatus: false, + // text: '三连', + // ), + // Column( + // children: [], + // ), + InkWell( + onTap: () => videoIntroController.actionOneThree(), + borderRadius: StyleString.mdRadius, + child: Padding( + padding: const EdgeInsets.all(12), + child: Image.asset( + 'assets/images/logo/logo_big.png', + width: 10, + height: 10, + ), + ), + ), Obx( () => ActionItem( icon: const Icon(FontAwesomeIcons.thumbsUp), @@ -423,13 +445,13 @@ class _VideoInfoState extends State with TickerProviderStateMixin { ? widget.videoDetail!.stat!.like!.toString() : '-'), ), - ActionItem( - icon: const Icon(FontAwesomeIcons.thumbsDown), - selectIcon: const Icon(FontAwesomeIcons.solidThumbsDown), - onTap: () => {}, - selectStatus: false, - loadingStatus: widget.loadingStatus, - text: '不喜欢'), + // ActionItem( + // icon: const Icon(FontAwesomeIcons.thumbsDown), + // selectIcon: const Icon(FontAwesomeIcons.solidThumbsDown), + // onTap: () => {}, + // selectStatus: false, + // loadingStatus: widget.loadingStatus, + // text: '不喜欢'), Obx( () => ActionItem( icon: const Icon(FontAwesomeIcons.b), @@ -445,7 +467,6 @@ class _VideoInfoState extends State with TickerProviderStateMixin { () => ActionItem( icon: const Icon(FontAwesomeIcons.star), selectIcon: const Icon(FontAwesomeIcons.star), - // onTap: () => videoIntroController.actionFavVideo(), onTap: () => showFavBottomSheet(), selectStatus: videoIntroController.hasFav.value, loadingStatus: widget.loadingStatus, @@ -488,37 +509,32 @@ class ActionItem extends StatelessWidget { @override Widget build(BuildContext context) { - return Material( - child: Ink( - child: InkWell( - onTap: () => onTap!(), - borderRadius: StyleString.mdRadius, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const SizedBox(height: 4), - selectStatus - ? Icon(selectIcon!.icon!, - size: 21, color: Theme.of(context).primaryColor) - : Icon(icon!.icon!, - size: 21, color: Theme.of(context).colorScheme.outline), - const SizedBox(height: 4), - AnimatedOpacity( - opacity: loadingStatus! ? 0 : 1, - duration: const Duration(milliseconds: 200), - child: Text( - text!, - style: TextStyle( - color: selectStatus - ? Theme.of(context).primaryColor - : Theme.of(context).colorScheme.outline, - fontSize: - Theme.of(context).textTheme.labelSmall?.fontSize), - ), - ), - ], + return InkWell( + onTap: () => onTap!(), + borderRadius: StyleString.mdRadius, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const SizedBox(height: 4), + selectStatus + ? Icon(selectIcon!.icon!, + size: 21, color: Theme.of(context).primaryColor) + : Icon(icon!.icon!, + size: 21, color: Theme.of(context).colorScheme.outline), + const SizedBox(height: 4), + AnimatedOpacity( + opacity: loadingStatus! ? 0 : 1, + duration: const Duration(milliseconds: 200), + child: Text( + text ?? '', + style: TextStyle( + color: selectStatus + ? Theme.of(context).primaryColor + : Theme.of(context).colorScheme.outline, + fontSize: Theme.of(context).textTheme.labelSmall?.fontSize), + ), ), - ), + ], ), ); } diff --git a/lib/pages/video/detail/view.dart b/lib/pages/video/detail/view.dart index 030ccc8e..3265ea24 100644 --- a/lib/pages/video/detail/view.dart +++ b/lib/pages/video/detail/view.dart @@ -114,23 +114,11 @@ class _VideoDetailPageState extends State { children: [ Builder( builder: (context) { - return CustomScrollView( - key: const PageStorageKey('简介'), + return const CustomScrollView( + key: PageStorageKey('简介'), slivers: [ - const VideoIntroPanel(), - SliverPadding( - padding: - const EdgeInsets.only(top: 8, bottom: 5), - sliver: SliverToBoxAdapter( - child: Divider( - height: 1, - color: Theme.of(context) - .dividerColor - .withOpacity(0.1), - ), - ), - ), - const RelatedVideoPanel(), + VideoIntroPanel(), + RelatedVideoPanel(), ], ); }, diff --git a/lib/pages/webview/controller.dart b/lib/pages/webview/controller.dart index eee80c02..9fe1b670 100644 --- a/lib/pages/webview/controller.dart +++ b/lib/pages/webview/controller.dart @@ -1,10 +1,13 @@ import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; +import 'package:hive/hive.dart'; import 'package:pilipala/http/constants.dart'; import 'package:pilipala/http/init.dart'; import 'package:pilipala/http/user.dart'; +import 'package:pilipala/pages/home/index.dart'; import 'package:pilipala/pages/mine/index.dart'; import 'package:pilipala/utils/cookie.dart'; +import 'package:pilipala/utils/storage.dart'; import 'package:webview_cookie_manager/webview_cookie_manager.dart'; import 'package:webview_flutter/webview_flutter.dart'; @@ -52,10 +55,15 @@ class WebviewController extends GetxController { await WebviewCookieManager().getCookies(HttpString.baseUrl); await SetCookie.onSet(cookies, HttpString.baseUrl); await SetCookie.onSet(apiCookies, HttpString.baseApiUrl); + await UserHttp.userInfo(); var result = await UserHttp.userInfo(); + print('网页登录: $result'); if (result['status'] && result['data'].isLogin) { SmartDialog.showToast('登录成功'); - Get.find().userInfo = result['data']; + Box user = GStrorage.user; + user.put(UserBoxKey.userLogin, true); + Get.find().userInfo.value = result['data']; + Get.find().queryRcmdFeed('onRefresh'); Get.back(); } } catch (e) { diff --git a/pubspec.yaml b/pubspec.yaml index a856f809..47c6ee49 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -113,6 +113,7 @@ flutter: assets: - assets/images/ - assets/images/lv/ + - assets/images/logo/ # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/assets-and-images/#resolution-aware