Skip to content

Commit

Permalink
Implement minimize to tray
Browse files Browse the repository at this point in the history
Closes #2
  • Loading branch information
timokoessler committed Mar 24, 2024
1 parent 720a2e7 commit e3c3bcf
Show file tree
Hide file tree
Showing 9 changed files with 169 additions and 15 deletions.
Binary file added Guard/Assets/logo-tray.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions Guard/Core/Models/AppSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,6 @@ internal class AppSettings
public bool LockOnScreenLock { get; set; } = true;
public SortOrderSetting SortOrder { get; set; } = SortOrderSetting.ISSUER_ASC;
public bool ShowTokenCardIntro { get; set; } = true;
public bool MinimizeToTray { get; set; } = false;
}
}
3 changes: 3 additions & 0 deletions Guard/Guard.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
<None Remove="Assets\key.svg" />
<None Remove="Assets\logo-256.png" />
<None Remove="Assets\logo-512.png" />
<None Remove="Assets\logo-tray.png" />
<None Remove="Assets\logo.svg" />
<None Remove="Assets\padlock-gradient.svg" />
<None Remove="Assets\twofas.svg" />
Expand All @@ -70,6 +71,7 @@
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="SharpVectors.Wpf" Version="1.8.4" />
<PackageReference Include="WPF-UI" Version="3.0.2" />
<PackageReference Include="WPF-UI.Tray" Version="3.0.2" />
<PackageReference Include="ZXing.Net" Version="0.16.9" />
<PackageReference Include="ZXing.Net.Bindings.Windows.Compatibility" Version="0.16.12" />
</ItemGroup>
Expand All @@ -83,6 +85,7 @@
<Resource Include="Assets\key.svg" />
<Resource Include="Assets\logo-256.png" />
<Resource Include="Assets\logo-512.png" />
<Resource Include="Assets\logo-tray.png" />
<Resource Include="Assets\logo.svg" />
<Resource Include="Assets\padlock-gradient.svg" />
<Resource Include="Assets\twofas.svg" />
Expand Down
2 changes: 1 addition & 1 deletion Guard/MainWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
WindowCornerPreference="Round"
WindowStartupLocation="CenterScreen"
mc:Ignorable="d">
<Grid>
<Grid x:Name="RootGrid">
<ui:TitleBar Title="2FAGuard" Grid.Row="0">
<ui:TitleBar.Icon>
<ui:ImageIcon Source="pack://application:,,,/Assets/logo-256.png" />
Expand Down
119 changes: 111 additions & 8 deletions Guard/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
using Guard.Core;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Web;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interop;
using System.Windows.Media.Imaging;
using Guard.Core;
using Guard.Core.Aptabase;
using Guard.Core.Icons;
using Guard.Core.Installation;
using Guard.Core.Models;
using Guard.Core.Security;
using Guard.Core.Storage;
using Guard.Views.Pages.Start;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Web;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interop;
using Wpf.Ui;
using Wpf.Ui.Appearance;
using Wpf.Ui.Controls;
using Wpf.Ui.Input;
using Wpf.Ui.Tray.Controls;

namespace Guard
{
Expand All @@ -26,7 +30,7 @@ public partial class MainWindow : FluentWindow
private readonly ContentDialogService ContentDialogService;
private AptabaseClient? StatsClient;
private IntPtr windowInteropHandle;
private bool isAutostart;
private readonly bool isAutostart;

public MainWindow(bool autostart)
{
Expand Down Expand Up @@ -81,7 +85,13 @@ private void OnWindowLoaded()
StatsClient.TrackEvent("AppOpened");
FullContentFrame.Content = new Login(!isAutostart);
}

CheckLocalTime();

if (SettingsManager.Settings.MinimizeToTray)
{
AddTrayIcon();
}
}

internal void ApplyTheme(ThemeSetting theme)
Expand Down Expand Up @@ -275,5 +285,98 @@ private static async void CheckLocalTime()
_ = await uiMessageBox.ShowDialogAsync();
}
}

internal void AddTrayIcon()
{
BitmapImage trayIconImage = new();
trayIconImage.BeginInit();
trayIconImage.UriSource = new("pack://application:,,,/Assets/logo-tray.png");
trayIconImage.EndInit();

NotifyIcon trayIcon =
new()
{
FocusOnLeftClick = false,
Icon = trayIconImage,
ToolTip = "2FAGuard",
MenuOnRightClick = true,
Menu = new ContextMenu
{
Items =
{
new Wpf.Ui.Controls.MenuItem
{
Header = I18n.GetString("i.tray.exit"),
Command = new RelayCommand<object>(Tray_Exit_Click)
}
}
}
};
trayIcon.LeftClick += Tray_Open_Click;

Check warning on line 315 in Guard/MainWindow.xaml.cs

View workflow job for this annotation

GitHub Actions / Analyze (csharp)

Nullability of reference types in type of parameter 'sender' of 'void MainWindow.Tray_Open_Click(NotifyIcon sender, RoutedEventArgs e)' doesn't match the target delegate 'RoutedNotifyIconEvent' (possibly because of nullability attributes).

Check warning on line 315 in Guard/MainWindow.xaml.cs

View workflow job for this annotation

GitHub Actions / Analyze (csharp)

Nullability of reference types in type of parameter 'sender' of 'void MainWindow.Tray_Open_Click(NotifyIcon sender, RoutedEventArgs e)' doesn't match the target delegate 'RoutedNotifyIconEvent' (possibly because of nullability attributes).

Check warning on line 315 in Guard/MainWindow.xaml.cs

View workflow job for this annotation

GitHub Actions / Analyze (csharp)

Nullability of reference types in type of parameter 'sender' of 'void MainWindow.Tray_Open_Click(NotifyIcon sender, RoutedEventArgs e)' doesn't match the target delegate 'RoutedNotifyIconEvent' (possibly because of nullability attributes).

Check warning on line 315 in Guard/MainWindow.xaml.cs

View workflow job for this annotation

GitHub Actions / Analyze (csharp)

Nullability of reference types in type of parameter 'sender' of 'void MainWindow.Tray_Open_Click(NotifyIcon sender, RoutedEventArgs e)' doesn't match the target delegate 'RoutedNotifyIconEvent' (possibly because of nullability attributes).
if (Auth.IsLoginEnabled())
{
trayIcon.Menu.Items.Insert(
0,
new Wpf.Ui.Controls.MenuItem
{
Header = I18n.GetString("i.tray.lock"),
Command = new RelayCommand<object>(Tray_Lock_Click)
}
);
}
RootGrid.Children.Add(trayIcon);
}

internal void RemoveTrayIcon()
{
NotifyIcon? trayIcon = RootGrid.Children.OfType<NotifyIcon>().FirstOrDefault();
if (trayIcon != null)
{
RootGrid.Children.Remove(trayIcon);
trayIcon.Unregister();
trayIcon.Dispose();
}
}

private void Tray_Exit_Click(object? sender)
{
Application.Current.Shutdown();
}

private void Tray_Lock_Click(object? sender)
{
RemoveTrayIcon();
Logout();
}

private void Tray_Open_Click(NotifyIcon sender, RoutedEventArgs e)
{
Show();
WindowState = WindowState.Normal;
}

protected override void OnStateChanged(EventArgs e)
{
if (SettingsManager.Settings.MinimizeToTray)
{
if (WindowState == WindowState.Minimized)
{
Hide();
}
}

base.OnStateChanged(e);
}

protected override void OnClosing(CancelEventArgs e)
{
if (SettingsManager.Settings.MinimizeToTray)
{
e.Cancel = true;
WindowState = WindowState.Minimized;
Hide();
}
base.OnClosing(e);
}
}
}
6 changes: 6 additions & 0 deletions Guard/Resources/Strings.de.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@
<system:String x:Key="i.settings.autostart.error.disabled.user">Der automatische Start der App wurde im Windows Task-Manager deaktiviert und kann nur dort geändert werden</system:String>
<system:String x:Key="i.settings.autostart.error.alreadyenabled">Der automatische Start der App ist bereits aktiviert</system:String>
<system:String x:Key="i.settings.autostart.error.notenabled">Der automatische Start der App kann nicht deaktiviert werden, da er bereits deaktiviert ist</system:String>
<system:String x:Key="i.settings.tray">In den Infobereich minimieren</system:String>
<system:String x:Key="i.settings.tray.description">App wird in den Infobereich minimiert und nicht geschlossen</system:String>
<system:String x:Key="i.settings.imprint">Impressum</system:String>
<system:String x:Key="i.settings.privacy">Datenschutz</system:String>
<system:String x:Key="i.settings.reset">App zurücksetzen</system:String>
Expand Down Expand Up @@ -223,6 +225,10 @@
<system:String x:Key="i.update.error.title">Update fehlgeschlagen</system:String>
<system:String x:Key="i.update.error.content">Beim Aktualisieren ist ein Fehler aufgetreten</system:String>

<!-- Tray -->
<system:String x:Key="i.tray.exit">Beenden</system:String>
<system:String x:Key="i.tray.lock">Sperren</system:String>

<!-- Other -->
<system:String x:Key="i.win.hello.request">Die Anwendung 2FAGuard möchte deine Identität bestätigen.</system:String>
<system:String x:Key="i.error">Fehler</system:String>
Expand Down
6 changes: 6 additions & 0 deletions Guard/Resources/Strings.en.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@
<system:String x:Key="i.settings.autostart.error.disabled.user">The automatic start of the app has been deactivated in the Windows Task Manager and can only be changed there</system:String>
<system:String x:Key="i.settings.autostart.error.alreadyenabled">The automatic start of the app is already activated</system:String>
<system:String x:Key="i.settings.autostart.error.notenabled">The automatic start of the app cannot be deactivated as it is already deactivated</system:String>
<system:String x:Key="i.settings.tray">Minimize and close to tray</system:String>
<system:String x:Key="i.settings.tray.description">Move the app to the system tray when minimizing and closing</system:String>
<system:String x:Key="i.settings.imprint">Imprint</system:String>
<system:String x:Key="i.settings.privacy">Privacy</system:String>
<system:String x:Key="i.settings.reset">Reset app</system:String>
Expand Down Expand Up @@ -223,6 +225,10 @@
<system:String x:Key="i.update.error.title">Update failed</system:String>
<system:String x:Key="i.update.error.content">An error occurred while updating</system:String>

<!-- Tray -->
<system:String x:Key="i.tray.exit">Exit</system:String>
<system:String x:Key="i.tray.lock">Lock</system:String>

<!-- Other -->
<system:String x:Key="i.win.hello.request">The application 2FAGuard wants to prove your identity</system:String>
<system:String x:Key="i.error">Error</system:String>
Expand Down
22 changes: 22 additions & 0 deletions Guard/Views/Pages/Settings.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,28 @@
</ui:CardControl.Header>
<ui:ToggleSwitch x:Name="AutoStartSwitch" Grid.Column="1" />
</ui:CardControl>
<ui:CardControl
Grid.Column="1"
Margin="15,0,0,15"
Icon="{ui:SymbolIcon ShareCloseTray24}">
<ui:CardControl.Header>
<Grid Margin="0,0,35,0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ui:TextBlock
Grid.Row="0"
FontTypography="Body"
Text="{DynamicResource i.settings.tray}" />
<ui:TextBlock
Grid.Row="1"
Foreground="{DynamicResource TextFillColorSecondaryBrush}"
Text="{DynamicResource i.settings.tray.description}" />
</Grid>
</ui:CardControl.Header>
<ui:ToggleSwitch x:Name="TraySwitch" Grid.Column="1" />
</ui:CardControl>
</Grid>

<TextBlock
Expand Down
25 changes: 19 additions & 6 deletions Guard/Views/Pages/Settings.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
using Guard.Core;
using System.Windows;
using System.Windows.Controls;
using Guard.Core;
using Guard.Core.Installation;
using Guard.Core.Models;
using Guard.Core.Security;
using Guard.Core.Storage;
using Guard.Views.Controls;
using System.Windows;
using System.Windows.Controls;
using Wpf.Ui.Controls;

namespace Guard.Views.Pages
Expand Down Expand Up @@ -64,7 +64,6 @@ public Settings()
AutoStartSwitch.Unchecked += AutoStartSwitch_Unchecked;
}


WinHelloSwitch.IsChecked = Auth.IsWindowsHelloRegistered();
WinHelloSwitch.IsEnabled = Auth.IsLoginEnabled();
WinHelloSwitch.Checked += (sender, e) => EnableWinHello();
Expand Down Expand Up @@ -102,6 +101,22 @@ public Settings()
{
Core.EventManager.AppThemeChanged -= OnAppThemeChanged;
};

TraySwitch.IsChecked = SettingsManager.Settings.MinimizeToTray;

TraySwitch.Checked += (sender, e) =>
{
SettingsManager.Settings.MinimizeToTray = true;
mainWindow.AddTrayIcon();
_ = SettingsManager.Save();
};

TraySwitch.Unchecked += (sender, e) =>
{
SettingsManager.Settings.MinimizeToTray = false;
mainWindow.RemoveTrayIcon();
_ = SettingsManager.Save();
};
}

private void SetSelectedLanguage(LanguageSetting lang)
Expand Down Expand Up @@ -379,7 +394,6 @@ private async void Reset_Button_Click(object sender, RoutedEventArgs e)
{
throw new Exception(I18n.GetString("passdialog.incorrect"));
}

}

var confirmResult = await new Wpf.Ui.Controls.MessageBox
Expand All @@ -397,7 +411,6 @@ private async void Reset_Button_Click(object sender, RoutedEventArgs e)
Reset.DeleteEverything();
Application.Current.Shutdown();
}

}
catch (Exception ex)
{
Expand Down

0 comments on commit e3c3bcf

Please sign in to comment.