refactor: use ProxyImg widget

This commit is contained in:
2025-05-16 12:22:31 +01:00
parent 244a0aad38
commit dcf42e7a78
8 changed files with 73 additions and 63 deletions

View File

@ -1,7 +1,10 @@
import 'dart:convert';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:convert/convert.dart';
import 'package:crypto/crypto.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_svg/svg.dart';
import 'package:zap_stream_flutter/theme.dart';
class ImgProxySettings {
final String url;
@ -12,11 +15,12 @@ class ImgProxySettings {
static ImgProxySettings static() {
return ImgProxySettings(
url: "https://imgproxy.v0l.io",
key:
"a82fcf26aa0ccb55dfc6b4bd6a1c90744d3be0f38429f21a8828b43449ce7cebe6bdc2b09a827311bef37b18ce35cb1e6b1c60387a254541afa9e5b4264ae942",
salt:
"a897770d9abf163de055e9617891214e75a9016d748f8ef865e6ffbcb9ed932295659549773a22a019a5f06d0b440c320be411e3fddfe784e199e4f03d74bd9b");
url: "https://imgproxy.v0l.io",
key:
"a82fcf26aa0ccb55dfc6b4bd6a1c90744d3be0f38429f21a8828b43449ce7cebe6bdc2b09a827311bef37b18ce35cb1e6b1c60387a254541afa9e5b4264ae942",
salt:
"a897770d9abf163de055e9617891214e75a9016d748f8ef865e6ffbcb9ed932295659549773a22a019a5f06d0b440c320be411e3fddfe784e199e4f03d74bd9b",
);
}
}
@ -35,8 +39,14 @@ String signUrl(String u, ImgProxySettings settings) {
return urlSafe(base64.encode(result.bytes));
}
String proxyImg(BuildContext context, String url,
{ImgProxySettings? settings, int? resize, String? sha256, double? dpr}) {
String proxyImg(
BuildContext context,
String url, {
ImgProxySettings? settings,
int? resize,
String? sha256,
double? dpr,
}) {
final s = settings ?? ImgProxySettings.static();
if (url.startsWith("data:") || url.startsWith("blob:") || url.isEmpty) {
@ -63,4 +73,45 @@ String proxyImg(BuildContext context, String url,
final sig = signUrl(path, s);
return '${s.url}/$sig$path';
}
}
class ProxyImg extends StatelessWidget {
final String? url;
/// Size of the placeholder & error images
final double? placeholderSize;
/// request imgproxy to resize the image
final int? resize;
final double? width;
final double? height;
const ProxyImg({
super.key,
required this.url,
this.placeholderSize,
this.resize,
this.width,
this.height,
});
@override
Widget build(BuildContext context) {
return CachedNetworkImage(
imageUrl: proxyImg(context, url ?? "", resize: resize),
width: width,
height: height,
fit: BoxFit.cover,
placeholder:
(ctx, url) =>
SvgPicture.asset("assets/svg/logo.svg", height: placeholderSize),
errorWidget:
(context, url, error) => SvgPicture.asset(
"assets/svg/logo.svg",
height: placeholderSize,
colorFilter: ColorFilter.mode(WARNING, BlendMode.srcATop),
),
);
}
}

View File

@ -44,10 +44,7 @@ class CategoryPage extends StatelessWidget {
info!.coverImage!,
fit: BoxFit.contain,
)
: CachedNetworkImage(
imageUrl: proxyImg(context, info!.coverImage!),
fit: BoxFit.cover,
),
: ProxyImg(url: info!.coverImage!),
),
Expanded(
child: Column(

View File

@ -36,10 +36,7 @@ class ProfilePage extends StatelessWidget {
SizedBox(
height: 140,
width: double.maxFinite,
child: CachedNetworkImage(
imageUrl: proxyImg(context, profile.banner!),
fit: BoxFit.cover,
),
child: ProxyImg(url: profile.banner!),
),
Row(
spacing: 8,

View File

@ -53,9 +53,7 @@ class _StreamPage extends State<StreamPage> {
autoPlay: true,
placeholder:
(widget.stream.info.image?.isNotEmpty ?? false)
? CachedNetworkImage(
imageUrl: proxyImg(context, widget.stream.info.image!),
)
? ProxyImg(url: widget.stream.info.image!)
: null,
);
});
@ -109,9 +107,7 @@ class _StreamPage extends State<StreamPage> {
color: LAYER_1,
child:
(stream.info.image?.isNotEmpty ?? false)
? CachedNetworkImage(
imageUrl: proxyImg(context, stream.info.image!),
)
? ProxyImg(url: stream.info.image!)
: null,
),
),

View File

@ -23,17 +23,13 @@ class AvatarWidget extends StatelessWidget {
Widget build(BuildContext context) {
final thisSize = size ?? 40;
return ClipOval(
child: CachedNetworkImage(
fit: BoxFit.cover,
imageUrl: proxyImg(
context,
profile.picture ??
"https://nostr.api.v0l.io/api/v1/avatar/cyberpunks/${profile.pubKey}",
resize: thisSize.ceil(),
),
height: thisSize,
child: ProxyImg(
url:
profile.picture ??
"https://nostr.api.v0l.io/api/v1/avatar/cyberpunks/${profile.pubKey}",
resize: thisSize.ceil(),
width: thisSize,
errorWidget: (context, url, error) => Icon(Icons.error),
height: thisSize,
),
);
}

View File

@ -1,4 +1,3 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:collection/collection.dart';
import 'package:flutter/widgets.dart';
import 'package:zap_stream_flutter/imgproxy.dart';
@ -27,11 +26,7 @@ class CustomEmoji extends StatelessWidget {
(t) => t[0] == "emoji" && t[1] == cleanedEmojiName,
)?[2];
if (customEmoji != null) {
return CachedNetworkImage(
imageUrl: proxyImg(context, customEmoji),
height: size ?? 16,
width: size ?? 16,
);
return ProxyImg(url: customEmoji, width: size ?? 16, height: size ?? 16);
} else {
return Text(emoji);
}

View File

@ -77,16 +77,9 @@ class StreamCardsWidget extends StatelessWidget {
onTap: () {
launchUrl(Uri.parse(link));
},
child: CachedNetworkImage(
imageUrl: proxyImg(context, image!),
errorWidget:
(_, _, _) => SvgPicture.asset(
"assets/svg/logo.svg",
height: 40,
),
),
child: ProxyImg(url: link, placeholderSize: 40),
)
: CachedNetworkImage(imageUrl: proxyImg(context, image!)),
: ProxyImg(url: link, placeholderSize: 40),
),
MarkdownBody(
data: card.content,

View File

@ -31,22 +31,7 @@ class StreamTileWidget extends StatelessWidget {
aspectRatio: 16 / 9,
child: Stack(
children: [
Center(
child: CachedNetworkImage(
imageUrl: proxyImg(context, stream.info.image ?? ""),
fit: BoxFit.cover,
placeholder:
(ctx, url) => SvgPicture.asset(
"assets/svg/logo.svg",
height: 100,
),
errorWidget:
(context, url, error) => SvgPicture.asset(
"assets/svg/logo.svg",
height: 100,
),
),
),
Center(child: ProxyImg(url: stream.info.image ?? "", placeholderSize: 100,)),
if (stream.info.status != null)
Positioned(
right: 8,