diff --git a/lib/models/video/reply/data.dart b/lib/models/video/reply/data.dart index cce2b5d4..15735c53 100644 --- a/lib/models/video/reply/data.dart +++ b/lib/models/video/reply/data.dart @@ -44,6 +44,7 @@ class ReplyReplyData { this.replies, this.topReplies, this.upper, + this.root, }); ReplyPage? page; @@ -51,6 +52,7 @@ class ReplyReplyData { late List? replies; late List? topReplies; ReplyUpper? upper; + ReplyItemModel? root; ReplyReplyData.fromJson(Map json) { page = ReplyPage.fromJson(json['page']); @@ -67,5 +69,6 @@ class ReplyReplyData { isTopStatus: true))) : []; upper = ReplyUpper.fromJson(json['upper']); + root = ReplyItemModel.fromJson(json['root'], json['upper']['mid']); } } diff --git a/lib/pages/video/detail/reply_reply/controller.dart b/lib/pages/video/detail/reply_reply/controller.dart index af77743c..6a8377b1 100644 --- a/lib/pages/video/detail/reply_reply/controller.dart +++ b/lib/pages/video/detail/reply_reply/controller.dart @@ -11,7 +11,7 @@ class VideoReplyReplyController extends GetxController { int? aid; // rpid 请求楼中楼回复 String? rpid; - ReplyType replyType = ReplyType.video; + ReplyType replyType; // = ReplyType.video; RxList replyList = [].obs; // 当前页 int currentPage = 0; @@ -19,6 +19,7 @@ class VideoReplyReplyController extends GetxController { RxString noMore = ''.obs; // 当前回复的回复 ReplyItemModel? currentReplyItem; + ReplyItemModel? root; @override void onInit() { @@ -41,6 +42,7 @@ class VideoReplyReplyController extends GetxController { type: replyType.index, ); if (res['status']) { + if (res['data'].root != null) root = res['data'].root; final List replies = res['data'].replies; if (replies.isNotEmpty) { noMore.value = '加载中...'; diff --git a/lib/pages/video/detail/reply_reply/view.dart b/lib/pages/video/detail/reply_reply/view.dart index 89d323a2..a1d18889 100644 --- a/lib/pages/video/detail/reply_reply/view.dart +++ b/lib/pages/video/detail/reply_reply/view.dart @@ -73,7 +73,8 @@ class _VideoReplyReplyPanelState extends State { @override Widget build(BuildContext context) { return Container( - height: widget.source == 'videoDetail' ? Utils.getSheetHeight(context) : null, + height: + widget.source == 'videoDetail' ? Utils.getSheetHeight(context) : null, color: Theme.of(context).colorScheme.background, child: Column( children: [ @@ -137,60 +138,91 @@ class _VideoReplyReplyPanelState extends State { FutureBuilder( future: _futureBuilderFuture, builder: (BuildContext context, snapshot) { - if (snapshot.connectionState == ConnectionState.done) { + if (snapshot.connectionState == ConnectionState.done && + snapshot.hasData) { final Map data = snapshot.data as Map; if (data['status']) { // 请求成功 - return Obx( - () => SliverList( - delegate: SliverChildBuilderDelegate( - (BuildContext context, int index) { - if (index == - _videoReplyReplyController - .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( - _videoReplyReplyController - .noMore.value, - style: TextStyle( - fontSize: 12, - color: Theme.of(context) - .colorScheme - .outline, + return SliverMainAxisGroup( + slivers: [ + if (widget.firstFloor == null && + _videoReplyReplyController.root != null) ...[ + SliverToBoxAdapter( + child: ReplyItem( + replyItem: _videoReplyReplyController.root, + replyLevel: '2', + showReplyRow: false, + addReply: (replyItem) { + _videoReplyReplyController.replyList + .add(replyItem); + }, + replyType: widget.replyType, + replyReply: (replyItem) => + replyReply(replyItem), + ), + ), + SliverToBoxAdapter( + child: Divider( + height: 20, + color: Theme.of(context) + .dividerColor + .withOpacity(0.1), + thickness: 6, + ), + ), + ], + Obx( + () => SliverList( + delegate: SliverChildBuilderDelegate( + (BuildContext context, int index) { + if (index == + _videoReplyReplyController + .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( + _videoReplyReplyController + .noMore.value, + style: TextStyle( + fontSize: 12, + color: Theme.of(context) + .colorScheme + .outline, + ), + ), ), ), - ), - ), - ); - } else { - return ReplyItem( - replyItem: _videoReplyReplyController - .replyList[index], - replyLevel: '2', - showReplyRow: false, - addReply: (replyItem) { - _videoReplyReplyController.replyList - .add(replyItem); - }, - replyType: widget.replyType, - ); - } - }, - childCount: _videoReplyReplyController - .replyList.length + - 1, + ); + } else { + return ReplyItem( + replyItem: _videoReplyReplyController + .replyList[index], + replyLevel: '2', + showReplyRow: false, + addReply: (replyItem) { + _videoReplyReplyController.replyList + .add(replyItem); + }, + replyType: widget.replyType, + ); + } + }, + childCount: _videoReplyReplyController + .replyList.length + + 1, + ), + ), ), - ), + ], ); } else { // 请求错误 diff --git a/lib/utils/app_scheme.dart b/lib/utils/app_scheme.dart index ea5708c8..b90201ab 100644 --- a/lib/utils/app_scheme.dart +++ b/lib/utils/app_scheme.dart @@ -1,11 +1,15 @@ import 'dart:async'; +import 'package:PiliPalaX/models/common/reply_type.dart'; +import 'package:PiliPalaX/pages/video/detail/reply/widgets/reply_item.dart'; import 'package:app_links/app_links.dart'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; +import 'package:path/path.dart'; import '../http/search.dart'; import '../models/common/search_type.dart'; +import '../pages/video/detail/reply_reply/view.dart'; import 'id_utils.dart'; import 'url_utils.dart'; import 'utils.dart'; @@ -30,6 +34,7 @@ class PiliScheme { final String path = value.path; if (scheme == 'bilibili') { + print(value); if (host == 'root') { Navigator.popUntil( Get.context!, (Route route) => route.isFirst); @@ -41,6 +46,38 @@ class PiliScheme { ); } else if (host == 'video') { String pathQuery = path.split('/').last; + if (value.queryParameters['comment_root_id'] != null) { + Get.to( + () => Scaffold( + appBar: AppBar( + titleSpacing: 0, + centerTitle: false, + title: Text( + '评论详情', + // style: Theme.of(context).textTheme.titleMedium, + ), + actions: [ + IconButton( + tooltip: '前往原视频', + onPressed: () { + String? enterUri = value.toString().split('?').first; + routePush(Uri.parse(enterUri)); + }, + icon: const Icon(Icons.open_in_new), + ), + ], + ), + body: VideoReplyReplyPanel( + oid: int.tryParse(pathQuery), + rpid: int.tryParse(value.queryParameters['comment_root_id']!), + source: 'routePush', + replyType: ReplyType.video, + firstFloor: null, + ), + ), + ); + return; + } final numericRegex = RegExp(r'^[0-9]+$'); if (numericRegex.hasMatch(pathQuery)) { pathQuery = 'AV$pathQuery'; @@ -87,16 +124,92 @@ class PiliScheme { 'dynamicType': 'read' }, ); - } else if (host == 'following' && path.startsWith("/detail/")) { - var opusId = path.split('/').last; - Get.toNamed( - '/webview', - parameters: { - 'url': 'https://www.bilibili.com/opus/$opusId', - 'type': 'url', - 'pageTitle': '', - }, + } else if (host == 'comment' && path.startsWith("/detail/")) { + //bilibili://comment/detail/17/832703053858603029/238686570016/?subType=0&anchor=238686628816&showEnter=1&extraIntentId=0&scene=1&enterName=%E6%9F%A5%E7%9C%8B%E5%8A%A8%E6%80%81%E8%AF%A6%E6%83%85&enterUri=bilibili://following/detail/832703053858603029 + //fmt.Sprintf("bilibili://comment/detail/%d/%d/%d/?subType=%d&anchor=%d&showEnter=1&extraIntentId=%d", rp.Type, rp.Oid, rootID, subType, rp.RpID, extraIntentID) + print(value.queryParameters); + List pathParts = path.split('/'); + int type = int.parse(pathParts[2]); + int oid = int.parse(pathParts[3]); + int rootId = int.parse(pathParts[4]); + int subType = int.parse(value.queryParameters['subType'] ?? '0'); + int RpID = int.parse(value.queryParameters['anchor'] ?? '0'); + int extraIntentId = + int.parse(value.queryParameters['extraIntentId'] ?? '0'); + Get.to( + () => Scaffold( + appBar: AppBar( + titleSpacing: 0, + centerTitle: false, + title: Text( + '评论详情', + // style: Theme.of(context).textTheme.titleMedium, + ), + actions: [ + IconButton( + tooltip: '前往', + onPressed: () { + String? enterUri = value.queryParameters['enterUri']; + if (enterUri != null) { + routePush(Uri.parse(enterUri)); + } + }, + icon: const Icon(Icons.open_in_new), + ), + ], + ), + body: VideoReplyReplyPanel( + oid: oid, + rpid: RpID, + source: 'routePush', + replyType: ReplyType.dynamics, + firstFloor: null), + ), ); + } else if (host == 'following' && path.startsWith("/detail/")) { + void getToOpusWeb() { + var opusId = path.split('/').last; + Get.toNamed( + '/webview', + parameters: { + 'url': 'https://m.bilibili.com/dynamic/$opusId', + 'type': 'url', + 'pageTitle': '', + }, + ); + } + + if (value.queryParameters['comment_root_id'] != null) { + Get.to( + () => Scaffold( + appBar: AppBar( + titleSpacing: 0, + centerTitle: false, + title: Text( + '评论详情', + // style: Theme.of(context).textTheme.titleMedium, + ), + actions: [ + IconButton( + tooltip: '前往', + onPressed: () { + getToOpusWeb(); + }, + icon: const Icon(Icons.open_in_new), + ), + ], + ), + body: VideoReplyReplyPanel( + oid: int.tryParse(path.split('/').last), + rpid: int.tryParse(value.queryParameters['comment_root_id']!), + source: 'routePush', + replyType: ReplyType.dynamics, + firstFloor: null), + ), + ); + } else { + getToOpusWeb(); + } } else { print(value); SmartDialog.showToast('未知路径:$value,请截图反馈给开发者');