mirror of
https://github.com/wismna/ModernKeePass.git
synced 2025-10-03 15:40:18 -04:00
More commands/queries
WIP on XAML EntryVm and GroupVm
This commit is contained in:
@@ -54,6 +54,9 @@
|
|||||||
<Compile Include="Common\Interfaces\ISettingsProxy.cs" />
|
<Compile Include="Common\Interfaces\ISettingsProxy.cs" />
|
||||||
<Compile Include="Common\Mappings\IMapFrom.cs" />
|
<Compile Include="Common\Mappings\IMapFrom.cs" />
|
||||||
<Compile Include="Common\Mappings\MappingProfile.cs" />
|
<Compile Include="Common\Mappings\MappingProfile.cs" />
|
||||||
|
<Compile Include="Cryptography\Commands\SetCipher\SetCipherCommand.cs" />
|
||||||
|
<Compile Include="Cryptography\Commands\SetCompression\SetCompressionCommand.cs" />
|
||||||
|
<Compile Include="Cryptography\Commands\SetKeyDerivation\SetKeyDerivationCommand.cs" />
|
||||||
<Compile Include="Cryptography\Models\CipherVm.cs" />
|
<Compile Include="Cryptography\Models\CipherVm.cs" />
|
||||||
<Compile Include="Cryptography\Models\KeyDerivationVm.cs" />
|
<Compile Include="Cryptography\Models\KeyDerivationVm.cs" />
|
||||||
<Compile Include="Cryptography\Queries\GetCiphers\GetCiphersQuery.cs" />
|
<Compile Include="Cryptography\Queries\GetCiphers\GetCiphersQuery.cs" />
|
||||||
@@ -71,6 +74,7 @@
|
|||||||
<Compile Include="Database\Queries\ReOpenDatabase\ReOpenDatabaseQuery.cs" />
|
<Compile Include="Database\Queries\ReOpenDatabase\ReOpenDatabaseQuery.cs" />
|
||||||
<Compile Include="DependencyInjection.cs" />
|
<Compile Include="DependencyInjection.cs" />
|
||||||
<Compile Include="Entry\Commands\SetFieldValue\SetFieldValueCommand.cs" />
|
<Compile Include="Entry\Commands\SetFieldValue\SetFieldValueCommand.cs" />
|
||||||
|
<Compile Include="Entry\Commands\SetFieldValue\SetFieldValueCommandValidator.cs" />
|
||||||
<Compile Include="Entry\Models\EntryVm.cs" />
|
<Compile Include="Entry\Models\EntryVm.cs" />
|
||||||
<Compile Include="Group\Commands\AddEntry\AddEntryCommand.cs" />
|
<Compile Include="Group\Commands\AddEntry\AddEntryCommand.cs" />
|
||||||
<Compile Include="Group\Commands\AddGroup\AddGroupCommand.cs" />
|
<Compile Include="Group\Commands\AddGroup\AddGroupCommand.cs" />
|
||||||
@@ -78,6 +82,7 @@
|
|||||||
<Compile Include="Group\Commands\CreateGroup\CreateGroupCommand.cs" />
|
<Compile Include="Group\Commands\CreateGroup\CreateGroupCommand.cs" />
|
||||||
<Compile Include="Group\Commands\DeleteEntry\DeleteEntryCommand.cs" />
|
<Compile Include="Group\Commands\DeleteEntry\DeleteEntryCommand.cs" />
|
||||||
<Compile Include="Group\Commands\DeleteGroup\DeleteGroupCommand.cs" />
|
<Compile Include="Group\Commands\DeleteGroup\DeleteGroupCommand.cs" />
|
||||||
|
<Compile Include="Group\Commands\InsertEntry\InsertEntryCommand.cs" />
|
||||||
<Compile Include="Group\Commands\RemoveEntry\RemoveEntryCommand.cs" />
|
<Compile Include="Group\Commands\RemoveEntry\RemoveEntryCommand.cs" />
|
||||||
<Compile Include="Group\Commands\RemoveGroup\RemoveGroupCommand.cs" />
|
<Compile Include="Group\Commands\RemoveGroup\RemoveGroupCommand.cs" />
|
||||||
<Compile Include="Group\Commands\SortEntries\SortEntriesCommand.cs" />
|
<Compile Include="Group\Commands\SortEntries\SortEntriesCommand.cs" />
|
||||||
@@ -102,9 +107,6 @@
|
|||||||
<Folder Include="Entry\Queries\GetEntry\" />
|
<Folder Include="Entry\Queries\GetEntry\" />
|
||||||
<Folder Include="Group\Commands\UpdateGroup\" />
|
<Folder Include="Group\Commands\UpdateGroup\" />
|
||||||
<Folder Include="Group\Queries\GetGroup\" />
|
<Folder Include="Group\Queries\GetGroup\" />
|
||||||
<Folder Include="Parameters\Commands\SetCipher\" />
|
|
||||||
<Folder Include="Parameters\Commands\SetCompression\" />
|
|
||||||
<Folder Include="Parameters\Commands\SetKeyDerivation\" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\ModernKeePass.Domain\Domain.csproj">
|
<ProjectReference Include="..\ModernKeePass.Domain\Domain.csproj">
|
||||||
|
@@ -25,8 +25,9 @@ namespace ModernKeePass.Application.Common.Interfaces
|
|||||||
void CloseDatabase();
|
void CloseDatabase();
|
||||||
|
|
||||||
Task AddEntry(string parentGroupId, string entryId);
|
Task AddEntry(string parentGroupId, string entryId);
|
||||||
|
Task InsertEntry(string parentGroupId, string entryId, int messageIndex);
|
||||||
Task AddGroup(string parentGroupId, string groupId);
|
Task AddGroup(string parentGroupId, string groupId);
|
||||||
void UpdateEntry(string entryId, string fieldName, string fieldValue);
|
void UpdateEntry(string entryId, string fieldName, object fieldValue);
|
||||||
void UpdateGroup(string groupId);
|
void UpdateGroup(string groupId);
|
||||||
Task RemoveEntry(string parentGroupId, string entryId);
|
Task RemoveEntry(string parentGroupId, string entryId);
|
||||||
Task RemoveGroup(string parentGroupId, string groupId);
|
Task RemoveGroup(string parentGroupId, string groupId);
|
||||||
|
@@ -0,0 +1,27 @@
|
|||||||
|
using MediatR;
|
||||||
|
using ModernKeePass.Application.Common.Interfaces;
|
||||||
|
using ModernKeePass.Domain.Exceptions;
|
||||||
|
|
||||||
|
namespace ModernKeePass.Application.Cryptography.Commands.SetCipher
|
||||||
|
{
|
||||||
|
public class SetCipherCommand : IRequest
|
||||||
|
{
|
||||||
|
public string CipherId { get; set; }
|
||||||
|
|
||||||
|
public class SetCipherCommandHandler : IRequestHandler<SetCipherCommand>
|
||||||
|
{
|
||||||
|
private readonly IDatabaseProxy _database;
|
||||||
|
|
||||||
|
public SetCipherCommandHandler(IDatabaseProxy database)
|
||||||
|
{
|
||||||
|
_database = database;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Handle(SetCipherCommand message)
|
||||||
|
{
|
||||||
|
if (_database.IsOpen) _database.CipherId = message.CipherId;
|
||||||
|
else throw new DatabaseClosedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,27 @@
|
|||||||
|
using MediatR;
|
||||||
|
using ModernKeePass.Application.Common.Interfaces;
|
||||||
|
using ModernKeePass.Domain.Exceptions;
|
||||||
|
|
||||||
|
namespace ModernKeePass.Application.Cryptography.Commands.SetCompression
|
||||||
|
{
|
||||||
|
public class SetCompressionCommand : IRequest
|
||||||
|
{
|
||||||
|
public string Compression { get; set; }
|
||||||
|
|
||||||
|
public class SetCompressionCommandHandler : IRequestHandler<SetCompressionCommand>
|
||||||
|
{
|
||||||
|
private readonly IDatabaseProxy _database;
|
||||||
|
|
||||||
|
public SetCompressionCommandHandler(IDatabaseProxy database)
|
||||||
|
{
|
||||||
|
_database = database;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Handle(SetCompressionCommand message)
|
||||||
|
{
|
||||||
|
if (_database.IsOpen) _database.Compression = message.Compression;
|
||||||
|
else throw new DatabaseClosedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,27 @@
|
|||||||
|
using MediatR;
|
||||||
|
using ModernKeePass.Application.Common.Interfaces;
|
||||||
|
using ModernKeePass.Domain.Exceptions;
|
||||||
|
|
||||||
|
namespace ModernKeePass.Application.Cryptography.Commands.SetKeyDerivation
|
||||||
|
{
|
||||||
|
public class SetKeyDerivationCommand : IRequest
|
||||||
|
{
|
||||||
|
public string KeyDerivationId { get; set; }
|
||||||
|
|
||||||
|
public class SetKeyDerivationCommandHandler : IRequestHandler<SetKeyDerivationCommand>
|
||||||
|
{
|
||||||
|
private readonly IDatabaseProxy _database;
|
||||||
|
|
||||||
|
public SetKeyDerivationCommandHandler(IDatabaseProxy database)
|
||||||
|
{
|
||||||
|
_database = database;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Handle(SetKeyDerivationCommand message)
|
||||||
|
{
|
||||||
|
if (_database.IsOpen) _database.KeyDerivationId = message.KeyDerivationId;
|
||||||
|
else throw new DatabaseClosedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -14,7 +14,7 @@ namespace ModernKeePass.Application.Database.Commands.UpdateCredentials
|
|||||||
{
|
{
|
||||||
private readonly IDatabaseProxy _database;
|
private readonly IDatabaseProxy _database;
|
||||||
|
|
||||||
public UpdateCredentialsCommandHandler(IDatabaseProxy database, IMediator mediator)
|
public UpdateCredentialsCommandHandler(IDatabaseProxy database)
|
||||||
{
|
{
|
||||||
_database = database;
|
_database = database;
|
||||||
}
|
}
|
||||||
|
@@ -13,7 +13,7 @@ namespace ModernKeePass.Application
|
|||||||
var assembly = typeof(DependencyInjection).GetTypeInfo().Assembly;
|
var assembly = typeof(DependencyInjection).GetTypeInfo().Assembly;
|
||||||
services.AddAutoMapper(assembly);
|
services.AddAutoMapper(assembly);
|
||||||
services.AddMediatR(assembly);
|
services.AddMediatR(assembly);
|
||||||
//services.AddValidatorsFromAssembly(Assembly.GetExecutingAssembly());
|
//services.AddValidatorsFromAssembly(assembly);
|
||||||
|
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
@@ -8,7 +8,7 @@ namespace ModernKeePass.Application.Entry.Commands.SetFieldValue
|
|||||||
{
|
{
|
||||||
public string EntryId { get; set; }
|
public string EntryId { get; set; }
|
||||||
public string FieldName { get; set; }
|
public string FieldName { get; set; }
|
||||||
public string FieldValue { get; set; }
|
public object FieldValue { get; set; }
|
||||||
|
|
||||||
public class SetFieldValueCommandHandler : IRequestHandler<SetFieldValueCommand>
|
public class SetFieldValueCommandHandler : IRequestHandler<SetFieldValueCommand>
|
||||||
{
|
{
|
||||||
|
@@ -0,0 +1,17 @@
|
|||||||
|
using FluentValidation;
|
||||||
|
|
||||||
|
namespace ModernKeePass.Application.Entry.Commands.SetFieldValue
|
||||||
|
{
|
||||||
|
public class SetFieldValueCommandValidator: AbstractValidator<SetFieldValueCommand>
|
||||||
|
{
|
||||||
|
public SetFieldValueCommandValidator()
|
||||||
|
{
|
||||||
|
RuleFor(v => v.EntryId)
|
||||||
|
.NotNull()
|
||||||
|
.NotEmpty();
|
||||||
|
RuleFor(v => v.FieldName)
|
||||||
|
.NotNull()
|
||||||
|
.NotEmpty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -17,7 +17,7 @@ namespace ModernKeePass.Application.Entry.Models
|
|||||||
public string Notes { get; set; }
|
public string Notes { get; set; }
|
||||||
public Uri Url { get; set; }
|
public Uri Url { get; set; }
|
||||||
public Dictionary<string, string> AdditionalFields { get; set; }
|
public Dictionary<string, string> AdditionalFields { get; set; }
|
||||||
public IEnumerable<EntryEntity> History { get; set; }
|
public IEnumerable<EntryVm> History { get; set; }
|
||||||
public Icon Icon { get; set; }
|
public Icon Icon { get; set; }
|
||||||
public Color ForegroundColor { get; set; }
|
public Color ForegroundColor { get; set; }
|
||||||
public Color BackgroundColor { get; set; }
|
public Color BackgroundColor { get; set; }
|
||||||
|
@@ -0,0 +1,34 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
using MediatR;
|
||||||
|
using ModernKeePass.Application.Common.Interfaces;
|
||||||
|
using ModernKeePass.Application.Entry.Models;
|
||||||
|
using ModernKeePass.Application.Group.Models;
|
||||||
|
using ModernKeePass.Domain.Exceptions;
|
||||||
|
|
||||||
|
namespace ModernKeePass.Application.Group.Commands.InsertEntry
|
||||||
|
{
|
||||||
|
public class InsertEntryCommand : IRequest
|
||||||
|
{
|
||||||
|
public GroupVm ParentGroup { get; set; }
|
||||||
|
public EntryVm Entry { get; set; }
|
||||||
|
public int Index { get; set; }
|
||||||
|
|
||||||
|
public class InsertEntryCommandHandler : IAsyncRequestHandler<InsertEntryCommand>
|
||||||
|
{
|
||||||
|
private readonly IDatabaseProxy _database;
|
||||||
|
|
||||||
|
public InsertEntryCommandHandler(IDatabaseProxy database)
|
||||||
|
{
|
||||||
|
_database = database;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Handle(InsertEntryCommand message)
|
||||||
|
{
|
||||||
|
if (!_database.IsOpen) throw new DatabaseClosedException();
|
||||||
|
|
||||||
|
await _database.InsertEntry(message.ParentGroup.Id, message.Entry.Id, message.Index);
|
||||||
|
message.ParentGroup.Entries.Insert(message.Index, message.Entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -5,6 +5,7 @@ using AutoMapper;
|
|||||||
using ModernKeePass.Application.Common.Interfaces;
|
using ModernKeePass.Application.Common.Interfaces;
|
||||||
using ModernKeePass.Domain.Dtos;
|
using ModernKeePass.Domain.Dtos;
|
||||||
using ModernKeePass.Domain.Entities;
|
using ModernKeePass.Domain.Entities;
|
||||||
|
using ModernKeePass.Domain.Enums;
|
||||||
using ModernKeePass.Domain.Exceptions;
|
using ModernKeePass.Domain.Exceptions;
|
||||||
using ModernKeePassLib;
|
using ModernKeePassLib;
|
||||||
using ModernKeePassLib.Cryptography.KeyDerivation;
|
using ModernKeePassLib.Cryptography.KeyDerivation;
|
||||||
@@ -45,6 +46,7 @@ namespace ModernKeePass.Infrastructure.KeePass
|
|||||||
}
|
}
|
||||||
set { _pwDatabase.RecycleBinUuid = BuildIdFromString(value); }
|
set { _pwDatabase.RecycleBinUuid = BuildIdFromString(value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public string CipherId
|
public string CipherId
|
||||||
{
|
{
|
||||||
get { return _pwDatabase.DataCipherUuid.ToHexString(); }
|
get { return _pwDatabase.DataCipherUuid.ToHexString(); }
|
||||||
@@ -168,6 +170,17 @@ namespace ModernKeePass.Infrastructure.KeePass
|
|||||||
parentPwGroup.AddEntry(pwEntry, true);
|
parentPwGroup.AddEntry(pwEntry, true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task InsertEntry(string parentGroupId, string entryId, int index)
|
||||||
|
{
|
||||||
|
await Task.Run(() =>
|
||||||
|
{
|
||||||
|
var parentPwGroup = _pwDatabase.RootGroup.FindGroup(BuildIdFromString(parentGroupId), true);
|
||||||
|
var pwEntry = _pwDatabase.RootGroup.FindEntry(BuildIdFromString(entryId), true);
|
||||||
|
parentPwGroup.Entries.Insert((uint)index, pwEntry);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public async Task AddGroup(string parentGroupId, string groupId)
|
public async Task AddGroup(string parentGroupId, string groupId)
|
||||||
{
|
{
|
||||||
await Task.Run(() =>
|
await Task.Run(() =>
|
||||||
@@ -197,15 +210,34 @@ namespace ModernKeePass.Infrastructure.KeePass
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateEntry(string entryId, string fieldName, string fieldValue)
|
public void UpdateEntry(string entryId, string fieldName, object fieldValue)
|
||||||
{
|
{
|
||||||
var pwEntry = _pwDatabase.RootGroup.FindEntry(BuildIdFromString(entryId), true);
|
var pwEntry = _pwDatabase.RootGroup.FindEntry(BuildIdFromString(entryId), true);
|
||||||
pwEntry.Touch(true);
|
pwEntry.Touch(true);
|
||||||
pwEntry.CreateBackup(null);
|
pwEntry.CreateBackup(null);
|
||||||
pwEntry.Strings.Set(EntryFieldMapper.MapFieldToPwDef(fieldName), new ProtectedString(true, fieldValue));
|
|
||||||
|
switch (fieldName)
|
||||||
|
{
|
||||||
|
case EntryFieldName.Title:
|
||||||
|
case EntryFieldName.UserName:
|
||||||
|
case EntryFieldName.Password:
|
||||||
|
case EntryFieldName.Notes:
|
||||||
|
case EntryFieldName.Url:
|
||||||
|
pwEntry.Strings.Set(EntryFieldMapper.MapFieldToPwDef(fieldName), new ProtectedString(true, fieldValue.ToString()));
|
||||||
|
break;
|
||||||
|
case EntryFieldName.HasExpirationDate:
|
||||||
|
pwEntry.Expires = (bool)fieldValue;
|
||||||
|
break;
|
||||||
|
case EntryFieldName.ExpirationDate:
|
||||||
|
pwEntry.ExpiryTime = (DateTime)fieldValue;
|
||||||
|
break;
|
||||||
|
case EntryFieldName.Icon:
|
||||||
|
pwEntry.IconId = IconMapper.MapIconToPwIcon((Icon)fieldValue);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateGroup(string group)
|
public void UpdateGroup(string groupId)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
@@ -237,7 +269,7 @@ namespace ModernKeePass.Infrastructure.KeePass
|
|||||||
var id = pwEntry.Uuid;
|
var id = pwEntry.Uuid;
|
||||||
pwEntry.ParentGroup.Entries.Remove(pwEntry);
|
pwEntry.ParentGroup.Entries.Remove(pwEntry);
|
||||||
|
|
||||||
if (_pwDatabase.RecycleBinEnabled)
|
if (!_pwDatabase.RecycleBinEnabled || pwEntry.ParentGroup.Uuid.Equals(_pwDatabase.RecycleBinUuid))
|
||||||
{
|
{
|
||||||
_pwDatabase.DeletedObjects.Add(new PwDeletedObject(id, DateTime.UtcNow));
|
_pwDatabase.DeletedObjects.Add(new PwDeletedObject(id, DateTime.UtcNow));
|
||||||
}
|
}
|
||||||
@@ -252,7 +284,7 @@ namespace ModernKeePass.Infrastructure.KeePass
|
|||||||
var id = pwGroup.Uuid;
|
var id = pwGroup.Uuid;
|
||||||
pwGroup.ParentGroup.Groups.Remove(pwGroup);
|
pwGroup.ParentGroup.Groups.Remove(pwGroup);
|
||||||
|
|
||||||
if (_pwDatabase.RecycleBinEnabled)
|
if (!_pwDatabase.RecycleBinEnabled || pwGroup.ParentGroup.Uuid.Equals(_pwDatabase.RecycleBinUuid))
|
||||||
{
|
{
|
||||||
_pwDatabase.DeletedObjects.Add(new PwDeletedObject(id, DateTime.UtcNow));
|
_pwDatabase.DeletedObjects.Add(new PwDeletedObject(id, DateTime.UtcNow));
|
||||||
}
|
}
|
||||||
|
@@ -1,9 +1,9 @@
|
|||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using Windows.UI.Xaml;
|
using Windows.UI.Xaml;
|
||||||
using Microsoft.Xaml.Interactivity;
|
using Microsoft.Xaml.Interactivity;
|
||||||
|
using ModernKeePass.Application.Resources.Queries;
|
||||||
using ModernKeePass.Common;
|
using ModernKeePass.Common;
|
||||||
using ModernKeePass.Interfaces;
|
using ModernKeePass.Interfaces;
|
||||||
using ModernKeePass.Services;
|
|
||||||
using ModernKeePass.ViewModels;
|
using ModernKeePass.ViewModels;
|
||||||
|
|
||||||
namespace ModernKeePass.Actions
|
namespace ModernKeePass.Actions
|
||||||
@@ -32,19 +32,23 @@ namespace ModernKeePass.Actions
|
|||||||
|
|
||||||
public object Execute(object sender, object parameter)
|
public object Execute(object sender, object parameter)
|
||||||
{
|
{
|
||||||
var resource = new ResourcesService();
|
var mediator = App.Mediator;
|
||||||
var type = Entity is GroupVm ? "Group" : "Entry";
|
var type = Entity is GroupVm ? "Group" : "Entry";
|
||||||
|
|
||||||
var message = Entity.IsRecycleOnDelete
|
var message = Entity.IsRecycleOnDelete
|
||||||
? resource.GetResourceValue($"{type}RecyclingConfirmation")
|
? mediator.Send(new GetResourceQuery { Key = $"{type}RecyclingConfirmation" })
|
||||||
: resource.GetResourceValue($"{type}DeletingConfirmation");
|
: mediator.Send(new GetResourceQuery { Key = $"{type}DeletingConfirmation" });
|
||||||
var text = Entity.IsRecycleOnDelete ? resource.GetResourceValue($"{type}Recycled") : resource.GetResourceValue($"{type}Deleted");
|
var text = Entity.IsRecycleOnDelete ?
|
||||||
MessageDialogHelper.ShowActionDialog(resource.GetResourceValue("EntityDeleteTitle"), message,
|
mediator.Send(new GetResourceQuery { Key = $"{type}Recycled" }) :
|
||||||
resource.GetResourceValue("EntityDeleteActionButton"),
|
mediator.Send(new GetResourceQuery { Key = $"{type}Deleted" });
|
||||||
resource.GetResourceValue("EntityDeleteCancelButton"), a =>
|
MessageDialogHelper.ShowActionDialog(
|
||||||
|
mediator.Send(new GetResourceQuery { Key = "EntityDeleteTitle" }).GetAwaiter().GetResult(),
|
||||||
|
message.GetAwaiter().GetResult(),
|
||||||
|
mediator.Send(new GetResourceQuery { Key = "EntityDeleteActionButton" }).GetAwaiter().GetResult(),
|
||||||
|
mediator.Send(new GetResourceQuery { Key = "EntityDeleteCancelButton" }).GetAwaiter().GetResult(), async a =>
|
||||||
{
|
{
|
||||||
ToastNotificationHelper.ShowMovedToast(Entity, resource.GetResourceValue("EntityDeleting"), text);
|
ToastNotificationHelper.ShowMovedToast(Entity, await mediator.Send(new GetResourceQuery { Key = "EntityDeleting" }), await text);
|
||||||
Entity.MarkForDelete(resource.GetResourceValue("RecycleBinTitle"));
|
await Entity.MarkForDelete(await mediator.Send(new GetResourceQuery { Key = "RecycleBinTitle"}));
|
||||||
Command.Execute(null);
|
Command.Execute(null);
|
||||||
}, null).GetAwaiter();
|
}, null).GetAwaiter();
|
||||||
|
|
||||||
|
@@ -13,7 +13,7 @@ namespace ModernKeePass.Common
|
|||||||
{
|
{
|
||||||
var notificationXml = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastText02);
|
var notificationXml = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastText02);
|
||||||
var toastElements = notificationXml.GetElementsByTagName("text");
|
var toastElements = notificationXml.GetElementsByTagName("text");
|
||||||
toastElements[0].AppendChild(notificationXml.CreateTextNode($"{action} {entity.Name}"));
|
toastElements[0].AppendChild(notificationXml.CreateTextNode($"{action} {entity.Title}"));
|
||||||
toastElements[1].AppendChild(notificationXml.CreateTextNode(text));
|
toastElements[1].AppendChild(notificationXml.CreateTextNode(text));
|
||||||
var toastNode = notificationXml.SelectSingleNode("/toast");
|
var toastNode = notificationXml.SelectSingleNode("/toast");
|
||||||
|
|
||||||
|
@@ -9,9 +9,9 @@ namespace ModernKeePass.Interfaces
|
|||||||
{
|
{
|
||||||
GroupVm ParentGroup { get; }
|
GroupVm ParentGroup { get; }
|
||||||
GroupVm PreviousGroup { get; }
|
GroupVm PreviousGroup { get; }
|
||||||
int IconId { get; }
|
int Icon { get; }
|
||||||
string Id { get; }
|
string Id { get; }
|
||||||
string Name { get; set; }
|
string Title { get; set; }
|
||||||
IEnumerable<IVmEntity> BreadCrumb { get; }
|
IEnumerable<IVmEntity> BreadCrumb { get; }
|
||||||
bool IsEditMode { get; }
|
bool IsEditMode { get; }
|
||||||
bool IsRecycleOnDelete { get; }
|
bool IsRecycleOnDelete { get; }
|
||||||
|
@@ -14,7 +14,7 @@ namespace ModernKeePass.Services
|
|||||||
foreach (var entity in data)
|
foreach (var entity in data)
|
||||||
{
|
{
|
||||||
var entry = group.AddNewEntry();
|
var entry = group.AddNewEntry();
|
||||||
entry.Name = entity["0"];
|
entry.Title = entity["0"];
|
||||||
entry.UserName = entity["1"];
|
entry.UserName = entity["1"];
|
||||||
entry.Password = entity["2"];
|
entry.Password = entity["2"];
|
||||||
if (entity.Count > 3) entry.Url = entity["3"];
|
if (entity.Count > 3) entry.Url = entity["3"];
|
||||||
|
@@ -1,25 +1,27 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
|
using MediatR;
|
||||||
|
using ModernKeePass.Application.Database.Commands.SaveDatabase;
|
||||||
|
using ModernKeePass.Application.Entry.Commands.SetFieldValue;
|
||||||
|
using ModernKeePass.Application.Group.Commands.DeleteEntry;
|
||||||
|
using ModernKeePass.Application.Resources.Queries;
|
||||||
|
using ModernKeePass.Application.Security.Commands.GeneratePassword;
|
||||||
|
using ModernKeePass.Application.Security.Queries.EstimatePasswordComplexity;
|
||||||
using ModernKeePass.Common;
|
using ModernKeePass.Common;
|
||||||
using ModernKeePass.Interfaces;
|
using ModernKeePass.Interfaces;
|
||||||
using ModernKeePass.Services;
|
|
||||||
using ModernKeePassLib;
|
|
||||||
using ModernKeePassLib.Cryptography.PasswordGenerator;
|
|
||||||
using ModernKeePassLib.Security;
|
|
||||||
using ModernKeePassLib.Cryptography;
|
|
||||||
|
|
||||||
namespace ModernKeePass.ViewModels
|
namespace ModernKeePass.ViewModels
|
||||||
{
|
{
|
||||||
public class EntryVm : INotifyPropertyChanged, IVmEntity, ISelectableModel
|
public class EntryVm : NotifyPropertyChangedBase, IVmEntity, ISelectableModel
|
||||||
{
|
{
|
||||||
public GroupVm ParentGroup { get; private set; }
|
public GroupVm ParentGroup { get; private set; }
|
||||||
public GroupVm PreviousGroup { get; private set; }
|
public GroupVm PreviousGroup { get; private set; }
|
||||||
public bool IsRevealPasswordEnabled => !string.IsNullOrEmpty(Password);
|
public bool IsRevealPasswordEnabled => !string.IsNullOrEmpty(Password);
|
||||||
public bool HasExpired => HasExpirationDate && _pwEntry.ExpiryTime < DateTime.Now;
|
public bool HasExpired => HasExpirationDate && ExpiryDate < DateTime.Now;
|
||||||
public double PasswordComplexityIndicator => QualityEstimation.EstimatePasswordBits(Password?.ToCharArray());
|
public double PasswordComplexityIndicator => _mediator.Send(new EstimatePasswordComplexityQuery {Password = Password}).GetAwaiter().GetResult();
|
||||||
public bool UpperCasePatternSelected { get; set; } = true;
|
public bool UpperCasePatternSelected { get; set; } = true;
|
||||||
public bool LowerCasePatternSelected { get; set; } = true;
|
public bool LowerCasePatternSelected { get; set; } = true;
|
||||||
public bool DigitsPatternSelected { get; set; } = true;
|
public bool DigitsPatternSelected { get; set; } = true;
|
||||||
@@ -29,8 +31,7 @@ namespace ModernKeePass.ViewModels
|
|||||||
public bool SpecialPatternSelected { get; set; }
|
public bool SpecialPatternSelected { get; set; }
|
||||||
public bool BracketsPatternSelected { get; set; }
|
public bool BracketsPatternSelected { get; set; }
|
||||||
public string CustomChars { get; set; } = string.Empty;
|
public string CustomChars { get; set; } = string.Empty;
|
||||||
public PwUuid IdUuid => _pwEntry?.Uuid;
|
public string Id => _entry.Id;
|
||||||
public string Id => _pwEntry?.Uuid.ToHexString();
|
|
||||||
public bool IsRecycleOnDelete => _database.RecycleBinEnabled && !ParentGroup.IsSelected;
|
public bool IsRecycleOnDelete => _database.RecycleBinEnabled && !ParentGroup.IsSelected;
|
||||||
public IEnumerable<IVmEntity> BreadCrumb => new List<IVmEntity>(ParentGroup.BreadCrumb) {ParentGroup};
|
public IEnumerable<IVmEntity> BreadCrumb => new List<IVmEntity>(ParentGroup.BreadCrumb) {ParentGroup};
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -44,80 +45,73 @@ namespace ModernKeePass.ViewModels
|
|||||||
set
|
set
|
||||||
{
|
{
|
||||||
_passwordLength = value;
|
_passwordLength = value;
|
||||||
NotifyPropertyChanged("PasswordLength");
|
OnPropertyChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Name
|
public string Title
|
||||||
{
|
{
|
||||||
get { return GetEntryValue(PwDefs.TitleField); }
|
get { return _entry.Title; }
|
||||||
set { SetEntryValue(PwDefs.TitleField, new ProtectedString(true, value)); }
|
set { _mediator.Send(new SetFieldValueCommand { EntryId = Id, FieldName = nameof(Title), FieldValue = value}); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public string UserName
|
public string UserName
|
||||||
{
|
{
|
||||||
get { return GetEntryValue(PwDefs.UserNameField); }
|
get { return _entry.Username; }
|
||||||
set { SetEntryValue(PwDefs.UserNameField, new ProtectedString(true, value)); }
|
set { _mediator.Send(new SetFieldValueCommand { EntryId = Id, FieldName = nameof(UserName), FieldValue = value }); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Password
|
public string Password
|
||||||
{
|
{
|
||||||
get { return GetEntryValue(PwDefs.PasswordField); }
|
get { return _entry.Password; }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
SetEntryValue(PwDefs.PasswordField, new ProtectedString(true, value));
|
_mediator.Send(new SetFieldValueCommand { EntryId = Id, FieldName = nameof(Password), FieldValue = value });
|
||||||
NotifyPropertyChanged("Password");
|
OnPropertyChanged();
|
||||||
NotifyPropertyChanged("PasswordComplexityIndicator");
|
OnPropertyChanged(nameof(PasswordComplexityIndicator));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Url
|
public string Url
|
||||||
{
|
{
|
||||||
get { return GetEntryValue(PwDefs.UrlField); }
|
get { return _entry.Url.ToString();}
|
||||||
set { SetEntryValue(PwDefs.UrlField, new ProtectedString(true, value)); }
|
set { _mediator.Send(new SetFieldValueCommand { EntryId = Id, FieldName = nameof(Url), FieldValue = value }); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Notes
|
public string Notes
|
||||||
{
|
{
|
||||||
get { return GetEntryValue(PwDefs.NotesField); }
|
get { return _entry.Notes; }
|
||||||
set { SetEntryValue(PwDefs.NotesField, new ProtectedString(true, value)); }
|
set { _mediator.Send(new SetFieldValueCommand { EntryId = Id, FieldName = nameof(Notes), FieldValue = value }); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public int IconId
|
public int Icon
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (HasExpired) return (int) PwIcon.Expired;
|
if (HasExpired) return (int)Domain.Enums.Icon.ReportHacked;
|
||||||
if (_pwEntry?.IconId != null) return (int) _pwEntry?.IconId;
|
return (int) _entry.Icon;
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
HandleBackup();
|
|
||||||
_pwEntry.IconId = (PwIcon)value;
|
|
||||||
}
|
}
|
||||||
|
set { _mediator.Send(new SetFieldValueCommand { EntryId = Id, FieldName = nameof(Icon), FieldValue = value }); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public DateTimeOffset ExpiryDate
|
public DateTimeOffset ExpiryDate
|
||||||
{
|
{
|
||||||
get { return new DateTimeOffset(_pwEntry.ExpiryTime.Date); }
|
get { return _entry.ExpirationDate; }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (!HasExpirationDate) return;
|
if (!HasExpirationDate) return;
|
||||||
HandleBackup();
|
_mediator.Send(new SetFieldValueCommand { EntryId = Id, FieldName = "ExpirationDate", FieldValue = value.Date });
|
||||||
_pwEntry.ExpiryTime = value.DateTime;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public TimeSpan ExpiryTime
|
public TimeSpan ExpiryTime
|
||||||
{
|
{
|
||||||
get { return _pwEntry.ExpiryTime.TimeOfDay; }
|
get { return _entry.ExpirationDate.TimeOfDay; }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (!HasExpirationDate) return;
|
if (!HasExpirationDate) return;
|
||||||
HandleBackup();
|
_mediator.Send(new SetFieldValueCommand { EntryId = Id, FieldName = "ExpirationDate", FieldValue = ExpiryDate.Date.Add(value) });
|
||||||
_pwEntry.ExpiryTime = _pwEntry.ExpiryTime.Date.Add(value);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,7 +121,7 @@ namespace ModernKeePass.ViewModels
|
|||||||
set
|
set
|
||||||
{
|
{
|
||||||
_isEditMode = value;
|
_isEditMode = value;
|
||||||
NotifyPropertyChanged("IsEditMode");
|
OnPropertyChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,7 +131,7 @@ namespace ModernKeePass.ViewModels
|
|||||||
set
|
set
|
||||||
{
|
{
|
||||||
_isVisible = value;
|
_isVisible = value;
|
||||||
NotifyPropertyChanged("IsVisible");
|
OnPropertyChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,16 +141,16 @@ namespace ModernKeePass.ViewModels
|
|||||||
set
|
set
|
||||||
{
|
{
|
||||||
_isRevealPassword = value;
|
_isRevealPassword = value;
|
||||||
NotifyPropertyChanged("IsRevealPassword");
|
OnPropertyChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public bool HasExpirationDate
|
public bool HasExpirationDate
|
||||||
{
|
{
|
||||||
get { return _pwEntry.Expires; }
|
get { return _entry.HasExpirationDate; }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
_pwEntry.Expires = value;
|
_mediator.Send(new SetFieldValueCommand {EntryId = Id, FieldName = nameof(HasExpirationDate), FieldValue = value});
|
||||||
NotifyPropertyChanged("HasExpirationDate");
|
OnPropertyChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,7 +159,7 @@ namespace ModernKeePass.ViewModels
|
|||||||
get
|
get
|
||||||
{
|
{
|
||||||
var history = new Stack<EntryVm>();
|
var history = new Stack<EntryVm>();
|
||||||
foreach (var historyEntry in _pwEntry.History)
|
foreach (var historyEntry in _entry.History)
|
||||||
{
|
{
|
||||||
history.Push(new EntryVm(historyEntry, ParentGroup) {IsSelected = false});
|
history.Push(new EntryVm(historyEntry, ParentGroup) {IsSelected = false});
|
||||||
}
|
}
|
||||||
@@ -178,89 +172,68 @@ namespace ModernKeePass.ViewModels
|
|||||||
|
|
||||||
public Color? BackgroundColor
|
public Color? BackgroundColor
|
||||||
{
|
{
|
||||||
get { return _pwEntry?.BackgroundColor; }
|
get { return _entry?.BackgroundColor; }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (value != null) _pwEntry.BackgroundColor = (Color) value;
|
if (value != null) _entry.BackgroundColor = (Color) value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Color? ForegroundColor
|
public Color? ForegroundColor
|
||||||
{
|
{
|
||||||
get { return _pwEntry?.ForegroundColor; }
|
get { return _entry?.ForegroundColor; }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (value != null) _pwEntry.ForegroundColor = (Color)value;
|
if (value != null) _entry.ForegroundColor = (Color)value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ICommand SaveCommand { get; }
|
public ICommand SaveCommand { get; }
|
||||||
public ICommand GeneratePasswordCommand { get; }
|
public ICommand GeneratePasswordCommand { get; }
|
||||||
public ICommand UndoDeleteCommand { get; }
|
public ICommand UndoDeleteCommand { get; }
|
||||||
|
|
||||||
public event PropertyChangedEventHandler PropertyChanged;
|
private readonly Application.Entry.Models.EntryVm _entry;
|
||||||
|
private readonly IMediator _mediator;
|
||||||
private readonly PwEntry _pwEntry;
|
|
||||||
private readonly IDatabaseService _database;
|
|
||||||
private readonly IResourceService _resource;
|
|
||||||
private bool _isEditMode;
|
private bool _isEditMode;
|
||||||
private bool _isDirty = true;
|
|
||||||
private bool _isRevealPassword;
|
private bool _isRevealPassword;
|
||||||
private double _passwordLength = 25;
|
private double _passwordLength = 25;
|
||||||
private bool _isVisible = true;
|
private bool _isVisible = true;
|
||||||
|
|
||||||
private void NotifyPropertyChanged(string propertyName)
|
|
||||||
{
|
|
||||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
|
||||||
}
|
|
||||||
|
|
||||||
public EntryVm() { }
|
public EntryVm() { }
|
||||||
|
|
||||||
internal EntryVm(PwEntry entry, GroupVm parent) : this(entry, parent, DatabaseService.Instance, new ResourcesService()) { }
|
internal EntryVm(Application.Entry.Models.EntryVm entry, GroupVm parent) : this(entry, parent, App.Mediator) { }
|
||||||
|
|
||||||
public EntryVm(PwEntry entry, GroupVm parent, IDatabaseService database, IResourceService resource)
|
public EntryVm(Application.Entry.Models.EntryVm entry, GroupVm parent, IMediator mediator)
|
||||||
{
|
{
|
||||||
_database = database;
|
_entry = entry;
|
||||||
_resource = resource;
|
_mediator = mediator;
|
||||||
_pwEntry = entry;
|
|
||||||
ParentGroup = parent;
|
ParentGroup = parent;
|
||||||
|
|
||||||
SaveCommand = new RelayCommand(() => _database.Save());
|
SaveCommand = new RelayCommand(() => _mediator.Send(new SaveDatabaseCommand()));
|
||||||
GeneratePasswordCommand = new RelayCommand(GeneratePassword);
|
GeneratePasswordCommand = new RelayCommand(async () => await GeneratePassword());
|
||||||
UndoDeleteCommand = new RelayCommand(() => Move(PreviousGroup), () => PreviousGroup != null);
|
UndoDeleteCommand = new RelayCommand(() => Move(PreviousGroup), () => PreviousGroup != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void GeneratePassword()
|
public async Task GeneratePassword()
|
||||||
{
|
{
|
||||||
var pwProfile = new PwProfile
|
Password = await _mediator.Send(new GeneratePasswordCommand
|
||||||
{
|
{
|
||||||
GeneratorType = PasswordGeneratorType.CharSet,
|
BracketsPatternSelected = BracketsPatternSelected,
|
||||||
Length = (uint)PasswordLength,
|
CustomChars = CustomChars,
|
||||||
CharSet = new PwCharSet()
|
DigitsPatternSelected = DigitsPatternSelected,
|
||||||
};
|
LowerCasePatternSelected = LowerCasePatternSelected,
|
||||||
|
MinusPatternSelected = MinusPatternSelected,
|
||||||
if (UpperCasePatternSelected) pwProfile.CharSet.Add(PwCharSet.UpperCase);
|
PasswordLength = (int)PasswordLength,
|
||||||
if (LowerCasePatternSelected) pwProfile.CharSet.Add(PwCharSet.LowerCase);
|
SpacePatternSelected = SpacePatternSelected,
|
||||||
if (DigitsPatternSelected) pwProfile.CharSet.Add(PwCharSet.Digits);
|
SpecialPatternSelected = SpecialPatternSelected,
|
||||||
if (SpecialPatternSelected) pwProfile.CharSet.Add(PwCharSet.Special);
|
UnderscorePatternSelected = UnderscorePatternSelected,
|
||||||
if (MinusPatternSelected) pwProfile.CharSet.Add('-');
|
UpperCasePatternSelected = UpperCasePatternSelected
|
||||||
if (UnderscorePatternSelected) pwProfile.CharSet.Add('_');
|
});
|
||||||
if (SpacePatternSelected) pwProfile.CharSet.Add(' ');
|
OnPropertyChanged(nameof(IsRevealPasswordEnabled));
|
||||||
if (BracketsPatternSelected) pwProfile.CharSet.Add(PwCharSet.Brackets);
|
|
||||||
|
|
||||||
pwProfile.CharSet.Add(CustomChars);
|
|
||||||
|
|
||||||
ProtectedString password;
|
|
||||||
PwGenerator.Generate(out password, pwProfile, null, new CustomPwGeneratorPool());
|
|
||||||
|
|
||||||
SetEntryValue(PwDefs.PasswordField, password);
|
|
||||||
NotifyPropertyChanged("Password");
|
|
||||||
NotifyPropertyChanged("IsRevealPasswordEnabled");
|
|
||||||
NotifyPropertyChanged("PasswordComplexityIndicator");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void MarkForDelete(string recycleBinTitle)
|
public Task MarkForDelete(string recycleBinTitle)
|
||||||
{
|
{
|
||||||
if (_database.RecycleBinEnabled && _database.RecycleBin?.IdUuid == null)
|
if (_database.RecycleBinEnabled && _database.RecycleBin?.IdUuid == null)
|
||||||
_database.CreateRecycleBin(recycleBinTitle);
|
_database.CreateRecycleBin(recycleBinTitle);
|
||||||
@@ -280,43 +253,21 @@ namespace ModernKeePass.ViewModels
|
|||||||
ParentGroup.Entries.Add(this);
|
ParentGroup.Entries.Add(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CommitDelete()
|
public async Task CommitDelete()
|
||||||
{
|
{
|
||||||
_pwEntry.ParentGroup.Entries.Remove(_pwEntry);
|
await _mediator.Send(new DeleteEntryCommand {Entry = _entry});
|
||||||
if (!_database.RecycleBinEnabled || PreviousGroup.IsSelected) _database.AddDeletedItem(IdUuid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public PwEntry GetPwEntry()
|
public Application.Entry.Models.EntryVm GetEntry()
|
||||||
{
|
{
|
||||||
return _pwEntry;
|
return _entry;
|
||||||
}
|
|
||||||
public void Reset()
|
|
||||||
{
|
|
||||||
_isDirty = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return IsSelected ? _resource.GetResourceValue("EntryCurrent") : _pwEntry.LastModificationTime.ToString("g");
|
return IsSelected ?
|
||||||
}
|
_mediator.Send(new GetResourceQuery{Key = "EntryCurrent"}).GetAwaiter().GetResult() :
|
||||||
|
_entry.ModificationDate.ToString("g");
|
||||||
private void HandleBackup()
|
|
||||||
{
|
|
||||||
if (_isDirty) return;
|
|
||||||
_pwEntry?.Touch(true);
|
|
||||||
_pwEntry?.CreateBackup(null);
|
|
||||||
_isDirty = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetEntryValue(string key)
|
|
||||||
{
|
|
||||||
return _pwEntry?.Strings.GetSafe(key).ReadString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetEntryValue(string key, ProtectedString newValue)
|
|
||||||
{
|
|
||||||
HandleBackup();
|
|
||||||
_pwEntry?.Strings.Set(key, newValue);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
using System;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Collections.Specialized;
|
using System.Collections.Specialized;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -8,10 +7,17 @@ using System.Windows.Input;
|
|||||||
using MediatR;
|
using MediatR;
|
||||||
using ModernKeePass.Application.Database.Commands.SaveDatabase;
|
using ModernKeePass.Application.Database.Commands.SaveDatabase;
|
||||||
using ModernKeePass.Application.Database.Queries.GetDatabase;
|
using ModernKeePass.Application.Database.Queries.GetDatabase;
|
||||||
|
using ModernKeePass.Application.Group.Commands.AddEntry;
|
||||||
|
using ModernKeePass.Application.Group.Commands.CreateEntry;
|
||||||
|
using ModernKeePass.Application.Group.Commands.CreateGroup;
|
||||||
|
using ModernKeePass.Application.Group.Commands.DeleteGroup;
|
||||||
|
using ModernKeePass.Application.Group.Commands.InsertEntry;
|
||||||
|
using ModernKeePass.Application.Group.Commands.RemoveEntry;
|
||||||
|
using ModernKeePass.Application.Group.Commands.SortEntries;
|
||||||
|
using ModernKeePass.Application.Group.Commands.SortGroups;
|
||||||
using ModernKeePass.Common;
|
using ModernKeePass.Common;
|
||||||
using ModernKeePass.Domain.Enums;
|
using ModernKeePass.Domain.Enums;
|
||||||
using ModernKeePass.Interfaces;
|
using ModernKeePass.Interfaces;
|
||||||
using ModernKeePassLib;
|
|
||||||
|
|
||||||
namespace ModernKeePass.ViewModels
|
namespace ModernKeePass.ViewModels
|
||||||
{
|
{
|
||||||
@@ -63,17 +69,17 @@ namespace ModernKeePass.ViewModels
|
|||||||
}
|
}
|
||||||
|
|
||||||
public IOrderedEnumerable<IGrouping<char, EntryVm>> EntriesZoomedOut => from e in Entries
|
public IOrderedEnumerable<IGrouping<char, EntryVm>> EntriesZoomedOut => from e in Entries
|
||||||
group e by e.Name.ToUpper().FirstOrDefault() into grp
|
group e by e.Title.ToUpper().FirstOrDefault() into grp
|
||||||
orderby grp.Key
|
orderby grp.Key
|
||||||
select grp;
|
select grp;
|
||||||
|
|
||||||
public string Name
|
public string Title
|
||||||
{
|
{
|
||||||
get { return _group == null ? string.Empty : _group.Title; }
|
get { return _group == null ? string.Empty : _group.Title; }
|
||||||
set { _group.Title = value; }
|
set { _group.Title = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public int IconId
|
public int Icon
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
@@ -152,38 +158,44 @@ namespace ModernKeePass.ViewModels
|
|||||||
Groups = new ObservableCollection<GroupVm>(group.SubGroups.Select(g => new GroupVm(g, this, recycleBinId)));
|
Groups = new ObservableCollection<GroupVm>(group.SubGroups.Select(g => new GroupVm(g, this, recycleBinId)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Entries_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
private async void Entries_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||||
{
|
{
|
||||||
switch (e.Action)
|
switch (e.Action)
|
||||||
{
|
{
|
||||||
case NotifyCollectionChangedAction.Remove:
|
case NotifyCollectionChangedAction.Remove:
|
||||||
var oldIndex = (uint) e.OldStartingIndex;
|
var oldIndex = e.OldStartingIndex;
|
||||||
_reorderedEntry = _group.Entries.GetAt(oldIndex);
|
_reorderedEntry = _group.Entries[oldIndex];
|
||||||
_group.Entries.RemoveAt(oldIndex);
|
await _mediator.Send(new RemoveEntryCommand {Entry = _reorderedEntry, ParentGroup = _group});
|
||||||
break;
|
break;
|
||||||
case NotifyCollectionChangedAction.Add:
|
case NotifyCollectionChangedAction.Add:
|
||||||
if (_reorderedEntry == null) _group.AddEntry(((EntryVm) e.NewItems[0]).GetPwEntry(), true);
|
if (_reorderedEntry == null)
|
||||||
else _group.Entries.Insert((uint)e.NewStartingIndex, _reorderedEntry);
|
{
|
||||||
|
var entry = ((EntryVm) e.NewItems[0]).GetEntry();
|
||||||
|
await _mediator.Send(new AddEntryCommand {Entry = entry, ParentGroup = _group});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await _mediator.Send(new InsertEntryCommand {Entry = _reorderedEntry, ParentGroup = _group, Index = e.NewStartingIndex});
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public GroupVm AddNewGroup(string name = "")
|
public async Task<GroupVm> AddNewGroup(string name = "")
|
||||||
{
|
{
|
||||||
var pwGroup = new PwGroup(true, true, name, PwIcon.Folder);
|
var newGroup = await _mediator.Send(new CreateGroupCommand {Name = name, ParentGroup = _group});
|
||||||
_group.AddGroup(pwGroup, true);
|
var newGroupVm = new GroupVm(newGroup, this) {Title = name, IsEditMode = string.IsNullOrEmpty(name)};
|
||||||
var newGroup = new GroupVm(pwGroup, this) {Name = name, IsEditMode = string.IsNullOrEmpty(name)};
|
Groups.Add(newGroupVm);
|
||||||
Groups.Add(newGroup);
|
return newGroupVm;
|
||||||
return newGroup;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public EntryVm AddNewEntry()
|
public async Task<EntryVm> AddNewEntry()
|
||||||
{
|
{
|
||||||
var pwEntry = new PwEntry(true, true);
|
var newEntry = await _mediator.Send(new CreateEntryCommand { ParentGroup = _group });
|
||||||
var newEntry = new EntryVm(pwEntry, this) {IsEditMode = true};
|
var newEntryVm = new EntryVm(newEntry, this) {IsEditMode = true};
|
||||||
newEntry.GeneratePassword();
|
await newEntryVm.GeneratePassword();
|
||||||
Entries.Add(newEntry);
|
Entries.Add(newEntryVm);
|
||||||
return newEntry;
|
return newEntryVm;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task MarkForDelete(string recycleBinTitle)
|
public async Task MarkForDelete(string recycleBinTitle)
|
||||||
@@ -217,42 +229,26 @@ namespace ModernKeePass.ViewModels
|
|||||||
|
|
||||||
public async Task CommitDelete()
|
public async Task CommitDelete()
|
||||||
{
|
{
|
||||||
_group.ParentGroup.Groups.Remove(_group);
|
await _mediator.Send(new DeleteGroupCommand { Group = _group });
|
||||||
if (await IsRecycleBinEnabled() && !PreviousGroup.IsSelected) _database.RecycleBin._group.AddGroup(_group, true);
|
|
||||||
else _database.AddDeletedItem(IdUuid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return Name;
|
return Title;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task SortEntriesAsync()
|
private async Task SortEntriesAsync()
|
||||||
{
|
{
|
||||||
var comparer = new PwEntryComparer(PwDefs.TitleField, true, false);
|
await _mediator.Send(new SortEntriesCommand {Group = _group});
|
||||||
try
|
Entries = new ObservableCollection<EntryVm>(Entries.OrderBy(e => e.Title));
|
||||||
{
|
|
||||||
_group.Entries.Sort(comparer);
|
|
||||||
Entries = new ObservableCollection<EntryVm>(Entries.OrderBy(e => e.Name));
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
await MessageDialogHelper.ShowErrorDialog(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task SortGroupsAsync()
|
private async Task SortGroupsAsync()
|
||||||
{
|
{
|
||||||
try
|
await _mediator.Send(new SortGroupsCommand {Group = _group});
|
||||||
{
|
Groups = new ObservableCollection<GroupVm>(Groups.OrderBy(g => g.Title).ThenBy(g => g._group == null));
|
||||||
_group.SortSubGroups(false);
|
// TODO: should not be needed
|
||||||
Groups = new ObservableCollection<GroupVm>(Groups.OrderBy(g => g.Name).ThenBy(g => g._group == null));
|
OnPropertyChanged(nameof(Groups));
|
||||||
OnPropertyChanged("Groups");
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
await MessageDialogHelper.ShowErrorDialog(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<bool> IsRecycleBinEnabled()
|
private async Task<bool> IsRecycleBinEnabled()
|
||||||
|
@@ -41,23 +41,23 @@ namespace ModernKeePass.ViewModels
|
|||||||
var converter = new IntToSymbolConverter();
|
var converter = new IntToSymbolConverter();
|
||||||
|
|
||||||
var bankingGroup = group.AddNewGroup("Banking");
|
var bankingGroup = group.AddNewGroup("Banking");
|
||||||
bankingGroup.IconId = (int)converter.ConvertBack(Symbol.Calculator, null, null, string.Empty);
|
bankingGroup.Icon = (int)converter.ConvertBack(Symbol.Calculator, null, null, string.Empty);
|
||||||
|
|
||||||
var emailGroup = group.AddNewGroup("Email");
|
var emailGroup = group.AddNewGroup("Email");
|
||||||
emailGroup.IconId = (int)converter.ConvertBack(Symbol.Mail, null, null, string.Empty);
|
emailGroup.Icon = (int)converter.ConvertBack(Symbol.Mail, null, null, string.Empty);
|
||||||
|
|
||||||
var internetGroup = group.AddNewGroup("Internet");
|
var internetGroup = group.AddNewGroup("Internet");
|
||||||
internetGroup.IconId = (int)converter.ConvertBack(Symbol.World, null, null, string.Empty);
|
internetGroup.Icon = (int)converter.ConvertBack(Symbol.World, null, null, string.Empty);
|
||||||
|
|
||||||
var sample1 = group.AddNewEntry();
|
var sample1 = group.AddNewEntry();
|
||||||
sample1.Name = "Sample Entry";
|
sample1.Title = "Sample Entry";
|
||||||
sample1.UserName = "Username";
|
sample1.UserName = "Username";
|
||||||
sample1.Url = PwDefs.HomepageUrl;
|
sample1.Url = PwDefs.HomepageUrl;
|
||||||
sample1.Password = "Password";
|
sample1.Password = "Password";
|
||||||
sample1.Notes = "You may safely delete this sample";
|
sample1.Notes = "You may safely delete this sample";
|
||||||
|
|
||||||
var sample2 = group.AddNewEntry();
|
var sample2 = group.AddNewEntry();
|
||||||
sample2.Name = "Sample Entry #2";
|
sample2.Title = "Sample Entry #2";
|
||||||
sample2.UserName = "Michael321";
|
sample2.UserName = "Michael321";
|
||||||
sample2.Url = PwDefs.HelpUrl + "kb/testform.html";
|
sample2.Url = PwDefs.HelpUrl + "kb/testform.html";
|
||||||
sample2.Password = "12345";
|
sample2.Password = "12345";
|
||||||
|
@@ -415,7 +415,7 @@
|
|||||||
<interactivity:Interaction.Behaviors>
|
<interactivity:Interaction.Behaviors>
|
||||||
<core:EventTriggerBehavior EventName="ButtonClick">
|
<core:EventTriggerBehavior EventName="ButtonClick">
|
||||||
<actions:ClipboardAction Text="{Binding UserName}" />
|
<actions:ClipboardAction Text="{Binding UserName}" />
|
||||||
<actions:ToastAction x:Uid="ToastCopyLogin" Title="{Binding Name}" />
|
<actions:ToastAction x:Uid="ToastCopyLogin" Title="{Binding Title}" />
|
||||||
</core:EventTriggerBehavior>
|
</core:EventTriggerBehavior>
|
||||||
</interactivity:Interaction.Behaviors>
|
</interactivity:Interaction.Behaviors>
|
||||||
</local:TextBoxWithButton>
|
</local:TextBoxWithButton>
|
||||||
@@ -425,7 +425,7 @@
|
|||||||
<interactivity:Interaction.Behaviors>
|
<interactivity:Interaction.Behaviors>
|
||||||
<core:EventTriggerBehavior EventName="ButtonClick">
|
<core:EventTriggerBehavior EventName="ButtonClick">
|
||||||
<actions:ClipboardAction Text="{Binding Password}" />
|
<actions:ClipboardAction Text="{Binding Password}" />
|
||||||
<actions:ToastAction x:Uid="ToastCopyPassword" Title="{Binding Name}" />
|
<actions:ToastAction x:Uid="ToastCopyPassword" Title="{Binding Title}" />
|
||||||
</core:EventTriggerBehavior>
|
</core:EventTriggerBehavior>
|
||||||
</interactivity:Interaction.Behaviors>
|
</interactivity:Interaction.Behaviors>
|
||||||
</local:TextBoxWithButton>
|
</local:TextBoxWithButton>
|
||||||
@@ -498,13 +498,13 @@
|
|||||||
<RowDefinition Height="20" />
|
<RowDefinition Height="20" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Viewbox MaxHeight="30" Width="50" Grid.Column="0" Grid.Row="0" Visibility="{Binding IsEditMode, Converter={StaticResource BooleanToVisibilityConverter}}">
|
<Viewbox MaxHeight="30" Width="50" Grid.Column="0" Grid.Row="0" Visibility="{Binding IsEditMode, Converter={StaticResource BooleanToVisibilityConverter}}">
|
||||||
<userControls:SymbolPickerUserControl Width="80" Height="40" SelectedSymbol="{Binding IconId, Converter={StaticResource IntToSymbolConverter}, ConverterParameter=0, Mode=TwoWay}" />
|
<userControls:SymbolPickerUserControl Width="80" Height="40" SelectedSymbol="{Binding Icon, Converter={StaticResource IntToSymbolConverter}, ConverterParameter=0, Mode=TwoWay}" />
|
||||||
</Viewbox>
|
</Viewbox>
|
||||||
<Viewbox MaxHeight="30" Width="50" Grid.Column="0" Grid.Row="0" Visibility="{Binding IsEditMode, Converter={StaticResource InverseBooleanToVisibilityConverter}}">
|
<Viewbox MaxHeight="30" Width="50" Grid.Column="0" Grid.Row="0" Visibility="{Binding IsEditMode, Converter={StaticResource InverseBooleanToVisibilityConverter}}">
|
||||||
<SymbolIcon Symbol="{Binding IconId, Converter={StaticResource IntToSymbolConverter}}" Width="80" Height="40" />
|
<SymbolIcon Symbol="{Binding Icon, Converter={StaticResource IntToSymbolConverter}}" Width="80" Height="40" />
|
||||||
</Viewbox>
|
</Viewbox>
|
||||||
<TextBox Grid.Column="1" Grid.Row="0"
|
<TextBox Grid.Column="1" Grid.Row="0"
|
||||||
Text="{Binding Name, Mode=TwoWay}"
|
Text="{Binding Title, Mode=TwoWay}"
|
||||||
Foreground="{ThemeResource DefaultTextForegroundThemeBrush}"
|
Foreground="{ThemeResource DefaultTextForegroundThemeBrush}"
|
||||||
Background="Transparent"
|
Background="Transparent"
|
||||||
SelectionHighlightColor="{StaticResource MainColor}"
|
SelectionHighlightColor="{StaticResource MainColor}"
|
||||||
@@ -539,7 +539,7 @@
|
|||||||
</core:EventTriggerBehavior>
|
</core:EventTriggerBehavior>
|
||||||
<core:EventTriggerBehavior EventName="RestoreButtonClick">
|
<core:EventTriggerBehavior EventName="RestoreButtonClick">
|
||||||
<core:InvokeCommandAction Command="{Binding NavigationHelper.GoBackCommand, ElementName=PageRoot}" />
|
<core:InvokeCommandAction Command="{Binding NavigationHelper.GoBackCommand, ElementName=PageRoot}" />
|
||||||
<actions:ToastAction x:Uid="RestoreEntryCommand" Title="{Binding Name}" />
|
<actions:ToastAction x:Uid="RestoreEntryCommand" Title="{Binding Title}" />
|
||||||
</core:EventTriggerBehavior>
|
</core:EventTriggerBehavior>
|
||||||
</interactivity:Interaction.Behaviors>
|
</interactivity:Interaction.Behaviors>
|
||||||
</userControls:TopMenuUserControl>
|
</userControls:TopMenuUserControl>
|
||||||
|
@@ -49,7 +49,6 @@ namespace ModernKeePass.Views
|
|||||||
protected override void OnNavigatedFrom(NavigationEventArgs e)
|
protected override void OnNavigatedFrom(NavigationEventArgs e)
|
||||||
{
|
{
|
||||||
NavigationHelper.OnNavigatedFrom(e);
|
NavigationHelper.OnNavigatedFrom(e);
|
||||||
Model.Reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
@@ -105,11 +105,11 @@
|
|||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<Border Grid.Column="0" Background="{Binding BackgroundColor, ConverterParameter={StaticResource MainColor}, Converter={StaticResource ColorToBrushConverter}}">
|
<Border Grid.Column="0" Background="{Binding BackgroundColor, ConverterParameter={StaticResource MainColor}, Converter={StaticResource ColorToBrushConverter}}">
|
||||||
<Viewbox MaxHeight="50" Width="100">
|
<Viewbox MaxHeight="50" Width="100">
|
||||||
<SymbolIcon Symbol="{Binding IconId, Converter={StaticResource IntToSymbolConverter}, ConverterParameter=0}" Foreground="{StaticResource TextColor}" />
|
<SymbolIcon Symbol="{Binding Icon, Converter={StaticResource IntToSymbolConverter}, ConverterParameter=0}" Foreground="{StaticResource TextColor}" />
|
||||||
</Viewbox>
|
</Viewbox>
|
||||||
</Border>
|
</Border>
|
||||||
<StackPanel Grid.Column="1" VerticalAlignment="Top" Margin="10,10,0,0" >
|
<StackPanel Grid.Column="1" VerticalAlignment="Top" Margin="10,10,0,0" >
|
||||||
<TextBlock x:Name="NameTextBlock" Text="{Binding Name}" Style="{StaticResource TitleTextBlockStyle}" TextWrapping="NoWrap" Foreground="{Binding ForegroundColor, ConverterParameter={StaticResource TextBoxForegroundThemeBrush}, Converter={StaticResource ColorToBrushConverter}}"/>
|
<TextBlock x:Name="NameTextBlock" Text="{Binding Title}" Style="{StaticResource TitleTextBlockStyle}" TextWrapping="NoWrap" Foreground="{Binding ForegroundColor, ConverterParameter={StaticResource TextBoxForegroundThemeBrush}, Converter={StaticResource ColorToBrushConverter}}"/>
|
||||||
<TextBlock Style="{StaticResource CaptionTextBlockStyle}" TextWrapping="NoWrap" />
|
<TextBlock Style="{StaticResource CaptionTextBlockStyle}" TextWrapping="NoWrap" />
|
||||||
<TextBlock Text="{Binding UserName}" Style="{StaticResource BodyTextBlockStyle}" Foreground="{Binding ForegroundColor, ConverterParameter={StaticResource TextBoxForegroundThemeBrush}, Converter={StaticResource ColorToBrushConverter}}" MaxHeight="60" />
|
<TextBlock Text="{Binding UserName}" Style="{StaticResource BodyTextBlockStyle}" Foreground="{Binding ForegroundColor, ConverterParameter={StaticResource TextBoxForegroundThemeBrush}, Converter={StaticResource ColorToBrushConverter}}" MaxHeight="60" />
|
||||||
<TextBlock Text="{Binding Url}" Style="{StaticResource BodyTextBlockStyle}" Foreground="{Binding ForegroundColor, ConverterParameter={StaticResource TextBoxForegroundThemeBrush}, Converter={StaticResource ColorToBrushConverter}}" MaxHeight="60" />
|
<TextBlock Text="{Binding Url}" Style="{StaticResource BodyTextBlockStyle}" Foreground="{Binding ForegroundColor, ConverterParameter={StaticResource TextBoxForegroundThemeBrush}, Converter={StaticResource ColorToBrushConverter}}" MaxHeight="60" />
|
||||||
@@ -122,7 +122,7 @@
|
|||||||
<interactivity:Interaction.Behaviors>
|
<interactivity:Interaction.Behaviors>
|
||||||
<core:EventTriggerBehavior EventName="Click">
|
<core:EventTriggerBehavior EventName="Click">
|
||||||
<actions:ClipboardAction Text="{Binding UserName}" />
|
<actions:ClipboardAction Text="{Binding UserName}" />
|
||||||
<actions:ToastAction x:Uid="ToastCopyLogin" Title="{Binding Name}" />
|
<actions:ToastAction x:Uid="ToastCopyLogin" Title="{Binding Title}" />
|
||||||
</core:EventTriggerBehavior>
|
</core:EventTriggerBehavior>
|
||||||
</interactivity:Interaction.Behaviors>
|
</interactivity:Interaction.Behaviors>
|
||||||
</MenuFlyoutItem>
|
</MenuFlyoutItem>
|
||||||
@@ -130,7 +130,7 @@
|
|||||||
<interactivity:Interaction.Behaviors>
|
<interactivity:Interaction.Behaviors>
|
||||||
<core:EventTriggerBehavior EventName="Click">
|
<core:EventTriggerBehavior EventName="Click">
|
||||||
<actions:ClipboardAction Text="{Binding Password}" />
|
<actions:ClipboardAction Text="{Binding Password}" />
|
||||||
<actions:ToastAction x:Uid="ToastCopyPassword" Title="{Binding Name}" />
|
<actions:ToastAction x:Uid="ToastCopyPassword" Title="{Binding Title}" />
|
||||||
</core:EventTriggerBehavior>
|
</core:EventTriggerBehavior>
|
||||||
</interactivity:Interaction.Behaviors>
|
</interactivity:Interaction.Behaviors>
|
||||||
</MenuFlyoutItem>
|
</MenuFlyoutItem>
|
||||||
@@ -138,7 +138,7 @@
|
|||||||
<interactivity:Interaction.Behaviors>
|
<interactivity:Interaction.Behaviors>
|
||||||
<core:EventTriggerBehavior EventName="Click">
|
<core:EventTriggerBehavior EventName="Click">
|
||||||
<actions:NavigateToUrlAction Url="{Binding Url}" />
|
<actions:NavigateToUrlAction Url="{Binding Url}" />
|
||||||
<actions:ToastAction x:Uid="ToastCopyUrl" Title="{Binding Name}" />
|
<actions:ToastAction x:Uid="ToastCopyUrl" Title="{Binding Title}" />
|
||||||
</core:EventTriggerBehavior>
|
</core:EventTriggerBehavior>
|
||||||
</interactivity:Interaction.Behaviors>
|
</interactivity:Interaction.Behaviors>
|
||||||
</MenuFlyoutItem>
|
</MenuFlyoutItem>
|
||||||
@@ -159,7 +159,7 @@
|
|||||||
<GridView.ItemTemplate>
|
<GridView.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<StackPanel Orientation="Vertical">
|
<StackPanel Orientation="Vertical">
|
||||||
<TextBlock Width="100" Text="{Binding Name}" Style="{StaticResource TitleTextBlockStyle}" TextWrapping="NoWrap"/>
|
<TextBlock Width="100" Text="{Binding Title}" Style="{StaticResource TitleTextBlockStyle}" TextWrapping="NoWrap"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</GridView.ItemTemplate>
|
</GridView.ItemTemplate>
|
||||||
@@ -207,14 +207,14 @@
|
|||||||
<RowDefinition Height="20" />
|
<RowDefinition Height="20" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Viewbox MaxHeight="30" Width="50" Grid.Column="0" Grid.Row="0" Visibility="{Binding IsEditMode, Converter={StaticResource BooleanToVisibilityConverter}}">
|
<Viewbox MaxHeight="30" Width="50" Grid.Column="0" Grid.Row="0" Visibility="{Binding IsEditMode, Converter={StaticResource BooleanToVisibilityConverter}}">
|
||||||
<userControls:SymbolPickerUserControl Width="80" Height="40" SelectedSymbol="{Binding IconId, Converter={StaticResource IntToSymbolConverter}, ConverterParameter=48, Mode=TwoWay}" />
|
<userControls:SymbolPickerUserControl Width="80" Height="40" SelectedSymbol="{Binding Icon, Converter={StaticResource IntToSymbolConverter}, ConverterParameter=48, Mode=TwoWay}" />
|
||||||
</Viewbox>
|
</Viewbox>
|
||||||
<Viewbox MaxHeight="30" Width="50" Grid.Column="0" Grid.Row="0" Visibility="{Binding IsEditMode, Converter={StaticResource InverseBooleanToVisibilityConverter}}">
|
<Viewbox MaxHeight="30" Width="50" Grid.Column="0" Grid.Row="0" Visibility="{Binding IsEditMode, Converter={StaticResource InverseBooleanToVisibilityConverter}}">
|
||||||
<SymbolIcon Symbol="{Binding IconId, Converter={StaticResource IntToSymbolConverter}}" Width="80" Height="40" />
|
<SymbolIcon Symbol="{Binding Icon, Converter={StaticResource IntToSymbolConverter}}" Width="80" Height="40" />
|
||||||
</Viewbox>
|
</Viewbox>
|
||||||
<TextBox Grid.Column="1" Grid.Row="0"
|
<TextBox Grid.Column="1" Grid.Row="0"
|
||||||
x:Name="TitleTextBox"
|
x:Name="TitleTextBox"
|
||||||
Text="{Binding Name, Mode=TwoWay}"
|
Text="{Binding Title, Mode=TwoWay}"
|
||||||
Foreground="{ThemeResource DefaultTextForegroundThemeBrush}"
|
Foreground="{ThemeResource DefaultTextForegroundThemeBrush}"
|
||||||
SelectionHighlightColor="{StaticResource MainColor}"
|
SelectionHighlightColor="{StaticResource MainColor}"
|
||||||
Background="Transparent"
|
Background="Transparent"
|
||||||
@@ -252,7 +252,7 @@
|
|||||||
</core:EventTriggerBehavior>
|
</core:EventTriggerBehavior>
|
||||||
<core:EventTriggerBehavior EventName="RestoreButtonClick">
|
<core:EventTriggerBehavior EventName="RestoreButtonClick">
|
||||||
<core:InvokeCommandAction Command="{Binding NavigationHelper.GoBackCommand, ElementName=PageRoot}" />
|
<core:InvokeCommandAction Command="{Binding NavigationHelper.GoBackCommand, ElementName=PageRoot}" />
|
||||||
<actions:ToastAction x:Uid="RestoreGroupCommand" Title="{Binding Name}" />
|
<actions:ToastAction x:Uid="RestoreGroupCommand" Title="{Binding Title}" />
|
||||||
</core:EventTriggerBehavior>
|
</core:EventTriggerBehavior>
|
||||||
</interactivity:Interaction.Behaviors>
|
</interactivity:Interaction.Behaviors>
|
||||||
</userControls:TopMenuUserControl>
|
</userControls:TopMenuUserControl>
|
||||||
|
@@ -122,10 +122,10 @@ namespace ModernKeePass.Views
|
|||||||
private void SearchBox_OnSuggestionsRequested(SearchBox sender, SearchBoxSuggestionsRequestedEventArgs args)
|
private void SearchBox_OnSuggestionsRequested(SearchBox sender, SearchBoxSuggestionsRequestedEventArgs args)
|
||||||
{
|
{
|
||||||
var imageUri = RandomAccessStreamReference.CreateFromUri(new Uri("ms-appdata://Assets/ModernKeePass-SmallLogo.scale-80.png"));
|
var imageUri = RandomAccessStreamReference.CreateFromUri(new Uri("ms-appdata://Assets/ModernKeePass-SmallLogo.scale-80.png"));
|
||||||
var results = Model.SubEntries.Where(e => e.Name.IndexOf(args.QueryText, StringComparison.OrdinalIgnoreCase) >= 0).Take(5);
|
var results = Model.SubEntries.Where(e => e.Title.IndexOf(args.QueryText, StringComparison.OrdinalIgnoreCase) >= 0).Take(5);
|
||||||
foreach (var result in results)
|
foreach (var result in results)
|
||||||
{
|
{
|
||||||
args.Request.SearchSuggestionCollection.AppendResultSuggestion(result.Name, result.ParentGroup.Name, result.Id, imageUri, string.Empty);
|
args.Request.SearchSuggestionCollection.AppendResultSuggestion(result.Title, result.ParentGroup.Title, result.Id, imageUri, string.Empty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -118,7 +118,7 @@ namespace ModernKeePassApp.Test
|
|||||||
var database = new DatabaseServiceMock();
|
var database = new DatabaseServiceMock();
|
||||||
var entryVm = new EntryVm(new PwEntry(true, true), new GroupVm(), database, _resource)
|
var entryVm = new EntryVm(new PwEntry(true, true), new GroupVm(), database, _resource)
|
||||||
{
|
{
|
||||||
Name = "Test",
|
Title = "Test",
|
||||||
UserName = "login",
|
UserName = "login",
|
||||||
Password = "password"
|
Password = "password"
|
||||||
};
|
};
|
||||||
@@ -130,7 +130,7 @@ namespace ModernKeePassApp.Test
|
|||||||
var database = new DatabaseServiceMock();
|
var database = new DatabaseServiceMock();
|
||||||
var entryVm = new GroupVm(new PwGroup(true, true), new GroupVm(), database)
|
var entryVm = new GroupVm(new PwGroup(true, true), new GroupVm(), database)
|
||||||
{
|
{
|
||||||
Name = "Test"
|
Title = "Test"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user