Skip to content

Commit be15f23

Browse files
authored
Merge pull request #40 from YassinLokhat/38-gui-bugfix
38 gui bugfix
2 parents 33a3212 + dc17812 commit be15f23

30 files changed

Lines changed: 306 additions & 196 deletions

Core/Models/Database.cs

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public sealed class Database : IDatabase
2424
public IPasswordFactory PasswordFactory { get; private set; }
2525
public IClipboardManager ClipboardManager { get; private set; }
2626

27-
public event EventHandler<WarningDetectedEventArgs>? WarningDetected;
27+
public event EventHandler<WarningsUpdatedEventArgs>? WarningsUpdated;
2828
public event EventHandler<AutoSaveDetectedEventArgs>? AutoSaveDetected;
2929
public event EventHandler? DatabaseSaved;
3030
public event EventHandler<LogoutEventArgs>? DatabaseClosed;
@@ -465,23 +465,19 @@ private void _lookAtWarnings()
465465
..passwordLeakedWarnings,
466466
..duplicatedPasswordsWarnings];
467467

468-
IWarning[] warnings = [.. Warnings?.Where(x => User is not null && User.WarningsToNotify.HasFlag(x.WarningType)) ?? []];
469-
470-
if (warnings.Length != 0)
471-
{
472-
WarningDetected?.Invoke(this, new WarningDetectedEventArgs(warnings));
473-
}
468+
WarningsUpdated?.Invoke(this, new WarningsUpdatedEventArgs([.. Warnings.Where(x => User.WarningsToNotify.HasFlag(x.WarningType))]));
474469
}
475470
catch { }
476471
}
477472

478473
private Warning[] _lookAtActivityWarnings()
479474
{
480-
return User is null
481-
? throw new NullReferenceException(nameof(User))
482-
: ActivityCenter.Activities is null
483-
? throw new NullReferenceException(nameof(ActivityCenter.Activities))
484-
: [new Warning([.. ActivityCenter.Activities.Where(x => x.NeedsReview).Cast<Activity>()])];
475+
if (User is null) throw new NullReferenceException(nameof(User));
476+
if (ActivityCenter.Activities is null) throw new NullReferenceException(nameof(ActivityCenter.Activities));
477+
478+
IActivity[] activities = [.. ActivityCenter.Activities.Where(x => x.NeedsReview)];
479+
480+
return activities.Length != 0 ? [new Warning([.. activities])] : [];
485481
}
486482

487483
private Warning[] _lookAtPasswordUpdateReminderWarnings()

GUI/WPF/Helper/WindowHelper.cs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
using System.Windows;
22
using System.Windows.Controls;
33
using System.Windows.Input;
4+
using System.Windows.Media;
5+
using Upsilon.Apps.Passkey.GUI.WPF.Themes;
46

57
namespace Upsilon.Apps.Passkey.GUI.WPF.Helper
68
{
@@ -20,5 +22,34 @@ public static bool GetIsBusy(this UserControl control)
2022
{
2123
return Window.GetWindow(control).GetIsBusy();
2224
}
25+
26+
public static void PostLoadSetup(this Window window)
27+
{
28+
DarkMode.SetDarkMode(window);
29+
ComputeTabIndex(window);
30+
}
31+
32+
public static void ComputeTabIndex(this Window window)
33+
{
34+
int tabIndex = 0;
35+
_computeTabIndex(window, ref tabIndex);
36+
}
37+
38+
private static void _computeTabIndex(DependencyObject depObj, ref int tabIndex)
39+
{
40+
if (depObj == null) return;
41+
42+
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
43+
{
44+
DependencyObject ithChild = VisualTreeHelper.GetChild(depObj, i);
45+
46+
if (ithChild is Control control)
47+
{
48+
control.TabIndex = tabIndex++;
49+
}
50+
51+
_computeTabIndex(ithChild, ref tabIndex);
52+
}
53+
}
2354
}
2455
}

GUI/WPF/MainWindow.xaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,14 @@
1212
ResizeMode="CanMinimize"
1313
WindowStartupLocation="CenterScreen"
1414
Height="140" Width="500">
15+
<Window.CommandBindings>
16+
<CommandBinding Command="Open" Executed="_openDatabase_MenuItem_Click"/>
17+
<CommandBinding Command="New" Executed="_newUser_MenuItem_Click"/>
18+
</Window.CommandBindings>
19+
<Window.InputBindings>
20+
<KeyBinding Key="O" Modifiers="Control" Command="Open"/>
21+
<KeyBinding Key="N" Modifiers="Control" Command="New"/>
22+
</Window.InputBindings>
1523
<StackPanel>
1624
<Menu>
1725
<Menu.ItemsPanel>
@@ -20,8 +28,12 @@
2028
</ItemsPanelTemplate>
2129
</Menu.ItemsPanel>
2230
<MenuItem Header="_Open database"
31+
Command="Open"
32+
InputGestureText="Ctrl+O"
2333
Click="_openDatabase_MenuItem_Click"/>
2434
<MenuItem Header="_New User"
35+
Command="New"
36+
InputGestureText="Ctrl+N"
2537
Click="_newUser_MenuItem_Click"/>
2638
<MenuItem Header="_Generate random Password"
2739
HorizontalAlignment="Right"

GUI/WPF/MainWindow.xaml.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
using System.Windows.Input;
55
using System.Windows.Threading;
66
using Upsilon.Apps.Passkey.Core.Models;
7-
using Upsilon.Apps.Passkey.GUI.WPF.Themes;
7+
using Upsilon.Apps.Passkey.GUI.WPF.Helper;
88
using Upsilon.Apps.Passkey.GUI.WPF.ViewModels;
99
using Upsilon.Apps.Passkey.GUI.WPF.Views;
1010

@@ -30,7 +30,6 @@ public MainWindow()
3030
};
3131

3232
_resetCredentials();
33-
MainViewModel.Database = null;
3433

3534
try
3635
{
@@ -46,12 +45,13 @@ public MainWindow()
4645
_username_TB.KeyUp += _credential_TB_KeyUp;
4746
_password_PB.KeyUp += _credential_TB_KeyUp;
4847
_timer.Tick += _timer_Elapsed;
49-
Loaded += (s, e) => DarkMode.SetDarkMode(this);
48+
Loaded += (s, e) => this.PostLoadSetup();
5049
}
5150

5251
private void _timer_Elapsed(object? sender, EventArgs e)
5352
{
5453
_resetCredentials();
54+
MainViewModel.Database?.Close();
5555
MainViewModel.Database = null;
5656
}
5757

@@ -143,6 +143,7 @@ private void _credential_TB_KeyUp(object sender, KeyEventArgs e)
143143
else if (e.Key == Key.Escape)
144144
{
145145
_resetCredentials();
146+
MainViewModel.Database?.Close();
146147
MainViewModel.Database = null;
147148
}
148149
else
@@ -154,6 +155,8 @@ private void _credential_TB_KeyUp(object sender, KeyEventArgs e)
154155

155156
private void _database_AutoSaveDetected(object? sender, Interfaces.Events.AutoSaveDetectedEventArgs e)
156157
{
158+
Hide();
159+
157160
MessageBoxResult result = MessageBox.Show("Unsaved changes have been detected.\nClick Yes to apply these changes.\nClick No to discard them.\nClick Cancel to ignore and keep the save file.", "Autosave detected", MessageBoxButton.YesNoCancel, MessageBoxImage.Question);
158161

159162
e.MergeBehavior = result switch

GUI/WPF/ViewModels/Controls/AccountViewModel.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,14 @@ public bool PasswordLeaked
147147
&& MainViewModel.Database.Warnings.Any(x => x.WarningType == WarningType.PasswordLeakedWarning
148148
&& x.Accounts.Contains(Account));
149149

150+
public string[] IdentifierAutoCompleteList => MainViewModel.User?.Services
151+
.SelectMany(x => x.Accounts)
152+
.SelectMany(x => x.Identifiers)
153+
.Distinct()
154+
.Where(x => !string.IsNullOrEmpty(x))
155+
.OrderBy(x => x)
156+
.ToArray() ?? [];
157+
150158
public event PropertyChangedEventHandler? PropertyChanged;
151159

152160
protected virtual void OnPropertyChanged(string propertyName)

GUI/WPF/ViewModels/Controls/IdentifiantViewModel.cs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,6 @@ public class IdentifierViewModel : INotifyPropertyChanged
1111
private readonly IAccount _account;
1212

1313
public Brush IdentifierBackground => _account.HasChanged("Identifiers") ? DarkMode.ChangedBrush : DarkMode.UnchangedBrush2;
14-
public string[] IdentifierAutoCompleteList => _account.Database.User?.Services
15-
.SelectMany(x => x.Accounts)
16-
.SelectMany(x => x.Identifiers)
17-
.Distinct()
18-
.OrderBy(x => x)
19-
.ToArray() ?? [];
2014

2115
public string Identifier
2216
{
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
using System.Collections.ObjectModel;
2+
using System.ComponentModel;
3+
using Upsilon.Apps.Passkey.GUI.WPF.Helper;
4+
5+
namespace Upsilon.Apps.Passkey.GUI.WPF.ViewModels
6+
{
7+
internal class InsertIdentifierViewModel(IEnumerable<string> identifiers, string identifier) : INotifyPropertyChanged
8+
{
9+
private readonly string[] _identifiers = [.. identifiers];
10+
11+
public ObservableCollection<string> Identifiers = [.. identifiers.Where(x => x.StartsWith(identifier.Trim(), StringComparison.CurrentCultureIgnoreCase)),
12+
.. identifiers.Where(x => x.Contains(identifier.Trim(), StringComparison.CurrentCultureIgnoreCase)
13+
&& !x.StartsWith(identifier.Trim(), StringComparison.CurrentCultureIgnoreCase))];
14+
15+
public string Identifier
16+
{
17+
get => field.Trim();
18+
set
19+
{
20+
PropertyHelper.SetProperty(ref field, value.Trim(), this, PropertyChanged);
21+
_refreshFilter();
22+
}
23+
} = identifier;
24+
25+
public event PropertyChangedEventHandler? PropertyChanged;
26+
27+
protected virtual void OnPropertyChanged(string propertyName)
28+
{
29+
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
30+
}
31+
32+
private void _refreshFilter()
33+
{
34+
Identifiers.Clear();
35+
36+
string[] identifiers = [.. _identifiers.Where(x => x.StartsWith(Identifier, StringComparison.CurrentCultureIgnoreCase)),
37+
.. _identifiers.Where(x => x.Contains(Identifier, StringComparison.CurrentCultureIgnoreCase)
38+
&& !x.StartsWith(Identifier, StringComparison.CurrentCultureIgnoreCase))];
39+
40+
foreach (string identifier in identifiers)
41+
{
42+
Identifiers.Add(identifier);
43+
}
44+
}
45+
}
46+
}

GUI/WPF/ViewModels/MainViewModel.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public static string AppTitle
1616
get
1717
{
1818
System.Reflection.AssemblyName package = System.Reflection.Assembly.GetExecutingAssembly().GetName();
19-
string? packageVersion = package.Version?.ToString(2);
19+
string? packageVersion = package.Version?.ToString(3);
2020

2121
return $"{package.Name} v{packageVersion}";
2222
}

GUI/WPF/ViewModels/UserActivitiesViewModel.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,16 +101,25 @@ public UserActivitiesViewModel()
101101
RefreshFilters();
102102
}
103103

104+
private bool _locked = false;
104105
public void ClearFilters()
105106
{
107+
_locked = true;
108+
106109
FromDateFilter = ToDateFilter = DateTime.Now.Date.AddDays(1);
107110
EventType = ActivityEventType.None;
108111
Message = string.Empty;
109112
NeedsReview = false;
113+
114+
_locked = false;
115+
116+
RefreshFilters();
110117
}
111118

112119
public void RefreshFilters(string itemId = "")
113120
{
121+
if (_locked) return;
122+
114123
Activities.Clear();
115124

116125
if (MainViewModel.Database?.Activities is null) return;

GUI/WPF/Views/AccountPasswordsWarningView.xaml.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
using System.Windows;
22
using Upsilon.Apps.Passkey.GUI.WPF.Helper;
3-
using Upsilon.Apps.Passkey.GUI.WPF.Themes;
43
using Upsilon.Apps.Passkey.GUI.WPF.ViewModels;
54
using Upsilon.Apps.Passkey.Interfaces.Enums;
65

@@ -28,7 +27,7 @@ internal AccountPasswordsWarningView(WarningType warningType)
2827

2928
_warnings_DGV.ItemsSource = _viewModel.Warnings;
3029

31-
Loaded += (s, e) => DarkMode.SetDarkMode(this);
30+
Loaded += (s, e) => this.PostLoadSetup();
3231
}
3332

3433
private void _filterClear_Button_Click(object sender, RoutedEventArgs e)

0 commit comments

Comments
 (0)