Implemented proper viewModels
This commit is contained in:
@@ -15,7 +15,8 @@ class Program
|
|||||||
var application = Adw.Application.New("org.typomustakes.keychain", Gio.ApplicationFlags.FlagsNone);
|
var application = Adw.Application.New("org.typomustakes.keychain", Gio.ApplicationFlags.FlagsNone);
|
||||||
application.OnActivate += (sender, args) =>
|
application.OnActivate += (sender, args) =>
|
||||||
{
|
{
|
||||||
var window = new UI.MainWindow().Window;
|
var passwordStoreService = provider.GetRequiredService<IPasswordStoreService>();
|
||||||
|
var window = new UI.MainWindow(passwordStoreService).Window;
|
||||||
window.Application = (Adw.Application)sender;
|
window.Application = (Adw.Application)sender;
|
||||||
window.Show();
|
window.Show();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,59 +1,109 @@
|
|||||||
using Adw;
|
using Adw;
|
||||||
|
using Keychain.ViewModels;
|
||||||
|
|
||||||
namespace Keychain.UI;
|
namespace Keychain.UI;
|
||||||
|
|
||||||
public class AddShortcutWindow
|
public class AddShortcutWindow
|
||||||
{
|
{
|
||||||
|
private readonly PasswordStoreShortcutCollection shortcuts;
|
||||||
public Dialog Dialog { get; }
|
public Dialog Dialog { get; }
|
||||||
|
private const string dialogId = "add_shortcut_dialog";
|
||||||
private Gtk.Button? closeButton;
|
private Gtk.Button? closeButton;
|
||||||
|
private const string closeButtonId = "close_button";
|
||||||
private Gtk.Button? iconPickerButton;
|
private Gtk.Button? iconPickerButton;
|
||||||
|
private const string iconPickerButtonId = "icon_picker_button";
|
||||||
|
private EntryRow? displayNameEntryRow;
|
||||||
|
private const string displayNameEntryRowId = "display_name_entry_row";
|
||||||
|
private ActionRow? folderActionRow;
|
||||||
|
private const string folderActionRowId = "folder_action_row";
|
||||||
private Gtk.Button? browseButton;
|
private Gtk.Button? browseButton;
|
||||||
|
private const string browseButtonId = "folder_browse_button";
|
||||||
private Gtk.Button? clearSelectedFolderButton;
|
private Gtk.Button? clearSelectedFolderButton;
|
||||||
|
private const string clearSelectedFolderButtonId = "clear_selected_folder_button";
|
||||||
private Gtk.Button? saveButton;
|
private Gtk.Button? saveButton;
|
||||||
|
private const string saveButtonId = "save_button";
|
||||||
|
|
||||||
public AddShortcutWindow()
|
public AddShortcutWindow(PasswordStoreShortcutCollection shortcuts)
|
||||||
{
|
{
|
||||||
|
this.shortcuts = shortcuts;
|
||||||
var builder = new Gtk.Builder("Keychain.UI.AddShortcutWindow.AddShortcutWindow.xml");
|
var builder = new Gtk.Builder("Keychain.UI.AddShortcutWindow.AddShortcutWindow.xml");
|
||||||
|
|
||||||
Dialog = builder.GetObject("add_shortcut_dialog") as Dialog;
|
Dialog = builder.GetObject(dialogId) as Dialog;
|
||||||
if (Dialog == null)
|
if (Dialog == null)
|
||||||
{
|
{
|
||||||
throw new Exception("Failed to load embedded resource AddShortcutWindow.xml");
|
throw new NullReferenceException("Failed to load embedded resource AddShortcutWindow.xml");
|
||||||
}
|
}
|
||||||
|
|
||||||
closeButton = builder.GetObject("close_button") as Gtk.Button;
|
try
|
||||||
if (closeButton == null)
|
|
||||||
{
|
{
|
||||||
throw new Exception("Failed to load UI element with ID: close_button");
|
|
||||||
}
|
|
||||||
closeButton.OnClicked += Close;
|
|
||||||
|
|
||||||
iconPickerButton = builder.GetObject("icon_picker_button") as Gtk.Button;
|
closeButton = builder.GetObject(closeButtonId) as Gtk.Button;
|
||||||
if (iconPickerButton == null)
|
if (closeButton == null)
|
||||||
{
|
{
|
||||||
throw new Exception("Failed to load UI element with ID: icon_picker_button");
|
throw new NullReferenceException(closeButtonId);
|
||||||
}
|
}
|
||||||
iconPickerButton.OnClicked += OpenIconPicker;
|
closeButton.OnClicked += Close;
|
||||||
|
|
||||||
clearSelectedFolderButton = builder.GetObject("clear_selected_folder_button") as Gtk.Button;
|
iconPickerButton = builder.GetObject(iconPickerButtonId) as Gtk.Button;
|
||||||
if (clearSelectedFolderButton == null)
|
if (iconPickerButton == null)
|
||||||
{
|
{
|
||||||
throw new Exception("Failed to load UI element with ID: icon_picker_button");
|
throw new NullReferenceException(iconPickerButtonId);
|
||||||
}
|
}
|
||||||
clearSelectedFolderButton.OnClicked += ClearSelectedFolder;
|
iconPickerButton.OnClicked += OpenIconPicker;
|
||||||
|
|
||||||
browseButton = builder.GetObject("folder_browse_button") as Gtk.Button;
|
displayNameEntryRow = builder.GetObject(displayNameEntryRowId) as EntryRow;
|
||||||
if (browseButton == null)
|
if (displayNameEntryRow == null)
|
||||||
{
|
{
|
||||||
throw new Exception("Failed to load UI element with ID: folder_browse_button");
|
throw new NullReferenceException(displayNameEntryRowId);
|
||||||
}
|
}
|
||||||
browseButton.OnClicked += BrowseFolder;
|
|
||||||
|
|
||||||
saveButton = builder.GetObject("save_button") as Gtk.Button;
|
folderActionRow = builder.GetObject(folderActionRowId) as ActionRow;
|
||||||
if (saveButton == null)
|
if (folderActionRow == null)
|
||||||
{
|
{
|
||||||
throw new Exception("Failed to load UI element with ID: save_button");
|
throw new NullReferenceException(folderActionRowId);
|
||||||
|
}
|
||||||
|
|
||||||
|
clearSelectedFolderButton = builder.GetObject(clearSelectedFolderButtonId) as Gtk.Button;
|
||||||
|
if (clearSelectedFolderButton == null)
|
||||||
|
{
|
||||||
|
throw new NullReferenceException(clearSelectedFolderButtonId);
|
||||||
|
}
|
||||||
|
clearSelectedFolderButton.OnClicked += ClearSelectedFolder;
|
||||||
|
|
||||||
|
browseButton = builder.GetObject(browseButtonId) as Gtk.Button;
|
||||||
|
if (browseButton == null)
|
||||||
|
{
|
||||||
|
throw new NullReferenceException(browseButtonId);
|
||||||
|
}
|
||||||
|
browseButton.OnClicked += BrowseFolder;
|
||||||
|
|
||||||
|
saveButton = builder.GetObject(saveButtonId) as Gtk.Button;
|
||||||
|
if (saveButton == null)
|
||||||
|
{
|
||||||
|
throw new NullReferenceException(saveButtonId);
|
||||||
|
}
|
||||||
|
saveButton.OnClicked += (sender, e) => CreateShortcut();
|
||||||
}
|
}
|
||||||
|
catch (NullReferenceException e)
|
||||||
|
{
|
||||||
|
throw new Exception($"Failed to load UI element: {e.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateShortcut()
|
||||||
|
{
|
||||||
|
if (displayNameEntryRow == null || browseButton == null || iconPickerButton == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var displayName = displayNameEntryRow.GetText();
|
||||||
|
var path = ((ButtonContent)browseButton.Child).Label;
|
||||||
|
var iconName = iconPickerButton.Label;
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(displayName) || path.Equals("Browse") || string.IsNullOrWhiteSpace(path) || string.IsNullOrWhiteSpace(iconName))
|
||||||
|
return;
|
||||||
|
|
||||||
|
shortcuts.Add(path, displayName, iconName);
|
||||||
|
Dialog.Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OpenIconPicker(object sender, EventArgs e)
|
private void OpenIconPicker(object sender, EventArgs e)
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
<child>
|
<child>
|
||||||
<object class="AdwPreferencesGroup">
|
<object class="AdwPreferencesGroup">
|
||||||
<child>
|
<child>
|
||||||
<object class="AdwEntryRow">
|
<object class="AdwEntryRow" id="display_name_entry_row">
|
||||||
<property name="title" translatable="yes" context="Input field placeholder" comments="Noun. Tells the user that the display name of the new password store is to be supplied here">Name</property>
|
<property name="title" translatable="yes" context="Input field placeholder" comments="Noun. Tells the user that the display name of the new password store is to be supplied here">Name</property>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
@@ -51,7 +51,7 @@
|
|||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="AdwActionRow">
|
<object class="AdwActionRow" id="folder_action_row">
|
||||||
<property name="title" translatable="yes" context="Label" comments="Noun. Marks a button that allows the user to pick a folder where the new store will be.">Location</property>
|
<property name="title" translatable="yes" context="Label" comments="Noun. Marks a button that allows the user to pick a folder where the new store will be.">Location</property>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkBox">
|
<object class="GtkBox">
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using Adw;
|
using Adw;
|
||||||
using Keychain.ViewModels;
|
using Keychain.ViewModels;
|
||||||
|
using Logic;
|
||||||
|
|
||||||
namespace Keychain.UI;
|
namespace Keychain.UI;
|
||||||
|
|
||||||
@@ -12,6 +13,8 @@ public class MainWindow
|
|||||||
private Gtk.Stack titleStack;
|
private Gtk.Stack titleStack;
|
||||||
private Gtk.SearchEntry searchEntry;
|
private Gtk.SearchEntry searchEntry;
|
||||||
|
|
||||||
|
private readonly IPasswordStoreService passwordStoreService;
|
||||||
|
|
||||||
private readonly string windowId = "main_window";
|
private readonly string windowId = "main_window";
|
||||||
private readonly string shortcutsGroupId = "shortcuts_group";
|
private readonly string shortcutsGroupId = "shortcuts_group";
|
||||||
private readonly string addShortcutButtonId = "add_shortcut_button";
|
private readonly string addShortcutButtonId = "add_shortcut_button";
|
||||||
@@ -19,8 +22,9 @@ public class MainWindow
|
|||||||
private readonly string titleStackId = "title_stack";
|
private readonly string titleStackId = "title_stack";
|
||||||
private readonly string searchEntryId = "search_entry";
|
private readonly string searchEntryId = "search_entry";
|
||||||
|
|
||||||
public MainWindow()
|
public MainWindow(IPasswordStoreService passwordStoreService)
|
||||||
{
|
{
|
||||||
|
this.passwordStoreService = passwordStoreService;
|
||||||
var builder = new Gtk.Builder("Keychain.UI.MainWindow.MainWindow.xml");
|
var builder = new Gtk.Builder("Keychain.UI.MainWindow.MainWindow.xml");
|
||||||
|
|
||||||
|
|
||||||
@@ -74,38 +78,27 @@ public class MainWindow
|
|||||||
throw new Exception("Failed to load UI element with ID: " + e.Message);
|
throw new Exception("Failed to load UI element with ID: " + e.Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize the observable collection with property binding
|
// Initialize the observable collection with property binding
|
||||||
shortcuts = new PasswordStoreShortcutCollection(shortcutsGroup);
|
shortcuts = new PasswordStoreShortcutCollection(shortcutsGroup, passwordStoreService);
|
||||||
|
|
||||||
LoadDefaultShortcuts();
|
LoadDefaultShortcuts();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnAddShortcutClicked(object sender, EventArgs e)
|
private void OnAddShortcutClicked(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
var dialog = new AddShortcutWindow().Dialog;
|
var dialog = new AddShortcutWindow(shortcuts).Dialog;
|
||||||
dialog.Present(Window);
|
dialog.Present(Window);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddShortcut(string path)
|
|
||||||
{
|
|
||||||
var newShortcut = new PasswordStoreShortcut(path: path);
|
|
||||||
shortcuts.Add(newShortcut); // This will automatically update the UI
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RemoveShortcut(PasswordStoreViewModel shortcut)
|
|
||||||
{
|
|
||||||
shortcuts.Remove(shortcut); // This will automatically update the UI
|
|
||||||
}
|
|
||||||
|
|
||||||
private void LoadDefaultShortcuts()
|
private void LoadDefaultShortcuts()
|
||||||
{
|
{
|
||||||
shortcuts.Add(new PasswordStoreShortcut(displayName: "Default", path: Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + "/.password_store"));
|
shortcuts.Add(new PasswordStoreViewModel(displayName: "Default", path: Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + "/.password_store"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateShortcutName(PasswordStoreViewModel shortcut, string newName)
|
// private void UpdateShortcutName(PasswordStoreViewModel shortcut, string newName)
|
||||||
{
|
// {
|
||||||
shortcut.DisplayName = newName; // This will automatically update the UI row
|
// shortcut.DisplayName = newName; // This will automatically update the UI row
|
||||||
}
|
// }
|
||||||
|
|
||||||
private void SetSearchBarVisible(object sender, EventArgs e)
|
private void SetSearchBarVisible(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,17 +2,22 @@ namespace Keychain.ViewModels;
|
|||||||
|
|
||||||
using Adw;
|
using Adw;
|
||||||
using Gtk;
|
using Gtk;
|
||||||
|
using Logic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Collections.Specialized;
|
using System.Collections.Specialized;
|
||||||
|
|
||||||
public class PasswordStoreShortcutCollection : ObservableCollection<PasswordStoreViewModel>
|
public class PasswordStoreShortcutCollection : ObservableCollection<PasswordStoreViewModel>
|
||||||
{
|
{
|
||||||
|
private IPasswordStoreService _passwordStoreService;
|
||||||
|
|
||||||
private readonly PreferencesGroup shortcutsGroup;
|
private readonly PreferencesGroup shortcutsGroup;
|
||||||
private readonly Dictionary<PasswordStoreViewModel, ActionRow> itemToRowMap = new();
|
private readonly Dictionary<PasswordStoreViewModel, ActionRow> itemToRowMap = new();
|
||||||
|
|
||||||
public PasswordStoreShortcutCollection(PreferencesGroup shortcutsGroup)
|
public PasswordStoreShortcutCollection(PreferencesGroup shortcutsGroup, IPasswordStoreService passwordStoreService)
|
||||||
|
: base()
|
||||||
{
|
{
|
||||||
this.shortcutsGroup = shortcutsGroup;
|
this.shortcutsGroup = shortcutsGroup;
|
||||||
|
_passwordStoreService = passwordStoreService;
|
||||||
CollectionChanged += OnCollectionChanged;
|
CollectionChanged += OnCollectionChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,7 +64,8 @@ public class PasswordStoreShortcutCollection : ObservableCollection<PasswordStor
|
|||||||
UpdateRowFromItem(shortcut, ref row);
|
UpdateRowFromItem(shortcut, ref row);
|
||||||
|
|
||||||
row.SetActivatable(true);
|
row.SetActivatable(true);
|
||||||
row.OnActivated += (sender, args) => {
|
row.OnActivated += (sender, args) =>
|
||||||
|
{
|
||||||
Console.WriteLine($"[DEBUG] Opening: {shortcut.Path}");
|
Console.WriteLine($"[DEBUG] Opening: {shortcut.Path}");
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -91,4 +97,11 @@ public class PasswordStoreShortcutCollection : ObservableCollection<PasswordStor
|
|||||||
edit.IconName = "document-edit-symbolic";
|
edit.IconName = "document-edit-symbolic";
|
||||||
row.AddSuffix(edit);
|
row.AddSuffix(edit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Add(string path, string? displayName = null, string? iconName = null)
|
||||||
|
{
|
||||||
|
PasswordStoreViewModel item = new PasswordStoreViewModel(path, displayName, iconName);
|
||||||
|
Add(item);
|
||||||
|
_passwordStoreService.Create(item.Model);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -23,8 +23,20 @@ public class PasswordStoreViewModel : INotifyPropertyChanged
|
|||||||
get => _model.Path;
|
get => _model.Path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PasswordStore Model { get => _model; }
|
||||||
|
|
||||||
public PasswordStoreViewModel(PasswordStore item)
|
public PasswordStoreViewModel(PasswordStore item)
|
||||||
{
|
{
|
||||||
_model = item;
|
_model = item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PasswordStoreViewModel(string path, string? displayName = "New Shortcut", string? iconName = "text-x-generic-symbolic")
|
||||||
|
{
|
||||||
|
_model = new PasswordStore
|
||||||
|
{
|
||||||
|
DisplayName = displayName,
|
||||||
|
Path = path,
|
||||||
|
IconName = iconName
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,11 @@ public class PasswordStoreService : IPasswordStoreService
|
|||||||
{
|
{
|
||||||
private readonly IRepository repository;
|
private readonly IRepository repository;
|
||||||
|
|
||||||
|
public PasswordStoreService(IRepository repository)
|
||||||
|
{
|
||||||
|
this.repository = repository;
|
||||||
|
}
|
||||||
|
|
||||||
public void Create(PasswordStore item)
|
public void Create(PasswordStore item)
|
||||||
{
|
{
|
||||||
repository.Create(item);
|
repository.Create(item);
|
||||||
|
|||||||
Reference in New Issue
Block a user