Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
201 commits
Select commit Hold shift + click to select a range
47573ef
Updating Case05_DatabaseAutoLogout test case
YassinLokhat Oct 4, 2025
f050a3e
Adding Upsilon.Apps.Passkey.GUI MAUI project
YassinLokhat Oct 4, 2025
fdf5279
Merge remote-tracking branch 'origin/master' into 27-add-gui-client
YassinLokhat Oct 6, 2025
11f59eb
Removing Upsilon.Apps.Passkey.GUI MAUI project since it does NOT work !
YassinLokhat Oct 6, 2025
95b9809
Adding Upsilon.Apps.Passkey.GUI WPF project
YassinLokhat Oct 6, 2025
8c6ad37
Adding Dark theme
YassinLokhat Oct 7, 2025
5373ef2
Login Page
YassinLokhat Oct 7, 2025
f6eb58e
PasswordGenerator - Part 1
YassinLokhat Oct 7, 2025
3dd33e4
PasswordGenerator - Part 2
YassinLokhat Oct 7, 2025
399f481
PasswordGenerator - Part 3
YassinLokhat Oct 10, 2025
8fe2781
PasswordGenerator - Part 4
YassinLokhat Oct 10, 2025
ad6dc05
PasswordGenerator - Part 5
YassinLokhat Oct 10, 2025
497d13a
PasswordGenerator - Part 6
YassinLokhat Oct 10, 2025
55444d9
UserView - Part 1
YassinLokhat Oct 11, 2025
3ed32fe
UserView - Part 2
YassinLokhat Oct 11, 2025
e1c7fa0
PrivateTextBox - Part 1
YassinLokhat Oct 11, 2025
995e675
PrivateTextBox - Part 2
YassinLokhat Oct 11, 2025
c574c12
PrivateTextBox - Part 3
YassinLokhat Oct 11, 2025
46b8caf
Adding SlowHash unit test
YassinLokhat Oct 12, 2025
0b4f330
Implementing Login logic
YassinLokhat Oct 12, 2025
d7255a6
PasswordItem - Part 1
YassinLokhat Oct 12, 2025
dc08f40
Code Cleanup
YassinLokhat Oct 12, 2025
8459c0b
PasswordItem - Part 2
YassinLokhat Oct 13, 2025
2454903
PasswordContainer - Part 1
YassinLokhat Oct 13, 2025
f43e807
PasswordContainer - Part 2
YassinLokhat Oct 14, 2025
1e9c1e2
UserView- Part 1
YassinLokhat Oct 14, 2025
5225bf4
UserView- Part 2
YassinLokhat Oct 14, 2025
9c4ca9e
NumericUpDown - Part1
YassinLokhat Oct 14, 2025
92b7679
Removing NumericUpDown control
YassinLokhat Oct 15, 2025
63709ac
Removing unecesary FindName calls
YassinLokhat Oct 15, 2025
1c8dcc3
Adding NumericTextBoxHelper
YassinLokhat Oct 15, 2025
7ee4ece
UserView - Part 3
YassinLokhat Oct 15, 2025
4208a84
Code update
YassinLokhat Oct 15, 2025
4e52815
Removing unnecessary Visibility bindings
YassinLokhat Oct 16, 2025
71b85d6
Updating Core - Do not log if new value equals old one
YassinLokhat Oct 16, 2025
9f203b5
UserView - Clenup
YassinLokhat Oct 16, 2025
cc09d54
Global Code Cleanup
YassinLokhat Oct 17, 2025
31f31f9
Merge branch '30-core-improvments' into 27-add-gui-client
YassinLokhat Oct 17, 2025
ed4ca20
UserView - Part 4
YassinLokhat Oct 17, 2025
ef1417e
UserView - Part 5
YassinLokhat Oct 17, 2025
b6f4a8c
Finalizing UserView
YassinLokhat Oct 17, 2025
298e62b
Renaming `UserView` to `UserSettingsView`
YassinLokhat Oct 17, 2025
776babb
UserView - Part 6
YassinLokhat Oct 20, 2025
a1e5943
UserServicesView - Part 1
YassinLokhat Oct 20, 2025
5065f1f
UserServicesView - Part 2
YassinLokhat Oct 20, 2025
8a6bd68
Change username bugfix
YassinLokhat Oct 20, 2025
7d8d5d2
UserServicesView - Part 3
YassinLokhat Oct 20, 2025
f0b173e
UserServicesView - Part 4
YassinLokhat Oct 20, 2025
f5c1417
Moving "Margin=5" into the theme file
YassinLokhat Oct 20, 2025
634fb5d
Not close the database after its creation
YassinLokhat Oct 21, 2025
d885c27
Optimizing login and saving time
YassinLokhat Oct 21, 2025
7c4b501
Moving some properties into the theme file
YassinLokhat Oct 21, 2025
c853033
UserServicesView - Part 5
YassinLokhat Oct 24, 2025
630b96c
Generating Testing Database
YassinLokhat Oct 24, 2025
a693cc8
UserServicesView - Part 6 - Adding events
YassinLokhat Oct 25, 2025
4bd1d08
Optimizing warnings check
YassinLokhat Oct 25, 2025
cbccc9c
UserServicesView - Part 7 - Closing properly
YassinLokhat Oct 25, 2025
1e2945c
Code Cleanup
YassinLokhat Oct 25, 2025
a0e4dbc
Adding QrCodeGenerator
YassinLokhat Oct 25, 2025
764eab5
Adding compression and QRCode generator
YassinLokhat Oct 27, 2025
c107685
Using compressed database test files
YassinLokhat Oct 27, 2025
bd1381b
Fixing Core unit tests
YassinLokhat Oct 28, 2025
f47d029
Using RSA with OAEP padding for asymetric encryption
YassinLokhat Oct 30, 2025
0561f6f
Adding QrCodeHelper
YassinLokhat Nov 2, 2025
0d4849b
UserServicesView - Part 6 - Adding SelectionChanged event
YassinLokhat Nov 2, 2025
578ef9a
ServiceView - Part 1
YassinLokhat Nov 2, 2025
5a926fd
ServiceView - Part 2
YassinLokhat Nov 3, 2025
f1926d1
Optim for Autosave : remove all changes for the same item/field/action
YassinLokhat Nov 3, 2025
6c8ead4
Adding Autosave handler
YassinLokhat Nov 4, 2025
006929d
Moving SessionLeftTime from IUser to IDatabase
YassinLokhat Nov 4, 2025
65890bd
Optim for Autosave : Part 1
YassinLokhat Nov 5, 2025
75d69ea
Optim for Autosave : Part 2
YassinLokhat Nov 6, 2025
3775f8f
Adding HasChanged for all items
YassinLokhat Nov 6, 2025
88edcdf
Code Cleanup
YassinLokhat Nov 6, 2025
aeefdf6
Adding Changed indicator in title bar
YassinLokhat Nov 7, 2025
35e1594
Changing Background color on field changed
YassinLokhat Nov 7, 2025
571aa91
Using PropertyHelper when possible
YassinLokhat Nov 7, 2025
1fa1b6d
Changing Background color on changed
YassinLokhat Nov 7, 2025
ce45527
Closing AutoSave class
YassinLokhat Nov 10, 2025
ac03f82
UserServicesView - Adding Save
YassinLokhat Nov 10, 2025
d2a60e4
UserServicesView - Lock display while saving
YassinLokhat Nov 10, 2025
b0753a0
UserServicesView - Implementing Add Service button and Filters
YassinLokhat Nov 11, 2025
ae7f124
Moving Colors into DarkMode class
YassinLokhat Nov 11, 2025
790a7a1
Removing IsEnabled = false on saving
YassinLokhat Nov 12, 2025
a2df863
Adding Accounts list box
YassinLokhat Nov 12, 2025
10a5a75
Adding AccountView
YassinLokhat Nov 12, 2025
237bc6a
UserServicesView Layout
YassinLokhat Nov 12, 2025
8d240f1
AccountView - Adding Options
YassinLokhat Nov 13, 2025
a757a1b
Adding MergeWithoutSavingAndKeepAutoSaveFile feature
YassinLokhat Nov 14, 2025
b28f30e
Auto-logout bugfix
YassinLokhat Nov 14, 2025
6193f50
Renaming PasswordsContainer to UserPasswordsContainer
YassinLokhat Nov 14, 2025
47d1fc6
Adding AccountIdentifiantsView
YassinLokhat Nov 14, 2025
249b1e4
Forwarding Identifiant changed
YassinLokhat Nov 17, 2025
2176a1d
Account Identifiants - Part 1
YassinLokhat Nov 17, 2025
6d0dcfc
Account Identifiants - Part 2
YassinLokhat Nov 18, 2025
92d50ef
Account Identifiants - Part 3
YassinLokhat Nov 18, 2025
ce737cf
Account Identifiants - Part 4
YassinLokhat Nov 18, 2025
dee08d3
Account Identifiants - Part 5
YassinLokhat Nov 18, 2025
f43cba7
DeleteService feature
YassinLokhat Nov 18, 2025
4543409
DeleteAccount feature
YassinLokhat Nov 18, 2025
099d312
Code Cleanup
YassinLokhat Nov 18, 2025
4b0bfdf
Upgrade to DotNet 10
YassinLokhat Nov 18, 2025
6708964
Allow Empty view for Services and Accounts
YassinLokhat Nov 19, 2025
7bd3a44
Code Cleanup DotNet 10
YassinLokhat Nov 20, 2025
1e49bfa
Working on filters
YassinLokhat Nov 20, 2025
e3f3866
Working on filters
YassinLokhat Nov 21, 2025
d2d1a92
Using bigger test database
YassinLokhat Nov 21, 2025
2e78009
Optimize AddIdentifant
YassinLokhat Nov 21, 2025
52a5098
Code Cleanup
YassinLokhat Nov 21, 2025
394517b
Adding IUser.Shake
YassinLokhat Nov 22, 2025
35979b7
Adding Passwords view - Part 1
YassinLokhat Nov 22, 2025
5260c76
Adding Passwords view - Part 2
YassinLokhat Nov 22, 2025
5b6c4a1
Adding Passwords view - Part 3
YassinLokhat Nov 22, 2025
9aa7af5
Adding Passwords view - Part 4
YassinLokhat Nov 22, 2025
5aaac24
Adding IUser.ShowPasswordDelay
YassinLokhat Nov 22, 2025
3f48e48
Adding Copy to clipboard button
YassinLokhat Nov 22, 2025
3564ead
Inert Password feature
YassinLokhat Nov 23, 2025
f0f417c
Updating Testing Database
YassinLokhat Nov 23, 2025
03c7cc0
Removing UpdateSourceTrigger=PropertyChanged
YassinLokhat Nov 23, 2025
bc206c9
Code Cleanup
YassinLokhat Nov 23, 2025
69f553f
Adding Import/Export feature - Part 1
YassinLokhat Nov 23, 2025
628ee11
Renaming PassKey to Passkey in namespace
YassinLokhat Nov 24, 2025
2022599
Adding Import/Export feature - Part 2
YassinLokhat Nov 26, 2025
7222694
Adding Import CSV tests - Part 1
YassinLokhat Nov 26, 2025
178e84d
Adding Import CSV tests - Part 2
YassinLokhat Nov 26, 2025
de5b13b
Adding Import CSV tests - Part 3
YassinLokhat Nov 26, 2025
5f48f19
Adding Import CSV tests - Part 4
YassinLokhat Nov 26, 2025
09f3a86
Adding Import CSV tests - Part 5
YassinLokhat Nov 26, 2025
9603dfb
Code cleanup
YassinLokhat Nov 26, 2025
566c6ce
Adding Import CSV tests - Part 6
YassinLokhat Nov 26, 2025
9a7bf30
Adding Import CSV tests - Part 7
YassinLokhat Nov 27, 2025
3cb95d2
Adding Export feature
YassinLokhat Nov 28, 2025
d21cacc
Using extension methods for serialization
YassinLokhat Nov 28, 2025
f6efa60
Adding Export feature tests
YassinLokhat Nov 28, 2025
4b85267
Adding Identifiant and Passwords copy to clipboard feature
YassinLokhat Nov 28, 2025
7bb808e
Renaming Identifiant to Identifier
YassinLokhat Nov 28, 2025
887e7a9
Adding QrCodeView
YassinLokhat Nov 28, 2025
3f55d1f
Implementing QrCodeView
YassinLokhat Nov 28, 2025
295125e
Code cleanup
YassinLokhat Nov 28, 2025
4706e69
QrCode improvment
YassinLokhat Nov 28, 2025
4f07ceb
Adding Import/Export feature in the GUI
YassinLokhat Nov 28, 2025
0fc940b
Adding NumberOfOldPasswordToKeep feature
YassinLokhat Nov 29, 2025
649c325
Some bugfix
YassinLokhat Nov 29, 2025
953b364
Code cleanup
YassinLokhat Nov 29, 2025
57cc461
Copying testing files
YassinLokhat Nov 30, 2025
31be8d2
Adding insert Identifier/Password global hotkey
YassinLokhat Dec 1, 2025
082602f
Adding Open Url button
YassinLokhat Dec 3, 2025
bde5f8c
Using Globe icon for Open Url feature
YassinLokhat Dec 5, 2025
fe02cf3
Merge remote-tracking branch 'origin/master' into 27-add-gui-client
YassinLokhat Dec 14, 2025
6eee40c
Code Cleanup
YassinLokhat Dec 14, 2025
fac8c7e
Merge remote-tracking branch 'origin/master' into 27-add-gui-client
YassinLokhat Dec 19, 2025
96d2d31
Integrating Core improvements
YassinLokhat Dec 19, 2025
82e1a9a
Showing warnings number
YassinLokhat Dec 19, 2025
e42a07e
Removing Data array from ILog
YassinLokhat Dec 21, 2025
5a12550
Adding UserLogsView - Part 1
YassinLokhat Dec 21, 2025
333b876
Adding UserLogsView - Part 2
YassinLokhat Dec 22, 2025
fc41c28
Adding UserLogsView - Part 3
YassinLokhat Dec 22, 2025
c756bb2
Adding UserLogsView - Part 4
YassinLokhat Dec 27, 2025
20acd6f
Try to fix "Save needs review state changed"
YassinLokhat Dec 27, 2025
8841391
Focus to service filter on startup
YassinLokhat Dec 27, 2025
ed1f540
Moving HasChanged from IDatabase to IItem
YassinLokhat Dec 27, 2025
15747cb
Adding AutoCompleteTextBox
YassinLokhat Dec 27, 2025
9255085
Adding Go to item feature
YassinLokhat Dec 27, 2025
aa15fed
Save NeedsReview state
YassinLokhat Dec 28, 2025
0a8038c
Improving Thread safety
YassinLokhat Dec 28, 2025
05828a0
Code Cleanup
YassinLokhat Dec 28, 2025
c543797
Compressing Log.DateTimeTicks into hexa
YassinLokhat Dec 28, 2025
761b886
Using token to cancel Task
YassinLokhat Dec 28, 2025
4401828
Adding IsBusy feature
YassinLokhat Dec 29, 2025
538f739
Renaming Log into Activity
YassinLokhat Dec 30, 2025
8bc94dc
Improving Warning management
YassinLokhat Dec 30, 2025
eab9caa
Try fix random bugs - Part 1
YassinLokhat Dec 30, 2025
14623b0
Try fix random bugs - Part 2
YassinLokhat Dec 30, 2025
2f5b728
Adding Warnings sub menu items
YassinLokhat Dec 31, 2025
9cc58a0
Adding ExpiredOrLeakedPasswordsView
YassinLokhat Dec 31, 2025
bc29898
Adding AccountPasswordsWarningView
YassinLokhat Jan 2, 2026
eae75c6
Optimizing Leaked passwords check
YassinLokhat Jan 5, 2026
ec94c20
Using Enum.HasFlag instead of custom ContainsFlag method
YassinLokhat Jan 5, 2026
2259a25
Adding LeakedPassword Background color
YassinLokhat Jan 5, 2026
6ae1c3a
Adding DuplicatedPasswordsWarningView
YassinLokhat Jan 5, 2026
cd858bb
Database stress test
YassinLokhat Jan 5, 2026
ca1d9e0
Optimizing Warnings check
YassinLokhat Jan 6, 2026
f5e785a
Code Cleanup
YassinLokhat Jan 6, 2026
a371639
HasChanged bugfix
YassinLokhat Jan 6, 2026
28d24d4
Adding WarnIfDuplicatedPassword Account Option
YassinLokhat Jan 6, 2026
427b8c2
UI improvements
YassinLokhat Jan 6, 2026
9f6bb09
Adding details in Activities
YassinLokhat Jan 6, 2026
8434582
Adding IUser.NumberOfMonthActivitiesToKeep
YassinLokhat Jan 7, 2026
fcce969
Autosave bugfix
YassinLokhat Jan 7, 2026
138311b
Adding ChangedItemsOnly filter
YassinLokhat Jan 7, 2026
4b8be8d
Allow access to database file to be read by other process
YassinLokhat Jan 8, 2026
12779a4
Fixing tests
YassinLokhat Jan 8, 2026
f820e72
Allow open database file directly
YassinLokhat Jan 8, 2026
65ac6a7
Improve warnings views
YassinLokhat Jan 8, 2026
5aac636
Do not remove old activities if it needs review
YassinLokhat Jan 8, 2026
04e72af
Removing 'NewUser' database test
YassinLokhat Jan 12, 2026
449d52d
Merge remote-tracking branch 'origin/master' into 27-add-gui-client
YassinLokhat Jan 13, 2026
338fdef
Moving the GUI project to GUI/WPF
YassinLokhat Jan 13, 2026
01a05f5
Adding view Service and Account activities feature
YassinLokhat Jan 13, 2026
5b6b746
Code cleanup
YassinLokhat Jan 13, 2026
03920b0
Debug settings update
YassinLokhat Jan 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions GUI/WPF/App.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<Application x:Class="Upsilon.Apps.Passkey.GUI.WPF.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Upsilon.Apps.Passkey.GUI.WPF"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Themes/DarkTheme.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
12 changes: 12 additions & 0 deletions GUI/WPF/App.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System.Windows;

namespace Upsilon.Apps.Passkey.GUI.WPF
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
}

}
10 changes: 10 additions & 0 deletions GUI/WPF/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System.Windows;

[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)
)]
74 changes: 74 additions & 0 deletions GUI/WPF/Helper/EnumHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
using Upsilon.Apps.Passkey.Core.Utils;
using Upsilon.Apps.Passkey.Interfaces.Enums;

namespace Upsilon.Apps.Passkey.GUI.WPF.Helper
{
internal static class EnumHelper
{
public static string ToReadableString(this ActivityEventType eventType)
{
return eventType switch
{
ActivityEventType.None => "All",
ActivityEventType.MergeAndSaveThenRemoveAutoSaveFile => "Auto-save merged then saved",
ActivityEventType.MergeWithoutSavingAndKeepAutoSaveFile => "Auto-save merged but not saved",
ActivityEventType.DontMergeAndRemoveAutoSaveFile => "Auto-save discarded",
ActivityEventType.DontMergeAndKeepAutoSaveFile => "Auto-save not merged and keeped",
ActivityEventType.DatabaseCreated
or ActivityEventType.DatabaseOpened
or ActivityEventType.DatabaseSaved
or ActivityEventType.DatabaseClosed
or ActivityEventType.LoginSessionTimeoutReached
or ActivityEventType.LoginFailed
or ActivityEventType.UserLoggedIn
or ActivityEventType.UserLoggedOut
or ActivityEventType.ImportingDataStarted
or ActivityEventType.ImportingDataSucceded
or ActivityEventType.ImportingDataFailed
or ActivityEventType.ExportingDataStarted
or ActivityEventType.ExportingDataSucceded
or ActivityEventType.ExportingDataFailed
or ActivityEventType.ItemUpdated
or ActivityEventType.ItemAdded
or ActivityEventType.ItemDeleted => eventType.ToString().ToSentenceCase(),
_ => throw new InvalidOperationException($"'{eventType}' event type not handled"),
};
}

public static ActivityEventType ActivityEventTypeFromReadableString(string readableString)
{
try
{
return Enum.GetValues<ActivityEventType>()
.Cast<ActivityEventType>()
.First(x => x.ToReadableString() == readableString);
}
catch
{
throw new InvalidOperationException($"'{readableString}' event type not handled");
}
}

public static string ToReadableString(this WarningType warningType)
{
return warningType switch
{
WarningType.PasswordUpdateReminderWarning | WarningType.PasswordLeakedWarning => "All",
WarningType.PasswordUpdateReminderWarning => "Expired passwords",
WarningType.PasswordLeakedWarning => "Leaked passwords",
_ => throw new InvalidOperationException($"'{warningType}' warning type not handled"),
};
}

public static WarningType ActivityWarningTypeFromReadableString(string readableString)
{
return readableString switch
{
"All" => WarningType.PasswordUpdateReminderWarning | WarningType.PasswordLeakedWarning,
"Expired passwords" => WarningType.PasswordUpdateReminderWarning,
"Leaked passwords" => WarningType.PasswordLeakedWarning,
_ => throw new InvalidOperationException($"'{readableString}' warning type not handled"),
};
}
}
}
92 changes: 92 additions & 0 deletions GUI/WPF/Helper/HotKeyHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Input;
using System.Windows.Interop;

namespace Upsilon.Apps.Passkey.GUI.WPF.Helper
{
public static class HotkeyHelper
{
private static int _id = 0;

public static event EventHandler<HotkeyEventArgs>? HotkeyPressed;

public static int Register(Window window, ModifierKeys modifiers, Key key)
{
int hotkeyId = Interlocked.Increment(ref _id);
uint virtualKey = (uint)KeyInterop.VirtualKeyFromKey(key);

IntPtr hWnd = new WindowInteropHelper(window).Handle;
if (hWnd == IntPtr.Zero)
return -1;

bool success = RegisterHotKey(hWnd, hotkeyId, (uint)modifiers, virtualKey);
if (!success)
return -1;

if (PresentationSource.FromVisual(window) is HwndSource source)
{
source.AddHook((hwnd, msg, wParam, lParam, ref handled) =>
{
if (msg == 0x0312 && (int)wParam == hotkeyId)
{
HotkeyEventArgs e = new(lParam);
HotkeyPressed?.Invoke(window, e);
handled = true;
}
return IntPtr.Zero;
});
}

return hotkeyId;
}

public static bool Unregister(Window window, int hotkeyId)
{
if (window is null)
return false;

IntPtr hWnd = new WindowInteropHelper(window).Handle;
return hWnd != nint.Zero && UnregisterHotKey(hWnd, hotkeyId);
}

public static void Send(ModifierKeys modifiers, Key key)
{
//byte[] modifiers = [];
byte virtualKey = (byte)KeyInterop.VirtualKeyFromKey(key);

keybd_event((byte)modifiers, 0, 0, UIntPtr.Zero);

keybd_event(virtualKey, 0, 0, UIntPtr.Zero);
keybd_event(virtualKey, 0, 0x0002, UIntPtr.Zero);

keybd_event((byte)modifiers, 0, 0x0002, UIntPtr.Zero);
}

[DllImport("user32.dll")]
private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk);

[DllImport("user32.dll")]
private static extern bool UnregisterHotKey(IntPtr hWnd, int id);

[DllImport("user32.dll")]
private static extern uint MapVirtualKey(uint uCode, uint uMapType);

[DllImport("user32.dll")]
private static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, UIntPtr dwExtraInfo);
}

public class HotkeyEventArgs : EventArgs
{
public readonly Key Key;
public readonly ModifierKeys Modifiers;

internal HotkeyEventArgs(IntPtr hotKeyParam)
{
uint param = (uint)hotKeyParam.ToInt64();
int virtualKey = (int)((param & 0xffff0000) >> 16);
Key = KeyInterop.KeyFromVirtualKey(virtualKey);
Modifiers = (ModifierKeys)(param & 0x0000ffff);
}
}
}
57 changes: 57 additions & 0 deletions GUI/WPF/Helper/IItemHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using Upsilon.Apps.Passkey.Interfaces.Models;

namespace Upsilon.Apps.Passkey.GUI.WPF.Helper
{
public static class IItemHelper
{
public static void Shake(this IUser user)
{
_ = user.ItemId;
}

public static bool MeetsFilterConditions(this IService service, string serviceFilter, string identifierFilter, string globalTextFilter, bool changedItemsOnly)
{
serviceFilter = serviceFilter.ToLower().Trim();
identifierFilter = identifierFilter.ToLower().Trim();
globalTextFilter = globalTextFilter.ToLower().Trim();

string serviceId = service.ItemId.Replace(service.User.ItemId, string.Empty).ToLower().Trim();
string serviceName = service.ServiceName.ToLower().Trim();
string url = service.Url.ToLower().Trim();
string notes = service.Notes.ToLower().Trim();

return (!string.IsNullOrWhiteSpace(globalTextFilter)
? serviceId == globalTextFilter
|| serviceName.Contains(globalTextFilter)
|| url.Contains(globalTextFilter)
|| notes.Contains(globalTextFilter)
|| service.Accounts.Any(x => x.MeetsFilterConditions(string.Empty, globalTextFilter, changedItemsOnly))
: (string.IsNullOrWhiteSpace(serviceFilter)
|| (!string.IsNullOrWhiteSpace(serviceFilter) && serviceName.Contains(serviceFilter)))
&& (string.IsNullOrWhiteSpace(identifierFilter)
|| service.Accounts.Any(x => x.MeetsFilterConditions(identifierFilter, globalTextFilter, changedItemsOnly))))
&& (!changedItemsOnly || service.HasChanged());
}

public static bool MeetsFilterConditions(this IAccount account, string identifierFilter, string globalTextFilter, bool changedItemsOnly)
{
identifierFilter = identifierFilter.ToLower().Trim();
globalTextFilter = globalTextFilter.ToLower().Trim();

string accountId = account.ItemId.Replace(account.Service.ItemId, string.Empty).ToLower().Trim();
string label = account.Label.ToLower().Trim();
string notes = account.Notes.ToLower().Trim();
string identifiers = string.Join("\n", account.Identifiers.Select(x => x.ToLower().Trim()));

return (!string.IsNullOrWhiteSpace(globalTextFilter)
? accountId == globalTextFilter
|| identifiers.Contains(globalTextFilter)
|| label.ToLower().Contains(globalTextFilter)
|| notes.ToLower().Contains(globalTextFilter)
: string.IsNullOrWhiteSpace(identifierFilter)
|| identifiers.Contains(identifierFilter)
|| label.Contains(identifierFilter))
&& (!changedItemsOnly || account.HasChanged());
}
}
}
57 changes: 57 additions & 0 deletions GUI/WPF/Helper/NumericTextBoxHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace Upsilon.Apps.Passkey.GUI.WPF.Helper
{
public static class NumericTextBoxHelper
{
private static readonly Regex _regex = new("[^0-9]+"); //regex that matches disallowed text

private static bool _isTextAllowed(string text)
{
bool isValid = !_regex.IsMatch(text);

if (isValid)
{
isValid = int.TryParse(text, out _);
}

return isValid;
}

public static void TextChanged(object sender, TextChangedEventArgs e)
{
TextBox textBox = (TextBox)sender;

e.Handled = !_isTextAllowed(textBox.Text);

if (e.Handled)
{
textBox.Text = textBox.Text.Replace(" ", "");
}
}

public static void PreviewTextInput(object sender, TextCompositionEventArgs e)
{
e.Handled = !_isTextAllowed(e.Text);
}

public static void Pasting(object sender, DataObjectPastingEventArgs e)
{
if (e.DataObject.GetDataPresent(typeof(string)))
{
string text = (string)e.DataObject.GetData(typeof(string));
if (!_isTextAllowed(text))
{
e.CancelCommand();
}
}
else
{
e.CancelCommand();
}
}
}
}
25 changes: 25 additions & 0 deletions GUI/WPF/Helper/PropertyHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace Upsilon.Apps.Passkey.GUI.WPF.Helper
{
public static class PropertyHelper
{
public static bool SetProperty<T>(ref T field,
T newValue,
INotifyPropertyChanged sender,
PropertyChangedEventHandler? PropertyChanged,
[CallerMemberName] string? propertyName = null)
{
if (!Equals(field, newValue))
{
field = newValue;
PropertyChanged?.Invoke(sender, new PropertyChangedEventArgs(propertyName));

return true;
}

return false;
}
}
}
24 changes: 24 additions & 0 deletions GUI/WPF/Helper/WindowHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace Upsilon.Apps.Passkey.GUI.WPF.Helper
{
public static class WindowHelper
{
public static bool GetIsBusy(this Window window)
{
return window.Cursor == Cursors.Wait;
}

public static void SetIsBusy(this Window window, bool isBusy)
{
window.Cursor = isBusy ? Cursors.Wait : Cursors.Arrow;
}

public static bool GetIsBusy(this UserControl control)
{
return Window.GetWindow(control).GetIsBusy();
}
}
}
Loading