Added WinUI project.

This commit is contained in:
2025-03-22 02:40:25 -04:00
parent 9b80bf4a98
commit 107a20b713
25 changed files with 542 additions and 0 deletions

16
Harmonia.WinUI/App.xaml Normal file
View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<Application
x:Class="Harmonia.WinUI.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Harmonia.WinUI">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
<!-- Other merged dictionaries here -->
</ResourceDictionary.MergedDictionaries>
<!-- Other app resources here -->
</ResourceDictionary>
</Application.Resources>
</Application>

View File

@@ -0,0 +1,50 @@
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 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
{
/// <summary>
/// Provides application-specific behavior to supplement the default Application class.
/// </summary>
public partial class App : Application
{
/// <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();
}
/// <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();
}
private Window? m_window;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 432 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 637 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 283 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 456 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -0,0 +1,92 @@
using Harmonia.Core.Caching;
using Harmonia.Core.Imaging;
using Harmonia.Core.Models;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.UI.Xaml.Media.Imaging;
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace Harmonia.WinUI.Caching;
public class AudioBitmapImageCache(IAudioImageExtractor audioImageExtractor) : MemoryCache<Song, BitmapImage>, IAudioBitmapImageCache
{
protected virtual int MaxImageWidthOrHeight => 1000;
protected override MemoryCacheOptions Options => new()
{
SizeLimit = 40,
CompactionPercentage = 0.2,
};
protected override TimeSpan SlidingExpiration => TimeSpan.FromSeconds(600);
protected override int MaxConcurrentRequests => 8;
protected override object? GetKey(Song key)
{
if (string.IsNullOrWhiteSpace(key.ImageHash) == false)
{
return key.ImageHash;
}
else if (string.IsNullOrWhiteSpace(key.ImageName) == false)
{
return key.ImageName;
}
return null;
}
protected override async ValueTask<BitmapImage?> FetchAsync(Song key, CancellationToken cancellationToken)
{
SongPictureInfo? songPictureInfo = await audioImageExtractor.ExtractImageAsync(key.FileName, cancellationToken);
if (songPictureInfo == null)
return null;
using MemoryStream stream = new(songPictureInfo.Data);
BitmapImage bitmapImage = new();
await bitmapImage.SetSourceAsync(stream.AsRandomAccessStream());
bitmapImage.DecodePixelWidth = GetDecodePixelWidth(bitmapImage);
bitmapImage.DecodePixelHeight = GetDecodePixelHeight(bitmapImage);
return bitmapImage;
}
private int GetDecodePixelWidth(BitmapImage bitmapImage)
{
int originalImageWidth = bitmapImage.PixelWidth;
int orignalImageHeight = bitmapImage.PixelHeight;
if (originalImageWidth <= MaxImageWidthOrHeight && orignalImageHeight <= MaxImageWidthOrHeight)
return 0;
if (orignalImageHeight > originalImageWidth)
return 0;
return MaxImageWidthOrHeight;
}
private int GetDecodePixelHeight(BitmapImage bitmapImage)
{
int originalImageWidth = bitmapImage.PixelWidth;
int orignalImageHeight = bitmapImage.PixelHeight;
if (originalImageWidth <= MaxImageWidthOrHeight && orignalImageHeight <= MaxImageWidthOrHeight)
return 0;
if (originalImageWidth > orignalImageHeight)
return 0;
return MaxImageWidthOrHeight;
}
protected override long GetEntrySize(BitmapImage entry)
{
return entry.PixelWidth * entry.PixelHeight;
}
}

View File

@@ -0,0 +1,10 @@
using Harmonia.Core.Caching;
using Harmonia.Core.Models;
using Microsoft.UI.Xaml.Media.Imaging;
namespace Harmonia.WinUI.Caching;
public interface IAudioBitmapImageCache : ICache<Song, BitmapImage>
{
}

View File

@@ -0,0 +1,26 @@
using Microsoft.UI.Xaml.Data;
using System;
using System.Collections.Generic;
namespace Harmonia.WinUI.Converters;
public partial class ArtistsToStringConverter : IValueConverter
{
public ArtistsToStringConverter()
{
}
public object Convert(object value, Type targetType, object parameter, string language)
{
if (value is not string[] artists)
return string.Empty;
return string.Join(" / ", artists);
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}

View File

@@ -0,0 +1,27 @@
using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml;
using System;
using System.Collections;
namespace Harmonia.WinUI.Converters;
public sealed partial class NullVisibilityConverter : IValueConverter
{
public NullVisibilityConverter()
{
}
public object Convert(object value, Type targetType, object parameter, string language)
{
if (value is not IList list)
return Visibility.Collapsed;
return list.Count == 0 ? Visibility.Collapsed : Visibility.Visible;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}

View File

@@ -0,0 +1,26 @@
using Harmonia.Core.Player;
using Microsoft.UI.Xaml.Data;
using System;
namespace Harmonia.WinUI.Converters;
public sealed partial class RepeatStateConverter : IValueConverter
{
public RepeatStateConverter()
{
}
public object? Convert(object value, Type targetType, object parameter, string language)
{
if (value is not RepeatState repeatState)
return null;
return repeatState.ToString();
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}

View File

@@ -0,0 +1,30 @@
using Microsoft.UI.Xaml.Data;
using System;
namespace Harmonia.WinUI.Converters;
public sealed partial class SecondsToStringConverter : IValueConverter
{
public SecondsToStringConverter()
{
}
public object? Convert(object value, Type targetType, object parameter, string language)
{
if (value is not double doubleValue)
return null;
TimeSpan timeSpan = TimeSpan.FromSeconds(doubleValue);
if (timeSpan.Hours >= 1)
return timeSpan.ToString(@"%h\:mm\:ss");
return timeSpan.ToString(@"%m\:ss");
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
return TimeSpan.Parse((string)value);
}
}

View File

@@ -0,0 +1,26 @@
using Harmonia.Core.Models;
using Microsoft.UI.Xaml.Data;
using System;
namespace Harmonia.WinUI.Converters;
public sealed partial class SongTitleConverter : IValueConverter
{
public SongTitleConverter()
{
}
public object? Convert(object value, Type targetType, object parameter, string language)
{
if (value is not Song song)
return null;
return string.IsNullOrWhiteSpace(song.Title) ? song.ShortFileName : song.Title;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}

View File

@@ -0,0 +1,26 @@
using System;
using Microsoft.UI.Xaml.Data;
using Harmonia.WinUI.Models;
namespace Harmonia.WinUI.Converters;
public sealed partial class VolumeStateConverter : IValueConverter
{
public VolumeStateConverter()
{
}
public object? Convert(object value, Type targetType, object parameter, string language)
{
if (value is not VolumeState volumeState)
return null;
return volumeState.ToString();
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}

View File

@@ -0,0 +1,64 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net9.0-windows10.0.19041.0</TargetFramework>
<TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion>
<RootNamespace>Harmonia.WinUI</RootNamespace>
<ApplicationManifest>app.manifest</ApplicationManifest>
<Platforms>x86;x64;ARM64</Platforms>
<RuntimeIdentifiers>win-x86;win-x64;win-arm64</RuntimeIdentifiers>
<PublishProfile>win-$(Platform).pubxml</PublishProfile>
<UseWinUI>true</UseWinUI>
<EnableMsixTooling>true</EnableMsixTooling>
<WindowsPackageType>None</WindowsPackageType>
<WindowsAppSDKSelfContained>true</WindowsAppSDKSelfContained>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<Content Include="Assets\SplashScreen.scale-200.png" />
<Content Include="Assets\LockScreenLogo.scale-200.png" />
<Content Include="Assets\Square150x150Logo.scale-200.png" />
<Content Include="Assets\Square44x44Logo.scale-200.png" />
<Content Include="Assets\Square44x44Logo.targetsize-24_altform-unplated.png" />
<Content Include="Assets\StoreLogo.png" />
<Content Include="Assets\Wide310x150Logo.scale-200.png" />
</ItemGroup>
<ItemGroup>
<Manifest Include="$(ApplicationManifest)" />
</ItemGroup>
<!--
Defining the "Msix" ProjectCapability here allows the Single-project MSIX Packaging
Tools extension to be activated for this project even if the Windows App SDK Nuget
package has not yet been restored.
-->
<ItemGroup Condition="'$(DisableMsixProjectCapabilityAddedByProject)'!='true' and '$(EnableMsixTooling)'=='true'">
<ProjectCapability Include="Msix" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.1742" />
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.7.250310001" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Harmonia.Core\Harmonia.Core.csproj" />
</ItemGroup>
<!--
Defining the "HasPackageAndPublishMenuAddedByProject" property here allows the Solution
Explorer "Package and Publish" context menu entry to be enabled for this project even if
the Windows App SDK Nuget package has not yet been restored.
-->
<PropertyGroup Condition="'$(DisableHasPackageAndPublishMenuAddedByProject)'!='true' and '$(EnableMsixTooling)'=='true'">
<HasPackageAndPublishMenu>true</HasPackageAndPublishMenu>
</PropertyGroup>
<!-- Publish Properties -->
<PropertyGroup>
<PublishReadyToRun Condition="'$(Configuration)' == 'Debug'">False</PublishReadyToRun>
<PublishReadyToRun Condition="'$(Configuration)' != 'Debug'">True</PublishReadyToRun>
<PublishTrimmed Condition="'$(Configuration)' == 'Debug'">False</PublishTrimmed>
<PublishTrimmed Condition="'$(Configuration)' != 'Debug'">True</PublishTrimmed>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<Window
x:Class="Harmonia.WinUI.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Harmonia.WinUI"
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">
<Button x:Name="myButton" Click="myButton_Click">Click Me</Button>
</StackPanel>
</Window>

View File

@@ -0,0 +1,36 @@
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
{
/// <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";
}
}
}

View File

@@ -0,0 +1,10 @@
namespace Harmonia.WinUI.Models;
public enum VolumeState
{
Muted,
Off,
Low,
Medium,
High
}

View File

@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<Package
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
IgnorableNamespaces="uap rescap">
<Identity
Name="52b8577e-aca4-4ab5-b180-69e74b1b5b49"
Publisher="CN=Brian"
Version="1.0.0.0" />
<mp:PhoneIdentity PhoneProductId="52b8577e-aca4-4ab5-b180-69e74b1b5b49" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
<Properties>
<DisplayName>Harmonia.WinUI</DisplayName>
<PublisherDisplayName>Brian</PublisherDisplayName>
<Logo>Assets\StoreLogo.png</Logo>
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" />
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" />
</Dependencies>
<Resources>
<Resource Language="x-generate"/>
</Resources>
<Applications>
<Application Id="App"
Executable="$targetnametoken$.exe"
EntryPoint="$targetentrypoint$">
<uap:VisualElements
DisplayName="Harmonia.WinUI"
Description="Harmonia.WinUI"
BackgroundColor="transparent"
Square150x150Logo="Assets\Square150x150Logo.png"
Square44x44Logo="Assets\Square44x44Logo.png">
<uap:DefaultTile Wide310x150Logo="Assets\Wide310x150Logo.png" />
<uap:SplashScreen Image="Assets\SplashScreen.png" />
</uap:VisualElements>
</Application>
</Applications>
<Capabilities>
<rescap:Capability Name="runFullTrust" />
</Capabilities>
</Package>

View File

@@ -0,0 +1,10 @@
{
"profiles": {
"Harmonia.WinUI (Package)": {
"commandName": "MsixPackage"
},
"Harmonia.WinUI (Unpackaged)": {
"commandName": "Project"
}
}
}

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="Harmonia.WinUI.app"/>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- The ID below informs the system that this application is compatible with OS features first introduced in Windows 10.
It is necessary to support features in unpackaged applications, for example the custom titlebar implementation.
For more info see https://docs.microsoft.com/windows/apps/windows-app-sdk/use-windows-app-sdk-run-time#declare-os-compatibility-in-your-application-manifest -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
</windowsSettings>
</application>
</assembly>