Added resource classses and a missing converter.

This commit is contained in:
2025-03-24 23:31:01 -04:00
parent 9245e9c4cc
commit 97f6040122
14 changed files with 507 additions and 49 deletions

View File

@@ -9,6 +9,10 @@
<ResourceDictionary.MergedDictionaries>
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
<!-- Other merged dictionaries here -->
<ResourceDictionary Source="/Resources/Converters.xaml"/>
<ResourceDictionary Source="/Resources/Geometry.xaml"/>
<ResourceDictionary Source="/Resources/Styles.xaml"/>
<ResourceDictionary Source="/Resources/ViewModels.xaml"/>
</ResourceDictionary.MergedDictionaries>
<!-- Other app resources here -->
</ResourceDictionary>

View File

@@ -1,50 +1,46 @@
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 Microsoft.UI.Xaml.Shapes;
using Harmonia.Core.Extensions;
using Harmonia.WinUI.Caching;
using Harmonia.WinUI.Storage;
using Harmonia.WinUI.ViewModels;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.UI.Xaml;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Activation;
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
public partial class App : Application
{
/// <summary>
/// Provides application-specific behavior to supplement the default Application class.
/// </summary>
public partial class App : Application
private Window? _mainWindow;
public static IServiceProvider ServiceProvider { get; private set; }
static App()
{
/// <summary>
/// Initializes the singleton application object. This is the first line of authored code
/// executed, and as such is the logical equivalent of main() or WinMain().
/// </summary>
public App()
{
this.InitializeComponent();
}
ServiceCollection services = new();
/// <summary>
/// Invoked when the application is launched.
/// </summary>
/// <param name="args">Details about the launch request and process.</param>
protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
{
m_window = new MainWindow();
m_window.Activate();
}
services.AddSingleton<MainWindow>();
private Window? m_window;
//services.AddSingleton<MainViewModel>();
services.AddSingleton<PlayerViewModel>();
//services.AddSingleton<PlayingSongInfoViewModel>();
services.AddSingleton<PlaylistViewModel>();
services.AddSingleton<IAudioBitmapImageCache, AudioBitmapImageCache>();
services.AddSingleton<IStorageProvider, WindowsStorageProvider>();
services.AddHarmonia();
ServiceProvider = services.BuildServiceProvider();
}
}
public App()
{
InitializeComponent();
}
protected override void OnLaunched(LaunchActivatedEventArgs args)
{
_mainWindow = ServiceProvider.GetRequiredService<MainWindow>();
_mainWindow.Activate();
}
}

View File

@@ -0,0 +1,25 @@
using Microsoft.UI.Xaml.Data;
using System;
namespace Harmonia.WinUI.Converters;
public sealed partial class DoubleToPercentConverter : IValueConverter
{
public DoubleToPercentConverter()
{
}
public object? Convert(object value, Type targetType, object parameter, string language)
{
if (value is not double doubleValue)
return null;
return Math.Round(doubleValue * 100) + "%";
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}

View File

@@ -14,6 +14,10 @@
<WindowsAppSDKSelfContained>true</WindowsAppSDKSelfContained>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<None Remove="Resources\Styles.xaml" />
<None Remove="Views\PlayerView.xaml" />
</ItemGroup>
<ItemGroup>
<Content Include="Assets\SplashScreen.scale-200.png" />
@@ -46,7 +50,23 @@
<ProjectReference Include="..\Harmonia.Core\Harmonia.Core.csproj" />
</ItemGroup>
<ItemGroup>
<Folder Include="Views\" />
<Page Update="Resources\Geometry.xaml">
<SubType>Designer</SubType>
</Page>
<Page Update="Resources\ViewModels.xaml">
<SubType>Designer</SubType>
</Page>
<Page Update="Resources\Converters.xaml">
<SubType>Designer</SubType>
</Page>
<Page Update="Views\PlayerView.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Page Update="Resources\Styles.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<!--

View File

@@ -4,12 +4,22 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Harmonia.WinUI"
xmlns:views="using:Harmonia.WinUI.Views"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="Harmonia.WinUI">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
<!--<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
<Button x:Name="myButton" Click="myButton_Click">Click Me</Button>
</StackPanel>
</StackPanel>-->
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<!--<views:PlayingSongInfo Grid.Row="0"></views:PlayingSongInfo>-->
<views:PlayerView Grid.Row="1"></views:PlayerView>
</Grid>
</Window>

View File

@@ -30,7 +30,7 @@ namespace Harmonia.WinUI
private void myButton_Click(object sender, RoutedEventArgs e)
{
myButton.Content = "Clicked";
//myButton.Content = "Clicked";
}
}
}

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="using:Harmonia.WinUI.Converters">
<converters:SecondsToStringConverter x:Key="SecondsToString" />
<converters:ArtistsToStringConverter x:Key="ArtistsToString" />
<converters:NullVisibilityConverter x:Key="NullVisibility" />
<converters:SongTitleConverter x:Key="SongTitle" />
<converters:DoubleToPercentConverter x:Key="DoubleToPercent" />
<converters:RepeatStateConverter x:Key="RepeatState" />
<converters:VolumeStateConverter x:Key="VolumeState" />
</ResourceDictionary>

View File

@@ -0,0 +1,125 @@
<?xml version="1.0" encoding="utf-8"?>
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<x:String x:Key="PlayIcon">
M10.804 8 5 4.633v6.734zm.792-.696a.802.802 0 0 1 0 1.392l-6.363 3.692C4.713 12.69 4 12.345 4 11.692V4.308c0-.653.713-.998 1.233-.696z
</x:String>
<x:String x:Key="PlayFillIcon">
m11.596 8.697-6.363 3.692c-.54.313-1.233-.066-1.233-.697V4.308c0-.63.692-1.01 1.233-.696l6.363 3.692a.802.802 0 0 1 0 1.39
</x:String>
<x:String x:Key="StopIcon">
M3.5 5A1.5 1.5 0 0 1 5 3.5h6A1.5 1.5 0 0 1 12.5 5v6a1.5 1.5 0 0 1-1.5 1.5H5A1.5 1.5 0 0 1 3.5 11zM5 4.5a.5.5 0 0 0-.5.5v6a.5.5 0 0 0 .5.5h6a.5.5 0 0 0 .5-.5V5a.5.5 0 0 0-.5-.5z
</x:String>
<x:String x:Key="StopFillIcon">
M5 3.5h6A1.5 1.5 0 0 1 12.5 5v6a1.5 1.5 0 0 1-1.5 1.5H5A1.5 1.5 0 0 1 3.5 11V5A1.5 1.5 0 0 1 5 3.5
</x:String>
<x:String x:Key="PauseIcon">
M6 3.5a.5.5 0 0 1 .5.5v8a.5.5 0 0 1-1 0V4a.5.5 0 0 1 .5-.5m4 0a.5.5 0 0 1 .5.5v8a.5.5 0 0 1-1 0V4a.5.5 0 0 1 .5-.5
</x:String>
<x:String x:Key="PauseFillIcon">
M5.5 3.5A1.5 1.5 0 0 1 7 5v6a1.5 1.5 0 0 1-3 0V5a1.5 1.5 0 0 1 1.5-1.5m5 0A1.5 1.5 0 0 1 12 5v6a1.5 1.5 0 0 1-3 0V5a1.5 1.5 0 0 1 1.5-1.5
</x:String>
<x:String x:Key="SkipStartIcon">
M4 4a.5.5 0 0 1 1 0v3.248l6.267-3.636c.52-.302 1.233.043 1.233.696v7.384c0 .653-.713.998-1.233.696L5 8.752V12a.5.5 0 0 1-1 0zm7.5.633L5.696 8l5.804 3.367z
</x:String>
<x:String x:Key="SkipStartFillIcon">
M4 4a.5.5 0 0 1 1 0v3.248l6.267-3.636c.54-.313 1.232.066 1.232.696v7.384c0 .63-.692 1.01-1.232.697L5 8.753V12a.5.5 0 0 1-1 0z
</x:String>
<x:String x:Key="SkipEndIcon">
M12.5 4a.5.5 0 0 0-1 0v3.248L5.233 3.612C4.713 3.31 4 3.655 4 4.308v7.384c0 .653.713.998 1.233.696L11.5 8.752V12a.5.5 0 0 0 1 0zM5 4.633 10.804 8 5 11.367z
</x:String>
<x:String x:Key="SkipEndFillIcon">
M12.5 4a.5.5 0 0 0-1 0v3.248L5.233 3.612C4.693 3.3 4 3.678 4 4.308v7.384c0 .63.692 1.01 1.233.697L11.5 8.753V12a.5.5 0 0 0 1 0z
</x:String>
<x:String x:Key="VolumeMutedIcon">
M6.717 3.55A.5.5 0 0 1 7 4v8a.5.5 0 0 1-.812.39L3.825 10.5H1.5A.5.5 0 0 1 1 10V6a.5.5 0 0 1 .5-.5h2.325l2.363-1.89a.5.5 0 0 1 .529-.06
M13.854 5.646a.5.5 0 0 1 0 .708L12.207 8l1.647 1.646a.5.5 0 0 1-.708.708L11.5 8.707l-1.646 1.647a.5.5 0 0 1-.708-.708L10.793 8 9.146 6.354a.5.5 0 1 1 .708-.708L11.5 7.293l1.646-1.647a.5.5 0 0 1 .708 0
</x:String>
<x:String x:Key="VolumeOffIcon">
M8.707 11.182A4.5 4.5 0 0 0 10.025 8a4.5 4.5 0 0 0-1.318-3.182L8 5.525A3.5 3.5 0 0 1 9.025 8 3.5 3.5 0 0 1 8 10.475z
M6.717 3.55A.5.5 0 0 1 7 4v8a.5.5 0 0 1-.812.39L3.825 10.5H1.5A.5.5 0 0 1 1 10V6a.5.5 0 0 1 .5-.5h2.325l2.363-1.89a.5.5 0 0 1 .529-.06
</x:String>
<x:String x:Key="VolumeLowIcon">
M8.707 11.182A4.5 4.5 0 0 0 10.025 8a4.5 4.5 0 0 0-1.318-3.182L8 5.525A3.5 3.5 0 0 1 9.025 8 3.5 3.5 0 0 1 8 10.475z
M6.717 3.55A.5.5 0 0 1 7 4v8a.5.5 0 0 1-.812.39L3.825 10.5H1.5A.5.5 0 0 1 1 10V6a.5.5 0 0 1 .5-.5h2.325l2.363-1.89a.5.5 0 0 1 .529-.06
</x:String>
<x:String x:Key="VolumeMediumIcon">
M10.121 12.596A6.48 6.48 0 0 0 12.025 8a6.48 6.48 0 0 0-1.904-4.596l-.707.707A5.48 5.48 0 0 1 11.025 8a5.48 5.48 0 0 1-1.61 3.89z
M8.707 11.182A4.5 4.5 0 0 0 10.025 8a4.5 4.5 0 0 0-1.318-3.182L8 5.525A3.5 3.5 0 0 1 9.025 8 3.5 3.5 0 0 1 8 10.475z
M6.717 3.55A.5.5 0 0 1 7 4v8a.5.5 0 0 1-.812.39L3.825 10.5H1.5A.5.5 0 0 1 1 10V6a.5.5 0 0 1 .5-.5h2.325l2.363-1.89a.5.5 0 0 1 .529-.06
</x:String>
<x:String x:Key="VolumeHighIcon">
M11.536 14.01A8.47 8.47 0 0 0 14.026 8a8.47 8.47 0 0 0-2.49-6.01l-.708.707A7.48 7.48 0 0 1 13.025 8c0 2.071-.84 3.946-2.197 5.303z
M10.121 12.596A6.48 6.48 0 0 0 12.025 8a6.48 6.48 0 0 0-1.904-4.596l-.707.707A5.48 5.48 0 0 1 11.025 8a5.48 5.48 0 0 1-1.61 3.89z
M8.707 11.182A4.5 4.5 0 0 0 10.025 8a4.5 4.5 0 0 0-1.318-3.182L8 5.525A3.5 3.5 0 0 1 9.025 8 3.5 3.5 0 0 1 8 10.475z
M6.717 3.55A.5.5 0 0 1 7 4v8a.5.5 0 0 1-.812.39L3.825 10.5H1.5A.5.5 0 0 1 1 10V6a.5.5 0 0 1 .5-.5h2.325l2.363-1.89a.5.5 0 0 1 .529-.06
</x:String>
<x:String x:Key="ShuffleIcon">
M0 3.5A.5.5 0 0 1 .5 3H1c2.202 0 3.827 1.24 4.874 2.418.49.552.865 1.102 1.126 1.532.26-.43.636-.98 1.126-1.532C9.173 4.24 10.798 3 13 3v1c-1.798 0-3.173 1.01-4.126 2.082A9.6 9.6 0 0 0 7.556 8a9.6 9.6 0 0 0 1.317 1.918C9.828 10.99 11.204 12 13 12v1c-2.202 0-3.827-1.24-4.874-2.418A10.6 10.6 0 0 1 7 9.05c-.26.43-.636.98-1.126 1.532C4.827 11.76 3.202 13 1 13H.5a.5.5 0 0 1 0-1H1c1.798 0 3.173-1.01 4.126-2.082A9.6 9.6 0 0 0 6.444 8a9.6 9.6 0 0 0-1.317-1.918C4.172 5.01 2.796 4 1 4H.5a.5.5 0 0 1-.5-.5
M13 5.466V1.534a.25.25 0 0 1 .41-.192l2.36 1.966c.12.1.12.284 0 .384l-2.36 1.966a.25.25 0 0 1-.41-.192
M13 14.466v-3.932a.25.25 0 0 1 .41-.192l2.36 1.966c.12.1.12.284 0 .384l-2.36 1.966a.25.25 0 0 1-.41-.192
</x:String>
<x:String x:Key="RepeatIcon">
M11 5.466V4H5a4 4 0 0 0-3.584 5.777.5.5 0 1 1-.896.446A5 5 0 0 1 5 3h6V1.534a.25.25 0 0 1 .41-.192l2.36 1.966c.12.1.12.284 0 .384l-2.36 1.966a.25.25 0 0 1-.41-.192m3.81.086a.5.5 0 0 1 .67.225A5 5 0 0 1 11 13H5v1.466a.25.25 0 0 1-.41.192l-2.36-1.966a.25.25 0 0 1 0-.384l2.36-1.966a.25.25 0 0 1 .41.192V12h6a4 4 0 0 0 3.585-5.777.5.5 0 0 1 .225-.67Z
</x:String>
<x:String x:Key="RepeatOneIcon">
M11 4v1.466a.25.25 0 0 0 .41.192l2.36-1.966a.25.25 0 0 0 0-.384l-2.36-1.966a.25.25 0 0 0-.41.192V3H5a5 5 0 0 0-4.48 7.223.5.5 0 0 0 .896-.446A4 4 0 0 1 5 4zm4.48 1.777a.5.5 0 0 0-.896.446A4 4 0 0 1 11 12H5.001v-1.466a.25.25 0 0 0-.41-.192l-2.36 1.966a.25.25 0 0 0 0 .384l2.36 1.966a.25.25 0 0 0 .41-.192V13h6a5 5 0 0 0 4.48-7.223Z
M9 5.5a.5.5 0 0 0-.854-.354l-1.75 1.75a.5.5 0 1 0 .708.708L8 6.707V10.5a.5.5 0 0 0 1 0z
</x:String>
<x:String x:Key="DeleteIcon">
M5.5 5.5A.5.5 0 0 1 6 6v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5m2.5 0a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5m3 .5a.5.5 0 0 0-1 0v6a.5.5 0 0 0 1 0z
M14.5 3a1 1 0 0 1-1 1H13v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V4h-.5a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1H6a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1h3.5a1 1 0 0 1 1 1zM4.118 4 4 4.059V13a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V4.059L11.882 4zM2.5 3h11V2h-11z
</x:String>
<x:String x:Key="CutIcon">
M3.5 3.5c-.614-.884-.074-1.962.858-2.5L8 7.226 11.642 1c.932.538 1.472 1.616.858 2.5L8.81 8.61l1.556 2.661a2.5 2.5 0 1 1-.794.637L8 9.73l-1.572 2.177a2.5 2.5 0 1 1-.794-.637L7.19 8.61zm2.5 10a1.5 1.5 0 1 0-3 0 1.5 1.5 0 0 0 3 0m7 0a1.5 1.5 0 1 0-3 0 1.5 1.5 0 0 0 3 0
</x:String>
<x:String x:Key="CopyIcon">
M4 2a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2zm2-1a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1zM2 5a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1v-1h1v1a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h1v1z
</x:String>
<x:String x:Key="PasteIcon">
M4 1.5H3a2 2 0 0 0-2 2V14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3.5a2 2 0 0 0-2-2h-1v1h1a1 1 0 0 1 1 1V14a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V3.5a1 1 0 0 1 1-1h1z
M9.5 1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-1a.5.5 0 0 1 .5-.5zm-3-1A1.5 1.5 0 0 0 5 1.5v1A1.5 1.5 0 0 0 6.5 4h3A1.5 1.5 0 0 0 11 2.5v-1A1.5 1.5 0 0 0 9.5 0z
</x:String>
<x:String x:Key="RefreshIcon">
M8 3a5 5 0 1 0 4.546 2.914.5.5 0 0 1 .908-.417A6 6 0 1 1 8 2z
M8 4.466V.534a.25.25 0 0 1 .41-.192l2.36 1.966c.12.1.12.284 0 .384L8.41 4.658A.25.25 0 0 1 8 4.466
</x:String>
<x:String x:Key="SettingsIcon">
M8 4.754a3.246 3.246 0 1 0 0 6.492 3.246 3.246 0 0 0 0-6.492M5.754 8a2.246 2.246 0 1 1 4.492 0 2.246 2.246 0 0 1-4.492 0
M9.796 1.343c-.527-1.79-3.065-1.79-3.592 0l-.094.319a.873.873 0 0 1-1.255.52l-.292-.16c-1.64-.892-3.433.902-2.54 2.541l.159.292a.873.873 0 0 1-.52 1.255l-.319.094c-1.79.527-1.79 3.065 0 3.592l.319.094a.873.873 0 0 1 .52 1.255l-.16.292c-.892 1.64.901 3.434 2.541 2.54l.292-.159a.873.873 0 0 1 1.255.52l.094.319c.527 1.79 3.065 1.79 3.592 0l.094-.319a.873.873 0 0 1 1.255-.52l.292.16c1.64.893 3.434-.902 2.54-2.541l-.159-.292a.873.873 0 0 1 .52-1.255l.319-.094c1.79-.527 1.79-3.065 0-3.592l-.319-.094a.873.873 0 0 1-.52-1.255l.16-.292c.893-1.64-.902-3.433-2.541-2.54l-.292.159a.873.873 0 0 1-1.255-.52zm-2.633.283c.246-.835 1.428-.835 1.674 0l.094.319a1.873 1.873 0 0 0 2.693 1.115l.291-.16c.764-.415 1.6.42 1.184 1.185l-.159.292a1.873 1.873 0 0 0 1.116 2.692l.318.094c.835.246.835 1.428 0 1.674l-.319.094a1.873 1.873 0 0 0-1.115 2.693l.16.291c.415.764-.42 1.6-1.185 1.184l-.291-.159a1.873 1.873 0 0 0-2.693 1.116l-.094.318c-.246.835-1.428.835-1.674 0l-.094-.319a1.873 1.873 0 0 0-2.692-1.115l-.292.16c-.764.415-1.6-.42-1.184-1.185l.159-.291A1.873 1.873 0 0 0 1.945 8.93l-.319-.094c-.835-.246-.835-1.428 0-1.674l.319-.094A1.873 1.873 0 0 0 3.06 4.377l-.16-.292c-.415-.764.42-1.6 1.185-1.184l.292.159a1.873 1.873 0 0 0 2.692-1.115z
</x:String>
<x:String x:Key="LockIcon">
M8 1a2 2 0 0 1 2 2v4H6V3a2 2 0 0 1 2-2m3 6V3a3 3 0 0 0-6 0v4a2 2 0 0 0-2 2v5a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2M5 8h6a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V9a1 1 0 0 1 1-1
</x:String>
<x:String x:Key="UnlockIcon">
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>
</ResourceDictionary>

View File

@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- Flat Button -->
<Style x:Key="FlatButton" TargetType="Button">
<Setter Property="Padding" Value="10"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderThickness" Value="0"/>
</Style>
<!-- Flat Button Path Icon -->
<Style x:Key="FlatButtonIcon" TargetType="PathIcon">
<Setter Property="Width" Value="18"/>
<Setter Property="Height" Value="18"/>
<Setter Property="Foreground" Value="White"/>
</Style>
<!-- Flat Button Path -->
<Style x:Key="FlatButtonPath" TargetType="Path">
<Setter Property="Width" Value="18"/>
<Setter Property="Height" Value="18"/>
<Setter Property="Stretch" Value="Uniform"/>
<Setter Property="Fill" Value="White"/>
</Style>
<!-- Flat Button Path Icon (Medium) -->
<Style x:Key="FlatButtonPath-Medium" TargetType="Path" BasedOn="{StaticResource FlatButtonPath}">
<Setter Property="Width" Value="24"/>
<Setter Property="Height" Value="24"/>
</Style>
<!-- Flat Button Path Icon (Large) -->
<Style x:Key="FlatButtonPath-Large" TargetType="Path" BasedOn="{StaticResource FlatButtonPath}">
<Setter Property="Width" Value="36"/>
<Setter Property="Height" Value="36"/>
</Style>
<!-- Flat Button Path Icon (Medium) -->
<Style x:Key="FlatButtonIcon-Medium" TargetType="PathIcon" BasedOn="{StaticResource FlatButtonIcon}">
<Setter Property="Width" Value="24"/>
<Setter Property="Height" Value="24"/>
</Style>
<!-- Flat Button Path Icon (Large) -->
<Style x:Key="FlatButtonIcon-Large" TargetType="PathIcon" BasedOn="{StaticResource FlatButtonIcon}">
<Setter Property="Width" Value="36"/>
<Setter Property="Height" Value="36"/>
</Style>
</ResourceDictionary>

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:Harmonia.WinUI.ViewModels">
<vm:ViewModelLocator x:Key="Locator" />
</ResourceDictionary>

View File

@@ -9,7 +9,6 @@ using Harmonia.WinUI.Storage;
using Microsoft.UI.Dispatching;
using Microsoft.UI.Xaml.Media.Imaging;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
@@ -21,7 +20,6 @@ using System.Threading.Tasks;
using System.Timers;
using System.Windows.Input;
using Windows.ApplicationModel.DataTransfer;
using Windows.Storage;
using Timer = System.Timers.Timer;
namespace Harmonia.WinUI.ViewModels;
@@ -116,6 +114,8 @@ public partial class PlaylistViewModel : ViewModelBase
public ICommand RemoveMissingSongsCommand => new RelayCommand(RemoveMissingSongs);
public ICommand RemoveDuplicateSongsCommand => new RelayCommand(RemoveDuplicateSongs);
public bool IsUserUpdating { get; set; }
public PlaylistViewModel(
IAudioPlayer audioPlayer,
IAudioBitmapImageCache audioBitmapImageCache,
@@ -155,6 +155,9 @@ public partial class PlaylistViewModel : ViewModelBase
private void OnPlaylistUpdated(object? sender, PlaylistUpdatedEventArgs e)
{
if (IsUserUpdating)
return;
switch (e.Action)
{
case PlaylistUpdateAction.Add:
@@ -191,7 +194,6 @@ public partial class PlaylistViewModel : ViewModelBase
private void OnPlayingSongChanged(object? sender, EventArgs e)
{
//OnPropertyChanged(nameof(PlayingSong));
PlayingSong = _audioPlayer.PlayingSong;
}

View File

@@ -0,0 +1,18 @@
using Microsoft.Extensions.DependencyInjection;
namespace Harmonia.WinUI.ViewModels;
public class ViewModelLocator
{
//public static MainViewModel MainViewModel
// => App.ServiceProvider.GetRequiredService<MainViewModel>();
public static PlayerViewModel PlayerViewModel
=> App.ServiceProvider.GetRequiredService<PlayerViewModel>();
//public static PlayingSongInfoViewModel PlayingSongInfoViewModel
// => App.ServiceProvider.GetRequiredService<PlayingSongInfoViewModel>();
public static PlaylistViewModel PlaylistViewModel
=> App.ServiceProvider.GetRequiredService<PlaylistViewModel>();
}

View File

@@ -0,0 +1,114 @@
<UserControl
x:Class="Harmonia.WinUI.Views.PlayerView"
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:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
DataContext="{Binding Source={StaticResource Locator}, Path=PlayerViewModel}"
d:DataContext="{d:DesignInstance Type=vm:PlayerViewModel, IsDesignTimeCreatable=True}"
mc:Ignorable="d">
<UserControl.Resources>
<Style x:Key="PlayerGrid" TargetType="Grid">
<Setter Property="Background" Value="#1a1a1a"/>
<Setter Property="Padding" Value="10"/>
</Style>
<Style x:Key="SongImage" TargetType="Image">
<Setter Property="Width" Value="80"/>
<Setter Property="Height" Value="80"/>
</Style>
</UserControl.Resources>
<Grid Style="{StaticResource PlayerGrid}">
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<!-- Position Slider -->
<Grid Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3" VerticalAlignment="Center" Margin="0 0 0 10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition Width="Auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<TextBlock
Grid.Column="0"
Foreground="#aaaaaa"
Text="{Binding Position, Converter={StaticResource SecondsToString}}"
FontSize="13"
Margin="0 0 6 0"
VerticalAlignment="Center"
LineHeight="0">
</TextBlock>
<Slider
Name="PositionSlider"
Loaded="PositionSlider_Loaded"
Grid.Column="1"
Value="{Binding CurrentPosition, Mode=TwoWay, UpdateSourceTrigger=Explicit}"
Minimum="0"
Maximum="{Binding MaxPosition, Mode=OneWay}"
ThumbToolTipValueConverter="{StaticResource SecondsToString}"
VerticalAlignment="Center"
VerticalContentAlignment="Center" />
<TextBlock
Grid.Column="2"
Foreground="#aaaaaa"
Text="{Binding MaxPosition, Converter={StaticResource SecondsToString}}"
FontSize="13"
Margin="6 0 0 0"
VerticalAlignment="Center">
</TextBlock>
</Grid>
<!-- Song Info -->
<Grid Grid.Row="1" Grid.Column="0" Name="PlayingSongGrid">
<StackPanel Orientation="Horizontal">
<Grid Margin="0 0 10 0">
<Image Source="{Binding SongImageSource, Mode=OneWay}" Style="{StaticResource SongImage}"></Image>
<Canvas Background="#19000000"></Canvas>
</Grid>
<StackPanel VerticalAlignment="Center">
<TextBlock Foreground="#dddddd" FontWeight="SemiBold" FontSize="16" LineHeight="20" Text="{Binding Song, Converter={StaticResource SongTitle}}"></TextBlock>
<TextBlock Foreground="#aaaaaa" FontSize="14" LineHeight="20" Text="{Binding Song.Artists, Converter={StaticResource ArtistsToString}}"></TextBlock>
<TextBlock Foreground="#aaaaaa" FontSize="14" LineHeight="20" Text="{Binding Song.Album}"></TextBlock>
<TextBlock Foreground="#777" FontSize="12" Visibility="{Binding Song, Converter={StaticResource NullVisibility}}" FontWeight="Normal" Opacity="1.0">
<Run Text="{Binding Song.FileType}"></Run><Run Text=" - "></Run><Run Text="{Binding Song.BitRate}"></Run><Run Text=" kbps - "></Run><Run Text="{Binding Song.SampleRate}"></Run><Run Text=" Hz"></Run>
</TextBlock>
</StackPanel>
</StackPanel>
</Grid>
<!-- Playback Actions -->
<Grid Grid.Row="1" Grid.Column="1" VerticalAlignment="Center" HorizontalAlignment="Center">
<StackPanel Orientation="Horizontal" Spacing="16">
<Button Style="{StaticResource FlatButton}" Command="{Binding PreviousSongCommand}">
<Path Style="{StaticResource FlatButtonPath}" Data="{StaticResource SkipStartFillIcon}"></Path>
</Button>
<Button Style="{StaticResource FlatButton}" Command="{Binding StopSongCommand}">
<Path Style="{StaticResource FlatButtonPath}" Data="{StaticResource StopFillIcon}"></Path>
</Button>
<Button Style="{StaticResource FlatButton}" Command="{Binding PlaySongCommand}">
<Path Style="{StaticResource FlatButtonPath-Large}" Data="{StaticResource PlayFillIcon}"></Path>
</Button>
<Button Style="{StaticResource FlatButton}" Command="{Binding PauseSongCommand}">
<Path Style="{StaticResource FlatButtonPath}" Data="{StaticResource PauseFillIcon}"></Path>
</Button>
<Button Style="{StaticResource FlatButton}" Command="{Binding NextSongCommand}">
<Path Style="{StaticResource FlatButtonPath}" Data="{StaticResource SkipEndFillIcon}"></Path>
</Button>
</StackPanel>
</Grid>
</Grid>
</UserControl>

View File

@@ -0,0 +1,68 @@
using Harmonia.WinUI.ViewModels;
using Microsoft.UI.Input;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Input;
namespace Harmonia.WinUI.Views;
public sealed partial class PlayerView : UserControl
{
private readonly PlayerViewModel _viewModel;
public PlayerView()
{
InitializeComponent();
_viewModel = (PlayerViewModel)DataContext;
}
private void PositionSlider_Loaded(object? sender, RoutedEventArgs e)
{
if (sender is not Slider slider)
return;
PointerEventHandler pointerPressedHandler = new(OnSliderPointerPressed);
slider.AddHandler(PointerPressedEvent, pointerPressedHandler, true);
PointerEventHandler pointerReleasedHandler = new(OnSliderPointerReleased);
slider.AddHandler(PointerReleasedEvent, pointerReleasedHandler, true);
}
private void OnSliderPointerPressed(object? sender, PointerRoutedEventArgs e)
{
if (sender is not Slider slider)
return;
PointerPointProperties pointerProperties = e.GetCurrentPoint(slider).Properties;
if (pointerProperties.IsLeftButtonPressed == false)
return;
_viewModel.IsPositionChangeInProgress = true;
}
private void OnSliderPointerReleased(object? sender, PointerRoutedEventArgs e)
{
if (sender is not Slider slider)
return;
_viewModel.CurrentPosition = slider.Value;
_viewModel.IsPositionChangeInProgress = false;
}
private void VolumeSlider_PointerWheelChanged(object? sender, PointerRoutedEventArgs e)
{
if (sender is not Slider slider)
return;
var pointerProperties = e.GetCurrentPoint(slider).Properties;
var mouseWheelDelta = pointerProperties.MouseWheelDelta;
if (mouseWheelDelta == 0)
return;
double delta = mouseWheelDelta > 0 ? .02 : -.02;
_viewModel.Volume += delta;
}
}