Files
harmonia/Harmonia.WinUI/Views/PlaylistView.xaml.cs

251 lines
7.7 KiB
C#

using CommunityToolkit.WinUI;
using Harmonia.Core.Playlists;
using Harmonia.WinUI.ViewModels;
using Microsoft.UI.Dispatching;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Media.Imaging;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using Windows.UI.Popups;
namespace Harmonia.WinUI.Views;
public sealed partial class PlaylistView : UserControl
{
private readonly PlaylistViewModel _viewModel;
public PlaylistView()
{
InitializeComponent();
_viewModel = (PlaylistViewModel)DataContext;
_viewModel.PropertyChanging += OnViewModelPropertyChanging;
_viewModel.PropertyChanged += OnViewModelPropertyChanged;
_viewModel.PlayingSongChangedAutomatically += OnPlayingSongChangedAutomatically;
foreach (MenuFlyoutItemBase item in PlaylistListViewMenuFlyout.Items)
{
item.DataContextChanged += Item_DataContextChanged;
}
}
private void OnViewModelPropertyChanging(object? sender, PropertyChangingEventArgs e)
{
if (e.PropertyName == nameof(_viewModel.PlayingSong))
{
ListViewItem listViewItem = (ListViewItem)PlaylistListView.ContainerFromItem(_viewModel.PlayingSong);
if (listViewItem != null)
{
UpdateListViewItemStyle(listViewItem, false);
}
}
}
private void OnViewModelPropertyChanged(object? sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(_viewModel.PlayingSong))
{
ListViewItem listViewItem = (ListViewItem)PlaylistListView.ContainerFromItem(_viewModel.PlayingSong);
UpdateListViewItemStyle(listViewItem, true);
}
}
private void UpdateListViewItemStyle(FrameworkElement listViewItem, bool isPlaying)
{
if (listViewItem == null)
return;
FrameworkElement? frameworkElement;
if (listViewItem.Name == "PlaylistSongListViewItem")
{
frameworkElement = listViewItem;
}
else
{
if (listViewItem.FindDescendant("PlaylistSongListViewItem") is not FrameworkElement frameworkElement2)
return;
frameworkElement = frameworkElement2;
}
if (frameworkElement == null)
return;
string songItemTitleBrushName = isPlaying ? "PlayingSongTitleTextBlock" : "SongTitleTextBlock";
string songItemSubtitleBrushName = isPlaying ? "PlayingSongSubtitleTextBlock" : "SongSubtitleTextBlock";
UpdateElementStyle(frameworkElement, "SongTitleTextBlock", songItemTitleBrushName);
UpdateElementStyle(frameworkElement, "SongArtistsTextBlock", songItemSubtitleBrushName);
UpdateElementStyle(frameworkElement, "SongAlbumTextBlock", songItemSubtitleBrushName);
}
private void UpdateElementStyle(FrameworkElement dependencyObject, string elementName, string resourceName)
{
if (dependencyObject.FindDescendant(elementName) is not FrameworkElement frameworkElement)
return;
Resources.TryGetValue(resourceName, out object? resource);
if (resource == null)
Application.Current.Resources.TryGetValue(resourceName, out resource);
if (resource is not Style style)
return;
frameworkElement.Style = style;
}
private void OnPlayingSongChangedAutomatically(object? sender, EventArgs e)
{
BringPlayingSongIntoView();
}
private void BringPlayingSongIntoView()
{
PlaylistSong? playingSong = _viewModel.PlayingSong;
if (playingSong == null)
return;
ListViewItem listViewItem = (ListViewItem)PlaylistListView.ContainerFromItem(playingSong);
if (listViewItem != null)
{
listViewItem.UpdateLayout();
listViewItem.StartBringIntoView(new BringIntoViewOptions() { VerticalAlignmentRatio = .5, AnimationDesired = true });
}
else
{
PlaylistListView.UpdateLayout();
PlaylistListView.ScrollIntoView(playingSong);
}
}
private void Item_DataContextChanged(FrameworkElement sender, DataContextChangedEventArgs args)
{
if (sender is not MenuFlyoutItemBase item)
return;
if (args.NewValue == _viewModel)
return;
item.DataContext = _viewModel;
}
private void Image_Loaded(object sender, RoutedEventArgs e)
{
if (sender is not Image image)
return;
image.DataContextChanged += Image_DataContextChanged;
if (image.DataContext is not PlaylistSong playlistSong)
return;
//Task.Run(async () => await UpdateImage(image, playlistSong));
UpdateImage(image, playlistSong);
}
private void Image_Unloaded(object sender, RoutedEventArgs e)
{
if (sender is not Image image)
return;
image.DataContextChanged -= Image_DataContextChanged;
}
private void Image_DataContextChanged(FrameworkElement sender, DataContextChangedEventArgs args)
{
if (sender is not Image image)
return;
if (args.NewValue is not PlaylistSong playlistSong)
return;
//Task.Run(async () => await UpdateImage(image, playlistSong));
UpdateImage(image, playlistSong);
}
private void UpdateImage(Image image, PlaylistSong playlistSong)
{
int hashCode = image.GetHashCode();
//BitmapImage? bitmapImage = await _viewModel.GetBitmapImageAsync(hashCode, playlistSong);
DispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, async () =>
{
BitmapImage? bitmapImage = await _viewModel.GetBitmapImageAsync(hashCode, playlistSong);
image.Source = bitmapImage;
});
}
private void PlaylistSongListViewItem_DataContextChanged(FrameworkElement sender, DataContextChangedEventArgs args)
{
if (args.NewValue is not PlaylistSong playlistSong)
return;
bool isPlaying = playlistSong == _viewModel.PlayingSong;
UpdateListViewItemStyle(sender, isPlaying);
}
private async void PlaylistListViewItem_DoubleTapped(object sender, DoubleTappedRoutedEventArgs e)
{
if (sender is not FrameworkElement element)
return;
if (element == null || element.DataContext is not PlaylistSong playlistSong)
return;
await _viewModel.PlaySongAsync(playlistSong);
}
private void PlaylistListViewItem_RightTapped(object sender, RightTappedRoutedEventArgs e)
{
if (sender is not FrameworkElement element)
return;
if (element == null || element.DataContext is not PlaylistSong playlistSong)
return;
if (PlaylistListView.SelectedItems.Contains(playlistSong))
return;
int index = PlaylistListView.Items.IndexOf(playlistSong);
PlaylistListView.DeselectAll();
PlaylistListView.SelectRange(new ItemIndexRange(index, 1));
}
private void PlaylistListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (sender is not ListView listView)
return;
PlaylistSong[] selectedPlaylistSongs = [.. listView.SelectedItems.Cast<PlaylistSong>()];
_viewModel.SelectedPlaylistSongs = [.. selectedPlaylistSongs];
}
private void MenuFlyout_Opening(object sender, object e)
{
if (sender is not MenuFlyout menuFlyout)
return;
foreach (MenuFlyoutItemBase item in menuFlyout.Items)
{
if (item.DataContext != _viewModel)
{
item.DataContext = _viewModel;
}
}
}
}