opt dyn detail

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
bggRGjQaUbCoE
2025-05-20 22:29:51 +08:00
parent 12eb430d8c
commit 43d71bb368
4 changed files with 129 additions and 219 deletions

View File

@@ -320,16 +320,16 @@ Widget forWard(
);
// 课堂
case 'DYNAMIC_TYPE_COURSES_SEASON':
return Row(
children: [
Expanded(
return SizedBox(
width: double.infinity,
child: Padding(
padding: floor == 1
? const EdgeInsets.symmetric(horizontal: 12)
: EdgeInsets.zero,
child: Text(
"课堂💪${item.modules.moduleDynamic!.major!.courses!['title']}",
maxLines: 1,
overflow: TextOverflow.ellipsis,
"课堂:${item.modules.moduleDynamic!.major!.courses!['title']}",
),
),
)
],
);
// 活动
case 'DYNAMIC_TYPE_COMMON_SQUARE':

View File

@@ -1,7 +1,6 @@
import 'package:PiliPlus/grpc/bilibili/main/community/reply/v1.pb.dart'
show MainListReply, ReplyInfo;
import 'package:PiliPlus/grpc/reply.dart';
import 'package:PiliPlus/http/dynamics.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/models/dynamics/result.dart';
import 'package:PiliPlus/pages/common/reply_controller.dart';
@@ -10,41 +9,24 @@ import 'package:PiliPlus/utils/storage.dart';
import 'package:get/get.dart';
class DynamicDetailController extends ReplyController<MainListReply> {
DynamicDetailController(this.oid, this.type);
int oid;
int type;
late DynamicItemModel item;
int? floor;
late int oid;
late int replyType;
late DynamicItemModel dynItem;
late final horizontalPreview = GStorage.horizontalPreview;
late final showDynActionBar = GStorage.showDynActionBar;
@override
dynamic get sourceId => type == 1 ? IdUtils.av2bv(oid) : oid;
dynamic get sourceId => replyType == 1 ? IdUtils.av2bv(oid) : oid;
@override
void onInit() {
super.onInit();
item = Get.arguments['item'];
floor = Get.arguments['floor'];
if (floor == 1) {
count.value = item.modules.moduleStat?.comment?.count ?? 0;
}
if (oid != 0) {
dynItem = Get.arguments['item'];
oid = int.parse(dynItem.basic!.commentIdStr!);
replyType = dynItem.basic!.commentType!;
queryData();
}
}
Future<void> getCommentParams(int id) async {
var res = await DynamicsHttp.opusDetail(opusId: id);
if (res is Success) {
final data = (res as Success<DynamicItemModel>).response;
type = data.basic!.commentType!;
oid = int.parse(data.basic!.commentIdStr!);
queryData();
}
}
@override
List<ReplyInfo>? getDataList(MainListReply response) {
@@ -53,7 +35,7 @@ class DynamicDetailController extends ReplyController<MainListReply> {
@override
Future<LoadingState<MainListReply>> customGetData() => ReplyGrpc.mainList(
type: type,
type: replyType,
oid: oid,
mode: mode.value,
cursorNext: cursorNext,

View File

@@ -39,23 +39,20 @@ class DynamicDetailPage extends StatefulWidget {
class _DynamicDetailPageState extends State<DynamicDetailPage>
with TickerProviderStateMixin {
late DynamicDetailController _dynamicDetailController;
final _controller =
Get.put(DynamicDetailController(), tag: Utils.generateRandomString(8));
late final AnimationController _fabAnimationCtr;
late final Animation<Offset> _anim;
final RxBool _visibleTitle = false.obs;
// 回复类型
late int replyType;
bool _isFabVisible = true;
bool? _imageStatus;
int oid = 0;
int? opusId;
bool isOpusId = false;
late final List<double> _ratio = GStorage.dynamicDetailRatio;
bool get _horizontalPreview =>
context.orientation == Orientation.landscape &&
_dynamicDetailController.horizontalPreview;
_controller.horizontalPreview;
late final _key = GlobalKey<ScaffoldState>();
@@ -103,9 +100,6 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
@override
void initState() {
super.initState();
// floor 1原创 2转发
init();
_fabAnimationCtr = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 300),
@@ -118,50 +112,7 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
curve: Curves.easeInOut,
));
_fabAnimationCtr.forward();
_dynamicDetailController.scrollController.addListener(listener);
}
// 页面初始化
Future<void> init() async {
Map args = Get.arguments;
// 楼层
int floor = args['floor'];
// 评论类型
final item = args['item'] as DynamicItemModel;
int commentType = item.basic?.commentType ?? 11;
replyType = (commentType == 0) ? 11 : commentType;
if (floor == 1) {
oid = int.parse(item.basic!.commentIdStr!);
} else {
try {
final moduleDynamic = item.modules.moduleDynamic!;
String majorType = moduleDynamic.major!.type!;
if (majorType == 'MAJOR_TYPE_OPUS') {
// 转发的动态
String jumpUrl = moduleDynamic.major!.opus!.jumpUrl!;
opusId = int.parse(jumpUrl.split('/').last);
if (opusId != null) {
isOpusId = true;
_dynamicDetailController = Get.put(
DynamicDetailController(oid, replyType),
tag: Utils.makeHeroTag(opusId),
);
await _dynamicDetailController.getCommentParams(opusId!);
setState(() {});
}
} else {
oid = moduleDynamic.major!.draw!.id!;
}
} catch (_) {}
}
if (!isOpusId) {
_dynamicDetailController = Get.put(
DynamicDetailController(oid, replyType),
tag: Utils.makeHeroTag(oid),
);
}
_controller.scrollController.addListener(listener);
}
// 查看二级评论
@@ -189,7 +140,7 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
oid: oid,
rpid: rpid,
source: 'dynamic',
replyType: replyType,
replyType: _controller.replyType,
firstFloor: replyItem,
onDispose: onDispose,
),
@@ -200,7 +151,7 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
replyReplyPage,
routeName: 'dynamicDetail-Copy',
arguments: {
'item': _dynamicDetailController.item,
'item': _controller.dynItem,
},
);
} else {
@@ -230,7 +181,7 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
replyReplyPage,
routeName: 'dynamicDetail-Copy',
arguments: {
'item': _dynamicDetailController.item,
'item': _controller.dynItem,
},
);
}
@@ -242,10 +193,9 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
void didChangeDependencies() {
super.didChangeDependencies();
WidgetsBinding.instance.addPostFrameCallback((_) {
if (_dynamicDetailController.scrollController.hasClients) {
if (_controller.scrollController.hasClients) {
_visibleTitle.value =
_dynamicDetailController.scrollController.positions.first.pixels >
55;
_controller.scrollController.positions.first.pixels > 55;
}
});
}
@@ -253,13 +203,13 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
void listener() {
// 标题
_visibleTitle.value =
_dynamicDetailController.scrollController.positions.first.pixels > 55;
_controller.scrollController.positions.first.pixels > 55;
// fab按钮
final ScrollDirection direction1 = _dynamicDetailController
.scrollController.positions.first.userScrollDirection;
late final ScrollDirection direction2 = _dynamicDetailController
.scrollController.positions.last.userScrollDirection;
final ScrollDirection direction1 =
_controller.scrollController.positions.first.userScrollDirection;
late final ScrollDirection direction2 =
_controller.scrollController.positions.last.userScrollDirection;
if (direction1 == ScrollDirection.forward ||
direction2 == ScrollDirection.forward) {
_showFab();
@@ -286,7 +236,7 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
@override
void dispose() {
_fabAnimationCtr.dispose();
_dynamicDetailController.scrollController.removeListener(listener);
_controller.scrollController.removeListener(listener);
super.dispose();
}
@@ -304,7 +254,7 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
opacity: _visibleTitle.value ? 1 : 0,
duration: const Duration(milliseconds: 300),
child: AuthorPanel(
item: _dynamicDetailController.item,
item: _controller.dynItem,
source: 'detail', //to remove tag
),
);
@@ -364,7 +314,7 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
bottom: false,
child: context.orientation == Orientation.portrait
? refreshIndicator(
onRefresh: _dynamicDetailController.onRefresh,
onRefresh: _controller.onRefresh,
child: _buildBody(context.orientation, theme),
)
: _buildBody(context.orientation, theme),
@@ -380,20 +330,19 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
double padding = max(context.width / 2 - Grid.smallCardWidth, 0);
if (orientation == Orientation.portrait) {
return CustomScrollView(
controller: _dynamicDetailController.scrollController,
controller: _controller.scrollController,
physics: const AlwaysScrollableScrollPhysics(),
slivers: [
SliverToBoxAdapter(
child: DynamicPanel(
item: _dynamicDetailController.item,
item: _controller.dynItem,
source: 'detail',
callback: _getImageCallback,
),
),
replyPersistentHeader(theme),
Obx(
() => replyList(
theme, _dynamicDetailController.loadingState.value),
() => replyList(theme, _controller.loadingState.value),
),
]
.map<Widget>((e) => SliverPadding(
@@ -407,7 +356,7 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
Expanded(
flex: _ratio[0].toInt(),
child: CustomScrollView(
controller: _dynamicDetailController.scrollController,
controller: _controller.scrollController,
physics: const AlwaysScrollableScrollPhysics(),
slivers: [
SliverPadding(
@@ -417,7 +366,7 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
),
sliver: SliverToBoxAdapter(
child: DynamicPanel(
item: _dynamicDetailController.item,
item: _controller.dynItem,
source: 'detail',
callback: _getImageCallback,
),
@@ -432,10 +381,9 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
key: _key,
backgroundColor: Colors.transparent,
body: refreshIndicator(
onRefresh: _dynamicDetailController.onRefresh,
onRefresh: _controller.onRefresh,
child: CustomScrollView(
controller:
_dynamicDetailController.scrollController,
controller: _controller.scrollController,
physics: const AlwaysScrollableScrollPhysics(),
slivers: [
SliverPadding(
@@ -446,9 +394,7 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
padding: EdgeInsets.only(right: padding / 4),
sliver: Obx(
() => replyList(
theme,
_dynamicDetailController
.loadingState.value),
theme, _controller.loadingState.value),
),
),
],
@@ -473,16 +419,16 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
heroTag: null,
onPressed: () {
feedBack();
_dynamicDetailController.onReply(
_controller.onReply(
context,
oid: _dynamicDetailController.oid,
replyType: replyType,
oid: _controller.oid,
replyType: _controller.replyType,
);
},
tooltip: '评论动态',
child: const Icon(Icons.reply),
);
return _dynamicDetailController.showDynActionBar.not
return _controller.showDynActionBar.not
? Align(
alignment: Alignment.bottomRight,
child: Padding(
@@ -527,27 +473,25 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
isScrollControlled: true,
useSafeArea: true,
builder: (context) => RepostPanel(
item:
_dynamicDetailController.item,
item: _controller.dynItem,
callback: () {
int count =
_dynamicDetailController
.item
int count = _controller
.dynItem
.modules
.moduleStat
?.forward
?.count ??
0;
_dynamicDetailController.item
.modules.moduleStat ??=
_controller.dynItem.modules
.moduleStat ??=
ModuleStatModel();
_dynamicDetailController
.item
_controller
.dynItem
.modules
.moduleStat
?.forward ??= DynamicStat();
_dynamicDetailController
.item
_controller
.dynItem
.modules
.moduleStat!
.forward!
@@ -573,16 +517,11 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
theme.colorScheme.outline,
),
label: Text(
_dynamicDetailController
.item
.modules
.moduleStat
?.forward
?.count !=
_controller.dynItem.modules.moduleStat
?.forward?.count !=
null
? Utils.numFormat(
_dynamicDetailController
.item
? Utils.numFormat(_controller
.dynItem
.modules
.moduleStat!
.forward!
@@ -596,7 +535,7 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
child: TextButton.icon(
onPressed: () {
Utils.shareText(
'${HttpString.dynamicShareBaseUrl}/${_dynamicDetailController.item.idStr}');
'${HttpString.dynamicShareBaseUrl}/${_controller.dynItem.idStr}');
},
icon: Icon(
CustomIcon.share_node,
@@ -618,7 +557,7 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
builder: (context) => TextButton.icon(
onPressed: () =>
RequestUtils.onLikeDynamic(
_dynamicDetailController.item,
_controller.dynItem,
() {
if (context.mounted) {
(context as Element?)
@@ -627,18 +566,14 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
},
),
icon: Icon(
_dynamicDetailController
.item
.modules
.moduleStat
?.like
?.status ==
_controller.dynItem.modules.moduleStat
?.like?.status ==
true
? FontAwesomeIcons.solidThumbsUp
: FontAwesomeIcons.thumbsUp,
size: 16,
color: _dynamicDetailController
.item
color: _controller
.dynItem
.modules
.moduleStat
?.like
@@ -646,9 +581,8 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
true
? theme.colorScheme.primary
: theme.colorScheme.outline,
semanticLabel:
_dynamicDetailController
.item
semanticLabel: _controller
.dynItem
.modules
.moduleStat
?.like
@@ -672,24 +606,23 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
scale: animation, child: child);
},
child: Text(
_dynamicDetailController
.item
_controller
.dynItem
.modules
.moduleStat
?.like
?.count !=
null
? Utils.numFormat(
_dynamicDetailController
.item
? Utils.numFormat(_controller
.dynItem
.modules
.moduleStat!
.like!
.count)
: '点赞',
style: TextStyle(
color: _dynamicDetailController
.item
color: _controller
.dynItem
.modules
.moduleStat
?.like
@@ -732,8 +665,8 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
return ScaleTransition(scale: animation, child: child);
},
child: Text(
'${_dynamicDetailController.count.value == -1 ? 0 : Utils.numFormat(_dynamicDetailController.count.value)}条回复',
key: ValueKey<int>(_dynamicDetailController.count.value),
'${_controller.count.value == -1 ? 0 : Utils.numFormat(_controller.count.value)}条回复',
key: ValueKey<int>(_controller.count.value),
),
),
),
@@ -741,14 +674,14 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
SizedBox(
height: 35,
child: TextButton.icon(
onPressed: () => _dynamicDetailController.queryBySort(),
onPressed: () => _controller.queryBySort(),
icon: Icon(
Icons.sort,
size: 16,
color: theme.colorScheme.secondary,
),
label: Obx(() => Text(
_dynamicDetailController.sortType.value.label,
_controller.sortType.value.label,
style: TextStyle(
fontSize: 13,
color: theme.colorScheme.secondary,
@@ -777,14 +710,14 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
? SliverList.builder(
itemBuilder: (context, index) {
if (index == response.length) {
_dynamicDetailController.onLoadMore();
_controller.onLoadMore();
return Container(
alignment: Alignment.center,
margin: EdgeInsets.only(
bottom: MediaQuery.of(context).padding.bottom),
height: 125,
child: Text(
_dynamicDetailController.isEnd ? '没有更多了' : '加载中...',
_controller.isEnd ? '没有更多了' : '加载中...',
style: TextStyle(
fontSize: 12,
color: theme.colorScheme.outline,
@@ -798,23 +731,22 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
replyReply: (replyItem, id) =>
replyReply(context, replyItem, id),
onReply: () {
_dynamicDetailController.onReply(
_controller.onReply(
context,
replyItem: response[index],
index: index,
);
},
onDelete: (subIndex) =>
_dynamicDetailController.onRemove(index, subIndex),
upMid: _dynamicDetailController.upMid,
_controller.onRemove(index, subIndex),
upMid: _controller.upMid,
callback: _getImageCallback,
onCheckReply: (item) =>
_dynamicDetailController.onCheckReply(context, item),
onToggleTop: (isUpTop, rpid) =>
_dynamicDetailController.onToggleTop(
_controller.onCheckReply(context, item),
onToggleTop: (isUpTop, rpid) => _controller.onToggleTop(
index,
_dynamicDetailController.oid,
_dynamicDetailController.type,
_controller.oid,
_controller.replyType,
isUpTop,
rpid,
),
@@ -824,11 +756,11 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
itemCount: response!.length + 1,
)
: HttpError(
onReload: _dynamicDetailController.onReload,
onReload: _controller.onReload,
),
Error(:var errMsg) => HttpError(
errMsg: errMsg,
onReload: _dynamicDetailController.onReload,
onReload: _controller.onReload,
),
};
}

View File

@@ -284,8 +284,6 @@ class PageUtils {
'/dynamicDetail',
arguments: {
'item': res['data'],
'floor': 1,
'action': 'detail',
},
off: off,
);
@@ -350,16 +348,25 @@ class PageUtils {
{action = 'all'}) async {
feedBack();
/// 点击评论action 直接查看评论
if (action == 'comment') {
void push() {
var commentType = item.basic?.commentType;
if (commentType != null &&
commentType != 0 &&
item.basic?.commentIdStr?.isNotEmpty == true) {
toDupNamed(
'/dynamicDetail',
arguments: {
'item': item,
'floor': floor,
'action': action,
},
);
} else {
pushDynFromId(id: item.idStr);
}
}
/// 点击评论action 直接查看评论
if (action == 'comment') {
push();
return;
}
@@ -496,18 +503,7 @@ class PageUtils {
// 图文动态查看
// case 'DYNAMIC_TYPE_DRAW':
default:
if (item.basic?.commentIdStr?.isNotEmpty == true) {
toDupNamed(
'/dynamicDetail',
arguments: {
'item': item,
'floor': floor,
},
);
} else {
pushDynFromId(id: item.idStr);
}
push();
break;
}
}