mirror of
https://github.com/bggRGjQaUbCoE/PiliPlus.git
synced 2026-04-20 03:06:59 +08:00
305 lines
8.8 KiB
Dart
305 lines
8.8 KiB
Dart
import 'package:PiliPlus/common/widgets/avatars.dart';
|
|
import 'package:PiliPlus/common/widgets/image/image_save.dart';
|
|
import 'package:PiliPlus/http/loading_state.dart';
|
|
import 'package:PiliPlus/models/dynamics/result.dart';
|
|
import 'package:PiliPlus/pages/dynamics/widgets/action_panel.dart';
|
|
import 'package:PiliPlus/pages/dynamics/widgets/author_panel.dart';
|
|
import 'package:PiliPlus/pages/dynamics/widgets/dyn_content.dart';
|
|
import 'package:PiliPlus/pages/dynamics/widgets/interaction.dart';
|
|
import 'package:PiliPlus/utils/extension/theme_ext.dart';
|
|
import 'package:PiliPlus/utils/page_utils.dart';
|
|
import 'package:PiliPlus/utils/platform_utils.dart';
|
|
import 'package:flutter/material.dart';
|
|
|
|
class DynamicPanel extends StatelessWidget {
|
|
final DynamicItemModel item;
|
|
final bool isDetail;
|
|
final ValueChanged<Object>? onRemove;
|
|
final bool isSave;
|
|
final void Function(bool isTop, Object dynId)? onSetTop;
|
|
final VoidCallback? onBlock;
|
|
final VoidCallback? onUnfold;
|
|
final bool isDetailPortraitW;
|
|
final Future<LoadingState> Function(bool isPrivate, Object dynId)?
|
|
onSetPubSetting;
|
|
final VoidCallback? onEdit;
|
|
final ValueChanged<int>? onSetReplySubject;
|
|
|
|
const DynamicPanel({
|
|
super.key,
|
|
required this.item,
|
|
this.isDetail = false,
|
|
this.onRemove,
|
|
this.isSave = false,
|
|
this.onSetTop,
|
|
this.onBlock,
|
|
this.onUnfold,
|
|
this.isDetailPortraitW = true,
|
|
this.onSetPubSetting,
|
|
this.onEdit,
|
|
this.onSetReplySubject,
|
|
});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
if (item.visible == false) {
|
|
return const SizedBox.shrink();
|
|
}
|
|
final theme = Theme.of(context);
|
|
final authorWidget = AuthorPanel(
|
|
item: item,
|
|
isDetail: isDetail,
|
|
onRemove: onRemove,
|
|
isSave: isSave,
|
|
onSetTop: onSetTop,
|
|
onBlock: onBlock,
|
|
onSetPubSetting: onSetPubSetting,
|
|
onEdit: onEdit,
|
|
onSetReplySubject: onSetReplySubject,
|
|
);
|
|
|
|
void showMore() => _imageSaveDialog(context, authorWidget.morePanel);
|
|
|
|
final child = Material(
|
|
type: MaterialType.transparency,
|
|
child: InkWell(
|
|
onTap:
|
|
isDetail &&
|
|
!const {
|
|
'DYNAMIC_TYPE_AV',
|
|
'DYNAMIC_TYPE_UGC_SEASON',
|
|
'DYNAMIC_TYPE_PGC_UNION',
|
|
'DYNAMIC_TYPE_PGC',
|
|
'DYNAMIC_TYPE_LIVE',
|
|
'DYNAMIC_TYPE_LIVE_RCMD',
|
|
'DYNAMIC_TYPE_MEDIALIST',
|
|
'DYNAMIC_TYPE_COURSES_SEASON',
|
|
}.contains(item.type)
|
|
? null
|
|
: () => PageUtils.pushDynDetail(item),
|
|
onLongPress: showMore,
|
|
onSecondaryTap: PlatformUtils.isMobile ? null : showMore,
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Padding(
|
|
padding: const EdgeInsets.fromLTRB(12, 12, 12, 6),
|
|
child: authorWidget,
|
|
),
|
|
if (item.modules.moduleDispute case final moduleDispute?)
|
|
_buildDispute(theme, moduleDispute),
|
|
...dynContent(
|
|
context,
|
|
theme: theme,
|
|
isSave: isSave,
|
|
isDetail: isDetail,
|
|
item: item,
|
|
floor: 1,
|
|
),
|
|
const SizedBox(height: 2),
|
|
if (!isDetail) ...[
|
|
if (item.modules.moduleInteraction case ModuleInteraction(
|
|
:final items,
|
|
))
|
|
if (items != null && items.isNotEmpty)
|
|
dynInteraction(
|
|
theme: theme,
|
|
items: items,
|
|
),
|
|
ActionPanel(item: item),
|
|
if (item.modules.moduleFold case final moduleFold?) ...[
|
|
Divider(
|
|
height: 1,
|
|
color: theme.dividerColor.withValues(alpha: 0.1),
|
|
),
|
|
_buildFoldItem(theme, moduleFold),
|
|
],
|
|
] else if (!isSave)
|
|
const SizedBox(height: 12),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
if (isSave || (isDetail && !isDetailPortraitW)) {
|
|
return child;
|
|
}
|
|
return DecoratedBox(
|
|
decoration: BoxDecoration(
|
|
border: Border(
|
|
bottom: BorderSide(
|
|
width: 8,
|
|
color: theme.dividerColor.withValues(alpha: 0.05),
|
|
),
|
|
),
|
|
),
|
|
child: Padding(
|
|
padding: const EdgeInsets.only(bottom: 8),
|
|
child: child,
|
|
),
|
|
);
|
|
}
|
|
|
|
void _imageSaveDialog(
|
|
BuildContext context,
|
|
Function(BuildContext) morePanel,
|
|
) {
|
|
String? title;
|
|
String? cover;
|
|
String? bvid;
|
|
late final major = item.modules.moduleDynamic?.major;
|
|
switch (item.type) {
|
|
case 'DYNAMIC_TYPE_AV':
|
|
if (major?.archive case final archive?) {
|
|
title = archive.title;
|
|
cover = archive.cover;
|
|
bvid = archive.bvid;
|
|
}
|
|
break;
|
|
case 'DYNAMIC_TYPE_UGC_SEASON':
|
|
if (major?.ugcSeason case final ugcSeason?) {
|
|
title = ugcSeason.title;
|
|
cover = ugcSeason.cover;
|
|
bvid = ugcSeason.bvid;
|
|
}
|
|
break;
|
|
case 'DYNAMIC_TYPE_PGC' || 'DYNAMIC_TYPE_PGC_UNION':
|
|
if (major?.pgc case final pgc?) {
|
|
title = pgc.title;
|
|
cover = pgc.cover;
|
|
}
|
|
break;
|
|
case 'DYNAMIC_TYPE_LIVE_RCMD':
|
|
if (major?.liveRcmd case final liveRcmd?) {
|
|
title = liveRcmd.title;
|
|
cover = liveRcmd.cover;
|
|
}
|
|
break;
|
|
case 'DYNAMIC_TYPE_LIVE':
|
|
if (major?.live case final live?) {
|
|
title = live.title;
|
|
cover = live.cover;
|
|
}
|
|
break;
|
|
case 'DYNAMIC_TYPE_COURSES_SEASON':
|
|
if (major?.courses case final courses?) {
|
|
title = courses.title;
|
|
cover = courses.cover;
|
|
}
|
|
break;
|
|
case 'DYNAMIC_TYPE_SUBSCRIPTION_NEW':
|
|
if (major?.subscriptionNew?.liveRcmd?.content?.livePlayInfo
|
|
case final livePlayInfo?) {
|
|
title = livePlayInfo.title;
|
|
cover = livePlayInfo.cover;
|
|
}
|
|
break;
|
|
default:
|
|
morePanel(context);
|
|
return;
|
|
}
|
|
imageSaveDialog(
|
|
title: title,
|
|
cover: cover,
|
|
bvid: bvid,
|
|
);
|
|
}
|
|
|
|
Widget _buildFoldItem(ThemeData theme, ModuleFold moduleFold) {
|
|
Widget child = Text.rich(
|
|
textAlign: TextAlign.center,
|
|
style: TextStyle(
|
|
height: 1,
|
|
fontSize: 13,
|
|
color: theme.colorScheme.outline,
|
|
),
|
|
strutStyle: const StrutStyle(
|
|
height: 1,
|
|
leading: 0,
|
|
fontSize: 13,
|
|
),
|
|
TextSpan(
|
|
children: [
|
|
TextSpan(text: moduleFold.statement ?? '展开'),
|
|
WidgetSpan(
|
|
alignment: PlaceholderAlignment.middle,
|
|
child: Icon(
|
|
size: 19,
|
|
Icons.keyboard_arrow_down,
|
|
color: theme.colorScheme.outline,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
final users = moduleFold.users;
|
|
if (users != null && users.isNotEmpty) {
|
|
child = Row(
|
|
spacing: 5,
|
|
mainAxisAlignment: .center,
|
|
children: [
|
|
avatars(colorScheme: theme.colorScheme, users: users),
|
|
child,
|
|
],
|
|
);
|
|
}
|
|
return InkWell(
|
|
onTap: onUnfold,
|
|
child: Container(
|
|
alignment: Alignment.center,
|
|
padding: const EdgeInsets.symmetric(vertical: 10),
|
|
child: child,
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildDispute(ThemeData theme, ModuleDispute moduleDispute) {
|
|
final child = Container(
|
|
width: .infinity,
|
|
margin: const .fromLTRB(12, 2, 12, 6),
|
|
padding: const .symmetric(horizontal: 8, vertical: 6),
|
|
decoration: BoxDecoration(
|
|
color: theme.colorScheme.secondaryContainer.withValues(
|
|
alpha: theme.brightness.isLight ? 0.5 : 0.7,
|
|
),
|
|
borderRadius: const BorderRadius.all(Radius.circular(6)),
|
|
),
|
|
child: Text.rich(
|
|
style: TextStyle(
|
|
height: 1,
|
|
fontSize: 13,
|
|
color: theme.colorScheme.onSecondaryContainer,
|
|
),
|
|
strutStyle: const StrutStyle(
|
|
leading: 0,
|
|
height: 1,
|
|
fontSize: 13,
|
|
),
|
|
TextSpan(
|
|
children: [
|
|
WidgetSpan(
|
|
alignment: .middle,
|
|
child: Padding(
|
|
padding: const .only(right: 4),
|
|
child: Icon(
|
|
size: 15,
|
|
Icons.warning_rounded,
|
|
color: theme.colorScheme.onSecondaryContainer,
|
|
),
|
|
),
|
|
),
|
|
TextSpan(text: moduleDispute.title),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
if (moduleDispute.jumpUrl?.isNotEmpty == true) {
|
|
return GestureDetector(
|
|
onTap: () => PageUtils.handleWebview(moduleDispute.jumpUrl!),
|
|
child: child,
|
|
);
|
|
}
|
|
return child;
|
|
}
|
|
}
|