UI is now updated through MPD events and not every second + misc fixes

This commit is contained in:
Théo Marchal 2021-08-31 01:30:00 +02:00
parent 1b44c64ec5
commit 72d2c5993d
6 changed files with 211 additions and 113 deletions

View File

@ -14,15 +14,15 @@ namespace unison
{ {
base.OnStartup(e); base.OnStartup(e);
Snapcast = new SnapcastHandler();
Current.Properties["snapcast"] = Snapcast;
MPD = new MPDHandler(); MPD = new MPDHandler();
Current.Properties["mpd"] = MPD; Current.Properties["mpd"] = MPD;
Hotkeys = new HotkeyHandler(); Hotkeys = new HotkeyHandler();
Current.Properties["hotkeys"] = Hotkeys; Current.Properties["hotkeys"] = Hotkeys;
Snapcast = new SnapcastHandler();
Current.Properties["snapcast"] = Snapcast;
Current.MainWindow = new MainWindow(); Current.MainWindow = new MainWindow();
Systray = (TaskbarIcon)FindResource("SystrayTaskbar"); Systray = (TaskbarIcon)FindResource("SystrayTaskbar");

View File

@ -6,12 +6,16 @@ using System.Net;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
using System.Windows.Threading;
using MpcNET; using MpcNET;
using MpcNET.Commands.Database; using MpcNET.Commands.Database;
using MpcNET.Commands.Playback; using MpcNET.Commands.Playback;
using MpcNET.Commands.Reflection; using MpcNET.Commands.Reflection;
using MpcNET.Commands.Status; using MpcNET.Commands.Status;
using MpcNET.Message;
using MpcNET.Types;
namespace unison namespace unison
{ {
@ -26,13 +30,17 @@ namespace unison
public bool _currentConsume; public bool _currentConsume;
public double _currentTime; public double _currentTime;
public double _totalTime; public double _totalTime;
BitmapFrame _cover; BitmapFrame _cover;
public event EventHandler ConnectionChanged;
public event EventHandler StatusChanged;
public event EventHandler SongChanged;
public event EventHandler CoverChanged;
public static MpdStatus BOGUS_STATUS = new MpdStatus(0, false, false, false, false, -1, -1, -1, MpdState.Unknown, -1, -1, -1, -1, TimeSpan.Zero, TimeSpan.Zero, -1, -1, -1, -1, -1, "", ""); public static MpdStatus BOGUS_STATUS = new MpdStatus(0, false, false, false, false, -1, -1, -1, MpdState.Unknown, -1, -1, -1, -1, TimeSpan.Zero, TimeSpan.Zero, -1, -1, -1, -1, -1, "", "");
public MpdStatus CurrentStatus { get; private set; } = BOGUS_STATUS; public MpdStatus CurrentStatus { get; private set; } = BOGUS_STATUS;
MpcNET.Types.IMpdFile CurrentSong { get; set; } IMpdFile CurrentSong { get; set; }
private readonly System.Timers.Timer _elapsedTimer; private readonly System.Timers.Timer _elapsedTimer;
private async void ElapsedTimer(object sender, System.Timers.ElapsedEventArgs e) private async void ElapsedTimer(object sender, System.Timers.ElapsedEventArgs e)
@ -49,7 +57,6 @@ namespace unison
} }
private MpcConnection _connection; private MpcConnection _connection;
private MpcConnection _commandConnection; private MpcConnection _commandConnection;
private IPEndPoint _mpdEndpoint; private IPEndPoint _mpdEndpoint;
@ -64,20 +71,76 @@ namespace unison
_elapsedTimer = new System.Timers.Timer(500); _elapsedTimer = new System.Timers.Timer(500);
_elapsedTimer.Elapsed += new System.Timers.ElapsedEventHandler(ElapsedTimer); _elapsedTimer.Elapsed += new System.Timers.ElapsedEventHandler(ElapsedTimer);
ConnectionChanged += OnConnectionChanged;
StatusChanged += OnStatusChanged;
SongChanged += OnSongChanged;
CoverChanged += OnCoverChanged;
} }
private async void Initialize() static void OnConnectionChanged(object sender, EventArgs e)
{
Application.Current.Dispatcher.Invoke(() =>
{
MainWindow MainWin = (MainWindow)Application.Current.MainWindow;
MainWin.OnConnectionChanged(sender, e);
SnapcastHandler Snapcast = (SnapcastHandler)Application.Current.Properties["snapcast"];
Snapcast.OnConnectionChanged(sender, e);
}, DispatcherPriority.ContextIdle);
}
static void OnStatusChanged(object sender, EventArgs e)
{
Application.Current.Dispatcher.Invoke(() =>
{
MainWindow MainWin = (MainWindow)Application.Current.MainWindow;
MainWin.OnStatusChanged(sender, e);
}, DispatcherPriority.ContextIdle);
}
static void OnSongChanged(object sender, EventArgs e)
{
Application.Current.Dispatcher.Invoke(() =>
{
MainWindow MainWin = (MainWindow)Application.Current.MainWindow;
MainWin.OnSongChanged(sender, e);
}, DispatcherPriority.ContextIdle);
}
static void OnCoverChanged(object sender, EventArgs e)
{
Application.Current.Dispatcher.Invoke(() =>
{
MainWindow MainWin = (MainWindow)Application.Current.MainWindow;
MainWin.OnCoverChanged(sender, e);
}, DispatcherPriority.ContextIdle);
}
private void Initialize()
{
Connect();
}
public async void Connect()
{ {
var token = cancelToken.Token; var token = cancelToken.Token;
_connection = await Connect(token); try
_commandConnection = await Connect(token); {
_connection = await ConnectInternal(token);
_commandConnection = await ConnectInternal(token);
}
catch(MpcNET.Exceptions.MpcConnectException exception)
{
Trace.WriteLine("exception: " + exception);
}
if (_connection.IsConnected) if (_connection.IsConnected)
{ {
_connected = true; _connected = true;
_version = _connection.Version; _version = _connection.Version;
ConnectionChanged?.Invoke(this, EventArgs.Empty);
} }
Trace.WriteLine("is connected: " + _connected);
Trace.WriteLine("version: " + _version);
await UpdateStatusAsync(); await UpdateStatusAsync();
await UpdateSongAsync(); await UpdateSongAsync();
@ -85,7 +148,7 @@ namespace unison
Loop(token); Loop(token);
} }
private async Task<MpcConnection> Connect(CancellationToken token) private async Task<MpcConnection> ConnectInternal(CancellationToken token)
{ {
IPAddress.TryParse(Properties.Settings.Default.mpd_host, out IPAddress ipAddress); IPAddress.TryParse(Properties.Settings.Default.mpd_host, out IPAddress ipAddress);
@ -95,7 +158,7 @@ namespace unison
if (!string.IsNullOrEmpty(Properties.Settings.Default.mpd_password)) if (!string.IsNullOrEmpty(Properties.Settings.Default.mpd_password))
{ {
MpcNET.Message.IMpdMessage<string> result = await connection.SendAsync(new PasswordCommand(Properties.Settings.Default.mpd_password)); IMpdMessage<string> result = await connection.SendAsync(new PasswordCommand(Properties.Settings.Default.mpd_password));
if (!result.IsResponseValid) if (!result.IsResponseValid)
{ {
string mpdError = result.Response?.Result?.MpdError; string mpdError = result.Response?.Result?.MpdError;
@ -135,15 +198,45 @@ namespace unison
private async Task HandleIdleResponseAsync(string subsystems) private async Task HandleIdleResponseAsync(string subsystems)
{ {
if (subsystems.Contains("player") || subsystems.Contains("mixer") || subsystems.Contains("output") || subsystems.Contains("options")) try
{ {
await UpdateStatusAsync(); if (subsystems.Contains("player") || subsystems.Contains("mixer") || subsystems.Contains("output") || subsystems.Contains("options"))
if (subsystems.Contains("player"))
{ {
await UpdateSongAsync(); await UpdateStatusAsync();
if (subsystems.Contains("player"))
{
await UpdateSongAsync();
}
} }
} }
catch (Exception e)
{
Trace.WriteLine($"Error in Idle connection thread: {e.Message}");
}
}
private async Task UpdateStatusCommand()
{
if (_commandConnection == null) return;
try
{
MpdStatus response = await SafelySendCommandAsync(new StatusCommand());
if (response != null)
{
CurrentStatus = response;
UpdateStatus();
}
else
throw new Exception();
}
catch (Exception e)
{
Trace.WriteLine($"Error in Idle connection thread: {e.Message}");
Connect();
}
} }
bool _isUpdatingStatus = false; bool _isUpdatingStatus = false;
@ -156,7 +249,7 @@ namespace unison
try try
{ {
MpcNET.Message.IMpdMessage<MpdStatus> response = await _connection.SendAsync(new StatusCommand()); IMpdMessage<MpdStatus> response = await _connection.SendAsync(new StatusCommand());
if (response != null && response.IsResponseValid) if (response != null && response.IsResponseValid)
{ {
CurrentStatus = response.Response.Content; CurrentStatus = response.Response.Content;
@ -165,9 +258,10 @@ namespace unison
else else
throw new Exception(); throw new Exception();
} }
catch catch (Exception e)
{ {
await Connect(cancelToken.Token); Trace.WriteLine($"Error in Idle connection thread: {e.Message}");
Connect();
} }
_isUpdatingStatus = false; _isUpdatingStatus = false;
} }
@ -182,7 +276,7 @@ namespace unison
try try
{ {
MpcNET.Message.IMpdMessage<MpcNET.Types.IMpdFile> response = await _connection.SendAsync(new CurrentSongCommand()); IMpdMessage<IMpdFile> response = await _connection.SendAsync(new CurrentSongCommand());
if (response != null && response.IsResponseValid) if (response != null && response.IsResponseValid)
{ {
CurrentSong = response.Response.Content; CurrentSong = response.Response.Content;
@ -193,9 +287,10 @@ namespace unison
throw new Exception(); throw new Exception();
} }
} }
catch catch (Exception e)
{ {
await Connect(cancelToken.Token); Trace.WriteLine($"Error in Idle connection thread: {e.Message}");
Connect();
} }
_isUpdatingSong = false; _isUpdatingSong = false;
} }
@ -247,7 +342,7 @@ namespace unison
totalBinarySize = response.Size; totalBinarySize = response.Size;
currentSize += response.Binary; currentSize += response.Binary;
data.AddRange(response.Data); data.AddRange(response.Data);
Debug.WriteLine($"Downloading albumart: {currentSize}/{totalBinarySize}"); //Debug.WriteLine($"Downloading albumart: {currentSize}/{totalBinarySize}");
} while (currentSize < totalBinarySize && !token.IsCancellationRequested); } while (currentSize < totalBinarySize && !token.IsCancellationRequested);
} }
catch (Exception e) catch (Exception e)
@ -260,11 +355,12 @@ namespace unison
{ {
Trace.WriteLine("empty cover"); Trace.WriteLine("empty cover");
_cover = null; _cover = null;
return;
} }
else
using var stream = new MemoryStream(data.ToArray()); {
_cover = BitmapFrame.Create(stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad); using MemoryStream stream = new MemoryStream(data.ToArray());
_cover = BitmapFrame.Create(stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
}
UpdateCover(); UpdateCover();
} }
@ -275,20 +371,20 @@ namespace unison
if (CurrentSong == null) if (CurrentSong == null)
return; return;
Trace.WriteLine($"[DEBUG] Song: name[{CurrentSong.Title}] artist[{CurrentSong.Artist}] album[{CurrentSong.Album}] uri[{CurrentSong.Path}]");
_currentTime = CurrentStatus.Elapsed.TotalSeconds; _currentTime = CurrentStatus.Elapsed.TotalSeconds;
_totalTime = CurrentSong.Time; _totalTime = CurrentSong.Time;
if (!_elapsedTimer.Enabled) if (!_elapsedTimer.Enabled)
_elapsedTimer.Start(); _elapsedTimer.Start();
SongChanged?.Invoke(this, EventArgs.Empty);
string uri = Regex.Escape(CurrentSong.Path); string uri = Regex.Escape(CurrentSong.Path);
GetAlbumBitmap(uri); GetAlbumBitmap(uri);
} }
public void UpdateCover() public void UpdateCover()
{ {
CoverChanged?.Invoke(this, EventArgs.Empty);
} }
public void UpdateStatus() public void UpdateStatus()
@ -305,62 +401,26 @@ namespace unison
_currentSingle = CurrentStatus.Single; _currentSingle = CurrentStatus.Single;
_currentVolume = CurrentStatus.Volume; _currentVolume = CurrentStatus.Volume;
Trace.WriteLine($"[DEBUG] Status: volume[{CurrentStatus.Volume}] random[{CurrentStatus.Random}] consume[{CurrentStatus.Consume}] State[{CurrentStatus.State}] Bitrate[{CurrentStatus.Bitrate}]"); StatusChanged?.Invoke(this, EventArgs.Empty);
} }
public MpcNET.Types.IMpdFile GetCurrentSong() => CurrentSong; public IMpdFile GetCurrentSong() => CurrentSong;
public MpdStatus GetStatus() => CurrentStatus; public MpdStatus GetStatus() => CurrentStatus;
public BitmapFrame GetCover() => _cover; public BitmapFrame GetCover() => _cover;
public string GetVersion() => _version; public string GetVersion() => _version;
public async void Prev() public async void Prev() => await SafelySendCommandAsync(new PreviousCommand());
{ public async void Next() => await SafelySendCommandAsync(new NextCommand());
await SafelySendCommandAsync(new PreviousCommand()); public async void PlayPause() =>await SafelySendCommandAsync(new PauseResumeCommand());
}
public async void Next() public async void Random() => await SafelySendCommandAsync(new RandomCommand(!_currentRandom));
{ public async void Repeat() => await SafelySendCommandAsync(new RepeatCommand(!_currentRepeat));
await SafelySendCommandAsync(new NextCommand()); public async void Single() => await SafelySendCommandAsync(new SingleCommand(!_currentSingle));
} public async void Consume() => await SafelySendCommandAsync(new ConsumeCommand(!_currentConsume));
public async void PlayPause() public async void SetVolume(int value) => await SafelySendCommandAsync(new SetVolumeCommand((byte)value));
{ public async void SetTime(double value) => await SafelySendCommandAsync(new SeekCurCommand(value));
await SafelySendCommandAsync(new PauseResumeCommand());
}
public async void Random() public bool IsPlaying() => CurrentStatus?.State == MpdState.Play;
{
await SafelySendCommandAsync(new RandomCommand(!_currentRandom));
}
public async void Repeat()
{
await SafelySendCommandAsync(new RepeatCommand(!_currentRepeat));
}
public async void Single()
{
await SafelySendCommandAsync(new SingleCommand(!_currentSingle));
}
public async void Consume()
{
var response2 = await SafelySendCommandAsync(new ConsumeCommand(!_currentConsume));
}
public async void SetVolume(int value)
{
await SafelySendCommandAsync(new SetVolumeCommand((byte)value));
}
public async void SetTime(double value)
{
await SafelySendCommandAsync(new SeekCurCommand(value));
}
public bool IsPlaying()
{
return CurrentStatus?.State == MpdState.Play;
}
} }
} }

View File

@ -1,7 +1,8 @@
using Hardcodet.Wpf.TaskbarNotification; using System;
using System;
using System.Diagnostics; using System.Diagnostics;
using System.Windows; using System.Windows;
using System.Windows.Threading;
using Hardcodet.Wpf.TaskbarNotification;
namespace unison namespace unison
{ {
@ -9,28 +10,39 @@ namespace unison
{ {
private readonly Process _snapcast = new(); private readonly Process _snapcast = new();
public bool Started { get; private set; } public bool Started { get; private set; }
private string _snapcastPath;
public SnapcastHandler() public SnapcastHandler()
{ {
// wip: this will have to be moved after the mpd connection, later on
_snapcastPath = Properties.Settings.Default.snapcast_path;
if (Properties.Settings.Default.snapcast_startup)
Start();
} }
private void UpdateSystray() public void OnConnectionChanged(object sender, EventArgs e)
{
if (Properties.Settings.Default.snapcast_startup)
{
var mpd = (MPDHandler)Application.Current.Properties["mpd"];
if (mpd._connected)
Start();
}
}
public void UpdateInterface()
{ {
TaskbarIcon Systray = (TaskbarIcon)Application.Current.Properties["systray"]; TaskbarIcon Systray = (TaskbarIcon)Application.Current.Properties["systray"];
SystrayViewModel DataContext = Systray.DataContext as SystrayViewModel; SystrayViewModel DataContext = Systray.DataContext as SystrayViewModel;
DataContext.OnPropertyChanged("SnapcastText"); DataContext.OnPropertyChanged("SnapcastText");
Application.Current.Dispatcher.Invoke(() =>
{
MainWindow MainWin = (MainWindow)Application.Current.MainWindow;
MainWin.OnSnapcastChanged();
}, DispatcherPriority.ContextIdle);
} }
public void Start() public void Start()
{ {
if (!Started) if (!Started)
{ {
_snapcast.StartInfo.FileName = _snapcastPath + @"\snapclient.exe"; _snapcast.StartInfo.FileName = Properties.Settings.Default.snapcast_path + @"\snapclient.exe";
_snapcast.StartInfo.Arguments = $"--host {Properties.Settings.Default.mpd_host}"; _snapcast.StartInfo.Arguments = $"--host {Properties.Settings.Default.mpd_host}";
_snapcast.StartInfo.CreateNoWindow = true; _snapcast.StartInfo.CreateNoWindow = true;
try try
@ -39,19 +51,19 @@ namespace unison
} }
catch (Exception err) catch (Exception err)
{ {
MessageBox.Show($"[Snapcast error]\nInvalid path: {err.Message}\n\nCurrent path: {_snapcastPath}\nYou can reset it in the settings if needed.", MessageBox.Show($"[Snapcast error]\nInvalid path: {err.Message}\n\nCurrent path: {Properties.Settings.Default.snapcast_path}\nYou can reset it in the settings if needed.",
"unison", MessageBoxButton.OK, MessageBoxImage.Error); "unison", MessageBoxButton.OK, MessageBoxImage.Error);
Trace.WriteLine(err.Message); Trace.WriteLine(err.Message);
return; return;
} }
Started = true; Started = true;
UpdateSystray(); UpdateInterface();
} }
else else
{ {
_snapcast.Kill(); _snapcast.Kill();
Started = false; Started = false;
UpdateSystray(); UpdateInterface();
} }
} }
@ -61,7 +73,7 @@ namespace unison
{ {
_snapcast.Kill(); _snapcast.Kill();
Started = false; Started = false;
UpdateSystray(); UpdateInterface();
} }
} }
} }

View File

@ -25,7 +25,11 @@
<TextBlock x:Name="SongTitle" TextWrapping="Wrap" TextAlignment="Center" FontWeight="Normal" FontSize="20" Text="Title"/> <TextBlock x:Name="SongTitle" TextWrapping="Wrap" TextAlignment="Center" FontWeight="Normal" FontSize="20" Text="Title"/>
<TextBlock x:Name="SongArtist" TextWrapping="Wrap" TextAlignment="Center" FontWeight="Bold" FontSize="18" Text="Artist"/> <TextBlock x:Name="SongArtist" TextWrapping="Wrap" TextAlignment="Center" FontWeight="Bold" FontSize="18" Text="Artist"/>
<TextBlock x:Name="SongAlbum" TextWrapping="Wrap" TextAlignment="Center" FontWeight="Normal" FontSize="16" Text="Album"/> <TextBlock x:Name="SongAlbum" TextWrapping="Wrap" TextAlignment="Center" FontWeight="Normal" FontSize="16" Text="Album"/>
<TextBlock x:Name="Bitrate" TextWrapping="Wrap" TextAlignment="Center" FontWeight="Normal" Text="Bitrate" Foreground="{DynamicResource {x:Static SystemColors.ControlDarkDarkBrushKey}}"/> <TextBlock TextWrapping="Wrap" TextAlignment="Center" FontWeight="Normal" Foreground="{DynamicResource {x:Static SystemColors.ControlDarkDarkBrushKey}}" Margin="0,2,0,0">
<Run x:Name="SongGenre"/>
<Run> </Run>
<Run x:Name="Format"/>
</TextBlock>
</StackPanel> </StackPanel>
</Grid> </Grid>
<Grid x:Name="Controls" VerticalAlignment="Top" Margin="10,95,10,0"> <Grid x:Name="Controls" VerticalAlignment="Top" Margin="10,95,10,0">
@ -99,7 +103,7 @@
</Border> </Border>
</Grid> </Grid>
<Grid x:Name="BottomLayout" HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Background="{DynamicResource {x:Static SystemColors.ControlLightBrushKey}}" Width="Auto" MinHeight="40"> <Grid x:Name="BottomLayout" HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Background="{DynamicResource {x:Static SystemColors.ControlLightBrushKey}}" Width="Auto" MinHeight="40">
<Button x:Name="Snapcast" HorizontalAlignment="Left" VerticalAlignment="Center" Click="Snapcast_Clicked" Margin="10,0,0,0" Padding="5, 2" Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" FocusVisualStyle="{x:Null}"> <Button x:Name="Snapcast" HorizontalAlignment="Left" VerticalAlignment="Center" Click="Snapcast_Clicked" Margin="10,0,0,0" Padding="5, 2" Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" FocusVisualStyle="{x:Null}" IsEnabled="False">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<emoji:TextBlock Text="🔊" Padding="0,0,0,2"/> <emoji:TextBlock Text="🔊" Padding="0,0,0,2"/>
<TextBlock x:Name="SnapcastText" Text="Start Snapcast" Margin="5, 0, 0, 0"/> <TextBlock x:Name="SnapcastText" Text="Start Snapcast" Margin="5, 0, 0, 0"/>

View File

@ -12,7 +12,7 @@ namespace unison
{ {
public readonly Settings SettingsWindow = new Settings(); public readonly Settings SettingsWindow = new Settings();
private MPDHandler mpd; private readonly MPDHandler mpd;
Thickness SelectedThickness; Thickness SelectedThickness;
Thickness BaseThickness; Thickness BaseThickness;
@ -38,7 +38,11 @@ namespace unison
private void Timer_Tick(object sender, EventArgs e) private void Timer_Tick(object sender, EventArgs e)
{ {
UpdateInterface(); if (mpd.GetCurrentSong() == null)
return;
CurrentTime.Text = FormatSeconds(mpd._currentTime);
TimeSlider.Value = mpd._currentTime / mpd.GetCurrentSong().Time * 100;
} }
public void UpdateButton(ref Border border, bool b) public void UpdateButton(ref Border border, bool b)
@ -60,24 +64,39 @@ namespace unison
return timespan.ToString(@"mm\:ss"); return timespan.ToString(@"mm\:ss");
} }
public void UpdateInterface() public void OnConnectionChanged(object sender, EventArgs e)
{ {
if (mpd.GetCurrentSong() == null || mpd.GetStatus() == null) Connection.Text = (mpd._connected ? "✔️" : "❌") + $"{Properties.Settings.Default.mpd_host}:{Properties.Settings.Default.mpd_port}";
SettingsWindow.UpdateConnectionStatus();
if (mpd._connected)
Snapcast.IsEnabled = true;
}
public void OnSongChanged(object sender, EventArgs e)
{
if (mpd.GetCurrentSong() == null)
return; return;
SongTitle.Text = mpd.GetCurrentSong().Title; if (!mpd.GetCurrentSong().HasName)
SongTitle.Text = mpd.GetCurrentSong().Title;
else
SongTitle.Text = mpd.GetCurrentSong().Title;
SongTitle.ToolTip = mpd.GetCurrentSong().Path; SongTitle.ToolTip = mpd.GetCurrentSong().Path;
SongArtist.Text = mpd.GetCurrentSong().Artist; SongArtist.Text = mpd.GetCurrentSong().Artist;
SongAlbum.Text = mpd.GetCurrentSong().Album; SongAlbum.Text = mpd.GetCurrentSong().Album;
SongGenre.Text = mpd.GetCurrentSong().Genre;
if (mpd.GetCurrentSong().Date != null) if (mpd.GetCurrentSong().Date != null)
SongAlbum.Text += $" ({ mpd.GetCurrentSong().Date})"; SongAlbum.Text += $" ({ mpd.GetCurrentSong().Date})";
Bitrate.Text = mpd.GetCurrentSong().Path.Substring(mpd.GetCurrentSong().Path.LastIndexOf(".") + 1) + " "; Format.Text = mpd.GetCurrentSong().Path.Substring(mpd.GetCurrentSong().Path.LastIndexOf(".") + 1);
Bitrate.Text += mpd.GetStatus().Bitrate + "kbps";
CurrentTime.Text = FormatSeconds(mpd._currentTime);
EndTime.Text = FormatSeconds(mpd.GetCurrentSong().Time); EndTime.Text = FormatSeconds(mpd.GetCurrentSong().Time);
}
TimeSlider.Value = mpd._currentTime / mpd.GetCurrentSong().Time * 100; public void OnStatusChanged(object sender, EventArgs e)
{
if (mpd.GetStatus() == null)
return;
if (VolumeSlider.Value != mpd._currentVolume) if (VolumeSlider.Value != mpd._currentVolume)
{ {
@ -90,13 +109,14 @@ namespace unison
else else
PlayPause.Text = "\xedb5"; PlayPause.Text = "\xedb5";
Connection.Text = (mpd._connected ? "✔️" : "❌") + $"{Properties.Settings.Default.mpd_host}:{Properties.Settings.Default.mpd_port}";
UpdateButton(ref BorderRandom, mpd._currentRandom); UpdateButton(ref BorderRandom, mpd._currentRandom);
UpdateButton(ref BorderRepeat, mpd._currentRepeat); UpdateButton(ref BorderRepeat, mpd._currentRepeat);
UpdateButton(ref BorderSingle, mpd._currentSingle); UpdateButton(ref BorderSingle, mpd._currentSingle);
UpdateButton(ref BorderConsume, mpd._currentConsume); UpdateButton(ref BorderConsume, mpd._currentConsume);
}
public void OnCoverChanged(object sender, EventArgs e)
{
if (mpd.GetCover() == null) if (mpd.GetCover() == null)
{ {
NoCover.Visibility = Visibility.Visible; NoCover.Visibility = Visibility.Visible;
@ -108,7 +128,10 @@ namespace unison
Cover.Visibility = Visibility.Visible; Cover.Visibility = Visibility.Visible;
NoCover.Visibility = Visibility.Collapsed; NoCover.Visibility = Visibility.Collapsed;
} }
}
public void OnSnapcastChanged()
{
SnapcastHandler snapcast = (SnapcastHandler)Application.Current.Properties["snapcast"]; SnapcastHandler snapcast = (SnapcastHandler)Application.Current.Properties["snapcast"];
if (snapcast.Started) if (snapcast.Started)
SnapcastText.Text = "Stop Snapcast"; SnapcastText.Text = "Stop Snapcast";

View File

@ -46,7 +46,7 @@ namespace unison
MpdHost.Text = Properties.Settings.Default.mpd_host; MpdHost.Text = Properties.Settings.Default.mpd_host;
MpdPort.Text = Properties.Settings.Default.mpd_port.ToString(); MpdPort.Text = Properties.Settings.Default.mpd_port.ToString();
MpdPassword.Text = null; //Properties.Settings.Default.mpd_password; MpdPassword.Text = Properties.Settings.Default.mpd_password;
SnapcastStartup.IsChecked = Properties.Settings.Default.snapcast_startup; SnapcastStartup.IsChecked = Properties.Settings.Default.snapcast_startup;
SnapcastPath.Text = Properties.Settings.Default.snapcast_path; SnapcastPath.Text = Properties.Settings.Default.snapcast_path;
SnapcastPort.Text = Properties.Settings.Default.snapcast_port.ToString(); SnapcastPort.Text = Properties.Settings.Default.snapcast_port.ToString();
@ -71,18 +71,17 @@ namespace unison
{ {
MPDHandler mpd = (MPDHandler)Application.Current.Properties["mpd"]; MPDHandler mpd = (MPDHandler)Application.Current.Properties["mpd"];
if (mpd._connected) if (mpd._connected)
{
ConnectionStatus.Text = "Connected to MPD " + mpd.GetVersion() + "."; ConnectionStatus.Text = "Connected to MPD " + mpd.GetVersion() + ".";
ConnectButton.IsEnabled = false; else
} ConnectionStatus.Text = "Not connected.";
} }
private void MPDConnect_Clicked(object sender, RoutedEventArgs e) private void MPDConnect_Clicked(object sender, RoutedEventArgs e)
{ {
SaveSettings(); SaveSettings();
ConnectionStatus.Text = "Connecting...";
MPDHandler mpd = (MPDHandler)Application.Current.Properties["mpd"]; MPDHandler mpd = (MPDHandler)Application.Current.Properties["mpd"];
// connect to mpd mpd.Connect();
UpdateConnectionStatus();
} }
private void SnapcastReset_Clicked(object sender, RoutedEventArgs e) private void SnapcastReset_Clicked(object sender, RoutedEventArgs e)
@ -95,7 +94,7 @@ namespace unison
{ {
Properties.Settings.Default.mpd_host = MpdHost.Text; Properties.Settings.Default.mpd_host = MpdHost.Text;
Properties.Settings.Default.mpd_port = int.Parse(MpdPort.Text, CultureInfo.InvariantCulture); Properties.Settings.Default.mpd_port = int.Parse(MpdPort.Text, CultureInfo.InvariantCulture);
Properties.Settings.Default.mpd_password = null;//MpdPassword.Text; Properties.Settings.Default.mpd_password = MpdPassword.Text;
Properties.Settings.Default.snapcast_startup = (bool)SnapcastStartup.IsChecked; Properties.Settings.Default.snapcast_startup = (bool)SnapcastStartup.IsChecked;
Properties.Settings.Default.snapcast_path = SnapcastPath.Text; Properties.Settings.Default.snapcast_path = SnapcastPath.Text;
Properties.Settings.Default.snapcast_port = int.Parse(SnapcastPort.Text, CultureInfo.InvariantCulture); Properties.Settings.Default.snapcast_port = int.Parse(SnapcastPort.Text, CultureInfo.InvariantCulture);