Added playlist view.
This commit is contained in:
BIN
Harmonia.WinUI/Assets/Default.png
Normal file
BIN
Harmonia.WinUI/Assets/Default.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.9 MiB |
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net9.0-windows10.0.19041.0</TargetFramework>
|
||||
<TargetFramework>net9.0-windows10.0.26100.0</TargetFramework>
|
||||
<TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion>
|
||||
<RootNamespace>Harmonia.WinUI</RootNamespace>
|
||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||
@@ -43,6 +43,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.Media" Version="8.1.240916" />
|
||||
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.1742" />
|
||||
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.7.250310001" />
|
||||
</ItemGroup>
|
||||
@@ -59,6 +60,9 @@
|
||||
<Page Update="Resources\Converters.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Update="Views\PlaylistView.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Update="Views\PlayerView.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:Harmonia.WinUI"
|
||||
xmlns:views="using:Harmonia.WinUI.Views"
|
||||
xmlns:Media="using:CommunityToolkit.WinUI.Media"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d"
|
||||
@@ -18,6 +19,22 @@
|
||||
<RowDefinition Height="*"></RowDefinition>
|
||||
<RowDefinition Height="Auto"></RowDefinition>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid Grid.RowSpan="2">
|
||||
<Image Source="/Assets/Default.png" Stretch="UniformToFill" VerticalAlignment="Center" HorizontalAlignment="Center"></Image>
|
||||
<Canvas Background="#99000000"></Canvas>
|
||||
<Border>
|
||||
<Border.Background>
|
||||
<Media:BackdropBlurBrush Amount="20"></Media:BackdropBlurBrush>
|
||||
</Border.Background>
|
||||
</Border>
|
||||
</Grid>
|
||||
<Grid Grid.Row="0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition></ColumnDefinition>
|
||||
<ColumnDefinition></ColumnDefinition>
|
||||
</Grid.ColumnDefinitions>
|
||||
<views:PlaylistView Grid.Column="1"></views:PlaylistView>
|
||||
</Grid>
|
||||
<!--<views:PlayingSongInfo Grid.Row="0"></views:PlayingSongInfo>-->
|
||||
<views:PlayerView Grid.Row="1"></views:PlayerView>
|
||||
</Grid>
|
||||
|
||||
@@ -1,36 +1,11 @@
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Controls.Primitives;
|
||||
using Microsoft.UI.Xaml.Data;
|
||||
using Microsoft.UI.Xaml.Input;
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices.WindowsRuntime;
|
||||
using Windows.Foundation;
|
||||
using Windows.Foundation.Collections;
|
||||
|
||||
// To learn more about WinUI, the WinUI project structure,
|
||||
// and more about our project templates, see: http://aka.ms/winui-project-info.
|
||||
namespace Harmonia.WinUI;
|
||||
|
||||
namespace Harmonia.WinUI
|
||||
{
|
||||
/// <summary>
|
||||
/// An empty window that can be used on its own or navigated to within a Frame.
|
||||
/// </summary>
|
||||
public sealed partial class MainWindow : Window
|
||||
{
|
||||
public MainWindow()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
}
|
||||
|
||||
private void myButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
//myButton.Content = "Clicked";
|
||||
}
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
@@ -122,4 +122,13 @@
|
||||
M11 1a2 2 0 0 0-2 2v4a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V9a2 2 0 0 1 2-2h5V3a3 3 0 0 1 6 0v4a.5.5 0 0 1-1 0V3a2 2 0 0 0-2-2M3 8a1 1 0 0 0-1 1v5a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V9a1 1 0 0 0-1-1z
|
||||
</x:String>
|
||||
|
||||
<x:String x:Key="AddIcon">
|
||||
M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4
|
||||
</x:String>
|
||||
|
||||
<x:String x:Key="MoreIcon">
|
||||
M3 9.5a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3m5 0a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3m5 0a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3
|
||||
</x:String>
|
||||
|
||||
|
||||
</ResourceDictionary>
|
||||
|
||||
@@ -10,6 +10,11 @@
|
||||
<Setter Property="BorderThickness" Value="0"/>
|
||||
</Style>
|
||||
|
||||
<!-- Flat Round Button -->
|
||||
<Style x:Key="FlatRoundButton" TargetType="Button" BasedOn="{StaticResource FlatButton}">
|
||||
<Setter Property="CornerRadius" Value="32"/>
|
||||
</Style>
|
||||
|
||||
<!-- Flat Button Path Icon -->
|
||||
<Style x:Key="FlatButtonIcon" TargetType="PathIcon">
|
||||
<Setter Property="Width" Value="18"/>
|
||||
|
||||
@@ -4,7 +4,7 @@ namespace Harmonia.WinUI.Storage;
|
||||
|
||||
public interface IStorageProvider
|
||||
{
|
||||
public Task<string> GetFileAsync(FilePickerOptions? options = null);
|
||||
public Task<string?> GetSingleFileAsync(FilePickerOptions? options = null);
|
||||
public Task<string[]> GetFilesAsync(FilePickerOptions? options = null);
|
||||
public Task<string> GetPathAsync();
|
||||
public Task<string?> GetPathAsync();
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
@@ -7,16 +8,18 @@ using Windows.Storage.Pickers;
|
||||
|
||||
namespace Harmonia.WinUI.Storage;
|
||||
|
||||
public class WindowsStorageProvider(MainWindow mainWindow) : IStorageProvider
|
||||
public class WindowsStorageProvider : IStorageProvider
|
||||
{
|
||||
public async Task<string> GetFileAsync(FilePickerOptions? options = null)
|
||||
private static MainWindow MainWindow => App.ServiceProvider.GetRequiredService<MainWindow>();
|
||||
|
||||
public async Task<string?> GetSingleFileAsync(FilePickerOptions? options = null)
|
||||
{
|
||||
FileOpenPicker fileOpenPicker = GetFileOpenPicker(options);
|
||||
InitializePicker(fileOpenPicker);
|
||||
|
||||
StorageFile storageFile = await fileOpenPicker.PickSingleFileAsync();
|
||||
StorageFile? storageFile = await fileOpenPicker.PickSingleFileAsync();
|
||||
|
||||
return storageFile.Path;
|
||||
return storageFile?.Path;
|
||||
}
|
||||
|
||||
public async Task<string[]> GetFilesAsync(FilePickerOptions? options = null)
|
||||
@@ -67,7 +70,7 @@ public class WindowsStorageProvider(MainWindow mainWindow) : IStorageProvider
|
||||
return [.. fileTypes.SelectMany(fileType => fileType.Patterns)];
|
||||
}
|
||||
|
||||
public async Task<string> GetPathAsync()
|
||||
public async Task<string?> GetPathAsync()
|
||||
{
|
||||
var folderPicker = new FolderPicker
|
||||
{
|
||||
@@ -77,14 +80,14 @@ public class WindowsStorageProvider(MainWindow mainWindow) : IStorageProvider
|
||||
|
||||
InitializePicker(folderPicker);
|
||||
|
||||
StorageFolder folder = await folderPicker.PickSingleFolderAsync();
|
||||
StorageFolder? folder = await folderPicker.PickSingleFolderAsync();
|
||||
|
||||
return folder.Path;
|
||||
return folder?.Path;
|
||||
}
|
||||
|
||||
private void InitializePicker(object target)
|
||||
private static void InitializePicker(object target)
|
||||
{
|
||||
var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(mainWindow);
|
||||
var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(MainWindow);
|
||||
WinRT.Interop.InitializeWithWindow.Initialize(target, hWnd);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Harmonia.Core.Engine;
|
||||
using Harmonia.Core.Models;
|
||||
using Harmonia.Core.Player;
|
||||
using Harmonia.WinUI.Caching;
|
||||
@@ -7,6 +8,7 @@ using Microsoft.UI.Dispatching;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Media.Imaging;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
@@ -196,6 +198,7 @@ public partial class PlayerViewModel : ViewModelBase
|
||||
{
|
||||
_audioPlayer = audioPlayer;
|
||||
_audioPlayer.PlayingSongChanged += OnPlayingSongChanged;
|
||||
_audioPlayer.PropertyChanged += OnAudioPlayerPropertyChanged;
|
||||
|
||||
_audioBitmapImageCache = audioBitmapCache;
|
||||
|
||||
@@ -232,6 +235,28 @@ public partial class PlayerViewModel : ViewModelBase
|
||||
DispatcherQueue.GetForCurrentThread().TryEnqueue(() => SongImageSource = bitmapImage);
|
||||
}
|
||||
|
||||
private void OnAudioPlayerPropertyChanged(object? sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
switch (e.PropertyName)
|
||||
{
|
||||
case nameof(_audioPlayer.State):
|
||||
UpdateTimer();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateTimer()
|
||||
{
|
||||
if (_audioPlayer.State == AudioPlaybackState.Playing)
|
||||
{
|
||||
_timer.Start();
|
||||
}
|
||||
else
|
||||
{
|
||||
_timer.Stop();
|
||||
}
|
||||
}
|
||||
|
||||
private void TickTock(object? sender, object e)
|
||||
{
|
||||
Position = _audioPlayer.Position;
|
||||
|
||||
@@ -20,6 +20,8 @@ using System.Threading.Tasks;
|
||||
using System.Timers;
|
||||
using System.Windows.Input;
|
||||
using Windows.ApplicationModel.DataTransfer;
|
||||
using Windows.System;
|
||||
using DispatcherQueue = Microsoft.UI.Dispatching.DispatcherQueue;
|
||||
using Timer = System.Timers.Timer;
|
||||
|
||||
namespace Harmonia.WinUI.ViewModels;
|
||||
@@ -31,6 +33,7 @@ public partial class PlaylistViewModel : ViewModelBase
|
||||
private readonly IAudioFileScanner _audioFileScanner;
|
||||
private readonly IAudioEngine _audioEngine;
|
||||
private readonly IStorageProvider _storageProvider;
|
||||
private readonly DispatcherQueue _dispatcherQueue;
|
||||
|
||||
private Timer? _filterTimer;
|
||||
|
||||
@@ -121,7 +124,8 @@ public partial class PlaylistViewModel : ViewModelBase
|
||||
IAudioBitmapImageCache audioBitmapImageCache,
|
||||
IAudioFileScanner audioFileScanner,
|
||||
IAudioEngine audioEngine,
|
||||
IStorageProvider storageProvider)
|
||||
IStorageProvider storageProvider,
|
||||
IPlaylistRepository playlistRepository)
|
||||
{
|
||||
_audioPlayer = audioPlayer;
|
||||
_audioPlayer.PlaylistChanged += OnPlaylistChanged;
|
||||
@@ -131,6 +135,23 @@ public partial class PlaylistViewModel : ViewModelBase
|
||||
_audioFileScanner = audioFileScanner;
|
||||
_audioEngine = audioEngine;
|
||||
_storageProvider = storageProvider;
|
||||
_dispatcherQueue = DispatcherQueue.GetForCurrentThread();
|
||||
|
||||
// Testing
|
||||
Task.Run(() => PlayDemoSong(playlistRepository));
|
||||
}
|
||||
|
||||
private async Task PlayDemoSong(IPlaylistRepository playlistRepository)
|
||||
{
|
||||
if (playlistRepository.Get().Count == 0)
|
||||
{
|
||||
playlistRepository.AddPlaylist();
|
||||
}
|
||||
|
||||
Playlist playlist = playlistRepository.Get().First();
|
||||
|
||||
if (playlist.Songs.Count > 0)
|
||||
await _audioPlayer.LoadAsync(playlist.Songs[0], PlaybackMode.LoadOnly);
|
||||
}
|
||||
|
||||
private void OnPlaylistChanged(object? sender, EventArgs e)
|
||||
@@ -161,10 +182,10 @@ public partial class PlaylistViewModel : ViewModelBase
|
||||
switch (e.Action)
|
||||
{
|
||||
case PlaylistUpdateAction.Add:
|
||||
DispatcherQueue.GetForCurrentThread().TryEnqueue(() => AddSongs(e.Songs, e.Index));
|
||||
_dispatcherQueue.TryEnqueue(() => AddSongs(e.Songs, e.Index));
|
||||
break;
|
||||
case PlaylistUpdateAction.Remove:
|
||||
DispatcherQueue.GetForCurrentThread().TryEnqueue(() => RemoveSongsFromCollection(e.Songs));
|
||||
_dispatcherQueue.TryEnqueue(() => RemoveSongsFromCollection(e.Songs));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -232,7 +253,7 @@ public partial class PlaylistViewModel : ViewModelBase
|
||||
_filterTimer.Dispose();
|
||||
_filterTimer = null;
|
||||
|
||||
DispatcherQueue.GetForCurrentThread().TryEnqueue(UpdateFilteredSongs);
|
||||
_dispatcherQueue.TryEnqueue(UpdateFilteredSongs);
|
||||
}
|
||||
|
||||
private void UpdateFilteredSongs()
|
||||
@@ -304,10 +325,12 @@ public partial class PlaylistViewModel : ViewModelBase
|
||||
|
||||
private FilePickerFileType GetAudioFileTypes()
|
||||
{
|
||||
string[] patterns = _audioEngine.SupportedFormats.Select(format => format.Replace("*", "")).ToArray();
|
||||
|
||||
return new()
|
||||
{
|
||||
Name = "Audio Files",
|
||||
Patterns = [.. _audioEngine.SupportedFormats]
|
||||
Patterns = patterns
|
||||
};
|
||||
}
|
||||
|
||||
@@ -316,7 +339,7 @@ public partial class PlaylistViewModel : ViewModelBase
|
||||
if (Playlist == null)
|
||||
return;
|
||||
|
||||
string path = await _storageProvider.GetPathAsync();
|
||||
string? path = await _storageProvider.GetPathAsync();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(path))
|
||||
return;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
<Style x:Key="PlayerGrid" TargetType="Grid">
|
||||
<Setter Property="Background" Value="#1a1a1a"/>
|
||||
<Setter Property="Padding" Value="10"/>
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
</Style>
|
||||
<Style x:Key="SongImage" TargetType="Image">
|
||||
<Setter Property="Width" Value="80"/>
|
||||
|
||||
134
Harmonia.WinUI/Views/PlaylistView.xaml
Normal file
134
Harmonia.WinUI/Views/PlaylistView.xaml
Normal file
@@ -0,0 +1,134 @@
|
||||
<UserControl
|
||||
x:Class="Harmonia.WinUI.Views.PlaylistView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:Harmonia.WinUI.Views"
|
||||
xmlns:vm="using:Harmonia.WinUI.ViewModels"
|
||||
xmlns:playlists="using:Harmonia.Core.Playlists"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
DataContext="{Binding Source={StaticResource Locator}, Path=PlaylistViewModel}"
|
||||
d:DataContext="{d:DesignInstance Type=vm:PlaylistViewModel, IsDesignTimeCreatable=True}"
|
||||
mc:Ignorable="d">
|
||||
<UserControl.Resources>
|
||||
<!--<SolidColorBrush x:Key="PlaylistBackground" Color="#393a45"/>-->
|
||||
<SolidColorBrush x:Key="PlaylistBackground" Color="#292a35"/>
|
||||
<SolidColorBrush x:Key="PlaylistItemHighlightColor" Color="#494a55"/>
|
||||
<!--<SolidColorBrush x:Key="PlaylistBackground" Color="#222"/>-->
|
||||
<SolidColorBrush x:Key="SongItemTitleBrush" Color="#dddddd"/>
|
||||
<SolidColorBrush x:Key="SongItemTitleBrushHighlighted" Color="#A2D2F6"/>
|
||||
<SolidColorBrush x:Key="SongItemSubtitleBrush" Color="#aaaaaa"/>
|
||||
<!--<SolidColorBrush x:Key="SongItemSubtitleBrushHighlighted" Color="#76b9ed"/>-->
|
||||
<SolidColorBrush x:Key="SongItemSubtitleBrushHighlighted" Color="#ddA2D2F6"/>
|
||||
|
||||
<SolidColorBrush x:Key="SongItemFooterBrush" Color="#888"/>
|
||||
<SolidColorBrush x:Key="SongItemFooterBrushHighlighted" Color="#aaA2D2F6"/>
|
||||
|
||||
<!-- Image Border -->
|
||||
<Style x:Key="PlaylistSongImageBorder" TargetType="Border">
|
||||
<Setter Property="Width" Value="75"/>
|
||||
<Setter Property="Height" Value="75"/>
|
||||
<Setter Property="CornerRadius" Value="8"/>
|
||||
</Style>
|
||||
|
||||
<DataTemplate x:Key="SongTemplate" x:DataType="playlists:PlaylistSong">
|
||||
<!-- Background was formerly transparent -->
|
||||
<Border DoubleTapped="PlaylistListViewItem_DoubleTapped" Background="Transparent">
|
||||
<Grid Padding="10">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"></ColumnDefinition>
|
||||
<ColumnDefinition Width="*"></ColumnDefinition>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Border Grid.Column="0" Style="{StaticResource PlaylistSongImageBorder}">
|
||||
<Grid>
|
||||
<Image Loaded="Image_Loaded" Unloaded="Image_Unloaded"></Image>
|
||||
<Canvas Background="#19000000"></Canvas>
|
||||
</Grid>
|
||||
</Border>
|
||||
<Grid Grid.Column="1" Margin="10 0 0 0" VerticalAlignment="Center">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"></ColumnDefinition>
|
||||
<ColumnDefinition Width="60"></ColumnDefinition>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition></RowDefinition>
|
||||
<RowDefinition></RowDefinition>
|
||||
<RowDefinition></RowDefinition>
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock Grid.Column="0" Grid.Row="0" Foreground="{StaticResource SongItemTitleBrush}" Text="{x:Bind Song, Converter={StaticResource SongTitle}, Mode=OneWay}" FontSize="15" FontWeight="SemiBold" LineStackingStrategy="BlockLineHeight" VerticalAlignment="Center" TextTrimming="CharacterEllipsis" LineHeight="0">
|
||||
</TextBlock>
|
||||
<TextBlock Grid.Row="1" Text="{Binding Song.Artists, Converter={StaticResource ArtistsToString}}" Foreground="{StaticResource SongItemSubtitleBrush}" TextTrimming="CharacterEllipsis" LineStackingStrategy="BlockLineHeight" LineHeight="0" FontSize="14" Margin="0 0 0 0">
|
||||
</TextBlock>
|
||||
<TextBlock Grid.Row="2" Text="{Binding Song.Album}" Foreground="{StaticResource SongItemSubtitleBrush}" TextTrimming="CharacterEllipsis" LineStackingStrategy="BlockLineHeight" LineHeight="0" FontSize="14" Margin="0 0 0 0">
|
||||
</TextBlock>
|
||||
<TextBlock Grid.Row="0" Grid.Column="1" HorizontalAlignment="Right" VerticalAlignment="Center" TextAlignment="Right" HorizontalTextAlignment="Right" Foreground="{StaticResource SongItemSubtitleBrush}" TextTrimming="CharacterEllipsis" LineStackingStrategy="BlockLineHeight" LineHeight="0" FontSize="13" Text="{Binding Song.Length.TotalSeconds, Converter={StaticResource SecondsToString}}"></TextBlock>
|
||||
<TextBlock Grid.Row="1" Grid.Column="1" HorizontalAlignment="Right" VerticalAlignment="Center" Foreground="{StaticResource SongItemFooterBrush}" TextTrimming="CharacterEllipsis" LineStackingStrategy="BlockLineHeight" LineHeight="0" FontSize="12" Text="{Binding Song.FileType}"></TextBlock>
|
||||
<TextBlock Grid.Row="2" Grid.Column="1" HorizontalAlignment="Right" VerticalAlignment="Center" Foreground="{StaticResource SongItemFooterBrush}" TextTrimming="CharacterEllipsis" LineStackingStrategy="BlockLineHeight" LineHeight="0" FontSize="12">
|
||||
<Run Text="{Binding Song.BitRate}"></Run><Run Text=" kbps"></Run>
|
||||
</TextBlock>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</UserControl.Resources>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"></RowDefinition>
|
||||
<RowDefinition Height="*"></RowDefinition>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid Grid.Row="0" Margin="10">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"></ColumnDefinition>
|
||||
<ColumnDefinition Width="Auto"></ColumnDefinition>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBox Grid.Column="0" Text="{Binding Filter, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Center" Margin="10 0" HorizontalAlignment="Stretch" PlaceholderText="Filter"></TextBox>
|
||||
<StackPanel Grid.Column="1" Orientation="Horizontal" Spacing="10">
|
||||
<Button Style="{StaticResource FlatRoundButton}" Foreground="#7FD184">
|
||||
<Button.Content>
|
||||
<Path Style="{StaticResource FlatButtonPath}" Fill="#7FD184" Data="{StaticResource AddIcon}"></Path>
|
||||
</Button.Content>
|
||||
<Button.Flyout>
|
||||
<MenuFlyout Placement="Bottom">
|
||||
<MenuFlyoutItem Text="Add Files..." Command="{Binding AddFilesCommand}">
|
||||
<MenuFlyoutItem.Icon>
|
||||
<PathIcon Data="{StaticResource CopyIcon}"></PathIcon>
|
||||
</MenuFlyoutItem.Icon>
|
||||
</MenuFlyoutItem>
|
||||
<MenuFlyoutItem Text="Add Folder..." Command="{Binding AddFolderCommand}">
|
||||
<MenuFlyoutItem.Icon>
|
||||
<PathIcon Data="{StaticResource CopyIcon}"></PathIcon>
|
||||
</MenuFlyoutItem.Icon>
|
||||
</MenuFlyoutItem>
|
||||
</MenuFlyout>
|
||||
</Button.Flyout>
|
||||
</Button>
|
||||
<Button Style="{StaticResource FlatRoundButton}">
|
||||
<Button.Content>
|
||||
<Path Style="{StaticResource FlatButtonPath}" Data="{StaticResource MoreIcon}"></Path>
|
||||
</Button.Content>
|
||||
<Button.Flyout>
|
||||
<MenuFlyout Placement="Bottom">
|
||||
<MenuFlyoutItem Text="Add Files..." Command="{Binding AddFilesCommand}">
|
||||
<MenuFlyoutItem.Icon>
|
||||
<PathIcon Data="{StaticResource CopyIcon}"></PathIcon>
|
||||
</MenuFlyoutItem.Icon>
|
||||
</MenuFlyoutItem>
|
||||
<MenuFlyoutItem Text="Add Folder..." Command="{Binding AddFolderCommand}">
|
||||
<MenuFlyoutItem.Icon>
|
||||
<PathIcon Data="{StaticResource CopyIcon}"></PathIcon>
|
||||
</MenuFlyoutItem.Icon>
|
||||
</MenuFlyoutItem>
|
||||
</MenuFlyout>
|
||||
</Button.Flyout>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
<ListView
|
||||
Grid.Row="1"
|
||||
Name="PlaylistListView"
|
||||
ItemsSource="{Binding FilteredPlaylistSongs}"
|
||||
ItemTemplate="{StaticResource SongTemplate}"
|
||||
SelectionMode="Extended">
|
||||
</ListView>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
57
Harmonia.WinUI/Views/PlaylistView.xaml.cs
Normal file
57
Harmonia.WinUI/Views/PlaylistView.xaml.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
using Harmonia.Core.Playlists;
|
||||
using Harmonia.WinUI.ViewModels;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Input;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Harmonia.WinUI.Views;
|
||||
|
||||
public sealed partial class PlaylistView : UserControl
|
||||
{
|
||||
private readonly PlaylistViewModel _viewModel;
|
||||
|
||||
public PlaylistView()
|
||||
{
|
||||
InitializeComponent();
|
||||
_viewModel = (PlaylistViewModel)DataContext;
|
||||
}
|
||||
|
||||
private void Image_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
//Image? image = sender as Image;
|
||||
|
||||
//if (image == null)
|
||||
// return;
|
||||
|
||||
//image.DataContextChanged += Image_DataContextChanged;
|
||||
|
||||
//var song = (PlaylistSong)image.DataContext;
|
||||
|
||||
//if (song == null)
|
||||
// return;
|
||||
|
||||
//Task.Run(async () => await FetchImage(song.Song, image));
|
||||
}
|
||||
|
||||
private void Image_Unloaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
//Image? image = sender as Image;
|
||||
|
||||
//if (image == null)
|
||||
// return;
|
||||
|
||||
//image.DataContextChanged -= Image_DataContextChanged;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user