diff --git a/YAPA/Const.cs b/YAPA/Const.cs new file mode 100644 index 0000000..e12009e --- /dev/null +++ b/YAPA/Const.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace YAPA +{ + public class Const + { + #region Font awesome glyph icons + + //public const string ICON_WINDOW_MINIMIZE = "\uf068"; //minus + //public const string ICON_WINDOW_CLOSE = "\uf00d"; //"times" x + //public const string ICON_SETTINGS = "\uf0ad"; // wrench + //public const string ICON_PLAY = "\uf04b"; //play + public const string ICON_PAUSE = "\uf04c"; //pause + //public const string ICON_STOP = "\uf04d"; //stop + public const string ICON_PERIOD_POMODORO = "\uf0e7"; // Lightning Bolt + public const string ICON_PERIOD_BREAK = "\uf08a"; // Heart Outlined + public const string ICON_PERIOD_BREAK_LONG = "\uf004"; //Heart + public const string ICON_PERIOD_STOPPED = ""; + + #endregion + } +} diff --git a/YAPA/DismissSettings.cs b/YAPA/DismissSettings.cs new file mode 100644 index 0000000..f99cc07 --- /dev/null +++ b/YAPA/DismissSettings.cs @@ -0,0 +1,45 @@ +using System; +using System.Windows.Input; + +namespace YAPA +{ + /// + /// Command used to support close & dismissing changes to the settings. + /// + class DismissSettings : ICommand + { + private ISettingsViewModel _host; + + /// + /// Creates a new instance of this command. + /// + /// The hosting Window control + public DismissSettings(ISettingsViewModel host) + { + _host = host; + } + + /// + /// Returns true if the command can execute; otherwise false. + /// + public bool CanExecute(object parameter) + { + return true; + } + + /// + /// Raised when the CanExecute value changes. + /// + public event EventHandler CanExecuteChanged; + + /// + /// Executes the command. + /// + public void Execute(object parameter) + { + Properties.Settings.Default.Reload(); + _host.IsDirty = false; + _host.CloseSettings(); + } + } +} \ No newline at end of file diff --git a/YAPA/Fonts/fontawesome-webfont.ttf b/YAPA/Fonts/fontawesome-webfont.ttf new file mode 100644 index 0000000..ed9372f Binary files /dev/null and b/YAPA/Fonts/fontawesome-webfont.ttf differ diff --git a/YAPA/ISettingsViewModel.cs b/YAPA/ISettingsViewModel.cs index 56c6ba9..7ec25cc 100644 --- a/YAPA/ISettingsViewModel.cs +++ b/YAPA/ISettingsViewModel.cs @@ -12,6 +12,11 @@ public interface ISettingsViewModel /// void CloseSettings(); + /// + /// Indicates if data is dirty + /// + bool IsDirty { get; set; } + /// /// The desired opacity of the /// diff --git a/YAPA/MainWindow.xaml b/YAPA/MainWindow.xaml index 4d69ec3..662bdf8 100644 --- a/YAPA/MainWindow.xaml +++ b/YAPA/MainWindow.xaml @@ -210,28 +210,54 @@ - - - - - + + + + + + + + + + + + + + diff --git a/YAPA/MainWindow.xaml.cs b/YAPA/MainWindow.xaml.cs index 3899ca1..8e6ede1 100644 --- a/YAPA/MainWindow.xaml.cs +++ b/YAPA/MainWindow.xaml.cs @@ -148,6 +148,8 @@ private void PauseMusic() private void MainWindow_StateChanged(object sender, EventArgs e) { + GetMainWindowPosAndSaveSettings(); + if (this.WindowState == WindowState.Minimized && MinimizeToTray == true && Properties.Settings.Default.ShowInTaskbar) { Hide(); @@ -175,14 +177,19 @@ void MainWindow_Closing(object sender, CancelEventArgs e) Properties.Settings.Default.IsFirstRun = false; } + GetMainWindowPosAndSaveSettings(); + + PauseMusic(); + } + + private void GetMainWindowPosAndSaveSettings() + { GDIScreen currentScreen = GDIScreen.FromHandle(new WindowInteropHelper(this).Handle); Properties.Settings.Default.CurrentScreenHeight = currentScreen.WorkingArea.Height; Properties.Settings.Default.CurrentScreenWidth = currentScreen.WorkingArea.Width; Properties.Settings.Default.Save(); - - PauseMusic(); } void MainWindow_Loaded(object sender, RoutedEventArgs e) @@ -199,9 +206,12 @@ void MainWindow_Loaded(object sender, RoutedEventArgs e) var screenChanged = (currentScreen.WorkingArea.Height != Properties.Settings.Default.CurrentScreenHeight || currentScreen.WorkingArea.Width != Properties.Settings.Default.CurrentScreenWidth); + var offScreen = (Properties.Settings.Default.WindowTop < 0 || Properties.Settings.Default.WindowTop > currentScreen.WorkingArea.Height || + Properties.Settings.Default.WindowLeft < 0 || Properties.Settings.Default.WindowLeft > currentScreen.WorkingArea.Width); + // default position only for first run or when screen size changes // position the clock at top / right, primary screen - if (Properties.Settings.Default.IsFirstRun || screenChanged) + if (Properties.Settings.Default.IsFirstRun || screenChanged || offScreen) { Left = SystemParameters.PrimaryScreenWidth - Width - 15.0; Top = 0; @@ -392,7 +402,6 @@ public Brush MouseOverBackgroundColor } } - public bool SoundEffects { get { return Properties.Settings.Default.SoundNotification; } @@ -618,7 +627,14 @@ private void Start_Click(object sender, RoutedEventArgs e) _stopWatch.Start(); _dispacherTime.Start(); if (_isWork) + { _period++; + CurrentPeriodIcon.Text = Const.ICON_PERIOD_POMODORO; + } + if(_isBreak) + CurrentPeriodIcon.Text = Const.ICON_PERIOD_BREAK; + if (_isBreakLong) + CurrentPeriodIcon.Text = Const.ICON_PERIOD_BREAK_LONG; } } @@ -635,12 +651,14 @@ private void Stop_Click(object sender, RoutedEventArgs e) _period--; _stopWatch.Stop(); ProgressState = "Paused"; + CurrentPeriodIcon.Text = Const.ICON_PAUSE; PauseMusic(); } else { ResetTicking(); PlayMusic(false); + CurrentPeriodIcon.Text = Const.ICON_PERIOD_STOPPED; } } @@ -755,6 +773,7 @@ private void RaisePropertyChanged(string propName) private void Window_MouseRightButtonUp(object sender, MouseButtonEventArgs e) { + GetMainWindowPosAndSaveSettings(); ShowSettings.Execute(this); } diff --git a/YAPA/SaveSettings.cs b/YAPA/SaveSettings.cs index 8792866..8123cce 100644 --- a/YAPA/SaveSettings.cs +++ b/YAPA/SaveSettings.cs @@ -38,6 +38,7 @@ public bool CanExecute(object parameter) public void Execute(object parameter) { Properties.Settings.Default.Save(); + _host.IsDirty = false; _host.CloseSettings(); } } diff --git a/YAPA/Settings.xaml b/YAPA/Settings.xaml index 75533c5..59fde9e 100644 --- a/YAPA/Settings.xaml +++ b/YAPA/Settings.xaml @@ -15,7 +15,8 @@ WindowStyle="None" WindowStartupLocation="CenterScreen" Background="Transparent" - AllowsTransparency="True"> + AllowsTransparency="True" + Closing="Settings_Closing"> @@ -25,10 +26,30 @@ - + + + + + + + diff --git a/YAPA/Settings.xaml.cs b/YAPA/Settings.xaml.cs index aed380b..144140e 100644 --- a/YAPA/Settings.xaml.cs +++ b/YAPA/Settings.xaml.cs @@ -21,6 +21,7 @@ public partial class Settings : Window, ISettingsViewModel, INotifyPropertyChang { private IMainViewModel _host; private ICommand _saveSettings; + private ICommand _dismissSettings; private double _clockOpacity; private double _shadowOpacity; private bool _useWhiteText; @@ -36,6 +37,7 @@ public partial class Settings : Window, ISettingsViewModel, INotifyPropertyChang private string _breakMusic; private bool _repeatBreakMusic; private bool _autoStartBreak; + private bool _isDirty; // INPC support public event PropertyChangedEventHandler PropertyChanged; @@ -52,6 +54,7 @@ public Settings(IMainViewModel host, double currentOpacity, Brush currentTextCol _soundEfects = soundEfects; _clockOpacity = currentOpacity; _saveSettings = new SaveSettings(this); + _dismissSettings = new DismissSettings(this); _useWhiteText = (currentTextColor.ToString() == Brushes.White.ToString()); _breakTime = breakTime; _breakLongTime = breakLongTime; @@ -66,6 +69,7 @@ public Settings(IMainViewModel host, double currentOpacity, Brush currentTextCol _repeatBreakMusic = repeatBreakMusic; _repeatWorkMusic = repeatWorkMusic; _autoStartBreak = autoStartBreak; + _isDirty = false; Loaded += Settings_Loaded; @@ -75,6 +79,8 @@ public Settings(IMainViewModel host, double currentOpacity, Brush currentTextCol private async void Settings_Loaded(object sender, RoutedEventArgs e) { + this.Activate(); + await Task.Run(() => { var dfi = DateTimeFormatInfo.CurrentInfo; @@ -115,6 +121,40 @@ await Task.Run(() => }); } + /// + /// Overrides Windows.Closing-Event + /// If windows is closed with Alt+F4 ask the user if he really want to dismiss the changes + /// The MsgBox is not shown, if the Settings window was Saved() or Dismissed() + /// + /// + /// + void Settings_Closing(object sender, CancelEventArgs e) + { + Debug.WriteLine("Closing called"); + + // If data is dirty, notify user and ask for a response + if (_isDirty) + { + string msg = "Settings changed. Close without saving?"; + MessageBoxResult result = + System.Windows.MessageBox.Show( + msg, + "YAPA Settings", + MessageBoxButton.YesNo, + MessageBoxImage.Warning); + if (result == MessageBoxResult.No) + { + // If user doesn't want to close, cancel closure + e.Cancel = true; + } + else + { + //restore settings and continue with closure + Properties.Settings.Default.Reload(); + } + } + } + private PomodoroLevelEnum GetLevelFromCount(int count, int maxCount) { if (count == 0) @@ -341,6 +381,27 @@ public ICommand SaveSettings get { return _saveSettings; } } + /// + /// Command invoked when user clicks 'Close' + /// + public ICommand DismissSettings + { + get { return _dismissSettings; } + } + + public bool IsDirty + { + get + { + return _isDirty; + } + + set + { + _isDirty = value; + } + } + /// /// Used to raise change notifications to other consumers. /// @@ -349,6 +410,7 @@ private void RaisePropertyChanged(string propName) if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propName)); + _isDirty = true; } } diff --git a/YAPA/YAPA.csproj b/YAPA/YAPA.csproj index c9b94e5..28bc740 100644 --- a/YAPA/YAPA.csproj +++ b/YAPA/YAPA.csproj @@ -75,7 +75,7 @@ false - + true @@ -127,7 +127,9 @@ MSBuild:Compile Designer + + @@ -179,6 +181,9 @@ ResXFileCodeGenerator Resources.Designer.cs + + PreserveNewest +