diff --git a/lib/common/view/header_bar.dart b/lib/common/view/header_bar.dart index 29bc9c9a5..6b45e1f7c 100644 --- a/lib/common/view/header_bar.dart +++ b/lib/common/view/header_bar.dart @@ -206,6 +206,7 @@ class SidebarButton extends StatelessWidget { }, icon: Icon( Iconz().sidebar, + size: iconSize, ), ), ); diff --git a/lib/common/view/icons.dart b/lib/common/view/icons.dart index 2f521ad7c..d838ab372 100644 --- a/lib/common/view/icons.dart +++ b/lib/common/view/icons.dart @@ -473,7 +473,11 @@ class Iconz { double get sideBarImageSize => 38; -double get iconSize => yaruStyled ? kYaruIconSize : 24; +double get iconSize => yaruStyled + ? kYaruIconSize + : isMobile + ? 24.0 + : 20.0; IconData getIconForTag(String tag) { final tagsToIcons = { diff --git a/lib/common/view/icy_image.dart b/lib/common/view/icy_image.dart deleted file mode 100644 index 77596c6b0..000000000 --- a/lib/common/view/icy_image.dart +++ /dev/null @@ -1,89 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../../common/view/icons.dart'; -import '../../constants.dart'; -import '../../l10n/l10n.dart'; -import '../../online_album_art_utils.dart'; -import '../data/mpv_meta_data.dart'; -import 'mpv_metadata_dialog.dart'; -import 'safe_network_image.dart'; - -class IcyImage extends StatefulWidget { - const IcyImage({ - super.key, - required this.mpvMetaData, - this.height = kAudioTrackWidth, - this.width = kAudioTrackWidth, - this.borderRadius, - this.fallBackWidget, - this.fit, - this.errorWidget, - this.fallBackImageUrl, - }); - - final MpvMetaData mpvMetaData; - - final double height, width; - final BorderRadius? borderRadius; - final Widget? fallBackWidget; - final Widget? errorWidget; - final BoxFit? fit; - final String? fallBackImageUrl; - - @override - State createState() => _IcyImageState(); -} - -class _IcyImageState extends State { - late Future _imageUrl; - - @override - void initState() { - super.initState(); - final url = UrlStore().get(widget.mpvMetaData.icyTitle); - _imageUrl = url?.isNotEmpty == true - ? Future.value(url) - : fetchAlbumArt(widget.mpvMetaData.icyTitle); - } - - @override - Widget build(BuildContext context) { - final bR = widget.borderRadius ?? BorderRadius.circular(4); - - return Tooltip( - message: context.l10n.metadata, - child: ClipRRect( - borderRadius: bR, - child: InkWell( - borderRadius: bR, - onTap: () => showDialog( - context: context, - builder: (context) { - final image = UrlStore().get(widget.mpvMetaData.icyTitle); - return MpvMetadataDialog( - image: image, - mpvMetaData: widget.mpvMetaData, - ); - }, - ), - child: SizedBox( - height: widget.height, - width: widget.width, - child: FutureBuilder( - future: _imageUrl, - builder: (context, snapshot) => _buildImage(snapshot.data), - ), - ), - ), - ), - ); - } - - Widget _buildImage(String? url) => SafeNetworkImage( - errorIcon: widget.errorWidget ?? Icon(Iconz().imageMissing), - url: url, - fallBackIcon: widget.fallBackWidget ?? Icon(Iconz().radio), - filterQuality: FilterQuality.medium, - fit: widget.fit ?? BoxFit.fitHeight, - ); -} diff --git a/lib/common/view/search_button.dart b/lib/common/view/search_button.dart index c5cf3065e..c33ab581b 100644 --- a/lib/common/view/search_button.dart +++ b/lib/common/view/search_button.dart @@ -27,8 +27,13 @@ class SearchButton extends StatelessWidget { Icon( Iconz().search, color: context.t.colorScheme.primary, + size: iconSize, + ), + icon: icon ?? + Icon( + Iconz().search, + size: iconSize, ), - icon: icon ?? Icon(Iconz().search), ); } } diff --git a/lib/common/view/theme.dart b/lib/common/view/theme.dart index 08fd4cda1..926ca628c 100644 --- a/lib/common/view/theme.dart +++ b/lib/common/view/theme.dart @@ -21,10 +21,6 @@ ThemeData? yaruDarkWithTweaks(YaruThemeData yaru) { space: 1.0, thickness: 0.0, ), - snackBarTheme: SnackBarThemeData( - behavior: SnackBarBehavior.floating, - actionTextColor: yaru.theme?.colorScheme.primary, - ), cardColor: yaru.darkTheme?.cardColor.scale( lightness: -0.2, ), @@ -37,10 +33,6 @@ ThemeData? yaruLightWithTweaks(YaruThemeData yaru) { actionIconTheme: ActionIconThemeData( backButtonIconBuilder: (context) => Icon(Iconz().goBack), ), - snackBarTheme: SnackBarThemeData( - behavior: SnackBarBehavior.floating, - actionTextColor: yaru.theme?.colorScheme.primary, - ), cardColor: yaru.theme?.dividerColor.scale( lightness: -0.01, ), diff --git a/lib/player/player_model.dart b/lib/player/player_model.dart index 25741402e..9e9538e21 100644 --- a/lib/player/player_model.dart +++ b/lib/player/player_model.dart @@ -100,6 +100,7 @@ class PlayerModel extends SafeChangeNotifier { ); Color? get color => _service.color; + String? get remoteImageUrl => _service.remoteImageUrl; bool _isUpNextExpanded = false; bool get isUpNextExpanded => _isUpNextExpanded; diff --git a/lib/player/player_service.dart b/lib/player/player_service.dart index 622f4aeb2..4ee46d536 100644 --- a/lib/player/player_service.dart +++ b/lib/player/player_service.dart @@ -60,7 +60,6 @@ class PlayerService { MpvMetaData? _mpvMetaData; MpvMetaData? get mpvMetaData => _mpvMetaData; void setMpvMetaData(MpvMetaData? value) { - if (value?.icyTitle == _mpvMetaData?.icyTitle) return; _mpvMetaData = value; var validHistoryElement = _mpvMetaData?.icyTitle.isNotEmpty == true; @@ -218,7 +217,7 @@ class PlayerService { ); } _setMediaControlsMetaData(audio: audio!); - _loadColor(); + _loadColorAndSetRemoteUrl(); _firstPlay = false; } on Exception catch (_) {} } @@ -276,22 +275,25 @@ class PlayerService { return; } final mpvMetaData = MpvMetaData.fromJson(data); + + if (mpvMetaData.icyTitle == _mpvMetaData?.icyTitle) return; setMpvMetaData( mpvMetaData.copyWith( icyTitle: HtmlParser(mpvMetaData.icyTitle).parseFragment().text, ), ); + final songInfo = mpvMetaData.icyTitle.splitByDash; fetchAlbumArt(mpvMetaData.icyTitle).then( - (albumArt) { - _setMediaControlsMetaData( + (albumArt) async { + await _setMediaControlsMetaData( audio: (_audio ?? const Audio()).copyWith( imageUrl: albumArt, title: songInfo.songName, artist: songInfo.artist, ), ); - _loadColor(artUrl: albumArt); + await _loadColorAndSetRemoteUrl(artUrl: albumArt); }, ); }, @@ -437,22 +439,34 @@ class PlayerService { Color? _color; Color? get color => _color; - Future _loadColor({String? artUrl}) async { + String? _remoteImageUrl; + String? get remoteImageUrl => _remoteImageUrl; + void _setRemoteImageUrl(String? url) { + _remoteImageUrl = url; + _propertiesChangedController.add(true); + } + + Future _loadColorAndSetRemoteUrl({String? artUrl}) async { final pic = CoverStore().get(_audio?.albumId); if (pic == null && audio?.imageUrl == null && audio?.albumArtUrl == null && artUrl == null) { _color = null; + _setRemoteImageUrl(null); + return; } ImageProvider? image; if (pic != null) { + _setRemoteImageUrl(null); image = MemoryImage(pic); } else { + final url = artUrl ?? _audio!.imageUrl ?? _audio!.albumArtUrl!; + _setRemoteImageUrl(url); image = NetworkImage( - artUrl ?? _audio!.imageUrl ?? _audio!.albumArtUrl!, + url, ); } final generator = await PaletteGenerator.fromImageProvider(image); diff --git a/lib/player/view/blurred_full_height_player_image.dart b/lib/player/view/blurred_full_height_player_image.dart index c0c07afbd..b17dd1846 100644 --- a/lib/player/view/blurred_full_height_player_image.dart +++ b/lib/player/view/blurred_full_height_player_image.dart @@ -1,13 +1,11 @@ import 'package:blur/blur.dart'; import 'package:flutter/material.dart'; -import 'package:watch_it/watch_it.dart'; import '../../extensions/build_context_x.dart'; import '../../extensions/theme_data_x.dart'; -import '../player_model.dart'; import 'full_height_player_image.dart'; -class BlurredFullHeightPlayerImage extends StatelessWidget with WatchItMixin { +class BlurredFullHeightPlayerImage extends StatelessWidget { const BlurredFullHeightPlayerImage({ super.key, required this.size, @@ -18,13 +16,8 @@ class BlurredFullHeightPlayerImage extends StatelessWidget with WatchItMixin { @override Widget build(BuildContext context) { final theme = context.t; - final audio = watchPropertyValue((PlayerModel m) => m.audio); - final mpvMetaData = watchPropertyValue((PlayerModel m) => m.mpvMetaData); return Opacity( - key: ValueKey( - '${audio?.path ?? ''}${mpvMetaData?.icyTitle ?? ''}${audio?.albumArtUrl ?? ''}${audio?.imageUrl ?? ''}', - ), opacity: theme.isLight ? 0.8 : 0.9, child: SizedBox( width: size.width, @@ -35,6 +28,7 @@ class BlurredFullHeightPlayerImage extends StatelessWidget with WatchItMixin { blurColor: theme.isLight ? Colors.white : theme.scaffoldBackgroundColor, child: FullHeightPlayerImage( + emptyFallBack: true, borderRadius: BorderRadius.zero, fit: BoxFit.cover, height: size.height, diff --git a/lib/player/view/bottom_player_image.dart b/lib/player/view/bottom_player_image.dart index d3eb4ec4b..fa0c46614 100644 --- a/lib/player/view/bottom_player_image.dart +++ b/lib/player/view/bottom_player_image.dart @@ -5,7 +5,6 @@ import 'package:watch_it/watch_it.dart'; import '../../app/app_model.dart'; import '../../common/data/audio.dart'; import '../../local_audio/view/local_cover.dart'; -import '../player_model.dart'; import 'player_fall_back_image.dart'; import 'player_remote_source_image.dart'; @@ -46,8 +45,6 @@ class BottomPlayerImage extends StatelessWidget with WatchItMixin { ); } - final mpvMetaData = watchPropertyValue((PlayerModel m) => m.mpvMetaData); - Widget child; final fallBackImage = PlayerFallBackImage( @@ -67,13 +64,8 @@ class BottomPlayerImage extends StatelessWidget with WatchItMixin { ); } else { child = PlayerRemoteSourceImage( - key: ValueKey( - '${mpvMetaData?.icyTitle ?? ''}${audio?.albumArtUrl ?? ''}${audio?.imageUrl ?? ''}', - ), - mpvMetaData: mpvMetaData, height: size, width: size, - audio: audio, fit: BoxFit.cover, fallBackIcon: fallBackImage, errorIcon: fallBackImage, diff --git a/lib/player/view/full_height_player_image.dart b/lib/player/view/full_height_player_image.dart index 241778c50..b12b3c8e8 100644 --- a/lib/player/view/full_height_player_image.dart +++ b/lib/player/view/full_height_player_image.dart @@ -14,19 +14,20 @@ class FullHeightPlayerImage extends StatelessWidget with WatchItMixin { this.height, this.width, this.borderRadius, + this.emptyFallBack = false, }); final BoxFit? fit; final double? height, width; final BorderRadius? borderRadius; + final bool emptyFallBack; @override Widget build(BuildContext context) { final audio = watchPropertyValue((PlayerModel m) => m.audio); - final mpvMetaData = watchPropertyValue((PlayerModel m) => m.mpvMetaData); - final fallBackImage = PlayerFallBackImage( + noIcon: emptyFallBack, audio: audio, height: height ?? fullHeightPlayerImageSize, width: width ?? fullHeightPlayerImageSize, @@ -45,13 +46,8 @@ class FullHeightPlayerImage extends StatelessWidget with WatchItMixin { ); } else { image = PlayerRemoteSourceImage( - key: ValueKey( - '${mpvMetaData?.icyTitle ?? ''}${audio?.albumArtUrl ?? ''}${audio?.imageUrl ?? ''}', - ), - mpvMetaData: mpvMetaData, height: height ?? fullHeightPlayerImageSize, width: width ?? fullHeightPlayerImageSize, - audio: audio, fit: fit, fallBackIcon: fallBackImage, errorIcon: fallBackImage, diff --git a/lib/player/view/player_fall_back_image.dart b/lib/player/view/player_fall_back_image.dart index ae11021bc..2a9731e28 100644 --- a/lib/player/view/player_fall_back_image.dart +++ b/lib/player/view/player_fall_back_image.dart @@ -13,11 +13,13 @@ class PlayerFallBackImage extends StatelessWidget { this.audio, required this.height, required this.width, + this.noIcon = false, }); final Audio? audio; final double height; final double width; + final bool noIcon; @override Widget build(BuildContext context) { @@ -55,15 +57,17 @@ class PlayerFallBackImage extends StatelessWidget { ), width: width, height: height, - child: Icon( - iconData, - size: iconSize, - color: contrastColor( - getAlphabetColor( - audio?.title ?? audio?.album ?? 'a', - ), - ), - ), + child: noIcon + ? null + : Icon( + iconData, + size: iconSize, + color: contrastColor( + getAlphabetColor( + audio?.title ?? audio?.album ?? 'a', + ), + ), + ), ), ); } diff --git a/lib/player/view/player_remote_source_image.dart b/lib/player/view/player_remote_source_image.dart index 523ad63d7..5438de0ab 100644 --- a/lib/player/view/player_remote_source_image.dart +++ b/lib/player/view/player_remote_source_image.dart @@ -1,61 +1,43 @@ import 'package:flutter/material.dart'; +import 'package:watch_it/watch_it.dart'; -import '../../common/data/audio.dart'; -import '../../common/data/mpv_meta_data.dart'; -import '../../common/view/icy_image.dart'; import '../../common/view/safe_network_image.dart'; import '../../extensions/build_context_x.dart'; +import '../player_model.dart'; -class PlayerRemoteSourceImage extends StatelessWidget { +class PlayerRemoteSourceImage extends StatelessWidget with WatchItMixin { const PlayerRemoteSourceImage({ super.key, required this.height, required this.width, - required this.audio, required this.fit, required this.fallBackIcon, required this.errorIcon, - required this.mpvMetaData, }); final double height; final double width; - final Audio? audio; final BoxFit? fit; final Widget fallBackIcon; final Widget errorIcon; - final MpvMetaData? mpvMetaData; @override Widget build(BuildContext context) { final theme = context.t; - final safeNetworkImage = SafeNetworkImage( - url: audio?.imageUrl ?? audio?.albumArtUrl, - filterQuality: FilterQuality.medium, - fit: fit ?? BoxFit.scaleDown, - fallBackIcon: fallBackIcon, - errorIcon: errorIcon, - height: height, - width: width, - ); - return Container( color: theme.cardColor, height: height, width: width, - child: - mpvMetaData?.icyTitle != null && audio?.audioType == AudioType.radio - ? IcyImage( - mpvMetaData: mpvMetaData!, - fallBackWidget: safeNetworkImage, - errorWidget: safeNetworkImage, - height: height, - width: width, - fit: fit, - fallBackImageUrl: audio?.imageUrl, - ) - : safeNetworkImage, + child: SafeNetworkImage( + url: watchPropertyValue((PlayerModel m) => m.remoteImageUrl), + filterQuality: FilterQuality.medium, + fit: fit ?? BoxFit.scaleDown, + fallBackIcon: fallBackIcon, + errorIcon: errorIcon, + height: height, + width: width, + ), ); } } diff --git a/lib/radio/view/icy_image.dart b/lib/radio/view/icy_image.dart new file mode 100644 index 000000000..ba29b5d9b --- /dev/null +++ b/lib/radio/view/icy_image.dart @@ -0,0 +1,65 @@ +import 'package:flutter/material.dart'; +import 'package:watch_it/watch_it.dart'; + +import '../../common/view/icons.dart'; +import '../../constants.dart'; +import '../../l10n/l10n.dart'; +import '../../online_album_art_utils.dart'; +import '../../player/player_model.dart'; +import '../../common/data/mpv_meta_data.dart'; +import '../../common/view/mpv_metadata_dialog.dart'; +import '../../common/view/safe_network_image.dart'; + +class IcyImage extends StatelessWidget with WatchItMixin { + const IcyImage({ + super.key, + required this.mpvMetaData, + this.height = kAudioTrackWidth, + this.width = kAudioTrackWidth, + this.borderRadius, + this.fallBackWidget, + this.fit, + }); + + final MpvMetaData mpvMetaData; + + final double height, width; + final BorderRadius? borderRadius; + final Widget? fallBackWidget; + final BoxFit? fit; + + @override + Widget build(BuildContext context) { + final bR = borderRadius ?? BorderRadius.circular(4); + watchPropertyValue( + (PlayerModel m) => m.remoteImageUrl, + ); + + return Tooltip( + message: context.l10n.metadata, + child: ClipRRect( + borderRadius: bR, + child: InkWell( + borderRadius: bR, + onTap: () => showDialog( + context: context, + builder: (context) => MpvMetadataDialog( + image: UrlStore().get(mpvMetaData.icyTitle), + mpvMetaData: mpvMetaData, + ), + ), + child: SizedBox( + height: height, + width: width, + child: SafeNetworkImage( + url: UrlStore().get(mpvMetaData.icyTitle), + fallBackIcon: fallBackWidget ?? Icon(Iconz().radio), + filterQuality: FilterQuality.medium, + fit: fit ?? BoxFit.fitHeight, + ), + ), + ), + ), + ); + } +} diff --git a/lib/radio/view/radio_history_list.dart b/lib/radio/view/radio_history_list.dart index e3a3e5800..0938a7bfd 100644 --- a/lib/radio/view/radio_history_list.dart +++ b/lib/radio/view/radio_history_list.dart @@ -86,6 +86,7 @@ class SliverRadioHistoryList extends StatelessWidget final length = watchPropertyValue( (PlayerModel m) => m.getRadioHistoryLength(filter: filter), ); + final current = watchPropertyValue((PlayerModel m) => m.mpvMetaData); if (length == 0) { diff --git a/lib/radio/view/radio_history_tile.dart b/lib/radio/view/radio_history_tile.dart index 928379deb..3b04eb080 100644 --- a/lib/radio/view/radio_history_tile.dart +++ b/lib/radio/view/radio_history_tile.dart @@ -5,7 +5,7 @@ import 'package:yaru/constants.dart'; import '../../common/data/audio.dart'; import '../../common/data/mpv_meta_data.dart'; import '../../common/view/icons.dart'; -import '../../common/view/icy_image.dart'; +import 'icy_image.dart'; import '../../common/view/mpv_metadata_dialog.dart'; import '../../common/view/tapable_text.dart'; import '../../common/view/theme.dart';