@@ -20,12 +20,25 @@ namespace SafeNotes
2020 public partial class MainForm : MaterialSkin . Controls . MaterialForm
2121 {
2222 private AppSettings _settings ;
23+ private NotifyIcon notifyIcon ;
2324
2425 private async void MainForm_Load ( object sender , EventArgs e )
2526 {
27+ InitializeSysTrayIcon ( ) ;
2628 _settings = SettingsManager . LoadSettings ( ) ;
2729 shouldExit = false ;
2830
31+ if ( _settings . IsRestartingForUpdate == true )
32+ {
33+ _settings . IsRestartingForUpdate = false ;
34+ SettingsManager . SaveSettings ( _settings ) ;
35+ }
36+
37+ if ( _settings . PinCode == null && _settings . RequirePinCode == true )
38+ {
39+ UserPINCodeField . Hint = "Set your PIN..." ;
40+ }
41+
2942 // Sets the minimum size of the form
3043 this . MinimumSize = new Size ( 960 , 600 ) ;
3144 // If the user screen is 1280x720 set the size to 960x600
@@ -56,7 +69,7 @@ private async void MainForm_Load(object sender, EventArgs e)
5669 ( Screen . PrimaryScreen . WorkingArea . Height - this . Height ) / 2 ) ;
5770
5871 // Reset the IsRestartingForUpdate flag on application start
59- if ( _settings . IsRestartingForUpdate )
72+ if ( _settings . IsRestartingForUpdate == true )
6073 {
6174 _settings . IsRestartingForUpdate = false ;
6275 SettingsManager . SaveSettings ( _settings ) ;
@@ -124,8 +137,9 @@ private async void MainForm_Load(object sender, EventArgs e)
124137 ApplyDateCheckbox . Checked = _settings . SaveDate ;
125138 DisableNotificationsCheckbox . Checked = _settings . DisableNotifications ;
126139 RequirePinToLogin . Checked = _settings . RequirePinCode ;
140+ MinToSysTray . Checked = _settings . MinimizeToTray ;
127141
128- // Fetching the release info to populate ReleaseNotesMultiText and uses a thread to not block the UI
142+ // Fetching the release info to popu` ReleaseNotesMultiText and uses a thread to not block the UI
129143 await Task . Run ( async ( ) =>
130144 {
131145 try
@@ -180,6 +194,20 @@ private void PasswordLengthDisclaimer_LinkClicked(object sender, LinkLabelLinkCl
180194 MessageBoxButtons . OK , MessageBoxIcon . Information ) ;
181195 }
182196
197+ private void MinToSysTray_CheckedChanged ( object sender , EventArgs e )
198+ {
199+ if ( MinToSysTray . Checked == true )
200+ {
201+ _settings . MinimizeToTray = true ;
202+ SettingsManager . SaveSettings ( _settings ) ;
203+ }
204+ else if ( MinToSysTray . Checked == false )
205+ {
206+ _settings . MinimizeToTray = false ;
207+ SettingsManager . SaveSettings ( _settings ) ;
208+ }
209+ }
210+
183211 private void RequirePenToLogin_CheckedChanged ( object sender , EventArgs e )
184212 {
185213 if ( RequirePinToLogin . Checked == true )
@@ -352,7 +380,7 @@ private void Notepad_Click(object sender, EventArgs e)
352380
353381 private void MainForm_FormClosing ( object sender , FormClosingEventArgs e )
354382 {
355- if ( _settings . IsRestartingForUpdate )
383+ if ( _settings . IsRestartingForUpdate == true )
356384 {
357385 // Skip saving settings if the application is restarting for an update
358386 return ;
@@ -835,22 +863,20 @@ private void UserLoginButton_Click(object sender, EventArgs e)
835863 }
836864 else
837865 {
838- MessageBox . Show ( "None of the supported password managers are installed.\n \n Remember to save your password! " , "Password Manager Not Found" , MessageBoxButtons . OK , MessageBoxIcon . Information ) ;
866+ MessageBox . Show ( "None of the supported password managers are installed.\n \n Remember to save your password to gurantee access to SafeNotes. " , "Password Manager Not Found" , MessageBoxButtons . OK , MessageBoxIcon . Information ) ;
839867 UserPassword . Text = UserConfirmPassword . Text ;
840868 UserConfirmPassword . Text = UserPassword . Text ;
841869 }
842870
843- string hashedPassword = HashPassword ( UserPassword . Text ) ;
844- _settings . UserPassword = hashedPassword ;
845-
846871 // Generate a unique salt and store it in setSaltedDecryptionKey
847872 byte [ ] salt = new byte [ 16 ] ;
848873 using ( var rng = new RNGCryptoServiceProvider ( ) )
849874 {
850875 rng . GetBytes ( salt ) ;
851876 }
852877
853- _settings . FirstTimeOpened = false ;
878+ string hashedPassword = HashPassword ( UserPassword . Text ) ;
879+ _settings . UserPassword = hashedPassword ;
854880 SettingsManager . SaveSettings ( _settings ) ;
855881 UserConfirmPassword . Visible = false ;
856882 UserLoginButton . Text = "Login" ;
@@ -885,6 +911,8 @@ private void UserLoginButton_Click(object sender, EventArgs e)
885911 {
886912 _settings . PinCode = HashPassword ( UserPINCodeField . Text ) ;
887913 SettingsManager . SaveSettings ( _settings ) ;
914+ MessageBox . Show ( "Your PIN code has been successfully set and will now be required at login." , "Pin Code Set" , MessageBoxButtons . OK , MessageBoxIcon . Information ) ;
915+ UserPINCodeField . Hint = "Enter your PIN..." ;
888916 }
889917 }
890918 else
@@ -907,7 +935,6 @@ private void UserLoginButton_Click(object sender, EventArgs e)
907935 LoginTabSelector . Enabled = true ;
908936 TabControl . TabPages . Remove ( LoginPage ) ;
909937
910- _settings . FirstTimeOpened = false ;
911938 SettingsManager . SaveSettings ( _settings ) ;
912939
913940 // Load the entries from the settings into the entriesListBox
@@ -1013,6 +1040,7 @@ private void LeftMenuNav_AfterSelect(object sender, TreeViewEventArgs e)
10131040 EncryptEntriesButton . Visible = false ;
10141041 SettingsInfoLabel . Visible = false ;
10151042 RequirePinToLogin . Visible = false ;
1043+ MinToSysTray . Visible = false ;
10161044 }
10171045 else if ( LeftSettingsNav . SelectedNode == LeftSettingsNav . Nodes [ 1 ] )
10181046 {
@@ -1021,18 +1049,19 @@ private void LeftMenuNav_AfterSelect(object sender, TreeViewEventArgs e)
10211049 RequirePinToLogin . Visible = true ;
10221050 SettingsInfoLabel . Visible = true ;
10231051
1024- SettingsInfoLabel . Text = "Require Login PIN: The PIN is in experimental mode and is not implemented fully, meaning the PIN \n may not be stored and " +
1025- "accessed as securely." + " \n \n NOTE: This will not affect the security of your entries or login status as the PIN will be " +
1026- "required in \n conjunction " + "with your password. Enabling this feature will still come with benefits and strengthen \n app " +
1027- "security. The only fallback is the PIN will be more easily decrypted/dehashed; knowing this PIN \n does not mean access to " +
1028- "SafeNotes." ;
1052+ SettingsInfoLabel . Text = "Require Login PIN: The login PIN is a second layer of security to help eliminate unwanted access to SafeNotes. " +
1053+ "\n \n NOTE: This is only as secure as you make it; the same goes for passwords. To ensure security, use a PIN code \n " +
1054+ "generator, similar to SafeNotes built-in password generator, and to ensure that it is secure, make it a minimum " +
1055+ "of \n at least eight numbers long. \n \n Remember to save your PIN and password in a password manager (e.g Bitwarden, " +
1056+ "1Password, ProtonPass, etc.) \n as doing so will ensure you do not lose access to SafeNotes." ;
10291057
10301058 ApplyDateCheckbox . Visible = false ;
10311059 LightModeCheckbox . Visible = false ;
10321060 ImportEntriesButton . Visible = false ;
10331061 ExportEntriesButton . Visible = false ;
10341062 DisableNotificationsCheckbox . Visible = false ;
10351063 EncryptEntriesButton . Visible = false ;
1064+ MinToSysTray . Visible = false ;
10361065 }
10371066 else if ( LeftSettingsNav . SelectedNode == LeftSettingsNav . Nodes [ 2 ] )
10381067 {
@@ -1054,8 +1083,24 @@ private void LeftMenuNav_AfterSelect(object sender, TreeViewEventArgs e)
10541083 LightModeCheckbox . Visible = false ;
10551084 DisableNotificationsCheckbox . Visible = false ;
10561085 RequirePinToLogin . Visible = false ;
1086+ MinToSysTray . Visible = false ;
10571087 }
10581088 else if ( LeftSettingsNav . SelectedNode == LeftSettingsNav . Nodes [ 3 ] )
1089+ {
1090+ MinToSysTray . Visible = true ;
1091+
1092+ ApplyDateCheckbox . Visible = false ;
1093+ ResetAccountCheckbox . Visible = false ;
1094+ ResetLoginStatusButton . Visible = false ;
1095+ ImportEntriesButton . Visible = false ;
1096+ ExportEntriesButton . Visible = false ;
1097+ DisableNotificationsCheckbox . Visible = false ;
1098+ EncryptEntriesButton . Visible = false ;
1099+ SettingsInfoLabel . Visible = false ;
1100+ RequirePinToLogin . Visible = false ;
1101+ LightModeCheckbox . Visible = false ;
1102+ }
1103+ else if ( LeftSettingsNav . SelectedNode == LeftSettingsNav . Nodes [ 4 ] )
10591104 {
10601105 LightModeCheckbox . Visible = true ;
10611106
@@ -1068,6 +1113,7 @@ private void LeftMenuNav_AfterSelect(object sender, TreeViewEventArgs e)
10681113 EncryptEntriesButton . Visible = false ;
10691114 SettingsInfoLabel . Visible = false ;
10701115 RequirePinToLogin . Visible = false ;
1116+ MinToSysTray . Visible = false ;
10711117 }
10721118 }
10731119
@@ -1840,5 +1886,74 @@ private string GenerateSecurePassword(int length)
18401886
18411887 return password . ToString ( ) ;
18421888 }
1889+
1890+ private ContextMenuStrip trayMenu ;
1891+
1892+ private void InitializeSysTrayIcon ( )
1893+ {
1894+ SysTrayIcon = new NotifyIcon ( ) ;
1895+ SysTrayIcon . Icon = this . Icon ;
1896+ SysTrayIcon . Text = "SafeNotes" ;
1897+ SysTrayIcon . Visible = false ;
1898+ SysTrayIcon . DoubleClick += SysTrayIcon_DoubleClick ;
1899+
1900+ trayMenu = new ContextMenuStrip ( ) ;
1901+ var openItem = new ToolStripMenuItem ( "Open" , null , ( s , e ) => SysTrayIcon_DoubleClick ( s , e ) ) ;
1902+ var websiteItem = new ToolStripMenuItem ( "SafeNotes Website" , null , ( s , e ) => Process . Start ( new ProcessStartInfo
1903+ {
1904+ FileName = "https://safenotes.space" ,
1905+ UseShellExecute = true
1906+ } ) ) ;
1907+ var aboutItem = new ToolStripMenuItem ( "About SafeNotes" , null , ( s , e ) => Process . Start ( new ProcessStartInfo
1908+ {
1909+ FileName = "https://safenotes.space/about" ,
1910+ UseShellExecute = true
1911+ } ) ) ;
1912+ var policyItem = new ToolStripMenuItem ( "Privacy Policy" , null , ( s , e ) => Process . Start ( new ProcessStartInfo
1913+ {
1914+ FileName = "https://safenotes.space/privacy" ,
1915+ UseShellExecute = true
1916+ } ) ) ;
1917+ var termsItem = new ToolStripMenuItem ( "Terms of Service" , null , ( s , e ) => Process . Start ( new ProcessStartInfo
1918+ {
1919+ FileName = "https://safenotes.space/terms" ,
1920+ UseShellExecute = true
1921+ } ) ) ;
1922+ var exitItem = new ToolStripMenuItem ( "Exit" , null , ( s , e ) => Application . Exit ( ) ) ;
1923+ trayMenu . Items . Add ( openItem ) ;
1924+ trayMenu . Items . Add ( websiteItem ) ;
1925+ trayMenu . Items . Add ( aboutItem ) ;
1926+ trayMenu . Items . Add ( policyItem ) ;
1927+ trayMenu . Items . Add ( termsItem ) ;
1928+ trayMenu . Items . Add ( exitItem ) ;
1929+
1930+ SysTrayIcon . ContextMenuStrip = trayMenu ;
1931+ }
1932+
1933+ private void SysTrayIcon_DoubleClick ( object sender , EventArgs e )
1934+ {
1935+ this . Show ( ) ;
1936+ this . WindowState = FormWindowState . Normal ;
1937+ }
1938+
1939+ private void MainForm_Resize ( object sender , EventArgs e )
1940+ {
1941+ if ( _settings != null && _settings . MinimizeToTray )
1942+ {
1943+ SysTrayIcon . Visible = true ;
1944+ if ( this . WindowState == FormWindowState . Minimized )
1945+ {
1946+ this . Hide ( ) ;
1947+ }
1948+ else if ( this . WindowState == FormWindowState . Normal )
1949+ {
1950+ this . Show ( ) ;
1951+ }
1952+ }
1953+ else
1954+ {
1955+ SysTrayIcon . Visible = false ;
1956+ }
1957+ }
18431958 }
18441959}
0 commit comments