mirror of
https://github.com/Royce551/FRESHMusicPlayer.git
synced 2025-01-22 10:51:52 -05:00
Add queue management implementation, fix audio skipping
This commit is contained in:
parent
dac32e7096
commit
176026f1c4
5 changed files with 221 additions and 3 deletions
|
@ -3,6 +3,7 @@ using ATL.Playlist;
|
|||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.ApplicationLifetimes;
|
||||
using Avalonia.Media.Imaging;
|
||||
using Avalonia.Threading;
|
||||
using FRESHMusicPlayer.Handlers;
|
||||
using FRESHMusicPlayer.Handlers.Configuration;
|
||||
using LiteDB;
|
||||
|
@ -61,7 +62,7 @@ namespace FRESHMusicPlayer.ViewModels
|
|||
ProgressTimer.Stop();
|
||||
}
|
||||
|
||||
private void ProgressTimer_Elapsed(object sender, ElapsedEventArgs e) => ProgressTick();
|
||||
private async void ProgressTimer_Elapsed(object sender, ElapsedEventArgs e) => await Dispatcher.UIThread.InvokeAsync(() => ProgressTick());
|
||||
|
||||
public void ProgressTick()
|
||||
{
|
||||
|
@ -500,6 +501,11 @@ namespace FRESHMusicPlayer.ViewModels
|
|||
{
|
||||
new Views.Settings().Show();
|
||||
}
|
||||
|
||||
public void OpenQueueManagementCommand()
|
||||
{
|
||||
new Views.QueueManagement().SetStuff(Player, Library, ProgressTimer).Show();
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,108 @@
|
|||
using FRESHMusicPlayer.Handlers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using ReactiveUI;
|
||||
using System.Timers;
|
||||
using Avalonia.Threading;
|
||||
|
||||
namespace FRESHMusicPlayer.ViewModels
|
||||
{
|
||||
public class QueueManagementViewModel : ViewModelBase
|
||||
{
|
||||
public Player Player { get; set; }
|
||||
public Library Library { get; set; }
|
||||
public Timer ProgressTimer { get; set; }
|
||||
|
||||
public ObservableCollection<QueueManagementEntry> Queue { get; set; } = new();
|
||||
|
||||
public void Update()
|
||||
{
|
||||
Queue.Clear();
|
||||
int number = 1;
|
||||
foreach (var track in Player.Queue.Queue)
|
||||
{
|
||||
var info = Library.GetFallbackTrack(track);
|
||||
var entry = new QueueManagementEntry
|
||||
{
|
||||
Title = info.Title,
|
||||
Artist = info.Artist,
|
||||
Position = number
|
||||
};
|
||||
entry.IsCurrentTrack = Player.Queue.Position == number;
|
||||
Queue.Add(entry);
|
||||
number++;
|
||||
}
|
||||
}
|
||||
|
||||
public void JumpToCommand(int position)
|
||||
{
|
||||
Player.Queue.Position = position;
|
||||
Player.PlayMusic();
|
||||
}
|
||||
public void RemoveCommand(int position)
|
||||
{
|
||||
Player.Queue.Remove(position);
|
||||
}
|
||||
|
||||
private TimeSpan timeRemaining = new();
|
||||
public TimeSpan TimeRemaining
|
||||
{
|
||||
get => timeRemaining;
|
||||
set => this.RaiseAndSetIfChanged(ref timeRemaining, value);
|
||||
}
|
||||
|
||||
public void StartThings()
|
||||
{
|
||||
Player.Queue.QueueChanged += Queue_QueueChanged;
|
||||
Player.SongChanged += Player_SongChanged;
|
||||
Player.SongStopped += Player_SongStopped;
|
||||
ProgressTimer.Elapsed += ProgressTimer_Elapsed;
|
||||
Update();
|
||||
}
|
||||
|
||||
private async void ProgressTimer_Elapsed(object sender, ElapsedEventArgs e)
|
||||
{
|
||||
await Dispatcher.UIThread.InvokeAsync(() =>
|
||||
{
|
||||
TimeSpan x = new();
|
||||
int i = 1;
|
||||
foreach (var track in Player.Queue.Queue)
|
||||
{
|
||||
i++;
|
||||
if (i <= Player.Queue.Position) continue;
|
||||
var y = Library.GetFallbackTrack(track);
|
||||
x += TimeSpan.FromSeconds(y.Length);
|
||||
|
||||
}
|
||||
x -= Player.CurrentTime;
|
||||
TimeRemaining = x;
|
||||
});
|
||||
}
|
||||
|
||||
private void Player_SongStopped(object sender, EventArgs e) => Update();
|
||||
|
||||
private void Player_SongChanged(object sender, EventArgs e) => Update();
|
||||
|
||||
public void CloseThings()
|
||||
{
|
||||
Player.Queue.QueueChanged -= Queue_QueueChanged;
|
||||
Player.SongChanged -= Player_SongChanged;
|
||||
Player.SongStopped -= Player_SongStopped;
|
||||
ProgressTimer.Elapsed -= ProgressTimer_Elapsed;
|
||||
}
|
||||
|
||||
private void Queue_QueueChanged(object sender, EventArgs e) => Update();
|
||||
}
|
||||
|
||||
public class QueueManagementEntry
|
||||
{
|
||||
public string Title { get; init; }
|
||||
public string Artist { get; init; }
|
||||
public int Position { get; init; }
|
||||
public bool IsCurrentTrack { get; set; }
|
||||
}
|
||||
}
|
|
@ -46,7 +46,7 @@
|
|||
<Button Margin="0,5">
|
||||
<Image Source="{DynamicResource Notification}"/>
|
||||
</Button>
|
||||
<Button Margin="0,5">
|
||||
<Button Margin="0,5" Command="{Binding OpenQueueManagementCommand}">
|
||||
<Image Source="{DynamicResource Queue}"/>
|
||||
</Button>
|
||||
<Button Margin="0,5" Command="{Binding OpenSettingsCommand}">
|
||||
|
@ -68,7 +68,7 @@
|
|||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock x:Name="TrackTitleTextBlock" Grid.Row="0" Text="{Binding Title}" FontSize="20" FontWeight="Bold" Padding="10,10,0,0" />
|
||||
<TextBlock x:Name="TrackTitleTextBlock" Grid.Row="0" Text="{Binding Title}" TextTrimming="CharacterEllipsis" FontSize="20" FontWeight="Bold" Padding="10,10,0,0" />
|
||||
<TextBlock x:Name="TrackArtistTextBlock" Grid.Row="1" Text="{Binding Artist}" Foreground="{DynamicResource ThemeMidBrush}" Padding="10,0,0,0" />
|
||||
<Grid Grid.Row="2" Margin="10, -15">
|
||||
<Grid.ColumnDefinitions>
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
<Window xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:vm="using:FRESHMusicPlayer.ViewModels"
|
||||
mc:Ignorable="d" Width="500" Height="400"
|
||||
xmlns:svg="clr-namespace:Avalonia.Svg.Skia;assembly=Avalonia.Svg.Skia"
|
||||
x:Class="FRESHMusicPlayer.Views.QueueManagement"
|
||||
Title="QueueManagement">
|
||||
<Window.DataContext>
|
||||
<vm:QueueManagementViewModel/>
|
||||
</Window.DataContext>
|
||||
<Window.Resources>
|
||||
<svg:SvgImage x:Key="Play" Source="/Assets/play.svg"/>
|
||||
<svg:SvgImage x:Key="Delete" Source="/Assets/delete.svg"/>
|
||||
</Window.Resources>
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="1*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<StackPanel Grid.Column="0" Grid.Row="0" Orientation="Horizontal" Margin="5,5,5,0">
|
||||
<CheckBox Grid.Column="0" Grid.Row="0" IsChecked="{Binding $parent[Window].Topmost}" Content="Pin to top"/>
|
||||
<TextBlock Text="Time Remaining:" VerticalAlignment="Center"/>
|
||||
<TextBlock Text="{Binding TimeRemaining, StringFormat=\{0:hh\\:mm\\:ss\}}" VerticalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
|
||||
|
||||
<ListBox Grid.Column="0" Grid.Row="1" Items="{Binding Queue}" Margin="5,0,5,5" ScrollViewer.HorizontalScrollBarVisibility="Disabled" SelectionMode="AlwaysSelected" VirtualizationMode="Simple" Focusable="False">
|
||||
<ListBox.DataTemplates>
|
||||
<DataTemplate>
|
||||
<Grid Margin="-5" Height="25" Background="Transparent" HorizontalAlignment="Stretch">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<StackPanel Grid.Column="0" Grid.Row="0" Grid.RowSpan="2" Margin="0,0,5,0" VerticalAlignment="Center" HorizontalAlignment="Center">
|
||||
<TextBlock Text="{Binding Position}" FontWeight="Bold" FontSize="16" IsVisible="{Binding !IsCurrentTrack}"/>
|
||||
<TextBlock Text=">" FontWeight="Bold" FontSize="16" IsVisible="{Binding IsCurrentTrack}"/>
|
||||
</StackPanel>
|
||||
<TextBlock Grid.Column="1" Grid.Row="0" Text="{Binding Title}" HorizontalAlignment="Stretch" TextTrimming="CharacterEllipsis" FontSize="15" FontWeight="Bold"/>
|
||||
<TextBlock Grid.Column="1" Grid.Row="1" Text="{Binding Artist}" FontSize="10"/>
|
||||
<StackPanel Grid.Column="2" Grid.RowSpan="2" VerticalAlignment="Center" Height="38" Margin="0,-27,0,-30" Orientation="Horizontal">
|
||||
<Button IsVisible="{Binding $parent[1].IsPointerOver}" Command="{Binding JumpToCommand}" CommandParameter="{Binding Position}" VerticalAlignment="Center">
|
||||
<Image Source="{DynamicResource Play}"/>
|
||||
</Button>
|
||||
<Button IsVisible="{Binding $parent[1].IsPointerOver}" Command="{Binding RemoveCommand}" CommandParameter="{Binding Position}" VerticalAlignment="Center">
|
||||
<Image Source="{DynamicResource Delete}"/>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListBox.DataTemplates>
|
||||
</ListBox>
|
||||
|
||||
<StackPanel Grid.Row="2" Grid.RowSpan="3" HorizontalAlignment="Center" Orientation="Horizontal" Margin="0,0,0,5" IsVisible="{Binding $parent[1].IsPointerOver}">
|
||||
<Button Content="Add Track"/>
|
||||
<Button Content="Add Playlist"/>
|
||||
<Button Content="Clear Queue" Foreground="Red"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Window>
|
|
@ -0,0 +1,35 @@
|
|||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using FRESHMusicPlayer.Handlers;
|
||||
using FRESHMusicPlayer.ViewModels;
|
||||
using System.Timers;
|
||||
|
||||
namespace FRESHMusicPlayer.Views
|
||||
{
|
||||
public class QueueManagement : Window
|
||||
{
|
||||
public QueueManagement()
|
||||
{
|
||||
InitializeComponent();
|
||||
#if DEBUG
|
||||
this.AttachDevTools();
|
||||
#endif
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
|
||||
public QueueManagement SetStuff(Player player, Library library, Timer progressTimer)
|
||||
{
|
||||
var context = DataContext as QueueManagementViewModel;
|
||||
context.Player = player;
|
||||
context.Library = library;
|
||||
context.ProgressTimer = progressTimer;
|
||||
context.StartThings();
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue