Various updates.
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
using Microsoft.Extensions.Caching.Memory;
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
namespace Harmonia.Core.Caching;
|
namespace Harmonia.Core.Caching;
|
||||||
|
|
||||||
@@ -27,10 +28,16 @@ public abstract class MemoryCache<TKey, TValue> : Cache<TKey, TValue> where TKey
|
|||||||
|
|
||||||
var cacheEntryOptions = new MemoryCacheEntryOptions()
|
var cacheEntryOptions = new MemoryCacheEntryOptions()
|
||||||
.SetSize(entrySize)
|
.SetSize(entrySize)
|
||||||
.SetSlidingExpiration(SlidingExpiration);
|
.SetSlidingExpiration(SlidingExpiration)
|
||||||
|
.RegisterPostEvictionCallback(PostEvictionCallback);
|
||||||
|
|
||||||
_memoryCache.Set(key, entry, cacheEntryOptions);
|
_memoryCache.Set(key, entry, cacheEntryOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected virtual void PostEvictionCallback(object? cacheKey, object? cacheValue, EvictionReason evictionReason, object? state)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract long GetEntrySize(TValue entry);
|
protected abstract long GetEntrySize(TValue entry);
|
||||||
}
|
}
|
||||||
@@ -7,12 +7,12 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ManagedBass" Version="3.1.1" />
|
<PackageReference Include="ManagedBass" Version="4.0.2" />
|
||||||
<PackageReference Include="ManagedBass.Flac" Version="3.1.1" />
|
<PackageReference Include="ManagedBass.Flac" Version="4.0.2" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.3" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.9" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="9.0.3" />
|
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="9.0.9" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="9.0.3" />
|
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="9.0.9" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.3" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.9" />
|
||||||
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" />
|
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" />
|
||||||
<PackageReference Include="TagLibSharp" Version="2.3.0" />
|
<PackageReference Include="TagLibSharp" Version="2.3.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -23,4 +23,26 @@ public class Song
|
|||||||
public string? FileDirectory => Directory.GetParent(FileName)?.Name;
|
public string? FileDirectory => Directory.GetParent(FileName)?.Name;
|
||||||
public string? FileType => Path.GetExtension(FileName)?.Replace(".", "").ToUpper();
|
public string? FileType => Path.GetExtension(FileName)?.Replace(".", "").ToUpper();
|
||||||
public string ShortFileName => Path.GetFileNameWithoutExtension(FileName);
|
public string ShortFileName => Path.GetFileNameWithoutExtension(FileName);
|
||||||
|
|
||||||
|
public void Update(Song song)
|
||||||
|
{
|
||||||
|
if (string.Equals(song.FileName, FileName, StringComparison.OrdinalIgnoreCase) == false)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Size = song.Size;
|
||||||
|
LastModified = song.LastModified;
|
||||||
|
Title = song.Title;
|
||||||
|
Album = song.Album;
|
||||||
|
Artists = song.Artists;
|
||||||
|
AlbumArtists = song.AlbumArtists;
|
||||||
|
DiscNumber = song.DiscNumber;
|
||||||
|
TrackNumber = song.TrackNumber;
|
||||||
|
Length = song.Length;
|
||||||
|
Year = song.Year;
|
||||||
|
Genre = song.Genre;
|
||||||
|
BitRate = song.BitRate;
|
||||||
|
SampleRate = song.SampleRate;
|
||||||
|
ImageName = song?.ImageName;
|
||||||
|
ImageHash = song?.ImageHash;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -172,6 +172,7 @@ public class Playlist
|
|||||||
foreach (PlaylistSong playlistSong in playlistSongs)
|
foreach (PlaylistSong playlistSong in playlistSongs)
|
||||||
{
|
{
|
||||||
//playlistSong.Song = song;
|
//playlistSong.Song = song;
|
||||||
|
//playlistSong.Song.Update(song);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,14 +16,14 @@
|
|||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.13.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.0" />
|
||||||
<PackageReference Include="NSubstitute" Version="5.3.0" />
|
<PackageReference Include="NSubstitute" Version="5.3.0" />
|
||||||
<PackageReference Include="Shouldly" Version="4.3.0" />
|
<PackageReference Include="Shouldly" Version="4.3.0" />
|
||||||
<PackageReference Include="xunit.runner.visualstudio" Version="3.0.2">
|
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="xunit.v3" Version="2.0.0" />
|
<PackageReference Include="xunit.v3" Version="3.1.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Avalonia.Desktop" Version="11.2.6" />
|
<PackageReference Include="Avalonia.Desktop" Version="11.3.7" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -11,15 +11,15 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Avalonia" Version="11.2.6" />
|
<PackageReference Include="Avalonia" Version="11.3.7" />
|
||||||
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.2.6" />
|
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.3.7" />
|
||||||
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.2.6" />
|
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.3.7" />
|
||||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
|
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
|
||||||
|
|
||||||
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
|
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
|
||||||
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.2.6" />
|
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.3.7" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.3" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.9" />
|
||||||
<PackageReference Include="Semi.Avalonia" Version="11.2.1.6" />
|
<PackageReference Include="Semi.Avalonia" Version="11.3.7" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -2,8 +2,10 @@
|
|||||||
using Harmonia.Core.Imaging;
|
using Harmonia.Core.Imaging;
|
||||||
using Harmonia.Core.Models;
|
using Harmonia.Core.Models;
|
||||||
using Microsoft.Extensions.Caching.Memory;
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
|
using Microsoft.UI.Dispatching;
|
||||||
using Microsoft.UI.Xaml.Media.Imaging;
|
using Microsoft.UI.Xaml.Media.Imaging;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@@ -99,4 +101,128 @@ public class AudioBitmapImageCache(IAudioImageExtractor audioImageExtractor) : M
|
|||||||
{
|
{
|
||||||
return entry.DecodePixelWidth * entry.DecodePixelHeight;
|
return entry.DecodePixelWidth * entry.DecodePixelHeight;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public class AudioBitmapImageCache2 : MemoryCache<Song, BitmapImage>, IAudioBitmapImageCache
|
||||||
|
{
|
||||||
|
private readonly IAudioImageExtractor _audioImageExtractor;
|
||||||
|
private readonly BitmapImage[] _bitmapPool;
|
||||||
|
private int _nextIndex = 0;
|
||||||
|
private ConcurrentDictionary<object, BitmapImage> _test = [];
|
||||||
|
|
||||||
|
protected override MemoryCacheOptions Options => new()
|
||||||
|
{
|
||||||
|
SizeLimit = 200_000_000,
|
||||||
|
CompactionPercentage = 0.2,
|
||||||
|
};
|
||||||
|
|
||||||
|
protected override TimeSpan SlidingExpiration => TimeSpan.FromSeconds(600);
|
||||||
|
protected override int MaxConcurrentRequests => 8;
|
||||||
|
protected virtual int MaxImageWidthOrHeight => 1000;
|
||||||
|
protected virtual int BitmapPoolSize => 64;
|
||||||
|
|
||||||
|
public AudioBitmapImageCache2(IAudioImageExtractor audioImageExtractor)
|
||||||
|
{
|
||||||
|
_audioImageExtractor = audioImageExtractor;
|
||||||
|
_bitmapPool = new BitmapImage[BitmapPoolSize];
|
||||||
|
|
||||||
|
InitializeBitmapPool();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeBitmapPool()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < _bitmapPool.Length; i++)
|
||||||
|
_bitmapPool[i] = new BitmapImage();
|
||||||
|
|
||||||
|
//DispatcherQueue dispatcherQueue = DispatcherQueue.GetForCurrentThread();
|
||||||
|
|
||||||
|
//TaskCompletionSource taskCompletionSource = new();
|
||||||
|
|
||||||
|
//dispatcherQueue.TryEnqueue(() =>
|
||||||
|
//{
|
||||||
|
// for (int i = 0; i < _bitmapPool.Length; i++)
|
||||||
|
// _bitmapPool[i] = new BitmapImage();
|
||||||
|
|
||||||
|
// taskCompletionSource.SetResult();
|
||||||
|
//});
|
||||||
|
|
||||||
|
//taskCompletionSource.Task.GetAwaiter().GetResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
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 "Default";
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async ValueTask<BitmapImage?> FetchAsync(Song key, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
int index = Interlocked.Increment(ref _nextIndex);
|
||||||
|
BitmapImage bitmapImage = _bitmapPool[index % _bitmapPool.Length];
|
||||||
|
//_test.AddOrUpdate(index, bitmapImage);
|
||||||
|
|
||||||
|
SongPictureInfo? songPictureInfo = await _audioImageExtractor.ExtractImageAsync(key.FileName, cancellationToken);
|
||||||
|
|
||||||
|
if (songPictureInfo == null)
|
||||||
|
{
|
||||||
|
bitmapImage.UriSource = new("ms-appx:///Assets/Default.png", UriKind.Absolute);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
using MemoryStream stream = new(songPictureInfo.Data);
|
||||||
|
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.DecodePixelWidth * entry.DecodePixelHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void PostEvictionCallback(object? cacheKey, object? cacheValue, EvictionReason evictionReason, object? state)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
76
Harmonia.WinUI/Flex/IFlexView.cs
Normal file
76
Harmonia.WinUI/Flex/IFlexView.cs
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Harmonia.WinUI.Flex;
|
||||||
|
|
||||||
|
public interface IFlexView
|
||||||
|
{
|
||||||
|
FlexLayout Layout { get; }
|
||||||
|
int ImageWidth { get; }
|
||||||
|
FlexOrientation ListOrientation { get; }
|
||||||
|
int RowSpacing { get; }
|
||||||
|
int ColumnSpacing { get; }
|
||||||
|
int TextLineHeight { get; }
|
||||||
|
FlexOrientation SubtitleFooterOrientation { get; }
|
||||||
|
int SubtitleFooterMargin { get; }
|
||||||
|
FlexOrientation ImageToTextOrientation { get; }
|
||||||
|
int TitleFontSize { get; }
|
||||||
|
int SubtitleFontSize { get; }
|
||||||
|
int FooterFontSize { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class GridFlexViewBase : IFlexView
|
||||||
|
{
|
||||||
|
public FlexLayout Layout => FlexLayout.Grid;
|
||||||
|
public FlexOrientation ListOrientation => FlexOrientation.Horizontal;
|
||||||
|
public FlexOrientation SubtitleFooterOrientation => FlexOrientation.Vertical;
|
||||||
|
public FlexOrientation ImageToTextOrientation => FlexOrientation.Vertical;
|
||||||
|
|
||||||
|
public abstract int ImageWidth { get; }
|
||||||
|
public abstract int RowSpacing { get; }
|
||||||
|
public abstract int ColumnSpacing { get; }
|
||||||
|
public abstract int TextLineHeight { get; }
|
||||||
|
public abstract int SubtitleFooterMargin { get; }
|
||||||
|
public abstract int TitleFontSize { get; }
|
||||||
|
public abstract int SubtitleFontSize { get; }
|
||||||
|
public abstract int FooterFontSize { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class ListFlexViewBase : IFlexView
|
||||||
|
{
|
||||||
|
public FlexLayout Layout => FlexLayout.List;
|
||||||
|
public FlexOrientation ListOrientation => FlexOrientation.Vertical;
|
||||||
|
public FlexOrientation SubtitleFooterOrientation => FlexOrientation.Vertical;
|
||||||
|
public FlexOrientation ImageToTextOrientation => FlexOrientation.Vertical;
|
||||||
|
|
||||||
|
public abstract int ImageWidth { get; }
|
||||||
|
|
||||||
|
public abstract int RowSpacing { get; }
|
||||||
|
|
||||||
|
public abstract int ColumnSpacing { get; }
|
||||||
|
|
||||||
|
public abstract int TextLineHeight { get; }
|
||||||
|
|
||||||
|
public abstract int SubtitleFooterMargin { get; }
|
||||||
|
|
||||||
|
public abstract int TitleFontSize { get; }
|
||||||
|
|
||||||
|
public abstract int SubtitleFontSize { get; }
|
||||||
|
|
||||||
|
public abstract int FooterFontSize { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum FlexLayout
|
||||||
|
{
|
||||||
|
List,
|
||||||
|
Grid
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum FlexOrientation
|
||||||
|
{
|
||||||
|
Horizontal,
|
||||||
|
Vertical
|
||||||
|
}
|
||||||
@@ -43,9 +43,9 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
|
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
|
||||||
<PackageReference Include="CommunityToolkit.WinUI.Media" Version="8.1.240916" />
|
<PackageReference Include="CommunityToolkit.WinUI.Media" Version="8.2.250402" />
|
||||||
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.1742" />
|
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.6584" />
|
||||||
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.7.250310001" />
|
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.8.250916003" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Harmonia.Core\Harmonia.Core.csproj" />
|
<ProjectReference Include="..\Harmonia.Core\Harmonia.Core.csproj" />
|
||||||
|
|||||||
@@ -5,19 +5,19 @@
|
|||||||
|
|
||||||
<!-- Global Font -->
|
<!-- Global Font -->
|
||||||
<Style TargetType="TextBlock">
|
<Style TargetType="TextBlock">
|
||||||
<Setter Property="FontFamily" Value="Lexend" />
|
<Setter Property="FontFamily" Value="Lexend,Noto Sans JP" />
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
<Style TargetType="TextBox" BasedOn="{StaticResource DefaultTextBoxStyle}">
|
<Style TargetType="TextBox" BasedOn="{StaticResource DefaultTextBoxStyle}">
|
||||||
<Setter Property="FontFamily" Value="Lexend" />
|
<Setter Property="FontFamily" Value="Lexend,Noto Sans JP" />
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
<Style TargetType="MenuFlyoutItem" BasedOn="{StaticResource DefaultMenuFlyoutItemStyle}">
|
<Style TargetType="MenuFlyoutItem" BasedOn="{StaticResource DefaultMenuFlyoutItemStyle}">
|
||||||
<Setter Property="FontFamily" Value="Lexend" />
|
<Setter Property="FontFamily" Value="Lexend,Noto Sans JP" />
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
<Style TargetType="ListViewItem" BasedOn="{StaticResource DefaultListViewItemStyle}">
|
<Style TargetType="ListViewItem" BasedOn="{StaticResource DefaultListViewItemStyle}">
|
||||||
<Setter Property="FontFamily" Value="Lexend" />
|
<Setter Property="FontFamily" Value="Lexend,Noto Sans JP" />
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
<!-- Flat Button -->
|
<!-- Flat Button -->
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace Harmonia.WinUI.ViewModels;
|
namespace Harmonia.WinUI.ViewModels;
|
||||||
|
|
||||||
public class PlayingSongViewModel : ViewModelBase
|
public partial class PlayingSongViewModel : ViewModelBase
|
||||||
{
|
{
|
||||||
private readonly IAudioPlayer _audioPlayer;
|
private readonly IAudioPlayer _audioPlayer;
|
||||||
private readonly IAudioBitmapImageCache _audioBitmapImageCache;
|
private readonly IAudioBitmapImageCache _audioBitmapImageCache;
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
using CommunityToolkit.Mvvm.Input;
|
using CommunityToolkit.Mvvm.Input;
|
||||||
|
using Harmonia.Core.Caching;
|
||||||
using Harmonia.Core.Engine;
|
using Harmonia.Core.Engine;
|
||||||
|
using Harmonia.Core.Imaging;
|
||||||
using Harmonia.Core.Models;
|
using Harmonia.Core.Models;
|
||||||
using Harmonia.Core.Player;
|
using Harmonia.Core.Player;
|
||||||
using Harmonia.Core.Playlists;
|
using Harmonia.Core.Playlists;
|
||||||
@@ -8,10 +10,10 @@ using Harmonia.WinUI.Caching;
|
|||||||
using Harmonia.WinUI.Storage;
|
using Harmonia.WinUI.Storage;
|
||||||
using Microsoft.UI.Xaml.Media.Imaging;
|
using Microsoft.UI.Xaml.Media.Imaging;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Collections.Specialized;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -20,7 +22,6 @@ using System.Threading;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Timers;
|
using System.Timers;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using Windows.ApplicationModel.Contacts;
|
|
||||||
using Windows.ApplicationModel.DataTransfer;
|
using Windows.ApplicationModel.DataTransfer;
|
||||||
using DispatcherQueue = Microsoft.UI.Dispatching.DispatcherQueue;
|
using DispatcherQueue = Microsoft.UI.Dispatching.DispatcherQueue;
|
||||||
using Timer = System.Timers.Timer;
|
using Timer = System.Timers.Timer;
|
||||||
@@ -30,6 +31,7 @@ namespace Harmonia.WinUI.ViewModels;
|
|||||||
public partial class PlaylistViewModel : ViewModelBase
|
public partial class PlaylistViewModel : ViewModelBase
|
||||||
{
|
{
|
||||||
private readonly IAudioPlayer _audioPlayer;
|
private readonly IAudioPlayer _audioPlayer;
|
||||||
|
private readonly IAudioImageCache _audioImageCache;
|
||||||
private readonly IAudioBitmapImageCache _audioBitmapImageCache;
|
private readonly IAudioBitmapImageCache _audioBitmapImageCache;
|
||||||
private readonly IAudioFileScanner _audioFileScanner;
|
private readonly IAudioFileScanner _audioFileScanner;
|
||||||
private readonly IAudioEngine _audioEngine;
|
private readonly IAudioEngine _audioEngine;
|
||||||
@@ -126,6 +128,7 @@ public partial class PlaylistViewModel : ViewModelBase
|
|||||||
|
|
||||||
public PlaylistViewModel(
|
public PlaylistViewModel(
|
||||||
IAudioPlayer audioPlayer,
|
IAudioPlayer audioPlayer,
|
||||||
|
IAudioImageCache audioImageCache,
|
||||||
IAudioBitmapImageCache audioBitmapImageCache,
|
IAudioBitmapImageCache audioBitmapImageCache,
|
||||||
IAudioFileScanner audioFileScanner,
|
IAudioFileScanner audioFileScanner,
|
||||||
IAudioEngine audioEngine,
|
IAudioEngine audioEngine,
|
||||||
@@ -136,16 +139,27 @@ public partial class PlaylistViewModel : ViewModelBase
|
|||||||
_audioPlayer.PlaylistChanged += OnPlaylistChanged;
|
_audioPlayer.PlaylistChanged += OnPlaylistChanged;
|
||||||
_audioPlayer.PlayingSongChanged += OnPlayingSongChanged;
|
_audioPlayer.PlayingSongChanged += OnPlayingSongChanged;
|
||||||
|
|
||||||
|
_audioImageCache = audioImageCache;
|
||||||
_audioBitmapImageCache = audioBitmapImageCache;
|
_audioBitmapImageCache = audioBitmapImageCache;
|
||||||
_audioFileScanner = audioFileScanner;
|
_audioFileScanner = audioFileScanner;
|
||||||
_audioEngine = audioEngine;
|
_audioEngine = audioEngine;
|
||||||
_storageProvider = storageProvider;
|
_storageProvider = storageProvider;
|
||||||
_dispatcherQueue = DispatcherQueue.GetForCurrentThread();
|
_dispatcherQueue = DispatcherQueue.GetForCurrentThread();
|
||||||
|
|
||||||
|
FilteredPlaylistSongs.CollectionChanged += OnFilteredPlaylistSongsCollectionChanged;
|
||||||
|
|
||||||
// Testing
|
// Testing
|
||||||
Task.Run(() => PlayDemoSong(playlistRepository));
|
Task.Run(() => PlayDemoSong(playlistRepository));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnFilteredPlaylistSongsCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (IsUserUpdating == false)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int x = 1;
|
||||||
|
}
|
||||||
|
|
||||||
private async Task PlayDemoSong(IPlaylistRepository playlistRepository)
|
private async Task PlayDemoSong(IPlaylistRepository playlistRepository)
|
||||||
{
|
{
|
||||||
if (playlistRepository.Get().Count == 0)
|
if (playlistRepository.Get().Count == 0)
|
||||||
@@ -238,13 +252,24 @@ public partial class PlaylistViewModel : ViewModelBase
|
|||||||
await _audioPlayer.LoadAsync(playlistSong, PlaybackMode.LoadAndPlay);
|
await _audioPlayer.LoadAsync(playlistSong, PlaybackMode.LoadAndPlay);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<SongPictureInfo?> GetSongPictureInfoAsync(int hashCode, PlaylistSong playlistSong)
|
||||||
|
{
|
||||||
|
_imageCancellationTokens.TryGetValue(hashCode, out CancellationTokenSource? cancellationTokenSource);
|
||||||
|
cancellationTokenSource?.Cancel();
|
||||||
|
|
||||||
|
cancellationTokenSource = new();
|
||||||
|
_imageCancellationTokens.AddOrUpdate(hashCode, cancellationTokenSource, (_, _) => cancellationTokenSource);
|
||||||
|
|
||||||
|
return await _audioImageCache.GetAsync(playlistSong.Song, cancellationTokenSource.Token);
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<BitmapImage?> GetBitmapImageAsync(int hashCode, PlaylistSong playlistSong)
|
public async Task<BitmapImage?> GetBitmapImageAsync(int hashCode, PlaylistSong playlistSong)
|
||||||
{
|
{
|
||||||
_imageCancellationTokens.TryGetValue(hashCode, out CancellationTokenSource? cancellationTokenSource);
|
_imageCancellationTokens.TryGetValue(hashCode, out CancellationTokenSource? cancellationTokenSource);
|
||||||
cancellationTokenSource?.Cancel();
|
cancellationTokenSource?.Cancel();
|
||||||
|
|
||||||
cancellationTokenSource = new();
|
cancellationTokenSource = new();
|
||||||
_imageCancellationTokens.AddOrUpdate(hashCode, cancellationTokenSource, (_,_) => cancellationTokenSource);
|
_imageCancellationTokens.AddOrUpdate(hashCode, cancellationTokenSource, (_, _) => cancellationTokenSource);
|
||||||
|
|
||||||
return await _audioBitmapImageCache.GetAsync(playlistSong.Song, cancellationTokenSource.Token);
|
return await _audioBitmapImageCache.GetAsync(playlistSong.Song, cancellationTokenSource.Token);
|
||||||
}
|
}
|
||||||
@@ -290,7 +315,7 @@ public partial class PlaylistViewModel : ViewModelBase
|
|||||||
List<PlaylistSong> filteredPlaylistSongs = [.. Playlist.Songs.Where(playlistSong => IsFiltered(playlistSong.Song))];
|
List<PlaylistSong> filteredPlaylistSongs = [.. Playlist.Songs.Where(playlistSong => IsFiltered(playlistSong.Song))];
|
||||||
//FilteredPlaylistSongs = [.. filteredPlaylistSongs];
|
//FilteredPlaylistSongs = [.. filteredPlaylistSongs];
|
||||||
|
|
||||||
for (int i = FilteredPlaylistSongs.Count -1; i >= 0; i--)
|
for (int i = FilteredPlaylistSongs.Count - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
PlaylistSong playlistSong = FilteredPlaylistSongs[i];
|
PlaylistSong playlistSong = FilteredPlaylistSongs[i];
|
||||||
|
|
||||||
@@ -382,7 +407,7 @@ public partial class PlaylistViewModel : ViewModelBase
|
|||||||
|
|
||||||
private FilePickerFileType GetAudioFileTypes()
|
private FilePickerFileType GetAudioFileTypes()
|
||||||
{
|
{
|
||||||
string[] patterns = _audioEngine.SupportedFormats.Select(format => format.Replace("*", "")).ToArray();
|
string[] patterns = [.. _audioEngine.SupportedFormats.Select(format => format.Replace("*", ""))];
|
||||||
|
|
||||||
return new()
|
return new()
|
||||||
{
|
{
|
||||||
@@ -396,7 +421,7 @@ public partial class PlaylistViewModel : ViewModelBase
|
|||||||
if (Playlist == null)
|
if (Playlist == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
string? path = await _storageProvider.GetPathAsync();
|
string? path = await _storageProvider.GetPathAsync();
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(path))
|
if (string.IsNullOrWhiteSpace(path))
|
||||||
return;
|
return;
|
||||||
@@ -448,7 +473,7 @@ public partial class PlaylistViewModel : ViewModelBase
|
|||||||
{
|
{
|
||||||
if (SelectedPlaylistSongs.Count == 0)
|
if (SelectedPlaylistSongs.Count == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
CopySelectedSongsToClipboard();
|
CopySelectedSongsToClipboard();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -184,6 +184,11 @@
|
|||||||
Name="PlaylistListView"
|
Name="PlaylistListView"
|
||||||
ItemsSource="{Binding FilteredPlaylistSongs}"
|
ItemsSource="{Binding FilteredPlaylistSongs}"
|
||||||
ItemTemplate="{StaticResource SongTemplate}"
|
ItemTemplate="{StaticResource SongTemplate}"
|
||||||
|
CanReorderItems="True"
|
||||||
|
CanDragItems="True"
|
||||||
|
DragItemsStarting="PlaylistListView_DragItemsStarting"
|
||||||
|
DragItemsCompleted="PlaylistListView_DragItemsCompleted"
|
||||||
|
AllowDrop="True"
|
||||||
SelectionMode="Extended"
|
SelectionMode="Extended"
|
||||||
SelectionChanged="PlaylistListView_SelectionChanged">
|
SelectionChanged="PlaylistListView_SelectionChanged">
|
||||||
<ListView.ContextFlyout>
|
<ListView.ContextFlyout>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using CommunityToolkit.WinUI;
|
using CommunityToolkit.WinUI;
|
||||||
|
using Harmonia.Core.Imaging;
|
||||||
using Harmonia.Core.Playlists;
|
using Harmonia.Core.Playlists;
|
||||||
using Harmonia.WinUI.ViewModels;
|
using Harmonia.WinUI.ViewModels;
|
||||||
using Microsoft.UI.Dispatching;
|
using Microsoft.UI.Dispatching;
|
||||||
@@ -12,6 +13,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Windows.UI.Popups;
|
using Windows.UI.Popups;
|
||||||
|
|
||||||
namespace Harmonia.WinUI.Views;
|
namespace Harmonia.WinUI.Views;
|
||||||
@@ -179,6 +181,7 @@ public sealed partial class PlaylistView : UserControl
|
|||||||
{
|
{
|
||||||
int hashCode = image.GetHashCode();
|
int hashCode = image.GetHashCode();
|
||||||
//BitmapImage? bitmapImage = await _viewModel.GetBitmapImageAsync(hashCode, playlistSong);
|
//BitmapImage? bitmapImage = await _viewModel.GetBitmapImageAsync(hashCode, playlistSong);
|
||||||
|
//SongPictureInfo? songPictureInfo = await _viewModel.GetSongPictureInfoAsync(hashCode, playlistSong);
|
||||||
|
|
||||||
DispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, async () =>
|
DispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, async () =>
|
||||||
{
|
{
|
||||||
@@ -248,4 +251,14 @@ public sealed partial class PlaylistView : UserControl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void PlaylistListView_DragItemsStarting(object sender, DragItemsStartingEventArgs e)
|
||||||
|
{
|
||||||
|
_viewModel.IsUserUpdating = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PlaylistListView_DragItemsCompleted(ListViewBase sender, DragItemsCompletedEventArgs args)
|
||||||
|
{
|
||||||
|
_viewModel.IsUserUpdating = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user