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.Imaging; using System; using System.Linq; namespace Harmonia.WinUI.Views; public sealed partial class PlaylistView : UserControl { private readonly PlaylistViewModel _viewModel; public PlaylistView() { InitializeComponent(); _viewModel = (PlaylistViewModel)DataContext; _viewModel.PlayingSongChangedAutomatically += OnPlayingSongChangedAutomatically; foreach (MenuFlyoutItemBase item in PlaylistListViewMenuFlyout.Items) { item.DataContextChanged += Item_DataContextChanged; } } 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 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()]; _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; } } } }