From b252711101c598005dc3b394b58977a66e7c67e8 Mon Sep 17 00:00:00 2001 From: Tim W Date: Sat, 24 Jun 2017 15:41:00 +0200 Subject: [PATCH 1/5] Added basic search features for song history --- LunaticPlayer.GRadioAPI/ApiClient.cs | 5 +- LunaticPlayer/LunaticPlayer.csproj | 3 + LunaticPlayer/Player/RadioPlayer.cs | 1 + LunaticPlayer/Player/SongHistoryManager.cs | 22 +++-- LunaticPlayer/PlayerInterface.xaml.cs | 66 ++++++++----- LunaticPlayer/Resources/help_black_92.png | Bin 0 -> 2044 bytes LunaticPlayer/SongHistoryWindow.xaml | 104 +++++++++++++++------ LunaticPlayer/SongHistoryWindow.xaml.cs | 28 ++++++ 8 files changed, 163 insertions(+), 66 deletions(-) create mode 100644 LunaticPlayer/Resources/help_black_92.png diff --git a/LunaticPlayer.GRadioAPI/ApiClient.cs b/LunaticPlayer.GRadioAPI/ApiClient.cs index 97f08d7..4b3db6a 100644 --- a/LunaticPlayer.GRadioAPI/ApiClient.cs +++ b/LunaticPlayer.GRadioAPI/ApiClient.cs @@ -15,8 +15,7 @@ public class ApiClient public StructuredApiData CurrentStructuredApiData { get; private set; } /// - /// Converts the raw API data into the song class. - /// + /// Converts the raw API data into the class. /// /// The song fetched from the API. public Song PlayingSong() @@ -162,8 +161,6 @@ public async Task CheckApiAccess() Console.WriteLine(e); return false; } - - return false; } } diff --git a/LunaticPlayer/LunaticPlayer.csproj b/LunaticPlayer/LunaticPlayer.csproj index 2407d9c..d4a92b8 100644 --- a/LunaticPlayer/LunaticPlayer.csproj +++ b/LunaticPlayer/LunaticPlayer.csproj @@ -187,6 +187,9 @@ + + + diff --git a/LunaticPlayer/Player/RadioPlayer.cs b/LunaticPlayer/Player/RadioPlayer.cs index 6e587d8..8d6e94f 100644 --- a/LunaticPlayer/Player/RadioPlayer.cs +++ b/LunaticPlayer/Player/RadioPlayer.cs @@ -26,6 +26,7 @@ public void PlayFromUrl(string url) public void Stop() { _player.Stop(); + _player.Close(); } //TODO: Lautstärke richtig einstellen diff --git a/LunaticPlayer/Player/SongHistoryManager.cs b/LunaticPlayer/Player/SongHistoryManager.cs index bd9692d..5c84078 100644 --- a/LunaticPlayer/Player/SongHistoryManager.cs +++ b/LunaticPlayer/Player/SongHistoryManager.cs @@ -50,8 +50,18 @@ private void InitializeHistory() } /// - /// Loads the song history from the JSON file. + /// Adds the last song to the database. + /// + private void StoreHistory(Song lastSong) + { + Database.AddSong(lastSong); + } + + /// + /// Loads the song history from the JSON file. + /// This should not be used in favor of storing history in the database. /// + [Obsolete] private void InitializeHistoryJson() { if (System.IO.File.Exists("songhist.json")) @@ -62,17 +72,11 @@ private void InitializeHistoryJson() } } - /// - /// Adds the last song to the database. - /// - private void StoreHistory(Song lastSong) - { - Database.AddSong(lastSong); - } - /// /// Stores the current state of the song history in the JSON file. + /// As with , this shouldn't be used in favor of the database. /// + [Obsolete] private void StoreHistoryJson() { var json = JsonConvert.SerializeObject(SongHistory); diff --git a/LunaticPlayer/PlayerInterface.xaml.cs b/LunaticPlayer/PlayerInterface.xaml.cs index c85f733..83cf09d 100644 --- a/LunaticPlayer/PlayerInterface.xaml.cs +++ b/LunaticPlayer/PlayerInterface.xaml.cs @@ -18,9 +18,9 @@ namespace LunaticPlayer /// public partial class MainWindow : Window { - private Player.RadioPlayer _radioPlayer; - private ApiClient _apiClient; - private Player.SongManager _songManager; + private readonly Player.RadioPlayer _radioPlayer; + private readonly ApiClient _apiClient; + private readonly Player.SongManager _songManager; private bool _isPlaying; @@ -76,8 +76,16 @@ private async void UpdateSong() if (_currentSong != previousSong) { - animationRun = false; - RunFadeInAnimation(); + if (previousSong == null) + { + animationRun = false; + RunFadeInAnimation(); + } + else if (previousSong.ApiSongId != _currentSong.ApiSongId) // prevents continuous fade in of same song + { + animationRun = false; + RunFadeInAnimation(); + } } if (_isPlaying) @@ -167,8 +175,7 @@ private void MuteRadioStream() } } - - // Events + #region Button Events private void Button_Click(object sender, RoutedEventArgs e) { @@ -190,17 +197,6 @@ private void MuteButton_Click(object sender, RoutedEventArgs e) MuteRadioStream(); } - private void SongListButton_OnClick(object sender, RoutedEventArgs e) - { - SongHistoryWindow sWindow = new SongHistoryWindow(_songManager.SongHistory); - sWindow.Show(); - } - - private void Window_Closed(object sender, EventArgs e) - { - Application.Current.Shutdown(); - } - private void SongInfoButton_Click(object sender, RoutedEventArgs e) { SongDetailsWindow sdWindow = new SongDetailsWindow(_currentSong); @@ -213,6 +209,25 @@ private void OptionsButton_OnClick(object sender, RoutedEventArgs e) sWindow.Show(); } + private void SongListButton_OnClick(object sender, RoutedEventArgs e) + { + SongHistoryWindow sWindow = new SongHistoryWindow(_songManager.SongHistory); + sWindow.Show(); + } + + #endregion + + /// + /// Stops the radio player and closes all open windows (since PlayerInterface is the main window). + /// + /// + /// + private void Window_Closed(object sender, EventArgs e) + { + _radioPlayer.Stop(); + Application.Current.Shutdown(); + } + private PopupBanner _messageBanner; /// @@ -224,15 +239,22 @@ private void OptionsButton_OnClick(object sender, RoutedEventArgs e) /// TODO: add ability to refresh player after connection failiure private async void Window_Loaded(object sender, RoutedEventArgs e) { - if (!await _apiClient.CheckApiAccess()) + var apiAccess = await _apiClient.CheckApiAccess(); + + if (!apiAccess) { - _messageBanner = new PopupBanner(new PopupBannerData + var bannerData = new PopupBannerData() { - Message = "Could not connect to GR", Closable = false, Level = PopupLevel.Error, CloseAction = ClosePopupBanner - }); + }; + + if (!apiAccess) + bannerData.Message = "Could not connect to the API"; + + _messageBanner = new PopupBanner(bannerData); + _messageBanner.Height = 40; _messageBanner.VerticalAlignment = VerticalAlignment.Top; _messageBanner.Effect = new DropShadowEffect() {BlurRadius = 20, Direction = -180}; diff --git a/LunaticPlayer/Resources/help_black_92.png b/LunaticPlayer/Resources/help_black_92.png new file mode 100644 index 0000000000000000000000000000000000000000..f37b335c0257f9a4b659154b16dcd69a81804797 GIT binary patch literal 2044 zcmX|CdpHwp8{g(U#~gZ{Vpj5^9cgUY*vKioLWUy7u-G9c=9E!M_V1+?CG=DCF-Fb_yO!R0={O0)ru*%rq)wI~)UxM>)AdT(EG|cC0Jfc^d?c zL}3s}ECS^WL!xj_Z&p(LpTmoq9-l^Iv1v>OM9CRPVP>%LP$)tvg7~ST zXb)hrkr3X=I|2q%=7JXf&@NgC52@eXVx~Rh&m=J^-^)-9m)Ijm%@(T;n_e>( zkC!huo=jIy`H??^o%wT~Gm)81U@;E8`L^md^VjN*`IU9j7Q+%RXqoR8Qs9tY#IUNH z`VF;k(DkK>{sMdHMwW>w?9mR5XB!vHrDm}fgWyz9je2;*o5L1&HTMAqfS!UEf_>99 z@VE~JdQv27lgZ_6FEg4Yb#w{eS!FeN)MJd;QsLbpoVI*MHjgT}DsWy=%RX2&M!2mC zPpNYT<{4YO_vg;P?2$N)fbas>#~OE|%wG}4)K3r@seohlgxWi_h*ir|XM_*nwbs1f zn$k_=CZn&rfNQ1M(4p~^f(+jDyHMV8ws{}drNGEOBkijCsNq81vld{tz|o_q_`7-@ zvvo|i6mLECvGMieG^y+7qg^UGfKLf~PmdiC0_hJ&Ti%!;d$vH|kEE+_e;P0wa4>PA53lERa*@^?tt;34_q>LGcWGdQB42W ziQnI+46kM5cK7&CnQdmx@C-XdOAtG5bq&VKr=x*h*fto`+ViTox?=g*Q;unE|AQv8 zwVFAq!0I(9+I}JDc733Bn2=3_Le*zydz9ng6m;%dO;K7%Nt< zH%JK7mfW5#DBe%s*y)33Hz#}NcWSt?`QWOPFR9X;YWR*fU84`(X{NDN9_jTVr_(^a z?PX4dpL6R7b+Q-yoil$0NU9eXS~qY6j$f>jH_7Jyo3Af{6;4~Sj6{sOj_Cc4v-HJ< z^xj&mf8Q=7PPHg=!GeO{@;(T3Y13ECX8wdeM}E(Wpl+Z~(UI}g-9iUiklpS6iyxmQ{8C?pRm3=QS8_&Ha}{Fg36L%mg?$!LUtBzSU-ZuXd^b+O<$kD-#)$^TD5b zoum5>w&qDCd( z>ytiu5xzk7-y2d{iaH1CiF#uFi|mUuaHPJ)*{f4u?x2#R%1*DTTUZV5 zx5AtR?ueeXk?dsD&JM8LFl*@Tc(-8HY`o%G>ZwX&R#Wsn??vTm0lm6R;mR^{Yj(!epG)kxpxcBaV9J|P z4i8KJZTaDf4gNb#YrI3lm5D?aPY^7v$86jskv*1UDH5(2rxFQA#Ay^yN?WCB8~Fsx&VUhm-iy+9L5TwQ7#tGUmOP4e zd@2fWx}!@Hm9~%i>fAZ2^QoK>zisl?QVy!*e$d&n(qYE;V{3XY7wu3YU-Tei=|AdU z9=+QEhFArkb6V8A20C7R%EZIXyA|-3Sf*xhnzY?Of3^FPZKi0R^!DJGnt^^Q;<((e zu<*FGARqa3_ex25KQ|(XlZ_oSZm4jY6?>9)@Ra10rTY@_8DL-w$ Mok3nLq}am$0nHeZJOBUy literal 0 HcmV?d00001 diff --git a/LunaticPlayer/SongHistoryWindow.xaml b/LunaticPlayer/SongHistoryWindow.xaml index be10c8f..e7c5dbf 100644 --- a/LunaticPlayer/SongHistoryWindow.xaml +++ b/LunaticPlayer/SongHistoryWindow.xaml @@ -5,37 +5,79 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:LunaticPlayer" mc:Ignorable="d" - Title="Song History" Height="300" Width="400"> + Title="Song History" Height="360" Width="450"> + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/LunaticPlayer/SongHistoryWindow.xaml.cs b/LunaticPlayer/SongHistoryWindow.xaml.cs index 379c21c..13b324b 100644 --- a/LunaticPlayer/SongHistoryWindow.xaml.cs +++ b/LunaticPlayer/SongHistoryWindow.xaml.cs @@ -1,5 +1,9 @@ using System; +using System.Collections.Generic; +using System.Linq; using System.Windows; +using System.Windows.Controls; +using System.Windows.Input; using LunaticPlayer.Classes; using LunaticPlayer.Player; using Newtonsoft.Json; @@ -13,10 +17,13 @@ public partial class SongHistoryWindow : Window { private readonly SongHistoryManager _songHistory; + private List _allSongs; + public SongHistoryWindow(SongHistoryManager shManager) { InitializeComponent(); _songHistory = shManager; + _allSongs = _songHistory.SongHistory; PopulateList(); } @@ -88,6 +95,27 @@ private void ShowDetails_OnClick(object sender, RoutedEventArgs e) { HandleClick(CMenuAction.ShowDetails); } + + private void SearchQueryBox_KeyDown(object sender, System.Windows.Input.KeyEventArgs e) + { + var liveSearch = true; + + if (e.Key == Key.Enter || liveSearch) + { + var box = sender as TextBox; + + if (!string.IsNullOrWhiteSpace(box.Text)) + { + var normalized = box.Text.ToLower(); + + SongList.ItemsSource = _allSongs.Where(s => s.Title.ToLower().Contains(normalized) || s.CircleArtist.ToLower().Contains(normalized)); + } + else + { + PopulateList(); + } + } + } } internal enum CMenuAction From 84c6770a59d3f241c3971f4d926693d0400f1bb3 Mon Sep 17 00:00:00 2001 From: Tim W Date: Sat, 24 Jun 2017 16:53:43 +0200 Subject: [PATCH 2/5] Added DialogWindow and help window. --- LunaticPlayer/LunaticPlayer.csproj | 10 +++++++ LunaticPlayer/Resources/help_white_92.png | Bin 0 -> 2393 bytes LunaticPlayer/SongHistoryWindow.xaml | 2 +- LunaticPlayer/SongHistoryWindow.xaml.cs | 13 +++++++++ LunaticPlayer/Windows/DialogWindow.xaml | 29 +++++++++++++++++++ LunaticPlayer/Windows/DialogWindow.xaml.cs | 32 +++++++++++++++++++++ 6 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 LunaticPlayer/Resources/help_white_92.png create mode 100644 LunaticPlayer/Windows/DialogWindow.xaml create mode 100644 LunaticPlayer/Windows/DialogWindow.xaml.cs diff --git a/LunaticPlayer/LunaticPlayer.csproj b/LunaticPlayer/LunaticPlayer.csproj index d4a92b8..5fe0baf 100644 --- a/LunaticPlayer/LunaticPlayer.csproj +++ b/LunaticPlayer/LunaticPlayer.csproj @@ -78,6 +78,9 @@ SongHistoryWindow.xaml + + DialogWindow.xaml + MSBuild:Compile Designer @@ -106,6 +109,10 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + @@ -190,6 +197,9 @@ + + + diff --git a/LunaticPlayer/Resources/help_white_92.png b/LunaticPlayer/Resources/help_white_92.png new file mode 100644 index 0000000000000000000000000000000000000000..dd0035145c5a3988fe6f3596583afe7067e9aa1f GIT binary patch literal 2393 zcmX|D2{aqn8jjl6T51m>s7{dx2@=9I*3i(}LOX^;wT(3+ArT=4qtw#ULG5Gg(^64X zADYzKD%z$CT~tb2I;Aqzm&QbSF>hwRbMErr`=9T--+%5o_ZA%U_f}OhPyzq|s#qV7 zK*{*sUQ>{h^vfH(FaSWxj}#n64Z|HpMJFXd2&a;WF%WtJS+WlRxVX{Dgy^^!Du@_! zhLnf~Zwzw4Akrx`7>~f&;>hkXXGuPcZot3N;Q5KC&kW3d0=(xhEyZfDjM|n`oH56UY$>fgzAic5rKu zoh{4(YKw%z;5N1}lr0iv3j_TPu&WZtCHd58RG^2~-(r#o4L(byl2K47jYfme>>)|X zXP_`75(%}ngWB2INHT0FX^B(<-6oM@wny=Q4v!d0bTWxdB_$<-_BaW|q!cO|42JHB zK>t>e*n|G-PZIoFp_oKTS&}9GLD()703d%C>v1HQUb|iwQDhvVKgk;GYq5Z6{<07; z?o}Y=o^LM9b_jK-fOnk#;Hd!>*^}-i)m<8&6lb)*PV@_&3YtdR{t#N zA2dQw|NJ=ESjU}P&V9>O;+HLLV)+LI#sUZ1hvjQJ59a2=p9a7$pF8KuM@6B#bq0(F z?7#(bWOceeU6HQ3T4mp+J1c16;&fZQy`*SeaQ?PBK}sfg?E1y zddY57_AZvbENWIQ*vAZQv{~19y+(H~j1D3uk|$nV^Vvk4<9|VxRfjyU8us7?)c!;x zwhGwhraSG-%1SY6tNoH3E|v z>d4iXO^DTf`JblR&=ZSy3e_5CeV(^?X5Jby;NFtLc8wR+mG-vgau7W)HuhV- zL0S*GWjxy6f&E$ce33ZcV6HOo%{@m|F*FPBCra;gYW1BSck*wC<+YUJ{wV%07Im6A zXs9(?Z92L#SXN;vihziDJ*%pP>;yQ|IOt)9;V309(wixI1{+cD>0v(XcEjmeg;hKn zXNM4>6Hbj!{Z+Jj&o5~(hY76eUN*2&U&t~SeKw98|Go&h2IcXl5RBAL0&DhlG)zq+ z&y2d%;=xhR3mg-aOhnwFaQB-D`?yI&HJ9wjr1{;C0=C|+bw7|f(aot`o%`(xZz=_Q z^B^(Z(CNM4A>2?^TvL!4pc(toZa6h%J)KAF~J{zSNO zLK^o+3}1UKRWQsIYe$D8yb;%BIAh%b`oe<)%JTu2M>M0I3H1RXSF4+<)5L*{(w5wt zsKFl#i!w~WM=9@7q0UTRH{M8GH#N>RQMmrfx_=+%Dy%<*5^V1$2+I2!I9i`$kz4QV zw}u=Eu3W8)+!s1?e8&2Ar*lt89$Nk+doV0O`i2y1N`3LKlsAu= zv+p}ZMNR-iH942y8$;-96Zo1T(Dirz>7^~>g9`OpS3>=)D)~@D;WZ@l@oj_A9l(|@ zq&v2+H(4Tws#)UHgZ@WoO!Lc~Y zlD&J7wq!QKFr#@3Z)(w>zP_RqAO)p%hpb=xL~bLn+eO)s0)QsP0 zj%DHrC{}i5wcb$nbU5S`TZt)-eGU<(L&9~%36Q$xxl%g - + + + + + + + + + + diff --git a/LunaticPlayer/Windows/DialogWindow.xaml.cs b/LunaticPlayer/Windows/DialogWindow.xaml.cs new file mode 100644 index 0000000..479d593 --- /dev/null +++ b/LunaticPlayer/Windows/DialogWindow.xaml.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Shapes; + +namespace LunaticPlayer.Windows +{ + /// + /// Interaktionslogik für DialogWindow.xaml + /// + public partial class DialogWindow : Window + { + public DialogWindow() + { + InitializeComponent(); + } + + private void OkButton_OnClick(object sender, RoutedEventArgs e) + { + this.Close(); + } + } +} From 7ba18038e3085acd558257512c24218aa58ad861 Mon Sep 17 00:00:00 2001 From: Tim W Date: Sat, 24 Jun 2017 16:56:51 +0200 Subject: [PATCH 3/5] Center dialog window over parent --- LunaticPlayer/SongHistoryWindow.xaml.cs | 1 + LunaticPlayer/Windows/DialogWindow.xaml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/LunaticPlayer/SongHistoryWindow.xaml.cs b/LunaticPlayer/SongHistoryWindow.xaml.cs index 84ef0ae..a09d7ec 100644 --- a/LunaticPlayer/SongHistoryWindow.xaml.cs +++ b/LunaticPlayer/SongHistoryWindow.xaml.cs @@ -126,6 +126,7 @@ private void HelpButton_OnClick(object sender, RoutedEventArgs e) dialogWindow.ContentText.Text = "Start typing to see search results. When the search field is empty, press enter to return to the full list."; dialogWindow.Title = "Search Help"; dialogWindow.HeaderImage.Source = new BitmapImage(new Uri(@"/LunaticPlayer;component/Resources/help_white_92.png", UriKind.Relative)); + dialogWindow.Owner = this; dialogWindow.ShowDialog(); } diff --git a/LunaticPlayer/Windows/DialogWindow.xaml b/LunaticPlayer/Windows/DialogWindow.xaml index f5139b4..50b052b 100644 --- a/LunaticPlayer/Windows/DialogWindow.xaml +++ b/LunaticPlayer/Windows/DialogWindow.xaml @@ -5,7 +5,7 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:LunaticPlayer.Windows" mc:Ignorable="d" - Title="Dialog Window" Height="250" Width="350"> + Title="Dialog Window" Height="250" Width="350" WindowStartupLocation="CenterOwner"> From 0a9cc976ced451374dd85e828ff42f00c0c8a831 Mon Sep 17 00:00:00 2001 From: Tim W Date: Sat, 24 Jun 2017 16:59:00 +0200 Subject: [PATCH 4/5] Only show scrollbar when needed --- LunaticPlayer/Windows/DialogWindow.xaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LunaticPlayer/Windows/DialogWindow.xaml b/LunaticPlayer/Windows/DialogWindow.xaml index 50b052b..fa59bcb 100644 --- a/LunaticPlayer/Windows/DialogWindow.xaml +++ b/LunaticPlayer/Windows/DialogWindow.xaml @@ -19,7 +19,7 @@ - + From 1e0f0e769676cc14e158436fa25e90e65b546d32 Mon Sep 17 00:00:00 2001 From: Tim W Date: Sat, 24 Jun 2017 20:42:33 +0200 Subject: [PATCH 5/5] Added volume bar, configuration and small fixes --- LunaticPlayer/Client/Configuration.cs | 84 ++++++++++++++++++ LunaticPlayer/Controls/VolumeBar.xaml | 14 +++ LunaticPlayer/Controls/VolumeBar.xaml.cs | 45 ++++++++++ LunaticPlayer/LunaticPlayer.csproj | 15 +++- LunaticPlayer/Player/RadioPlayer.cs | 16 +++- LunaticPlayer/PlayerInterface.xaml | 22 +++-- LunaticPlayer/PlayerInterface.xaml.cs | 48 +++++++++- LunaticPlayer/Resources/mute_92.png | Bin 4055 -> 1058 bytes LunaticPlayer/Resources/voloff_92.png | Bin 0 -> 4055 bytes .../{unmute_92.png => volume_92.png} | Bin LunaticPlayer/SongHistoryWindow.xaml | 4 +- LunaticPlayer/SongHistoryWindow.xaml.cs | 7 +- 12 files changed, 239 insertions(+), 16 deletions(-) create mode 100644 LunaticPlayer/Client/Configuration.cs create mode 100644 LunaticPlayer/Controls/VolumeBar.xaml create mode 100644 LunaticPlayer/Controls/VolumeBar.xaml.cs create mode 100644 LunaticPlayer/Resources/voloff_92.png rename LunaticPlayer/Resources/{unmute_92.png => volume_92.png} (100%) diff --git a/LunaticPlayer/Client/Configuration.cs b/LunaticPlayer/Client/Configuration.cs new file mode 100644 index 0000000..56044c7 --- /dev/null +++ b/LunaticPlayer/Client/Configuration.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Newtonsoft.Json; + +namespace LunaticPlayer.Client +{ + class ConfigurationData + { + public double Volume { get; set; } + } + + class Configuration + { + private const string Filename = "config.json"; + + private static Configuration _instance; + + public ConfigurationData Data { get; set; } + + /// + /// The source of configuration data (Filesystem, Default Object, ...). + /// + public string Source { get; set; } + + public static Configuration GetInstance() + { + if (_instance == null) + { + _instance = new Configuration(); + _instance.Initialize(); + } + + return _instance; + } + + /// + /// Loads the configuration and stores it to the filesystem if necessary. + /// + private void Initialize() + { + + if (File.Exists(Filename)) + { + Data = JsonConvert.DeserializeObject(File.ReadAllText(Filename)); + Source = "Filesystem"; + } + else + { + Source = "DefaultDataObject"; + + SetupData(); + + // Erstellt eine Konfigurationsdatei für das nächste Mal. + Save(); + } + } + + /// + /// Creates a object with default values. + /// + private void SetupData() + { + var data = new ConfigurationData() + { + Volume = 0.4 + }; + + Data = data; + } + + /// + /// Saves the current configuration to the file specified at . + /// + public void Save() + { + Console.WriteLine("Saving configuration to filesystem."); + File.WriteAllText(Filename, JsonConvert.SerializeObject(Data)); + } + } +} diff --git a/LunaticPlayer/Controls/VolumeBar.xaml b/LunaticPlayer/Controls/VolumeBar.xaml new file mode 100644 index 0000000..1deceb8 --- /dev/null +++ b/LunaticPlayer/Controls/VolumeBar.xaml @@ -0,0 +1,14 @@ + + + + + + + diff --git a/LunaticPlayer/Controls/VolumeBar.xaml.cs b/LunaticPlayer/Controls/VolumeBar.xaml.cs new file mode 100644 index 0000000..4d1ccbe --- /dev/null +++ b/LunaticPlayer/Controls/VolumeBar.xaml.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace LunaticPlayer.Controls +{ + public class VolumeBarData + { + public double Volume { get; set; } + } + + /// + /// Interaktionslogik für VolumeBar.xaml + /// + public partial class VolumeBar : UserControl + { + public VolumeBarData Data { get; set; } + public Action OnValueChange { get; set; } + + public VolumeBar(VolumeBarData data) + { + InitializeComponent(); + + DataContext = Data = data; + } + + private void VolumeSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs e) + { + Data.Volume = VolumeSlider.Value; + + OnValueChange?.Invoke(); + } + } +} diff --git a/LunaticPlayer/LunaticPlayer.csproj b/LunaticPlayer/LunaticPlayer.csproj index 5fe0baf..2041010 100644 --- a/LunaticPlayer/LunaticPlayer.csproj +++ b/LunaticPlayer/LunaticPlayer.csproj @@ -66,6 +66,10 @@ MSBuild:Compile Designer + + + VolumeBar.xaml + PopupBanner.xaml @@ -81,6 +85,10 @@ DialogWindow.xaml + + Designer + MSBuild:Compile + MSBuild:Compile Designer @@ -163,8 +171,8 @@ - - + + @@ -200,6 +208,9 @@ + + + diff --git a/LunaticPlayer/Player/RadioPlayer.cs b/LunaticPlayer/Player/RadioPlayer.cs index 8d6e94f..675d4e3 100644 --- a/LunaticPlayer/Player/RadioPlayer.cs +++ b/LunaticPlayer/Player/RadioPlayer.cs @@ -7,7 +7,7 @@ class RadioPlayer { private readonly MediaPlayer _player; - public bool Muted => _player.Volume == 0.0; + public bool Muted { get; set; } public double Volume => _player.Volume; @@ -39,5 +39,19 @@ public void ToggleMute() { _player.Volume = _player.Volume == 0.0 ? 0.5 : 0.0; } + + public void ToggleMute(double volume) + { + if (Muted) + { + _player.Volume = volume; + Muted = false; + } + else + { + _player.Volume = 0.0; + Muted = true; + } + } } } diff --git a/LunaticPlayer/PlayerInterface.xaml b/LunaticPlayer/PlayerInterface.xaml index b1c64fe..f569519 100644 --- a/LunaticPlayer/PlayerInterface.xaml +++ b/LunaticPlayer/PlayerInterface.xaml @@ -4,6 +4,7 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:LunaticPlayer" + xmlns:controls="clr-namespace:LunaticPlayer.Controls" mc:Ignorable="d" Title="Lunatic Player" Height="245" Width="375" Closed="Window_Closed" Loaded="Window_Loaded"> @@ -79,20 +80,27 @@ - + - - + + + + + - + - - + + private void MuteRadioStream() { - _radioPlayer.ToggleMute(); + _radioPlayer.ToggleMute(Configuration.GetInstance().Data.Volume); if (_radioPlayer.Muted) { @@ -161,7 +165,7 @@ private void MuteRadioStream() var packUri = "pack://application:,,,/LunaticPlayer;component/Resources/unmute_mat.ico"; TBMuteButton.ImageSource = new ImageSourceConverter().ConvertFromString(packUri) as ImageSource; - var appUri = new Uri("pack://application:,,,/LunaticPlayer;component/Resources/unmute_92.png"); + var appUri = new Uri("pack://application:,,,/LunaticPlayer;component/Resources/mute_92.png"); MuteButton.Background = new ImageBrush(new BitmapImage(appUri)); } else @@ -170,11 +174,13 @@ private void MuteRadioStream() var packUri = "pack://application:,,,/LunaticPlayer;component/Resources/mute_92.png"; TBMuteButton.ImageSource = new ImageSourceConverter().ConvertFromString(packUri) as ImageSource; - var appUri = new Uri("pack://application:,,,/LunaticPlayer;component/Resources/mute_92.png"); + var appUri = new Uri("pack://application:,,,/LunaticPlayer;component/Resources/voloff_92.png"); MuteButton.Background = new ImageBrush(new BitmapImage(appUri)); } } + private VolumeBar volumeBar; + #region Button Events private void Button_Click(object sender, RoutedEventArgs e) @@ -215,6 +221,35 @@ private void SongListButton_OnClick(object sender, RoutedEventArgs e) sWindow.Show(); } + private void VolumeButton_OnClick(object sender, RoutedEventArgs e) + { + if (volumeBar == null) + { + var vol = Configuration.GetInstance().Data.Volume; + volumeBar = new VolumeBar(new VolumeBarData() { Volume = vol }); + volumeBar.Height = 50; + volumeBar.Width = 100; + volumeBar.OnValueChange = OnVolumeChange; + } + + if (this.ButtonToolbar.Children.Contains(volumeBar)) + { + if (volumeBar.Visibility == Visibility.Visible) + { + volumeBar.Visibility = Visibility.Collapsed; + } + else + { + volumeBar.Visibility = Visibility.Visible; + } + + } + else + { + this.ButtonToolbar.Children.Insert(1, volumeBar); + } + } + #endregion /// @@ -224,6 +259,7 @@ private void SongListButton_OnClick(object sender, RoutedEventArgs e) /// private void Window_Closed(object sender, EventArgs e) { + Configuration.GetInstance().Save(); _radioPlayer.Stop(); Application.Current.Shutdown(); } @@ -297,5 +333,11 @@ private void RunFadeInAnimation() Storyboard.SetTarget(sb, this.PlayerContent); sb.Begin(); } + + private void OnVolumeChange() + { + _radioPlayer.SetVolume(volumeBar.Data.Volume); + Configuration.GetInstance().Data.Volume = Math.Round(volumeBar.Data.Volume, 2); + } } } diff --git a/LunaticPlayer/Resources/mute_92.png b/LunaticPlayer/Resources/mute_92.png index 2fd3f7a886f31337187f64ad3016e73cff98377c..f29af8c116a9af43511840ab6c597d0a62e2c1a5 100644 GIT binary patch delta 693 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 diff --git a/LunaticPlayer/Resources/voloff_92.png b/LunaticPlayer/Resources/voloff_92.png new file mode 100644 index 0000000000000000000000000000000000000000..2fd3f7a886f31337187f64ad3016e73cff98377c GIT binary patch literal 4055 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 -