Compare commits
No commits in common. "2c8696155ad4c10dd176d2dc3237f80e81042be7" and "984d2056de74e6e5c1207ce5f25cf08693365289" have entirely different histories.
2c8696155a
...
984d2056de
30
App.xaml.cs
30
App.xaml.cs
@ -5,35 +5,35 @@ namespace unison
|
||||
{
|
||||
public partial class App : Application
|
||||
{
|
||||
private TaskbarIcon _systray;
|
||||
private HotkeyHandler _hotkeys;
|
||||
private SnapcastHandler _snapcast;
|
||||
private MPDHandler _mpd;
|
||||
private TaskbarIcon Systray;
|
||||
private HotkeyHandler Hotkeys;
|
||||
private SnapcastHandler Snapcast;
|
||||
private MPDHandler MPD;
|
||||
|
||||
protected override void OnStartup(StartupEventArgs e)
|
||||
{
|
||||
base.OnStartup(e);
|
||||
|
||||
_mpd = new MPDHandler();
|
||||
Current.Properties["mpd"] = _mpd;
|
||||
MPD = new MPDHandler();
|
||||
Current.Properties["mpd"] = MPD;
|
||||
|
||||
_hotkeys = new HotkeyHandler();
|
||||
Current.Properties["hotkeys"] = _hotkeys;
|
||||
Hotkeys = new HotkeyHandler();
|
||||
Current.Properties["hotkeys"] = Hotkeys;
|
||||
|
||||
_snapcast = new SnapcastHandler();
|
||||
Current.Properties["snapcast"] = _snapcast;
|
||||
Snapcast = new SnapcastHandler();
|
||||
Current.Properties["snapcast"] = Snapcast;
|
||||
|
||||
Current.MainWindow = new MainWindow();
|
||||
|
||||
_systray = (TaskbarIcon)FindResource("SystrayTaskbar");
|
||||
Current.Properties["systray"] = _systray;
|
||||
Systray = (TaskbarIcon)FindResource("SystrayTaskbar");
|
||||
Current.Properties["systray"] = Systray;
|
||||
}
|
||||
|
||||
protected override void OnExit(ExitEventArgs e)
|
||||
{
|
||||
_systray.Dispose();
|
||||
_snapcast.LaunchOrExit(true);
|
||||
_hotkeys.RemoveHotKeys();
|
||||
Systray.Dispose();
|
||||
Snapcast.Stop();
|
||||
Hotkeys.RemoveHotKeys();
|
||||
base.OnExit(e);
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows;
|
||||
using System.Windows.Interop;
|
||||
@ -30,15 +31,14 @@ namespace unison
|
||||
private const uint VK_VOLUME_DOWN = 0xAE;
|
||||
private const uint VK_ENTER = 0x0D;
|
||||
|
||||
private MainWindow _appWindow;
|
||||
private readonly MPDHandler _mpd;
|
||||
|
||||
private IntPtr _windowHandle;
|
||||
private HwndSource _source;
|
||||
|
||||
private readonly MPDHandler mpd;
|
||||
|
||||
public HotkeyHandler()
|
||||
{
|
||||
_mpd = (MPDHandler)Application.Current.Properties["mpd"];
|
||||
mpd = (MPDHandler)Application.Current.Properties["mpd"];
|
||||
}
|
||||
|
||||
public void Activate(Window win)
|
||||
@ -65,45 +65,49 @@ namespace unison
|
||||
if (msg == WM_HOTKEY && wParam.ToInt32() == HOTKEY_ID)
|
||||
{
|
||||
uint vkey = ((uint)lParam >> 16) & 0xFFFF;
|
||||
MainWindow AppWindow = (MainWindow)Application.Current.MainWindow;
|
||||
switch (vkey)
|
||||
{
|
||||
case VK_MEDIA_NEXT_TRACK:
|
||||
_mpd.Next();
|
||||
mpd.Next();
|
||||
break;
|
||||
case VK_MEDIA_PREV_TRACK:
|
||||
_mpd.Prev();
|
||||
mpd.Prev();
|
||||
break;
|
||||
case VK_VOLUME_DOWN:
|
||||
_mpd.VolumeDown();
|
||||
mpd._currentVolume -= Properties.Settings.Default.volume_offset;
|
||||
if (mpd._currentVolume < 0)
|
||||
mpd._currentVolume = 0;
|
||||
mpd.SetVolume(mpd._currentVolume);
|
||||
break;
|
||||
case VK_VOLUME_UP:
|
||||
_mpd.VolumeUp();
|
||||
mpd._currentVolume += Properties.Settings.Default.volume_offset;
|
||||
if (mpd._currentVolume > 100)
|
||||
mpd._currentVolume = 100;
|
||||
mpd.SetVolume(mpd._currentVolume);
|
||||
break;
|
||||
case VK_MEDIA_PLAY_PAUSE:
|
||||
_mpd.PlayPause();
|
||||
mpd.PlayPause();
|
||||
break;
|
||||
case VK_ENTER:
|
||||
if (_appWindow == null)
|
||||
_appWindow = (MainWindow)Application.Current.MainWindow;
|
||||
|
||||
if (_appWindow.WindowState == WindowState.Minimized)
|
||||
if (AppWindow.WindowState == WindowState.Minimized)
|
||||
{
|
||||
_appWindow.Show();
|
||||
_appWindow.Activate();
|
||||
_appWindow.WindowState = WindowState.Normal;
|
||||
AppWindow.Show();
|
||||
AppWindow.Activate();
|
||||
AppWindow.WindowState = WindowState.Normal;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_appWindow.IsActive)
|
||||
if (AppWindow.IsActive)
|
||||
{
|
||||
_appWindow.Hide();
|
||||
_appWindow.WindowState = WindowState.Minimized;
|
||||
AppWindow.Hide();
|
||||
AppWindow.WindowState = WindowState.Minimized;
|
||||
}
|
||||
else // not minimized but not in front
|
||||
{
|
||||
_appWindow.Show();
|
||||
_appWindow.Activate();
|
||||
_appWindow.WindowState = WindowState.Normal;
|
||||
AppWindow.Show();
|
||||
AppWindow.Activate();
|
||||
AppWindow.WindowState = WindowState.Normal;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -8,6 +8,7 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Threading;
|
||||
using MpcNET;
|
||||
using MpcNET.Commands.Database;
|
||||
using MpcNET.Commands.Playback;
|
||||
@ -20,29 +21,46 @@ namespace unison
|
||||
{
|
||||
public class MPDHandler
|
||||
{
|
||||
private bool _connected;
|
||||
public bool _connected;
|
||||
public string _version;
|
||||
private int _currentVolume;
|
||||
private bool _currentRandom;
|
||||
private bool _currentRepeat;
|
||||
private bool _currentSingle;
|
||||
private bool _currentConsume;
|
||||
private double _currentTime;
|
||||
private double _totalTime;
|
||||
public int _currentVolume;
|
||||
public bool _currentRandom;
|
||||
public bool _currentRepeat;
|
||||
public bool _currentSingle;
|
||||
public bool _currentConsume;
|
||||
public double _currentTime;
|
||||
public double _totalTime;
|
||||
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 MpdStatus CurrentStatus { get; private set; } = BOGUS_STATUS;
|
||||
|
||||
IMpdFile CurrentSong { get; set; }
|
||||
|
||||
private MpdStatus _currentStatus;
|
||||
private IMpdFile _currentSong;
|
||||
private BitmapFrame _cover;
|
||||
private readonly System.Timers.Timer _elapsedTimer;
|
||||
|
||||
private event EventHandler ConnectionChanged;
|
||||
private event EventHandler StatusChanged;
|
||||
private event EventHandler SongChanged;
|
||||
private event EventHandler CoverChanged;
|
||||
private async void ElapsedTimer(object sender, System.Timers.ElapsedEventArgs e)
|
||||
{
|
||||
if ((_currentTime < _totalTime) && (CurrentStatus.State == MpdState.Play))
|
||||
{
|
||||
_currentTime += 0.5;
|
||||
await Task.Delay(5);
|
||||
}
|
||||
else
|
||||
{
|
||||
_elapsedTimer.Stop();
|
||||
}
|
||||
}
|
||||
|
||||
private MpcConnection _connection;
|
||||
private MpcConnection _commandConnection;
|
||||
|
||||
private IPEndPoint _mpdEndpoint;
|
||||
|
||||
private CancellationTokenSource cancelToken;
|
||||
|
||||
public MPDHandler()
|
||||
@ -60,14 +78,6 @@ namespace unison
|
||||
CoverChanged += OnCoverChanged;
|
||||
}
|
||||
|
||||
private void ElapsedTimer(object sender, System.Timers.ElapsedEventArgs e)
|
||||
{
|
||||
if ((_currentTime < _totalTime || _totalTime == -1) && (_currentStatus.State == MpdState.Play))
|
||||
_currentTime += 0.5;
|
||||
else
|
||||
_elapsedTimer.Stop();
|
||||
}
|
||||
|
||||
static void OnConnectionChanged(object sender, EventArgs e)
|
||||
{
|
||||
Application.Current.Dispatcher.Invoke(() =>
|
||||
@ -77,7 +87,8 @@ namespace unison
|
||||
|
||||
SnapcastHandler Snapcast = (SnapcastHandler)Application.Current.Properties["snapcast"];
|
||||
Snapcast.OnConnectionChanged(sender, e);
|
||||
});
|
||||
|
||||
}, DispatcherPriority.ContextIdle);
|
||||
}
|
||||
|
||||
static void OnStatusChanged(object sender, EventArgs e)
|
||||
@ -86,7 +97,7 @@ namespace unison
|
||||
{
|
||||
MainWindow MainWin = (MainWindow)Application.Current.MainWindow;
|
||||
MainWin.OnStatusChanged(sender, e);
|
||||
});
|
||||
}, DispatcherPriority.ContextIdle);
|
||||
}
|
||||
|
||||
static void OnSongChanged(object sender, EventArgs e)
|
||||
@ -95,7 +106,7 @@ namespace unison
|
||||
{
|
||||
MainWindow MainWin = (MainWindow)Application.Current.MainWindow;
|
||||
MainWin.OnSongChanged(sender, e);
|
||||
});
|
||||
}, DispatcherPriority.ContextIdle);
|
||||
}
|
||||
|
||||
static void OnCoverChanged(object sender, EventArgs e)
|
||||
@ -104,7 +115,7 @@ namespace unison
|
||||
{
|
||||
MainWindow MainWin = (MainWindow)Application.Current.MainWindow;
|
||||
MainWin.OnCoverChanged(sender, e);
|
||||
});
|
||||
}, DispatcherPriority.ContextIdle);
|
||||
}
|
||||
|
||||
private void Initialize()
|
||||
@ -114,7 +125,7 @@ namespace unison
|
||||
|
||||
public async void Connect()
|
||||
{
|
||||
CancellationToken token = cancelToken.Token;
|
||||
var token = cancelToken.Token;
|
||||
try
|
||||
{
|
||||
_connection = await ConnectInternal(token);
|
||||
@ -151,7 +162,6 @@ namespace unison
|
||||
if (!result.IsResponseValid)
|
||||
{
|
||||
string mpdError = result.Response?.Result?.MpdError;
|
||||
Trace.WriteLine(mpdError);
|
||||
}
|
||||
}
|
||||
|
||||
@ -206,6 +216,29 @@ namespace unison
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
private async Task UpdateStatusAsync()
|
||||
{
|
||||
@ -219,7 +252,7 @@ namespace unison
|
||||
IMpdMessage<MpdStatus> response = await _connection.SendAsync(new StatusCommand());
|
||||
if (response != null && response.IsResponseValid)
|
||||
{
|
||||
_currentStatus = response.Response.Content;
|
||||
CurrentStatus = response.Response.Content;
|
||||
UpdateStatus();
|
||||
}
|
||||
else
|
||||
@ -246,7 +279,7 @@ namespace unison
|
||||
IMpdMessage<IMpdFile> response = await _connection.SendAsync(new CurrentSongCommand());
|
||||
if (response != null && response.IsResponseValid)
|
||||
{
|
||||
_currentSong = response.Response.Content;
|
||||
CurrentSong = response.Response.Content;
|
||||
UpdateSong();
|
||||
}
|
||||
else
|
||||
@ -266,7 +299,7 @@ namespace unison
|
||||
{
|
||||
try
|
||||
{
|
||||
IMpdMessage<T> response = await _commandConnection.SendAsync(command);
|
||||
var response = await _commandConnection.SendAsync(command);
|
||||
if (!response.IsResponseValid)
|
||||
{
|
||||
// If we have an MpdError string, only show that as the error to avoid extra noise
|
||||
@ -314,7 +347,7 @@ namespace unison
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Trace.WriteLine("Exception caught while getting albumart: " + e);
|
||||
Debug.WriteLine("Exception caught while getting albumart: " + e);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -335,17 +368,17 @@ namespace unison
|
||||
{
|
||||
if (!_connected)
|
||||
return;
|
||||
if (_currentSong == null)
|
||||
if (CurrentSong == null)
|
||||
return;
|
||||
|
||||
_currentTime = _currentStatus.Elapsed.TotalSeconds;
|
||||
_totalTime = _currentSong.Time;
|
||||
_currentTime = CurrentStatus.Elapsed.TotalSeconds;
|
||||
_totalTime = CurrentSong.Time;
|
||||
if (!_elapsedTimer.Enabled)
|
||||
_elapsedTimer.Start();
|
||||
|
||||
SongChanged?.Invoke(this, EventArgs.Empty);
|
||||
|
||||
string uri = Regex.Escape(_currentSong.Path);
|
||||
string uri = Regex.Escape(CurrentSong.Path);
|
||||
GetAlbumBitmap(uri);
|
||||
}
|
||||
|
||||
@ -358,26 +391,23 @@ namespace unison
|
||||
{
|
||||
if (!_connected)
|
||||
return;
|
||||
if (_currentStatus == null)
|
||||
|
||||
if (CurrentStatus == null)
|
||||
return;
|
||||
|
||||
_currentRandom = _currentStatus.Random;
|
||||
_currentRepeat = _currentStatus.Repeat;
|
||||
_currentConsume = _currentStatus.Consume;
|
||||
_currentSingle = _currentStatus.Single;
|
||||
_currentVolume = _currentStatus.Volume;
|
||||
_currentRandom = CurrentStatus.Random;
|
||||
_currentRepeat = CurrentStatus.Repeat;
|
||||
_currentConsume = CurrentStatus.Consume;
|
||||
_currentSingle = CurrentStatus.Single;
|
||||
_currentVolume = CurrentStatus.Volume;
|
||||
|
||||
StatusChanged?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
public IMpdFile GetCurrentSong() => _currentSong;
|
||||
public MpdStatus GetStatus() => _currentStatus;
|
||||
public IMpdFile GetCurrentSong() => CurrentSong;
|
||||
public MpdStatus GetStatus() => CurrentStatus;
|
||||
public BitmapFrame GetCover() => _cover;
|
||||
public string GetVersion() => _version;
|
||||
public double GetCurrentTime() => _currentTime;
|
||||
|
||||
public bool IsConnected() => _connected;
|
||||
public bool IsPlaying() => _currentStatus?.State == MpdState.Play;
|
||||
|
||||
public async void Prev() => await SafelySendCommandAsync(new PreviousCommand());
|
||||
public async void Next() => await SafelySendCommandAsync(new NextCommand());
|
||||
@ -388,23 +418,9 @@ namespace unison
|
||||
public async void Single() => await SafelySendCommandAsync(new SingleCommand(!_currentSingle));
|
||||
public async void Consume() => await SafelySendCommandAsync(new ConsumeCommand(!_currentConsume));
|
||||
|
||||
public async void SetTime(double value) => await SafelySendCommandAsync(new SeekCurCommand(value));
|
||||
public async void SetVolume(int value) => await SafelySendCommandAsync(new SetVolumeCommand((byte)value));
|
||||
|
||||
public void VolumeUp()
|
||||
{
|
||||
_currentVolume += Properties.Settings.Default.volume_offset;
|
||||
if (_currentVolume > 100)
|
||||
_currentVolume = 100;
|
||||
SetVolume(_currentVolume);
|
||||
}
|
||||
public async void SetTime(double value) => await SafelySendCommandAsync(new SeekCurCommand(value));
|
||||
|
||||
public void VolumeDown()
|
||||
{
|
||||
_currentVolume -= Properties.Settings.Default.volume_offset;
|
||||
if (_currentVolume < 0)
|
||||
_currentVolume = 0;
|
||||
SetVolume(_currentVolume);
|
||||
}
|
||||
public bool IsPlaying() => CurrentStatus?.State == MpdState.Play;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Windows;
|
||||
using System.Windows.Threading;
|
||||
using Hardcodet.Wpf.TaskbarNotification;
|
||||
|
||||
namespace unison
|
||||
@ -8,15 +9,19 @@ namespace unison
|
||||
public class SnapcastHandler
|
||||
{
|
||||
private readonly Process _snapcast = new();
|
||||
public bool HasStarted { get; private set; }
|
||||
public bool Started { get; private set; }
|
||||
|
||||
public SnapcastHandler()
|
||||
{
|
||||
}
|
||||
|
||||
public void OnConnectionChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (Properties.Settings.Default.snapcast_startup)
|
||||
{
|
||||
var mpd = (MPDHandler)Application.Current.Properties["mpd"];
|
||||
if (mpd.IsConnected())
|
||||
LaunchOrExit();
|
||||
if (mpd._connected)
|
||||
Start();
|
||||
}
|
||||
}
|
||||
|
||||
@ -30,12 +35,12 @@ namespace unison
|
||||
{
|
||||
MainWindow MainWin = (MainWindow)Application.Current.MainWindow;
|
||||
MainWin.OnSnapcastChanged();
|
||||
});
|
||||
}, DispatcherPriority.ContextIdle);
|
||||
}
|
||||
|
||||
public void LaunchOrExit(bool ForceExit = false)
|
||||
public void Start()
|
||||
{
|
||||
if (!HasStarted && !ForceExit)
|
||||
if (!Started)
|
||||
{
|
||||
_snapcast.StartInfo.FileName = Properties.Settings.Default.snapcast_path + @"\snapclient.exe";
|
||||
_snapcast.StartInfo.Arguments = $"--host {Properties.Settings.Default.mpd_host}";
|
||||
@ -48,18 +53,28 @@ namespace unison
|
||||
{
|
||||
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);
|
||||
Trace.WriteLine(err.Message);
|
||||
return;
|
||||
}
|
||||
HasStarted = true;
|
||||
Started = true;
|
||||
UpdateInterface();
|
||||
}
|
||||
else if (HasStarted)
|
||||
else
|
||||
{
|
||||
_snapcast.Kill();
|
||||
HasStarted = false;
|
||||
}
|
||||
|
||||
if (!ForceExit)
|
||||
Started = false;
|
||||
UpdateInterface();
|
||||
}
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
if (Started)
|
||||
{
|
||||
_snapcast.Kill();
|
||||
Started = false;
|
||||
UpdateInterface();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -4,6 +4,8 @@
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:emoji="clr-namespace:Emoji.Wpf;assembly=Emoji.Wpf"
|
||||
xmlns:clr="clr-namespace:System;assembly=mscorlib"
|
||||
xmlns:local="clr-namespace:unison"
|
||||
mc:Ignorable="d"
|
||||
Title="unison"
|
||||
Closing="Window_Closing" Icon="/images/icon-full.ico" ResizeMode="CanMinimize" SizeToContent="WidthAndHeight">
|
||||
@ -17,7 +19,7 @@
|
||||
</Style>
|
||||
</Window.Resources>
|
||||
|
||||
<Grid Background="{DynamicResource {x:Static SystemColors.ControlLightLightBrushKey}}" MinHeight="270" MinWidth="650">
|
||||
<Grid Background="{DynamicResource {x:Static SystemColors.ControlLightLightBrushKey}}" MinHeight="270">
|
||||
<Grid x:Name="TopLayout" Margin="10,0,10,0" VerticalAlignment="Stretch" Width="Auto" Height="Auto">
|
||||
<Grid x:Name="Display" HorizontalAlignment="Stretch" VerticalAlignment="Top" Margin="225,0,0,0" Height="Auto" Width="Auto">
|
||||
<GroupBox Height="220" VerticalAlignment="Center">
|
||||
@ -32,10 +34,10 @@
|
||||
<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="SongAlbum" TextWrapping="Wrap" TextAlignment="Center" FontWeight="Normal" FontSize="16" Text="Album"/>
|
||||
<TextBlock x:Name="SongInfo" TextWrapping="Wrap" TextAlignment="Center" FontWeight="Normal" Foreground="{DynamicResource {x:Static SystemColors.ControlDarkDarkBrushKey}}" Margin="0,2,0,0">
|
||||
<TextBlock TextWrapping="Wrap" TextAlignment="Center" FontWeight="Normal" Foreground="{DynamicResource {x:Static SystemColors.ControlDarkDarkBrushKey}}" Margin="0,2,0,0">
|
||||
<Run x:Name="SongGenre"/>
|
||||
<Run x:Name="SongInfoDash"> – </Run>
|
||||
<Run x:Name="SongFormat"/>
|
||||
<Run> – </Run>
|
||||
<Run x:Name="Format"/>
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
@ -61,7 +63,7 @@
|
||||
</Button>
|
||||
</StackPanel>
|
||||
<Grid VerticalAlignment="Stretch" Margin="0,18,0,0">
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Top" HorizontalAlignment="Center" Margin="10,2,10,0">
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Top" HorizontalAlignment="Center" Margin="0,2,0,0">
|
||||
<TextBlock FontFamily="Segoe MDL2 Assets" Text="" TextWrapping="Wrap" HorizontalAlignment="Left" VerticalAlignment="Center" FontSize="16"/>
|
||||
<Slider x:Name="VolumeSlider" Maximum="100" Value="50" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" VerticalAlignment="Center" HorizontalAlignment="Center" MinWidth="180" FlowDirection="LeftToRight" PreviewMouseUp="VolumeSlider_DragCompleted" FocusVisualStyle="{x:Null}"/>
|
||||
<TextBlock FontFamily="Segoe MDL2 Assets" Text="" TextWrapping="Wrap" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="7.5,0,0,0" FontSize="16"/>
|
||||
|
@ -9,157 +9,35 @@ using System.Windows.Controls.Primitives;
|
||||
|
||||
namespace unison
|
||||
{
|
||||
public partial class MainWindow : Window
|
||||
public partial class MainWindow : Window, INotifyPropertyChanged
|
||||
{
|
||||
private readonly Settings _settingsWin;
|
||||
private readonly DispatcherTimer _timer;
|
||||
private readonly MPDHandler _mpd;
|
||||
public readonly Settings SettingsWindow = new Settings();
|
||||
|
||||
private readonly MPDHandler mpd;
|
||||
|
||||
DispatcherTimer timer = new DispatcherTimer();
|
||||
|
||||
public MainWindow()
|
||||
{
|
||||
InitHwnd();
|
||||
InitializeComponent();
|
||||
|
||||
WindowState = WindowState.Minimized;
|
||||
|
||||
_settingsWin = new Settings();
|
||||
_timer = new DispatcherTimer();
|
||||
_mpd = (MPDHandler)Application.Current.Properties["mpd"];
|
||||
mpd = (MPDHandler)Application.Current.Properties["mpd"];
|
||||
|
||||
_timer.Interval = TimeSpan.FromSeconds(0.5);
|
||||
_timer.Tick += Timer_Tick;
|
||||
_timer.Start();
|
||||
timer.Interval = TimeSpan.FromSeconds(0.5);
|
||||
timer.Tick += Timer_Tick;
|
||||
timer.Start();
|
||||
}
|
||||
|
||||
private void Timer_Tick(object sender, EventArgs e)
|
||||
{
|
||||
if (_mpd.GetCurrentSong() == null)
|
||||
if (mpd.GetCurrentSong() == null)
|
||||
return;
|
||||
|
||||
CurrentTime.Text = FormatSeconds(_mpd.GetCurrentTime());
|
||||
TimeSlider.Value = _mpd.GetCurrentTime() / _mpd.GetCurrentSong().Time * 100;
|
||||
}
|
||||
|
||||
public void OnConnectionChanged(object sender, EventArgs e)
|
||||
{
|
||||
Connection.Text = (_mpd.IsConnected() ? "✔️" : "❌") + $"{Properties.Settings.Default.mpd_host}:{Properties.Settings.Default.mpd_port}";
|
||||
_settingsWin.UpdateConnectionStatus();
|
||||
if (_mpd.IsConnected())
|
||||
Snapcast.IsEnabled = true;
|
||||
}
|
||||
|
||||
public void OnSongChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (_mpd.GetCurrentSong() == null)
|
||||
return;
|
||||
|
||||
if (_mpd.GetCurrentSong().HasTitle && _mpd.GetCurrentSong().Title.Length > 0)
|
||||
SongTitle.Text = _mpd.GetCurrentSong().Title;
|
||||
else if (_mpd.GetCurrentSong().HasName && _mpd.GetCurrentSong().Name.Length > 0)
|
||||
SongTitle.Text = _mpd.GetCurrentSong().Name;
|
||||
else
|
||||
{
|
||||
int start = _mpd.GetCurrentSong().Path.LastIndexOf("/") + 1;
|
||||
int end = _mpd.GetCurrentSong().Path.LastIndexOf(".");
|
||||
SongTitle.Text = _mpd.GetCurrentSong().Path.Substring(start, end - start);
|
||||
}
|
||||
|
||||
SongTitle.ToolTip = _mpd.GetCurrentSong().Path;
|
||||
SongArtist.Text = _mpd.GetCurrentSong().Artist;
|
||||
SongAlbum.Text = _mpd.GetCurrentSong().Album;
|
||||
|
||||
if (_mpd.GetCurrentSong().Date != null)
|
||||
SongAlbum.Text += $" ({ _mpd.GetCurrentSong().Date})";
|
||||
|
||||
SongGenre.Text = _mpd.GetCurrentSong().Genre;
|
||||
SongFormat.Text = _mpd.GetCurrentSong().Path.Substring(_mpd.GetCurrentSong().Path.LastIndexOf(".") + 1);
|
||||
if (SongGenre.Text.Length == 0 || SongFormat.Text.Length == 0)
|
||||
SongInfoDash.Text = "";
|
||||
else
|
||||
SongInfoDash.Text = " – ";
|
||||
|
||||
TimeSlider.IsEnabled = true;
|
||||
if (_mpd.GetCurrentSong().Time == -1)
|
||||
{
|
||||
CurrentTime.Text = "";
|
||||
EndTime.Text = "";
|
||||
_timer.Stop();
|
||||
TimeSlider.Value = 50;
|
||||
TimeSlider.IsEnabled = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!_timer.IsEnabled)
|
||||
_timer.Start();
|
||||
EndTime.Text = FormatSeconds(_mpd.GetCurrentSong().Time);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnStatusChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (_mpd.GetStatus() == null)
|
||||
return;
|
||||
|
||||
if (VolumeSlider.Value != _mpd.GetStatus().Volume)
|
||||
{
|
||||
VolumeSlider.Value = _mpd.GetStatus().Volume;
|
||||
VolumeSlider.ToolTip = _mpd.GetStatus().Volume;
|
||||
}
|
||||
|
||||
UpdateButton(ref BorderRandom, _mpd.GetStatus().Random);
|
||||
UpdateButton(ref BorderRepeat, _mpd.GetStatus().Repeat);
|
||||
UpdateButton(ref BorderSingle, _mpd.GetStatus().Single);
|
||||
UpdateButton(ref BorderConsume, _mpd.GetStatus().Consume);
|
||||
|
||||
if (_mpd.IsPlaying())
|
||||
PlayPause.Text = "\xedb4";
|
||||
else
|
||||
{
|
||||
PlayPause.Text = "\xedb5";
|
||||
if (_mpd.GetStatus().State == MpcNET.MpdState.Stop)
|
||||
{
|
||||
DefaultState();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DefaultState()
|
||||
{
|
||||
SongTitle.Text = "";
|
||||
SongArtist.Text = "";
|
||||
SongAlbum.Text = "";
|
||||
SongGenre.Text = "";
|
||||
SongInfoDash.Text = "";
|
||||
SongFormat.Text = "";
|
||||
CurrentTime.Text = "";
|
||||
EndTime.Text = "";
|
||||
TimeSlider.Value = 50;
|
||||
TimeSlider.IsEnabled = false;
|
||||
NoCover.Visibility = Visibility.Visible;
|
||||
Cover.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
|
||||
public void OnCoverChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (_mpd.GetCover() == null)
|
||||
{
|
||||
NoCover.Visibility = Visibility.Visible;
|
||||
Cover.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
else if (Cover.Source != _mpd.GetCover())
|
||||
{
|
||||
Cover.Source = _mpd.GetCover();
|
||||
Cover.Visibility = Visibility.Visible;
|
||||
NoCover.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnSnapcastChanged()
|
||||
{
|
||||
SnapcastHandler snapcast = (SnapcastHandler)Application.Current.Properties["snapcast"];
|
||||
if (snapcast.HasStarted)
|
||||
SnapcastText.Text = "Stop Snapcast";
|
||||
else
|
||||
SnapcastText.Text = "Start Snapcast";
|
||||
CurrentTime.Text = FormatSeconds(mpd._currentTime);
|
||||
TimeSlider.Value = mpd._currentTime / mpd.GetCurrentSong().Time * 100;
|
||||
}
|
||||
|
||||
public void UpdateButton(ref Border border, bool b)
|
||||
@ -178,34 +56,119 @@ namespace unison
|
||||
return timespan.ToString(@"mm\:ss");
|
||||
}
|
||||
|
||||
public void Pause_Clicked(object sender, RoutedEventArgs e) => _mpd.PlayPause();
|
||||
public void Previous_Clicked(object sender, RoutedEventArgs e) => _mpd.Prev();
|
||||
public void Next_Clicked(object sender, RoutedEventArgs e) => _mpd.Next();
|
||||
public void OnConnectionChanged(object sender, EventArgs e)
|
||||
{
|
||||
Connection.Text = (mpd._connected ? "✔️" : "❌") + $"{Properties.Settings.Default.mpd_host}:{Properties.Settings.Default.mpd_port}";
|
||||
SettingsWindow.UpdateConnectionStatus();
|
||||
if (mpd._connected)
|
||||
Snapcast.IsEnabled = true;
|
||||
}
|
||||
|
||||
public void Random_Clicked(object sender, RoutedEventArgs e) => _mpd.Random();
|
||||
public void Repeat_Clicked(object sender, RoutedEventArgs e) => _mpd.Repeat();
|
||||
public void Single_Clicked(object sender, RoutedEventArgs e) => _mpd.Single();
|
||||
public void Consume_Clicked(object sender, RoutedEventArgs e) => _mpd.Consume();
|
||||
public void ChangeVolume(int value) => _mpd.SetVolume(value);
|
||||
public void OnSongChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (mpd.GetCurrentSong() == null)
|
||||
return;
|
||||
|
||||
if (!mpd.GetCurrentSong().HasName)
|
||||
SongTitle.Text = mpd.GetCurrentSong().Title;
|
||||
else
|
||||
SongTitle.Text = mpd.GetCurrentSong().Title;
|
||||
SongTitle.ToolTip = mpd.GetCurrentSong().Path;
|
||||
SongArtist.Text = mpd.GetCurrentSong().Artist;
|
||||
SongAlbum.Text = mpd.GetCurrentSong().Album;
|
||||
SongGenre.Text = mpd.GetCurrentSong().Genre;
|
||||
|
||||
if (mpd.GetCurrentSong().Date != null)
|
||||
SongAlbum.Text += $" ({ mpd.GetCurrentSong().Date})";
|
||||
Format.Text = mpd.GetCurrentSong().Path.Substring(mpd.GetCurrentSong().Path.LastIndexOf(".") + 1);
|
||||
|
||||
EndTime.Text = FormatSeconds(mpd.GetCurrentSong().Time);
|
||||
}
|
||||
|
||||
public void OnStatusChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (mpd.GetStatus() == null)
|
||||
return;
|
||||
|
||||
if (VolumeSlider.Value != mpd._currentVolume)
|
||||
{
|
||||
VolumeSlider.Value = mpd._currentVolume;
|
||||
VolumeSlider.ToolTip = mpd._currentVolume;
|
||||
}
|
||||
|
||||
if (mpd.IsPlaying())
|
||||
PlayPause.Text = "\xedb4";
|
||||
else
|
||||
PlayPause.Text = "\xedb5";
|
||||
|
||||
UpdateButton(ref BorderRandom, mpd._currentRandom);
|
||||
UpdateButton(ref BorderRepeat, mpd._currentRepeat);
|
||||
UpdateButton(ref BorderSingle, mpd._currentSingle);
|
||||
UpdateButton(ref BorderConsume, mpd._currentConsume);
|
||||
}
|
||||
|
||||
public void OnCoverChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (mpd.GetCover() == null)
|
||||
{
|
||||
NoCover.Visibility = Visibility.Visible;
|
||||
Cover.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
else if (Cover.Source != mpd.GetCover())
|
||||
{
|
||||
Cover.Source = mpd.GetCover();
|
||||
Cover.Visibility = Visibility.Visible;
|
||||
NoCover.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnSnapcastChanged()
|
||||
{
|
||||
SnapcastHandler snapcast = (SnapcastHandler)Application.Current.Properties["snapcast"];
|
||||
if (snapcast.Started)
|
||||
SnapcastText.Text = "Stop Snapcast";
|
||||
else
|
||||
SnapcastText.Text = "Start Snapcast";
|
||||
}
|
||||
|
||||
public void Pause_Clicked(object sender, RoutedEventArgs e) => mpd.PlayPause();
|
||||
public void Previous_Clicked(object sender, RoutedEventArgs e) => mpd.Prev();
|
||||
public void Next_Clicked(object sender, RoutedEventArgs e) => mpd.Next();
|
||||
|
||||
public void Random_Clicked(object sender, RoutedEventArgs e) => mpd.Random();
|
||||
public void Repeat_Clicked(object sender, RoutedEventArgs e) => mpd.Repeat();
|
||||
public void Single_Clicked(object sender, RoutedEventArgs e) => mpd.Single();
|
||||
public void Consume_Clicked(object sender, RoutedEventArgs e) => mpd.Consume();
|
||||
public void ChangeVolume(int value) => mpd.SetVolume(value);
|
||||
|
||||
public void Snapcast_Clicked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
SnapcastHandler snapcast = (SnapcastHandler)Application.Current.Properties["snapcast"];
|
||||
snapcast.LaunchOrExit();
|
||||
if (!snapcast.Started)
|
||||
snapcast.Start();
|
||||
else
|
||||
snapcast.Stop();
|
||||
}
|
||||
|
||||
public void Settings_Clicked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_settingsWin.Show();
|
||||
_settingsWin.Activate();
|
||||
SettingsWindow.Show();
|
||||
SettingsWindow.Activate();
|
||||
|
||||
if (_settingsWin.WindowState == WindowState.Minimized)
|
||||
_settingsWin.WindowState = WindowState.Normal;
|
||||
if (SettingsWindow.WindowState == WindowState.Minimized)
|
||||
SettingsWindow.WindowState = WindowState.Normal;
|
||||
}
|
||||
|
||||
private void Window_Closing(object sender, CancelEventArgs e)
|
||||
{
|
||||
e.Cancel = true;
|
||||
WindowState = WindowState.Minimized;
|
||||
Hide();
|
||||
}
|
||||
|
||||
private void TimeSlider_DragStarted(object sender, DragStartedEventArgs e)
|
||||
{
|
||||
_timer.Stop();
|
||||
timer.Stop();
|
||||
}
|
||||
|
||||
private void TimeSlider_DragCompleted(object sender, MouseButtonEventArgs e)
|
||||
@ -213,18 +176,18 @@ namespace unison
|
||||
Slider slider = (Slider)sender;
|
||||
|
||||
double SongPercentage = slider.Value;
|
||||
double SongTime = _mpd.GetCurrentSong().Time;
|
||||
double SongTime = mpd._totalTime;
|
||||
double SeekTime = SongPercentage / 100 * SongTime;
|
||||
|
||||
_mpd.SetTime(SeekTime);
|
||||
_timer.Start();
|
||||
mpd.SetTime(SeekTime);
|
||||
timer.Start();
|
||||
}
|
||||
|
||||
private void VolumeSlider_DragCompleted(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
Slider slider = (Slider)sender;
|
||||
_mpd.SetVolume((int)slider.Value);
|
||||
slider.ToolTip = (int)slider.Value;
|
||||
mpd.SetVolume((int)slider.Value);
|
||||
slider.ToolTip = mpd._currentVolume;
|
||||
}
|
||||
|
||||
protected override void OnSourceInitialized(EventArgs e)
|
||||
@ -240,11 +203,11 @@ namespace unison
|
||||
helper.EnsureHandle();
|
||||
}
|
||||
|
||||
private void Window_Closing(object sender, CancelEventArgs e)
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
protected virtual void OnPropertyChanged(string propertyName)
|
||||
{
|
||||
e.Cancel = true;
|
||||
WindowState = WindowState.Minimized;
|
||||
Hide();
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:emoji="clr-namespace:Emoji.Wpf;assembly=Emoji.Wpf"
|
||||
xmlns:local="clr-namespace:unison"
|
||||
mc:Ignorable="d"
|
||||
Closing="Window_Closing" Title="Settings" ResizeMode="CanMinimize" Icon="/images/icon-full.ico" WindowStyle="ToolWindow" SizeToContent="WidthAndHeight">
|
||||
<Grid>
|
||||
|
@ -13,8 +13,8 @@ namespace unison
|
||||
{
|
||||
public partial class Settings : Window
|
||||
{
|
||||
private readonly string defaultSnapcastPath = "snapclient_0.25.0-1_win64";
|
||||
private readonly string defaultSnapcastPort = "1704";
|
||||
private string defaultSnapcastPath = "snapclient_0.25.0-1_win64";
|
||||
private string defaultSnapcastPort = "1704";
|
||||
|
||||
public static string GetVersion => Assembly.GetEntryAssembly().GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion;
|
||||
|
||||
@ -71,7 +71,7 @@ namespace unison
|
||||
public void UpdateConnectionStatus()
|
||||
{
|
||||
MPDHandler mpd = (MPDHandler)Application.Current.Properties["mpd"];
|
||||
if (mpd.IsConnected())
|
||||
if (mpd._connected)
|
||||
ConnectionStatus.Text = "Connected to MPD " + mpd.GetVersion() + ".";
|
||||
else
|
||||
ConnectionStatus.Text = "Not connected.";
|
||||
|
@ -8,8 +8,6 @@ namespace unison
|
||||
{
|
||||
public class SystrayViewModel : INotifyPropertyChanged
|
||||
{
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
public static string GetAppText => "unison v" + Assembly.GetEntryAssembly().GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion;
|
||||
|
||||
public static ICommand ShowWindowCommand => new DelegateCommand
|
||||
@ -28,7 +26,10 @@ namespace unison
|
||||
|
||||
public static ICommand ExitApplicationCommand => new DelegateCommand
|
||||
{
|
||||
CommandAction = () => Application.Current.Shutdown(),
|
||||
CommandAction = () =>
|
||||
{
|
||||
Application.Current.Shutdown();
|
||||
},
|
||||
CanExecuteFunc = () => true
|
||||
};
|
||||
|
||||
@ -37,7 +38,7 @@ namespace unison
|
||||
get
|
||||
{
|
||||
SnapcastHandler snapcast = (SnapcastHandler)Application.Current.Properties["snapcast"];
|
||||
return snapcast.HasStarted ? "Stop Snapcast" : "Start Snapcast";
|
||||
return snapcast.Started ? "Stop Snapcast" : "Start Snapcast";
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,9 +51,7 @@ namespace unison
|
||||
CommandAction = () =>
|
||||
{
|
||||
Application.Current.Dispatcher.BeginInvoke(new Action(() => OnPropertyChanged("SnapcastText")));
|
||||
|
||||
SnapcastHandler snapcast = (SnapcastHandler)Application.Current.Properties["snapcast"];
|
||||
snapcast.LaunchOrExit();
|
||||
((MainWindow)Application.Current.MainWindow).Snapcast_Clicked(null, null);
|
||||
},
|
||||
CanExecuteFunc = () => true
|
||||
};
|
||||
@ -65,12 +64,17 @@ namespace unison
|
||||
{
|
||||
return new DelegateCommand
|
||||
{
|
||||
CommandAction = () => ((MainWindow)Application.Current.MainWindow).Settings_Clicked(null, null),
|
||||
CommandAction = () =>
|
||||
{
|
||||
((MainWindow)Application.Current.MainWindow).Settings_Clicked(null, null);
|
||||
},
|
||||
CanExecuteFunc = () => true
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
public virtual void OnPropertyChanged(string propertyName)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
|
Loading…
Reference in New Issue
Block a user