Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
bggRGjQaUbCoE
2025-12-31 12:13:38 +08:00
parent 2e11247af4
commit 63e4bac204
62 changed files with 316 additions and 162 deletions

View File

@@ -787,7 +787,7 @@ class RichTextEditingController extends TextEditingController {
width: 22, // emote.width,
height: 22, // emote.height,
type: ImageType.emote,
boxFit: BoxFit.contain,
fit: BoxFit.contain,
),
),
);

View File

@@ -177,13 +177,11 @@ class CustomGridView extends StatelessWidget {
context,
).colorScheme.onInverseSurface.withValues(alpha: 0.4),
),
child: Center(
child: Image.asset(
'assets/images/loading.png',
width: imageWidth,
height: imageHeight,
cacheWidth: imageWidth.cacheSize(context),
),
child: Image.asset(
'assets/images/loading.png',
width: imageWidth,
height: imageHeight,
cacheWidth: imageWidth.cacheSize(context),
),
);
@@ -216,11 +214,11 @@ class CustomGridView extends StatelessWidget {
ClipRRect(
borderRadius: radius,
child: NetworkImgLayer(
radius: 0,
type: .emote,
src: item.url,
width: imageWidth,
height: imageHeight,
isLongPic: item.isLongPic,
alignment: item.isLongPic ? .topCenter : .center,
forceUseCacheWidth: item.width <= item.height,
getPlaceHolder: () => placeHolder,
),

View File

@@ -12,68 +12,57 @@ class NetworkImgLayer extends StatelessWidget {
required this.src,
required this.width,
this.height,
this.type = ImageType.def,
this.fadeOutDuration,
this.fadeInDuration,
// 图片质量 默认1%
this.type = .def,
this.fadeOutDuration = const Duration(milliseconds: 120),
this.fadeInDuration = const Duration(milliseconds: 120),
this.quality,
this.semanticsLabel,
this.radius,
this.isLongPic = false,
this.borderRadius = StyleString.mdRadius,
this.forceUseCacheWidth = false,
this.getPlaceHolder,
this.boxFit,
this.fit = .cover,
this.alignment = .center,
});
final String? src;
final double width;
final double? height;
final ImageType type;
final Duration? fadeOutDuration;
final Duration? fadeInDuration;
final Duration fadeOutDuration;
final Duration fadeInDuration;
final int? quality;
final String? semanticsLabel;
final double? radius;
final bool isLongPic;
final BorderRadius borderRadius;
final bool forceUseCacheWidth;
final Widget Function()? getPlaceHolder;
final BoxFit? boxFit;
final ValueGetter<Widget>? getPlaceHolder;
final BoxFit fit;
final Alignment alignment;
static Color? reduceLuxColor = Pref.reduceLuxColor;
static bool reduce = false;
@override
Widget build(BuildContext context) {
final noRadius = type == ImageType.emote || radius == 0;
final Widget child;
final isEmote = type == ImageType.emote;
final isAvatar = type == ImageType.avatar;
if (src?.isNotEmpty == true) {
child = noRadius
? _buildImage(context, noRadius)
: type == ImageType.avatar
? ClipOval(child: _buildImage(context, noRadius))
: ClipRRect(
borderRadius: radius != null
? BorderRadius.circular(radius!)
: StyleString.mdRadius,
child: _buildImage(context, noRadius),
);
Widget child = _buildImage(context, isEmote: isEmote, isAvatar: isAvatar);
if (isEmote) {
return child;
} else if (isAvatar) {
return ClipOval(child: child);
} else {
return ClipRRect(borderRadius: borderRadius, child: child);
}
} else {
child = getPlaceHolder?.call() ?? _placeholder(context, noRadius);
return getPlaceHolder?.call() ??
_placeholder(context, isEmote: isEmote, isAvatar: isAvatar);
}
return semanticsLabel?.isNotEmpty == true
? Semantics(
container: true,
image: true,
excludeSemantics: true,
label: semanticsLabel,
child: child,
)
: child;
}
Widget _buildImage(BuildContext context, bool noRadius) {
Widget _buildImage(
BuildContext context, {
required bool isEmote,
required bool isAvatar,
}) {
int? memCacheWidth, memCacheHeight;
if (height == null || forceUseCacheWidth || width <= height!) {
memCacheWidth = width.cacheSize(context);
@@ -86,35 +75,36 @@ class NetworkImgLayer extends StatelessWidget {
height: height,
memCacheWidth: memCacheWidth,
memCacheHeight: memCacheHeight,
fit: boxFit ?? BoxFit.cover,
alignment: isLongPic ? Alignment.topCenter : Alignment.center,
fadeOutDuration: fadeOutDuration ?? const Duration(milliseconds: 120),
fadeInDuration: fadeInDuration ?? const Duration(milliseconds: 120),
fit: fit,
alignment: alignment,
fadeOutDuration: fadeOutDuration,
fadeInDuration: fadeInDuration,
filterQuality: FilterQuality.low,
placeholder: (context, url) =>
getPlaceHolder?.call() ?? _placeholder(context, noRadius),
errorWidget: (context, url, error) => _placeholder(context, noRadius),
placeholder: (_, _) =>
getPlaceHolder?.call() ??
_placeholder(context, isEmote: isEmote, isAvatar: isAvatar),
errorWidget: (_, _, _) =>
_placeholder(context, isEmote: isEmote, isAvatar: isAvatar),
colorBlendMode: reduce ? BlendMode.modulate : null,
color: reduce ? reduceLuxColor : null,
);
}
Widget _placeholder(BuildContext context, bool noRadius) {
final isAvatar = type == ImageType.avatar;
Widget _placeholder(
BuildContext context, {
required bool isEmote,
required bool isAvatar,
}) {
return Container(
width: width,
height: height,
clipBehavior: noRadius ? Clip.none : Clip.antiAlias,
clipBehavior: isEmote ? Clip.none : Clip.antiAlias,
decoration: BoxDecoration(
shape: isAvatar ? BoxShape.circle : BoxShape.rectangle,
color: Theme.of(
context,
).colorScheme.onInverseSurface.withValues(alpha: 0.4),
borderRadius: noRadius || isAvatar
? null
: radius != null
? BorderRadius.circular(radius!)
: StyleString.mdRadius,
borderRadius: isEmote || isAvatar ? null : borderRadius,
),
child: Center(
child: Image.asset(

View File

@@ -1,6 +1,7 @@
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';
import 'package:PiliPlus/utils/extension/num_ext.dart';
import 'package:PiliPlus/utils/extension/string_ext.dart';
import 'package:PiliPlus/utils/page_utils.dart';
import 'package:PiliPlus/utils/storage_pref.dart';
@@ -50,7 +51,7 @@ class PendantAvatar extends StatelessWidget {
top: -0.375 * size + (size == 80 ? 2 : 0),
child: IgnorePointer(
child: NetworkImgLayer(
radius: 0,
type: .emote,
width: pendantSize,
height: pendantSize,
src: garbPendantImage,
@@ -105,7 +106,7 @@ class PendantAvatar extends StatelessWidget {
),
)
else if (_badgeType != BadgeType.none)
_buildBadge(colorScheme, isMemberAvatar),
_buildBadge(context, colorScheme, isMemberAvatar),
],
);
}
@@ -137,11 +138,17 @@ class PendantAvatar extends StatelessWidget {
type: ImageType.avatar,
);
Widget _buildBadge(ColorScheme colorScheme, bool isMemberAvatar) {
Widget _buildBadge(
BuildContext context,
ColorScheme colorScheme,
bool isMemberAvatar,
) {
final child = switch (_badgeType) {
BadgeType.vip => Image.asset(
'assets/images/big-vip.png',
width: badgeSize,
height: badgeSize,
cacheWidth: badgeSize.cacheSize(context),
semanticLabel: _badgeType.desc,
),
_ => Icon(

View File

@@ -98,7 +98,7 @@ class VideoCardV extends StatelessWidget {
src: videoItem.cover,
width: maxWidth,
height: maxHeight,
radius: 0,
type: .emote,
),
if (videoItem.duration > 0)
PBadge(