From c42275cb58f94fca5bdc9e7306b296242cbe1c03 Mon Sep 17 00:00:00 2001 From: Feichtmeier Date: Sun, 17 Nov 2024 21:53:09 +0100 Subject: [PATCH] feat: more android UI fixes --- lib/common/view/audio_tile.dart | 40 +++--- lib/common/view/audio_tile_option_button.dart | 45 ++++--- lib/common/view/icons.dart | 2 +- lib/common/view/sliver_audio_page.dart | 117 +++++++++--------- lib/common/view/sliver_audio_tile_list.dart | 33 ++--- lib/common/view/theme.dart | 9 +- lib/constants.dart | 4 +- lib/local_audio/local_cover_service.dart | 5 +- lib/player/view/player_main_controls.dart | 4 +- .../view/add_to_playlist_dialog.dart | 65 ++++++---- lib/podcasts/view/podcast_page.dart | 7 +- 11 files changed, 184 insertions(+), 147 deletions(-) diff --git a/lib/common/view/audio_tile.dart b/lib/common/view/audio_tile.dart index e140a21b3..1e53a26ef 100644 --- a/lib/common/view/audio_tile.dart +++ b/lib/common/view/audio_tile.dart @@ -102,7 +102,9 @@ class _AudioTileState extends State { ? selectedColor : theme.colorScheme.onSurface, selectedTileColor: theme.colorScheme.onSurface.withOpacity(0.05), - contentPadding: audioTilePadding, + contentPadding: audioTilePadding.copyWith( + left: widget.audioPageType == AudioPageType.album ? 10 : null, + ), onTap: () { if (widget.selected) { if (widget.isPlayerPlaying) { @@ -191,7 +193,8 @@ class _AudioTileTrail extends StatelessWidget with WatchItMixin { selected: selected && isPlayerPlaying, playlistId: pageId, audio: audio, - allowRemove: audioPageType == AudioPageType.playlist, + allowRemove: audioPageType == AudioPageType.playlist || + audioPageType == AudioPageType.likedAudio, insertIntoQueue: insertIntoQueue != null ? () => insertIntoQueue!(audio) : null, ), @@ -199,22 +202,23 @@ class _AudioTileTrail extends StatelessWidget with WatchItMixin { const SizedBox( width: 5, ), - Opacity( - opacity: hovered || selected || liked ? 1 : 0, - child: switch (audio.audioType) { - AudioType.radio => RadioLikeIcon( - audio: audio, - color: selected && isPlayerPlaying ? selectedColor : null, - ), - AudioType.local => LikeIcon( - audio: audio, - color: selected && isPlayerPlaying ? selectedColor : null, - ), - _ => SizedBox.square( - dimension: context.theme.buttonTheme.height, - ), - }, - ), + if (!isMobile) + Opacity( + opacity: hovered || selected || liked ? 1 : 0, + child: switch (audio.audioType) { + AudioType.radio => RadioLikeIcon( + audio: audio, + color: selected && isPlayerPlaying ? selectedColor : null, + ), + AudioType.local => LikeIcon( + audio: audio, + color: selected && isPlayerPlaying ? selectedColor : null, + ), + _ => SizedBox.square( + dimension: context.theme.buttonTheme.height, + ), + }, + ), if (!isMobile && audio.audioType != AudioType.radio && audio.durationMs != null) diff --git a/lib/common/view/audio_tile_option_button.dart b/lib/common/view/audio_tile_option_button.dart index 86f2dba5c..2ce78b3e9 100644 --- a/lib/common/view/audio_tile_option_button.dart +++ b/lib/common/view/audio_tile_option_button.dart @@ -3,6 +3,7 @@ import 'package:watch_it/watch_it.dart'; import 'package:yaru/yaru.dart'; import '../../app_config.dart'; +import '../../constants.dart'; import '../../extensions/build_context_x.dart'; import '../../l10n/l10n.dart'; import '../../library/library_model.dart'; @@ -32,10 +33,11 @@ class AudioTileOptionButton extends StatelessWidget { @override Widget build(BuildContext context) { final theme = context.theme; + final l10n = context.l10n; final libraryModel = di(); return PopupMenuButton( - tooltip: context.l10n.moreOptions, + tooltip: l10n.moreOptions, padding: EdgeInsets.zero, itemBuilder: (context) { return [ @@ -46,23 +48,26 @@ class AudioTileOptionButton extends StatelessWidget { showSnackBar( context: context, content: Text( - '${context.l10n.addedTo} ${context.l10n.queue}: ${audio.artist} - ${audio.title}', + '${l10n.addedTo} ${l10n.queue}: ${audio.artist} - ${audio.title}', ), ); }, child: YaruTile( leading: Icon(Iconz.insertIntoQueue), - title: Text(context.l10n.playNext), + title: Text(l10n.playNext), ), ), if (audio.audioType != AudioType.radio) if (allowRemove) PopupMenuItem( - onTap: () => - libraryModel.removeAudioFromPlaylist(playlistId, audio), + onTap: () => playlistId == kLikedAudiosPageId + ? libraryModel.removeLikedAudio(audio) + : libraryModel.removeAudioFromPlaylist(playlistId, audio), child: YaruTile( leading: Icon(Iconz.remove), - title: Text('${context.l10n.removeFrom} $playlistId'), + title: Text( + '${l10n.removeFrom} ${playlistId == kLikedAudiosPageId ? l10n.likedSongs : playlistId}', + ), ), ), if (audio.audioType != AudioType.radio) @@ -79,7 +84,7 @@ class AudioTileOptionButton extends StatelessWidget { child: YaruTile( leading: Icon(Iconz.plus), title: Text( - '${context.l10n.addToPlaylist} ...', + '${l10n.addToPlaylist} ...', ), ), ), @@ -93,7 +98,7 @@ class AudioTileOptionButton extends StatelessWidget { child: YaruTile( leading: Icon(Iconz.info), title: Text( - '${context.l10n.showMetaData} ...', + '${l10n.showMetaData} ...', ), ), ), @@ -130,45 +135,45 @@ class MetaDataDialog extends StatelessWidget { @override Widget build(BuildContext context) { final radio = audio.audioType == AudioType.radio; - + final l10n = context.l10n; final items = <(String, String)>{ ( - radio ? context.l10n.stationName : context.l10n.title, + radio ? l10n.stationName : l10n.title, '${audio.title}', ), ( - radio ? context.l10n.tags : context.l10n.album, + radio ? l10n.tags : l10n.album, '${radio ? audio.album?.replaceAll(',', ', ') : audio.album}', ), ( - radio ? context.l10n.language : context.l10n.artist, + radio ? l10n.language : l10n.artist, '${radio ? audio.language : audio.artist}', ), ( - radio ? context.l10n.quality : context.l10n.albumArtists, + radio ? l10n.quality : l10n.albumArtists, '${audio.albumArtist}', ), if (!radio) ( - context.l10n.trackNumber, + l10n.trackNumber, '${audio.trackNumber}', ), if (!radio) ( - context.l10n.diskNumber, + l10n.diskNumber, '${audio.discNumber}', ), ( - radio ? context.l10n.clicks : context.l10n.totalDisks, + radio ? l10n.clicks : l10n.totalDisks, '${radio ? audio.clicks : audio.discTotal}', ), if (!radio) ( - context.l10n.genre, + l10n.genre, '${audio.genre}', ), ( - context.l10n.url, + l10n.url, (audio.url ?? ''), ), }; @@ -176,9 +181,9 @@ class MetaDataDialog extends StatelessWidget { return AlertDialog( title: yaruStyled ? YaruDialogTitleBar( - title: Text(context.l10n.metadata), + title: Text(l10n.metadata), ) - : Center(child: Text(context.l10n.metadata)), + : Center(child: Text(l10n.metadata)), titlePadding: yaruStyled ? EdgeInsets.zero : const EdgeInsets.only(top: 10), contentPadding: const EdgeInsets.only(bottom: 12), diff --git a/lib/common/view/icons.dart b/lib/common/view/icons.dart index 2231f9014..6525bc91e 100644 --- a/lib/common/view/icons.dart +++ b/lib/common/view/icons.dart @@ -25,7 +25,7 @@ class Iconz { : Icons.menu_rounded; } - static IconData get materialSidebar => Icons.view_sidebar_rounded; + static IconData get materialSidebar => Icons.menu_rounded; static IconData get sidebar { return yaruStyled diff --git a/lib/common/view/sliver_audio_page.dart b/lib/common/view/sliver_audio_page.dart index 1b3096019..221310b64 100644 --- a/lib/common/view/sliver_audio_page.dart +++ b/lib/common/view/sliver_audio_page.dart @@ -82,64 +82,67 @@ class SliverAudioPage extends StatelessWidget { ), body: LayoutBuilder( builder: (context, constraints) { - return audios == null - ? const Center( - child: Progress(), + final padding = getAdaptiveHorizontalPadding( + constraints: constraints, + min: isMobile ? 5 : 15, + ); + + if (audios == null) { + return const Center( + child: Progress(), + ); + } + + if (audios!.isEmpty) { + return NoSearchResultPage( + message: noSearchResultMessage, + icon: noSearchResultIcons, + ); + } + + return CustomScrollView( + slivers: [ + SliverPadding( + padding: padding, + sliver: SliverToBoxAdapter( + child: AudioPageHeader( + title: pageTitle ?? pageId, + image: image, + subTitle: pageSubTitle, + label: pageLabel, + onLabelTab: audioPageType == AudioPageType.likedAudio + ? null + : onPageLabelTab, + onSubTitleTab: onPageSubTitleTab, + description: description, + ), + ), + ), + SliverAudioPageControlPanel( + controlPanel: controlPanel ?? + AvatarPlayButton( + audios: audios ?? [], + pageId: pageId, + ), + ), + if (audios == null) + const SliverToBoxAdapter( + child: Center( + child: Progress(), + ), ) - : audios!.isEmpty - ? NoSearchResultPage( - message: noSearchResultMessage, - icon: noSearchResultIcons, - ) - : CustomScrollView( - slivers: [ - SliverPadding( - padding: getAdaptiveHorizontalPadding( - constraints: constraints, - min: 40, - ), - sliver: SliverToBoxAdapter( - child: AudioPageHeader( - title: pageTitle ?? pageId, - image: image, - subTitle: pageSubTitle, - label: pageLabel, - onLabelTab: - audioPageType == AudioPageType.likedAudio - ? null - : onPageLabelTab, - onSubTitleTab: onPageSubTitleTab, - description: description, - ), - ), - ), - SliverAudioPageControlPanel( - controlPanel: controlPanel ?? - AvatarPlayButton( - audios: audios ?? [], - pageId: pageId, - ), - ), - if (audios == null) - const SliverToBoxAdapter( - child: Center( - child: Progress(), - ), - ) - else - SliverPadding( - padding: getAdaptiveHorizontalPadding( - constraints: constraints, - ), - sliver: SliverAudioTileList( - audioPageType: audioPageType, - audios: audios!, - pageId: pageId, - onSubTitleTab: onPageLabelTab, - ), - ), - ], - ); + else + SliverPadding( + padding: padding, + sliver: SliverAudioTileList( + audioPageType: audioPageType, + audios: audios!, + pageId: pageId, + onSubTitleTab: onPageLabelTab, + ), + ), + ], + ); }, ), ); diff --git a/lib/common/view/sliver_audio_tile_list.dart b/lib/common/view/sliver_audio_tile_list.dart index 67168c457..d1998baff 100644 --- a/lib/common/view/sliver_audio_tile_list.dart +++ b/lib/common/view/sliver_audio_tile_list.dart @@ -36,22 +36,25 @@ class SliverAudioTileList extends StatelessWidget with WatchItMixin { (context, index) { final audio = audios.elementAt(index); final audioSelected = currentAudio == audio; - return AudioTile( - showLeading: showLeading, - key: ValueKey(audio.path ?? audio.url), - audioPageType: audioPageType, - onSubTitleTap: onSubTitleTab, - isPlayerPlaying: isPlaying, - onTap: () => playerModel.startPlaylist( - audios: audios, - listName: pageId, - index: index, + return Padding( + padding: const EdgeInsets.only(bottom: 5), + child: AudioTile( + showLeading: showLeading, + key: ValueKey(audio.path ?? audio.url), + audioPageType: audioPageType, + onSubTitleTap: onSubTitleTab, + isPlayerPlaying: isPlaying, + onTap: () => playerModel.startPlaylist( + audios: audios, + listName: pageId, + index: index, + ), + selected: audioSelected, + audio: audio, + insertIntoQueue: playerModel.insertIntoQueue, + pageId: pageId, + selectedColor: selectedColor, ), - selected: audioSelected, - audio: audio, - insertIntoQueue: playerModel.insertIntoQueue, - pageId: pageId, - selectedColor: selectedColor, ); }, ), diff --git a/lib/common/view/theme.dart b/lib/common/view/theme.dart index e40bf0f3d..07e443e94 100644 --- a/lib/common/view/theme.dart +++ b/lib/common/view/theme.dart @@ -218,7 +218,11 @@ double get avatarIconRadius => : 38) / 2; -double get bigPlayButtonRadius => yaruStyled ? 22 : 23; +double get bigPlayButtonRadius => yaruStyled + ? 22 + : isMobile + ? 26 + : 23; EdgeInsets get filterPanelPadding => EdgeInsets.only(top: isMobile ? 10 : 0, bottom: 10); @@ -237,8 +241,7 @@ FontWeight get largeTextWeight => double get chipHeight => isMobile ? 40 : 34.0; -EdgeInsets get audioTilePadding => - isMobile ? kMobileAudioTilePadding : kDesktopAudioTilePadding; +EdgeInsets get audioTilePadding => kAudioTilePadding; SliverGridDelegate get audioCardGridDelegate => isMobile ? kMobileAudioCardGridDelegate : kAudioCardGridDelegate; diff --git a/lib/constants.dart b/lib/constants.dart index ca94514e5..1d1a6a3cc 100644 --- a/lib/constants.dart +++ b/lib/constants.dart @@ -41,9 +41,7 @@ const kMinAudioPageHeaderHeight = 0.0; const kSnackBarDuration = Duration(seconds: 10); -const kMobileAudioTilePadding = EdgeInsets.symmetric(horizontal: 20); - -const kDesktopAudioTilePadding = EdgeInsets.symmetric(horizontal: 20); +const kAudioTilePadding = EdgeInsets.symmetric(horizontal: 10); const kAudioTileTrackPadding = EdgeInsets.only(right: 20); diff --git a/lib/local_audio/local_cover_service.dart b/lib/local_audio/local_cover_service.dart index 00af001ad..269066efd 100644 --- a/lib/local_audio/local_cover_service.dart +++ b/lib/local_audio/local_cover_service.dart @@ -20,8 +20,9 @@ class LocalCoverService { required String albumId, required String path, }) async { - if (albumId.isNotEmpty == true) { - final metadata = readMetadata(File(path), getImage: true); + final file = File(path); + if (file.existsSync() && albumId.isNotEmpty == true) { + final metadata = readMetadata(file, getImage: true); final cover = _put( albumId: albumId, data: metadata.pictures diff --git a/lib/player/view/player_main_controls.dart b/lib/player/view/player_main_controls.dart index 2604ddfdb..d4ba099ce 100644 --- a/lib/player/view/player_main_controls.dart +++ b/lib/player/view/player_main_controls.dart @@ -50,11 +50,11 @@ class PlayerMainControls extends StatelessWidget with WatchItMixin { final playButton = avatarPlayButton ? CircleAvatar( - radius: avatarIconRadius, + radius: bigPlayButtonRadius, backgroundColor: avatarColor ?? (theme.isLight ? Colors.black : Colors.white), child: SizedBox.square( - dimension: 2 * avatarIconRadius, + dimension: 2 * bigPlayButtonRadius, child: rawPlayButton, ), ) diff --git a/lib/playlists/view/add_to_playlist_dialog.dart b/lib/playlists/view/add_to_playlist_dialog.dart index 1eaaf4ae9..305716a95 100644 --- a/lib/playlists/view/add_to_playlist_dialog.dart +++ b/lib/playlists/view/add_to_playlist_dialog.dart @@ -9,6 +9,7 @@ import '../../common/view/global_keys.dart'; import '../../common/view/icons.dart'; import '../../common/view/side_bar_fall_back_image.dart'; import '../../common/view/theme.dart'; +import '../../constants.dart'; import '../../l10n/l10n.dart'; import '../../library/library_model.dart'; import 'add_to_playlist_snack_bar.dart'; @@ -70,29 +71,43 @@ class _PlaylistTilesList extends StatelessWidget with WatchItMixin { final playlistNames = watchPropertyValue( (LibraryModel m) => m.playlists.keys.map((e) => e.toString()), ); - return ListView( - shrinkWrap: true, - children: [ - ListTile( - onTap: () => playlistNavigatorKey.currentState?.pushNamed('/new'), - leading: SideBarFallBackImage( - color: Colors.transparent, - child: Icon(Iconz.plus), - ), - title: Text(context.l10n.createNewPlaylist), + + final children = [ + ListTile( + onTap: () => playlistNavigatorKey.currentState?.pushNamed('/new'), + leading: SideBarFallBackImage( + color: Colors.transparent, + child: Icon(Iconz.plus), ), - ...playlistNames.map( - (playlistId) => Builder( - builder: (context) { - return _PlaylistTile( - playlistId: playlistId, - libraryModel: di(), - audio: audio, - ); - }, - ), + title: Text(context.l10n.createNewPlaylist), + ), + _PlaylistTile( + playlistId: kLikedAudiosPageId, + title: context.l10n.likedSongs, + iconData: Iconz.heartFilled, + libraryModel: di(), + audio: audio, + ), + ...playlistNames.map( + (playlistId) => Builder( + builder: (context) { + return _PlaylistTile( + playlistId: playlistId, + libraryModel: di(), + audio: audio, + ); + }, ), - ], + ), + ]; + + return ListView.separated( + shrinkWrap: true, + itemCount: children.length, + separatorBuilder: (context, index) => const SizedBox( + height: 10, + ), + itemBuilder: (context, index) => children.elementAt(index), ); } } @@ -102,11 +117,15 @@ class _PlaylistTile extends StatelessWidget { required this.libraryModel, required this.audio, required this.playlistId, + this.title, + this.iconData, }); final LibraryModel libraryModel; final Audio audio; final String playlistId; + final String? title; + final IconData? iconData; @override Widget build(BuildContext context) { @@ -122,9 +141,9 @@ class _PlaylistTile extends StatelessWidget { }, leading: SideBarFallBackImage( color: getAlphabetColor(playlistId), - child: Icon(Iconz.starFilled), + child: Icon(iconData ?? Iconz.starFilled), ), - title: Text(playlistId), + title: Text(title ?? playlistId), ); } } diff --git a/lib/podcasts/view/podcast_page.dart b/lib/podcasts/view/podcast_page.dart index 228196623..1d3c7e212 100644 --- a/lib/podcasts/view/podcast_page.dart +++ b/lib/podcasts/view/podcast_page.dart @@ -183,9 +183,10 @@ class _PodcastPageState extends State { ), ), SliverPadding( - padding: - getAdaptiveHorizontalPadding(constraints: constraints) - .copyWith(bottom: kYaruPagePadding), + padding: getAdaptiveHorizontalPadding( + min: isMobile ? 0 : 15, + constraints: constraints, + ).copyWith(bottom: kYaruPagePadding), sliver: SliverPodcastPageList( audios: episodesWithDownloads, pageId: widget.feedUrl,