opt: get theme color

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
bggRGjQaUbCoE
2025-04-28 21:32:30 +08:00
parent 451a84e696
commit ca993df0c6
149 changed files with 4415 additions and 4803 deletions

View File

@@ -58,8 +58,10 @@ class _ActionPanelState extends State<ActionPanel> {
@override
Widget build(BuildContext context) {
var color = Theme.of(context).colorScheme.outline;
var primary = Theme.of(context).colorScheme.primary;
final theme = Theme.of(context);
final color = theme.colorScheme.outline;
final primary = theme.colorScheme.primary;
final outline = theme.colorScheme.outline;
return Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
@@ -90,7 +92,7 @@ class _ActionPanelState extends State<ActionPanel> {
),
style: TextButton.styleFrom(
padding: const EdgeInsets.fromLTRB(15, 0, 15, 0),
foregroundColor: Theme.of(context).colorScheme.outline,
foregroundColor: outline,
),
label: Text(
widget.item.modules.moduleStat!.forward!.count != null
@@ -113,7 +115,7 @@ class _ActionPanelState extends State<ActionPanel> {
),
style: TextButton.styleFrom(
padding: const EdgeInsets.fromLTRB(15, 0, 15, 0),
foregroundColor: Theme.of(context).colorScheme.outline,
foregroundColor: outline,
),
label: Text(
widget.item.modules.moduleStat!.comment!.count != null
@@ -140,7 +142,7 @@ class _ActionPanelState extends State<ActionPanel> {
),
style: TextButton.styleFrom(
padding: const EdgeInsets.fromLTRB(15, 0, 15, 0),
foregroundColor: Theme.of(context).colorScheme.outline,
foregroundColor: outline,
),
label: AnimatedSwitcher(
duration: const Duration(milliseconds: 400),

View File

@@ -1,3 +1,4 @@
import 'package:PiliPlus/models/dynamics/result.dart';
import 'package:PiliPlus/utils/page_utils.dart';
import 'package:PiliPlus/utils/utils.dart';
import 'package:flutter/material.dart';
@@ -6,33 +7,36 @@ import 'package:PiliPlus/common/widgets/network_img_layer.dart';
import 'package:PiliPlus/http/search.dart';
/// TODO 点击跳转
Widget addWidget(item, context, type, {floor = 1}) {
Widget addWidget(
ThemeData theme, DynamicItemModel item, BuildContext context, type,
{floor = 1}) {
Map<dynamic, dynamic> dynamicProperty = {
'ADDITIONAL_TYPE_UGC': item.modules.moduleDynamic.additional.ugc,
'ADDITIONAL_TYPE_UGC': item.modules.moduleDynamic!.additional!.ugc,
// 直播预约
'ADDITIONAL_TYPE_RESERVE': item.modules.moduleDynamic.additional.reserve,
'ADDITIONAL_TYPE_RESERVE': item.modules.moduleDynamic!.additional!.reserve,
// 商品
'ADDITIONAL_TYPE_GOODS': item.modules.moduleDynamic.additional.goods,
'ADDITIONAL_TYPE_GOODS': item.modules.moduleDynamic!.additional!.goods,
// 比赛信息
'ADDITIONAL_TYPE_MATCH': item.modules.moduleDynamic.additional.match,
'ADDITIONAL_TYPE_MATCH': item.modules.moduleDynamic!.additional!.match,
// 游戏信息
'ADDITIONAL_TYPE_COMMON': item.modules.moduleDynamic.additional.common,
'ADDITIONAL_TYPE_COMMON': item.modules.moduleDynamic!.additional!.common,
};
dynamic content = dynamicProperty[type];
Color bgColor = floor == 1
? Theme.of(context).dividerColor.withOpacity(0.08)
: Theme.of(context).colorScheme.surface;
? theme.dividerColor.withOpacity(0.08)
: theme.colorScheme.surface;
switch (type) {
case 'ADDITIONAL_TYPE_UGC':
// 转发的投稿
return InkWell(
onTap: () async {
String text = dynamicProperty[type].jumpUrl;
String text = content.jumpUrl;
RegExp bvRegex = RegExp(r'BV[0-9A-Za-z]{10}', caseSensitive: false);
Iterable<Match> matches = bvRegex.allMatches(text);
if (matches.isNotEmpty) {
Match match = matches.first;
String bvid = match.group(0)!;
String cover = dynamicProperty[type].cover;
String cover = content.cover;
try {
int cid = await SearchHttp.ab2c(bvid: bvid);
PageUtils.toVideoPage(
@@ -58,7 +62,7 @@ Widget addWidget(item, context, type, {floor = 1}) {
NetworkImgLayer(
width: 120,
height: 75,
src: dynamicProperty[type].cover,
src: content.cover,
),
const SizedBox(width: 10),
Expanded(
@@ -67,17 +71,16 @@ Widget addWidget(item, context, type, {floor = 1}) {
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
dynamicProperty[type].title,
content.title,
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
const SizedBox(height: 4),
Text(
dynamicProperty[type].descSecond,
content.descSecond,
style: TextStyle(
color: Theme.of(context).colorScheme.outline,
fontSize:
Theme.of(context).textTheme.labelMedium!.fontSize,
color: theme.colorScheme.outline,
fontSize: theme.textTheme.labelMedium!.fontSize,
),
)
],
@@ -88,22 +91,22 @@ Widget addWidget(item, context, type, {floor = 1}) {
),
);
case 'ADDITIONAL_TYPE_RESERVE':
return dynamicProperty[type].state != -1
? dynamicProperty[type].title != null
return content.state != -1
? content.title != null
? Padding(
padding: const EdgeInsets.only(top: 8),
child: InkWell(
onTap: () {},
child: Container(
width: double.infinity,
padding: const EdgeInsets.only(
left: 12, top: 10, right: 12, bottom: 10),
padding: const EdgeInsets.symmetric(
horizontal: 12, vertical: 10),
color: bgColor,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
dynamicProperty[type].title,
content.title,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
@@ -111,21 +114,15 @@ Widget addWidget(item, context, type, {floor = 1}) {
Text.rich(
TextSpan(
style: TextStyle(
color: Theme.of(context).colorScheme.outline,
fontSize: Theme.of(context)
.textTheme
.labelMedium!
.fontSize),
color: theme.colorScheme.outline,
fontSize: theme.textTheme.labelMedium!.fontSize,
),
children: [
if (dynamicProperty[type].desc1 != null)
TextSpan(
text:
dynamicProperty[type].desc1['text']),
if (content.desc1 != null)
TextSpan(text: content.desc1['text']),
const TextSpan(text: ' '),
if (dynamicProperty[type].desc2 != null)
TextSpan(
text:
dynamicProperty[type].desc2['text']),
if (content.desc2 != null)
TextSpan(text: content.desc2['text']),
],
),
)
@@ -146,6 +143,6 @@ Widget addWidget(item, context, type, {floor = 1}) {
case 'ADDITIONAL_TYPE_VOTE':
return const SizedBox.shrink();
default:
return const Text('11');
return const SizedBox.shrink();
}
}

View File

@@ -1,12 +1,18 @@
import 'package:PiliPlus/models/dynamics/result.dart';
import 'package:flutter/material.dart';
import 'package:PiliPlus/utils/utils.dart';
import '../../../common/constants.dart';
import 'pic_panel.dart';
Widget articlePanel(source, item, context, callback, {floor = 1}) {
TextStyle authorStyle =
TextStyle(color: Theme.of(context).colorScheme.primary);
Widget articlePanel(
ThemeData theme,
String? source,
DynamicItemModel item,
BuildContext context,
callback, {
floor = 1,
}) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: StyleString.safeSpace),
child: Column(
@@ -15,37 +21,32 @@ Widget articlePanel(source, item, context, callback, {floor = 1}) {
if (floor == 2) ...[
Row(
children: [
GestureDetector(
onTap: () {},
child: Text(
'@${item.modules.moduleAuthor.name}',
style: authorStyle,
),
Text(
'@${item.modules.moduleAuthor!.name}',
style: TextStyle(color: theme.colorScheme.primary),
),
const SizedBox(width: 6),
Text(
Utils.dateFormat(item.modules.moduleAuthor.pubTs),
Utils.dateFormat(item.modules.moduleAuthor!.pubTs),
style: TextStyle(
color: Theme.of(context).colorScheme.outline,
fontSize: Theme.of(context).textTheme.labelSmall!.fontSize),
color: theme.colorScheme.outline,
fontSize: theme.textTheme.labelSmall!.fontSize),
),
],
),
const SizedBox(height: 8),
],
Text(
item.modules.moduleDynamic.major.opus.title,
style: Theme.of(context)
.textTheme
.titleMedium!
item.modules.moduleDynamic!.major!.opus!.title!,
style: theme.textTheme.titleMedium!
.copyWith(fontWeight: FontWeight.bold),
),
const SizedBox(height: 2),
if (item.modules.moduleDynamic.major.opus.summary.text !=
if (item.modules.moduleDynamic?.major?.opus?.summary?.text !=
'undefined') ...[
Text(
item.modules.moduleDynamic.major.opus.summary.richTextNodes.first
.text,
item.modules.moduleDynamic!.major!.opus!.summary!.richTextNodes!
.first.text!,
maxLines: source == 'detail' ? null : 4,
style: const TextStyle(height: 1.55),
overflow: source == 'detail' ? null : TextOverflow.ellipsis,

View File

@@ -241,6 +241,7 @@ class AuthorPanel extends StatelessWidget {
maxWidth: min(640, min(Get.width, Get.height)),
),
builder: (context1) {
final theme = Theme.of(context);
return Padding(
padding:
EdgeInsets.only(bottom: MediaQuery.of(context1).padding.bottom),
@@ -261,7 +262,7 @@ class AuthorPanel extends StatelessWidget {
width: 32,
height: 3,
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.outline,
color: theme.colorScheme.outline,
borderRadius:
const BorderRadius.all(Radius.circular(3))),
),
@@ -283,7 +284,7 @@ class AuthorPanel extends StatelessWidget {
leading: const Icon(Icons.watch_later_outlined, size: 19),
title: Text(
'稍后再看',
style: Theme.of(context).textTheme.titleSmall,
style: theme.textTheme.titleSmall,
),
),
ListTile(
@@ -293,13 +294,12 @@ class AuthorPanel extends StatelessWidget {
},
minLeadingWidth: 0,
leading: const Icon(Icons.save_alt, size: 19),
title: Text('保存动态',
style: Theme.of(context).textTheme.titleSmall!),
title: Text('保存动态', style: theme.textTheme.titleSmall!),
),
ListTile(
title: Text(
'分享动态',
style: Theme.of(context).textTheme.titleSmall,
style: theme.textTheme.titleSmall,
),
leading: const Icon(Icons.share_outlined, size: 19),
onTap: () {
@@ -314,7 +314,7 @@ class AuthorPanel extends StatelessWidget {
ListTile(
title: Text(
'分享至消息',
style: Theme.of(context).textTheme.titleSmall,
style: theme.textTheme.titleSmall,
),
leading: const Icon(Icons.forward_to_inbox, size: 19),
onTap: () {
@@ -359,7 +359,7 @@ class AuthorPanel extends StatelessWidget {
ListTile(
title: Text(
'临时屏蔽:${item.modules.moduleAuthor?.name}',
style: Theme.of(context).textTheme.titleSmall,
style: theme.textTheme.titleSmall,
),
leading: const Icon(Icons.visibility_off_outlined, size: 19),
onTap: () {
@@ -387,8 +387,7 @@ class AuthorPanel extends StatelessWidget {
Icon(Icons.published_with_changes_sharp, size: 12),
],
),
title: Text('检查动态',
style: Theme.of(context).textTheme.titleSmall!),
title: Text('检查动态', style: theme.textTheme.titleSmall!),
),
if (onSetTop != null)
ListTile(
@@ -401,7 +400,7 @@ class AuthorPanel extends StatelessWidget {
leading: const Icon(Icons.vertical_align_top, size: 19),
title: Text(
'${item.modules.moduleTag?.text != null ? '取消' : ''}置顶',
style: Theme.of(context).textTheme.titleSmall!),
style: theme.textTheme.titleSmall!),
),
if (onRemove != null)
ListTile(
@@ -417,7 +416,7 @@ class AuthorPanel extends StatelessWidget {
child: Text(
'取消',
style: TextStyle(
color: Theme.of(context).colorScheme.outline,
color: theme.colorScheme.outline,
),
),
),
@@ -434,24 +433,24 @@ class AuthorPanel extends StatelessWidget {
},
minLeadingWidth: 0,
leading: Icon(Icons.delete_outline,
color: Theme.of(context).colorScheme.error, size: 19),
color: theme.colorScheme.error, size: 19),
title: Text('删除',
style: Theme.of(context).textTheme.titleSmall!.copyWith(
color: Theme.of(context).colorScheme.error)),
style: theme.textTheme.titleSmall!
.copyWith(color: theme.colorScheme.error)),
),
],
if (Accounts.main.isLogin)
ListTile(
title: Text(
'举报',
style: Theme.of(context).textTheme.titleSmall!.copyWith(
color: Theme.of(context).colorScheme.error,
),
style: theme.textTheme.titleSmall!.copyWith(
color: theme.colorScheme.error,
),
),
leading: Icon(
Icons.error_outline_outlined,
size: 19,
color: Theme.of(context).colorScheme.error,
color: theme.colorScheme.error,
),
onTap: () {
Get.back();
@@ -483,8 +482,7 @@ class AuthorPanel extends StatelessWidget {
dense: true,
title: Text(
'取消',
style:
TextStyle(color: Theme.of(context).colorScheme.outline),
style: TextStyle(color: theme.colorScheme.outline),
textAlign: TextAlign.center,
),
),

View File

@@ -1,16 +1,24 @@
// 内容
import 'package:PiliPlus/common/widgets/image_view.dart';
import 'package:PiliPlus/models/dynamics/result.dart';
import 'package:flutter/material.dart';
import 'rich_node_panel.dart';
Widget content(bool isSave, BuildContext context, item, source, callback) {
Widget content(
ThemeData theme,
bool isSave,
BuildContext context,
DynamicItemModel item,
String? source,
Function(List<String>, int)? callback,
) {
InlineSpan picsNodes() {
return WidgetSpan(
child: LayoutBuilder(
builder: (context, constraints) => imageView(
constraints.maxWidth,
(item.modules.moduleDynamic.major.opus.pics as List)
(item.modules.moduleDynamic!.major!.opus!.pics as List)
.map(
(item) => ImageModel(
width: item.width,
@@ -26,9 +34,7 @@ Widget content(bool isSave, BuildContext context, item, source, callback) {
);
}
TextStyle authorStyle =
TextStyle(color: Theme.of(context).colorScheme.primary);
InlineSpan? richNodes = richNode(item, context);
TextSpan? richNodes = richNode(theme, item, context);
return Container(
width: double.infinity,
@@ -36,24 +42,17 @@ Widget content(bool isSave, BuildContext context, item, source, callback) {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (item.modules.moduleDynamic.topic != null) ...[
GestureDetector(
child: Text(
'#${item.modules.moduleDynamic.topic.name}',
style: authorStyle,
),
if (item.modules.moduleDynamic?.topic != null) ...[
Text(
'#${item.modules.moduleDynamic!.topic!.name}',
style: TextStyle(color: theme.colorScheme.primary),
),
],
if (richNodes != null)
source == 'detail'
? SelectableRegion(
magnifierConfiguration: const TextMagnifierConfiguration(),
focusNode: FocusNode(),
selectionControls: MaterialTextSelectionControls(),
child: Text.rich(
style: TextStyle(fontSize: !isSave ? 16 : 15),
richNodes,
),
? SelectableText.rich(
richNodes,
style: TextStyle(fontSize: !isSave ? 16 : 15),
)
: Text.rich(
style: const TextStyle(fontSize: 15),
@@ -61,12 +60,8 @@ Widget content(bool isSave, BuildContext context, item, source, callback) {
maxLines: 6,
overflow: TextOverflow.ellipsis,
),
if (item.modules.moduleDynamic.major != null &&
item.modules.moduleDynamic.major.opus != null &&
item.modules.moduleDynamic.major.opus.pics.isNotEmpty)
Text.rich(
picsNodes(),
),
if (item.modules.moduleDynamic?.major?.opus?.pics?.isNotEmpty == true)
Text.rich(picsNodes()),
],
),
);

View File

@@ -29,6 +29,7 @@ class DynamicPanel extends StatelessWidget {
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final authorWidget = AuthorPanel(
item: item,
source: source,
@@ -45,7 +46,7 @@ class DynamicPanel extends StatelessWidget {
border: Border(
bottom: BorderSide(
width: 8,
color: Theme.of(context).dividerColor.withOpacity(0.05),
color: theme.dividerColor.withOpacity(0.05),
),
),
),
@@ -76,8 +77,8 @@ class DynamicPanel extends StatelessWidget {
),
if (item.modules.moduleDynamic!.desc != null ||
item.modules.moduleDynamic!.major != null)
content(isSave, context, item, source, callback),
forWard(isSave, item, context, source, callback),
content(theme, isSave, context, item, source, callback),
forWard(theme, isSave, item, context, source, callback),
const SizedBox(height: 2),
if (source == null) ActionPanel(item: item),
if (source == 'detail' && !isSave) const SizedBox(height: 12),
@@ -121,7 +122,6 @@ class DynamicPanel extends StatelessWidget {
return;
}
imageSaveDialog(
context: context,
title: title,
cover: cover,
);

View File

@@ -19,7 +19,10 @@ import 'pic_panel.dart';
import 'rich_node_panel.dart';
import 'video_panel.dart';
InlineSpan picsNodes(List<OpusPicsModel> pics, callback) {
InlineSpan picsNodes(
List<OpusPicsModel> pics,
Function(List<String>, int)? callback,
) {
return WidgetSpan(
child: LayoutBuilder(
builder: (context, constraints) => imageView(
@@ -40,7 +43,7 @@ InlineSpan picsNodes(List<OpusPicsModel> pics, callback) {
);
}
Widget _blockedItem(BuildContext context, DynamicItemModel item, source) {
Widget _blockedItem(ThemeData theme, DynamicItemModel item, String? source) {
return Container(
width: double.infinity,
padding: EdgeInsets.only(
@@ -53,7 +56,7 @@ Widget _blockedItem(BuildContext context, DynamicItemModel item, source) {
Text(
item.modules.moduleDynamic!.major!.blocked!['title'],
style: TextStyle(
color: Theme.of(context).colorScheme.secondary,
color: theme.colorScheme.secondary,
),
),
if (item.modules.moduleDynamic!.major!.blocked!['hint_message'] != null)
@@ -61,7 +64,7 @@ Widget _blockedItem(BuildContext context, DynamicItemModel item, source) {
item.modules.moduleDynamic!.major!.blocked!['hint_message'],
style: TextStyle(
fontSize: 12,
color: Theme.of(context).colorScheme.outline,
color: theme.colorScheme.outline,
),
),
],
@@ -70,15 +73,21 @@ Widget _blockedItem(BuildContext context, DynamicItemModel item, source) {
}
Widget forWard(
bool isSave, DynamicItemModel item, BuildContext context, source, callback,
{floor = 1}) {
ThemeData theme,
bool isSave,
DynamicItemModel item,
BuildContext context,
source,
callback, {
floor = 1,
}) {
switch (item.type) {
// 图文
case 'DYNAMIC_TYPE_DRAW':
bool hasPics =
item.modules.moduleDynamic?.major?.opus?.pics?.isNotEmpty == true;
InlineSpan? richNodes = richNode(item, context);
TextSpan? richNodes = richNode(theme, item, context);
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@@ -91,17 +100,15 @@ Widget forWard(
arguments: {'face': item.modules.moduleAuthor!.face}),
child: Text(
'@${item.modules.moduleAuthor!.name}',
style:
TextStyle(color: Theme.of(context).colorScheme.primary),
style: TextStyle(color: theme.colorScheme.primary),
),
),
const SizedBox(width: 6),
Text(
Utils.dateFormat(item.modules.moduleAuthor!.pubTs),
style: TextStyle(
color: Theme.of(context).colorScheme.outline,
fontSize:
Theme.of(context).textTheme.labelSmall!.fontSize),
color: theme.colorScheme.outline,
fontSize: theme.textTheme.labelSmall!.fontSize),
),
],
),
@@ -139,22 +146,24 @@ Widget forWard(
/// 附加内容 商品信息、直播预约等等
if (item.modules.moduleDynamic?.additional != null)
addWidget(
theme,
item,
context,
item.modules.moduleDynamic?.additional?.type,
floor: floor,
),
if (item.modules.moduleDynamic?.major?.blocked != null)
_blockedItem(context, item, source),
_blockedItem(theme, item, source),
],
);
// 视频
case 'DYNAMIC_TYPE_AV':
return videoSeasonWidget(source, item, context, 'archive', floor: floor);
return videoSeasonWidget(theme, source, item, context, 'archive',
floor: floor);
// 文章
case 'DYNAMIC_TYPE_ARTICLE':
return item.isForwarded == true
? articlePanel(source, item, context, callback, floor: floor)
? articlePanel(theme, source, item, context, callback, floor: floor)
: item.modules.moduleDynamic?.major?.blocked != null
? Padding(
padding: const EdgeInsets.symmetric(horizontal: 12),
@@ -168,7 +177,7 @@ Widget forWard(
Text(
item.modules.moduleDynamic!.major!.blocked!['title'],
style: TextStyle(
color: Theme.of(context).colorScheme.secondary,
color: theme.colorScheme.secondary,
),
),
if (item.modules.moduleDynamic?.major
@@ -179,7 +188,7 @@ Widget forWard(
.blocked!['hint_message'],
style: TextStyle(
fontSize: 12,
color: Theme.of(context).colorScheme.outline,
color: theme.colorScheme.outline,
),
)
],
@@ -225,29 +234,28 @@ Widget forWard(
return;
}
imageSaveDialog(
context: context,
title: title,
cover: cover,
);
},
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 8),
color: Theme.of(context).dividerColor.withOpacity(0.08),
child: forWard(isSave, item.orig!, context, source, callback,
color: theme.dividerColor.withOpacity(0.08),
child: forWard(theme, isSave, item.orig!, context, source, callback,
floor: floor + 1),
),
);
// 直播
case 'DYNAMIC_TYPE_LIVE_RCMD':
return liveRcmdPanel(source, item, context, floor: floor);
return liveRcmdPanel(theme, source, item, context, floor: floor);
// 直播
case 'DYNAMIC_TYPE_LIVE':
return livePanel(source, item, context, floor: floor);
return livePanel(theme, source, item, context, floor: floor);
// 合集
case 'DYNAMIC_TYPE_UGC_SEASON':
return videoSeasonWidget(source, item, context, 'ugcSeason');
return videoSeasonWidget(theme, source, item, context, 'ugcSeason');
case 'DYNAMIC_TYPE_WORD':
InlineSpan? richNodes = richNode(item, context);
late TextSpan? richNodes = richNode(theme, item, context);
return floor == 2
? Column(
crossAxisAlignment: CrossAxisAlignment.start,
@@ -260,17 +268,15 @@ Widget forWard(
arguments: {'face': item.modules.moduleAuthor?.face}),
child: Text(
'@${item.modules.moduleAuthor?.name}',
style: TextStyle(
color: Theme.of(context).colorScheme.primary),
style: TextStyle(color: theme.colorScheme.primary),
),
),
const SizedBox(width: 6),
Text(
Utils.dateFormat(item.modules.moduleAuthor?.pubTs),
style: TextStyle(
color: Theme.of(context).colorScheme.outline,
fontSize:
Theme.of(context).textTheme.labelSmall!.fontSize),
color: theme.colorScheme.outline,
fontSize: theme.textTheme.labelSmall!.fontSize),
),
],
),
@@ -294,18 +300,21 @@ Widget forWard(
)
: item.modules.moduleDynamic?.additional != null
? addWidget(
theme,
item,
context,
item.modules.moduleDynamic!.additional!.type,
floor: floor,
)
: item.modules.moduleDynamic?.major?.blocked != null
? _blockedItem(context, item, source)
? _blockedItem(theme, item, source)
: const SizedBox(height: 0);
case 'DYNAMIC_TYPE_PGC':
return videoSeasonWidget(source, item, context, 'pgc', floor: floor);
return videoSeasonWidget(theme, source, item, context, 'pgc',
floor: floor);
case 'DYNAMIC_TYPE_PGC_UNION':
return videoSeasonWidget(source, item, context, 'pgc', floor: floor);
return videoSeasonWidget(theme, source, item, context, 'pgc',
floor: floor);
// 直播结束
case 'DYNAMIC_TYPE_NONE':
return Row(
@@ -347,7 +356,7 @@ Widget forWard(
width: double.infinity,
padding:
const EdgeInsets.only(left: 12, top: 10, right: 12, bottom: 10),
color: Theme.of(context).dividerColor.withOpacity(0.08),
color: theme.dividerColor.withOpacity(0.08),
child: Row(
children: [
NetworkImgLayer(
@@ -365,7 +374,7 @@ Widget forWard(
Text(
item.modules.moduleDynamic!.major!.common!['title'],
style: TextStyle(
color: Theme.of(context).colorScheme.primary,
color: theme.colorScheme.primary,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
@@ -374,9 +383,8 @@ Widget forWard(
Text(
item.modules.moduleDynamic!.major!.common!['desc'],
style: TextStyle(
color: Theme.of(context).colorScheme.outline,
fontSize:
Theme.of(context).textTheme.labelMedium!.fontSize,
color: theme.colorScheme.outline,
fontSize: theme.textTheme.labelMedium!.fontSize,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
@@ -398,7 +406,7 @@ Widget forWard(
width: double.infinity,
padding:
const EdgeInsets.only(left: 12, top: 10, right: 12, bottom: 10),
color: Theme.of(context).dividerColor.withOpacity(0.08),
color: theme.dividerColor.withOpacity(0.08),
child: Row(
children: [
NetworkImgLayer(
@@ -415,7 +423,7 @@ Widget forWard(
Text(
music['title'],
style: TextStyle(
color: Theme.of(context).colorScheme.primary,
color: theme.colorScheme.primary,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
@@ -424,9 +432,8 @@ Widget forWard(
Text(
music['label'],
style: TextStyle(
color: Theme.of(context).colorScheme.outline,
fontSize:
Theme.of(context).textTheme.labelMedium!.fontSize,
color: theme.colorScheme.outline,
fontSize: theme.textTheme.labelMedium!.fontSize,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
@@ -464,9 +471,8 @@ Widget forWard(
item.modules.moduleAuthor!.vip!['status'] > 0 &&
item.modules.moduleAuthor!.vip!['type'] == 2
? context.vipColor
: Theme.of(context).colorScheme.onSurface,
fontSize:
Theme.of(context).textTheme.titleMedium!.fontSize,
: theme.colorScheme.onSurface,
fontSize: theme.textTheme.titleMedium!.fontSize,
),
),
],
@@ -510,10 +516,7 @@ Widget forWard(
Text(
item.modules.moduleDynamic!.major!.medialist!['title'],
style: TextStyle(
fontSize: Theme.of(context)
.textTheme
.titleMedium!
.fontSize,
fontSize: theme.textTheme.titleMedium!.fontSize,
fontWeight: FontWeight.bold),
),
if (item.modules.moduleDynamic?.major
@@ -524,11 +527,8 @@ Widget forWard(
item.modules.moduleDynamic!.major!
.medialist!['sub_title'],
style: TextStyle(
fontSize: Theme.of(context)
.textTheme
.labelLarge!
.fontSize,
color: Theme.of(context).colorScheme.outline),
fontSize: theme.textTheme.labelLarge!.fontSize,
color: theme.colorScheme.outline),
),
],
],

View File

@@ -1,4 +1,5 @@
import 'package:PiliPlus/common/widgets/image_save.dart';
import 'package:PiliPlus/models/dynamics/result.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:PiliPlus/common/widgets/network_img_layer.dart';
@@ -6,11 +7,19 @@ import 'package:PiliPlus/utils/utils.dart';
import 'rich_node_panel.dart';
Widget livePanel(source, item, context, {floor = 1}) {
dynamic content = item.modules.moduleDynamic.major;
late final TextStyle authorStyle =
TextStyle(color: Theme.of(context).colorScheme.primary);
InlineSpan? richNodes = richNode(item, context);
Widget livePanel(
ThemeData theme,
String? source,
DynamicItemModel item,
BuildContext context, {
int floor = 1,
}) {
DynamicMajorModel? content = item.modules.moduleDynamic!.major;
if (content == null) {
return const SizedBox.shrink();
}
late final authorStyle = TextStyle(color: theme.colorScheme.primary);
TextSpan? richNodes = richNode(theme, item, context);
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@@ -19,40 +28,41 @@ Widget livePanel(source, item, context, {floor = 1}) {
children: [
GestureDetector(
onTap: () => Get.toNamed(
'/member?mid=${item.modules.moduleAuthor.mid}',
arguments: {'face': item.modules.moduleAuthor.face}),
'/member?mid=${item.modules.moduleAuthor!.mid}',
arguments: {'face': item.modules.moduleAuthor!.face}),
child: Text(
'@${item.modules.moduleAuthor.name}',
'@${item.modules.moduleAuthor!.name}',
style: authorStyle,
),
),
const SizedBox(width: 6),
Text(
Utils.dateFormat(item.modules.moduleAuthor.pubTs),
Utils.dateFormat(item.modules.moduleAuthor?.pubTs),
style: TextStyle(
color: Theme.of(context).colorScheme.outline,
fontSize: Theme.of(context).textTheme.labelSmall!.fontSize),
color: theme.colorScheme.outline,
fontSize: theme.textTheme.labelSmall!.fontSize,
),
),
],
),
],
const SizedBox(height: 4),
if (item.modules.moduleDynamic.topic != null) ...[
if (item.modules.moduleDynamic?.topic != null) ...[
Padding(
padding: floor == 2
? EdgeInsets.zero
: const EdgeInsets.only(left: 12, right: 12),
child: GestureDetector(
child: Text(
'#${item.modules.moduleDynamic.topic.name}',
style: authorStyle,
),
child: Text(
'#${item.modules.moduleDynamic!.topic!.name}',
style: authorStyle,
),
),
const SizedBox(height: 6),
],
if (floor == 2 && item.modules.moduleDynamic.desc != null) ...[
if (richNodes != null) Text.rich(richNodes),
if (floor == 2 &&
item.modules.moduleDynamic?.desc != null &&
richNodes != null) ...[
Text.rich(richNodes),
const SizedBox(height: 6),
],
GestureDetector(
@@ -63,9 +73,8 @@ Widget livePanel(source, item, context, {floor = 1}) {
onLongPress: () {
Feedback.forLongPress(context);
imageSaveDialog(
context: context,
title: content.live.title,
cover: content.live.cover,
title: content.live!.title,
cover: content.live!.cover,
);
},
child: Row(
@@ -75,7 +84,7 @@ Widget livePanel(source, item, context, {floor = 1}) {
NetworkImgLayer(
width: 120,
height: 75,
src: content.live.cover,
src: content.live!.cover,
),
const SizedBox(width: 10),
Expanded(
@@ -84,26 +93,26 @@ Widget livePanel(source, item, context, {floor = 1}) {
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
content.live.title,
content.live!.title!,
maxLines: source == 'detail' ? null : 2,
overflow: source == 'detail' ? null : TextOverflow.ellipsis,
),
const SizedBox(height: 4),
Text(
content.live.descFirst,
style: TextStyle(
color: Theme.of(context).colorScheme.outline,
fontSize:
Theme.of(context).textTheme.labelMedium!.fontSize,
),
)
if (content.live?.descFirst != null)
Text(
content.live!.descFirst!,
style: TextStyle(
color: theme.colorScheme.outline,
fontSize: theme.textTheme.labelMedium!.fontSize,
),
)
],
),
),
Text(
content.live.badge['text'],
content.live!.badge!['text'],
style: TextStyle(
fontSize: Theme.of(context).textTheme.labelMedium!.fontSize,
fontSize: theme.textTheme.labelMedium!.fontSize,
),
)
],

View File

@@ -9,13 +9,21 @@ import 'package:PiliPlus/utils/utils.dart';
import 'rich_node_panel.dart';
Widget liveRcmdPanel(source, DynamicItemModel item, context, {floor = 1}) {
TextStyle authorStyle =
TextStyle(color: Theme.of(context).colorScheme.primary);
DynamicLiveModel liveRcmd = item.modules.moduleDynamic!.major!.liveRcmd!;
int liveStatus = liveRcmd.liveStatus!;
Map watchedShow = liveRcmd.watchedShow!;
InlineSpan? richNodes = richNode(item, context);
Widget liveRcmdPanel(
ThemeData theme,
String? source,
DynamicItemModel item,
BuildContext context, {
int floor = 1,
}) {
DynamicLiveModel? liveRcmd = item.modules.moduleDynamic?.major?.liveRcmd;
if (liveRcmd == null) {
return const SizedBox.shrink();
}
int? liveStatus = liveRcmd.liveStatus;
Map? watchedShow = liveRcmd.watchedShow;
TextSpan? richNodes = richNode(theme, item, context);
late final authorStyle = TextStyle(color: theme.colorScheme.primary);
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@@ -24,8 +32,9 @@ Widget liveRcmdPanel(source, DynamicItemModel item, context, {floor = 1}) {
children: [
GestureDetector(
onTap: () => Get.toNamed(
'/member?mid=${item.modules.moduleAuthor?.mid}',
arguments: {'face': item.modules.moduleAuthor?.face}),
'/member?mid=${item.modules.moduleAuthor?.mid}',
arguments: {'face': item.modules.moduleAuthor?.face},
),
child: Text(
'@${item.modules.moduleAuthor?.name}',
style: authorStyle,
@@ -35,8 +44,9 @@ Widget liveRcmdPanel(source, DynamicItemModel item, context, {floor = 1}) {
Text(
Utils.dateFormat(item.modules.moduleAuthor?.pubTs),
style: TextStyle(
color: Theme.of(context).colorScheme.outline,
fontSize: Theme.of(context).textTheme.labelSmall!.fontSize),
color: theme.colorScheme.outline,
fontSize: theme.textTheme.labelSmall!.fontSize,
),
),
],
),
@@ -46,27 +56,27 @@ Widget liveRcmdPanel(source, DynamicItemModel item, context, {floor = 1}) {
Padding(
padding:
const EdgeInsets.symmetric(horizontal: StyleString.safeSpace),
child: GestureDetector(
child: Text(
'#${item.modules.moduleDynamic!.topic!.name}',
style: authorStyle,
),
child: Text(
'#${item.modules.moduleDynamic!.topic!.name}',
style: authorStyle,
),
),
const SizedBox(height: 6),
],
if (floor == 2 && item.modules.moduleDynamic?.desc != null) ...[
if (richNodes != null) Text.rich(richNodes),
if (floor == 2 &&
item.modules.moduleDynamic?.desc != null &&
richNodes != null) ...[
Text.rich(richNodes),
const SizedBox(height: 6),
],
Padding(
padding:
const EdgeInsets.symmetric(horizontal: StyleString.safeSpace),
child: GestureDetector(
onTap: () {
PageUtils.pushDynDetail(item, floor);
},
child: LayoutBuilder(builder: (context, box) {
padding: const EdgeInsets.symmetric(horizontal: StyleString.safeSpace),
child: GestureDetector(
onTap: () {
PageUtils.pushDynDetail(item, floor);
},
child: LayoutBuilder(
builder: (context, box) {
double width = box.maxWidth;
return Stack(
children: [
@@ -75,33 +85,31 @@ Widget liveRcmdPanel(source, DynamicItemModel item, context, {floor = 1}) {
child: NetworkImgLayer(
width: width,
height: width / StyleString.aspectRatio,
src: item.modules.moduleDynamic?.major?.liveRcmd?.cover,
src: liveRcmd.cover,
),
),
PBadge(
text: watchedShow['text_large'],
text: watchedShow?['text_large'],
top: 6,
right: 56,
bottom: null,
left: null,
type: 'gray',
),
PBadge(
text: liveStatus == 1 ? '直播中' : '直播结束',
top: 6,
right: 6,
bottom: null,
left: null,
),
Positioned(
left: 0,
right: 0,
bottom: 0,
child: Container(
height: 80,
padding: const EdgeInsets.fromLTRB(12, 0, 10, 10),
clipBehavior: Clip.hardEdge,
decoration: BoxDecoration(
if (liveRcmd.areaName != null)
Positioned(
left: 0,
right: 0,
bottom: 0,
child: Container(
height: 80,
alignment: Alignment.bottomLeft,
padding: const EdgeInsets.fromLTRB(12, 0, 10, 10),
clipBehavior: Clip.hardEdge,
decoration: BoxDecoration(
gradient: const LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
@@ -111,45 +119,42 @@ Widget liveRcmdPanel(source, DynamicItemModel item, context, {floor = 1}) {
],
),
borderRadius: floor == 1
? StyleString.mdRadius
: const BorderRadius.all(Radius.circular(6))),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
DefaultTextStyle.merge(
style: TextStyle(
fontSize: Theme.of(context)
.textTheme
.labelMedium!
.fontSize,
color: Colors.white),
child: Row(
children: [
Text(item.modules.moduleDynamic?.major?.liveRcmd
?.areaName ??
''),
],
),
? const BorderRadius.only(
bottomLeft: StyleString.imgRadius,
bottomRight: StyleString.imgRadius,
)
: const BorderRadius.only(
bottomLeft: Radius.circular(6),
bottomRight: Radius.circular(6),
),
),
child: Text(
liveRcmd.areaName!,
style: TextStyle(
fontSize: theme.textTheme.labelMedium!.fontSize,
color: Colors.white,
),
],
),
),
),
),
],
);
}),
)),
const SizedBox(height: 6),
Padding(
padding: const EdgeInsets.symmetric(horizontal: StyleString.safeSpace),
child: Text(
item.modules.moduleDynamic!.major!.liveRcmd!.title!,
maxLines: source == 'detail' ? null : 1,
style: const TextStyle(fontWeight: FontWeight.bold),
overflow: source == 'detail' ? null : TextOverflow.ellipsis,
},
),
),
),
const SizedBox(height: 6),
if (liveRcmd.title != null)
Padding(
padding:
const EdgeInsets.symmetric(horizontal: StyleString.safeSpace),
child: Text(
liveRcmd.title!,
maxLines: source == 'detail' ? null : 1,
style: const TextStyle(fontWeight: FontWeight.bold),
overflow: source == 'detail' ? null : TextOverflow.ellipsis,
),
),
const SizedBox(height: 2),
],
);

View File

@@ -1,9 +1,14 @@
import 'package:PiliPlus/common/widgets/image_view.dart';
import 'package:PiliPlus/models/dynamics/result.dart';
import 'package:flutter/material.dart';
Widget picWidget(item, context, callback) {
if (item.modules.moduleDynamic.major?.draw?.items == null ||
item.modules.moduleDynamic.major.type == 'MAJOR_TYPE_OPUS') {
Widget picWidget(
DynamicItemModel item,
BuildContext context,
Function(List<String>, int)? callback,
) {
if (item.modules.moduleDynamic?.major?.draw?.items == null ||
item.modules.moduleDynamic?.major?.type == 'MAJOR_TYPE_OPUS') {
/// fix 图片跟rich_node_panel重复
// pictures = item.modules.moduleDynamic.major.opus.pics;
return const SizedBox.shrink();
@@ -11,7 +16,7 @@ Widget picWidget(item, context, callback) {
return LayoutBuilder(
builder: (context, constraints) => imageView(
constraints.maxWidth,
(item.modules.moduleDynamic.major.draw.items as List)
(item.modules.moduleDynamic!.major!.draw!.items as List)
.map(
(item) => ImageModel(
width: item.width,

View File

@@ -10,27 +10,27 @@ import 'package:PiliPlus/http/search.dart';
import 'package:PiliPlus/utils/app_scheme.dart';
// 富文本
InlineSpan? richNode(item, BuildContext context) {
final spacer = _VerticalSpaceSpan(0.0);
TextSpan? richNode(
ThemeData theme,
DynamicItemModel item,
BuildContext context,
) {
try {
TextStyle authorStyle =
TextStyle(color: Theme.of(context).colorScheme.primary);
late final authorStyle = TextStyle(color: theme.colorScheme.primary);
List<InlineSpan> spanChildren = [];
List<RichTextNodeItem>? richTextNodes;
if (item.modules.moduleDynamic.desc != null) {
richTextNodes = item.modules.moduleDynamic.desc.richTextNodes;
} else if (item.modules.moduleDynamic.major != null) {
if (item.modules.moduleDynamic?.desc != null) {
richTextNodes = item.modules.moduleDynamic!.desc!.richTextNodes;
} else if (item.modules.moduleDynamic?.major != null) {
// 动态页面 richTextNodes 层级可能与主页动态层级不同
richTextNodes =
item.modules.moduleDynamic.major.opus?.summary?.richTextNodes;
if (item.modules.moduleDynamic.major.opus?.title != null) {
item.modules.moduleDynamic!.major!.opus?.summary?.richTextNodes;
if (item.modules.moduleDynamic?.major?.opus?.title != null) {
spanChildren.add(
TextSpan(
text: item.modules.moduleDynamic.major.opus.title + '\n',
style: Theme.of(context)
.textTheme
.titleMedium!
text: '${item.modules.moduleDynamic!.major!.opus!.title!}\n',
style: theme.textTheme.titleMedium!
.copyWith(fontWeight: FontWeight.bold),
),
);
@@ -42,7 +42,8 @@ InlineSpan? richNode(item, BuildContext context) {
for (var i in richTextNodes) {
if (i.type == 'RICH_TEXT_NODE_TYPE_TEXT') {
spanChildren.add(
TextSpan(text: i.origText, style: const TextStyle(height: 1.65)));
TextSpan(text: i.origText, style: const TextStyle(height: 1.65)),
);
}
// @用户
else if (i.type == 'RICH_TEXT_NODE_TYPE_AT') {
@@ -53,8 +54,7 @@ InlineSpan? richNode(item, BuildContext context) {
mainAxisSize: MainAxisSize.min,
children: [
GestureDetector(
onTap: () => Get.toNamed('/member?mid=${i.rid}',
arguments: {'face': null}),
onTap: () => Get.toNamed('/member?mid=${i.rid}'),
child: Text(
' ${i.text}',
style: authorStyle,
@@ -88,7 +88,7 @@ InlineSpan? richNode(item, BuildContext context) {
child: Icon(
Icons.link,
size: 20,
color: Theme.of(context).colorScheme.primary,
color: theme.colorScheme.primary,
),
),
);
@@ -120,14 +120,12 @@ InlineSpan? richNode(item, BuildContext context) {
child: GestureDetector(
onTap: () {
try {
String dynamicId = item.basic.commentIdStr;
String dynamicId = item.basic!.commentIdStr!;
Get.toNamed(
'/webview',
parameters: {
'url':
'https://t.bilibili.com/vote/h5/index/#/result?vote_id=${i.rid}&dynamic_id=$dynamicId&isWeb=1',
'type': 'vote',
'pageTitle': '投票'
},
);
} catch (_) {}
@@ -161,7 +159,7 @@ InlineSpan? richNode(item, BuildContext context) {
child: Icon(
Icons.redeem_rounded,
size: 16,
color: Theme.of(context).colorScheme.primary,
color: theme.colorScheme.primary,
),
),
);
@@ -195,7 +193,7 @@ InlineSpan? richNode(item, BuildContext context) {
child: Icon(
Icons.shopping_bag_outlined,
size: 16,
color: Theme.of(context).colorScheme.primary,
color: theme.colorScheme.primary,
),
),
);
@@ -220,7 +218,7 @@ InlineSpan? richNode(item, BuildContext context) {
child: Icon(
Icons.play_circle_outline_outlined,
size: 16,
color: Theme.of(context).colorScheme.primary,
color: theme.colorScheme.primary,
),
),
);
@@ -234,7 +232,6 @@ InlineSpan? richNode(item, BuildContext context) {
PageUtils.toVideoPage(
'bvid=${i.rid}&cid=$cid',
arguments: {
'pic': null,
'heroTag': Utils.makeHeroTag(i.rid),
},
);
@@ -285,11 +282,6 @@ InlineSpan? richNode(item, BuildContext context) {
}
} catch (err) {
debugPrint('❌rich_node_panel err: $err');
return spacer;
return null;
}
}
class _VerticalSpaceSpan extends WidgetSpan {
_VerticalSpaceSpan(double height)
: super(child: SizedBox(height: height, width: double.infinity));
}

View File

@@ -27,6 +27,7 @@ class _UpPanelState extends State<UpPanel> {
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
if (widget.dynamicsController.isLogin.value.not) {
return const SizedBox.shrink();
}
@@ -74,14 +75,15 @@ class _UpPanelState extends State<UpPanel> {
SliverList.builder(
itemCount: liveList.length,
itemBuilder: (context, index) {
return upItemBuild(liveList[index]);
return upItemBuild(theme, liveList[index]);
},
),
SliverToBoxAdapter(
child: upItemBuild(UpItem(face: '', uname: '全部动态', mid: -1)),
child: upItemBuild(theme, UpItem(face: '', uname: '全部动态', mid: -1)),
),
SliverToBoxAdapter(
child: upItemBuild(
theme,
UpItem(
uname: '',
face: widget.dynamicsController.face,
@@ -93,7 +95,7 @@ class _UpPanelState extends State<UpPanel> {
SliverList.builder(
itemCount: upList.length,
itemBuilder: (context, index) {
return upItemBuild(upList[index]);
return upItemBuild(theme, upList[index]);
},
),
const SliverToBoxAdapter(child: SizedBox(height: 200)),
@@ -101,7 +103,7 @@ class _UpPanelState extends State<UpPanel> {
);
}
Widget upItemBuild(data) {
Widget upItemBuild(theme, data) {
bool isCurrent = widget.dynamicsController.currentMid == data.mid ||
widget.dynamicsController.currentMid == -1;
return SizedBox(
@@ -163,17 +165,14 @@ class _UpPanelState extends State<UpPanel> {
child: Badge(
smallSize: 8,
label: data.type == 'live' ? const Text(' Live ') : null,
textColor:
Theme.of(context).colorScheme.onSecondaryContainer,
textColor: theme.colorScheme.onSecondaryContainer,
alignment: AlignmentDirectional.topStart,
isLabelVisible: data.type == 'live' ||
(data.type == 'up' && (data.hasUpdate ?? false)),
backgroundColor: data.type == 'live'
? Theme.of(context)
.colorScheme
.secondaryContainer
? theme.colorScheme.secondaryContainer
.withOpacity(0.75)
: Theme.of(context).colorScheme.primary,
: theme.colorScheme.primary,
),
),
],
@@ -189,8 +188,8 @@ class _UpPanelState extends State<UpPanel> {
textAlign: TextAlign.center,
style: TextStyle(
color: widget.dynamicsController.currentMid == data.mid
? Theme.of(context).colorScheme.primary
: Theme.of(context).colorScheme.outline,
? theme.colorScheme.primary
: theme.colorScheme.outline,
height: 1.1,
fontSize: 12.5,
),
@@ -203,31 +202,3 @@ class _UpPanelState extends State<UpPanel> {
);
}
}
class UpPanelSkeleton extends StatelessWidget {
const UpPanelSkeleton({super.key});
@override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: 50,
height: 50,
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.onInverseSurface,
borderRadius: BorderRadius.circular(50),
),
),
Container(
margin: const EdgeInsets.only(top: 6),
width: 45,
height: 12,
color: Theme.of(context).colorScheme.onInverseSurface,
),
],
);
}
}

View File

@@ -1,4 +1,5 @@
// 视频or合集
import 'package:PiliPlus/models/dynamics/result.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:PiliPlus/common/constants.dart';
@@ -8,21 +9,28 @@ import 'package:PiliPlus/utils/utils.dart';
import 'rich_node_panel.dart';
Widget videoSeasonWidget(source, item, context, type, {floor = 1}) {
if (item.modules.moduleDynamic.major?.type == 'MAJOR_TYPE_NONE') {
return item.modules.moduleDynamic.major?.none?.tips != null
Widget videoSeasonWidget(
ThemeData theme,
String? source,
DynamicItemModel item,
BuildContext context,
String type, {
floor = 1,
}) {
if (item.modules.moduleDynamic?.major?.type == 'MAJOR_TYPE_NONE') {
return item.modules.moduleDynamic?.major?.none?.tips != null
? Row(
children: [
Icon(
Icons.error,
size: 18,
color: Theme.of(context).colorScheme.outline,
color: theme.colorScheme.outline,
),
const SizedBox(width: 5),
Text(
'${item.modules.moduleDynamic.major.none.tips}',
item.modules.moduleDynamic!.major!.none!.tips!,
style: TextStyle(
color: Theme.of(context).colorScheme.outline,
color: theme.colorScheme.outline,
),
),
],
@@ -30,8 +38,6 @@ Widget videoSeasonWidget(source, item, context, type, {floor = 1}) {
: const SizedBox.shrink();
}
TextStyle authorStyle =
TextStyle(color: Theme.of(context).colorScheme.primary);
// type archive ugcSeason
// archive 视频/显示发布人
// ugcSeason 合集/不显示发布人
@@ -39,93 +45,97 @@ Widget videoSeasonWidget(source, item, context, type, {floor = 1}) {
// floor 1 2
// 1 投稿视频 铺满 borderRadius 0
// 2 转发视频 铺满 borderRadius 6
Map<dynamic, dynamic> dynamicProperty = {
'ugcSeason': item.modules.moduleDynamic.major.ugcSeason,
'archive': item.modules.moduleDynamic.major.archive,
'pgc': item.modules.moduleDynamic.major.pgc
DynamicArchiveModel? content = switch (type) {
'ugcSeason' => item.modules.moduleDynamic?.major?.ugcSeason,
'archive' => item.modules.moduleDynamic?.major?.archive,
'pgc' => item.modules.moduleDynamic?.major?.pgc,
_ => null,
};
dynamic content = dynamicProperty[type];
InlineSpan? richNodes = richNode(item, context);
if (content == null) {
return const SizedBox.shrink();
}
TextSpan? richNodes = richNode(theme, item, context);
Widget buildCover() {
if (content?.cover == null) {
return const SizedBox.shrink();
}
return LayoutBuilder(builder: (context, box) {
double width = box.maxWidth;
return Stack(
children: [
NetworkImgLayer(
width: width,
height: width / StyleString.aspectRatio,
src: content.cover,
semanticsLabel: content.title,
),
if (content?.badge?['text'] != null)
PBadge(
text: content.badge['text'],
top: 8.0,
right: 10.0,
bottom: null,
left: null,
type: content.badge['text'] == '充电专属' ? 'error' : 'primary',
return LayoutBuilder(
builder: (context, box) {
double width = box.maxWidth;
return Stack(
children: [
NetworkImgLayer(
width: width,
height: width / StyleString.aspectRatio,
src: content.cover,
),
Positioned(
left: 0,
right: 0,
bottom: 0,
child: Container(
height: 70,
padding: const EdgeInsets.fromLTRB(10, 0, 8, 8),
clipBehavior: Clip.hardEdge,
decoration: BoxDecoration(
gradient: const LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: <Color>[
Colors.transparent,
Colors.black54,
],
if (content.badge?['text'] != null)
PBadge(
text: content.badge!['text'],
top: 8.0,
right: 10.0,
bottom: null,
left: null,
type: content.badge!['text'] == '充电专属' ? 'error' : 'primary',
),
Positioned(
left: 0,
right: 0,
bottom: 0,
child: Container(
height: 70,
alignment: Alignment.bottomLeft,
padding: const EdgeInsets.fromLTRB(10, 0, 8, 8),
clipBehavior: Clip.hardEdge,
decoration: BoxDecoration(
gradient: const LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Colors.transparent,
Colors.black54,
],
),
borderRadius: const BorderRadius.only(
bottomLeft: StyleString.imgRadius,
bottomRight: StyleString.imgRadius,
),
),
borderRadius: StyleString.mdRadius,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
DefaultTextStyle.merge(
style: TextStyle(
fontSize:
Theme.of(context).textTheme.labelMedium!.fontSize,
color: Colors.white),
child: Row(
children: [
if (content.durationText != null)
Text(
content.durationText,
semanticsLabel:
'时长${Utils.durationReadFormat(content.durationText)}',
),
if (content.durationText != null)
const SizedBox(width: 6),
Text(content.stat.play + '次围观'),
child: DefaultTextStyle.merge(
style: TextStyle(
fontSize: theme.textTheme.labelMedium!.fontSize,
color: Colors.white,
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
if (content.durationText != null) ...[
Text(
content.durationText!,
semanticsLabel:
'时长${Utils.durationReadFormat(content.durationText!)}',
),
const SizedBox(width: 6),
Text(content.stat.danmu + '条弹幕')
],
),
Text('${content.stat?.play}次围观'),
const SizedBox(width: 6),
Text('${content.stat?.danmu}条弹幕'),
const Spacer(),
Image.asset(
'assets/images/play.png',
width: 50,
height: 50,
),
],
),
Image.asset(
'assets/images/play.png',
width: 50,
height: 50,
),
],
),
),
),
),
],
);
});
],
);
},
);
}
return Column(
@@ -137,45 +147,50 @@ Widget videoSeasonWidget(source, item, context, type, {floor = 1}) {
children: [
GestureDetector(
onTap: () => Get.toNamed(
'/member?mid=${item.modules.moduleAuthor.mid}',
arguments: {'face': item.modules.moduleAuthor.face}),
'/member?mid=${item.modules.moduleAuthor!.mid}',
arguments: {'face': item.modules.moduleAuthor!.face},
),
child: Text(
item.modules.moduleAuthor.type == null
? '@${item.modules.moduleAuthor.name}'
: item.modules.moduleAuthor.name,
style: authorStyle,
item.modules.moduleAuthor?.type == null
? '@${item.modules.moduleAuthor!.name}'
: item.modules.moduleAuthor!.name!,
style: TextStyle(color: theme.colorScheme.primary),
),
),
const SizedBox(width: 6),
Text(
Utils.dateFormat(item.modules.moduleAuthor.pubTs),
style: TextStyle(
color: Theme.of(context).colorScheme.outline,
fontSize: Theme.of(context).textTheme.labelSmall!.fontSize),
),
if (item.modules.moduleAuthor?.pubTs != null)
Text(
Utils.dateFormat(item.modules.moduleAuthor!.pubTs),
style: TextStyle(
color: theme.colorScheme.outline,
fontSize: theme.textTheme.labelSmall!.fontSize,
),
),
],
),
const SizedBox(height: 6),
],
if (floor == 2 && item.modules.moduleDynamic.desc != null) ...[
if (richNodes != null) Text.rich(richNodes),
if (floor == 2 && content.desc != null && richNodes != null) ...[
Text.rich(richNodes),
const SizedBox(height: 6),
],
if (item.isForwarded == true)
buildCover()
else
Padding(
padding: EdgeInsets.symmetric(horizontal: StyleString.safeSpace),
child: buildCover(),
),
if (content.cover != null)
if (item.isForwarded == true)
buildCover()
else
Padding(
padding:
const EdgeInsets.symmetric(horizontal: StyleString.safeSpace),
child: buildCover(),
),
const SizedBox(height: 6),
if (content?.title != null)
if (content.title != null)
Padding(
padding: floor == 1
? const EdgeInsets.only(left: 12, right: 12)
: EdgeInsets.zero,
child: Text(
content.title,
content.title!,
maxLines: source == 'detail' ? null : 1,
style: const TextStyle(fontWeight: FontWeight.bold),
overflow: source == 'detail' ? null : TextOverflow.ellipsis,