From a0b0ae67a2b41cbf94035076b53ee0071b7bc27e Mon Sep 17 00:00:00 2001 From: NicolasConstant Date: Mon, 9 Nov 2015 20:54:47 -0500 Subject: [PATCH] Creation of a windows app --- SpotifySleepModeStopper.sln | 7 + .../PowerRequestContextHandler.cs | 27 +--- .../Domain/SpotifySaveModeStopper.cs | 4 +- SpotifySleepModeStopperGui/App.config | 6 + SpotifySleepModeStopperGui/App.xaml | 9 ++ SpotifySleepModeStopperGui/App.xaml.cs | 17 +++ SpotifySleepModeStopperGui/IconChanger.cs | 34 +++++ SpotifySleepModeStopperGui/MainWindow.xaml | 12 ++ SpotifySleepModeStopperGui/MainWindow.xaml.cs | 94 +++++++++++++ .../Properties/AssemblyInfo.cs | 55 ++++++++ .../Properties/Resources.Designer.cs | 71 ++++++++++ .../Properties/Resources.resx | 117 ++++++++++++++++ .../Properties/Settings.Designer.cs | 30 +++++ .../Properties/Settings.settings | 7 + .../SpotifySleepModeStopperGui.csproj | 127 ++++++++++++++++++ SpotifySleepModeStopperGui/music.ico | Bin 0 -> 102314 bytes SpotifySleepModeStopperGui/music_big.ico | Bin 0 -> 67646 bytes SpotifySleepModeStopperGui/music_playing.ico | Bin 0 -> 1150 bytes 18 files changed, 590 insertions(+), 27 deletions(-) create mode 100644 SpotifySleepModeStopperGui/App.config create mode 100644 SpotifySleepModeStopperGui/App.xaml create mode 100644 SpotifySleepModeStopperGui/App.xaml.cs create mode 100644 SpotifySleepModeStopperGui/IconChanger.cs create mode 100644 SpotifySleepModeStopperGui/MainWindow.xaml create mode 100644 SpotifySleepModeStopperGui/MainWindow.xaml.cs create mode 100644 SpotifySleepModeStopperGui/Properties/AssemblyInfo.cs create mode 100644 SpotifySleepModeStopperGui/Properties/Resources.Designer.cs create mode 100644 SpotifySleepModeStopperGui/Properties/Resources.resx create mode 100644 SpotifySleepModeStopperGui/Properties/Settings.Designer.cs create mode 100644 SpotifySleepModeStopperGui/Properties/Settings.settings create mode 100644 SpotifySleepModeStopperGui/SpotifySleepModeStopperGui.csproj create mode 100644 SpotifySleepModeStopperGui/music.ico create mode 100644 SpotifySleepModeStopperGui/music_big.ico create mode 100644 SpotifySleepModeStopperGui/music_playing.ico diff --git a/SpotifySleepModeStopper.sln b/SpotifySleepModeStopper.sln index 44faaaf..2b27ce1 100644 --- a/SpotifySleepModeStopper.sln +++ b/SpotifySleepModeStopper.sln @@ -15,6 +15,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SpotifySleepModeStopperCons EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SpotifySleepModeStopperService", "WindowsService\SpotifySleepModeStopperService.csproj", "{23717C35-642B-41D5-882B-460083C1E376}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SpotifySleepModeStopperGui", "SpotifySleepModeStopperGui\SpotifySleepModeStopperGui.csproj", "{8C0977F4-070D-4B83-A825-EDDECD812C36}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -33,6 +35,10 @@ Global {23717C35-642B-41D5-882B-460083C1E376}.Debug|Any CPU.Build.0 = Debug|Any CPU {23717C35-642B-41D5-882B-460083C1E376}.Release|Any CPU.ActiveCfg = Release|Any CPU {23717C35-642B-41D5-882B-460083C1E376}.Release|Any CPU.Build.0 = Release|Any CPU + {8C0977F4-070D-4B83-A825-EDDECD812C36}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8C0977F4-070D-4B83-A825-EDDECD812C36}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8C0977F4-070D-4B83-A825-EDDECD812C36}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8C0977F4-070D-4B83-A825-EDDECD812C36}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -41,5 +47,6 @@ Global {0EFA9F55-FD0A-4B27-B953-4B6F5213A7B5} = {3D8B40CA-FF63-47A7-B987-16C32BABDA81} {ECEFE84A-5AB9-460C-9937-AA18C20674A2} = {EA773A42-7CE2-4520-936D-4B76A417252D} {23717C35-642B-41D5-882B-460083C1E376} = {A18AF2DC-D0FB-4CA4-AB24-07EA9826EF48} + {8C0977F4-070D-4B83-A825-EDDECD812C36} = {EA773A42-7CE2-4520-936D-4B76A417252D} EndGlobalSection EndGlobal diff --git a/SpotifySleepModeStopper/Domain/PowerManagement/PowerRequestContextHandler.cs b/SpotifySleepModeStopper/Domain/PowerManagement/PowerRequestContextHandler.cs index 694f5a9..ec02915 100644 --- a/SpotifySleepModeStopper/Domain/PowerManagement/PowerRequestContextHandler.cs +++ b/SpotifySleepModeStopper/Domain/PowerManagement/PowerRequestContextHandler.cs @@ -95,8 +95,8 @@ public void EnableConstantDisplayAndPower(bool enableConstantDisplayAndPower) _powerRequest = PowerCreateRequest(ref _powerRequestContext); // Set the request - var s = PowerSetRequest(_powerRequest, PowerRequestType.PowerRequestSystemRequired); - var s2 = PowerSetRequest(_powerRequest, PowerRequestType.PowerRequestDisplayRequired); + PowerSetRequest(_powerRequest, PowerRequestType.PowerRequestSystemRequired); + PowerSetRequest(_powerRequest, PowerRequestType.PowerRequestDisplayRequired); } else { @@ -107,28 +107,5 @@ public void EnableConstantDisplayAndPower(bool enableConstantDisplayAndPower) CloseHandle(_powerRequest); } } - - //[DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true, BestFitMapping = false, ThrowOnUnmappableChar = true)] - //internal static extern IntPtr GetProcAddress(IntPtr hModule, string procName); - - //[DllImport("kernel32.dll", CharSet = CharSet.Unicode)] - //internal static extern IntPtr LoadLibrary(string dllToLoad); - - //private static bool PowerAvailabilityRequestsSupported() - //{ - // var ptr = LoadLibrary("kernel32.dll"); - // var ptr2 = GetProcAddress(ptr, "PowerSetRequest"); - - // if (ptr2 == IntPtr.Zero) - // { - // // Power availability requests NOT suppoted. - // return false; - // } - // else - // { - // // Power availability requests ARE suppoted. - // return true; - // } - //} } } \ No newline at end of file diff --git a/SpotifySleepModeStopper/Domain/SpotifySaveModeStopper.cs b/SpotifySleepModeStopper/Domain/SpotifySaveModeStopper.cs index ad70110..229127b 100644 --- a/SpotifySleepModeStopper/Domain/SpotifySaveModeStopper.cs +++ b/SpotifySleepModeStopper/Domain/SpotifySaveModeStopper.cs @@ -94,8 +94,8 @@ private bool IsSpotifyRunning() private bool IsSoundStreaming() { - //var isSpotifyPlaying = _soundAnalyser.IsProcessNameOutputingSound(SpotifyProcessName); - var isSpotifyPlaying = _soundAnalyser.IsWindowsOutputingSound(); + var isSpotifyPlaying = _soundAnalyser.IsProcessNameOutputingSound(SpotifyProcessName); + //var isSpotifyPlaying = _soundAnalyser.IsWindowsOutputingSound(); return isSpotifyPlaying; } } diff --git a/SpotifySleepModeStopperGui/App.config b/SpotifySleepModeStopperGui/App.config new file mode 100644 index 0000000..d740e88 --- /dev/null +++ b/SpotifySleepModeStopperGui/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/SpotifySleepModeStopperGui/App.xaml b/SpotifySleepModeStopperGui/App.xaml new file mode 100644 index 0000000..3fdbec9 --- /dev/null +++ b/SpotifySleepModeStopperGui/App.xaml @@ -0,0 +1,9 @@ + + + + + diff --git a/SpotifySleepModeStopperGui/App.xaml.cs b/SpotifySleepModeStopperGui/App.xaml.cs new file mode 100644 index 0000000..f8c6f4b --- /dev/null +++ b/SpotifySleepModeStopperGui/App.xaml.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data; +using System.Linq; +using System.Threading.Tasks; +using System.Windows; + +namespace SpotifySleepModeStopperGui +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application + { + } +} diff --git a/SpotifySleepModeStopperGui/IconChanger.cs b/SpotifySleepModeStopperGui/IconChanger.cs new file mode 100644 index 0000000..7377098 --- /dev/null +++ b/SpotifySleepModeStopperGui/IconChanger.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Media; +using SpotifyTools.Contracts; + +namespace SpotifySleepModeStopperGui +{ + public class IconChanger : IMessageDisplayer + { + private readonly Action _notifyIsPlaying; + private readonly Action _notifyIsNotPlaying; + + public IconChanger(Action notifyIsPlaying, Action notifyIsNotPlaying) + { + _notifyIsPlaying = notifyIsPlaying; + _notifyIsNotPlaying = notifyIsNotPlaying; + } + + public void OutputMessage(string mess) + { + if (mess == "Spotify Playing: True") + { + _notifyIsPlaying(); + } + else + { + _notifyIsNotPlaying(); + } + } + } +} diff --git a/SpotifySleepModeStopperGui/MainWindow.xaml b/SpotifySleepModeStopperGui/MainWindow.xaml new file mode 100644 index 0000000..2d316f8 --- /dev/null +++ b/SpotifySleepModeStopperGui/MainWindow.xaml @@ -0,0 +1,12 @@ + + + + + diff --git a/SpotifySleepModeStopperGui/MainWindow.xaml.cs b/SpotifySleepModeStopperGui/MainWindow.xaml.cs new file mode 100644 index 0000000..2586a05 --- /dev/null +++ b/SpotifySleepModeStopperGui/MainWindow.xaml.cs @@ -0,0 +1,94 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Reflection; +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.Forms; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; +using SpotifyTools.Domain; +using SpotifyTools.Domain.AudioManagement; +using SpotifyTools.Domain.MessageManagement; +using SpotifyTools.Domain.PowerManagement; + +namespace SpotifySleepModeStopperGui +{ + /// + /// Interaction logic for MainWindow.xaml + /// + public partial class MainWindow : Window + { + private readonly NotifyIcon _notifyIcon; + private readonly Icon _notPlayingIcon; + private readonly Icon _playingIcon; + private readonly SpotifySaveModeStopper _analyser; + + public MainWindow() + { + InitializeComponent(); + + #region Init Tray Icon + WindowState = WindowState.Minimized; + Visibility = Visibility.Hidden; + ShowInTaskbar = false; + + _notifyIcon = new NotifyIcon(); + using ( + var stream = + Assembly.GetExecutingAssembly().GetManifestResourceStream("SpotifySleepModeStopperGui.music.ico")) + { + _notPlayingIcon = new Icon(stream); + } + using ( + var stream = + Assembly.GetExecutingAssembly() + .GetManifestResourceStream("SpotifySleepModeStopperGui.music_playing.ico")) + { + _playingIcon = new Icon(stream); + } + SetNotPlaying(); + _notifyIcon.Visible = true; + + var contextMenu = new System.Windows.Forms.ContextMenu(); + var menuItem = new System.Windows.Forms.MenuItem(); + + contextMenu.MenuItems.AddRange(new[] { menuItem }); + menuItem.Index = 0; + menuItem.Text = "Exit"; + menuItem.Click += exit_Click; + _notifyIcon.ContextMenu = contextMenu; + #endregion + + var iconChanger = new IconChanger(SetPlaying, SetNotPlaying); + _analyser = new SpotifySaveModeStopper(iconChanger, new PowerRequestContextHandler(), new CsCoreSoundAnalyser()); + _analyser.StartListening(); + } + + private void exit_Click(object sender, EventArgs e) + { + _analyser.StopListening(); + Environment.Exit(0); + } + + private void SetNotPlaying() + { + _notifyIcon.Icon = _notPlayingIcon; + _notifyIcon.Text = "Spotify isn't playing"; + } + + private void SetPlaying() + { + _notifyIcon.Icon = _playingIcon; + _notifyIcon.Text = "Spotify is playing"; + } + } +} diff --git a/SpotifySleepModeStopperGui/Properties/AssemblyInfo.cs b/SpotifySleepModeStopperGui/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..bde55a1 --- /dev/null +++ b/SpotifySleepModeStopperGui/Properties/AssemblyInfo.cs @@ -0,0 +1,55 @@ +using System.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Windows; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Spotify Sleep Mode Stopper")] +[assembly: AssemblyDescription("Prevent windows to sleep when spotify is playing")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Spotify Sleep Mode Stopper")] +[assembly: AssemblyCopyright("Copyright © 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +//In order to begin building localizable applications, set +//CultureYouAreCodingWith in your .csproj file +//inside a . For example, if you are using US english +//in your source files, set the to en-US. Then uncomment +//the NeutralResourceLanguage attribute below. Update the "en-US" in +//the line below to match the UICulture setting in the project file. + +//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] + + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] + + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/SpotifySleepModeStopperGui/Properties/Resources.Designer.cs b/SpotifySleepModeStopperGui/Properties/Resources.Designer.cs new file mode 100644 index 0000000..42e1591 --- /dev/null +++ b/SpotifySleepModeStopperGui/Properties/Resources.Designer.cs @@ -0,0 +1,71 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace SpotifySleepModeStopperGui.Properties +{ + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources + { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() + { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager + { + get + { + if ((resourceMan == null)) + { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SpotifySleepModeStopperGui.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture + { + get + { + return resourceCulture; + } + set + { + resourceCulture = value; + } + } + } +} diff --git a/SpotifySleepModeStopperGui/Properties/Resources.resx b/SpotifySleepModeStopperGui/Properties/Resources.resx new file mode 100644 index 0000000..ffecec8 --- /dev/null +++ b/SpotifySleepModeStopperGui/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/SpotifySleepModeStopperGui/Properties/Settings.Designer.cs b/SpotifySleepModeStopperGui/Properties/Settings.Designer.cs new file mode 100644 index 0000000..1dac4c4 --- /dev/null +++ b/SpotifySleepModeStopperGui/Properties/Settings.Designer.cs @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace SpotifySleepModeStopperGui.Properties +{ + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase + { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default + { + get + { + return defaultInstance; + } + } + } +} diff --git a/SpotifySleepModeStopperGui/Properties/Settings.settings b/SpotifySleepModeStopperGui/Properties/Settings.settings new file mode 100644 index 0000000..8f2fd95 --- /dev/null +++ b/SpotifySleepModeStopperGui/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/SpotifySleepModeStopperGui/SpotifySleepModeStopperGui.csproj b/SpotifySleepModeStopperGui/SpotifySleepModeStopperGui.csproj new file mode 100644 index 0000000..002350f --- /dev/null +++ b/SpotifySleepModeStopperGui/SpotifySleepModeStopperGui.csproj @@ -0,0 +1,127 @@ + + + + + Debug + AnyCPU + {8C0977F4-070D-4B83-A825-EDDECD812C36} + WinExe + Properties + SpotifySleepModeStopperGui + SpotifySleepModeStopper + v4.5.2 + 512 + {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 4 + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + music_big.ico + + + + + + + + + + + + + + 4.0 + + + + + + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + App.xaml + Code + + + + MainWindow.xaml + Code + + + + + Code + + + True + True + Resources.resx + + + True + Settings.settings + True + + + ResXFileCodeGenerator + Resources.Designer.cs + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + + + + + + + + + + + + {0efa9f55-fd0a-4b27-b953-4b6f5213a7b5} + SpotifySleepModeStopper + + + + + + + + \ No newline at end of file diff --git a/SpotifySleepModeStopperGui/music.ico b/SpotifySleepModeStopperGui/music.ico new file mode 100644 index 0000000000000000000000000000000000000000..8b83c999f07a1460910e8895ecbf1bf7b2a18950 GIT binary patch literal 102314 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

Eg`01^SrArZPx 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