Signed-off-by: dom <githubaccount56556@proton.me>
This commit is contained in:
dom
2026-03-23 11:47:56 +08:00
parent 1724f0d202
commit 9578f948b4
20 changed files with 132 additions and 77 deletions

View File

@@ -1,4 +1,5 @@
import 'package:PiliPlus/common/assets.dart';
import 'package:PiliPlus/common/style.dart';
import 'package:PiliPlus/common/widgets/image/network_img_layer.dart';
import 'package:PiliPlus/models/common/avatar_badge_type.dart';
import 'package:PiliPlus/models/common/image_type.dart';
@@ -18,6 +19,8 @@ class PendantAvatar extends StatelessWidget {
this.pendantImage,
this.pendentOffset = 6,
this.roomId,
this.liveBottom,
this.liveFontSize,
this.onTap,
}) : preferredSize = size,
badgeSize = badgeSize ?? size / 3,
@@ -31,7 +34,7 @@ class PendantAvatar extends StatelessWidget {
? .institution
: .none;
static bool showDynDecorate = Pref.showDynDecorate;
static bool showDecorate = Pref.showDecorate;
final BadgeType badgeType;
final String? url;
@@ -40,12 +43,14 @@ class PendantAvatar extends StatelessWidget {
final String? pendantImage;
final double pendentOffset;
final int? roomId;
final double? liveBottom;
final double? liveFontSize;
final VoidCallback? onTap;
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
final showPendant = showDynDecorate && pendantImage?.isNotEmpty == true;
final showPendant = showDecorate && pendantImage?.isNotEmpty == true;
final size = showPendant ? preferredSize - pendentOffset : preferredSize;
Widget? pendant;
if (showPendant) {
@@ -84,39 +89,8 @@ class PendantAvatar extends StatelessWidget {
avatar,
?pendant,
if (roomId != null)
Positioned(
bottom: 0,
child: InkWell(
onTap: () => PageUtils.toLiveRoom(roomId),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 5, vertical: 1),
decoration: BoxDecoration(
color: colorScheme.secondaryContainer,
borderRadius: const BorderRadius.all(Radius.circular(36)),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
size: 16,
applyTextScaling: true,
Icons.equalizer_rounded,
color: colorScheme.onSecondaryContainer,
),
Text(
'直播中',
style: TextStyle(
height: 1,
fontSize: 13,
color: colorScheme.onSecondaryContainer,
),
),
],
),
),
),
)
else if (badgeType != BadgeType.none)
_buildLive(colorScheme)
else if (badgeType != .none)
_buildBadge(context, colorScheme),
],
);
@@ -129,9 +103,45 @@ class PendantAvatar extends StatelessWidget {
return child;
}
Widget _buildLive(ColorScheme colorScheme) {
final fontSize = liveFontSize ?? 13.0;
return Positioned(
bottom: liveBottom ?? 0.0,
child: GestureDetector(
onTap: () => PageUtils.toLiveRoom(roomId),
child: Container(
padding: const .symmetric(horizontal: 5, vertical: 1),
decoration: BoxDecoration(
color: colorScheme.secondaryContainer,
borderRadius: Style.mdRadius,
),
child: Row(
mainAxisSize: .min,
children: [
Icon(
size: fontSize + 3,
applyTextScaling: true,
Icons.equalizer_rounded,
color: colorScheme.onSecondaryContainer,
),
Text(
'直播中',
style: TextStyle(
height: 1,
fontSize: fontSize,
color: colorScheme.onSecondaryContainer,
),
),
],
),
),
),
);
}
Widget _buildBadge(BuildContext context, ColorScheme colorScheme) {
final child = switch (badgeType) {
BadgeType.vip => Image.asset(
.vip => Image.asset(
Assets.vipIcon,
width: badgeSize,
height: badgeSize,

View File

@@ -424,7 +424,7 @@ class ModuleAuthorModel extends Avatar {
pubTime = json['pub_time'];
pubTs = json['pub_ts'] == 0 ? null : Utils.safeToInt(json['pub_ts']);
type = json['type'];
if (PendantAvatar.showDynDecorate) {
if (PendantAvatar.showDecorate) {
decorate = json['decorate'] == null
? null
: Decorate.fromJson(json['decorate']);

View File

@@ -2,6 +2,7 @@ import 'package:PiliPlus/models/model_owner.dart';
import 'package:PiliPlus/models_new/live/live_danmaku/live_emote.dart';
import 'package:PiliPlus/models_new/live/live_medal_wall/uinfo_medal.dart';
import 'package:PiliPlus/pages/danmaku/danmaku_model.dart';
import 'package:PiliPlus/utils/global_data.dart';
class DanmakuMsg {
final String name;
@@ -55,7 +56,9 @@ class DanmakuMsg {
ts: checkInfo['ts'],
ct: checkInfo['ct'],
),
medalInfo: medal == null ? null : UinfoMedal.fromJson(medal),
medalInfo: !GlobalData().showMedal || medal == null
? null
: UinfoMedal.fromJson(medal),
);
}
@@ -66,5 +69,6 @@ class DanmakuMsg {
'uemote': ?uemote?.toJson(),
'reply': ?reply?.toJson(),
'extra': extra.toJson(),
'medal': ?medalInfo?.toJson(),
};
}

View File

@@ -23,4 +23,13 @@ class UinfoMedal {
v2MedalColorStart: json['v2_medal_color_start'] as String?,
v2MedalColorText: json['v2_medal_color_text'] as String?,
);
Map<String, dynamic> toJson() => {
'name': name,
'level': level,
'id': id,
'ruid': ruid,
'v2_medal_color_start': v2MedalColorStart,
'v2_medal_color_text': v2MedalColorText,
};
}

View File

@@ -1,5 +1,6 @@
import 'package:PiliPlus/models_new/live/live_medal_wall/uinfo_medal.dart';
import 'package:PiliPlus/models_new/live/live_superchat/user_info.dart';
import 'package:PiliPlus/utils/global_data.dart';
import 'package:PiliPlus/utils/parse_string.dart';
import 'package:PiliPlus/utils/utils.dart';
@@ -50,6 +51,16 @@ class SuperChatItem {
},
'token': '',
'ts': 0,
'uinfo': {
'medal': {
"name": "MedalName",
"level": Utils.random.nextInt(40),
"id": 123,
"ruid": 456,
"v2_medal_color_start": "#4C7DFF99",
"v2_medal_color_text": "#FFFFFF",
},
},
});
factory SuperChatItem.fromJson(Map<String, dynamic> json) => SuperChatItem(
@@ -66,7 +77,7 @@ class SuperChatItem {
token: json['token'],
ts: Utils.safeToInt(json['ts'])!,
userInfo: UserInfo.fromJson(json['user_info'] as Map<String, dynamic>),
medalInfo: json['uinfo']?['medal'] == null
medalInfo: !GlobalData().showMedal || json['uinfo']?['medal'] == null
? null
: UinfoMedal.fromJson(json['uinfo']['medal']),
);
@@ -119,5 +130,6 @@ class SuperChatItem {
'token': token,
'ts': ts,
'user_info': userInfo.toJson(),
'medal': ?medalInfo?.toJson(),
};
}

View File

@@ -758,9 +758,7 @@ Widget moduleBlockedItem(
padding: padding,
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
visualDensity: visualDensity,
backgroundColor: isDarkMode
? const Color(0xFF8F0030)
: const Color(0xFFFF6699),
backgroundColor: theme.colorScheme.btnColor,
foregroundColor: Colors.white,
shape: shape,
),

View File

@@ -200,7 +200,10 @@ class _Item extends StatelessWidget {
crossAxisAlignment: .start,
children: [
child,
MedalWidget.fromMedalInfo(medal: uinfoMedal),
MedalWidget.fromMedalInfo(
medal: uinfoMedal,
padding: MedalWidget.mediumPadding,
),
],
);
} catch (e, s) {

View File

@@ -31,6 +31,7 @@ import 'package:PiliPlus/utils/danmaku_utils.dart';
import 'package:PiliPlus/utils/duration_utils.dart';
import 'package:PiliPlus/utils/extension/iterable_ext.dart';
import 'package:PiliPlus/utils/extension/size_ext.dart';
import 'package:PiliPlus/utils/global_data.dart';
import 'package:PiliPlus/utils/num_utils.dart';
import 'package:PiliPlus/utils/platform_utils.dart';
import 'package:PiliPlus/utils/storage_pref.dart';
@@ -486,7 +487,6 @@ class LiveRoomController extends GetxController {
name: extra['reply_uname'],
);
}
final medal = user['medal'];
addDm(
DanmakuMsg(
name: name,
@@ -497,7 +497,9 @@ class LiveRoomController extends GetxController {
uemote: uemote,
extra: liveExtra,
reply: reply,
medalInfo: medal == null ? null : UinfoMedal.fromJson(medal),
medalInfo: !GlobalData().showMedal || user['medal'] == null
? null
: UinfoMedal.fromJson(user['medal']),
),
DanmakuContentItem(
msg,

View File

@@ -154,7 +154,10 @@ class _SuperChatCardState extends State<SuperChatCard> {
spacing: 5,
children: [
Flexible(child: name),
MedalWidget.fromMedalInfo(medal: medal),
MedalWidget.fromMedalInfo(
medal: medal,
padding: MedalWidget.mediumPadding,
),
],
);
} catch (e, s) {

View File

@@ -63,8 +63,11 @@ class LiveRoomChatPanel extends StatelessWidget {
try {
medal = WidgetSpan(
child: Padding(
padding: const .symmetric(horizontal: 3),
child: MedalWidget.fromMedalInfo(medal: medalInfo),
padding: const .only(right: 4),
child: MedalWidget.fromMedalInfo(
medal: medalInfo,
padding: MedalWidget.mediumPadding,
),
),
);
} catch (e, s) {
@@ -78,21 +81,17 @@ class LiveRoomChatPanel extends StatelessWidget {
child: Builder(
builder: (itemContext) {
return Container(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 4,
),
padding: const .symmetric(horizontal: 10, vertical: 4),
decoration: BoxDecoration(
color: bg,
borderRadius: const BorderRadius.all(
Radius.circular(14),
),
borderRadius: const .all(.circular(14)),
),
child: Text.rich(
TextSpan(
children: [
?medal,
TextSpan(
text: item.name,
text: '${item.name}: ',
style: TextStyle(
color: nameColor,
fontSize: 14,
@@ -107,14 +106,6 @@ class LiveRoomChatPanel extends StatelessWidget {
item,
)),
),
?medal,
TextSpan(
text: ': ',
style: TextStyle(
color: nameColor,
fontSize: 14,
),
),
if (item.reply case final reply?)
TextSpan(
text: '@${reply.name} ',

View File

@@ -124,9 +124,7 @@ class MedalWall extends StatelessWidget {
padding: const .symmetric(horizontal: 8, vertical: 3),
decoration: BoxDecoration(
borderRadius: const .all(.circular(3)),
color: colorScheme.isDark
? const Color(0xFF8F0030)
: const Color(0xFFFF6699),
color: colorScheme.btnColor,
),
child: const Text(
'佩戴中',

View File

@@ -38,6 +38,8 @@ class MedalWidget extends StatelessWidget {
final StrutStyle strutStyle;
final EdgeInsets padding;
static const mediumPadding = EdgeInsets.symmetric(horizontal: 6, vertical: 3);
@override
Widget build(BuildContext context) {
return Container(

View File

@@ -200,7 +200,7 @@ class UserInfoCard extends StatelessWidget {
),
if (card.vip?.status == 1)
Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3),
padding: const .symmetric(horizontal: 8, vertical: 3),
decoration: BoxDecoration(
borderRadius: Style.mdRadius,
color: colorScheme.vipColor,

View File

@@ -32,6 +32,8 @@ class SearchUserItem extends StatelessWidget {
item.upic,
size: 42,
officialType: item.officialVerify?.type,
liveBottom: -5,
liveFontSize: 11,
roomId: item.isLive == 1 ? item.roomId : null,
),
const SizedBox(width: 10),

View File

@@ -32,6 +32,7 @@ import 'package:PiliPlus/utils/accounts.dart';
import 'package:PiliPlus/utils/cache_manager.dart';
import 'package:PiliPlus/utils/extension/num_ext.dart';
import 'package:PiliPlus/utils/feed_back.dart';
import 'package:PiliPlus/utils/global_data.dart';
import 'package:PiliPlus/utils/image_utils.dart';
import 'package:PiliPlus/utils/path_utils.dart';
import 'package:PiliPlus/utils/platform_utils.dart';
@@ -329,9 +330,16 @@ List<SettingsModel> get extraSettings => [
SwitchModel(
title: '展示头像/评论/动态装饰',
leading: const Icon(MdiIcons.stickerCircleOutline),
setKey: SettingBoxKey.showDynDecorate,
setKey: SettingBoxKey.showDecorate,
defaultVal: true,
onChanged: (value) => PendantAvatar.showDynDecorate = value,
onChanged: (value) => PendantAvatar.showDecorate = value,
),
SwitchModel(
title: '显示粉丝勋章',
leading: const Icon(MdiIcons.medalOutline),
setKey: SettingBoxKey.showMedal,
defaultVal: true,
onChanged: (value) => GlobalData().showMedal = value,
),
SwitchModel(
title: '预览 Live Photo',

View File

@@ -30,6 +30,7 @@ import 'package:PiliPlus/utils/extension/context_ext.dart';
import 'package:PiliPlus/utils/extension/num_ext.dart';
import 'package:PiliPlus/utils/extension/theme_ext.dart';
import 'package:PiliPlus/utils/feed_back.dart';
import 'package:PiliPlus/utils/global_data.dart';
import 'package:PiliPlus/utils/image_utils.dart';
import 'package:PiliPlus/utils/page_utils.dart';
import 'package:PiliPlus/utils/platform_utils.dart';
@@ -188,7 +189,8 @@ class ReplyItemGrpc extends StatelessWidget {
isStack: false,
fontSize: 9,
)
else if (member.hasFansMedalLevel())
else if (GlobalData().showMedal &&
member.hasFansMedalLevel())
MedalWidget(
medalName: member.fansMedalName,
level: member.fansMedalLevel.toInt(),
@@ -233,7 +235,7 @@ class ReplyItemGrpc extends StatelessWidget {
],
),
);
if (PendantAvatar.showDynDecorate) {
if (PendantAvatar.showDecorate) {
final garb = replyItem.memberV2.garb;
if (garb.hasCardImage()) {
const double height = 38.0;

View File

@@ -1,9 +1,14 @@
import 'package:flex_seed_scheme/flex_seed_scheme.dart';
import 'package:flutter/material.dart';
const _pinkLight = Color(0xFFFF6699);
const _pinkDark = Color(0xFFD44E7D);
extension ColorSchemeExt on ColorScheme {
Color get vipColor =>
brightness.isLight ? const Color(0xFFFF6699) : const Color(0xFFD44E7D);
Color get vipColor => brightness.isLight ? _pinkLight : _pinkDark;
Color get btnColor =>
brightness.isLight ? _pinkLight : const Color(0xFF8F0030);
Color get freeColor =>
brightness.isLight ? const Color(0xFFFF7F24) : const Color(0xFFD66011);

View File

@@ -15,6 +15,8 @@ class GlobalData {
bool dynamicsWaterfallFlow = Pref.dynamicsWaterfallFlow;
bool showMedal = Pref.showMedal;
// 私有构造函数
GlobalData._();

View File

@@ -100,7 +100,8 @@ abstract final class SettingBoxKey {
preInitPlayer = 'preInitPlayer',
mainTabBarView = 'mainTabBarView',
searchSuggestion = 'searchSuggestion',
showDynDecorate = 'showDynDecorate',
showDecorate = 'showDynDecorate',
showMedal = 'showMedal',
enableLivePhoto = 'enableLivePhoto',
showSeekPreview = 'showSeekPreview',
showDmChart = 'showDmChart',

View File

@@ -477,8 +477,11 @@ abstract final class Pref {
static bool get searchSuggestion =>
_setting.get(SettingBoxKey.searchSuggestion, defaultValue: true);
static bool get showDynDecorate =>
_setting.get(SettingBoxKey.showDynDecorate, defaultValue: true);
static bool get showDecorate =>
_setting.get(SettingBoxKey.showDecorate, defaultValue: true);
static bool get showMedal =>
_setting.get(SettingBoxKey.showMedal, defaultValue: true);
static bool get enableLivePhoto =>
_setting.get(SettingBoxKey.enableLivePhoto, defaultValue: true);