mirror of
https://github.com/KeyKeeperApp/KeyKeeper.git
synced 2026-05-18 22:36:30 +03:00
add group tree display
This commit is contained in:
@@ -20,6 +20,7 @@ public abstract class PassStoreEntry
|
||||
return $"avares://KeyKeeper/Assets/builtin-entry-icon-{IconType}.svg";
|
||||
}
|
||||
}
|
||||
public virtual string DisplayName => Name;
|
||||
|
||||
public void WriteToStream(Stream str)
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using static KeyKeeper.PasswordStore.FileFormatConstants;
|
||||
|
||||
namespace KeyKeeper.PasswordStore;
|
||||
@@ -12,6 +13,16 @@ public class PassStoreEntryGroup : PassStoreEntry, IPassStoreDirectory
|
||||
public Guid? CustomGroupSubtype { get; set; }
|
||||
public List<PassStoreEntry> ChildEntries { get; set; }
|
||||
|
||||
public override string DisplayName => GroupType switch
|
||||
{
|
||||
GROUP_TYPE_DEFAULT => "All Passwords",
|
||||
GROUP_TYPE_FAVOURITES => "Favourites",
|
||||
GROUP_TYPE_ROOT => ":root:",
|
||||
_ => Name
|
||||
};
|
||||
|
||||
public IEnumerable<PassStoreEntryGroup> ChildGroups => ChildEntries.OfType<PassStoreEntryGroup>();
|
||||
|
||||
public PassStoreEntryGroup(Guid id, DateTime createdAt, DateTime modifiedAt,
|
||||
Guid iconType, string name, byte groupType,
|
||||
List<PassStoreEntry>? children = null,
|
||||
|
||||
@@ -269,6 +269,15 @@ public class PassStoreFileAccessor : IPassStore
|
||||
"",
|
||||
GROUP_TYPE_DEFAULT
|
||||
);
|
||||
PassStoreEntryGroup favourites = new(
|
||||
Guid.NewGuid(),
|
||||
DateTime.UtcNow,
|
||||
DateTime.UtcNow,
|
||||
Guid.Empty,
|
||||
"",
|
||||
GROUP_TYPE_FAVOURITES
|
||||
);
|
||||
|
||||
PassStoreEntryGroup root = new(
|
||||
Guid.NewGuid(),
|
||||
DateTime.UtcNow,
|
||||
@@ -276,9 +285,10 @@ public class PassStoreFileAccessor : IPassStore
|
||||
Guid.Empty,
|
||||
"",
|
||||
GROUP_TYPE_ROOT,
|
||||
[defaultGroup]
|
||||
[defaultGroup, favourites]
|
||||
);
|
||||
defaultGroup.Parent = root;
|
||||
favourites.Parent = root;
|
||||
root.WriteToStream(w);
|
||||
return root;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ public class UnlockedRepositoryViewModel : ViewModelBase
|
||||
{
|
||||
private IPassStore passStore;
|
||||
private IPassStoreDirectory currentDirectory;
|
||||
private PassStoreEntryGroup? rootDirectory;
|
||||
private bool hasUnsavedChanges;
|
||||
private DispatcherTimer? _totpRefreshTimer;
|
||||
private Dictionary<Guid, string> _totpCodes = new();
|
||||
@@ -25,6 +26,31 @@ public class UnlockedRepositoryViewModel : ViewModelBase
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<PassStoreEntryGroup> PasswordGroups
|
||||
{
|
||||
get
|
||||
{
|
||||
if (rootDirectory == null) return [];
|
||||
return rootDirectory
|
||||
.Where(entry => entry is PassStoreEntryGroup)
|
||||
.Select(entry => (entry as PassStoreEntryGroup)!);
|
||||
}
|
||||
}
|
||||
public PassStoreEntryGroup SelectedPasswordGroup
|
||||
{
|
||||
get
|
||||
{
|
||||
return PasswordGroups.First(group => group == currentDirectory);
|
||||
}
|
||||
set
|
||||
{
|
||||
if (PasswordGroups.Any(group => group == value))
|
||||
{
|
||||
ChangeDirectory(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasUnsavedChanges
|
||||
{
|
||||
get => hasUnsavedChanges;
|
||||
@@ -39,6 +65,7 @@ public class UnlockedRepositoryViewModel : ViewModelBase
|
||||
{
|
||||
passStore = store;
|
||||
currentDirectory = directory;
|
||||
rootDirectory = (directory as PassStoreEntryGroup)?.Parent;
|
||||
HasUnsavedChanges = false;
|
||||
InitializeTotpCodes();
|
||||
StartTotpRefreshTimer();
|
||||
@@ -88,6 +115,19 @@ public class UnlockedRepositoryViewModel : ViewModelBase
|
||||
HasUnsavedChanges = false;
|
||||
}
|
||||
|
||||
private void ChangeDirectory(PassStoreEntryGroup newDir)
|
||||
{
|
||||
if (newDir == currentDirectory)
|
||||
return;
|
||||
|
||||
currentDirectory = newDir;
|
||||
InitializeTotpCodes();
|
||||
StartTotpRefreshTimer();
|
||||
|
||||
OnPropertyChanged(nameof(SelectedPasswordGroup));
|
||||
OnPropertyChanged(nameof(Passwords));
|
||||
}
|
||||
|
||||
private void InitializeTotpCodes()
|
||||
{
|
||||
_totpCodes.Clear();
|
||||
@@ -102,6 +142,10 @@ public class UnlockedRepositoryViewModel : ViewModelBase
|
||||
// Calculate time until next TOTP period boundary
|
||||
int secondsUntilNextCode = CalculateSecondsUntilNextTotpRefresh();
|
||||
|
||||
if (_totpRefreshTimer != null)
|
||||
{
|
||||
_totpRefreshTimer.Stop();
|
||||
}
|
||||
_totpRefreshTimer = new DispatcherTimer
|
||||
{
|
||||
Interval = TimeSpan.FromSeconds(secondsUntilNextCode)
|
||||
|
||||
@@ -56,22 +56,23 @@
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- Рамочка -->
|
||||
<!-- <Border BorderBrush="Gray"
|
||||
BorderThickness="1"
|
||||
CornerRadius="5"
|
||||
Padding="20"
|
||||
Background="#F5F5F5"
|
||||
HorizontalAlignment="Left">
|
||||
<!-- Группы паролей -->
|
||||
<TreeView x:Name="GroupTree"
|
||||
ItemsSource="{Binding PasswordGroups}"
|
||||
SelectedItem="{Binding SelectedPasswordGroup}"
|
||||
Background="#FFFFFFFF"
|
||||
SelectionMode="Single" >
|
||||
<TreeView.ItemTemplate>
|
||||
<TreeDataTemplate ItemsSource="{Binding ChildGroups}">
|
||||
<Border Background="Transparent"
|
||||
DoubleTapped="Entry_DoubleTapped">
|
||||
<TextBlock Text="{Binding DisplayName}"
|
||||
Foreground="Black" />
|
||||
</Border>
|
||||
</TreeDataTemplate>
|
||||
</TreeView.ItemTemplate>
|
||||
</TreeView>
|
||||
|
||||
<StackPanel HorizontalAlignment="Left">
|
||||
<Button Content="All Passwords"
|
||||
Width="120"
|
||||
Height="30"
|
||||
HorizontalAlignment="Left"/>
|
||||
</StackPanel>
|
||||
|
||||
</Border> -->
|
||||
<!-- Save Passwords -->
|
||||
<Button Content="Save Passwords"
|
||||
Classes="accentSidebarButton"
|
||||
|
||||
Reference in New Issue
Block a user