Files
feeddeck/app/lib/widgets/source/source_icon.dart
Rico Berger 92bea5d715 [core] Improve Media Handling (#66)
This commit improves / simplifies the media handling within the app.
Until now we always had to provide the type of the media file (item
media / source icon) when we wanted to display it. This is now not
necessary anymore. Instead we always display the image from it's
original path when the url starts with "http://" or "https://".
Additionally we also check the platform to proxy the image request on
the web. If the image doesn't start with "http://" or "https://" we
always try to display the image from the Supabase storage.

For this we also adjusted the corresponding Deno function, so that we
check if the image starts with "http://" or "https://" before we upload
it to the Supabase storage. If this is the case we upload the source
icon to the Supabase storage. If the upload fails, we will use the
original path of the icon.

Last but not least this commit also introduces our own
"CachedNetworkImage" widget, which wraps the original
"CachedNetworkImage" widget. Our own widget will ensure that we use the
correct url for the image request, so that we do not have to use this
function all over the app anymore. Later this widget can also be used to
introduce our own cache manager.
2023-11-04 18:27:17 +01:00

162 lines
4.1 KiB
Dart

import 'package:flutter/material.dart';
import 'package:feeddeck/models/source.dart';
import 'package:feeddeck/utils/constants.dart';
import 'package:feeddeck/utils/fd_icons.dart';
import 'package:feeddeck/widgets/utils/cached_network_image.dart';
/// [SourceIcon] can be used to show the image for a source. For that the [icon]
/// of the source must be provided. The size of the image can be adjusted via
/// the [size] parameter.
///
/// If we are not able to display the image or when the [icon] is `null` we will
/// display a default icon, which is generated via the provided source [type].
class SourceIcon extends StatelessWidget {
const SourceIcon({
super.key,
required this.type,
required this.icon,
required this.size,
});
final FDSourceType type;
final String? icon;
final double size;
/// buildIcon returns the provided [icon] with the provided [backgroundColor].
Widget buildIcon(
IconData icon,
double iconSize,
Color backgroundColor,
Color foregroundColor,
) {
return CircleAvatar(
radius: iconSize / 2,
backgroundColor: backgroundColor,
child: Icon(
icon,
size: iconSize / 2,
color: foregroundColor,
),
);
}
/// [buildDefaultIcon] returns an icon based on the provided source [type].
Widget buildDefaultIcon(double iconSize) {
switch (type) {
case FDSourceType.github:
return buildIcon(
FDIcons.github,
iconSize,
type.color,
const Color(0xffffffff),
);
case FDSourceType.googlenews:
return buildIcon(
FDIcons.googlenews,
iconSize,
type.color,
const Color(0xffffffff),
);
case FDSourceType.mastodon:
return buildIcon(
FDIcons.mastodon,
iconSize,
type.color,
const Color(0xffffffff),
);
case FDSourceType.medium:
return buildIcon(
FDIcons.medium,
iconSize,
type.color,
const Color(0xffffffff),
);
case FDSourceType.nitter:
return buildIcon(
FDIcons.nitter,
iconSize,
type.color,
const Color(0xffffffff),
);
case FDSourceType.podcast:
return buildIcon(
Icons.podcasts,
iconSize,
type.color,
const Color(0xffffffff),
);
case FDSourceType.reddit:
return buildIcon(
FDIcons.reddit,
iconSize,
type.color,
const Color(0xffffffff),
);
case FDSourceType.rss:
return buildIcon(
FDIcons.rss,
iconSize,
type.color,
const Color(0xffffffff),
);
case FDSourceType.stackoverflow:
return buildIcon(
FDIcons.stackoverflow,
iconSize,
type.color,
const Color(0xffffffff),
);
case FDSourceType.tumblr:
return buildIcon(
FDIcons.tumblr,
iconSize,
type.color,
const Color(0xffffffff),
);
// case FDSourceType.x:
// return buildIcon(
// FDIcons.x,
// iconSize,
// type.color,
// const Color(0xffffffff),
// );
case FDSourceType.youtube:
return buildIcon(
FDIcons.youtube,
iconSize,
type.color,
const Color(0xffffffff),
);
default:
return buildIcon(
FDIcons.feeddeck,
iconSize,
Constants.primary,
Constants.onPrimary,
);
}
}
@override
Widget build(BuildContext context) {
if (icon == null || icon == '') {
return buildDefaultIcon(size);
}
return ClipOval(
child: SizedBox.fromSize(
size: Size.fromRadius(size / 2),
child: CachedNetworkImage(
height: size,
width: size,
fit: BoxFit.cover,
imageUrl: icon!,
placeholder: (context, url) => buildDefaultIcon(size),
errorWidget: (context, url, error) => buildDefaultIcon(size),
),
),
);
}
}