diff --git a/lib/imgproxy.dart b/lib/imgproxy.dart index b381ba9..f806516 100644 --- a/lib/imgproxy.dart +++ b/lib/imgproxy.dart @@ -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'; -} \ No newline at end of file +} + +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), + ), + ); + } +} diff --git a/lib/pages/category.dart b/lib/pages/category.dart index 9f7906e..ed21e90 100644 --- a/lib/pages/category.dart +++ b/lib/pages/category.dart @@ -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( diff --git a/lib/pages/profile.dart b/lib/pages/profile.dart index 2837e16..bed10a9 100644 --- a/lib/pages/profile.dart +++ b/lib/pages/profile.dart @@ -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, diff --git a/lib/pages/stream.dart b/lib/pages/stream.dart index 61d205c..e9df81e 100644 --- a/lib/pages/stream.dart +++ b/lib/pages/stream.dart @@ -53,9 +53,7 @@ class _StreamPage extends State { 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 { color: LAYER_1, child: (stream.info.image?.isNotEmpty ?? false) - ? CachedNetworkImage( - imageUrl: proxyImg(context, stream.info.image!), - ) + ? ProxyImg(url: stream.info.image!) : null, ), ), diff --git a/lib/widgets/avatar.dart b/lib/widgets/avatar.dart index 3e16d62..9d16c6f 100644 --- a/lib/widgets/avatar.dart +++ b/lib/widgets/avatar.dart @@ -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, ), ); } diff --git a/lib/widgets/custom_emoji.dart b/lib/widgets/custom_emoji.dart index 3828032..de6f41a 100644 --- a/lib/widgets/custom_emoji.dart +++ b/lib/widgets/custom_emoji.dart @@ -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); } diff --git a/lib/widgets/stream_cards.dart b/lib/widgets/stream_cards.dart index 29fabbc..b5fd468 100644 --- a/lib/widgets/stream_cards.dart +++ b/lib/widgets/stream_cards.dart @@ -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, diff --git a/lib/widgets/stream_tile.dart b/lib/widgets/stream_tile.dart index d7ec290..e05ebfc 100644 --- a/lib/widgets/stream_tile.dart +++ b/lib/widgets/stream_tile.dart @@ -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,