Sidebar shortcuts bound
This commit is contained in:
@@ -1,21 +1,69 @@
|
||||
using Adw;
|
||||
using App.UI.Models;
|
||||
|
||||
namespace App.UI;
|
||||
|
||||
public class MainWindow
|
||||
{
|
||||
public Adw.Window Window { get; }
|
||||
public Window Window { get; }
|
||||
private PreferencesGroup shortcutsGroup;
|
||||
private PasswordStoreShortcutCollection shortcuts;
|
||||
|
||||
public MainWindow()
|
||||
{
|
||||
var assembly = typeof(MainWindow).Assembly;
|
||||
using var stream = assembly.GetManifestResourceStream("App.UI.MainWindow.xml");
|
||||
if (stream == null)
|
||||
throw new Exception("Failed to load embedded resource MainWindow.xml");
|
||||
using var reader = new System.IO.StreamReader(stream);
|
||||
var xml = reader.ReadToEnd();
|
||||
var builder = Gtk.Builder.NewFromString(xml, -1);
|
||||
var window = builder.GetObject("main_window") as Adw.Window;
|
||||
var builder = new Gtk.Builder("App.UI.MainWindow.xml");
|
||||
|
||||
var window = builder.GetObject("main_window") as Window;
|
||||
if (window == null)
|
||||
throw new Exception("Failed to load main_window from MainWindow.ui");
|
||||
{
|
||||
throw new Exception("Failed to load embedded resource MainWindow.xml");
|
||||
}
|
||||
Window = window;
|
||||
|
||||
var group = builder.GetObject("shortcuts_group") as PreferencesGroup;
|
||||
if (group == null)
|
||||
{
|
||||
throw new Exception("Failed to load UI element with ID: shortcuts_group");
|
||||
}
|
||||
shortcutsGroup = group;
|
||||
|
||||
var addButton = builder.GetObject("add_shortcut_button") as ActionRow;
|
||||
if (addButton == null)
|
||||
{
|
||||
throw new Exception("Failed to load UI element with ID: add_shortcut_button");
|
||||
}
|
||||
addButton.OnActivated += OnAddShortcutClicked;
|
||||
|
||||
// Initialize the observable collection with property binding
|
||||
shortcuts = new PasswordStoreShortcutCollection(shortcutsGroup);
|
||||
|
||||
LoadDefaultShortcuts();
|
||||
}
|
||||
|
||||
private void OnAddShortcutClicked(object sender, EventArgs e)
|
||||
{
|
||||
AddShortcut("/path/to/location");
|
||||
}
|
||||
|
||||
public void AddShortcut(string path)
|
||||
{
|
||||
var newShortcut = new PasswordStoreShortcut(path:path);
|
||||
shortcuts.Add(newShortcut); // This will automatically update the UI
|
||||
}
|
||||
|
||||
public void RemoveShortcut(PasswordStoreShortcut shortcut)
|
||||
{
|
||||
shortcuts.Remove(shortcut); // This will automatically update the UI
|
||||
}
|
||||
|
||||
private void LoadDefaultShortcuts()
|
||||
{
|
||||
shortcuts.Add(new PasswordStoreShortcut(displayName:"Default", path:Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)+"/.password_store"));
|
||||
}
|
||||
|
||||
// Example of reactive property updates
|
||||
public void UpdateShortcutName(PasswordStoreShortcut shortcut, string newName)
|
||||
{
|
||||
shortcut.DisplayName = newName; // This will automatically update the UI row
|
||||
}
|
||||
}
|
||||
@@ -14,23 +14,43 @@
|
||||
</child>
|
||||
<property name="content">
|
||||
<object class="AdwOverlaySplitView" id="split_view">
|
||||
<property name="min-sidebar-width">200</property>
|
||||
<property name="max-sidebar-width">200</property>
|
||||
<property name="min-sidebar-width">250</property>
|
||||
<property name="max-sidebar-width">250</property>
|
||||
<property name="show-sidebar"
|
||||
bind-source="show_sidebar_button"
|
||||
bind-property="active"
|
||||
bind-flags="sync-create|bidirectional"/>
|
||||
<property name="sidebar">
|
||||
<object class="AdwNavigationPage">
|
||||
<property name="title" translatable="yes">Sidebar</property>
|
||||
<property name="title" translatable="yes" context="label" comments="Noun. Marks a list of password collections.">Password stores</property>
|
||||
<property name="child">
|
||||
<object class="AdwToolbarView">
|
||||
<child type="top">
|
||||
<object class="AdwHeaderBar" />
|
||||
</child>
|
||||
<property name="content">
|
||||
<object class="GtkLabel">
|
||||
<property name="label">I am a sidebar</property>
|
||||
<object class="AdwPreferencesPage">
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup" id="shortcuts_group">
|
||||
<!-- Dynamic rows will be added here via model binding -->
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup">
|
||||
<child>
|
||||
<object class="AdwActionRow" id="add_shortcut_button">
|
||||
<property name="title" translatable="yes" context="button" comments="Verb. This button allows the user to add additional password collections.">Add</property>
|
||||
<property name="activatable">True</property>
|
||||
<child type="suffix">
|
||||
<object class="GtkImage">
|
||||
<property name="icon-name">list-add-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
@@ -64,5 +84,5 @@
|
||||
</property>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</object>
|
||||
</interface>
|
||||
50
App/UI/Models/PasswordStoreShortcut.cs
Normal file
50
App/UI/Models/PasswordStoreShortcut.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace App.UI.Models;
|
||||
|
||||
public class PasswordStoreShortcut : INotifyPropertyChanged
|
||||
{
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
|
||||
private string displayName;
|
||||
private bool displayNameSet = false;
|
||||
private string? iconName;
|
||||
private string path;
|
||||
public bool DisplayNameSet { get => displayNameSet; }
|
||||
|
||||
public string DisplayName
|
||||
{
|
||||
get => displayName;
|
||||
set
|
||||
{
|
||||
displayName = value;
|
||||
displayNameSet = true;
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(DisplayName)));
|
||||
}
|
||||
}
|
||||
|
||||
public string? IconName
|
||||
{
|
||||
get => iconName;
|
||||
set { iconName = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IconName))); }
|
||||
}
|
||||
|
||||
public string Path
|
||||
{
|
||||
get => path;
|
||||
}
|
||||
|
||||
public PasswordStoreShortcut(string path, string iconName = "text-x-generic-symbolic", string? displayName = null)
|
||||
{
|
||||
this.path = path;
|
||||
|
||||
this.iconName = iconName;
|
||||
|
||||
this.displayName = path;
|
||||
|
||||
if (displayName != null)
|
||||
{
|
||||
DisplayName = displayName;
|
||||
}
|
||||
}
|
||||
}
|
||||
86
App/UI/Models/PasswordStoreShortcutCollection.cs
Normal file
86
App/UI/Models/PasswordStoreShortcutCollection.cs
Normal file
@@ -0,0 +1,86 @@
|
||||
namespace App.UI.Models;
|
||||
|
||||
using Adw;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Collections.Specialized;
|
||||
|
||||
public class PasswordStoreShortcutCollection : ObservableCollection<PasswordStoreShortcut>
|
||||
{
|
||||
private readonly PreferencesGroup shortcutsGroup;
|
||||
private readonly Dictionary<PasswordStoreShortcut, ActionRow> itemToRowMap = new();
|
||||
|
||||
public PasswordStoreShortcutCollection(PreferencesGroup shortcutsGroup)
|
||||
{
|
||||
this.shortcutsGroup = shortcutsGroup;
|
||||
CollectionChanged += OnCollectionChanged;
|
||||
}
|
||||
|
||||
private void OnCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
switch (e.Action)
|
||||
{
|
||||
case NotifyCollectionChangedAction.Add:
|
||||
foreach (PasswordStoreShortcut item in e.NewItems)
|
||||
{
|
||||
var row = CreateShortcutRow(item);
|
||||
itemToRowMap[item] = row;
|
||||
shortcutsGroup.Add(row);
|
||||
|
||||
// Subscribe to property changes for reactive updates
|
||||
item.PropertyChanged += (sender, args) => UpdateRowFromItem(item, ref row);
|
||||
}
|
||||
break;
|
||||
|
||||
case NotifyCollectionChangedAction.Remove:
|
||||
foreach (PasswordStoreShortcut item in e.OldItems)
|
||||
{
|
||||
if (itemToRowMap.TryGetValue(item, out var row))
|
||||
{
|
||||
shortcutsGroup.Remove(row);
|
||||
itemToRowMap.Remove(item);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case NotifyCollectionChangedAction.Reset:
|
||||
foreach (var row in itemToRowMap.Values)
|
||||
{
|
||||
shortcutsGroup.Remove(row);
|
||||
}
|
||||
itemToRowMap.Clear();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private ActionRow CreateShortcutRow(PasswordStoreShortcut shortcut)
|
||||
{
|
||||
var row = new ActionRow();
|
||||
UpdateRowFromItem(shortcut, ref row);
|
||||
|
||||
row.SetActivatable(true);
|
||||
row.OnActivated += (sender, args) => {
|
||||
Console.WriteLine($"[DEBUG] Opening: {shortcut.Path}");
|
||||
};
|
||||
|
||||
return row;
|
||||
}
|
||||
|
||||
private void UpdateRowFromItem(PasswordStoreShortcut shortcut, ref ActionRow row)
|
||||
{
|
||||
row.SetTitle(shortcut.DisplayName);
|
||||
row.SetSubtitle(shortcut.Path);
|
||||
|
||||
//Update icon
|
||||
var existingIcon = row.GetFirstChild() as Gtk.Image;
|
||||
if (existingIcon == null)
|
||||
{
|
||||
var icon = new Gtk.Image();
|
||||
icon.SetFromIconName(shortcut.IconName);
|
||||
row.AddPrefix(icon);
|
||||
}
|
||||
else
|
||||
{
|
||||
existingIcon.SetFromIconName(shortcut.IconName);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user