mirror of
https://github.com/wismna/ModernKeePass.git
synced 2025-10-04 16:10:16 -04:00
Compare commits
14 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
7a2ce30512 | ||
![]() |
d497f69a5e | ||
![]() |
72e5bf4ee1 | ||
![]() |
2e01fa2212 | ||
![]() |
0adb44bc81 | ||
![]() |
d38d6461bd | ||
![]() |
7ac1595aaa | ||
![]() |
f8f7c19f65 | ||
![]() |
d6dc6a74a3 | ||
![]() |
bb2b99ed66 | ||
![]() |
71b6009a29 | ||
![]() |
fbcc354809 | ||
![]() |
e901afaf29 | ||
![]() |
ca04a6c8ee |
@@ -77,6 +77,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Common\Behaviors\DirtyStatusBehavior.cs" />
|
<Compile Include="Common\Behaviors\DirtyStatusBehavior.cs" />
|
||||||
<Compile Include="Common\Interfaces\ICryptographyClient.cs" />
|
<Compile Include="Common\Interfaces\ICryptographyClient.cs" />
|
||||||
|
<Compile Include="Common\Interfaces\IDatabaseSettingsProxy.cs" />
|
||||||
<Compile Include="Common\Interfaces\IDatabaseProxy.cs" />
|
<Compile Include="Common\Interfaces\IDatabaseProxy.cs" />
|
||||||
<Compile Include="Common\Interfaces\IEntityVm.cs" />
|
<Compile Include="Common\Interfaces\IEntityVm.cs" />
|
||||||
<Compile Include="Common\Interfaces\IFileProxy.cs" />
|
<Compile Include="Common\Interfaces\IFileProxy.cs" />
|
||||||
@@ -88,12 +89,17 @@
|
|||||||
<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="Entry\Commands\AddAttachment\AddAttachmentCommand.cs" />
|
||||||
<Compile Include="Entry\Commands\AddHistory\AddHistoryCommand.cs" />
|
<Compile Include="Entry\Commands\AddHistory\AddHistoryCommand.cs" />
|
||||||
|
<Compile Include="Entry\Commands\DeleteAttachment\DeleteAttachmentCommand.cs" />
|
||||||
|
<Compile Include="Entry\Commands\DeleteField\DeleteFieldCommand.cs" />
|
||||||
<Compile Include="Entry\Commands\DeleteHistory\DeleteHistoryCommand.cs" />
|
<Compile Include="Entry\Commands\DeleteHistory\DeleteHistoryCommand.cs" />
|
||||||
<Compile Include="Entry\Commands\RestoreHistory\RestoreHistoryCommand.cs" />
|
<Compile Include="Entry\Commands\RestoreHistory\RestoreHistoryCommand.cs" />
|
||||||
|
<Compile Include="Entry\Models\FieldVm.cs" />
|
||||||
<Compile Include="Entry\Queries\GetEntry\GetEntryQuery.cs" />
|
<Compile Include="Entry\Queries\GetEntry\GetEntryQuery.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\MoveGroup\MoveGroupCommand.cs" />
|
||||||
<Compile Include="Group\Commands\UpdateGroup\UpdateGroupCommand.cs" />
|
<Compile Include="Group\Commands\UpdateGroup\UpdateGroupCommand.cs" />
|
||||||
<Compile Include="Group\Queries\GetAllGroups\GetAllGroupsQuery.cs" />
|
<Compile Include="Group\Queries\GetAllGroups\GetAllGroupsQuery.cs" />
|
||||||
<Compile Include="Group\Queries\GetGroup\GetGroupQuery.cs" />
|
<Compile Include="Group\Queries\GetGroup\GetGroupQuery.cs" />
|
||||||
@@ -101,7 +107,9 @@
|
|||||||
<Compile Include="Parameters\Commands\SetCipher\SetCipherCommand.cs" />
|
<Compile Include="Parameters\Commands\SetCipher\SetCipherCommand.cs" />
|
||||||
<Compile Include="Parameters\Commands\SetCompression\SetCompressionCommand.cs" />
|
<Compile Include="Parameters\Commands\SetCompression\SetCompressionCommand.cs" />
|
||||||
<Compile Include="Parameters\Commands\SetHasRecycleBin\SetHasRecycleBinCommand.cs" />
|
<Compile Include="Parameters\Commands\SetHasRecycleBin\SetHasRecycleBinCommand.cs" />
|
||||||
|
<Compile Include="Parameters\Commands\SetMaxHistoryCount\SetHistoryCountCommand.cs" />
|
||||||
<Compile Include="Parameters\Commands\SetKeyDerivation\SetKeyDerivationCommand.cs" />
|
<Compile Include="Parameters\Commands\SetKeyDerivation\SetKeyDerivationCommand.cs" />
|
||||||
|
<Compile Include="Parameters\Commands\SetMaxHistorySize\SetMaxHistorySizeCommand.cs" />
|
||||||
<Compile Include="Parameters\Commands\SetRecycleBin\SetRecycleBinCommand.cs" />
|
<Compile Include="Parameters\Commands\SetRecycleBin\SetRecycleBinCommand.cs" />
|
||||||
<Compile Include="Parameters\Models\CipherVm.cs" />
|
<Compile Include="Parameters\Models\CipherVm.cs" />
|
||||||
<Compile Include="Parameters\Models\KeyDerivationVm.cs" />
|
<Compile Include="Parameters\Models\KeyDerivationVm.cs" />
|
||||||
@@ -119,8 +127,8 @@
|
|||||||
<Compile Include="Database\Queries\OpenDatabase\OpenDatabaseQueryValidator.cs" />
|
<Compile Include="Database\Queries\OpenDatabase\OpenDatabaseQueryValidator.cs" />
|
||||||
<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\UpsertField\UpsertFieldCommand.cs" />
|
||||||
<Compile Include="Entry\Commands\SetFieldValue\SetFieldValueCommandValidator.cs" />
|
<Compile Include="Entry\Commands\UpsertField\UpsertFieldCommandValidator.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" />
|
||||||
|
@@ -1,12 +1,10 @@
|
|||||||
using System.Collections.Generic;
|
using System.Threading.Tasks;
|
||||||
using ModernKeePass.Domain.Entities;
|
|
||||||
|
|
||||||
namespace ModernKeePass.Application.Common.Interfaces
|
namespace ModernKeePass.Application.Common.Interfaces
|
||||||
{
|
{
|
||||||
public interface ICryptographyClient
|
public interface ICryptographyClient
|
||||||
{
|
{
|
||||||
IEnumerable<BaseEntity> Ciphers { get; }
|
Task<string> Protect(string value);
|
||||||
IEnumerable<BaseEntity> KeyDerivations { get; }
|
Task<string> UnProtect(string value);
|
||||||
IEnumerable<string> CompressionAlgorithms { get; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -22,6 +22,8 @@ namespace ModernKeePass.Application.Common.Interfaces
|
|||||||
string FileAccessToken { get; set; }
|
string FileAccessToken { get; set; }
|
||||||
int Size { get; set; }
|
int Size { get; set; }
|
||||||
bool IsDirty { get; set; }
|
bool IsDirty { get; set; }
|
||||||
|
int MaxHistoryCount { get; set; }
|
||||||
|
long MaxHistorySize { get; set; }
|
||||||
|
|
||||||
Task Open(byte[] file, Credentials credentials);
|
Task Open(byte[] file, Credentials credentials);
|
||||||
Task ReOpen(byte[] file);
|
Task ReOpen(byte[] file);
|
||||||
@@ -31,20 +33,26 @@ namespace ModernKeePass.Application.Common.Interfaces
|
|||||||
void CloseDatabase();
|
void CloseDatabase();
|
||||||
|
|
||||||
EntryEntity GetEntry(string id);
|
EntryEntity GetEntry(string id);
|
||||||
GroupEntity GetGroup(string id);
|
|
||||||
Task AddEntry(string parentGroupId, string entryId);
|
Task AddEntry(string parentGroupId, string entryId);
|
||||||
Task MoveEntry(string parentGroupId, string entryId, int index);
|
Task MoveEntry(string parentGroupId, string entryId, int index);
|
||||||
Task AddGroup(string parentGroupId, string groupId);
|
void UpdateEntry(string entryId, string fieldName, object fieldValue, bool isProtected);
|
||||||
void UpdateEntry(string entryId, string fieldName, object fieldValue);
|
void DeleteField(string entryId, string fieldName);
|
||||||
void UpdateGroup(GroupEntity group);
|
|
||||||
Task RemoveEntry(string parentGroupId, string entryId);
|
Task RemoveEntry(string parentGroupId, string entryId);
|
||||||
|
EntryEntity CreateEntry(string parentGroupId);
|
||||||
|
void SortEntries(string groupId);
|
||||||
|
|
||||||
|
GroupEntity GetGroup(string id);
|
||||||
|
Task AddGroup(string parentGroupId, string groupId);
|
||||||
|
Task MoveGroup(string parentGroupId, string groupId, int index);
|
||||||
|
void UpdateGroup(GroupEntity group);
|
||||||
Task RemoveGroup(string parentGroupId, string groupId);
|
Task RemoveGroup(string parentGroupId, string groupId);
|
||||||
void DeleteEntity(string entityId);
|
void DeleteEntity(string entityId);
|
||||||
EntryEntity CreateEntry(string parentGroupId);
|
|
||||||
GroupEntity CreateGroup(string parentGroupId, string name, bool isRecycleBin = false);
|
GroupEntity CreateGroup(string parentGroupId, string name, bool isRecycleBin = false);
|
||||||
void SortEntries(string groupId);
|
|
||||||
void SortSubGroups(string groupId);
|
void SortSubGroups(string groupId);
|
||||||
|
|
||||||
|
void AddAttachment(string entryId, string attachmentName, byte[] attachmentContent);
|
||||||
|
void DeleteAttachment(string entryId, string attachmentName);
|
||||||
|
|
||||||
EntryEntity AddHistory(string entryId);
|
EntryEntity AddHistory(string entryId);
|
||||||
EntryEntity RestoreFromHistory(string entryId, int historyIndex);
|
EntryEntity RestoreFromHistory(string entryId, int historyIndex);
|
||||||
void DeleteHistory(string entryId, int historyIndex);
|
void DeleteHistory(string entryId, int historyIndex);
|
||||||
|
@@ -0,0 +1,12 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using ModernKeePass.Domain.Entities;
|
||||||
|
|
||||||
|
namespace ModernKeePass.Application.Common.Interfaces
|
||||||
|
{
|
||||||
|
public interface IDatabaseSettingsProxy
|
||||||
|
{
|
||||||
|
IEnumerable<BaseEntity> Ciphers { get; }
|
||||||
|
IEnumerable<BaseEntity> KeyDerivations { get; }
|
||||||
|
IEnumerable<string> CompressionAlgorithms { get; }
|
||||||
|
}
|
||||||
|
}
|
@@ -5,7 +5,6 @@ namespace ModernKeePass.Application.Common.Interfaces
|
|||||||
public interface IEntityVm
|
public interface IEntityVm
|
||||||
{
|
{
|
||||||
string Id { get; set; }
|
string Id { get; set; }
|
||||||
string Title { get; set; }
|
|
||||||
Icon Icon { get; set; }
|
Icon Icon { get; set; }
|
||||||
string ParentGroupId { get; set; }
|
string ParentGroupId { get; set; }
|
||||||
string ParentGroupName { get; set; }
|
string ParentGroupName { get; set; }
|
||||||
|
@@ -17,6 +17,8 @@ namespace ModernKeePass.Application.Database.Commands.CloseDatabase
|
|||||||
public void Handle(CloseDatabaseCommand message)
|
public void Handle(CloseDatabaseCommand message)
|
||||||
{
|
{
|
||||||
if (!_database.IsOpen) throw new DatabaseClosedException();
|
if (!_database.IsOpen) throw new DatabaseClosedException();
|
||||||
|
// Prevent reopening the database due to possible de-synchronization between app and data
|
||||||
|
if (_database.IsDirty) _database.FileAccessToken = null;
|
||||||
_database.CloseDatabase();
|
_database.CloseDatabase();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -64,17 +64,17 @@ namespace ModernKeePass.Application.Database.Commands.CreateDatabase
|
|||||||
_database.UpdateGroup(internetGroup);
|
_database.UpdateGroup(internetGroup);
|
||||||
|
|
||||||
var sample1 = _database.CreateEntry(_database.RootGroupId);
|
var sample1 = _database.CreateEntry(_database.RootGroupId);
|
||||||
_database.UpdateEntry(sample1.Id, EntryFieldName.Title, "Sample Entry" );
|
_database.UpdateEntry(sample1.Id, EntryFieldName.Title, "Sample Entry", false);
|
||||||
_database.UpdateEntry(sample1.Id, EntryFieldName.UserName, "Username" );
|
_database.UpdateEntry(sample1.Id, EntryFieldName.UserName, "Username", false);
|
||||||
_database.UpdateEntry(sample1.Id, EntryFieldName.Password, "Password" );
|
_database.UpdateEntry(sample1.Id, EntryFieldName.Password, "Password", true);
|
||||||
_database.UpdateEntry(sample1.Id, EntryFieldName.Url, "https://keepass.info/" );
|
_database.UpdateEntry(sample1.Id, EntryFieldName.Url, "https://keepass.info/", false);
|
||||||
_database.UpdateEntry(sample1.Id, EntryFieldName.Notes, "You may safely delete this sample" );
|
_database.UpdateEntry(sample1.Id, EntryFieldName.Notes, "You may safely delete this sample", false);
|
||||||
|
|
||||||
var sample2 = _database.CreateEntry(_database.RootGroupId);
|
var sample2 = _database.CreateEntry(_database.RootGroupId);
|
||||||
_database.UpdateEntry(sample2.Id, EntryFieldName.Title, "Sample Entry #2" );
|
_database.UpdateEntry(sample2.Id, EntryFieldName.Title, "Sample Entry #2", false);
|
||||||
_database.UpdateEntry(sample2.Id, EntryFieldName.UserName, "Michael321" );
|
_database.UpdateEntry(sample2.Id, EntryFieldName.UserName, "Michael321", false);
|
||||||
_database.UpdateEntry(sample2.Id, EntryFieldName.Password, "12345" );
|
_database.UpdateEntry(sample2.Id, EntryFieldName.Password, "12345", true);
|
||||||
_database.UpdateEntry(sample2.Id, EntryFieldName.Url, "https://keepass.info/help/kb/testform.html" );
|
_database.UpdateEntry(sample2.Id, EntryFieldName.Url, "https://keepass.info/help/kb/testform.html", false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -12,5 +12,7 @@
|
|||||||
public string KeyDerivationId { get; set; }
|
public string KeyDerivationId { get; set; }
|
||||||
public int Size { get; internal set; }
|
public int Size { get; internal set; }
|
||||||
public bool IsDirty { get; internal set; }
|
public bool IsDirty { get; internal set; }
|
||||||
|
public int MaxHistoryCount { get; set; }
|
||||||
|
public long MaxHistorySize { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -33,6 +33,8 @@ namespace ModernKeePass.Application.Database.Queries.GetDatabase
|
|||||||
database.KeyDerivationId = _databaseProxy.KeyDerivationId;
|
database.KeyDerivationId = _databaseProxy.KeyDerivationId;
|
||||||
database.Size = _databaseProxy.Size;
|
database.Size = _databaseProxy.Size;
|
||||||
database.IsDirty = _databaseProxy.IsDirty;
|
database.IsDirty = _databaseProxy.IsDirty;
|
||||||
|
database.MaxHistoryCount = _databaseProxy.MaxHistoryCount;
|
||||||
|
database.MaxHistorySize = _databaseProxy.MaxHistorySize;
|
||||||
}
|
}
|
||||||
return database;
|
return database;
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,34 @@
|
|||||||
|
using System;
|
||||||
|
using MediatR;
|
||||||
|
using ModernKeePass.Application.Common.Interfaces;
|
||||||
|
using ModernKeePass.Application.Entry.Models;
|
||||||
|
using ModernKeePass.Domain.Exceptions;
|
||||||
|
|
||||||
|
namespace ModernKeePass.Application.Entry.Commands.AddAttachment
|
||||||
|
{
|
||||||
|
public class AddAttachmentCommand : IRequest
|
||||||
|
{
|
||||||
|
public EntryVm Entry { get; set; }
|
||||||
|
public string AttachmentName { get; set; }
|
||||||
|
public byte[] AttachmentContent { get; set; }
|
||||||
|
|
||||||
|
public class AddAttachmentCommandHandler : IRequestHandler<AddAttachmentCommand>
|
||||||
|
{
|
||||||
|
private readonly IDatabaseProxy _database;
|
||||||
|
|
||||||
|
public AddAttachmentCommandHandler(IDatabaseProxy database)
|
||||||
|
{
|
||||||
|
_database = database;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Handle(AddAttachmentCommand message)
|
||||||
|
{
|
||||||
|
if (!_database.IsOpen) throw new DatabaseClosedException();
|
||||||
|
|
||||||
|
if (message.Entry.Attachments.ContainsKey(message.AttachmentName)) throw new ArgumentException("AttachmentAlreadyExists", nameof(message.AttachmentName));
|
||||||
|
_database.AddAttachment(message.Entry.Id, message.AttachmentName, message.AttachmentContent);
|
||||||
|
message.Entry.Attachments.Add(message.AttachmentName, message.AttachmentContent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,33 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using MediatR;
|
||||||
|
using ModernKeePass.Application.Common.Interfaces;
|
||||||
|
using ModernKeePass.Application.Entry.Models;
|
||||||
|
using ModernKeePass.Domain.Exceptions;
|
||||||
|
|
||||||
|
namespace ModernKeePass.Application.Entry.Commands.DeleteAttachment
|
||||||
|
{
|
||||||
|
public class DeleteAttachmentCommand : IRequest
|
||||||
|
{
|
||||||
|
public EntryVm Entry { get; set; }
|
||||||
|
public string AttachmentName { get; set; }
|
||||||
|
|
||||||
|
public class DeleteAttachmentCommandHandler : IRequestHandler<DeleteAttachmentCommand>
|
||||||
|
{
|
||||||
|
private readonly IDatabaseProxy _database;
|
||||||
|
|
||||||
|
public DeleteAttachmentCommandHandler(IDatabaseProxy database)
|
||||||
|
{
|
||||||
|
_database = database;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Handle(DeleteAttachmentCommand message)
|
||||||
|
{
|
||||||
|
if (!_database.IsOpen) throw new DatabaseClosedException();
|
||||||
|
|
||||||
|
if (!message.Entry.Attachments.ContainsKey(message.AttachmentName)) throw new KeyNotFoundException("AttachmentDoesntExist");
|
||||||
|
_database.DeleteAttachment(message.Entry.Id, message.AttachmentName);
|
||||||
|
message.Entry.Attachments.Remove(message.AttachmentName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,29 @@
|
|||||||
|
using MediatR;
|
||||||
|
using ModernKeePass.Application.Common.Interfaces;
|
||||||
|
using ModernKeePass.Domain.Exceptions;
|
||||||
|
|
||||||
|
namespace ModernKeePass.Application.Entry.Commands.DeleteField
|
||||||
|
{
|
||||||
|
public class DeleteFieldCommand: IRequest
|
||||||
|
{
|
||||||
|
public string EntryId { get; set; }
|
||||||
|
public string FieldName { get; set; }
|
||||||
|
|
||||||
|
public class DeleteFieldCommandHandler : IRequestHandler<DeleteFieldCommand>
|
||||||
|
{
|
||||||
|
private readonly IDatabaseProxy _database;
|
||||||
|
|
||||||
|
public DeleteFieldCommandHandler(IDatabaseProxy database)
|
||||||
|
{
|
||||||
|
_database = database;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Handle(DeleteFieldCommand message)
|
||||||
|
{
|
||||||
|
if (!_database.IsOpen) throw new DatabaseClosedException();
|
||||||
|
|
||||||
|
_database.DeleteField(message.EntryId, message.FieldName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -2,28 +2,29 @@
|
|||||||
using ModernKeePass.Application.Common.Interfaces;
|
using ModernKeePass.Application.Common.Interfaces;
|
||||||
using ModernKeePass.Domain.Exceptions;
|
using ModernKeePass.Domain.Exceptions;
|
||||||
|
|
||||||
namespace ModernKeePass.Application.Entry.Commands.SetFieldValue
|
namespace ModernKeePass.Application.Entry.Commands.UpsertField
|
||||||
{
|
{
|
||||||
public class SetFieldValueCommand : IRequest
|
public class UpsertFieldCommand : IRequest
|
||||||
{
|
{
|
||||||
public string EntryId { get; set; }
|
public string EntryId { get; set; }
|
||||||
public string FieldName { get; set; }
|
public string FieldName { get; set; }
|
||||||
public object FieldValue { get; set; }
|
public object FieldValue { get; set; }
|
||||||
|
public bool IsProtected { get; set; } = true;
|
||||||
|
|
||||||
public class SetFieldValueCommandHandler : IRequestHandler<SetFieldValueCommand>
|
public class UpsertFieldCommandHandler : IRequestHandler<UpsertFieldCommand>
|
||||||
{
|
{
|
||||||
private readonly IDatabaseProxy _database;
|
private readonly IDatabaseProxy _database;
|
||||||
|
|
||||||
public SetFieldValueCommandHandler(IDatabaseProxy database)
|
public UpsertFieldCommandHandler(IDatabaseProxy database)
|
||||||
{
|
{
|
||||||
_database = database;
|
_database = database;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Handle(SetFieldValueCommand message)
|
public void Handle(UpsertFieldCommand message)
|
||||||
{
|
{
|
||||||
if (!_database.IsOpen) throw new DatabaseClosedException();
|
if (!_database.IsOpen) throw new DatabaseClosedException();
|
||||||
|
|
||||||
_database.UpdateEntry(message.EntryId, message.FieldName, message.FieldValue);
|
_database.UpdateEntry(message.EntryId, message.FieldName, message.FieldValue, message.IsProtected);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,10 +1,10 @@
|
|||||||
using FluentValidation;
|
using FluentValidation;
|
||||||
|
|
||||||
namespace ModernKeePass.Application.Entry.Commands.SetFieldValue
|
namespace ModernKeePass.Application.Entry.Commands.UpsertField
|
||||||
{
|
{
|
||||||
public class SetFieldValueCommandValidator: AbstractValidator<SetFieldValueCommand>
|
public class UpsertFieldCommandValidator: AbstractValidator<UpsertFieldCommand>
|
||||||
{
|
{
|
||||||
public SetFieldValueCommandValidator()
|
public UpsertFieldCommandValidator()
|
||||||
{
|
{
|
||||||
RuleFor(v => v.EntryId)
|
RuleFor(v => v.EntryId)
|
||||||
.NotNull()
|
.NotNull()
|
@@ -15,13 +15,13 @@ namespace ModernKeePass.Application.Entry.Models
|
|||||||
public string ParentGroupId { get; set; }
|
public string ParentGroupId { get; set; }
|
||||||
public string ParentGroupName { get; set; }
|
public string ParentGroupName { get; set; }
|
||||||
public string Id { get; set; }
|
public string Id { get; set; }
|
||||||
public string Title { get; set; }
|
public FieldVm Title { get; set; }
|
||||||
public string Username { get; set; }
|
public FieldVm Username { get; set; }
|
||||||
public string Password { get; set; }
|
public FieldVm Password { get; set; }
|
||||||
public string Notes { get; set; }
|
public FieldVm Notes { get; set; }
|
||||||
public string Url { get; set; }
|
public FieldVm Url { get; set; }
|
||||||
public bool HasUrl => !string.IsNullOrEmpty(Url);
|
public bool IsValidUrl => Uri.IsWellFormedUriString(Url.Value, UriKind.Absolute);
|
||||||
public Dictionary<string, string> AdditionalFields { get; set; }
|
public List<FieldVm> AdditionalFields { get; set; }
|
||||||
public List<EntryVm> History { get; set; }
|
public List<EntryVm> History { get; set; }
|
||||||
public Icon Icon { get; set; }
|
public Icon Icon { get; set; }
|
||||||
public Color ForegroundColor { get; set; }
|
public Color ForegroundColor { get; set; }
|
||||||
@@ -29,6 +29,7 @@ namespace ModernKeePass.Application.Entry.Models
|
|||||||
public bool HasExpirationDate { get; set; }
|
public bool HasExpirationDate { get; set; }
|
||||||
public DateTimeOffset ExpirationDate { get; set; }
|
public DateTimeOffset ExpirationDate { get; set; }
|
||||||
public DateTimeOffset ModificationDate { get; set; }
|
public DateTimeOffset ModificationDate { get; set; }
|
||||||
|
public Dictionary<string, byte[]> Attachments { get; set; }
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
@@ -41,19 +42,26 @@ namespace ModernKeePass.Application.Entry.Models
|
|||||||
.ForMember(d => d.ParentGroupId, opts => opts.MapFrom(s => s.ParentId))
|
.ForMember(d => d.ParentGroupId, opts => opts.MapFrom(s => s.ParentId))
|
||||||
.ForMember(d => d.ParentGroupName, opts => opts.MapFrom(s => s.ParentName))
|
.ForMember(d => d.ParentGroupName, opts => opts.MapFrom(s => s.ParentName))
|
||||||
.ForMember(d => d.Id, opts => opts.MapFrom(s => s.Id))
|
.ForMember(d => d.Id, opts => opts.MapFrom(s => s.Id))
|
||||||
.ForMember(d => d.Title, opts => opts.MapFrom(s => s.Name))
|
.ForMember(d => d.Title, opts => opts.MapFrom(s => s.Fields.FirstOrDefault(f =>
|
||||||
.ForMember(d => d.Username, opts => opts.MapFrom(s => s.UserName))
|
f.Name.Equals(EntryFieldName.Title, StringComparison.OrdinalIgnoreCase)) ?? new FieldEntity { Name = EntryFieldName.Title, IsProtected = true } ))
|
||||||
.ForMember(d => d.Password, opts => opts.MapFrom(s => s.Password))
|
.ForMember(d => d.Username, opts => opts.MapFrom(s => s.Fields.FirstOrDefault(f =>
|
||||||
.ForMember(d => d.Url, opts => opts.MapFrom(s => s.Url))
|
f.Name.Equals(EntryFieldName.UserName, StringComparison.OrdinalIgnoreCase)) ?? new FieldEntity { Name = EntryFieldName.UserName, IsProtected = true } ))
|
||||||
.ForMember(d => d.Notes, opts => opts.MapFrom(s => s.Notes))
|
.ForMember(d => d.Password, opts => opts.MapFrom(s => s.Fields.FirstOrDefault(f =>
|
||||||
.ForMember(d => d.AdditionalFields, opts => opts.MapFrom(s => s.AdditionalFields))
|
f.Name.Equals(EntryFieldName.Password, StringComparison.OrdinalIgnoreCase)) ?? new FieldEntity { Name = EntryFieldName.Password, IsProtected = true } ))
|
||||||
|
.ForMember(d => d.Url, opts => opts.MapFrom(s => s.Fields.FirstOrDefault(f =>
|
||||||
|
f.Name.Equals(EntryFieldName.Url, StringComparison.OrdinalIgnoreCase)) ?? new FieldEntity { Name = EntryFieldName.Url, IsProtected = true } ))
|
||||||
|
.ForMember(d => d.Notes, opts => opts.MapFrom(s => s.Fields.FirstOrDefault(f =>
|
||||||
|
f.Name.Equals(EntryFieldName.Notes, StringComparison.OrdinalIgnoreCase)) ?? new FieldEntity { Name = EntryFieldName.Notes, IsProtected = true } ))
|
||||||
|
.ForMember(d => d.AdditionalFields, opts => opts.MapFrom(s =>
|
||||||
|
s.Fields.Where(f => !EntryFieldName.StandardFieldNames.Contains(f.Name, StringComparer.OrdinalIgnoreCase))))
|
||||||
.ForMember(d => d.History, opts => opts.MapFrom(s => s.History.Reverse()))
|
.ForMember(d => d.History, opts => opts.MapFrom(s => s.History.Reverse()))
|
||||||
.ForMember(d => d.HasExpirationDate, opts => opts.MapFrom(s => s.HasExpirationDate))
|
.ForMember(d => d.HasExpirationDate, opts => opts.MapFrom(s => s.HasExpirationDate))
|
||||||
.ForMember(d => d.ExpirationDate, opts => opts.MapFrom(s => s.ExpirationDate))
|
.ForMember(d => d.ExpirationDate, opts => opts.MapFrom(s => s.ExpirationDate))
|
||||||
.ForMember(d => d.ModificationDate, opts => opts.MapFrom(s => s.LastModificationDate))
|
.ForMember(d => d.ModificationDate, opts => opts.MapFrom(s => s.LastModificationDate))
|
||||||
.ForMember(d => d.Icon, opts => opts.MapFrom(s => s.HasExpirationDate && s.ExpirationDate < DateTimeOffset.Now ? Icon.ReportHacked : s.Icon))
|
.ForMember(d => d.Icon, opts => opts.MapFrom(s => s.HasExpirationDate && s.ExpirationDate < DateTimeOffset.Now ? Icon.ReportHacked : s.Icon))
|
||||||
.ForMember(d => d.ForegroundColor, opts => opts.MapFrom(s => s.ForegroundColor))
|
.ForMember(d => d.ForegroundColor, opts => opts.MapFrom(s => s.ForegroundColor))
|
||||||
.ForMember(d => d.BackgroundColor, opts => opts.MapFrom(s => s.BackgroundColor));
|
.ForMember(d => d.BackgroundColor, opts => opts.MapFrom(s => s.BackgroundColor))
|
||||||
|
.ForMember(d => d.Attachments, opts => opts.MapFrom(s => s.Attachments));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
20
ModernKeePass.Application/Entry/Models/FieldVm.cs
Normal file
20
ModernKeePass.Application/Entry/Models/FieldVm.cs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
using AutoMapper;
|
||||||
|
using ModernKeePass.Application.Common.Mappings;
|
||||||
|
using ModernKeePass.Domain.Entities;
|
||||||
|
|
||||||
|
namespace ModernKeePass.Application.Entry.Models
|
||||||
|
{
|
||||||
|
public class FieldVm: IMapFrom<FieldEntity>
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string Value { get; set; }
|
||||||
|
public bool IsProtected { get; set; }
|
||||||
|
|
||||||
|
public override string ToString() => Value;
|
||||||
|
|
||||||
|
public void Mapping(Profile profile)
|
||||||
|
{
|
||||||
|
profile.CreateMap<FieldEntity, FieldVm>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -25,12 +25,13 @@ namespace ModernKeePass.Application.Group.Commands.DeleteGroup
|
|||||||
{
|
{
|
||||||
if (!_database.IsOpen) throw new DatabaseClosedException();
|
if (!_database.IsOpen) throw new DatabaseClosedException();
|
||||||
|
|
||||||
|
var isRecycleBin = message.GroupId.Equals(_database.RecycleBinId);
|
||||||
if (_database.IsRecycleBinEnabled && (string.IsNullOrEmpty(_database.RecycleBinId) || _database.RecycleBinId.Equals(Constants.EmptyId)))
|
if (_database.IsRecycleBinEnabled && (string.IsNullOrEmpty(_database.RecycleBinId) || _database.RecycleBinId.Equals(Constants.EmptyId)))
|
||||||
{
|
{
|
||||||
_database.CreateGroup(_database.RootGroupId, message.RecycleBinName, true);
|
_database.CreateGroup(_database.RootGroupId, message.RecycleBinName, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_database.IsRecycleBinEnabled || message.ParentGroupId.Equals(_database.RecycleBinId))
|
if (!_database.IsRecycleBinEnabled || message.ParentGroupId.Equals(_database.RecycleBinId) || isRecycleBin)
|
||||||
{
|
{
|
||||||
_database.DeleteEntity(message.GroupId);
|
_database.DeleteEntity(message.GroupId);
|
||||||
}
|
}
|
||||||
@@ -40,6 +41,7 @@ namespace ModernKeePass.Application.Group.Commands.DeleteGroup
|
|||||||
}
|
}
|
||||||
|
|
||||||
await _database.RemoveGroup(message.ParentGroupId, message.GroupId);
|
await _database.RemoveGroup(message.ParentGroupId, message.GroupId);
|
||||||
|
if (isRecycleBin) _database.RecycleBinId = Constants.EmptyId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,33 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
using MediatR;
|
||||||
|
using ModernKeePass.Application.Common.Interfaces;
|
||||||
|
using ModernKeePass.Application.Group.Models;
|
||||||
|
using ModernKeePass.Domain.Exceptions;
|
||||||
|
|
||||||
|
namespace ModernKeePass.Application.Group.Commands.MoveGroup
|
||||||
|
{
|
||||||
|
public class MoveGroupCommand : IRequest
|
||||||
|
{
|
||||||
|
public GroupVm ParentGroup { get; set; }
|
||||||
|
public GroupVm Group { get; set; }
|
||||||
|
public int Index { get; set; }
|
||||||
|
|
||||||
|
public class MoveGroupCommandHandler : IAsyncRequestHandler<MoveGroupCommand>
|
||||||
|
{
|
||||||
|
private readonly IDatabaseProxy _database;
|
||||||
|
|
||||||
|
public MoveGroupCommandHandler(IDatabaseProxy database)
|
||||||
|
{
|
||||||
|
_database = database;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Handle(MoveGroupCommand message)
|
||||||
|
{
|
||||||
|
if (!_database.IsOpen) throw new DatabaseClosedException();
|
||||||
|
|
||||||
|
await _database.MoveGroup(message.ParentGroup.Id, message.Group.Id, message.Index);
|
||||||
|
message.ParentGroup.SubGroups.Insert(message.Index, message.Group);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -24,7 +24,7 @@ namespace ModernKeePass.Application.Group.Commands.SortEntries
|
|||||||
if (!_database.IsOpen) throw new DatabaseClosedException();
|
if (!_database.IsOpen) throw new DatabaseClosedException();
|
||||||
|
|
||||||
_database.SortEntries(message.Group.Id);
|
_database.SortEntries(message.Group.Id);
|
||||||
message.Group.Entries = message.Group.Entries.OrderBy(e => e.Title).ToList();
|
message.Group.Entries = message.Group.Entries.OrderBy(e => e.Title.Value).ToList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,27 @@
|
|||||||
|
using MediatR;
|
||||||
|
using ModernKeePass.Application.Common.Interfaces;
|
||||||
|
using ModernKeePass.Domain.Exceptions;
|
||||||
|
|
||||||
|
namespace ModernKeePass.Application.Parameters.Commands.SetMaxHistoryCount
|
||||||
|
{
|
||||||
|
public class SetMaxHistoryCountCommand : IRequest
|
||||||
|
{
|
||||||
|
public int MaxHistoryCount { get; set; }
|
||||||
|
|
||||||
|
public class SetMaxHistoryCountCommandHandler : IRequestHandler<SetMaxHistoryCountCommand>
|
||||||
|
{
|
||||||
|
private readonly IDatabaseProxy _database;
|
||||||
|
|
||||||
|
public SetMaxHistoryCountCommandHandler(IDatabaseProxy database)
|
||||||
|
{
|
||||||
|
_database = database;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Handle(SetMaxHistoryCountCommand message)
|
||||||
|
{
|
||||||
|
if (_database.IsOpen) _database.MaxHistoryCount = message.MaxHistoryCount;
|
||||||
|
else throw new DatabaseClosedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,28 @@
|
|||||||
|
using MediatR;
|
||||||
|
using ModernKeePass.Application.Common.Interfaces;
|
||||||
|
using ModernKeePass.Domain.Exceptions;
|
||||||
|
|
||||||
|
namespace ModernKeePass.Application.Parameters.Commands.SetMaxHistorySize
|
||||||
|
{
|
||||||
|
public class SetMaxHistorySizeCommand : IRequest
|
||||||
|
{
|
||||||
|
public long MaxHistorySize { get; set; }
|
||||||
|
|
||||||
|
public class SetMaxHistorySizeCommandHandler : IRequestHandler<SetMaxHistorySizeCommand>
|
||||||
|
{
|
||||||
|
private readonly IDatabaseProxy _database;
|
||||||
|
|
||||||
|
public SetMaxHistorySizeCommandHandler(IDatabaseProxy database)
|
||||||
|
{
|
||||||
|
_database = database;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Handle(SetMaxHistorySizeCommand message)
|
||||||
|
{
|
||||||
|
if (_database.IsOpen) _database.MaxHistorySize = message.MaxHistorySize;
|
||||||
|
else throw new DatabaseClosedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@@ -10,16 +10,16 @@ namespace ModernKeePass.Application.Parameters.Queries.GetCiphers
|
|||||||
{
|
{
|
||||||
public class GetCiphersQueryHandler: IRequestHandler<GetCiphersQuery, IEnumerable<CipherVm>>
|
public class GetCiphersQueryHandler: IRequestHandler<GetCiphersQuery, IEnumerable<CipherVm>>
|
||||||
{
|
{
|
||||||
private readonly ICryptographyClient _cryptography;
|
private readonly IDatabaseSettingsProxy _databaseSettings;
|
||||||
|
|
||||||
public GetCiphersQueryHandler(ICryptographyClient cryptography)
|
public GetCiphersQueryHandler(IDatabaseSettingsProxy databaseSettings)
|
||||||
{
|
{
|
||||||
_cryptography = cryptography;
|
_databaseSettings = databaseSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<CipherVm> Handle(GetCiphersQuery message)
|
public IEnumerable<CipherVm> Handle(GetCiphersQuery message)
|
||||||
{
|
{
|
||||||
return _cryptography.Ciphers.Select(c => new CipherVm
|
return _databaseSettings.Ciphers.Select(c => new CipherVm
|
||||||
{
|
{
|
||||||
Id = c.Id,
|
Id = c.Id,
|
||||||
Name = c.Name
|
Name = c.Name
|
||||||
|
@@ -9,16 +9,16 @@ namespace ModernKeePass.Application.Parameters.Queries.GetCompressions
|
|||||||
{
|
{
|
||||||
public class GetCompressionsQueryHandler : IRequestHandler<GetCompressionsQuery, IEnumerable<string>>
|
public class GetCompressionsQueryHandler : IRequestHandler<GetCompressionsQuery, IEnumerable<string>>
|
||||||
{
|
{
|
||||||
private readonly ICryptographyClient _cryptography;
|
private readonly IDatabaseSettingsProxy _databaseSettings;
|
||||||
|
|
||||||
public GetCompressionsQueryHandler(ICryptographyClient cryptography)
|
public GetCompressionsQueryHandler(IDatabaseSettingsProxy databaseSettings)
|
||||||
{
|
{
|
||||||
_cryptography = cryptography;
|
_databaseSettings = databaseSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<string> Handle(GetCompressionsQuery message)
|
public IEnumerable<string> Handle(GetCompressionsQuery message)
|
||||||
{
|
{
|
||||||
return _cryptography.CompressionAlgorithms.OrderBy(c => c);
|
return _databaseSettings.CompressionAlgorithms.OrderBy(c => c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -10,16 +10,16 @@ namespace ModernKeePass.Application.Parameters.Queries.GetKeyDerivations
|
|||||||
{
|
{
|
||||||
public class GetKeyDerivationsQueryHandler : IRequestHandler<GetKeyDerivationsQuery, IEnumerable<KeyDerivationVm>>
|
public class GetKeyDerivationsQueryHandler : IRequestHandler<GetKeyDerivationsQuery, IEnumerable<KeyDerivationVm>>
|
||||||
{
|
{
|
||||||
private readonly ICryptographyClient _cryptography;
|
private readonly IDatabaseSettingsProxy _databaseSettings;
|
||||||
|
|
||||||
public GetKeyDerivationsQueryHandler(ICryptographyClient cryptography)
|
public GetKeyDerivationsQueryHandler(IDatabaseSettingsProxy databaseSettings)
|
||||||
{
|
{
|
||||||
_cryptography = cryptography;
|
_databaseSettings = databaseSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<KeyDerivationVm> Handle(GetKeyDerivationsQuery message)
|
public IEnumerable<KeyDerivationVm> Handle(GetKeyDerivationsQuery message)
|
||||||
{
|
{
|
||||||
return _cryptography.KeyDerivations.Select(c => new KeyDerivationVm
|
return _databaseSettings.KeyDerivations.Select(c => new KeyDerivationVm
|
||||||
{
|
{
|
||||||
Id = c.Id,
|
Id = c.Id,
|
||||||
Name = c.Name
|
Name = c.Name
|
||||||
|
@@ -76,11 +76,13 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Common\Constants.cs" />
|
<Compile Include="Common\Constants.cs" />
|
||||||
|
<Compile Include="Dtos\Attachment.cs" />
|
||||||
<Compile Include="Dtos\Credentials.cs" />
|
<Compile Include="Dtos\Credentials.cs" />
|
||||||
<Compile Include="Dtos\FileInfo.cs" />
|
<Compile Include="Dtos\FileInfo.cs" />
|
||||||
<Compile Include="Dtos\PasswordGenerationOptions.cs" />
|
<Compile Include="Dtos\PasswordGenerationOptions.cs" />
|
||||||
<Compile Include="Entities\BaseEntity.cs" />
|
<Compile Include="Entities\BaseEntity.cs" />
|
||||||
<Compile Include="Entities\EntryEntity.cs" />
|
<Compile Include="Entities\EntryEntity.cs" />
|
||||||
|
<Compile Include="Entities\FieldEntity.cs" />
|
||||||
<Compile Include="Entities\GroupEntity.cs" />
|
<Compile Include="Entities\GroupEntity.cs" />
|
||||||
<Compile Include="Enums\CredentialStatusTypes.cs" />
|
<Compile Include="Enums\CredentialStatusTypes.cs" />
|
||||||
<Compile Include="Enums\DatabaseVersion.cs" />
|
<Compile Include="Enums\DatabaseVersion.cs" />
|
||||||
|
8
ModernKeePass.Domain/Dtos/Attachment.cs
Normal file
8
ModernKeePass.Domain/Dtos/Attachment.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
namespace ModernKeePass.Domain.Dtos
|
||||||
|
{
|
||||||
|
public class Attachment
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
public byte[] Content { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@@ -7,13 +7,10 @@ namespace ModernKeePass.Domain.Entities
|
|||||||
{
|
{
|
||||||
public class EntryEntity: BaseEntity
|
public class EntryEntity: BaseEntity
|
||||||
{
|
{
|
||||||
public string UserName { get; set; }
|
public IEnumerable<FieldEntity> Fields { get; set; } = new List<FieldEntity>();
|
||||||
public string Password { get; set; }
|
|
||||||
public string Url { get; set; }
|
|
||||||
public string Notes { get; set; }
|
|
||||||
public DateTimeOffset ExpirationDate { get; set; }
|
|
||||||
public Dictionary<string, string> AdditionalFields { get; set; } = new Dictionary<string, string>();
|
|
||||||
public IEnumerable<EntryEntity> History { get; set; } = new List<EntryEntity>();
|
public IEnumerable<EntryEntity> History { get; set; } = new List<EntryEntity>();
|
||||||
|
public Dictionary<string, byte[]> Attachments { get; set; } = new Dictionary<string, byte[]>();
|
||||||
|
public DateTimeOffset ExpirationDate { 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; }
|
||||||
|
9
ModernKeePass.Domain/Entities/FieldEntity.cs
Normal file
9
ModernKeePass.Domain/Entities/FieldEntity.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
namespace ModernKeePass.Domain.Entities
|
||||||
|
{
|
||||||
|
public class FieldEntity
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string Value { get; set; }
|
||||||
|
public bool IsProtected { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@@ -1,4 +1,6 @@
|
|||||||
namespace ModernKeePass.Domain.Enums
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace ModernKeePass.Domain.Enums
|
||||||
{
|
{
|
||||||
public static class EntryFieldName
|
public static class EntryFieldName
|
||||||
{
|
{
|
||||||
@@ -12,5 +14,19 @@
|
|||||||
public const string HasExpirationDate = nameof(HasExpirationDate);
|
public const string HasExpirationDate = nameof(HasExpirationDate);
|
||||||
public const string BackgroundColor = nameof(BackgroundColor);
|
public const string BackgroundColor = nameof(BackgroundColor);
|
||||||
public const string ForegroundColor = nameof(ForegroundColor);
|
public const string ForegroundColor = nameof(ForegroundColor);
|
||||||
|
|
||||||
|
public static IEnumerable<string> StandardFieldNames = new[]
|
||||||
|
{
|
||||||
|
Title,
|
||||||
|
UserName,
|
||||||
|
Password,
|
||||||
|
Url,
|
||||||
|
Notes,
|
||||||
|
Icon,
|
||||||
|
ExpirationDate,
|
||||||
|
HasExpirationDate,
|
||||||
|
BackgroundColor,
|
||||||
|
ForegroundColor
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -18,7 +18,7 @@ namespace ModernKeePass.Infrastructure
|
|||||||
public static IServiceCollection AddInfrastructureKeePass(this IServiceCollection services)
|
public static IServiceCollection AddInfrastructureKeePass(this IServiceCollection services)
|
||||||
{
|
{
|
||||||
services.AddSingleton(typeof(IDatabaseProxy), typeof(KeePassDatabaseClient));
|
services.AddSingleton(typeof(IDatabaseProxy), typeof(KeePassDatabaseClient));
|
||||||
services.AddTransient(typeof(ICryptographyClient), typeof(KeePassCryptographyClient));
|
services.AddTransient(typeof(IDatabaseSettingsProxy), typeof(KeePassDatabaseSettingsProxy));
|
||||||
services.AddTransient(typeof(ICredentialsProxy), typeof(KeePassCredentialsClient));
|
services.AddTransient(typeof(ICredentialsProxy), typeof(KeePassCredentialsClient));
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
@@ -29,6 +29,7 @@ namespace ModernKeePass.Infrastructure
|
|||||||
services.AddTransient(typeof(ISettingsProxy), typeof(UwpSettingsClient));
|
services.AddTransient(typeof(ISettingsProxy), typeof(UwpSettingsClient));
|
||||||
services.AddTransient(typeof(IRecentProxy), typeof(UwpRecentFilesClient));
|
services.AddTransient(typeof(IRecentProxy), typeof(UwpRecentFilesClient));
|
||||||
services.AddTransient(typeof(IResourceProxy), typeof(UwpResourceClient));
|
services.AddTransient(typeof(IResourceProxy), typeof(UwpResourceClient));
|
||||||
|
services.AddTransient(typeof(ICryptographyClient), typeof(UwpCryptographyClient));
|
||||||
services.AddTransient(typeof(INotificationService), typeof(ToastNotificationService));
|
services.AddTransient(typeof(INotificationService), typeof(ToastNotificationService));
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
@@ -80,15 +80,15 @@
|
|||||||
<Compile Include="DependencyInjection.cs" />
|
<Compile Include="DependencyInjection.cs" />
|
||||||
<Compile Include="File\CsvImportFormat.cs" />
|
<Compile Include="File\CsvImportFormat.cs" />
|
||||||
<Compile Include="KeePass\EntryFieldMapper.cs" />
|
<Compile Include="KeePass\EntryFieldMapper.cs" />
|
||||||
<Compile Include="KeePass\EntryMappingProfile.cs" />
|
<Compile Include="KeePass\MappingProfiles.cs" />
|
||||||
<Compile Include="KeePass\GroupMappingProfile.cs" />
|
|
||||||
<Compile Include="KeePass\IconMapper.cs" />
|
<Compile Include="KeePass\IconMapper.cs" />
|
||||||
<Compile Include="KeePass\KeePassCryptographyClient.cs" />
|
<Compile Include="KeePass\KeePassDatabaseSettingsProxy.cs" />
|
||||||
<Compile Include="KeePass\KeePassDatabaseClient.cs" />
|
<Compile Include="KeePass\KeePassDatabaseClient.cs" />
|
||||||
<Compile Include="KeePass\KeePassCredentialsClient.cs" />
|
<Compile Include="KeePass\KeePassCredentialsClient.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="UWP\StorageFileClient.cs" />
|
<Compile Include="UWP\StorageFileClient.cs" />
|
||||||
<Compile Include="UWP\ToastNotificationService.cs" />
|
<Compile Include="UWP\ToastNotificationService.cs" />
|
||||||
|
<Compile Include="UWP\UwpCryptographyClient.cs" />
|
||||||
<Compile Include="UWP\UwpRecentFilesClient.cs" />
|
<Compile Include="UWP\UwpRecentFilesClient.cs" />
|
||||||
<Compile Include="UWP\UwpResourceClient.cs" />
|
<Compile Include="UWP\UwpResourceClient.cs" />
|
||||||
<Compile Include="UWP\UwpSettingsClient.cs" />
|
<Compile Include="UWP\UwpSettingsClient.cs" />
|
||||||
|
@@ -1,35 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using AutoMapper;
|
|
||||||
using ModernKeePass.Domain.Entities;
|
|
||||||
using ModernKeePassLib;
|
|
||||||
|
|
||||||
namespace ModernKeePass.Infrastructure.KeePass
|
|
||||||
{
|
|
||||||
public class EntryMappingProfile: Profile
|
|
||||||
{
|
|
||||||
public EntryMappingProfile()
|
|
||||||
{
|
|
||||||
CreateMap<PwEntry, EntryEntity>()
|
|
||||||
.ForMember(dest => dest.ParentId, opt => opt.MapFrom(src => src.ParentGroup.Uuid.ToHexString()))
|
|
||||||
.ForMember(dest => dest.ParentName, opt => opt.MapFrom(src => src.ParentGroup.Name))
|
|
||||||
.ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.Uuid.ToHexString()))
|
|
||||||
.ForMember(dest => dest.Name, opt => opt.MapFrom(src => GetEntryValue(src, PwDefs.TitleField)))
|
|
||||||
.ForMember(dest => dest.UserName, opt => opt.MapFrom(src => GetEntryValue(src, PwDefs.UserNameField)))
|
|
||||||
.ForMember(dest => dest.Password, opt => opt.MapFrom(src => GetEntryValue(src, PwDefs.PasswordField)))
|
|
||||||
.ForMember(dest => dest.Url, opt => opt.MapFrom(src => GetEntryValue(src, PwDefs.UrlField)))
|
|
||||||
.ForMember(dest => dest.Notes, opt => opt.MapFrom(src => GetEntryValue(src, PwDefs.NotesField)))
|
|
||||||
.ForMember(dest => dest.ForegroundColor, opt => opt.MapFrom(src => src.ForegroundColor))
|
|
||||||
.ForMember(dest => dest.BackgroundColor, opt => opt.MapFrom(src => src.BackgroundColor))
|
|
||||||
.ForMember(dest => dest.ExpirationDate, opt => opt.MapFrom(src => new DateTimeOffset(src.ExpiryTime)))
|
|
||||||
.ForMember(dest => dest.HasExpirationDate, opt => opt.MapFrom(src => src.Expires))
|
|
||||||
.ForMember(dest => dest.Icon, opt => opt.MapFrom(src => IconMapper.MapPwIconToIcon(src.IconId)))
|
|
||||||
.ForMember(dest => dest.AdditionalFields, opt => opt.MapFrom(src =>
|
|
||||||
src.Strings.Where(s => !PwDefs.GetStandardFields().Contains(s.Key))
|
|
||||||
.ToDictionary(s => s.Key, s => GetEntryValue(src, s.Key))))
|
|
||||||
.ForMember(dest => dest.LastModificationDate, opt => opt.MapFrom(src => new DateTimeOffset(src.LastModificationTime)));
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetEntryValue(PwEntry entry, string key) => entry.Strings.GetSafe(key).ReadString();
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,23 +0,0 @@
|
|||||||
using AutoMapper;
|
|
||||||
using ModernKeePass.Domain.Entities;
|
|
||||||
using ModernKeePassLib;
|
|
||||||
|
|
||||||
namespace ModernKeePass.Infrastructure.KeePass
|
|
||||||
{
|
|
||||||
public class GroupMappingProfile : Profile
|
|
||||||
{
|
|
||||||
public GroupMappingProfile()
|
|
||||||
{
|
|
||||||
CreateMap<PwGroup, GroupEntity>()
|
|
||||||
.ForMember(d => d.ParentId, opts => opts.MapFrom(s => s.ParentGroup.Uuid.ToHexString()))
|
|
||||||
.ForMember(d => d.ParentName, opts => opts.MapFrom(s => s.ParentGroup.Name))
|
|
||||||
.ForMember(d => d.Id, opts => opts.MapFrom(s => s.Uuid.ToHexString()))
|
|
||||||
.ForMember(d => d.Name, opts => opts.MapFrom(s => s.Name))
|
|
||||||
.ForMember(d => d.Icon, opts => opts.MapFrom(s => IconMapper.MapPwIconToIcon(s.IconId)))
|
|
||||||
.ForMember(d => d.LastModificationDate, opts => opts.MapFrom(s => s.LastModificationTime))
|
|
||||||
.ForMember(d => d.Entries, opts => opts.MapFrom(s => s.Entries))
|
|
||||||
.ForMember(d => d.SubGroups, opts => opts.MapFrom(s => s.Groups))
|
|
||||||
.MaxDepth(2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -40,6 +40,18 @@ namespace ModernKeePass.Infrastructure.KeePass
|
|||||||
public int Size { get; set; }
|
public int Size { get; set; }
|
||||||
public bool IsDirty { get; set; }
|
public bool IsDirty { get; set; }
|
||||||
|
|
||||||
|
public int MaxHistoryCount
|
||||||
|
{
|
||||||
|
get { return _pwDatabase.HistoryMaxItems; }
|
||||||
|
set { _pwDatabase.HistoryMaxItems = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public long MaxHistorySize
|
||||||
|
{
|
||||||
|
get { return _pwDatabase.HistoryMaxSize; }
|
||||||
|
set { _pwDatabase.HistoryMaxSize = value; }
|
||||||
|
}
|
||||||
|
|
||||||
// Settings
|
// Settings
|
||||||
public bool IsRecycleBinEnabled
|
public bool IsRecycleBinEnabled
|
||||||
{
|
{
|
||||||
@@ -189,6 +201,20 @@ namespace ModernKeePass.Infrastructure.KeePass
|
|||||||
parentPwGroup.AddGroup(pwGroup, true);
|
parentPwGroup.AddGroup(pwGroup, true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task MoveGroup(string parentGroupId, string groupId, int index)
|
||||||
|
{
|
||||||
|
await Task.Run(() =>
|
||||||
|
{
|
||||||
|
var parentPwGroup = _pwDatabase.RootGroup.FindGroup(BuildIdFromString(parentGroupId), true);
|
||||||
|
var pwGroup = _pwDatabase.RootGroup.FindGroup(BuildIdFromString(groupId), true);
|
||||||
|
var currentIndex = (uint)parentPwGroup.Groups.IndexOf(pwGroup);
|
||||||
|
|
||||||
|
parentPwGroup.Groups.RemoveAt(currentIndex);
|
||||||
|
parentPwGroup.Groups.Insert((uint)index, pwGroup);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public async Task RemoveEntry(string parentGroupId, string entryId)
|
public async Task RemoveEntry(string parentGroupId, string entryId)
|
||||||
{
|
{
|
||||||
await Task.Run(() =>
|
await Task.Run(() =>
|
||||||
@@ -214,7 +240,7 @@ namespace ModernKeePass.Infrastructure.KeePass
|
|||||||
_pwDatabase.DeletedObjects.Add(new PwDeletedObject(BuildIdFromString(entityId), _dateTime.Now));
|
_pwDatabase.DeletedObjects.Add(new PwDeletedObject(BuildIdFromString(entityId), _dateTime.Now));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateEntry(string entryId, string fieldName, object fieldValue)
|
public void UpdateEntry(string entryId, string fieldName, object fieldValue, bool isProtected)
|
||||||
{
|
{
|
||||||
var pwEntry = _pwDatabase.RootGroup.FindEntry(BuildIdFromString(entryId), true);
|
var pwEntry = _pwDatabase.RootGroup.FindEntry(BuildIdFromString(entryId), true);
|
||||||
|
|
||||||
@@ -225,7 +251,7 @@ namespace ModernKeePass.Infrastructure.KeePass
|
|||||||
case EntryFieldName.Password:
|
case EntryFieldName.Password:
|
||||||
case EntryFieldName.Notes:
|
case EntryFieldName.Notes:
|
||||||
case EntryFieldName.Url:
|
case EntryFieldName.Url:
|
||||||
pwEntry.Strings.Set(EntryFieldMapper.MapFieldToPwDef(fieldName), new ProtectedString(true, fieldValue.ToString()));
|
pwEntry.Strings.Set(EntryFieldMapper.MapFieldToPwDef(fieldName), new ProtectedString(isProtected, fieldValue.ToString()));
|
||||||
break;
|
break;
|
||||||
case EntryFieldName.HasExpirationDate:
|
case EntryFieldName.HasExpirationDate:
|
||||||
pwEntry.Expires = (bool)fieldValue;
|
pwEntry.Expires = (bool)fieldValue;
|
||||||
@@ -242,9 +268,18 @@ namespace ModernKeePass.Infrastructure.KeePass
|
|||||||
case EntryFieldName.ForegroundColor:
|
case EntryFieldName.ForegroundColor:
|
||||||
pwEntry.ForegroundColor = (Color)fieldValue;
|
pwEntry.ForegroundColor = (Color)fieldValue;
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
pwEntry.Strings.Set(fieldName, new ProtectedString(isProtected, fieldValue.ToString()));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void DeleteField(string entryId, string fieldName)
|
||||||
|
{
|
||||||
|
var pwEntry = _pwDatabase.RootGroup.FindEntry(BuildIdFromString(entryId), true);
|
||||||
|
pwEntry.Strings.Remove(fieldName);
|
||||||
|
}
|
||||||
|
|
||||||
public EntryEntity AddHistory(string entryId)
|
public EntryEntity AddHistory(string entryId)
|
||||||
{
|
{
|
||||||
var pwEntry = _pwDatabase.RootGroup.FindEntry(BuildIdFromString(entryId), true);
|
var pwEntry = _pwDatabase.RootGroup.FindEntry(BuildIdFromString(entryId), true);
|
||||||
@@ -307,6 +342,18 @@ namespace ModernKeePass.Infrastructure.KeePass
|
|||||||
pwGroup.SortSubGroups(false);
|
pwGroup.SortSubGroups(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void AddAttachment(string entryId, string attachmentName, byte[] attachmentContent)
|
||||||
|
{
|
||||||
|
var pwEntry = _pwDatabase.RootGroup.FindEntry(BuildIdFromString(entryId), true);
|
||||||
|
pwEntry.Binaries.Set(attachmentName, new ProtectedBinary(true, attachmentContent));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DeleteAttachment(string entryId, string attachmentName)
|
||||||
|
{
|
||||||
|
var pwEntry = _pwDatabase.RootGroup.FindEntry(BuildIdFromString(entryId), true);
|
||||||
|
pwEntry.Binaries.Remove(attachmentName);
|
||||||
|
}
|
||||||
|
|
||||||
public EntryEntity GetEntry(string id)
|
public EntryEntity GetEntry(string id)
|
||||||
{
|
{
|
||||||
var pwEntry = _pwDatabase.RootGroup.FindEntry(BuildIdFromString(id), true);
|
var pwEntry = _pwDatabase.RootGroup.FindEntry(BuildIdFromString(id), true);
|
||||||
|
@@ -9,7 +9,7 @@ using ModernKeePassLib.Cryptography.KeyDerivation;
|
|||||||
|
|
||||||
namespace ModernKeePass.Infrastructure.KeePass
|
namespace ModernKeePass.Infrastructure.KeePass
|
||||||
{
|
{
|
||||||
public class KeePassCryptographyClient: ICryptographyClient
|
public class KeePassDatabaseSettingsProxy: IDatabaseSettingsProxy
|
||||||
{
|
{
|
||||||
public IEnumerable<BaseEntity> Ciphers
|
public IEnumerable<BaseEntity> Ciphers
|
||||||
{
|
{
|
45
ModernKeePass.Infrastructure/KeePass/MappingProfiles.cs
Normal file
45
ModernKeePass.Infrastructure/KeePass/MappingProfiles.cs
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using AutoMapper;
|
||||||
|
using ModernKeePass.Domain.Entities;
|
||||||
|
using ModernKeePassLib;
|
||||||
|
using ModernKeePassLib.Security;
|
||||||
|
|
||||||
|
namespace ModernKeePass.Infrastructure.KeePass
|
||||||
|
{
|
||||||
|
public class MappingProfiles: Profile
|
||||||
|
{
|
||||||
|
public MappingProfiles()
|
||||||
|
{
|
||||||
|
CreateMap<KeyValuePair<string, ProtectedString>, FieldEntity>()
|
||||||
|
.ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.Key))
|
||||||
|
.ForMember(dest => dest.Value, opt => opt.MapFrom(src => src.Value.ReadString()))
|
||||||
|
.ForMember(dest => dest.IsProtected, opt => opt.MapFrom(src => src.Value.IsProtected));
|
||||||
|
|
||||||
|
CreateMap<PwEntry, EntryEntity>()
|
||||||
|
.ForMember(dest => dest.ParentId, opt => opt.MapFrom(src => src.ParentGroup.Uuid.ToHexString()))
|
||||||
|
.ForMember(dest => dest.ParentName, opt => opt.MapFrom(src => src.ParentGroup.Name))
|
||||||
|
.ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.Uuid.ToHexString()))
|
||||||
|
.ForMember(dest => dest.Fields, opt => opt.MapFrom(src => src.Strings))
|
||||||
|
.ForMember(dest => dest.ForegroundColor, opt => opt.MapFrom(src => src.ForegroundColor))
|
||||||
|
.ForMember(dest => dest.BackgroundColor, opt => opt.MapFrom(src => src.BackgroundColor))
|
||||||
|
.ForMember(dest => dest.ExpirationDate, opt => opt.MapFrom(src => new DateTimeOffset(src.ExpiryTime)))
|
||||||
|
.ForMember(dest => dest.HasExpirationDate, opt => opt.MapFrom(src => src.Expires))
|
||||||
|
.ForMember(dest => dest.Icon, opt => opt.MapFrom(src => IconMapper.MapPwIconToIcon(src.IconId)))
|
||||||
|
.ForMember(dest => dest.LastModificationDate, opt => opt.MapFrom(src => new DateTimeOffset(src.LastModificationTime)))
|
||||||
|
.ForMember(dest => dest.Attachments, opt => opt.MapFrom(src => src.Binaries.Select(b => new KeyValuePair<string, byte[]> (b.Key, b.Value.ReadData()) )));
|
||||||
|
|
||||||
|
CreateMap<PwGroup, GroupEntity>()
|
||||||
|
.ForMember(d => d.ParentId, opts => opts.MapFrom(s => s.ParentGroup.Uuid.ToHexString()))
|
||||||
|
.ForMember(d => d.ParentName, opts => opts.MapFrom(s => s.ParentGroup.Name))
|
||||||
|
.ForMember(d => d.Id, opts => opts.MapFrom(s => s.Uuid.ToHexString()))
|
||||||
|
.ForMember(d => d.Name, opts => opts.MapFrom(s => s.Name))
|
||||||
|
.ForMember(d => d.Icon, opts => opts.MapFrom(s => IconMapper.MapPwIconToIcon(s.IconId)))
|
||||||
|
.ForMember(d => d.LastModificationDate, opts => opts.MapFrom(s => s.LastModificationTime))
|
||||||
|
.ForMember(d => d.Entries, opts => opts.MapFrom(s => s.Entries))
|
||||||
|
.ForMember(d => d.SubGroups, opts => opts.MapFrom(s => s.Groups))
|
||||||
|
.MaxDepth(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
47
ModernKeePass.Infrastructure/UWP/UwpCryptographyClient.cs
Normal file
47
ModernKeePass.Infrastructure/UWP/UwpCryptographyClient.cs
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Windows.Security.Cryptography;
|
||||||
|
using Windows.Security.Cryptography.DataProtection;
|
||||||
|
using ModernKeePass.Application.Common.Interfaces;
|
||||||
|
|
||||||
|
namespace ModernKeePass.Infrastructure.UWP
|
||||||
|
{
|
||||||
|
public class UwpCryptographyClient: ICryptographyClient
|
||||||
|
{
|
||||||
|
public async Task<string> Protect(string value)
|
||||||
|
{
|
||||||
|
// Create a DataProtectionProvider object for the specified descriptor.
|
||||||
|
var provider = new DataProtectionProvider();
|
||||||
|
|
||||||
|
// Encode the plaintext input message to a buffer.
|
||||||
|
var buffMsg = CryptographicBuffer.ConvertStringToBinary(value, BinaryStringEncoding.Utf8);
|
||||||
|
|
||||||
|
// Encrypt the message.
|
||||||
|
var buffProtected = await provider.ProtectAsync(buffMsg);
|
||||||
|
|
||||||
|
// Encode buffer to Base64
|
||||||
|
var stringProtected = CryptographicBuffer.EncodeToBase64String(buffProtected);
|
||||||
|
|
||||||
|
// Return the encrypted string.
|
||||||
|
return stringProtected;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string> UnProtect(string value)
|
||||||
|
{
|
||||||
|
// Create a DataProtectionProvider object.
|
||||||
|
var provider = new DataProtectionProvider();
|
||||||
|
|
||||||
|
// Decode from Base64 string
|
||||||
|
var buffProtected = CryptographicBuffer.DecodeFromBase64String(value);
|
||||||
|
|
||||||
|
// Decrypt the protected message specified on input.
|
||||||
|
var buffUnprotected = await provider.UnprotectAsync(buffProtected);
|
||||||
|
|
||||||
|
// Convert the unprotected message from an IBuffer object to a string.
|
||||||
|
var strClearText = CryptographicBuffer.ConvertBinaryToString(BinaryStringEncoding.Utf8, buffUnprotected);
|
||||||
|
|
||||||
|
// Return the plaintext string.
|
||||||
|
return strClearText;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -3,7 +3,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"AutoMapper": "5.2.0",
|
"AutoMapper": "5.2.0",
|
||||||
"Microsoft.NETCore.Portable.Compatibility": "1.0.1",
|
"Microsoft.NETCore.Portable.Compatibility": "1.0.1",
|
||||||
"ModernKeePassLib": "2.44.3",
|
"ModernKeePassLib": "2.45.1",
|
||||||
"NETStandard.Library": "2.0.3"
|
"NETStandard.Library": "2.0.3"
|
||||||
},
|
},
|
||||||
"frameworks": {
|
"frameworks": {
|
||||||
|
@@ -32,7 +32,8 @@ namespace ModernKeePass
|
|||||||
/// Provides application-specific behavior to supplement the default Application class.
|
/// Provides application-specific behavior to supplement the default Application class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
sealed partial class App
|
sealed partial class App
|
||||||
{
|
{ public static IServiceProvider Services { get; private set; }
|
||||||
|
|
||||||
private readonly IResourceProxy _resource;
|
private readonly IResourceProxy _resource;
|
||||||
private readonly IMediator _mediator;
|
private readonly IMediator _mediator;
|
||||||
private readonly ISettingsProxy _settings;
|
private readonly ISettingsProxy _settings;
|
||||||
@@ -42,8 +43,6 @@ namespace ModernKeePass
|
|||||||
private readonly IFileProxy _file;
|
private readonly IFileProxy _file;
|
||||||
private readonly IMessenger _messenger;
|
private readonly IMessenger _messenger;
|
||||||
|
|
||||||
public static IServiceProvider Services { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes the singleton application object. This is the first line of authored code
|
/// Initializes the singleton application object. This is the first line of authored code
|
||||||
/// executed, and as such is the logical equivalent of main() or WinMain().
|
/// executed, and as such is the logical equivalent of main() or WinMain().
|
||||||
@@ -166,14 +165,6 @@ namespace ModernKeePass
|
|||||||
#if DEBUG
|
#if DEBUG
|
||||||
_notification.Show("App resumed", "Nothing to do, no previous database opened");
|
_notification.Show("App resumed", "Nothing to do, no previous database opened");
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_hockey.TrackException(ex);
|
|
||||||
_hockey.Flush();
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
_navigation.NavigateTo(Constants.Navigation.MainPage);
|
_navigation.NavigateTo(Constants.Navigation.MainPage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -214,7 +205,7 @@ namespace ModernKeePass
|
|||||||
}
|
}
|
||||||
catch (SaveException ex)
|
catch (SaveException ex)
|
||||||
{
|
{
|
||||||
_notification.Show(_resource.GetResourceValue("MessageDialogSaveErrorTitle"), ex.Message);
|
_notification.Show(ex.Source, ex.Message);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Package xmlns="http://schemas.microsoft.com/appx/2010/manifest" xmlns:m2="http://schemas.microsoft.com/appx/2013/manifest">
|
<Package xmlns="http://schemas.microsoft.com/appx/2010/manifest" xmlns:m2="http://schemas.microsoft.com/appx/2013/manifest">
|
||||||
<Identity Name="wismna.ModernKeePass" Publisher="CN=0719A91A-C322-4EE0-A257-E60733EECF06" Version="1.17.0.12" />
|
<Identity Name="wismna.ModernKeePass" Publisher="CN=0719A91A-C322-4EE0-A257-E60733EECF06" Version="1.18.0.12" />
|
||||||
<Properties>
|
<Properties>
|
||||||
<DisplayName>ModernKeePass</DisplayName>
|
<DisplayName>ModernKeePass</DisplayName>
|
||||||
<PublisherDisplayName>wismna</PublisherDisplayName>
|
<PublisherDisplayName>wismna</PublisherDisplayName>
|
||||||
|
@@ -191,7 +191,7 @@
|
|||||||
To="1" />
|
To="1" />
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="contentPresenter"
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="contentPresenter"
|
||||||
Storyboard.TargetProperty="Foreground">
|
Storyboard.TargetProperty="Foreground">
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource MainColor}" />
|
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ListViewItemSelectedForegroundThemeBrush}" />
|
||||||
</ObjectAnimationUsingKeyFrames>
|
</ObjectAnimationUsingKeyFrames>
|
||||||
</Storyboard>
|
</Storyboard>
|
||||||
</VisualState>
|
</VisualState>
|
||||||
@@ -358,13 +358,13 @@
|
|||||||
</Grid>
|
</Grid>
|
||||||
</Border>
|
</Border>
|
||||||
<Border x:Name="SelectedLeftIndicator"
|
<Border x:Name="SelectedLeftIndicator"
|
||||||
BorderBrush="{StaticResource MainColor}"
|
BorderBrush="{ThemeResource MainColorBrush}"
|
||||||
BorderThickness="5,0,0,0"
|
BorderThickness="5,0,0,0"
|
||||||
Opacity="0"/>
|
Opacity="0"/>
|
||||||
<Rectangle x:Name="SelectedBorder"
|
<Rectangle x:Name="SelectedBorder"
|
||||||
IsHitTestVisible="False"
|
IsHitTestVisible="False"
|
||||||
Opacity="0"
|
Opacity="0"
|
||||||
Stroke="{StaticResource MainColor}"
|
Stroke="{ThemeResource MainColorBrush}"
|
||||||
StrokeThickness="{ThemeResource ListViewItemSelectedBorderThemeThickness}"
|
StrokeThickness="{ThemeResource ListViewItemSelectedBorderThemeThickness}"
|
||||||
Margin="0" />
|
Margin="0" />
|
||||||
<Border x:Name="SelectedCheckMarkOuter"
|
<Border x:Name="SelectedCheckMarkOuter"
|
||||||
@@ -373,7 +373,7 @@
|
|||||||
VerticalAlignment="Top"
|
VerticalAlignment="Top"
|
||||||
Margin="4">
|
Margin="4">
|
||||||
<Grid x:Name="SelectedCheckMark" Opacity="0" Height="40" Width="40">
|
<Grid x:Name="SelectedCheckMark" Opacity="0" Height="40" Width="40">
|
||||||
<Path x:Name="SelectedEarmark" Data="M0,0 L40,0 L40,40 z" Fill="{StaticResource MainColor}" Stretch="Fill"/>
|
<Path x:Name="SelectedEarmark" Data="M0,0 L40,0 L40,40 z" Fill="{ThemeResource MainColorBrush}" Stretch="Fill"/>
|
||||||
<Path Data="F1 M133.1,17.9 L137.2,13.2 L144.6,19.6 L156.4,5.8 L161.2,9.9 L145.6,28.4 z" Fill="{ThemeResource ListViewItemCheckThemeBrush}" Height="13" Stretch="Fill" Width="15" HorizontalAlignment="Right" Margin="0,5.5,5.5,0" VerticalAlignment="Top" FlowDirection="LeftToRight"/>
|
<Path Data="F1 M133.1,17.9 L137.2,13.2 L144.6,19.6 L156.4,5.8 L161.2,9.9 L145.6,28.4 z" Fill="{ThemeResource ListViewItemCheckThemeBrush}" Height="13" Stretch="Fill" Width="15" HorizontalAlignment="Right" Margin="0,5.5,5.5,0" VerticalAlignment="Top" FlowDirection="LeftToRight"/>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Border>
|
</Border>
|
||||||
|
@@ -5,10 +5,10 @@
|
|||||||
<!-- Common theme values -->
|
<!-- Common theme values -->
|
||||||
<x:Double x:Key="MenuWidth">60</x:Double>
|
<x:Double x:Key="MenuWidth">60</x:Double>
|
||||||
<x:Double x:Key="MenuHeight">40</x:Double>
|
<x:Double x:Key="MenuHeight">40</x:Double>
|
||||||
<x:Double x:Key="ExpandedMenuSize">300</x:Double>
|
<x:Double x:Key="ExpandedMenuSize">250</x:Double>
|
||||||
<GridLength x:Key="MenuHeightGridLength">40</GridLength>
|
<GridLength x:Key="MenuHeightGridLength">40</GridLength>
|
||||||
<GridLength x:Key="MenuWidthGridLength">60</GridLength>
|
<GridLength x:Key="MenuWidthGridLength">60</GridLength>
|
||||||
<GridLength x:Key="ExpandedMenuGridLength">300</GridLength>
|
<GridLength x:Key="ExpandedMenuGridLength">250</GridLength>
|
||||||
|
|
||||||
<Color x:Key="MainColor">SlateBlue</Color>
|
<Color x:Key="MainColor">SlateBlue</Color>
|
||||||
<Color x:Key="MainColorLight">MediumPurple</Color>
|
<Color x:Key="MainColorLight">MediumPurple</Color>
|
||||||
@@ -16,17 +16,22 @@
|
|||||||
<Color x:Key="TextColorLight">WhiteSmoke</Color>
|
<Color x:Key="TextColorLight">WhiteSmoke</Color>
|
||||||
<Color x:Key="BorderColor">DarkGray</Color>
|
<Color x:Key="BorderColor">DarkGray</Color>
|
||||||
<Color x:Key="FlyoutColor">#FFF0F0F0</Color>
|
<Color x:Key="FlyoutColor">#FFF0F0F0</Color>
|
||||||
|
<Color x:Key="HubSectionColor">#FF777777</Color>
|
||||||
|
|
||||||
<SolidColorBrush x:Key="MainColorBrush" Color="{ThemeResource MainColor}" />
|
<SolidColorBrush x:Key="MainColorBrush" Color="{ThemeResource MainColor}" />
|
||||||
<SolidColorBrush x:Key="MainColorLightBrush" Color="{ThemeResource MainColorLight}" />
|
<SolidColorBrush x:Key="MainColorLightBrush" Color="{ThemeResource MainColorLight}" />
|
||||||
<SolidColorBrush x:Key="MainColorDarkBrush" Color="{ThemeResource MainColorDark}" />
|
<SolidColorBrush x:Key="MainColorDarkBrush" Color="{ThemeResource MainColorDark}" />
|
||||||
<SolidColorBrush x:Key="TextColorLightBrush" Color="{ThemeResource TextColorLight}" />
|
<SolidColorBrush x:Key="TextColorLightBrush" Color="{ThemeResource TextColorLight}" />
|
||||||
|
<SolidColorBrush x:Key="HubSectionBrush" Color="{ThemeResource HubSectionColor}" />
|
||||||
|
|
||||||
<Style TargetType="TextBlock" x:Key="TextBlockSettingsHeaderStyle" >
|
<Style TargetType="TextBlock" x:Key="TextBlockSettingsHeaderStyle" >
|
||||||
<Setter Property="FontFamily" Value="Segoe UI" />
|
<Setter Property="FontFamily" Value="Segoe UI" />
|
||||||
<Setter Property="FontSize" Value="16" />
|
<Setter Property="FontSize" Value="16" />
|
||||||
<Setter Property="FontWeight" Value="SemiLight" />
|
<Setter Property="FontWeight" Value="SemiLight" />
|
||||||
</Style>
|
</Style>
|
||||||
|
<Style TargetType="HyperlinkButton">
|
||||||
|
<Setter Property="FontWeight" Value="SemiLight" />
|
||||||
|
</Style>
|
||||||
|
|
||||||
<SolidColorBrush x:Key="TextBoxBorderThemeBrush" Color="{ThemeResource BorderColor}" />
|
<SolidColorBrush x:Key="TextBoxBorderThemeBrush" Color="{ThemeResource BorderColor}" />
|
||||||
<SolidColorBrush x:Key="TextSelectionHighlightColorThemeBrush" Color="{ThemeResource MainColor}" />
|
<SolidColorBrush x:Key="TextSelectionHighlightColorThemeBrush" Color="{ThemeResource MainColor}" />
|
||||||
@@ -42,7 +47,6 @@
|
|||||||
<SolidColorBrush x:Key="HyperlinkForegroundThemeBrush" Color="{ThemeResource MainColor}" />
|
<SolidColorBrush x:Key="HyperlinkForegroundThemeBrush" Color="{ThemeResource MainColor}" />
|
||||||
<SolidColorBrush x:Key="HyperlinkPointerOverForegroundThemeBrush" Color="{ThemeResource MainColorLight}" />
|
<SolidColorBrush x:Key="HyperlinkPointerOverForegroundThemeBrush" Color="{ThemeResource MainColorLight}" />
|
||||||
|
|
||||||
<!--<SolidColorBrush x:Key="SearchBoxPointerOverBorderThemeBrush" Color="{ThemeResource MainColorLight}" />-->
|
|
||||||
<SolidColorBrush x:Key="SearchBoxPointerOverTextThemeBrush" Color="{ThemeResource MainColorLight}" />
|
<SolidColorBrush x:Key="SearchBoxPointerOverTextThemeBrush" Color="{ThemeResource MainColorLight}" />
|
||||||
<SolidColorBrush x:Key="SearchBoxBorderThemeBrush" Color="{ThemeResource BorderColor}" />
|
<SolidColorBrush x:Key="SearchBoxBorderThemeBrush" Color="{ThemeResource BorderColor}" />
|
||||||
<SolidColorBrush x:Key="SearchBoxFocusedBorderThemeBrush" Color="{ThemeResource MainColor}" />
|
<SolidColorBrush x:Key="SearchBoxFocusedBorderThemeBrush" Color="{ThemeResource MainColor}" />
|
||||||
@@ -81,4 +85,8 @@
|
|||||||
<Thickness x:Key="FlyoutBorderThemeThickness">0</Thickness>
|
<Thickness x:Key="FlyoutBorderThemeThickness">0</Thickness>
|
||||||
<SolidColorBrush x:Key="FlyoutBorderThemeBrush" Color="{ThemeResource FlyoutColor}" />
|
<SolidColorBrush x:Key="FlyoutBorderThemeBrush" Color="{ThemeResource FlyoutColor}" />
|
||||||
<SolidColorBrush x:Key="FlyoutBackgroundThemeBrush" Color="{ThemeResource FlyoutColor}" />
|
<SolidColorBrush x:Key="FlyoutBackgroundThemeBrush" Color="{ThemeResource FlyoutColor}" />
|
||||||
|
|
||||||
|
<Thickness x:Key="ToolTipBorderThemeThickness">0</Thickness>
|
||||||
|
<SolidColorBrush x:Key="ToolTipBorderThemeBrush" Color="{ThemeResource FlyoutColor}" />
|
||||||
|
<SolidColorBrush x:Key="ToolTipBackgroundThemeBrush" Color="{ThemeResource FlyoutColor}" />
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
|
@@ -300,7 +300,6 @@
|
|||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Style="{StaticResource ActionButtonStyle}"
|
Style="{StaticResource ActionButtonStyle}"
|
||||||
Content="{TemplateBinding ButtonSymbol}"
|
Content="{TemplateBinding ButtonSymbol}"
|
||||||
IsEnabled="{TemplateBinding IsButtonEnabled}"
|
|
||||||
Command="{TemplateBinding ButtonCommand}"
|
Command="{TemplateBinding ButtonCommand}"
|
||||||
CommandParameter="{TemplateBinding ButtonCommandParameter}">
|
CommandParameter="{TemplateBinding ButtonCommandParameter}">
|
||||||
<ToolTipService.ToolTip>
|
<ToolTipService.ToolTip>
|
||||||
|
@@ -147,35 +147,17 @@
|
|||||||
<data name="EntityRestoredTitle" xml:space="preserve">
|
<data name="EntityRestoredTitle" xml:space="preserve">
|
||||||
<value>Restored</value>
|
<value>Restored</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="EntryDeleted" xml:space="preserve">
|
|
||||||
<value>Entry permanently removed</value>
|
|
||||||
</data>
|
|
||||||
<data name="EntryDeletingConfirmation" xml:space="preserve">
|
<data name="EntryDeletingConfirmation" xml:space="preserve">
|
||||||
<value>Are you sure you want to delete this entry?</value>
|
<value>Are you sure you want to delete {0} ?</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="EntryRecycled" xml:space="preserve">
|
<data name="EntryRecycled" xml:space="preserve">
|
||||||
<value>Entry moved to the Recycle bin</value>
|
<value>{0} moved to the Recycle bin</value>
|
||||||
</data>
|
|
||||||
<data name="EntryRecyclingConfirmation" xml:space="preserve">
|
|
||||||
<value>Are you sure you want to send this entry to the recycle bin?</value>
|
|
||||||
</data>
|
</data>
|
||||||
<data name="EntryRestored" xml:space="preserve">
|
<data name="EntryRestored" xml:space="preserve">
|
||||||
<value>Entry returned to its original group</value>
|
<value>Entry returned to its original group</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="GroupDeleted" xml:space="preserve">
|
|
||||||
<value>Group permanently removed</value>
|
|
||||||
</data>
|
|
||||||
<data name="GroupDeletingConfirmation" xml:space="preserve">
|
|
||||||
<value>Are you sure you want to delete the whole group and all its entries?</value>
|
|
||||||
</data>
|
|
||||||
<data name="GroupRecycled" xml:space="preserve">
|
<data name="GroupRecycled" xml:space="preserve">
|
||||||
<value>Group moved to the Recycle bin</value>
|
<value>{0} moved to the Recycle bin</value>
|
||||||
</data>
|
|
||||||
<data name="GroupRecyclingConfirmation" xml:space="preserve">
|
|
||||||
<value>Are you sure you want to send the whole group and all its entries to the recycle bin?</value>
|
|
||||||
</data>
|
|
||||||
<data name="GroupRestored" xml:space="preserve">
|
|
||||||
<value>Group returned to its original group</value>
|
|
||||||
</data>
|
</data>
|
||||||
<data name="MainMenuItemAbout" xml:space="preserve">
|
<data name="MainMenuItemAbout" xml:space="preserve">
|
||||||
<value>About</value>
|
<value>About</value>
|
||||||
@@ -216,8 +198,8 @@
|
|||||||
<data name="CompositeKeyErrorUserAccount" xml:space="preserve">
|
<data name="CompositeKeyErrorUserAccount" xml:space="preserve">
|
||||||
<value>- user account</value>
|
<value>- user account</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SettingsMenuItemSave" xml:space="preserve">
|
<data name="SettingsMenuItemCredentials" xml:space="preserve">
|
||||||
<value>Saving</value>
|
<value>Credentials</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="RecycleBinTitle" xml:space="preserve">
|
<data name="RecycleBinTitle" xml:space="preserve">
|
||||||
<value>Recycle Bin</value>
|
<value>Recycle Bin</value>
|
||||||
@@ -276,4 +258,19 @@
|
|||||||
<data name="CompositeKeyFileNameSuggestion" xml:space="preserve">
|
<data name="CompositeKeyFileNameSuggestion" xml:space="preserve">
|
||||||
<value>Key</value>
|
<value>Key</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="DatabaseTooBigDescription" xml:space="preserve">
|
||||||
|
<value>Database size is too big for auto-save on suspend. Please save your changes before closing the app !</value>
|
||||||
|
</data>
|
||||||
|
<data name="DatabaseTooBigTitle" xml:space="preserve">
|
||||||
|
<value>Attention</value>
|
||||||
|
</data>
|
||||||
|
<data name="SettingsMenuItemHistory" xml:space="preserve">
|
||||||
|
<value>History</value>
|
||||||
|
</data>
|
||||||
|
<data name="SettingsMenuItemRecycleBin" xml:space="preserve">
|
||||||
|
<value>Recycle Bin</value>
|
||||||
|
</data>
|
||||||
|
<data name="GroupDeletingConfirmation" xml:space="preserve">
|
||||||
|
<value>Are you sure you want to delete the {0} and all its entries?</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@@ -121,7 +121,7 @@
|
|||||||
<value>Dominik Reichl for the KeePass application and file format</value>
|
<value>Dominik Reichl for the KeePass application and file format</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="AboutCredits2.Text" xml:space="preserve">
|
<data name="AboutCredits2.Text" xml:space="preserve">
|
||||||
<value>David Lechner for his PCL adapatation of the KeePass Library and his correlated tests</value>
|
<value>David Lechner for his PCL adapatation of the KeePass Library and his related tests</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="AboutCreditsLabel.Text" xml:space="preserve">
|
<data name="AboutCreditsLabel.Text" xml:space="preserve">
|
||||||
<value>Credits</value>
|
<value>Credits</value>
|
||||||
@@ -297,9 +297,6 @@
|
|||||||
<data name="SettingsDatabaseKdf.Text" xml:space="preserve">
|
<data name="SettingsDatabaseKdf.Text" xml:space="preserve">
|
||||||
<value>Key Derivation Algorithm</value>
|
<value>Key Derivation Algorithm</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SettingsDatabaseRecycleBin.Header" xml:space="preserve">
|
|
||||||
<value>Recycle bin</value>
|
|
||||||
</data>
|
|
||||||
<data name="SettingsDatabaseRecycleBin.OffContent" xml:space="preserve">
|
<data name="SettingsDatabaseRecycleBin.OffContent" xml:space="preserve">
|
||||||
<value>Disabled</value>
|
<value>Disabled</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -516,4 +513,55 @@
|
|||||||
<data name="NewGroupTextBox.ButtonTooltip" xml:space="preserve">
|
<data name="NewGroupTextBox.ButtonTooltip" xml:space="preserve">
|
||||||
<value>New group name</value>
|
<value>New group name</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="EntryHubAdditional.Header" xml:space="preserve">
|
||||||
|
<value>Additional</value>
|
||||||
|
</data>
|
||||||
|
<data name="EntryHubAttachments.Header" xml:space="preserve">
|
||||||
|
<value>Attachments</value>
|
||||||
|
</data>
|
||||||
|
<data name="EntryHubMain.Header" xml:space="preserve">
|
||||||
|
<value>Main</value>
|
||||||
|
</data>
|
||||||
|
<data name="EntryHubPresentation.Header" xml:space="preserve">
|
||||||
|
<value>Presentation</value>
|
||||||
|
</data>
|
||||||
|
<data name="EntryIcon.Text" xml:space="preserve">
|
||||||
|
<value>Icon</value>
|
||||||
|
</data>
|
||||||
|
<data name="EntryAddAttachment.Text" xml:space="preserve">
|
||||||
|
<value>Add attachment</value>
|
||||||
|
</data>
|
||||||
|
<data name="EntryAddAdditionalField.Text" xml:space="preserve">
|
||||||
|
<value>Add field</value>
|
||||||
|
</data>
|
||||||
|
<data name="EntryDeleteAdditionalField.Content" xml:space="preserve">
|
||||||
|
<value>Delete</value>
|
||||||
|
</data>
|
||||||
|
<data name="ReorderGroupsLabel.Text" xml:space="preserve">
|
||||||
|
<value>Drag and drop groups to reorder them</value>
|
||||||
|
</data>
|
||||||
|
<data name="EntryAdditionalFieldNameReserved.Text" xml:space="preserve">
|
||||||
|
<value>Invalid field name</value>
|
||||||
|
</data>
|
||||||
|
<data name="EntryEnableFieldProtection.Header" xml:space="preserve">
|
||||||
|
<value>Enable protection ?</value>
|
||||||
|
</data>
|
||||||
|
<data name="EntryEnableFieldProtection.OffContent" xml:space="preserve">
|
||||||
|
<value>No</value>
|
||||||
|
</data>
|
||||||
|
<data name="EntryEnableFieldProtection.OnContent" xml:space="preserve">
|
||||||
|
<value>Yes</value>
|
||||||
|
</data>
|
||||||
|
<data name="TopMenuRestoreButton.Content" xml:space="preserve">
|
||||||
|
<value>Restore</value>
|
||||||
|
</data>
|
||||||
|
<data name="SettingsHistoryMaxCount.Text" xml:space="preserve">
|
||||||
|
<value>Max history items</value>
|
||||||
|
</data>
|
||||||
|
<data name="SettingsHistoryMaxSize.Text" xml:space="preserve">
|
||||||
|
<value>Max history size (MB)</value>
|
||||||
|
</data>
|
||||||
|
<data name="SettingsCopyExpiration.Text" xml:space="preserve">
|
||||||
|
<value>Delete copied value from clipboard after how many seconds ?</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@@ -147,35 +147,17 @@
|
|||||||
<data name="EntityRestoredTitle" xml:space="preserve">
|
<data name="EntityRestoredTitle" xml:space="preserve">
|
||||||
<value>Restauré</value>
|
<value>Restauré</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="EntryDeleted" xml:space="preserve">
|
|
||||||
<value>Entrée supprimée définitivement</value>
|
|
||||||
</data>
|
|
||||||
<data name="EntryDeletingConfirmation" xml:space="preserve">
|
<data name="EntryDeletingConfirmation" xml:space="preserve">
|
||||||
<value>Êtes-vous sûr de vouloir supprimer cette entrée ?</value>
|
<value>Êtes-vous sûr de vouloir supprimer {0} ?</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="EntryRecycled" xml:space="preserve">
|
<data name="EntryRecycled" xml:space="preserve">
|
||||||
<value>Entrée placée dans la Corbeille</value>
|
<value>{0} placé dans la Corbeille</value>
|
||||||
</data>
|
|
||||||
<data name="EntryRecyclingConfirmation" xml:space="preserve">
|
|
||||||
<value>Êtes-vous sûr de vouloir placer cette entrée dans la Corbeille ?</value>
|
|
||||||
</data>
|
|
||||||
<data name="EntryRestored" xml:space="preserve">
|
|
||||||
<value>Entrée replacée dans son groupe d'origine</value>
|
|
||||||
</data>
|
|
||||||
<data name="GroupDeleted" xml:space="preserve">
|
|
||||||
<value>Groupe supprimé définitivement</value>
|
|
||||||
</data>
|
</data>
|
||||||
<data name="GroupDeletingConfirmation" xml:space="preserve">
|
<data name="GroupDeletingConfirmation" xml:space="preserve">
|
||||||
<value>Êtes-vous sûr de vouloir supprimer ce groupe et toutes ses entrées ?</value>
|
<value>Êtes-vous sûr de vouloir supprimer {0} et toutes ses entrées ?</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="GroupRecycled" xml:space="preserve">
|
<data name="GroupRecycled" xml:space="preserve">
|
||||||
<value>Groupe placé dans la Corbeille</value>
|
<value>{0} placé dans la Corbeille</value>
|
||||||
</data>
|
|
||||||
<data name="GroupRecyclingConfirmation" xml:space="preserve">
|
|
||||||
<value>Êtes-vous sûr de vouloir envoyer ce groupe et toutes ses entrées vers la Corbeille ?</value>
|
|
||||||
</data>
|
|
||||||
<data name="GroupRestored" xml:space="preserve">
|
|
||||||
<value>Groupe replacé à sa place originelle</value>
|
|
||||||
</data>
|
</data>
|
||||||
<data name="MainMenuItemAbout" xml:space="preserve">
|
<data name="MainMenuItemAbout" xml:space="preserve">
|
||||||
<value>A propos</value>
|
<value>A propos</value>
|
||||||
@@ -204,9 +186,6 @@
|
|||||||
<data name="SettingsMenuGroupDatabase" xml:space="preserve">
|
<data name="SettingsMenuGroupDatabase" xml:space="preserve">
|
||||||
<value>Base de données</value>
|
<value>Base de données</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SettingsMenuItemGeneral" xml:space="preserve">
|
|
||||||
<value>Général</value>
|
|
||||||
</data>
|
|
||||||
<data name="SettingsMenuItemNew" xml:space="preserve">
|
<data name="SettingsMenuItemNew" xml:space="preserve">
|
||||||
<value>Nouveau</value>
|
<value>Nouveau</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -216,9 +195,6 @@
|
|||||||
<data name="CompositeKeyErrorUserAccount" xml:space="preserve">
|
<data name="CompositeKeyErrorUserAccount" xml:space="preserve">
|
||||||
<value>- compte utilisateur</value>
|
<value>- compte utilisateur</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SettingsMenuItemSave" xml:space="preserve">
|
|
||||||
<value>Sauvegardes</value>
|
|
||||||
</data>
|
|
||||||
<data name="RecycleBinTitle" xml:space="preserve">
|
<data name="RecycleBinTitle" xml:space="preserve">
|
||||||
<value>Corbeille</value>
|
<value>Corbeille</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -276,4 +252,22 @@
|
|||||||
<data name="CompositeKeyFileNameSuggestion" xml:space="preserve">
|
<data name="CompositeKeyFileNameSuggestion" xml:space="preserve">
|
||||||
<value>Clé</value>
|
<value>Clé</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="DatabaseTooBigDescription" xml:space="preserve">
|
||||||
|
<value>La base de données est trop grosse pour sauvegarder automatiquement lors de la suspension. Pensez à bien sauvegarder vos changements avant de fermer l'app !</value>
|
||||||
|
</data>
|
||||||
|
<data name="DatabaseTooBigTitle" xml:space="preserve">
|
||||||
|
<value>Attention</value>
|
||||||
|
</data>
|
||||||
|
<data name="SettingsMenuItemCredentials" xml:space="preserve">
|
||||||
|
<value>Identifiants</value>
|
||||||
|
</data>
|
||||||
|
<data name="SettingsMenuItemHistory" xml:space="preserve">
|
||||||
|
<value>Historique</value>
|
||||||
|
</data>
|
||||||
|
<data name="SettingsMenuItemRecycleBin" xml:space="preserve">
|
||||||
|
<value>Corbeille</value>
|
||||||
|
</data>
|
||||||
|
<data name="SettingsMenuItemGeneral" xml:space="preserve">
|
||||||
|
<value>Général</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@@ -297,9 +297,6 @@
|
|||||||
<data name="SettingsDatabaseKdf.Text" xml:space="preserve">
|
<data name="SettingsDatabaseKdf.Text" xml:space="preserve">
|
||||||
<value>Algorithme de dérivation de clé</value>
|
<value>Algorithme de dérivation de clé</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SettingsDatabaseRecycleBin.Header" xml:space="preserve">
|
|
||||||
<value>Corbeille</value>
|
|
||||||
</data>
|
|
||||||
<data name="SettingsDatabaseRecycleBin.OffContent" xml:space="preserve">
|
<data name="SettingsDatabaseRecycleBin.OffContent" xml:space="preserve">
|
||||||
<value>Désactivé</value>
|
<value>Désactivé</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -516,4 +513,55 @@
|
|||||||
<data name="NewGroupTextBox.ButtonTooltip" xml:space="preserve">
|
<data name="NewGroupTextBox.ButtonTooltip" xml:space="preserve">
|
||||||
<value>Nom du groupe</value>
|
<value>Nom du groupe</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="EntryHubAdditional.Header" xml:space="preserve">
|
||||||
|
<value>Additionnel</value>
|
||||||
|
</data>
|
||||||
|
<data name="EntryHubAttachments.Header" xml:space="preserve">
|
||||||
|
<value>Pièce jointes</value>
|
||||||
|
</data>
|
||||||
|
<data name="EntryHubMain.Header" xml:space="preserve">
|
||||||
|
<value>Principal</value>
|
||||||
|
</data>
|
||||||
|
<data name="EntryHubPresentation.Header" xml:space="preserve">
|
||||||
|
<value>Affichage</value>
|
||||||
|
</data>
|
||||||
|
<data name="EntryIcon.Text" xml:space="preserve">
|
||||||
|
<value>Icone</value>
|
||||||
|
</data>
|
||||||
|
<data name="EntryAddAttachment.Text" xml:space="preserve">
|
||||||
|
<value>Ajouter une pièce jointe</value>
|
||||||
|
</data>
|
||||||
|
<data name="EntryDeleteAdditionalField.Content" xml:space="preserve">
|
||||||
|
<value>Supprimer</value>
|
||||||
|
</data>
|
||||||
|
<data name="ReorderGroupsLabel.Text" xml:space="preserve">
|
||||||
|
<value>Drag and drop groups to reorder them</value>
|
||||||
|
</data>
|
||||||
|
<data name="EntryAdditionalFieldNameReserved.Text" xml:space="preserve">
|
||||||
|
<value>Nom de champ invalide</value>
|
||||||
|
</data>
|
||||||
|
<data name="EntryEnableFieldProtection.Header" xml:space="preserve">
|
||||||
|
<value>Activer la protection ?</value>
|
||||||
|
</data>
|
||||||
|
<data name="EntryEnableFieldProtection.OffContent" xml:space="preserve">
|
||||||
|
<value>Non</value>
|
||||||
|
</data>
|
||||||
|
<data name="EntryEnableFieldProtection.OnContent" xml:space="preserve">
|
||||||
|
<value>Oui</value>
|
||||||
|
</data>
|
||||||
|
<data name="TopMenuRestoreButton.Content" xml:space="preserve">
|
||||||
|
<value>Restaurer</value>
|
||||||
|
</data>
|
||||||
|
<data name="SettingsHistoryMaxCount.Text" xml:space="preserve">
|
||||||
|
<value>Nombre d'éléments d'historique max</value>
|
||||||
|
</data>
|
||||||
|
<data name="SettingsHistoryMaxSize.Text" xml:space="preserve">
|
||||||
|
<value>Taille de l'historique (MO)</value>
|
||||||
|
</data>
|
||||||
|
<data name="SettingsCopyExpiration.Text" xml:space="preserve">
|
||||||
|
<value>Supprimer la valeur copiée dans le presse papier après combien de secondes ?</value>
|
||||||
|
</data>
|
||||||
|
<data name="EntryAddAdditionalField.Text" xml:space="preserve">
|
||||||
|
<value>Ajouter un champ</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@@ -1,5 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@@ -14,10 +13,13 @@ using ModernKeePass.Application.Common.Interfaces;
|
|||||||
using ModernKeePass.Application.Database.Commands.SaveDatabase;
|
using ModernKeePass.Application.Database.Commands.SaveDatabase;
|
||||||
using ModernKeePass.Application.Database.Models;
|
using ModernKeePass.Application.Database.Models;
|
||||||
using ModernKeePass.Application.Database.Queries.GetDatabase;
|
using ModernKeePass.Application.Database.Queries.GetDatabase;
|
||||||
|
using ModernKeePass.Application.Entry.Commands.AddAttachment;
|
||||||
using ModernKeePass.Application.Entry.Commands.AddHistory;
|
using ModernKeePass.Application.Entry.Commands.AddHistory;
|
||||||
|
using ModernKeePass.Application.Entry.Commands.DeleteAttachment;
|
||||||
|
using ModernKeePass.Application.Entry.Commands.DeleteField;
|
||||||
using ModernKeePass.Application.Entry.Commands.DeleteHistory;
|
using ModernKeePass.Application.Entry.Commands.DeleteHistory;
|
||||||
using ModernKeePass.Application.Entry.Commands.RestoreHistory;
|
using ModernKeePass.Application.Entry.Commands.RestoreHistory;
|
||||||
using ModernKeePass.Application.Entry.Commands.SetFieldValue;
|
using ModernKeePass.Application.Entry.Commands.UpsertField;
|
||||||
using ModernKeePass.Application.Entry.Models;
|
using ModernKeePass.Application.Entry.Models;
|
||||||
using ModernKeePass.Application.Entry.Queries.GetEntry;
|
using ModernKeePass.Application.Entry.Queries.GetEntry;
|
||||||
using ModernKeePass.Application.Group.Commands.AddEntry;
|
using ModernKeePass.Application.Group.Commands.AddEntry;
|
||||||
@@ -29,25 +31,67 @@ using ModernKeePass.Application.Security.Queries.EstimatePasswordComplexity;
|
|||||||
using ModernKeePass.Domain.Enums;
|
using ModernKeePass.Domain.Enums;
|
||||||
using ModernKeePass.Application.Group.Models;
|
using ModernKeePass.Application.Group.Models;
|
||||||
using ModernKeePass.Common;
|
using ModernKeePass.Common;
|
||||||
|
using ModernKeePass.Domain.Dtos;
|
||||||
using ModernKeePass.Domain.Exceptions;
|
using ModernKeePass.Domain.Exceptions;
|
||||||
using ModernKeePass.Extensions;
|
using ModernKeePass.Extensions;
|
||||||
using ModernKeePass.Models;
|
using ModernKeePass.Models;
|
||||||
|
using ModernKeePass.ViewModels.ListItems;
|
||||||
|
|
||||||
namespace ModernKeePass.ViewModels
|
namespace ModernKeePass.ViewModels
|
||||||
{
|
{
|
||||||
public class EntryDetailVm : ViewModelBase
|
public class EntryDetailVm : ViewModelBase
|
||||||
{
|
{
|
||||||
public bool IsRevealPasswordEnabled => !string.IsNullOrEmpty(Password);
|
|
||||||
public bool HasExpired => HasExpirationDate && ExpiryDate < DateTime.Now;
|
public bool HasExpired => HasExpirationDate && ExpiryDate < DateTime.Now;
|
||||||
public double PasswordComplexityIndicator => _mediator.Send(new EstimatePasswordComplexityQuery {Password = Password}).GetAwaiter().GetResult();
|
public double PasswordComplexityIndicator => _mediator.Send(new EstimatePasswordComplexityQuery {Password = Password}).GetAwaiter().GetResult();
|
||||||
public bool UpperCasePatternSelected { get; set; } = true;
|
public double PasswordLength
|
||||||
public bool LowerCasePatternSelected { get; set; } = true;
|
{
|
||||||
public bool DigitsPatternSelected { get; set; } = true;
|
get { return _settings.GetSetting(Constants.Settings.PasswordGenerationOptions.PasswordLength, 25); }
|
||||||
public bool MinusPatternSelected { get; set; }
|
set
|
||||||
public bool UnderscorePatternSelected { get; set; }
|
{
|
||||||
public bool SpacePatternSelected { get; set; }
|
_settings.PutSetting(Constants.Settings.PasswordGenerationOptions.PasswordLength, value);
|
||||||
public bool SpecialPatternSelected { get; set; }
|
RaisePropertyChanged(nameof(PasswordLength));
|
||||||
public bool BracketsPatternSelected { get; set; }
|
}
|
||||||
|
}
|
||||||
|
public bool UpperCasePatternSelected
|
||||||
|
{
|
||||||
|
get { return _settings.GetSetting(Constants.Settings.PasswordGenerationOptions.UpperCasePattern, true); }
|
||||||
|
set { _settings.PutSetting(Constants.Settings.PasswordGenerationOptions.UpperCasePattern, value); }
|
||||||
|
}
|
||||||
|
public bool LowerCasePatternSelected
|
||||||
|
{
|
||||||
|
get { return _settings.GetSetting(Constants.Settings.PasswordGenerationOptions.LowerCasePattern, true); }
|
||||||
|
set { _settings.PutSetting(Constants.Settings.PasswordGenerationOptions.LowerCasePattern, value); }
|
||||||
|
}
|
||||||
|
public bool DigitsPatternSelected
|
||||||
|
{
|
||||||
|
get { return _settings.GetSetting(Constants.Settings.PasswordGenerationOptions.DigitsPattern, true); }
|
||||||
|
set { _settings.PutSetting(Constants.Settings.PasswordGenerationOptions.DigitsPattern, value); }
|
||||||
|
}
|
||||||
|
public bool MinusPatternSelected
|
||||||
|
{
|
||||||
|
get { return _settings.GetSetting(Constants.Settings.PasswordGenerationOptions.MinusPattern, false); }
|
||||||
|
set { _settings.PutSetting(Constants.Settings.PasswordGenerationOptions.MinusPattern, value); }
|
||||||
|
}
|
||||||
|
public bool UnderscorePatternSelected
|
||||||
|
{
|
||||||
|
get { return _settings.GetSetting(Constants.Settings.PasswordGenerationOptions.UnderscorePattern, false); }
|
||||||
|
set { _settings.PutSetting(Constants.Settings.PasswordGenerationOptions.UnderscorePattern, value); }
|
||||||
|
}
|
||||||
|
public bool SpacePatternSelected
|
||||||
|
{
|
||||||
|
get { return _settings.GetSetting(Constants.Settings.PasswordGenerationOptions.SpacePattern, false); }
|
||||||
|
set { _settings.PutSetting(Constants.Settings.PasswordGenerationOptions.SpacePattern, value); }
|
||||||
|
}
|
||||||
|
public bool SpecialPatternSelected
|
||||||
|
{
|
||||||
|
get { return _settings.GetSetting(Constants.Settings.PasswordGenerationOptions.SpecialPattern, true); }
|
||||||
|
set { _settings.PutSetting(Constants.Settings.PasswordGenerationOptions.SpecialPattern, value); }
|
||||||
|
}
|
||||||
|
public bool BracketsPatternSelected
|
||||||
|
{
|
||||||
|
get { return _settings.GetSetting(Constants.Settings.PasswordGenerationOptions.BracketsPattern, false); }
|
||||||
|
set { _settings.PutSetting(Constants.Settings.PasswordGenerationOptions.BracketsPattern, value); }
|
||||||
|
}
|
||||||
public string CustomChars { get; set; } = string.Empty;
|
public string CustomChars { get; set; } = string.Empty;
|
||||||
|
|
||||||
public string Id => SelectedItem.Id;
|
public string Id => SelectedItem.Id;
|
||||||
@@ -63,8 +107,9 @@ namespace ModernKeePass.ViewModels
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<GroupVm> BreadCrumb => new List<GroupVm> { _parent };
|
|
||||||
public ObservableCollection<EntryVm> History { get; private set; }
|
public ObservableCollection<EntryVm> History { get; private set; }
|
||||||
|
public ObservableCollection<EntryFieldVm> AdditionalFields { get; private set; }
|
||||||
|
public ObservableCollection<Attachment> Attachments { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines if the Entry is current or from history
|
/// Determines if the Entry is current or from history
|
||||||
@@ -76,10 +121,26 @@ namespace ModernKeePass.ViewModels
|
|||||||
get { return _selectedItem; }
|
get { return _selectedItem; }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
Set(() => SelectedItem, ref _selectedItem, value);
|
Set(() => SelectedItem, ref _selectedItem, value, true);
|
||||||
if (value != null) RaisePropertyChanged();
|
if (value != null)
|
||||||
|
{
|
||||||
|
AdditionalFields =
|
||||||
|
new ObservableCollection<EntryFieldVm>(
|
||||||
|
SelectedItem.AdditionalFields.Select(f => new EntryFieldVm(f.Name, f.Value, f.IsProtected)));
|
||||||
|
Attachments = new ObservableCollection<Attachment>(SelectedItem.Attachments.Select(f => new Attachment
|
||||||
|
{
|
||||||
|
Name = f.Key,
|
||||||
|
Content = f.Value
|
||||||
|
}));
|
||||||
|
Attachments.CollectionChanged += (sender, args) =>
|
||||||
|
{
|
||||||
|
UpdateDirtyStatus(true);
|
||||||
|
};
|
||||||
|
RaisePropertyChanged(string.Empty);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int SelectedIndex
|
public int SelectedIndex
|
||||||
{
|
{
|
||||||
get { return _selectedIndex; }
|
get { return _selectedIndex; }
|
||||||
@@ -87,43 +148,49 @@ namespace ModernKeePass.ViewModels
|
|||||||
{
|
{
|
||||||
Set(() => SelectedIndex, ref _selectedIndex, value);
|
Set(() => SelectedIndex, ref _selectedIndex, value);
|
||||||
RaisePropertyChanged(nameof(IsCurrentEntry));
|
RaisePropertyChanged(nameof(IsCurrentEntry));
|
||||||
|
AddAttachmentCommand.RaiseCanExecuteChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public double PasswordLength
|
public int AdditionalFieldSelectedIndex
|
||||||
{
|
{
|
||||||
get { return _passwordLength; }
|
get { return _additionalFieldSelectedIndex; }
|
||||||
set { Set(() => PasswordLength, ref _passwordLength, value); }
|
set
|
||||||
|
{
|
||||||
|
Set(() => AdditionalFieldSelectedIndex, ref _additionalFieldSelectedIndex, value);
|
||||||
|
DeleteAdditionalField.RaiseCanExecuteChanged();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public string Title
|
public string Title
|
||||||
{
|
{
|
||||||
get { return SelectedItem.Title; }
|
get { return SelectedItem.Title.Value; }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
SelectedItem.Title = value;
|
SelectedItem.Title.Value = value;
|
||||||
SetFieldValue(nameof(Title), value).Wait();
|
SetFieldValue(nameof(Title), value, false).Wait();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string UserName
|
public string UserName
|
||||||
{
|
{
|
||||||
get { return SelectedItem.Username; }
|
get { return SelectedItem.Username.Value; }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
SelectedItem.Username = value;
|
SelectedItem.Username.Value = value;
|
||||||
SetFieldValue(nameof(UserName), value).Wait();
|
SetFieldValue(nameof(UserName), value, false).Wait();
|
||||||
RaisePropertyChanged(nameof(UserName));
|
RaisePropertyChanged(nameof(UserName));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Password
|
public string Password
|
||||||
{
|
{
|
||||||
get { return SelectedItem.Password; }
|
get { return SelectedItem.Password.Value; }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
SelectedItem.Password = value;
|
SelectedItem.Password.Value = value;
|
||||||
SetFieldValue(nameof(Password), value).Wait();
|
SetFieldValue(nameof(Password), value, true).Wait();
|
||||||
RaisePropertyChanged(nameof(Password));
|
RaisePropertyChanged(nameof(Password));
|
||||||
RaisePropertyChanged(nameof(PasswordComplexityIndicator));
|
RaisePropertyChanged(nameof(PasswordComplexityIndicator));
|
||||||
}
|
}
|
||||||
@@ -131,22 +198,22 @@ namespace ModernKeePass.ViewModels
|
|||||||
|
|
||||||
public string Url
|
public string Url
|
||||||
{
|
{
|
||||||
get { return SelectedItem.Url; }
|
get { return SelectedItem.Url.Value; }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
SelectedItem.Url = value;
|
SelectedItem.Url.Value = value;
|
||||||
SetFieldValue(nameof(Url), value).Wait();
|
SetFieldValue(nameof(Url), value, false).Wait();
|
||||||
RaisePropertyChanged(nameof(Url));
|
RaisePropertyChanged(nameof(Url));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Notes
|
public string Notes
|
||||||
{
|
{
|
||||||
get { return SelectedItem.Notes; }
|
get { return SelectedItem.Notes.Value; }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
SelectedItem.Notes = value;
|
SelectedItem.Notes.Value = value;
|
||||||
SetFieldValue(nameof(Notes), value).Wait();
|
SetFieldValue(nameof(Notes), value, false).Wait();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,7 +223,7 @@ namespace ModernKeePass.ViewModels
|
|||||||
set
|
set
|
||||||
{
|
{
|
||||||
SelectedItem.Icon = (Icon)Enum.Parse(typeof(Icon), value.ToString());
|
SelectedItem.Icon = (Icon)Enum.Parse(typeof(Icon), value.ToString());
|
||||||
SetFieldValue(nameof(Icon), SelectedItem.Icon).Wait();
|
SetFieldValue(nameof(Icon), SelectedItem.Icon, false).Wait();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,7 +235,7 @@ namespace ModernKeePass.ViewModels
|
|||||||
if (!HasExpirationDate) return;
|
if (!HasExpirationDate) return;
|
||||||
|
|
||||||
SelectedItem.ExpirationDate = value.Date;
|
SelectedItem.ExpirationDate = value.Date;
|
||||||
SetFieldValue("ExpirationDate", SelectedItem.ExpirationDate).Wait();
|
SetFieldValue("ExpirationDate", SelectedItem.ExpirationDate, false).Wait();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,7 +247,7 @@ namespace ModernKeePass.ViewModels
|
|||||||
if (!HasExpirationDate) return;
|
if (!HasExpirationDate) return;
|
||||||
|
|
||||||
SelectedItem.ExpirationDate = SelectedItem.ExpirationDate.Date.Add(value);
|
SelectedItem.ExpirationDate = SelectedItem.ExpirationDate.Date.Add(value);
|
||||||
SetFieldValue("ExpirationDate", SelectedItem.ExpirationDate).Wait();
|
SetFieldValue("ExpirationDate", SelectedItem.ExpirationDate, false).Wait();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,7 +257,7 @@ namespace ModernKeePass.ViewModels
|
|||||||
set
|
set
|
||||||
{
|
{
|
||||||
SelectedItem.HasExpirationDate = value;
|
SelectedItem.HasExpirationDate = value;
|
||||||
SetFieldValue(nameof(HasExpirationDate), value).Wait();
|
SetFieldValue(nameof(HasExpirationDate), value, false).Wait();
|
||||||
RaisePropertyChanged(nameof(HasExpirationDate));
|
RaisePropertyChanged(nameof(HasExpirationDate));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -201,7 +268,7 @@ namespace ModernKeePass.ViewModels
|
|||||||
set
|
set
|
||||||
{
|
{
|
||||||
SelectedItem.BackgroundColor = value.ToColor();
|
SelectedItem.BackgroundColor = value.ToColor();
|
||||||
SetFieldValue(nameof(BackgroundColor), SelectedItem.BackgroundColor).Wait();
|
SetFieldValue(nameof(BackgroundColor), SelectedItem.BackgroundColor, false).Wait();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -211,11 +278,10 @@ namespace ModernKeePass.ViewModels
|
|||||||
set
|
set
|
||||||
{
|
{
|
||||||
SelectedItem.ForegroundColor = value.ToColor();
|
SelectedItem.ForegroundColor = value.ToColor();
|
||||||
SetFieldValue(nameof(ForegroundColor), SelectedItem.ForegroundColor).Wait();
|
SetFieldValue(nameof(ForegroundColor), SelectedItem.ForegroundColor, false).Wait();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public bool IsEditMode
|
public bool IsEditMode
|
||||||
{
|
{
|
||||||
get { return IsCurrentEntry && _isEditMode; }
|
get { return IsCurrentEntry && _isEditMode; }
|
||||||
@@ -235,6 +301,11 @@ namespace ModernKeePass.ViewModels
|
|||||||
public RelayCommand DeleteCommand { get; }
|
public RelayCommand DeleteCommand { get; }
|
||||||
public RelayCommand GoBackCommand { get; }
|
public RelayCommand GoBackCommand { get; }
|
||||||
public RelayCommand GoToParentCommand { get; set; }
|
public RelayCommand GoToParentCommand { get; set; }
|
||||||
|
public RelayCommand AddAdditionalField { get; set; }
|
||||||
|
public RelayCommand<EntryFieldVm> DeleteAdditionalField { get; set; }
|
||||||
|
public RelayCommand<Attachment> OpenAttachmentCommand { get; set; }
|
||||||
|
public RelayCommand AddAttachmentCommand { get; set; }
|
||||||
|
public RelayCommand<Attachment> DeleteAttachmentCommand { get; set; }
|
||||||
|
|
||||||
private DatabaseVm Database => _mediator.Send(new GetDatabaseQuery()).GetAwaiter().GetResult();
|
private DatabaseVm Database => _mediator.Send(new GetDatabaseQuery()).GetAwaiter().GetResult();
|
||||||
|
|
||||||
@@ -243,21 +314,25 @@ namespace ModernKeePass.ViewModels
|
|||||||
private readonly IResourceProxy _resource;
|
private readonly IResourceProxy _resource;
|
||||||
private readonly IDialogService _dialog;
|
private readonly IDialogService _dialog;
|
||||||
private readonly INotificationService _notification;
|
private readonly INotificationService _notification;
|
||||||
|
private readonly IFileProxy _file;
|
||||||
|
private readonly ISettingsProxy _settings;
|
||||||
private GroupVm _parent;
|
private GroupVm _parent;
|
||||||
private EntryVm _selectedItem;
|
private EntryVm _selectedItem;
|
||||||
private int _selectedIndex;
|
private int _selectedIndex;
|
||||||
|
private int _additionalFieldSelectedIndex = -1;
|
||||||
private bool _isEditMode;
|
private bool _isEditMode;
|
||||||
private bool _isRevealPassword;
|
private bool _isRevealPassword;
|
||||||
private double _passwordLength = 25;
|
|
||||||
private bool _isDirty;
|
private bool _isDirty;
|
||||||
|
|
||||||
public EntryDetailVm(IMediator mediator, INavigationService navigation, IResourceProxy resource, IDialogService dialog, INotificationService notification)
|
public EntryDetailVm(IMediator mediator, INavigationService navigation, IResourceProxy resource, IDialogService dialog, INotificationService notification, IFileProxy file, ISettingsProxy settings)
|
||||||
{
|
{
|
||||||
_mediator = mediator;
|
_mediator = mediator;
|
||||||
_navigation = navigation;
|
_navigation = navigation;
|
||||||
_resource = resource;
|
_resource = resource;
|
||||||
_dialog = dialog;
|
_dialog = dialog;
|
||||||
_notification = notification;
|
_notification = notification;
|
||||||
|
_file = file;
|
||||||
|
_settings = settings;
|
||||||
|
|
||||||
SaveCommand = new RelayCommand(async () => await SaveChanges(), () => Database.IsDirty);
|
SaveCommand = new RelayCommand(async () => await SaveChanges(), () => Database.IsDirty);
|
||||||
GeneratePasswordCommand = new RelayCommand(async () => await GeneratePassword());
|
GeneratePasswordCommand = new RelayCommand(async () => await GeneratePassword());
|
||||||
@@ -266,12 +341,20 @@ namespace ModernKeePass.ViewModels
|
|||||||
DeleteCommand = new RelayCommand(async () => await AskForDelete());
|
DeleteCommand = new RelayCommand(async () => await AskForDelete());
|
||||||
GoBackCommand = new RelayCommand(() => _navigation.GoBack());
|
GoBackCommand = new RelayCommand(() => _navigation.GoBack());
|
||||||
GoToParentCommand = new RelayCommand(() => GoToGroup(_parent.Id));
|
GoToParentCommand = new RelayCommand(() => GoToGroup(_parent.Id));
|
||||||
|
AddAdditionalField = new RelayCommand(AddField, () => IsCurrentEntry);
|
||||||
|
DeleteAdditionalField = new RelayCommand<EntryFieldVm>(async field => await DeleteField(field), field => field != null && IsCurrentEntry);
|
||||||
|
OpenAttachmentCommand = new RelayCommand<Attachment>(async attachment => await OpenAttachment(attachment));
|
||||||
|
AddAttachmentCommand = new RelayCommand(async () => await AddAttachment(), () => IsCurrentEntry);
|
||||||
|
DeleteAttachmentCommand = new RelayCommand<Attachment>(async attachment => await DeleteAttachment(attachment), _ => IsCurrentEntry);
|
||||||
|
|
||||||
MessengerInstance.Register<DatabaseSavedMessage>(this, _ => SaveCommand.RaiseCanExecuteChanged());
|
MessengerInstance.Register<DatabaseSavedMessage>(this, _ => SaveCommand.RaiseCanExecuteChanged());
|
||||||
|
MessengerInstance.Register<EntryFieldValueChangedMessage>(this, async message => await SetFieldValue(message.FieldName, message.FieldValue, message.IsProtected));
|
||||||
|
MessengerInstance.Register<EntryFieldNameChangedMessage>(this, async message => await UpdateFieldName(message.OldName, message.NewName, message.Value, message.IsProtected));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Initialize(string entryId)
|
public async Task Initialize(string entryId)
|
||||||
{
|
{
|
||||||
|
SelectedIndex = 0;
|
||||||
SelectedItem = await _mediator.Send(new GetEntryQuery { Id = entryId });
|
SelectedItem = await _mediator.Send(new GetEntryQuery { Id = entryId });
|
||||||
_parent = await _mediator.Send(new GetGroupQuery { Id = SelectedItem.ParentGroupId });
|
_parent = await _mediator.Send(new GetGroupQuery { Id = SelectedItem.ParentGroupId });
|
||||||
History = new ObservableCollection<EntryVm> { SelectedItem };
|
History = new ObservableCollection<EntryVm> { SelectedItem };
|
||||||
@@ -279,43 +362,11 @@ namespace ModernKeePass.ViewModels
|
|||||||
{
|
{
|
||||||
History.Add(entry);
|
History.Add(entry);
|
||||||
}
|
}
|
||||||
SelectedIndex = 0;
|
History.CollectionChanged += (sender, args) =>
|
||||||
}
|
|
||||||
|
|
||||||
private async Task AskForDelete()
|
|
||||||
{
|
|
||||||
if (IsCurrentEntry)
|
|
||||||
{
|
{
|
||||||
if (IsRecycleOnDelete)
|
SelectedIndex = 0;
|
||||||
{
|
SaveCommand.RaiseCanExecuteChanged();
|
||||||
await Delete();
|
};
|
||||||
_notification.Show(_resource.GetResourceValue("EntryRecyclingConfirmation"), _resource.GetResourceValue("EntryRecycled"));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await _dialog.ShowMessage(_resource.GetResourceValue("EntryDeletingConfirmation"),
|
|
||||||
_resource.GetResourceValue("EntityDeleteTitle"),
|
|
||||||
_resource.GetResourceValue("EntityDeleteActionButton"),
|
|
||||||
_resource.GetResourceValue("EntityDeleteCancelButton"),
|
|
||||||
async isOk =>
|
|
||||||
{
|
|
||||||
if (isOk) await Delete();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await _dialog.ShowMessage(_resource.GetResourceValue("HistoryDeleteDescription"), _resource.GetResourceValue("HistoryDeleteTitle"),
|
|
||||||
_resource.GetResourceValue("EntityDeleteActionButton"),
|
|
||||||
_resource.GetResourceValue("EntityDeleteCancelButton"), async isOk =>
|
|
||||||
{
|
|
||||||
if (!isOk) return;
|
|
||||||
await _mediator.Send(new DeleteHistoryCommand { Entry = History[0], HistoryIndex = History.Count - SelectedIndex - 1 });
|
|
||||||
History.RemoveAt(SelectedIndex);
|
|
||||||
SelectedIndex = 0;
|
|
||||||
SaveCommand.RaiseCanExecuteChanged();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task GeneratePassword()
|
public async Task GeneratePassword()
|
||||||
@@ -333,21 +384,6 @@ namespace ModernKeePass.ViewModels
|
|||||||
UnderscorePatternSelected = UnderscorePatternSelected,
|
UnderscorePatternSelected = UnderscorePatternSelected,
|
||||||
UpperCasePatternSelected = UpperCasePatternSelected
|
UpperCasePatternSelected = UpperCasePatternSelected
|
||||||
});
|
});
|
||||||
RaisePropertyChanged(nameof(IsRevealPasswordEnabled));
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task Move(string destination)
|
|
||||||
{
|
|
||||||
await _mediator.Send(new AddEntryCommand { ParentGroupId = destination, EntryId = Id });
|
|
||||||
await _mediator.Send(new RemoveEntryCommand { ParentGroupId = _parent.Id, EntryId = Id });
|
|
||||||
GoToGroup(destination);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task SetFieldValue(string fieldName, object value)
|
|
||||||
{
|
|
||||||
await _mediator.Send(new SetFieldValueCommand { EntryId = Id, FieldName = fieldName, FieldValue = value });
|
|
||||||
SaveCommand.RaiseCanExecuteChanged();
|
|
||||||
_isDirty = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task AddHistory()
|
public async Task AddHistory()
|
||||||
@@ -355,12 +391,86 @@ namespace ModernKeePass.ViewModels
|
|||||||
if (_isDirty) await _mediator.Send(new AddHistoryCommand { Entry = History[0] });
|
if (_isDirty) await _mediator.Send(new AddHistoryCommand { Entry = History[0] });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void GoToGroup(string groupId)
|
||||||
|
{
|
||||||
|
_navigation.NavigateTo(Constants.Navigation.GroupPage, new NavigationItem { Id = groupId });
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task Move(string destination)
|
||||||
|
{
|
||||||
|
await _mediator.Send(new AddEntryCommand { ParentGroupId = destination, EntryId = Id });
|
||||||
|
await _mediator.Send(new RemoveEntryCommand { ParentGroupId = _parent.Id, EntryId = Id });
|
||||||
|
GoToGroup(destination);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SetFieldValue(string fieldName, object value, bool isProtected)
|
||||||
|
{
|
||||||
|
await _mediator.Send(new UpsertFieldCommand { EntryId = Id, FieldName = fieldName, FieldValue = value, IsProtected = isProtected});
|
||||||
|
UpdateDirtyStatus(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task UpdateFieldName(string oldName, string newName, string value, bool isProtected)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(oldName)) await _mediator.Send(new DeleteFieldCommand { EntryId = Id, FieldName = oldName });
|
||||||
|
await SetFieldValue(newName, value, isProtected);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddField()
|
||||||
|
{
|
||||||
|
AdditionalFields.Add(new EntryFieldVm(string.Empty, string.Empty, false));
|
||||||
|
AdditionalFieldSelectedIndex = AdditionalFields.Count - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task DeleteField(EntryFieldVm field)
|
||||||
|
{
|
||||||
|
AdditionalFields.Remove(field);
|
||||||
|
if (!string.IsNullOrEmpty(field.Name))
|
||||||
|
{
|
||||||
|
await _mediator.Send(new DeleteFieldCommand {EntryId = Id, FieldName = field.Name});
|
||||||
|
UpdateDirtyStatus(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task AskForDelete()
|
||||||
|
{
|
||||||
|
if (IsCurrentEntry)
|
||||||
|
{
|
||||||
|
if (IsRecycleOnDelete)
|
||||||
|
{
|
||||||
|
await Delete();
|
||||||
|
_notification.Show(_resource.GetResourceValue("EntityDeleting"), string.Format(_resource.GetResourceValue("EntryRecycled"), Title));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await _dialog.ShowMessage(
|
||||||
|
string.Format(_resource.GetResourceValue("EntryDeletingConfirmation"), Title),
|
||||||
|
_resource.GetResourceValue("EntityDeleting"),
|
||||||
|
_resource.GetResourceValue("EntityDeleteActionButton"),
|
||||||
|
_resource.GetResourceValue("EntityDeleteCancelButton"),
|
||||||
|
async isOk =>
|
||||||
|
{
|
||||||
|
if (isOk) await Delete();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await _dialog.ShowMessage(_resource.GetResourceValue("HistoryDeleteDescription"),
|
||||||
|
_resource.GetResourceValue("HistoryDeleteTitle"),
|
||||||
|
_resource.GetResourceValue("EntityDeleteActionButton"),
|
||||||
|
_resource.GetResourceValue("EntityDeleteCancelButton"), async isOk =>
|
||||||
|
{
|
||||||
|
if (!isOk) return;
|
||||||
|
await _mediator.Send(new DeleteHistoryCommand { Entry = History[0], HistoryIndex = History.Count - SelectedIndex - 1 });
|
||||||
|
History.RemoveAt(SelectedIndex);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task RestoreHistory()
|
private async Task RestoreHistory()
|
||||||
{
|
{
|
||||||
await _mediator.Send(new RestoreHistoryCommand { Entry = History[0], HistoryIndex = History.Count - SelectedIndex - 1 });
|
await _mediator.Send(new RestoreHistoryCommand { Entry = History[0], HistoryIndex = History.Count - SelectedIndex - 1 });
|
||||||
History.Insert(0, SelectedItem);
|
History.Insert(0, SelectedItem);
|
||||||
SelectedIndex = 0;
|
|
||||||
SaveCommand.RaiseCanExecuteChanged();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task SaveChanges()
|
private async Task SaveChanges()
|
||||||
@@ -374,8 +484,7 @@ namespace ModernKeePass.ViewModels
|
|||||||
{
|
{
|
||||||
MessengerInstance.Send(new SaveErrorMessage { Message = e.Message });
|
MessengerInstance.Send(new SaveErrorMessage { Message = e.Message });
|
||||||
}
|
}
|
||||||
SaveCommand.RaiseCanExecuteChanged();
|
UpdateDirtyStatus(false);
|
||||||
_isDirty = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task Delete()
|
private async Task Delete()
|
||||||
@@ -386,12 +495,40 @@ namespace ModernKeePass.ViewModels
|
|||||||
ParentGroupId = SelectedItem.ParentGroupId,
|
ParentGroupId = SelectedItem.ParentGroupId,
|
||||||
RecycleBinName = _resource.GetResourceValue("RecycleBinTitle")
|
RecycleBinName = _resource.GetResourceValue("RecycleBinTitle")
|
||||||
});
|
});
|
||||||
|
_isDirty = false;
|
||||||
_navigation.GoBack();
|
_navigation.GoBack();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void GoToGroup(string groupId)
|
private async Task OpenAttachment(Attachment attachment)
|
||||||
{
|
{
|
||||||
_navigation.NavigateTo(Constants.Navigation.GroupPage, new NavigationItem { Id = groupId });
|
var extensionIndex = attachment.Name.LastIndexOf('.');
|
||||||
|
var fileInfo = await _file.CreateFile(attachment.Name,
|
||||||
|
attachment.Name.Substring(extensionIndex, attachment.Name.Length - extensionIndex),
|
||||||
|
string.Empty,
|
||||||
|
false);
|
||||||
|
if (fileInfo == null) return;
|
||||||
|
await _file.WriteBinaryContentsToFile(fileInfo.Id, attachment.Content);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task AddAttachment()
|
||||||
|
{
|
||||||
|
var fileInfo = await _file.OpenFile(string.Empty, Domain.Common.Constants.Extensions.Any, false);
|
||||||
|
if (fileInfo == null) return;
|
||||||
|
var contents = await _file.ReadBinaryFile(fileInfo.Id);
|
||||||
|
await _mediator.Send(new AddAttachmentCommand { Entry = SelectedItem, AttachmentName = fileInfo.Name, AttachmentContent = contents });
|
||||||
|
Attachments.Add(new Attachment { Name = fileInfo.Name, Content = contents });
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task DeleteAttachment(Attachment attachment)
|
||||||
|
{
|
||||||
|
await _mediator.Send(new DeleteAttachmentCommand { Entry = SelectedItem, AttachmentName = attachment.Name });
|
||||||
|
Attachments.Remove(attachment);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateDirtyStatus(bool isDirty)
|
||||||
|
{
|
||||||
|
SaveCommand.RaiseCanExecuteChanged();
|
||||||
|
_isDirty = isDirty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -20,6 +20,7 @@ using ModernKeePass.Application.Group.Commands.CreateEntry;
|
|||||||
using ModernKeePass.Application.Group.Commands.CreateGroup;
|
using ModernKeePass.Application.Group.Commands.CreateGroup;
|
||||||
using ModernKeePass.Application.Group.Commands.DeleteGroup;
|
using ModernKeePass.Application.Group.Commands.DeleteGroup;
|
||||||
using ModernKeePass.Application.Group.Commands.MoveEntry;
|
using ModernKeePass.Application.Group.Commands.MoveEntry;
|
||||||
|
using ModernKeePass.Application.Group.Commands.MoveGroup;
|
||||||
using ModernKeePass.Application.Group.Commands.RemoveGroup;
|
using ModernKeePass.Application.Group.Commands.RemoveGroup;
|
||||||
using ModernKeePass.Application.Group.Commands.SortEntries;
|
using ModernKeePass.Application.Group.Commands.SortEntries;
|
||||||
using ModernKeePass.Application.Group.Commands.SortGroups;
|
using ModernKeePass.Application.Group.Commands.SortGroups;
|
||||||
@@ -42,7 +43,7 @@ namespace ModernKeePass.ViewModels
|
|||||||
public bool IsNotRoot => Database.RootGroupId != _group.Id;
|
public bool IsNotRoot => Database.RootGroupId != _group.Id;
|
||||||
|
|
||||||
public IOrderedEnumerable<IGrouping<char, EntryVm>> EntriesZoomedOut => from e in Entries
|
public IOrderedEnumerable<IGrouping<char, EntryVm>> EntriesZoomedOut => from e in Entries
|
||||||
group e by e.Title.ToUpper().FirstOrDefault() into grp
|
group e by (e.Title.Value ?? string.Empty).ToUpper().FirstOrDefault() into grp
|
||||||
orderby grp.Key
|
orderby grp.Key
|
||||||
select grp;
|
select grp;
|
||||||
|
|
||||||
@@ -106,6 +107,7 @@ namespace ModernKeePass.ViewModels
|
|||||||
private GroupVm _parent;
|
private GroupVm _parent;
|
||||||
private bool _isEditMode;
|
private bool _isEditMode;
|
||||||
private EntryVm _reorderedEntry;
|
private EntryVm _reorderedEntry;
|
||||||
|
private GroupVm _reorderedGroup;
|
||||||
|
|
||||||
public GroupDetailVm(IMediator mediator, IResourceProxy resource, INavigationService navigation, IDialogService dialog, INotificationService notification)
|
public GroupDetailVm(IMediator mediator, IResourceProxy resource, INavigationService navigation, IDialogService dialog, INotificationService notification)
|
||||||
{
|
{
|
||||||
@@ -139,6 +141,7 @@ namespace ModernKeePass.ViewModels
|
|||||||
Entries = new ObservableCollection<EntryVm>(_group.Entries);
|
Entries = new ObservableCollection<EntryVm>(_group.Entries);
|
||||||
Entries.CollectionChanged += Entries_CollectionChanged;
|
Entries.CollectionChanged += Entries_CollectionChanged;
|
||||||
Groups = new ObservableCollection<GroupVm>(_group.SubGroups);
|
Groups = new ObservableCollection<GroupVm>(_group.SubGroups);
|
||||||
|
Groups.CollectionChanged += Groups_CollectionChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void GoToEntry(string entryId, bool isNew = false)
|
public void GoToEntry(string entryId, bool isNew = false)
|
||||||
@@ -213,6 +216,29 @@ namespace ModernKeePass.ViewModels
|
|||||||
SaveCommand.RaiseCanExecuteChanged();
|
SaveCommand.RaiseCanExecuteChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async void Groups_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||||
|
{
|
||||||
|
switch (e.Action)
|
||||||
|
{
|
||||||
|
case NotifyCollectionChangedAction.Remove:
|
||||||
|
var oldIndex = e.OldStartingIndex;
|
||||||
|
_reorderedGroup = _group.SubGroups[oldIndex];
|
||||||
|
break;
|
||||||
|
case NotifyCollectionChangedAction.Add:
|
||||||
|
if (_reorderedGroup == null)
|
||||||
|
{
|
||||||
|
var group = (GroupVm)e.NewItems[0];
|
||||||
|
await _mediator.Send(new AddGroupCommand() { GroupId = group.Id, ParentGroupId = Id });
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await _mediator.Send(new MoveGroupCommand { Group = _reorderedGroup, ParentGroup = _group, Index = e.NewStartingIndex });
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
SaveCommand.RaiseCanExecuteChanged();
|
||||||
|
}
|
||||||
|
|
||||||
private async Task SortEntriesAsync()
|
private async Task SortEntriesAsync()
|
||||||
{
|
{
|
||||||
await _mediator.Send(new SortEntriesCommand {Group = _group});
|
await _mediator.Send(new SortEntriesCommand {Group = _group});
|
||||||
@@ -235,11 +261,13 @@ namespace ModernKeePass.ViewModels
|
|||||||
if (IsRecycleOnDelete)
|
if (IsRecycleOnDelete)
|
||||||
{
|
{
|
||||||
await Delete();
|
await Delete();
|
||||||
_notification.Show(_resource.GetResourceValue("GroupRecyclingConfirmation"), _resource.GetResourceValue("GroupRecycled"));
|
_notification.Show(_resource.GetResourceValue("EntityDeleting"), string.Format(_resource.GetResourceValue("GroupRecycled"), Title));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await _dialog.ShowMessage(_resource.GetResourceValue("GroupDeletingConfirmation"), _resource.GetResourceValue("EntityDeleteTitle"),
|
await _dialog.ShowMessage(
|
||||||
|
string.Format(_resource.GetResourceValue("GroupDeletingConfirmation"), Title),
|
||||||
|
_resource.GetResourceValue("EntityDeleting"),
|
||||||
_resource.GetResourceValue("EntityDeleteActionButton"),
|
_resource.GetResourceValue("EntityDeleteActionButton"),
|
||||||
_resource.GetResourceValue("EntityDeleteCancelButton"),
|
_resource.GetResourceValue("EntityDeleteCancelButton"),
|
||||||
async isOk =>
|
async isOk =>
|
||||||
|
@@ -8,6 +8,7 @@ using ModernKeePass.Application.Database.Queries.GetDatabase;
|
|||||||
using ModernKeePass.Domain.Interfaces;
|
using ModernKeePass.Domain.Interfaces;
|
||||||
using ModernKeePass.ViewModels.ListItems;
|
using ModernKeePass.ViewModels.ListItems;
|
||||||
using ModernKeePass.Views;
|
using ModernKeePass.Views;
|
||||||
|
using ModernKeePass.Views.SettingsPageFrames;
|
||||||
|
|
||||||
namespace ModernKeePass.ViewModels
|
namespace ModernKeePass.ViewModels
|
||||||
{
|
{
|
||||||
@@ -57,19 +58,11 @@ namespace ModernKeePass.ViewModels
|
|||||||
IsSelected = true
|
IsSelected = true
|
||||||
},
|
},
|
||||||
new ListMenuItemVm
|
new ListMenuItemVm
|
||||||
{
|
|
||||||
Title = resource.GetResourceValue("SettingsMenuItemSave"),
|
|
||||||
Group = resource.GetResourceValue("SettingsMenuGroupApplication"),
|
|
||||||
SymbolIcon = Symbol.Save,
|
|
||||||
PageType = typeof(SettingsSavePage)
|
|
||||||
},
|
|
||||||
new ListMenuItemVm
|
|
||||||
{
|
{
|
||||||
Title = resource.GetResourceValue("SettingsMenuItemGeneral"),
|
Title = resource.GetResourceValue("SettingsMenuItemGeneral"),
|
||||||
Group = resource.GetResourceValue("SettingsMenuGroupDatabase"),
|
Group = resource.GetResourceValue("SettingsMenuGroupApplication"),
|
||||||
SymbolIcon = Symbol.Setting,
|
SymbolIcon = Symbol.Setting,
|
||||||
PageType = typeof(SettingsDatabasePage),
|
PageType = typeof(SettingsGeneralPage)
|
||||||
IsEnabled = database.IsOpen
|
|
||||||
},
|
},
|
||||||
new ListMenuItemVm
|
new ListMenuItemVm
|
||||||
{
|
{
|
||||||
@@ -78,6 +71,30 @@ namespace ModernKeePass.ViewModels
|
|||||||
SymbolIcon = Symbol.Permissions,
|
SymbolIcon = Symbol.Permissions,
|
||||||
PageType = typeof(SettingsSecurityPage),
|
PageType = typeof(SettingsSecurityPage),
|
||||||
IsEnabled = database.IsOpen
|
IsEnabled = database.IsOpen
|
||||||
|
},
|
||||||
|
new ListMenuItemVm
|
||||||
|
{
|
||||||
|
Title = resource.GetResourceValue("SettingsMenuItemHistory"),
|
||||||
|
Group = resource.GetResourceValue("SettingsMenuGroupDatabase"),
|
||||||
|
SymbolIcon = Symbol.Undo,
|
||||||
|
PageType = typeof(SettingsHistoryPage),
|
||||||
|
IsEnabled = database.IsOpen
|
||||||
|
},
|
||||||
|
new ListMenuItemVm
|
||||||
|
{
|
||||||
|
Title = resource.GetResourceValue("SettingsMenuItemRecycleBin"),
|
||||||
|
Group = resource.GetResourceValue("SettingsMenuGroupDatabase"),
|
||||||
|
SymbolIcon = Symbol.Delete,
|
||||||
|
PageType = typeof(SettingsRecycleBinPage),
|
||||||
|
IsEnabled = database.IsOpen
|
||||||
|
},
|
||||||
|
new ListMenuItemVm
|
||||||
|
{
|
||||||
|
Title = resource.GetResourceValue("SettingsMenuItemCredentials"),
|
||||||
|
Group = resource.GetResourceValue("SettingsMenuGroupDatabase"),
|
||||||
|
SymbolIcon = Symbol.Account,
|
||||||
|
PageType = typeof(SettingsCredentialsPage),
|
||||||
|
IsEnabled = database.IsOpen
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
SelectedItem = menuItems.FirstOrDefault(m => m.IsSelected);
|
SelectedItem = menuItems.FirstOrDefault(m => m.IsSelected);
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
<Page
|
<Page x:Name="Page"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
@@ -380,84 +380,194 @@
|
|||||||
SelectedIndex="{Binding SelectedIndex, Mode=TwoWay}"
|
SelectedIndex="{Binding SelectedIndex, Mode=TwoWay}"
|
||||||
SelectedItem="{Binding SelectedItem, Mode=TwoWay}" />
|
SelectedItem="{Binding SelectedItem, Mode=TwoWay}" />
|
||||||
<Grid Grid.Column="1">
|
<Grid Grid.Column="1">
|
||||||
<ScrollViewer VerticalScrollBarVisibility="Auto">
|
<Hub Padding="0">
|
||||||
<StackPanel Margin="20,0,0,20">
|
<Hub.Resources>
|
||||||
<StackPanel.Resources>
|
<Style TargetType="TextBlock" x:Key="EntryTextBlockStyle">
|
||||||
<Style TargetType="TextBlock">
|
<Setter Property="Margin" Value="0,20,0,0"/>
|
||||||
<Setter Property="Margin" Value="0,20,0,0"/>
|
<Setter Property="FontSize" Value="16"/>
|
||||||
<Setter Property="FontSize" Value="18"/>
|
<Setter Property="TextWrapping" Value="Wrap"/>
|
||||||
<Setter Property="TextWrapping" Value="Wrap"/>
|
</Style>
|
||||||
</Style>
|
</Hub.Resources>
|
||||||
<Style TargetType="CheckBox">
|
<HubSection x:Uid="EntryHubMain">
|
||||||
<Setter Property="Margin" Value="0,20,0,0"/>
|
<DataTemplate>
|
||||||
<Setter Property="FontSize" Value="18"/>
|
<ScrollViewer VerticalScrollBarVisibility="Auto">
|
||||||
</Style>
|
<StackPanel Margin="20,0,0,20" MinWidth="400">
|
||||||
</StackPanel.Resources>
|
<StackPanel.Resources>
|
||||||
<TextBlock x:Uid="EntryLogin" />
|
<Style TargetType="CheckBox">
|
||||||
<local:TextBoxWithButton x:Uid="LoginTextBox" Text="{Binding UserName, Mode=TwoWay}" Style="{StaticResource TextBoxWithButtonStyle}" ButtonSymbol="" IsEnabled="{Binding IsCurrentEntry}">
|
<Setter Property="Margin" Value="0,20,0,0"/>
|
||||||
<interactivity:Interaction.Behaviors>
|
<Setter Property="FontSize" Value="18"/>
|
||||||
<core:EventTriggerBehavior EventName="ButtonClick">
|
</Style>
|
||||||
<actions:ClipboardAction Text="{Binding UserName}" />
|
</StackPanel.Resources>
|
||||||
<actions:ToastAction x:Uid="ToastCopyLogin" Title="{Binding Title}" />
|
<TextBlock x:Uid="EntryLogin" Style="{StaticResource EntryTextBlockStyle}" />
|
||||||
</core:EventTriggerBehavior>
|
<local:TextBoxWithButton x:Uid="LoginTextBox" Text="{Binding UserName, Mode=TwoWay}" Style="{StaticResource TextBoxWithButtonStyle}" ButtonSymbol="" IsEnabled="{Binding IsCurrentEntry}">
|
||||||
</interactivity:Interaction.Behaviors>
|
<interactivity:Interaction.Behaviors>
|
||||||
</local:TextBoxWithButton>
|
<core:EventTriggerBehavior EventName="ButtonClick">
|
||||||
<TextBlock x:Uid="EntryPassword" />
|
<actions:ClipboardAction Text="{Binding UserName}" />
|
||||||
<local:PasswordBoxWithButton Password="{Binding Password, Mode=TwoWay}" IsPasswordRevealEnabled="True" Visibility="{Binding IsRevealPassword, Converter={StaticResource InverseBooleanToVisibilityConverter}}" Style="{StaticResource PasswordBoxWithButtonStyle}" IsEnabled="{Binding IsCurrentEntry}" ButtonSymbol="" />
|
<actions:ToastAction x:Uid="ToastCopyLogin" Title="{Binding Title}" />
|
||||||
<local:TextBoxWithButton x:Uid="PasswordTextBox" Text="{Binding Password, Mode=TwoWay}" Visibility="{Binding IsRevealPassword, Converter={StaticResource BooleanToVisibilityConverter}}" Style="{StaticResource TextBoxWithButtonStyle}" ButtonSymbol="" IsEnabled="{Binding IsCurrentEntry}">
|
</core:EventTriggerBehavior>
|
||||||
<interactivity:Interaction.Behaviors>
|
</interactivity:Interaction.Behaviors>
|
||||||
<core:EventTriggerBehavior EventName="ButtonClick">
|
</local:TextBoxWithButton>
|
||||||
<actions:ClipboardAction Text="{Binding Password}" />
|
<TextBlock x:Uid="EntryPassword" Style="{StaticResource EntryTextBlockStyle}" />
|
||||||
<actions:ToastAction x:Uid="ToastCopyPassword" Title="{Binding Title}" />
|
<local:PasswordBoxWithButton Password="{Binding Password, Mode=TwoWay}" IsPasswordRevealEnabled="True" Visibility="{Binding IsRevealPassword, Converter={StaticResource InverseBooleanToVisibilityConverter}}" Style="{StaticResource PasswordBoxWithButtonStyle}" IsEnabled="{Binding IsCurrentEntry}" ButtonSymbol="" />
|
||||||
</core:EventTriggerBehavior>
|
<local:TextBoxWithButton x:Uid="PasswordTextBox" Text="{Binding Password, Mode=TwoWay}" Visibility="{Binding IsRevealPassword, Converter={StaticResource BooleanToVisibilityConverter}}" Style="{StaticResource TextBoxWithButtonStyle}" ButtonSymbol="" IsEnabled="{Binding IsCurrentEntry}">
|
||||||
</interactivity:Interaction.Behaviors>
|
<interactivity:Interaction.Behaviors>
|
||||||
</local:TextBoxWithButton>
|
<core:EventTriggerBehavior EventName="ButtonClick">
|
||||||
<ProgressBar Value="{Binding PasswordComplexityIndicator, ConverterParameter=0\,128, Converter={StaticResource ProgressBarLegalValuesConverter}}" Maximum="128" Width="350" HorizontalAlignment="Left" Foreground="{Binding PasswordComplexityIndicator, ConverterParameter=128, Converter={StaticResource DoubleToForegroundBrushComplexityConverter}}" />
|
<actions:ClipboardAction Text="{Binding Password}" />
|
||||||
<CheckBox x:Uid="EntryShowPassword" HorizontalAlignment="Left" Margin="-3,0,0,0" IsChecked="{Binding IsRevealPassword, Mode=TwoWay}" IsEnabled="{Binding IsRevealPasswordEnabled}" />
|
<actions:ToastAction x:Uid="ToastCopyPassword" Title="{Binding Title}" />
|
||||||
<TextBlock TextWrapping="Wrap" Text="URL" FontSize="18"/>
|
</core:EventTriggerBehavior>
|
||||||
<local:TextBoxWithButton x:Uid="UrlTextBox" Text="{Binding Url, Mode=TwoWay}" Style="{StaticResource TextBoxWithButtonStyle}" ButtonSymbol="" IsEnabled="{Binding IsCurrentEntry}">
|
</interactivity:Interaction.Behaviors>
|
||||||
<interactivity:Interaction.Behaviors>
|
</local:TextBoxWithButton>
|
||||||
<core:EventTriggerBehavior EventName="ButtonClick">
|
<ProgressBar Value="{Binding PasswordComplexityIndicator, ConverterParameter=0\,128, Converter={StaticResource ProgressBarLegalValuesConverter}}" Maximum="128" Width="350" HorizontalAlignment="Left" Foreground="{Binding PasswordComplexityIndicator, ConverterParameter=128, Converter={StaticResource DoubleToForegroundBrushComplexityConverter}}" />
|
||||||
<actions:NavigateToUrlAction Url="{Binding Url}" />
|
<CheckBox x:Uid="EntryShowPassword" HorizontalAlignment="Left" Margin="-3,0,0,0" IsChecked="{Binding IsRevealPassword, Mode=TwoWay}" />
|
||||||
</core:EventTriggerBehavior>
|
<TextBlock Text="URL" Style="{StaticResource EntryTextBlockStyle}"/>
|
||||||
</interactivity:Interaction.Behaviors>
|
<local:TextBoxWithButton x:Uid="UrlTextBox" Text="{Binding Url, Mode=TwoWay}" Style="{StaticResource TextBoxWithButtonStyle}" ButtonSymbol="" IsEnabled="{Binding IsCurrentEntry}">
|
||||||
</local:TextBoxWithButton>
|
<interactivity:Interaction.Behaviors>
|
||||||
<TextBlock x:Uid="EntryNotes" />
|
<core:EventTriggerBehavior EventName="ButtonClick">
|
||||||
<TextBox HorizontalAlignment="Left" TextWrapping="Wrap" Text="{Binding Notes, Mode=TwoWay}" Width="350" Height="200" AcceptsReturn="True" IsSpellCheckEnabled="True" IsEnabled="{Binding IsCurrentEntry}" />
|
<actions:NavigateToUrlAction Url="{Binding Url}" />
|
||||||
<CheckBox x:Uid="EntryExpirationDate" IsChecked="{Binding HasExpirationDate, Mode=TwoWay}" IsEnabled="{Binding IsCurrentEntry}" />
|
</core:EventTriggerBehavior>
|
||||||
<Grid>
|
</interactivity:Interaction.Behaviors>
|
||||||
<Grid.ColumnDefinitions>
|
</local:TextBoxWithButton>
|
||||||
<ColumnDefinition Width="Auto" />
|
<TextBlock x:Uid="EntryNotes" Style="{StaticResource EntryTextBlockStyle}" />
|
||||||
<ColumnDefinition Width="*" />
|
<TextBox HorizontalAlignment="Left" TextWrapping="Wrap" Text="{Binding Notes, Mode=TwoWay}" Width="350" Height="200" AcceptsReturn="True" IsSpellCheckEnabled="True" IsEnabled="{Binding IsCurrentEntry}" />
|
||||||
</Grid.ColumnDefinitions>
|
<CheckBox x:Uid="EntryExpirationDate" IsChecked="{Binding HasExpirationDate, Mode=TwoWay}" IsEnabled="{Binding IsCurrentEntry}" />
|
||||||
<SymbolIcon Grid.Column="0" Symbol="Important" Foreground="DarkRed" Visibility="{Binding HasExpired, Converter={StaticResource BooleanToVisibilityConverter}}">
|
<Grid>
|
||||||
<ToolTipService.ToolTip>
|
<Grid.ColumnDefinitions>
|
||||||
<ToolTip x:Uid="EntryExpirationTooltip" />
|
<ColumnDefinition Width="Auto" />
|
||||||
</ToolTipService.ToolTip>
|
<ColumnDefinition Width="*" />
|
||||||
</SymbolIcon>
|
</Grid.ColumnDefinitions>
|
||||||
<StackPanel Grid.Column="1" x:Name="ExpirationDatePanel" Orientation="Horizontal" Visibility="{Binding HasExpirationDate, Converter={StaticResource BooleanToVisibilityConverter}}">
|
<SymbolIcon Grid.Column="0" Symbol="Important" Foreground="DarkRed" Visibility="{Binding HasExpired, Converter={StaticResource BooleanToVisibilityConverter}}">
|
||||||
<DatePicker Margin="0,0,20,0" Date="{Binding ExpiryDate, Mode=TwoWay}" />
|
<ToolTipService.ToolTip>
|
||||||
<TimePicker Time="{Binding ExpiryTime, Mode=TwoWay}" />
|
<ToolTip x:Uid="EntryExpirationTooltip" />
|
||||||
|
</ToolTipService.ToolTip>
|
||||||
|
</SymbolIcon>
|
||||||
|
<StackPanel Grid.Column="1" x:Name="ExpirationDatePanel" Orientation="Vertical" Visibility="{Binding HasExpirationDate, Converter={StaticResource BooleanToVisibilityConverter}}">
|
||||||
|
<DatePicker Margin="10,5,20,0" Date="{Binding ExpiryDate, Mode=TwoWay}" />
|
||||||
|
<TimePicker Margin="10,10,0,0" Time="{Binding ExpiryTime, Mode=TwoWay}" />
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</StackPanel>
|
||||||
|
<VisualStateManager.VisualStateGroups>
|
||||||
|
<VisualStateGroup>
|
||||||
|
<VisualState x:Name="Small">
|
||||||
|
<Storyboard>
|
||||||
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ExpirationDatePanel" Storyboard.TargetProperty="Orientation">
|
||||||
|
<DiscreteObjectKeyFrame KeyTime="0" Value="Vertical"/>
|
||||||
|
</ObjectAnimationUsingKeyFrames>
|
||||||
|
</Storyboard>
|
||||||
|
</VisualState>
|
||||||
|
<VisualState x:Name="Large">
|
||||||
|
<Storyboard>
|
||||||
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ExpirationDatePanel" Storyboard.TargetProperty="Orientation">
|
||||||
|
<DiscreteObjectKeyFrame KeyTime="0" Value="Horizontal"/>
|
||||||
|
</ObjectAnimationUsingKeyFrames>
|
||||||
|
</Storyboard>
|
||||||
|
</VisualState>
|
||||||
|
</VisualStateGroup>
|
||||||
|
</VisualStateManager.VisualStateGroups>
|
||||||
|
</ScrollViewer>
|
||||||
|
</DataTemplate>
|
||||||
|
</HubSection>
|
||||||
|
<HubSection x:Uid="EntryHubPresentation">
|
||||||
|
<DataTemplate>
|
||||||
|
<StackPanel Orientation="Vertical">
|
||||||
|
<TextBlock x:Uid="EntryIcon" Style="{StaticResource EntryTextBlockStyle}" />
|
||||||
|
<userControls:SymbolPickerUserControl SelectedSymbol="{Binding Icon, Mode=TwoWay}" HorizontalAlignment="Left" IsEnabled="{Binding IsCurrentEntry}" />
|
||||||
|
<TextBlock x:Uid="EntryBackgroundColor" Style="{StaticResource EntryTextBlockStyle}" />
|
||||||
|
<userControls:ColorPickerUserControl SelectedColor="{Binding BackgroundColor, Mode=TwoWay}" IsEnabled="{Binding IsCurrentEntry}" Width="250" />
|
||||||
|
<TextBlock x:Uid="EntryForegroundColor" Style="{StaticResource EntryTextBlockStyle}" />
|
||||||
|
<userControls:ColorPickerUserControl SelectedColor="{Binding ForegroundColor, Mode=TwoWay}" IsEnabled="{Binding IsCurrentEntry}" Width="250" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</DataTemplate>
|
||||||
<StackPanel x:Name="EditDesign" Visibility="{Binding IsEditMode, Converter={StaticResource BooleanToVisibilityConverter}}" Orientation="Horizontal">
|
</HubSection>
|
||||||
<StackPanel Width="250" HorizontalAlignment="Left">
|
<HubSection x:Uid="EntryHubAdditional">
|
||||||
<TextBlock x:Uid="EntryBackgroundColor" />
|
<DataTemplate>
|
||||||
<userControls:ColorPickerUserControl SelectedColor="{Binding BackgroundColor, Mode=TwoWay}" IsEnabled="{Binding IsCurrentEntry}" />
|
<local:SelectableTemplateListView
|
||||||
</StackPanel>
|
ItemsSource="{Binding AdditionalFields}"
|
||||||
<StackPanel Width="250" HorizontalAlignment="Left">
|
SelectedIndex="{Binding AdditionalFieldSelectedIndex, Mode=TwoWay}"
|
||||||
<TextBlock x:Uid="EntryForegroundColor" />
|
ItemContainerStyle="{StaticResource ListViewLeftIndicatorItemExpanded}">
|
||||||
<userControls:ColorPickerUserControl SelectedColor="{Binding ForegroundColor, Mode=TwoWay}" IsEnabled="{Binding IsCurrentEntry}" />
|
<local:SelectableTemplateListView.HeaderTemplate>
|
||||||
</StackPanel>
|
<DataTemplate>
|
||||||
</StackPanel>
|
<StackPanel Orientation="Vertical">
|
||||||
</StackPanel>
|
<HyperlinkButton Command="{Binding Path=DataContext.AddAdditionalField, ElementName=Page}">
|
||||||
</ScrollViewer>
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<SymbolIcon Symbol="Add" />
|
||||||
|
<TextBlock x:Uid="EntryAddAdditionalField" VerticalAlignment="Center" Margin="10,0,0,0" />
|
||||||
|
</StackPanel>
|
||||||
|
</HyperlinkButton>
|
||||||
|
<Border BorderBrush="DarkGray" BorderThickness="0,0,0,1" />
|
||||||
|
</StackPanel>
|
||||||
|
</DataTemplate>
|
||||||
|
</local:SelectableTemplateListView.HeaderTemplate>
|
||||||
|
<local:SelectableTemplateListView.SelectedItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<Grid Margin="5">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition />
|
||||||
|
<RowDefinition />
|
||||||
|
<RowDefinition />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<TextBox Grid.Row="0" Text="{Binding Name, Mode=TwoWay}" Width="350"
|
||||||
|
IsEnabled="{Binding Path=DataContext.IsCurrentEntry, ElementName=Page}" />
|
||||||
|
<TextBox Grid.Row="1" AcceptsReturn="True" Height="100" TextWrapping="Wrap" Width="350" Margin="0,5,0,0"
|
||||||
|
Text="{Binding Value, Mode=TwoWay}"
|
||||||
|
IsEnabled="{Binding Path=DataContext.IsCurrentEntry, ElementName=Page}" />
|
||||||
|
<ToggleSwitch Grid.Row="2" x:Uid="EntryEnableFieldProtection" HorizontalAlignment="Left" IsOn="{Binding IsProtected, Mode=TwoWay}" />
|
||||||
|
<Button Grid.Row="2" x:Uid="EntryDeleteAdditionalField" HorizontalAlignment="Right" Margin="0,15,0,0" Command="{Binding Path=DataContext.DeleteAdditionalField, ElementName=Page}" CommandParameter="{Binding}" />
|
||||||
|
</Grid>
|
||||||
|
</DataTemplate>
|
||||||
|
</local:SelectableTemplateListView.SelectedItemTemplate>
|
||||||
|
<local:SelectableTemplateListView.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<StackPanel Orientation="Vertical" Margin="5">
|
||||||
|
<TextBlock Text="{Binding Name}" Style="{StaticResource EntryTextBlockStyle}" FontWeight="SemiBold" />
|
||||||
|
<TextBlock HorizontalAlignment="Left" MaxLines="3" FontSize="12" Margin="2,0,2,5" Text="*****" Visibility="{Binding IsProtected, Converter={StaticResource BooleanToVisibilityConverter}}" Style="{StaticResource EntryTextBlockStyle}"/>
|
||||||
|
<TextBlock HorizontalAlignment="Left" MaxLines="3" FontSize="12" Margin="2,0,2,5" Text="{Binding Value}" Visibility="{Binding IsProtected, Converter={StaticResource InverseBooleanToVisibilityConverter}}" Style="{StaticResource EntryTextBlockStyle}"/>
|
||||||
|
</StackPanel>
|
||||||
|
</DataTemplate>
|
||||||
|
</local:SelectableTemplateListView.ItemTemplate>
|
||||||
|
</local:SelectableTemplateListView>
|
||||||
|
</DataTemplate>
|
||||||
|
</HubSection>
|
||||||
|
<HubSection x:Uid="EntryHubAttachments" Foreground="{StaticResource HubSectionBrush}">
|
||||||
|
<DataTemplate>
|
||||||
|
<ScrollViewer VerticalScrollBarVisibility="Auto">
|
||||||
|
<StackPanel Orientation="Vertical">
|
||||||
|
<HyperlinkButton Command="{Binding Path=DataContext.AddAttachmentCommand, ElementName=Page}">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<SymbolIcon Symbol="Attach" />
|
||||||
|
<TextBlock x:Uid="EntryAddAttachment" VerticalAlignment="Center" Margin="10,0,0,0" />
|
||||||
|
</StackPanel>
|
||||||
|
</HyperlinkButton>
|
||||||
|
<Border BorderBrush="DarkGray" BorderThickness="0,0,0,1" />
|
||||||
|
<ItemsControl ItemsSource="{Binding Attachments}">
|
||||||
|
<ItemsControl.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<HyperlinkButton Content="{Binding Name}" Command="{Binding Path=DataContext.OpenAttachmentCommand, ElementName=Page}" CommandParameter="{Binding}" />
|
||||||
|
<HyperlinkButton Grid.Column="1" Margin="10,0,0,0" HorizontalAlignment="Right" Command="{Binding Path=DataContext.DeleteAttachmentCommand, ElementName=Page}" CommandParameter="{Binding}">
|
||||||
|
<SymbolIcon Symbol="Delete" />
|
||||||
|
</HyperlinkButton>
|
||||||
|
</Grid>
|
||||||
|
</DataTemplate>
|
||||||
|
</ItemsControl.ItemTemplate>
|
||||||
|
</ItemsControl>
|
||||||
|
</StackPanel>
|
||||||
|
</ScrollViewer>
|
||||||
|
</DataTemplate>
|
||||||
|
</HubSection>
|
||||||
|
</Hub>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
<!-- Bouton Précédent et titre de la page -->
|
<!-- Bouton Précédent et titre de la page -->
|
||||||
<Grid Grid.Row="0" Background="{ThemeResource AppBarBackgroundThemeBrush}">
|
<Grid Grid.Row="0" Background="{ThemeResource AppBarBackgroundThemeBrush}">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="{StaticResource MenuWidthGridLength}"/>
|
<ColumnDefinition Width="{StaticResource MenuWidthGridLength}"/>
|
||||||
|
<ColumnDefinition Width="{StaticResource MenuWidthGridLength}"/>
|
||||||
|
<ColumnDefinition Width="Auto"/>
|
||||||
<ColumnDefinition Width="*"/>
|
<ColumnDefinition Width="*"/>
|
||||||
<ColumnDefinition Width="Auto"/>
|
<ColumnDefinition Width="Auto"/>
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
@@ -471,47 +581,41 @@
|
|||||||
Style="{StaticResource NoBorderButtonStyle}">
|
Style="{StaticResource NoBorderButtonStyle}">
|
||||||
<SymbolIcon Symbol="Back" />
|
<SymbolIcon Symbol="Back" />
|
||||||
</Button>
|
</Button>
|
||||||
<StackPanel Grid.Column="1" Orientation="Horizontal">
|
<Button Grid.Column="1"
|
||||||
<Button
|
Height="{StaticResource MenuHeight}"
|
||||||
Height="{StaticResource MenuHeight}"
|
Width="{StaticResource MenuWidth}"
|
||||||
Width="{StaticResource MenuWidth}"
|
Command="{Binding GoToParentCommand}"
|
||||||
Command="{Binding GoToParentCommand}"
|
Style="{StaticResource NoBorderButtonStyle}">
|
||||||
Style="{StaticResource NoBorderButtonStyle}">
|
<SymbolIcon Symbol="Up" />
|
||||||
<SymbolIcon Symbol="Up" />
|
<ToolTipService.ToolTip>
|
||||||
<ToolTipService.ToolTip>
|
<ToolTip Content="{Binding ParentGroupName}" />
|
||||||
<ToolTip Content="{Binding ParentGroupName}" />
|
</ToolTipService.ToolTip>
|
||||||
</ToolTipService.ToolTip>
|
</Button>
|
||||||
</Button>
|
<Viewbox Grid.Column="2" MaxHeight="200">
|
||||||
<Viewbox MaxHeight="200" Visibility="{Binding IsEditMode, Converter={StaticResource BooleanToVisibilityConverter}}">
|
<SymbolIcon Symbol="{Binding Icon}" Width="100" Height="70" />
|
||||||
<userControls:SymbolPickerUserControl Width="100" Height="70" SelectedSymbol="{Binding Icon, Mode=TwoWay}" />
|
</Viewbox>
|
||||||
</Viewbox>
|
<TextBox Grid.Column="3"
|
||||||
<Viewbox MaxHeight="200" Visibility="{Binding IsEditMode, Converter={StaticResource InverseBooleanToVisibilityConverter}}">
|
x:Uid="EntryTitle"
|
||||||
<SymbolIcon Symbol="{Binding Icon}" Width="100" Height="70" />
|
x:Name="TitleTextBox"
|
||||||
</Viewbox>
|
Text="{Binding Title, Mode=TwoWay}"
|
||||||
<TextBox
|
Background="Transparent"
|
||||||
x:Uid="EntryTitle"
|
IsHitTestVisible="{Binding IsEditMode}"
|
||||||
x:Name="TitleTextBox"
|
FontSize="20"
|
||||||
Text="{Binding Title, Mode=TwoWay}"
|
FontWeight="Light"
|
||||||
Background="Transparent"
|
TextWrapping="NoWrap"
|
||||||
IsHitTestVisible="{Binding IsEditMode}"
|
VerticalAlignment="Center">
|
||||||
FontSize="20"
|
<interactivity:Interaction.Behaviors>
|
||||||
FontWeight="Light"
|
<core:DataTriggerBehavior Binding="{Binding IsEditMode}" Value="True">
|
||||||
TextWrapping="NoWrap"
|
<actions:SetupFocusAction TargetObject="{Binding ElementName=TitleTextBox}" />
|
||||||
MinWidth="360"
|
<core:ChangePropertyAction TargetObject="{Binding ElementName=TitleTextBox}" PropertyName="BorderThickness" Value="2" />
|
||||||
VerticalAlignment="Center">
|
</core:DataTriggerBehavior>
|
||||||
<interactivity:Interaction.Behaviors>
|
<core:DataTriggerBehavior Binding="{Binding IsEditMode}" Value="False">
|
||||||
<core:DataTriggerBehavior Binding="{Binding IsEditMode}" Value="True">
|
<core:ChangePropertyAction TargetObject="{Binding ElementName=TitleTextBox}" PropertyName="BorderThickness" Value="0" />
|
||||||
<actions:SetupFocusAction TargetObject="{Binding ElementName=TitleTextBox}" />
|
</core:DataTriggerBehavior>
|
||||||
<core:ChangePropertyAction TargetObject="{Binding ElementName=TitleTextBox}" PropertyName="BorderThickness" Value="2" />
|
</interactivity:Interaction.Behaviors>
|
||||||
</core:DataTriggerBehavior>
|
</TextBox>
|
||||||
<core:DataTriggerBehavior Binding="{Binding IsEditMode}" Value="False">
|
|
||||||
<core:ChangePropertyAction TargetObject="{Binding ElementName=TitleTextBox}" PropertyName="BorderThickness" Value="0" />
|
|
||||||
</core:DataTriggerBehavior>
|
|
||||||
</interactivity:Interaction.Behaviors>
|
|
||||||
</TextBox>
|
|
||||||
</StackPanel>
|
|
||||||
<userControls:TopMenuUserControl
|
<userControls:TopMenuUserControl
|
||||||
x:Name="TopMenu" Grid.Column="2"
|
x:Name="TopMenu" Grid.Column="4"
|
||||||
IsEditButtonChecked="{Binding IsEditMode, Mode=TwoWay}"
|
IsEditButtonChecked="{Binding IsEditMode, Mode=TwoWay}"
|
||||||
MoveButtonVisibility="{Binding IsCurrentEntry, Converter={StaticResource BooleanToVisibilityConverter}}"
|
MoveButtonVisibility="{Binding IsCurrentEntry, Converter={StaticResource BooleanToVisibilityConverter}}"
|
||||||
RestoreButtonVisibility="{Binding IsCurrentEntry, Converter={StaticResource InverseBooleanToVisibilityConverter}}"
|
RestoreButtonVisibility="{Binding IsCurrentEntry, Converter={StaticResource InverseBooleanToVisibilityConverter}}"
|
||||||
@@ -526,29 +630,5 @@
|
|||||||
</interactivity:Interaction.Behaviors>
|
</interactivity:Interaction.Behaviors>
|
||||||
</userControls:TopMenuUserControl>
|
</userControls:TopMenuUserControl>
|
||||||
</Grid>
|
</Grid>
|
||||||
<VisualStateManager.VisualStateGroups>
|
|
||||||
<VisualStateGroup>
|
|
||||||
<VisualState x:Name="Small">
|
|
||||||
<Storyboard>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ExpirationDatePanel" Storyboard.TargetProperty="Orientation">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="Vertical"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="EditDesign" Storyboard.TargetProperty="Orientation">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="Vertical"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
</Storyboard>
|
|
||||||
</VisualState>
|
|
||||||
<VisualState x:Name="Large">
|
|
||||||
<Storyboard>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ExpirationDatePanel" Storyboard.TargetProperty="Orientation">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="Horizontal"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="EditDesign" Storyboard.TargetProperty="Orientation">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="Horizontal"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
</Storyboard>
|
|
||||||
</VisualState>
|
|
||||||
</VisualStateGroup>
|
|
||||||
</VisualStateManager.VisualStateGroups>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</Page>
|
</Page>
|
@@ -48,6 +48,7 @@
|
|||||||
x:Name="HamburgerMenu"
|
x:Name="HamburgerMenu"
|
||||||
x:Uid="GroupsLeftListView"
|
x:Uid="GroupsLeftListView"
|
||||||
ItemsSource="{Binding Groups}"
|
ItemsSource="{Binding Groups}"
|
||||||
|
CanDragItems="{Binding IsEditMode}"
|
||||||
SelectionChanged="groups_SelectionChanged"
|
SelectionChanged="groups_SelectionChanged"
|
||||||
ActionButtonCommand="{Binding CreateGroupCommand}"
|
ActionButtonCommand="{Binding CreateGroupCommand}"
|
||||||
IsButtonVisible="Visible" />
|
IsButtonVisible="Visible" />
|
||||||
@@ -62,7 +63,6 @@
|
|||||||
<RowDefinition Height="*" />
|
<RowDefinition Height="*" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<TextBlock Grid.Column="0" Grid.Row="0" x:Uid="ReorderEntriesLabel" Margin="10,10,0,0" Visibility="{Binding IsEditMode, Converter={StaticResource BooleanToVisibilityConverter}}" Style="{StaticResource BodyTextBlockStyle}" />
|
<TextBlock Grid.Column="0" Grid.Row="0" x:Uid="ReorderEntriesLabel" Margin="10,10,0,0" Visibility="{Binding IsEditMode, Converter={StaticResource BooleanToVisibilityConverter}}" Style="{StaticResource BodyTextBlockStyle}" />
|
||||||
<!--<TextBlock Grid.Column="1" Grid.Row="0" x:Uid="EntrySymbol" Margin="40,20,0,0" Visibility="{Binding IsEditMode, Converter={StaticResource BooleanToVisibilityConverter}}" Style="{StaticResource BodyTextBlockStyle}" />-->
|
|
||||||
<HyperlinkButton Grid.Column="2" Grid.Row="0" VerticalAlignment="Top" Command="{Binding CreateEntryCommand}" HorizontalAlignment="Right">
|
<HyperlinkButton Grid.Column="2" Grid.Row="0" VerticalAlignment="Top" Command="{Binding CreateEntryCommand}" HorizontalAlignment="Right">
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<SymbolIcon Symbol="Add">
|
<SymbolIcon Symbol="Add">
|
||||||
@@ -83,17 +83,15 @@
|
|||||||
AutomationProperties.AutomationId="ItemGridView"
|
AutomationProperties.AutomationId="ItemGridView"
|
||||||
AutomationProperties.Name="Entries"
|
AutomationProperties.Name="Entries"
|
||||||
TabIndex="1"
|
TabIndex="1"
|
||||||
Margin="10,0,0,0"
|
|
||||||
SelectionChanged="entries_SelectionChanged"
|
SelectionChanged="entries_SelectionChanged"
|
||||||
IsSynchronizedWithCurrentItem="False"
|
IsSynchronizedWithCurrentItem="False"
|
||||||
BorderBrush="{StaticResource ListViewItemSelectedBackgroundThemeBrush}"
|
BorderBrush="{StaticResource ListViewItemSelectedBackgroundThemeBrush}"
|
||||||
AllowDrop="True"
|
AllowDrop="True"
|
||||||
CanReorderItems="True"
|
CanReorderItems="{Binding IsEditMode}"
|
||||||
CanDragItems="True"
|
CanDragItems="{Binding IsEditMode}">
|
||||||
DragItemsStarting="GridView_DragItemsStarting">
|
|
||||||
<interactivity:Interaction.Behaviors>
|
<interactivity:Interaction.Behaviors>
|
||||||
<core:DataTriggerBehavior Binding="{Binding IsEditMode}" Value="False">
|
<core:DataTriggerBehavior Binding="{Binding IsEditMode}" Value="False">
|
||||||
<actions:SetupFocusAction TargetObject="{Binding ElementName=GridView}" />
|
<actions:SetupFocusAction TargetObject="{Binding}" />
|
||||||
</core:DataTriggerBehavior>
|
</core:DataTriggerBehavior>
|
||||||
</interactivity:Interaction.Behaviors>
|
</interactivity:Interaction.Behaviors>
|
||||||
<GridView.ItemTemplate>
|
<GridView.ItemTemplate>
|
||||||
@@ -135,7 +133,7 @@
|
|||||||
</core:EventTriggerBehavior>
|
</core:EventTriggerBehavior>
|
||||||
</interactivity:Interaction.Behaviors>
|
</interactivity:Interaction.Behaviors>
|
||||||
</MenuFlyoutItem>
|
</MenuFlyoutItem>
|
||||||
<MenuFlyoutItem x:Uid="EntryItemCopyUrl" IsEnabled="{Binding HasUrl}">
|
<MenuFlyoutItem x:Uid="EntryItemCopyUrl" IsEnabled="{Binding IsValidUrl}">
|
||||||
<interactivity:Interaction.Behaviors>
|
<interactivity:Interaction.Behaviors>
|
||||||
<core:EventTriggerBehavior EventName="Click">
|
<core:EventTriggerBehavior EventName="Click">
|
||||||
<actions:NavigateToUrlAction Url="{Binding Url}" />
|
<actions:NavigateToUrlAction Url="{Binding Url}" />
|
||||||
@@ -183,6 +181,8 @@
|
|||||||
<Grid Grid.Row="0" Background="{ThemeResource AppBarBackgroundThemeBrush}">
|
<Grid Grid.Row="0" Background="{ThemeResource AppBarBackgroundThemeBrush}">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="{StaticResource MenuWidthGridLength}"/>
|
<ColumnDefinition Width="{StaticResource MenuWidthGridLength}"/>
|
||||||
|
<ColumnDefinition Width="{StaticResource MenuWidthGridLength}"/>
|
||||||
|
<ColumnDefinition Width="Auto"/>
|
||||||
<ColumnDefinition Width="*"/>
|
<ColumnDefinition Width="*"/>
|
||||||
<ColumnDefinition Width="Auto"/>
|
<ColumnDefinition Width="Auto"/>
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
@@ -196,24 +196,23 @@
|
|||||||
Style="{StaticResource NoBorderButtonStyle}">
|
Style="{StaticResource NoBorderButtonStyle}">
|
||||||
<SymbolIcon Symbol="Back" />
|
<SymbolIcon Symbol="Back" />
|
||||||
</Button>
|
</Button>
|
||||||
<StackPanel Grid.Column="1" Orientation="Horizontal">
|
<Button Grid.Column="1"
|
||||||
<Button
|
Height="{StaticResource MenuHeight}"
|
||||||
Height="{StaticResource MenuHeight}"
|
Width="{StaticResource MenuWidth}"
|
||||||
Width="{StaticResource MenuWidth}"
|
Command="{Binding GoToParentCommand}"
|
||||||
Command="{Binding GoToParentCommand}"
|
Style="{StaticResource NoBorderButtonStyle}">
|
||||||
Style="{StaticResource NoBorderButtonStyle}">
|
<SymbolIcon Symbol="Up" />
|
||||||
<SymbolIcon Symbol="Up" />
|
<ToolTipService.ToolTip>
|
||||||
<ToolTipService.ToolTip>
|
<ToolTip Content="{Binding ParentGroupName}" />
|
||||||
<ToolTip Content="{Binding ParentGroupName}" />
|
</ToolTipService.ToolTip>
|
||||||
</ToolTipService.ToolTip>
|
</Button>
|
||||||
</Button>
|
<Viewbox Grid.Column="2" MaxHeight="200" Visibility="{Binding IsEditMode, Converter={StaticResource BooleanToVisibilityConverter}}">
|
||||||
<Viewbox MaxHeight="200" Visibility="{Binding IsEditMode, Converter={StaticResource BooleanToVisibilityConverter}}">
|
<userControls:SymbolPickerUserControl Width="100" Height="70" SelectedSymbol="{Binding Icon, Mode=TwoWay}" />
|
||||||
<userControls:SymbolPickerUserControl Width="100" Height="70" SelectedSymbol="{Binding Icon, Mode=TwoWay}" />
|
</Viewbox>
|
||||||
</Viewbox>
|
<Viewbox Grid.Column="2" MaxHeight="200" Visibility="{Binding IsEditMode, Converter={StaticResource InverseBooleanToVisibilityConverter}}">
|
||||||
<Viewbox MaxHeight="200" Visibility="{Binding IsEditMode, Converter={StaticResource InverseBooleanToVisibilityConverter}}">
|
<SymbolIcon Symbol="{Binding Icon}" Width="100" Height="70" />
|
||||||
<SymbolIcon Symbol="{Binding Icon}" Width="100" Height="70" />
|
</Viewbox>
|
||||||
</Viewbox>
|
<TextBox Grid.Column="3"
|
||||||
<TextBox
|
|
||||||
x:Uid="GroupTitle"
|
x:Uid="GroupTitle"
|
||||||
x:Name="TitleTextBox"
|
x:Name="TitleTextBox"
|
||||||
Text="{Binding Title, Mode=TwoWay}"
|
Text="{Binding Title, Mode=TwoWay}"
|
||||||
@@ -222,20 +221,18 @@
|
|||||||
FontSize="20"
|
FontSize="20"
|
||||||
FontWeight="Light"
|
FontWeight="Light"
|
||||||
TextWrapping="NoWrap"
|
TextWrapping="NoWrap"
|
||||||
MinWidth="360"
|
|
||||||
VerticalAlignment="Center">
|
VerticalAlignment="Center">
|
||||||
<interactivity:Interaction.Behaviors>
|
<interactivity:Interaction.Behaviors>
|
||||||
<core:DataTriggerBehavior Binding="{Binding IsEditMode}" Value="True">
|
<core:DataTriggerBehavior Binding="{Binding IsEditMode}" Value="True">
|
||||||
<actions:SetupFocusAction TargetObject="{Binding ElementName=TitleTextBox}" />
|
<actions:SetupFocusAction TargetObject="{Binding ElementName=TitleTextBox}" />
|
||||||
<core:ChangePropertyAction TargetObject="{Binding ElementName=TitleTextBox}" PropertyName="BorderThickness" Value="2" />
|
<core:ChangePropertyAction TargetObject="{Binding ElementName=TitleTextBox}" PropertyName="BorderThickness" Value="2" />
|
||||||
</core:DataTriggerBehavior>
|
</core:DataTriggerBehavior>
|
||||||
<core:DataTriggerBehavior Binding="{Binding IsEditMode}" Value="False">
|
<core:DataTriggerBehavior Binding="{Binding IsEditMode}" Value="False">
|
||||||
<core:ChangePropertyAction TargetObject="{Binding ElementName=TitleTextBox}" PropertyName="BorderThickness" Value="0" />
|
<core:ChangePropertyAction TargetObject="{Binding ElementName=TitleTextBox}" PropertyName="BorderThickness" Value="0" />
|
||||||
</core:DataTriggerBehavior>
|
</core:DataTriggerBehavior>
|
||||||
</interactivity:Interaction.Behaviors>
|
</interactivity:Interaction.Behaviors>
|
||||||
</TextBox>
|
</TextBox>
|
||||||
</StackPanel>
|
<userControls:TopMenuUserControl x:Name="TopMenu" Grid.Column="4"
|
||||||
<userControls:TopMenuUserControl x:Name="TopMenu" Grid.Column="2"
|
|
||||||
SortButtonVisibility="{Binding IsEditMode, Converter={StaticResource BooleanToVisibilityConverter}}"
|
SortButtonVisibility="{Binding IsEditMode, Converter={StaticResource BooleanToVisibilityConverter}}"
|
||||||
IsEditButtonChecked="{Binding IsEditMode, Mode=TwoWay}"
|
IsEditButtonChecked="{Binding IsEditMode, Mode=TwoWay}"
|
||||||
SaveCommand="{Binding SaveCommand}"
|
SaveCommand="{Binding SaveCommand}"
|
||||||
@@ -252,22 +249,6 @@
|
|||||||
|
|
||||||
</Grid>
|
</Grid>
|
||||||
<VisualStateManager.VisualStateGroups>
|
<VisualStateManager.VisualStateGroups>
|
||||||
<VisualStateGroup x:Name="DragDropGroup">
|
|
||||||
<VisualState x:Name="Dragging">
|
|
||||||
<Storyboard>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="GridView" Storyboard.TargetProperty="BorderThickness">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="2"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
</Storyboard>
|
|
||||||
</VisualState>
|
|
||||||
<VisualState x:Name="Dropped">
|
|
||||||
<Storyboard>
|
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="GridView" Storyboard.TargetProperty="BorderThickness">
|
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="0"/>
|
|
||||||
</ObjectAnimationUsingKeyFrames>
|
|
||||||
</Storyboard>
|
|
||||||
</VisualState>
|
|
||||||
</VisualStateGroup>
|
|
||||||
<VisualStateGroup x:Name="PageLayout">
|
<VisualStateGroup x:Name="PageLayout">
|
||||||
<VisualState x:Name="Small">
|
<VisualState x:Name="Small">
|
||||||
<Storyboard>
|
<Storyboard>
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
using Windows.ApplicationModel.DataTransfer;
|
using Windows.UI.Xaml;
|
||||||
using Windows.UI.Xaml;
|
|
||||||
using Windows.UI.Xaml.Controls;
|
using Windows.UI.Xaml.Controls;
|
||||||
using Windows.UI.Xaml.Navigation;
|
using Windows.UI.Xaml.Navigation;
|
||||||
using ModernKeePass.Application.Entry.Models;
|
using ModernKeePass.Application.Entry.Models;
|
||||||
@@ -75,12 +74,6 @@ namespace ModernKeePass.Views
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GridView_DragItemsStarting(object sender, DragItemsStartingEventArgs e)
|
|
||||||
{
|
|
||||||
e.Cancel = !Model.IsEditMode;
|
|
||||||
e.Data.RequestedOperation = DataPackageOperation.Move;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void GroupDetailPage_OnSizeChanged(object sender, SizeChangedEventArgs e)
|
private void GroupDetailPage_OnSizeChanged(object sender, SizeChangedEventArgs e)
|
||||||
{
|
{
|
||||||
if (e.NewSize.Width <= 640)
|
if (e.NewSize.Width <= 640)
|
||||||
|
@@ -53,7 +53,7 @@
|
|||||||
</Button>
|
</Button>
|
||||||
<TextBlock x:Name="TitleTextBox" Text="{Binding Name}" Grid.Column="1" FontSize="24" HorizontalAlignment="Center" VerticalAlignment="Center" />
|
<TextBlock x:Name="TitleTextBox" Text="{Binding Name}" Grid.Column="1" FontSize="24" HorizontalAlignment="Center" VerticalAlignment="Center" />
|
||||||
</Grid>
|
</Grid>
|
||||||
<controls:ListViewWithDisable
|
<controls:DisableListView
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
x:Name="MenuListView"
|
x:Name="MenuListView"
|
||||||
@@ -62,15 +62,15 @@
|
|||||||
ItemsSource="{Binding Source={StaticResource MenuItemsSource}}"
|
ItemsSource="{Binding Source={StaticResource MenuItemsSource}}"
|
||||||
SelectedItem="{Binding SelectedItem, Mode=TwoWay}"
|
SelectedItem="{Binding SelectedItem, Mode=TwoWay}"
|
||||||
ItemContainerStyle="{StaticResource ListViewLeftIndicatorItemExpanded}">
|
ItemContainerStyle="{StaticResource ListViewLeftIndicatorItemExpanded}">
|
||||||
<controls:ListViewWithDisable.ItemTemplate>
|
<controls:DisableListView.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<SymbolIcon Symbol="{Binding SymbolIcon}" />
|
<SymbolIcon Symbol="{Binding SymbolIcon}" />
|
||||||
<TextBlock Text="{Binding Title}" Margin="10,5,0,0" />
|
<TextBlock Text="{Binding Title}" Margin="10,5,0,0" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</controls:ListViewWithDisable.ItemTemplate>
|
</controls:DisableListView.ItemTemplate>
|
||||||
<controls:ListViewWithDisable.GroupStyle>
|
<controls:DisableListView.GroupStyle>
|
||||||
<GroupStyle HidesIfEmpty="True">
|
<GroupStyle HidesIfEmpty="True">
|
||||||
<GroupStyle.HeaderTemplate>
|
<GroupStyle.HeaderTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
@@ -80,8 +80,8 @@
|
|||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</GroupStyle.HeaderTemplate>
|
</GroupStyle.HeaderTemplate>
|
||||||
</GroupStyle>
|
</GroupStyle>
|
||||||
</controls:ListViewWithDisable.GroupStyle>
|
</controls:DisableListView.GroupStyle>
|
||||||
</controls:ListViewWithDisable>
|
</controls:DisableListView>
|
||||||
<TextBlock x:Name="PageTitleTextBlock" Grid.Column="1" Grid.Row="0" FontSize="24" VerticalAlignment="Center" Margin="10,0,0,0" >
|
<TextBlock x:Name="PageTitleTextBlock" Grid.Column="1" Grid.Row="0" FontSize="24" VerticalAlignment="Center" Margin="10,0,0,0" >
|
||||||
<Run Text="{Binding SelectedItem}" />
|
<Run Text="{Binding SelectedItem}" />
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
|
@@ -3,14 +3,11 @@
|
|||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:converters="using:ModernKeePass.Converters"
|
|
||||||
xmlns:userControls="using:ModernKeePass.Views.UserControls"
|
xmlns:userControls="using:ModernKeePass.Views.UserControls"
|
||||||
|
xmlns:controls="using:ModernKeePass.Controls"
|
||||||
x:Class="ModernKeePass.Views.RecentDatabasesPage"
|
x:Class="ModernKeePass.Views.RecentDatabasesPage"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
DataContext="{Binding Source={StaticResource Locator}, Path=Recent}">
|
DataContext="{Binding Source={StaticResource Locator}, Path=Recent}">
|
||||||
<Page.Resources>
|
|
||||||
<converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
|
|
||||||
</Page.Resources>
|
|
||||||
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
|
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="40" />
|
<RowDefinition Height="40" />
|
||||||
@@ -22,11 +19,11 @@
|
|||||||
<TextBlock x:Uid="RecentClear" VerticalAlignment="Center" Margin="10,0,0,0" />
|
<TextBlock x:Uid="RecentClear" VerticalAlignment="Center" Margin="10,0,0,0" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</HyperlinkButton>
|
</HyperlinkButton>
|
||||||
<ListView Grid.Row="1"
|
<controls:SelectableTemplateListView Grid.Row="1"
|
||||||
|
SelectedIndex="{Binding SelectedIndex}"
|
||||||
ItemsSource="{Binding RecentItems}"
|
ItemsSource="{Binding RecentItems}"
|
||||||
SelectedItem="{Binding SelectedItem, Mode=TwoWay}"
|
|
||||||
ItemContainerStyle="{StaticResource ListViewLeftIndicatorItemExpanded}">
|
ItemContainerStyle="{StaticResource ListViewLeftIndicatorItemExpanded}">
|
||||||
<ListView.ItemTemplate>
|
<controls:SelectableTemplateListView.SelectedItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<Grid Margin="10,0,10,0">
|
<Grid Margin="10,0,10,0">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
@@ -35,17 +32,24 @@
|
|||||||
<RowDefinition />
|
<RowDefinition />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="*"/>
|
<ColumnDefinition Width="*" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<TextBlock Grid.Row="0" Text="{Binding Name}" Padding="5,0,0,0" />
|
<TextBlock Grid.Row="0" Text="{Binding Name}" Padding="5,0,0,0" />
|
||||||
<TextBlock Grid.Row="1" Text="{Binding Path}" Padding="5,0,0,0" FontSize="10" />
|
<TextBlock Grid.Row="1" Text="{Binding Path}" Padding="5,0,0,0" FontSize="10" />
|
||||||
<userControls:OpenDatabaseUserControl Grid.Row="2"
|
<userControls:OpenDatabaseUserControl Grid.Row="2"
|
||||||
HorizontalAlignment="Stretch" MinWidth="400" Margin="0,10,0,0"
|
HorizontalAlignment="Stretch" MinWidth="400" Margin="0,10,0,0"
|
||||||
Visibility="{Binding IsSelected, Converter={StaticResource BooleanToVisibilityConverter}}"
|
|
||||||
DatabaseFilePath="{Binding Token}" />
|
DatabaseFilePath="{Binding Token}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ListView.ItemTemplate>
|
</controls:SelectableTemplateListView.SelectedItemTemplate>
|
||||||
</ListView>
|
<controls:SelectableTemplateListView.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<StackPanel Margin="10,0,10,0" Orientation="Vertical">
|
||||||
|
<TextBlock Text="{Binding Name}" Padding="5,0,0,0" />
|
||||||
|
<TextBlock Text="{Binding Path}" Padding="5,0,0,0" FontSize="10" />
|
||||||
|
</StackPanel>
|
||||||
|
</DataTemplate>
|
||||||
|
</controls:SelectableTemplateListView.ItemTemplate>
|
||||||
|
</controls:SelectableTemplateListView>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Page>
|
</Page>
|
@@ -48,7 +48,7 @@
|
|||||||
</Button>
|
</Button>
|
||||||
<TextBlock x:Name="TitleTextBox" x:Uid="SettingsTitle" Grid.Column="1" FontSize="24" HorizontalAlignment="Center" VerticalAlignment="Center" />
|
<TextBlock x:Name="TitleTextBox" x:Uid="SettingsTitle" Grid.Column="1" FontSize="24" HorizontalAlignment="Center" VerticalAlignment="Center" />
|
||||||
</Grid>
|
</Grid>
|
||||||
<controls:ListViewWithDisable
|
<controls:DisableListView
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
x:Name="MenuListView"
|
x:Name="MenuListView"
|
||||||
@@ -58,15 +58,15 @@
|
|||||||
SelectedItem="{Binding SelectedItem, Mode=TwoWay}"
|
SelectedItem="{Binding SelectedItem, Mode=TwoWay}"
|
||||||
IsSynchronizedWithCurrentItem="False"
|
IsSynchronizedWithCurrentItem="False"
|
||||||
ItemContainerStyle="{StaticResource ListViewLeftIndicatorItemExpanded}">
|
ItemContainerStyle="{StaticResource ListViewLeftIndicatorItemExpanded}">
|
||||||
<controls:ListViewWithDisable.ItemTemplate>
|
<controls:DisableListView.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<SymbolIcon Symbol="{Binding SymbolIcon}" />
|
<SymbolIcon Symbol="{Binding SymbolIcon}" />
|
||||||
<TextBlock Text="{Binding Title}" Margin="10,5,0,0" />
|
<TextBlock Text="{Binding Title}" Margin="10,5,0,0" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</controls:ListViewWithDisable.ItemTemplate>
|
</controls:DisableListView.ItemTemplate>
|
||||||
<controls:ListViewWithDisable.GroupStyle>
|
<controls:DisableListView.GroupStyle>
|
||||||
<GroupStyle HidesIfEmpty="True">
|
<GroupStyle HidesIfEmpty="True">
|
||||||
<GroupStyle.HeaderTemplate>
|
<GroupStyle.HeaderTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
@@ -79,8 +79,8 @@
|
|||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</GroupStyle.HeaderTemplate>
|
</GroupStyle.HeaderTemplate>
|
||||||
</GroupStyle>
|
</GroupStyle>
|
||||||
</controls:ListViewWithDisable.GroupStyle>
|
</controls:DisableListView.GroupStyle>
|
||||||
</controls:ListViewWithDisable>
|
</controls:DisableListView>
|
||||||
<TextBlock x:Name="PageTitleTextBlock" Grid.Column="1" Grid.Row="0" FontSize="24" VerticalAlignment="Center" Margin="10,0,0,0" >
|
<TextBlock x:Name="PageTitleTextBlock" Grid.Column="1" Grid.Row="0" FontSize="24" VerticalAlignment="Center" Margin="10,0,0,0" >
|
||||||
<Run Text="{Binding SelectedItem}" />
|
<Run Text="{Binding SelectedItem}" />
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
|
@@ -0,0 +1,20 @@
|
|||||||
|
<Page
|
||||||
|
x:Class="ModernKeePass.Views.SettingsCredentialsPage"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:userControls="using:ModernKeePass.Views.UserControls"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
DataContext="{Binding Source={StaticResource Locator}, Path=Credentials}">
|
||||||
|
|
||||||
|
<StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||||
|
<TextBlock x:Uid="SettingsSecurityTitle" Style="{StaticResource TextBlockSettingsHeaderStyle}" Margin="5,0,0,0" />
|
||||||
|
<TextBlock TextWrapping="WrapWholeWords" Margin="5,0,0,0">
|
||||||
|
<Run x:Uid="SettingsSecurityDesc1" />
|
||||||
|
<Run x:Uid="SettingsSecurityDesc2" FontWeight="SemiBold" />
|
||||||
|
<Run x:Uid="SettingsSecurityDesc3" />
|
||||||
|
</TextBlock>
|
||||||
|
<userControls:SetCredentialsUserControl Margin="0,20,0,0" x:Uid="SettingsSecurityUpdateButton"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Page>
|
@@ -5,9 +5,9 @@ namespace ModernKeePass.Views
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// An empty page that can be used on its own or navigated to within a Frame.
|
/// An empty page that can be used on its own or navigated to within a Frame.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed partial class SettingsDatabasePage
|
public sealed partial class SettingsCredentialsPage
|
||||||
{
|
{
|
||||||
public SettingsDatabasePage()
|
public SettingsCredentialsPage()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
@@ -1,15 +1,17 @@
|
|||||||
<Page
|
<Page
|
||||||
x:Class="ModernKeePass.Views.SettingsSavePage"
|
x:Class="ModernKeePass.Views.SettingsGeneralPage"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
DataContext="{Binding Source={StaticResource Locator}, Path=SettingsSave}">
|
DataContext="{Binding Source={StaticResource Locator}, Path=General}">
|
||||||
|
|
||||||
<StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
<StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||||
<TextBlock x:Uid="SettingsSaveDatabaseSuspendTitle" Style="{StaticResource TextBlockSettingsHeaderStyle}" Margin="5,0,0,10"/>
|
<TextBlock x:Uid="SettingsSaveDatabaseSuspendTitle" Style="{StaticResource TextBlockSettingsHeaderStyle}" Margin="5,0,0,10"/>
|
||||||
<TextBlock x:Uid="SettingsSaveDatabaseSuspendDesc" TextWrapping="WrapWholeWords" Margin="5,0,0,10"/>
|
<TextBlock x:Uid="SettingsSaveDatabaseSuspendDesc" TextWrapping="WrapWholeWords" Margin="5,0,0,10"/>
|
||||||
<ToggleSwitch x:Uid="SettingsSaveDatabaseSuspend" IsOn="{Binding IsSaveSuspend, Mode=TwoWay}" />
|
<ToggleSwitch x:Uid="SettingsSaveDatabaseSuspend" IsOn="{Binding IsSaveSuspend, Mode=TwoWay}" />
|
||||||
|
<TextBlock x:Uid="SettingsCopyExpiration" Style="{StaticResource TextBlockSettingsHeaderStyle}" Margin="5,20,0,10" />
|
||||||
|
<TextBox Text="{Binding CopyExpiration, Mode=TwoWay}" InputScope="Number" KeyDown="UIElement_OnKeyDown" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Page>
|
</Page>
|
@@ -0,0 +1,26 @@
|
|||||||
|
// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238
|
||||||
|
|
||||||
|
using Windows.System;
|
||||||
|
using Windows.UI.Xaml.Input;
|
||||||
|
|
||||||
|
namespace ModernKeePass.Views
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// An empty page that can be used on its own or navigated to within a Frame.
|
||||||
|
/// </summary>
|
||||||
|
public sealed partial class SettingsGeneralPage
|
||||||
|
{
|
||||||
|
public SettingsGeneralPage()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UIElement_OnKeyDown(object sender, KeyRoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if ((e.Key < VirtualKey.NumberPad0 || e.Key > VirtualKey.NumberPad9) & (e.Key < VirtualKey.Number0 || e.Key > VirtualKey.Number9))
|
||||||
|
{
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,16 @@
|
|||||||
|
<Page
|
||||||
|
x:Class="ModernKeePass.Views.SettingsPageFrames.SettingsHistoryPage"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
DataContext="{Binding Source={StaticResource Locator}, Path=History}">
|
||||||
|
|
||||||
|
<StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||||
|
<TextBlock x:Uid="SettingsHistoryMaxCount" Style="{StaticResource TextBlockSettingsHeaderStyle}" Margin="5,20,0,10" />
|
||||||
|
<TextBox Text="{Binding MaxCount, Mode=TwoWay}" InputScope="Number" KeyDown="UIElement_OnKeyDown" />
|
||||||
|
<TextBlock x:Uid="SettingsHistoryMaxSize" Style="{StaticResource TextBlockSettingsHeaderStyle}" Margin="5,20,0,10" />
|
||||||
|
<TextBox Text="{Binding MaxSize, Mode=TwoWay}" InputScope="Number" KeyDown="UIElement_OnKeyDown" />
|
||||||
|
</StackPanel>
|
||||||
|
</Page>
|
@@ -0,0 +1,26 @@
|
|||||||
|
using Windows.System;
|
||||||
|
using Windows.UI.Xaml.Input;
|
||||||
|
|
||||||
|
// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238
|
||||||
|
|
||||||
|
namespace ModernKeePass.Views.SettingsPageFrames
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// An empty page that can be used on its own or navigated to within a Frame.
|
||||||
|
/// </summary>
|
||||||
|
public sealed partial class SettingsHistoryPage
|
||||||
|
{
|
||||||
|
public SettingsHistoryPage()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UIElement_OnKeyDown(object sender, KeyRoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if ((e.Key < VirtualKey.NumberPad0 || e.Key > VirtualKey.NumberPad9) & (e.Key < VirtualKey.Number0 || e.Key > VirtualKey.Number9))
|
||||||
|
{
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -1,12 +1,12 @@
|
|||||||
<Page
|
<Page
|
||||||
x:Class="ModernKeePass.Views.SettingsDatabasePage"
|
x:Class="ModernKeePass.Views.SettingsPageFrames.SettingsRecycleBinPage"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:converters="using:ModernKeePass.Converters"
|
xmlns:converters="using:ModernKeePass.Converters"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
DataContext="{Binding Source={StaticResource Locator}, Path=SettingsDatabase}">
|
DataContext="{Binding Source={StaticResource Locator}, Path=RecycleBin}">
|
||||||
<Page.Resources>
|
<Page.Resources>
|
||||||
<converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
|
<converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
|
||||||
<converters:NullToBooleanConverter x:Key="NullToBooleanConverter"/>
|
<converters:NullToBooleanConverter x:Key="NullToBooleanConverter"/>
|
||||||
@@ -15,9 +15,6 @@
|
|||||||
<StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
<StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||||
<StackPanel.Resources>
|
<StackPanel.Resources>
|
||||||
<CollectionViewSource x:Name="RecycleBinGroups" Source="{Binding Groups}" />
|
<CollectionViewSource x:Name="RecycleBinGroups" Source="{Binding Groups}" />
|
||||||
<CollectionViewSource x:Name="Ciphers" Source="{Binding Ciphers}" />
|
|
||||||
<CollectionViewSource x:Name="Compressions" Source="{Binding Compressions}" />
|
|
||||||
<CollectionViewSource x:Name="KeyDerivations" Source="{Binding KeyDerivations}" />
|
|
||||||
</StackPanel.Resources>
|
</StackPanel.Resources>
|
||||||
<ToggleSwitch x:Uid="SettingsDatabaseRecycleBin" IsOn="{Binding HasRecycleBin, Mode=TwoWay}" />
|
<ToggleSwitch x:Uid="SettingsDatabaseRecycleBin" IsOn="{Binding HasRecycleBin, Mode=TwoWay}" />
|
||||||
<StackPanel Visibility="{Binding HasRecycleBin, Converter={StaticResource BooleanToVisibilityConverter}}">
|
<StackPanel Visibility="{Binding HasRecycleBin, Converter={StaticResource BooleanToVisibilityConverter}}">
|
||||||
@@ -25,11 +22,5 @@
|
|||||||
<RadioButton x:Name="RadioButton" x:Uid="SettingsDatabaseRecycleBinExisting" GroupName="Recycle" IsChecked="{Binding SelectedRecycleBin, Converter={StaticResource NullToBooleanConverter}}" />
|
<RadioButton x:Name="RadioButton" x:Uid="SettingsDatabaseRecycleBinExisting" GroupName="Recycle" IsChecked="{Binding SelectedRecycleBin, Converter={StaticResource NullToBooleanConverter}}" />
|
||||||
<ComboBox ItemsSource="{Binding Source={StaticResource RecycleBinGroups}}" SelectedItem="{Binding SelectedRecycleBin, Mode=TwoWay}" IsEnabled="{Binding IsChecked, ElementName=RadioButton}" />
|
<ComboBox ItemsSource="{Binding Source={StaticResource RecycleBinGroups}}" SelectedItem="{Binding SelectedRecycleBin, Mode=TwoWay}" IsEnabled="{Binding IsChecked, ElementName=RadioButton}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<TextBlock x:Uid="SettingsDatabaseEncryption" Style="{StaticResource TextBlockSettingsHeaderStyle}" Margin="5,20,0,10" />
|
|
||||||
<ComboBox ItemsSource="{Binding Source={StaticResource Ciphers}}" DisplayMemberPath="Name" SelectedItem="{Binding SelectedCipher, Mode=TwoWay}" />
|
|
||||||
<TextBlock x:Uid="SettingsDatabaseCompression" Style="{StaticResource TextBlockSettingsHeaderStyle}" Margin="5,20,0,10" />
|
|
||||||
<ComboBox ItemsSource="{Binding Source={StaticResource Compressions}}" SelectedItem="{Binding SelectedCompression, Mode=TwoWay}" />
|
|
||||||
<TextBlock x:Uid="SettingsDatabaseKdf" Style="{StaticResource TextBlockSettingsHeaderStyle}" Margin="5,20,0,10" />
|
|
||||||
<ComboBox ItemsSource="{Binding Source={StaticResource KeyDerivations}}" DisplayMemberPath="Name" SelectedItem="{Binding SelectedKeyDerivation, Mode=TwoWay}" />
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Page>
|
</Page>
|
@@ -0,0 +1,30 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices.WindowsRuntime;
|
||||||
|
using Windows.Foundation;
|
||||||
|
using Windows.Foundation.Collections;
|
||||||
|
using Windows.UI.Xaml;
|
||||||
|
using Windows.UI.Xaml.Controls;
|
||||||
|
using Windows.UI.Xaml.Controls.Primitives;
|
||||||
|
using Windows.UI.Xaml.Data;
|
||||||
|
using Windows.UI.Xaml.Input;
|
||||||
|
using Windows.UI.Xaml.Media;
|
||||||
|
using Windows.UI.Xaml.Navigation;
|
||||||
|
|
||||||
|
// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238
|
||||||
|
|
||||||
|
namespace ModernKeePass.Views.SettingsPageFrames
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// An empty page that can be used on its own or navigated to within a Frame.
|
||||||
|
/// </summary>
|
||||||
|
public sealed partial class SettingsRecycleBinPage : Page
|
||||||
|
{
|
||||||
|
public SettingsRecycleBinPage()
|
||||||
|
{
|
||||||
|
this.InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -1,15 +0,0 @@
|
|||||||
// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238
|
|
||||||
|
|
||||||
namespace ModernKeePass.Views
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// An empty page that can be used on its own or navigated to within a Frame.
|
|
||||||
/// </summary>
|
|
||||||
public sealed partial class SettingsSavePage
|
|
||||||
{
|
|
||||||
public SettingsSavePage()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -4,17 +4,20 @@
|
|||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:userControls="using:ModernKeePass.Views.UserControls"
|
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
DataContext="{Binding Source={StaticResource Locator}, Path=SettingsSecurity}">
|
DataContext="{Binding Source={StaticResource Locator}, Path=Security}">
|
||||||
|
|
||||||
<StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
<StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||||
<TextBlock x:Uid="SettingsSecurityTitle" Style="{StaticResource TextBlockSettingsHeaderStyle}" Margin="5,0,0,0" />
|
<StackPanel.Resources>
|
||||||
<TextBlock TextWrapping="WrapWholeWords" Margin="5,0,0,0">
|
<CollectionViewSource x:Name="Ciphers" Source="{Binding Ciphers}" />
|
||||||
<Run x:Uid="SettingsSecurityDesc1" />
|
<CollectionViewSource x:Name="Compressions" Source="{Binding Compressions}" />
|
||||||
<Run x:Uid="SettingsSecurityDesc2" FontWeight="SemiBold" />
|
<CollectionViewSource x:Name="KeyDerivations" Source="{Binding KeyDerivations}" />
|
||||||
<Run x:Uid="SettingsSecurityDesc3" />
|
</StackPanel.Resources>
|
||||||
</TextBlock>
|
<TextBlock x:Uid="SettingsDatabaseEncryption" Style="{StaticResource TextBlockSettingsHeaderStyle}" Margin="5,20,0,10" />
|
||||||
<userControls:SetCredentialsUserControl Margin="0,20,0,0" x:Uid="SettingsSecurityUpdateButton"/>
|
<ComboBox ItemsSource="{Binding Source={StaticResource Ciphers}}" DisplayMemberPath="Name" SelectedItem="{Binding SelectedCipher, Mode=TwoWay}" />
|
||||||
|
<TextBlock x:Uid="SettingsDatabaseCompression" Style="{StaticResource TextBlockSettingsHeaderStyle}" Margin="5,20,0,10" />
|
||||||
|
<ComboBox ItemsSource="{Binding Source={StaticResource Compressions}}" SelectedItem="{Binding SelectedCompression, Mode=TwoWay}" />
|
||||||
|
<TextBlock x:Uid="SettingsDatabaseKdf" Style="{StaticResource TextBlockSettingsHeaderStyle}" Margin="5,20,0,10" />
|
||||||
|
<ComboBox ItemsSource="{Binding Source={StaticResource KeyDerivations}}" DisplayMemberPath="Name" SelectedItem="{Binding SelectedKeyDerivation, Mode=TwoWay}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Page>
|
</Page>
|
||||||
|
@@ -1,46 +0,0 @@
|
|||||||
<UserControl x:Name="UserControl"
|
|
||||||
x:Class="ModernKeePass.Views.UserControls.BreadCrumbUserControl"
|
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
|
||||||
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
|
|
||||||
xmlns:core="using:Microsoft.Xaml.Interactions.Core"
|
|
||||||
xmlns:templateSelectors="using:ModernKeePass.TemplateSelectors"
|
|
||||||
mc:Ignorable="d">
|
|
||||||
<ItemsControl ItemsSource="{Binding ItemsSource, ElementName=UserControl}">
|
|
||||||
<ItemsControl.ItemsPanel>
|
|
||||||
<ItemsPanelTemplate>
|
|
||||||
<VirtualizingStackPanel Orientation="Horizontal" />
|
|
||||||
</ItemsPanelTemplate>
|
|
||||||
</ItemsControl.ItemsPanel>
|
|
||||||
<ItemsControl.Resources>
|
|
||||||
<DataTemplate x:Name="FirstItemTemplate">
|
|
||||||
<HyperlinkButton FontWeight="Light" FontSize="12" Padding="0" Content="{Binding Title}">
|
|
||||||
<interactivity:Interaction.Behaviors>
|
|
||||||
<core:EventTriggerBehavior EventName="Click">
|
|
||||||
<core:NavigateToPageAction Parameter="{Binding Id}" TargetPage="ModernKeePass.Views.GroupDetailPage" />
|
|
||||||
</core:EventTriggerBehavior>
|
|
||||||
</interactivity:Interaction.Behaviors>
|
|
||||||
</HyperlinkButton>
|
|
||||||
</DataTemplate>
|
|
||||||
<DataTemplate x:Name="OtherItemsTemplate">
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<Viewbox MaxHeight="10" Margin="0,2,0,0">
|
|
||||||
<SymbolIcon Symbol="Forward" />
|
|
||||||
</Viewbox>
|
|
||||||
<HyperlinkButton Content="{Binding Title}" FontWeight="Light" FontSize="12" Padding="0">
|
|
||||||
<interactivity:Interaction.Behaviors>
|
|
||||||
<core:EventTriggerBehavior EventName="Click">
|
|
||||||
<core:NavigateToPageAction Parameter="{Binding Id}" TargetPage="ModernKeePass.Views.GroupDetailPage" />
|
|
||||||
</core:EventTriggerBehavior>
|
|
||||||
</interactivity:Interaction.Behaviors>
|
|
||||||
</HyperlinkButton>
|
|
||||||
</StackPanel>
|
|
||||||
</DataTemplate>
|
|
||||||
</ItemsControl.Resources>
|
|
||||||
<ItemsControl.ItemTemplateSelector>
|
|
||||||
<templateSelectors:FirstItemDataTemplateSelector FirstItem="{StaticResource FirstItemTemplate}" OtherItem="{StaticResource OtherItemsTemplate}"/>
|
|
||||||
</ItemsControl.ItemTemplateSelector>
|
|
||||||
</ItemsControl>
|
|
||||||
</UserControl>
|
|
@@ -1,29 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using Windows.UI.Xaml;
|
|
||||||
using ModernKeePass.Application.Common.Interfaces;
|
|
||||||
|
|
||||||
// The User Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234236
|
|
||||||
|
|
||||||
namespace ModernKeePass.Views.UserControls
|
|
||||||
{
|
|
||||||
public sealed partial class BreadCrumbUserControl
|
|
||||||
{
|
|
||||||
public BreadCrumbUserControl()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<IEntityVm> ItemsSource
|
|
||||||
{
|
|
||||||
get { return (IEnumerable<IEntityVm>)GetValue(ItemsSourceProperty); }
|
|
||||||
set { SetValue(ItemsSourceProperty, value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public static readonly DependencyProperty ItemsSourceProperty =
|
|
||||||
DependencyProperty.Register(
|
|
||||||
nameof(ItemsSource),
|
|
||||||
typeof(IEnumerable<IEntityVm>),
|
|
||||||
typeof(BreadCrumbUserControl),
|
|
||||||
new PropertyMetadata(new Stack<IEntityVm>(), (o, args) => { }));
|
|
||||||
}
|
|
||||||
}
|
|
@@ -4,7 +4,6 @@
|
|||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:templateSelectors="using:ModernKeePass.TemplateSelectors"
|
|
||||||
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
|
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
|
||||||
xmlns:core="using:Microsoft.Xaml.Interactions.Core"
|
xmlns:core="using:Microsoft.Xaml.Interactions.Core"
|
||||||
xmlns:converters="using:ModernKeePass.Converters"
|
xmlns:converters="using:ModernKeePass.Converters"
|
||||||
@@ -13,6 +12,7 @@
|
|||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
<UserControl.Resources>
|
<UserControl.Resources>
|
||||||
<converters:IconToSymbolConverter x:Key="IconToSymbolConverter"/>
|
<converters:IconToSymbolConverter x:Key="IconToSymbolConverter"/>
|
||||||
|
<converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
|
||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
<Grid HorizontalAlignment="Left">
|
<Grid HorizontalAlignment="Left">
|
||||||
<VisualStateManager.VisualStateGroups>
|
<VisualStateManager.VisualStateGroups>
|
||||||
@@ -80,6 +80,9 @@
|
|||||||
<ListView
|
<ListView
|
||||||
x:Name="ListView"
|
x:Name="ListView"
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
|
AllowDrop="True"
|
||||||
|
CanReorderItems="{Binding CanDragItems, ElementName=UserControl}"
|
||||||
|
CanDragItems="{Binding CanDragItems, ElementName=UserControl}"
|
||||||
ItemsSource="{Binding ItemsSource, ElementName=UserControl}"
|
ItemsSource="{Binding ItemsSource, ElementName=UserControl}"
|
||||||
SelectionChanged="Selector_OnSelectionChanged"
|
SelectionChanged="Selector_OnSelectionChanged"
|
||||||
SelectedItem="{Binding SelectedItem, ElementName=UserControl, Mode=TwoWay}"
|
SelectedItem="{Binding SelectedItem, ElementName=UserControl, Mode=TwoWay}"
|
||||||
@@ -88,31 +91,18 @@
|
|||||||
IsSynchronizedWithCurrentItem="False"
|
IsSynchronizedWithCurrentItem="False"
|
||||||
Background="{ThemeResource AppBarBackgroundThemeBrush}"
|
Background="{ThemeResource AppBarBackgroundThemeBrush}"
|
||||||
ItemContainerStyle="{StaticResource ListViewLeftIndicatorItemExpanded}">
|
ItemContainerStyle="{StaticResource ListViewLeftIndicatorItemExpanded}">
|
||||||
<ListView.Resources>
|
<ListView.ItemTemplate>
|
||||||
<DataTemplate x:Name="IsSpecial">
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<SymbolIcon Symbol="{Binding Icon, Converter={StaticResource IconToSymbolConverter}, ConverterParameter=48}" Margin="7,15,0,15">
|
|
||||||
<ToolTipService.ToolTip>
|
|
||||||
<ToolTip Content="{Binding Path={Binding DisplayMemberPath, ElementName=UserControl}}" />
|
|
||||||
</ToolTipService.ToolTip>
|
|
||||||
</SymbolIcon>
|
|
||||||
<TextBlock Text="{Binding Path={Binding DisplayMemberPath, ElementName=UserControl}}" x:Name="GroupTextBlock" TextWrapping="NoWrap" VerticalAlignment="Center" Margin="30,0,20,0" FontStyle="Italic" />
|
|
||||||
</StackPanel>
|
|
||||||
</DataTemplate>
|
|
||||||
<DataTemplate x:Name="IsNormal">
|
<DataTemplate x:Name="IsNormal">
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<SymbolIcon Symbol="{Binding Icon, Converter={StaticResource IconToSymbolConverter}, ConverterParameter=48}" Margin="7,15,0,15">
|
<SymbolIcon Symbol="{Binding Icon, Converter={StaticResource IconToSymbolConverter}, ConverterParameter=48}" Margin="7,10,0,15">
|
||||||
<ToolTipService.ToolTip>
|
<ToolTipService.ToolTip>
|
||||||
<ToolTip Content="{Binding Path={Binding DisplayMemberPath, ElementName=UserControl}}" />
|
<ToolTip Content="{Binding Path={Binding DisplayMemberPath, ElementName=UserControl}}" />
|
||||||
</ToolTipService.ToolTip>
|
</ToolTipService.ToolTip>
|
||||||
</SymbolIcon>
|
</SymbolIcon>
|
||||||
<TextBlock Text="{Binding Path={Binding DisplayMemberPath, ElementName=UserControl}}" x:Name="GroupTextBlock" TextWrapping="NoWrap" VerticalAlignment="Center" Margin="30,0,20,0" />
|
<TextBlock Text="{Binding Path={Binding DisplayMemberPath, ElementName=UserControl}}" x:Name="GroupTextBlock" TextWrapping="NoWrap" VerticalAlignment="Center" Margin="20,0,10,0" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ListView.Resources>
|
</ListView.ItemTemplate>
|
||||||
<ListView.ItemTemplateSelector>
|
|
||||||
<templateSelectors:SelectableDataTemplateSelector FalseItem="{StaticResource IsNormal}" TrueItem="{StaticResource IsSpecial}" />
|
|
||||||
</ListView.ItemTemplateSelector>
|
|
||||||
<ListView.HeaderTemplate>
|
<ListView.HeaderTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<StackPanel Orientation="Vertical" Visibility="{Binding IsButtonVisible, ElementName=UserControl}">
|
<StackPanel Orientation="Vertical" Visibility="{Binding IsButtonVisible, ElementName=UserControl}">
|
||||||
@@ -125,13 +115,13 @@
|
|||||||
BorderThickness="0"
|
BorderThickness="0"
|
||||||
Width="{StaticResource ExpandedMenuSize}"
|
Width="{StaticResource ExpandedMenuSize}"
|
||||||
HorizontalContentAlignment="Left">
|
HorizontalContentAlignment="Left">
|
||||||
<StackPanel Orientation="Horizontal" Margin="17,0,5,0">
|
<StackPanel Orientation="Horizontal" Margin="17,0,0,0">
|
||||||
<SymbolIcon Symbol="Add">
|
<SymbolIcon Symbol="Add">
|
||||||
<ToolTipService.ToolTip>
|
<ToolTipService.ToolTip>
|
||||||
<ToolTip Content="{Binding ButtonLabel, ElementName=UserControl}" />
|
<ToolTip Content="{Binding ButtonLabel, ElementName=UserControl}" />
|
||||||
</ToolTipService.ToolTip>
|
</ToolTipService.ToolTip>
|
||||||
</SymbolIcon>
|
</SymbolIcon>
|
||||||
<TextBlock Text="{Binding ButtonLabel, ElementName=UserControl}" FontWeight="SemiBold" TextWrapping="NoWrap" FontSize="16" VerticalAlignment="Center" Margin="30,0,20,0" />
|
<TextBlock Text="{Binding ButtonLabel, ElementName=UserControl}" FontWeight="SemiBold" TextWrapping="NoWrap" FontSize="16" VerticalAlignment="Center" Margin="20,0,0,0" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<interactivity:Interaction.Behaviors>
|
<interactivity:Interaction.Behaviors>
|
||||||
<core:EventTriggerBehavior EventName="Click">
|
<core:EventTriggerBehavior EventName="Click">
|
||||||
@@ -146,13 +136,13 @@
|
|||||||
x:Name="NewGroupTextBox"
|
x:Name="NewGroupTextBox"
|
||||||
Margin="0,5,0,5"
|
Margin="0,5,0,5"
|
||||||
Visibility="Collapsed"
|
Visibility="Collapsed"
|
||||||
Width="280"
|
Width="230"
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
ButtonCommand="{Binding ActionButtonCommand, ElementName=UserControl}"
|
ButtonCommand="{Binding ActionButtonCommand, ElementName=UserControl}"
|
||||||
ButtonCommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=Text}"
|
ButtonCommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=Text}"
|
||||||
Style="{StaticResource TextBoxWithButtonStyle}"
|
Style="{StaticResource TextBoxWithButtonStyle}"
|
||||||
KeyDown="NewGroupTextBox_OnKeyDown"
|
KeyDown="NewGroupTextBox_OnKeyDown"
|
||||||
ButtonSymbol="">
|
ButtonSymbol="">
|
||||||
<interactivity:Interaction.Behaviors>
|
<interactivity:Interaction.Behaviors>
|
||||||
<core:EventTriggerBehavior EventName="LostFocus">
|
<core:EventTriggerBehavior EventName="LostFocus">
|
||||||
<core:ChangePropertyAction TargetObject="{Binding ElementName=NewGroupButton}" PropertyName="Visibility" Value="Visible" />
|
<core:ChangePropertyAction TargetObject="{Binding ElementName=NewGroupButton}" PropertyName="Visibility" Value="Visible" />
|
||||||
@@ -162,6 +152,7 @@
|
|||||||
</interactivity:Interaction.Behaviors>
|
</interactivity:Interaction.Behaviors>
|
||||||
</controls:TextBoxWithButton>
|
</controls:TextBoxWithButton>
|
||||||
<Border BorderBrush="DarkGray" BorderThickness="0,0,0,1" />
|
<Border BorderBrush="DarkGray" BorderThickness="0,0,0,1" />
|
||||||
|
<TextBlock x:Uid="ReorderGroupsLabel" Margin="10,0,0,10" Visibility="{Binding CanDragItems, ElementName=UserControl, Converter={StaticResource BooleanToVisibilityConverter}}" TextWrapping="NoWrap" Style="{StaticResource BodyTextBlockStyle}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ListView.HeaderTemplate>
|
</ListView.HeaderTemplate>
|
||||||
@@ -176,13 +167,13 @@
|
|||||||
BorderThickness="0"
|
BorderThickness="0"
|
||||||
Width="{StaticResource ExpandedMenuSize}"
|
Width="{StaticResource ExpandedMenuSize}"
|
||||||
HorizontalContentAlignment="Left">
|
HorizontalContentAlignment="Left">
|
||||||
<StackPanel Orientation="Horizontal" Margin="17,0,5,0">
|
<StackPanel Orientation="Horizontal" Margin="17,0,0,0">
|
||||||
<SymbolIcon Symbol="Home">
|
<SymbolIcon Symbol="Home">
|
||||||
<ToolTipService.ToolTip>
|
<ToolTipService.ToolTip>
|
||||||
<ToolTip x:Uid="HamburgerMenuHomeTooltip" />
|
<ToolTip x:Uid="HamburgerMenuHomeTooltip" />
|
||||||
</ToolTipService.ToolTip>
|
</ToolTipService.ToolTip>
|
||||||
</SymbolIcon>
|
</SymbolIcon>
|
||||||
<TextBlock x:Uid="HamburgerMenuHomeLabel" FontWeight="SemiBold" TextWrapping="NoWrap" FontSize="16" VerticalAlignment="Center" Margin="30,0,20,0" />
|
<TextBlock x:Uid="HamburgerMenuHomeLabel" FontWeight="SemiBold" TextWrapping="NoWrap" FontSize="16" VerticalAlignment="Center" Margin="20,0,0,0" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<interactivity:Interaction.Behaviors>
|
<interactivity:Interaction.Behaviors>
|
||||||
<core:EventTriggerBehavior EventName="Click">
|
<core:EventTriggerBehavior EventName="Click">
|
||||||
@@ -198,13 +189,13 @@
|
|||||||
BorderThickness="0"
|
BorderThickness="0"
|
||||||
Width="{StaticResource ExpandedMenuSize}"
|
Width="{StaticResource ExpandedMenuSize}"
|
||||||
HorizontalContentAlignment="Left">
|
HorizontalContentAlignment="Left">
|
||||||
<StackPanel Orientation="Horizontal" Margin="17,0,5,0">
|
<StackPanel Orientation="Horizontal" Margin="17,0,0,0">
|
||||||
<SymbolIcon Symbol="Setting">
|
<SymbolIcon Symbol="Setting">
|
||||||
<ToolTipService.ToolTip>
|
<ToolTipService.ToolTip>
|
||||||
<ToolTip x:Uid="HamburgerMenuSettingsTooltip" />
|
<ToolTip x:Uid="HamburgerMenuSettingsTooltip" />
|
||||||
</ToolTipService.ToolTip>
|
</ToolTipService.ToolTip>
|
||||||
</SymbolIcon>
|
</SymbolIcon>
|
||||||
<TextBlock x:Uid="HamburgerMenuSettingsLabel" FontWeight="SemiBold" TextWrapping="NoWrap" FontSize="16" VerticalAlignment="Center" Margin="30,0,20,0" />
|
<TextBlock x:Uid="HamburgerMenuSettingsLabel" FontWeight="SemiBold" TextWrapping="NoWrap" FontSize="16" VerticalAlignment="Center" Margin="20,0,0,0" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<interactivity:Interaction.Behaviors>
|
<interactivity:Interaction.Behaviors>
|
||||||
<core:EventTriggerBehavior EventName="Click">
|
<core:EventTriggerBehavior EventName="Click">
|
||||||
|
@@ -111,6 +111,18 @@ namespace ModernKeePass.Views.UserControls
|
|||||||
typeof(HamburgerMenuUserControl),
|
typeof(HamburgerMenuUserControl),
|
||||||
new PropertyMetadata(false, (o, args) => { }));
|
new PropertyMetadata(false, (o, args) => { }));
|
||||||
|
|
||||||
|
public bool CanDragItems
|
||||||
|
{
|
||||||
|
get { return (bool)GetValue(CanDragItemsProperty); }
|
||||||
|
set { SetValue(CanDragItemsProperty, value); }
|
||||||
|
}
|
||||||
|
public static readonly DependencyProperty CanDragItemsProperty =
|
||||||
|
DependencyProperty.Register(
|
||||||
|
nameof(CanDragItems),
|
||||||
|
typeof(bool),
|
||||||
|
typeof(HamburgerMenuUserControl),
|
||||||
|
new PropertyMetadata(false, (o, args) => { }));
|
||||||
|
|
||||||
public ICommand ActionButtonCommand
|
public ICommand ActionButtonCommand
|
||||||
{
|
{
|
||||||
get { return (ICommand)GetValue(ActionButtonCommandProperty); }
|
get { return (ICommand)GetValue(ActionButtonCommandProperty); }
|
||||||
|
@@ -150,7 +150,6 @@
|
|||||||
<Button.Flyout>
|
<Button.Flyout>
|
||||||
<MenuFlyout Opening="OverflowFlyout_OnOpening">
|
<MenuFlyout Opening="OverflowFlyout_OnOpening">
|
||||||
<MenuFlyoutItem x:Uid="TopMenuSaveFlyout" x:Name="SaveFlyout" />
|
<MenuFlyoutItem x:Uid="TopMenuSaveFlyout" x:Name="SaveFlyout" />
|
||||||
<MenuFlyoutItem x:Uid="TopMenuMoveFlyout" x:Name="MoveFlyout" Visibility="{Binding MoveButtonVisibility, ElementName=UserControl}" />
|
|
||||||
<MenuFlyoutItem x:Uid="TopMenuRestoreFlyout" x:Name="RestoreFlyout" Visibility="{Binding RestoreButtonVisibility, ElementName=UserControl}" />
|
<MenuFlyoutItem x:Uid="TopMenuRestoreFlyout" x:Name="RestoreFlyout" Visibility="{Binding RestoreButtonVisibility, ElementName=UserControl}" />
|
||||||
<ToggleMenuFlyoutItem x:Uid="TopMenuEditFlyout" x:Name="EditFlyout" IsChecked="{Binding IsEditButtonChecked, ElementName=UserControl, Mode=TwoWay}" Click="EditButton_Click" />
|
<ToggleMenuFlyoutItem x:Uid="TopMenuEditFlyout" x:Name="EditFlyout" IsChecked="{Binding IsEditButtonChecked, ElementName=UserControl, Mode=TwoWay}" Click="EditButton_Click" />
|
||||||
<MenuFlyoutItem x:Uid="TopMenuDeleteFlyout" x:Name="DeleteFlyout" />
|
<MenuFlyoutItem x:Uid="TopMenuDeleteFlyout" x:Name="DeleteFlyout" />
|
||||||
|
@@ -170,7 +170,6 @@ namespace ModernKeePass.Views.UserControls
|
|||||||
{
|
{
|
||||||
EditFlyout.IsChecked = IsEditButtonChecked;
|
EditFlyout.IsChecked = IsEditButtonChecked;
|
||||||
|
|
||||||
MoveFlyout.Visibility = MoveButtonVisibility;
|
|
||||||
RestoreFlyout.Visibility = RestoreButtonVisibility;
|
RestoreFlyout.Visibility = RestoreButtonVisibility;
|
||||||
SortEntriesFlyout.Visibility = SortButtonVisibility;
|
SortEntriesFlyout.Visibility = SortButtonVisibility;
|
||||||
SortGroupsFlyout.Visibility = SortButtonVisibility;
|
SortGroupsFlyout.Visibility = SortButtonVisibility;
|
||||||
@@ -196,7 +195,7 @@ namespace ModernKeePass.Views.UserControls
|
|||||||
|
|
||||||
private void GroupSearchBox_OnSuggestionsRequested(SearchBox sender, SearchBoxSuggestionsRequestedEventArgs args)
|
private void GroupSearchBox_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 groups = Model.Groups.Where(g => g.Title.IndexOf(args.QueryText, StringComparison.OrdinalIgnoreCase) >= 0).Take(5);
|
var groups = Model.Groups.Where(g => g.Title.IndexOf(args.QueryText, StringComparison.OrdinalIgnoreCase) >= 0).Take(5);
|
||||||
foreach (var group in groups)
|
foreach (var group in groups)
|
||||||
{
|
{
|
||||||
@@ -218,11 +217,11 @@ namespace ModernKeePass.Views.UserControls
|
|||||||
|
|
||||||
private async void EntrySearchBox_OnSuggestionsRequested(SearchBox sender, SearchBoxSuggestionsRequestedEventArgs args)
|
private async void EntrySearchBox_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 = (await Model.Search(args.QueryText)).Take(5);
|
var results = (await Model.Search(args.QueryText)).Take(5);
|
||||||
foreach (var result in results)
|
foreach (var result in results)
|
||||||
{
|
{
|
||||||
args.Request.SearchSuggestionCollection.AppendResultSuggestion(result.Title, result.ParentGroupName, result.Id, imageUri, string.Empty);
|
args.Request.SearchSuggestionCollection.AppendResultSuggestion(result.Title.Value, result.ParentGroupName, result.Id, imageUri, string.Empty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -102,24 +102,27 @@
|
|||||||
<Compile Include="Views\MainPageFrames\ImportExportPage.xaml.cs">
|
<Compile Include="Views\MainPageFrames\ImportExportPage.xaml.cs">
|
||||||
<DependentUpon>ImportExportPage.xaml</DependentUpon>
|
<DependentUpon>ImportExportPage.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Views\SettingsPageFrames\SettingsDatabasePage.xaml.cs">
|
<Compile Include="Views\SettingsPageFrames\SettingsHistoryPage.xaml.cs">
|
||||||
<DependentUpon>SettingsDatabasePage.xaml</DependentUpon>
|
<DependentUpon>SettingsHistoryPage.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Views\SettingsPageFrames\SettingsNewDatabasePage.xaml.cs">
|
<Compile Include="Views\SettingsPageFrames\SettingsRecycleBinPage.xaml.cs">
|
||||||
<DependentUpon>SettingsNewDatabasePage.xaml</DependentUpon>
|
<DependentUpon>SettingsRecycleBinPage.xaml</DependentUpon>
|
||||||
</Compile>
|
|
||||||
<Compile Include="Views\SettingsPageFrames\SettingsSavePage.xaml.cs">
|
|
||||||
<DependentUpon>SettingsSavePage.xaml</DependentUpon>
|
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Views\SettingsPageFrames\SettingsSecurityPage.xaml.cs">
|
<Compile Include="Views\SettingsPageFrames\SettingsSecurityPage.xaml.cs">
|
||||||
<DependentUpon>SettingsSecurityPage.xaml</DependentUpon>
|
<DependentUpon>SettingsSecurityPage.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="Views\SettingsPageFrames\SettingsNewDatabasePage.xaml.cs">
|
||||||
|
<DependentUpon>SettingsNewDatabasePage.xaml</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Views\SettingsPageFrames\SettingsGeneralPage.xaml.cs">
|
||||||
|
<DependentUpon>SettingsGeneralPage.xaml</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Views\SettingsPageFrames\SettingsCredentialsPage.xaml.cs">
|
||||||
|
<DependentUpon>SettingsCredentialsPage.xaml</DependentUpon>
|
||||||
|
</Compile>
|
||||||
<Compile Include="Views\SettingsPageFrames\SettingsWelcomePage.xaml.cs">
|
<Compile Include="Views\SettingsPageFrames\SettingsWelcomePage.xaml.cs">
|
||||||
<DependentUpon>SettingsWelcomePage.xaml</DependentUpon>
|
<DependentUpon>SettingsWelcomePage.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Views\UserControls\BreadCrumbUserControl.xaml.cs">
|
|
||||||
<DependentUpon>BreadCrumbUserControl.xaml</DependentUpon>
|
|
||||||
</Compile>
|
|
||||||
<Compile Include="Views\UserControls\ColorPickerUserControl.xaml.cs">
|
<Compile Include="Views\UserControls\ColorPickerUserControl.xaml.cs">
|
||||||
<DependentUpon>ColorPickerUserControl.xaml</DependentUpon>
|
<DependentUpon>ColorPickerUserControl.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
@@ -204,11 +207,15 @@
|
|||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
</Page>
|
</Page>
|
||||||
<Page Include="Views\SettingsPageFrames\SettingsSavePage.xaml">
|
<Page Include="Views\SettingsPageFrames\SettingsHistoryPage.xaml">
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
</Page>
|
</Page>
|
||||||
<Page Include="Views\UserControls\BreadCrumbUserControl.xaml">
|
<Page Include="Views\SettingsPageFrames\SettingsRecycleBinPage.xaml">
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Page>
|
||||||
|
<Page Include="Views\SettingsPageFrames\SettingsGeneralPage.xaml">
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
</Page>
|
</Page>
|
||||||
@@ -260,7 +267,7 @@
|
|||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
</Page>
|
</Page>
|
||||||
<Page Include="Views\SettingsPageFrames\SettingsDatabasePage.xaml">
|
<Page Include="Views\SettingsPageFrames\SettingsSecurityPage.xaml">
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
</Page>
|
</Page>
|
||||||
@@ -268,7 +275,7 @@
|
|||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
</Page>
|
</Page>
|
||||||
<Page Include="Views\SettingsPageFrames\SettingsSecurityPage.xaml">
|
<Page Include="Views\SettingsPageFrames\SettingsCredentialsPage.xaml">
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
</Page>
|
</Page>
|
||||||
@@ -379,12 +386,8 @@
|
|||||||
<HintPath>..\packages\HockeySDK.WINRT.4.1.6\lib\portable-win81\Microsoft.HockeyApp.Kit.dll</HintPath>
|
<HintPath>..\packages\HockeySDK.WINRT.4.1.6\lib\portable-win81\Microsoft.HockeyApp.Kit.dll</HintPath>
|
||||||
<Private>True</Private>
|
<Private>True</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="Microsoft.Toolkit.Uwp.Notifications, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
<Reference Include="ModernKeePassLib, Version=2.45.1.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\Microsoft.Toolkit.Uwp.Notifications.2.0.0\lib\dotnet\Microsoft.Toolkit.Uwp.Notifications.dll</HintPath>
|
<HintPath>..\packages\ModernKeePassLib.2.45.1\lib\netstandard1.2\ModernKeePassLib.dll</HintPath>
|
||||||
<Private>True</Private>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="ModernKeePassLib, Version=2.44.3.0, Culture=neutral, processorArchitecture=MSIL">
|
|
||||||
<HintPath>..\packages\ModernKeePassLib.2.44.3\lib\netstandard1.2\ModernKeePassLib.dll</HintPath>
|
|
||||||
<Private>True</Private>
|
<Private>True</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="SixLabors.Core, Version=0.1.0.0, Culture=neutral, processorArchitecture=MSIL">
|
<Reference Include="SixLabors.Core, Version=0.1.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
@@ -1,5 +1,8 @@
|
|||||||
Redesign of the UI (top menu and hamburger menu)
|
Support for additional fields
|
||||||
Resuming the app re-opens previously opened database
|
Support for attachments
|
||||||
Notify user and show the Save As dialog when an error is encountered during saving
|
Add an expiration timer for clipboard data
|
||||||
Save As actually works now
|
Ability to manually reorder groups
|
||||||
Creating a new group is now done inline
|
Ability to set max history count and size
|
||||||
|
Design changes
|
||||||
|
Update to KeePassLib version 2.45
|
||||||
|
Bug corrections
|
@@ -1,5 +1,8 @@
|
|||||||
Redesign de l'interface utilisateur (menu superieur et menu hamburger)
|
Ajout des champs additionnels
|
||||||
Le re-chargement de l'app re-ouvre la base de donnees ouverte precedemment
|
Ajout des pi<70>ces-jointes
|
||||||
L'utlisateur est prevenu et un popup de sauvegarde est affiche quand il y a une erreur de sauvegarde
|
Ajout d'une expiration du presse papier
|
||||||
La fonctionnalite Sauvegarder Sous fonctionne correctement
|
Possibilite de reorganiser les groupes manuellement
|
||||||
La creation d'un nouveau groupe se fait directement dans le menu
|
Possibilite de parametrer le nombre max et la taille de l'historique
|
||||||
|
Quelques changements de design
|
||||||
|
Mise a jour de la KeePassLib version 2.45
|
||||||
|
Correction de bugs
|
@@ -14,8 +14,7 @@
|
|||||||
<package id="Microsoft.NETCore.Platforms" version="2.1.1" targetFramework="win81" />
|
<package id="Microsoft.NETCore.Platforms" version="2.1.1" targetFramework="win81" />
|
||||||
<package id="Microsoft.NETCore.Portable.Compatibility" version="1.0.1" targetFramework="win81" />
|
<package id="Microsoft.NETCore.Portable.Compatibility" version="1.0.1" targetFramework="win81" />
|
||||||
<package id="Microsoft.NETCore.UniversalWindowsPlatform" version="6.1.7" targetFramework="win81" />
|
<package id="Microsoft.NETCore.UniversalWindowsPlatform" version="6.1.7" targetFramework="win81" />
|
||||||
<package id="Microsoft.Toolkit.Uwp.Notifications" version="2.0.0" targetFramework="win81" />
|
<package id="ModernKeePassLib" version="2.45.1" targetFramework="win81" />
|
||||||
<package id="ModernKeePassLib" version="2.44.3" targetFramework="win81" />
|
|
||||||
<package id="MvvmLight" version="5.4.1.1" targetFramework="win81" />
|
<package id="MvvmLight" version="5.4.1.1" targetFramework="win81" />
|
||||||
<package id="MvvmLightLibs" version="5.4.1.1" targetFramework="win81" />
|
<package id="MvvmLightLibs" version="5.4.1.1" targetFramework="win81" />
|
||||||
<package id="NETStandard.Library" version="2.0.3" targetFramework="win81" />
|
<package id="NETStandard.Library" version="2.0.3" targetFramework="win81" />
|
||||||
|
@@ -21,12 +21,14 @@ You can get it [here](https://www.microsoft.com/en-us/store/p/modernkeepass/9mwq
|
|||||||
- View, delete and restore from entry history
|
- View, delete and restore from entry history
|
||||||
- Use Semantic Zoom to see your entries in a grouped mode
|
- Use Semantic Zoom to see your entries in a grouped mode
|
||||||
- List recently opened databases
|
- List recently opened databases
|
||||||
- Open database from Windows Explorer
|
- Open a database from Windows Explorer
|
||||||
- Change database encryption
|
- Change database encryption
|
||||||
- Change database compression
|
- Change database compression
|
||||||
- Change database key derivation
|
- Change database key derivation
|
||||||
- Displays and change entry colors and icons
|
- Displays and change entry colors and icons
|
||||||
- Move entries from a group to another
|
- Move entries and groups from a group to another
|
||||||
|
- Entry custom fields (view, add, update, delete)
|
||||||
|
- Entry attachments (view, add, delete)
|
||||||
|
|
||||||
# Build and Test
|
# Build and Test
|
||||||
1. Clone the repository
|
1. Clone the repository
|
||||||
@@ -36,8 +38,6 @@ You can get it [here](https://www.microsoft.com/en-us/store/p/modernkeepass/9mwq
|
|||||||
# Contribute
|
# Contribute
|
||||||
I'm not the best at creating nice assets, so if anyone would like to contribute some nice icons, it would be awesome :)
|
I'm not the best at creating nice assets, so if anyone would like to contribute some nice icons, it would be awesome :)
|
||||||
Otherwise, there are still many things left to implement:
|
Otherwise, there are still many things left to implement:
|
||||||
- Entry custom fields
|
|
||||||
- Entry attachments
|
|
||||||
- Multi entry selection (for delete, or move)
|
- Multi entry selection (for delete, or move)
|
||||||
- Import existing data from CSV, JSON, or XML
|
- Import existing data from CSV, JSON, or XML
|
||||||
- Open database from URL (and maybe some clouds?)
|
- Open database from URL (and maybe some clouds?)
|
||||||
|
@@ -1,11 +1,17 @@
|
|||||||
using Windows.ApplicationModel.DataTransfer;
|
using System;
|
||||||
|
using Windows.ApplicationModel.DataTransfer;
|
||||||
using Windows.UI.Xaml;
|
using Windows.UI.Xaml;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Xaml.Interactivity;
|
using Microsoft.Xaml.Interactivity;
|
||||||
|
using ModernKeePass.Application.Common.Interfaces;
|
||||||
|
using ModernKeePass.Common;
|
||||||
|
|
||||||
namespace ModernKeePass.Actions
|
namespace ModernKeePass.Actions
|
||||||
{
|
{
|
||||||
public class ClipboardAction : DependencyObject, IAction
|
public class ClipboardAction : DependencyObject, IAction
|
||||||
{
|
{
|
||||||
|
private DispatcherTimer _dispatcher;
|
||||||
|
|
||||||
public string Text
|
public string Text
|
||||||
{
|
{
|
||||||
get { return (string)GetValue(TextProperty); }
|
get { return (string)GetValue(TextProperty); }
|
||||||
@@ -18,10 +24,24 @@ namespace ModernKeePass.Actions
|
|||||||
public object Execute(object sender, object parameter)
|
public object Execute(object sender, object parameter)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(Text)) return null;
|
if (string.IsNullOrEmpty(Text)) return null;
|
||||||
|
|
||||||
|
var settings = App.Services.GetRequiredService<ISettingsProxy>();
|
||||||
|
|
||||||
|
_dispatcher = new DispatcherTimer {Interval = TimeSpan.FromSeconds(settings.GetSetting(Constants.Settings.ClipboardTimeout, 10))};
|
||||||
|
_dispatcher.Tick += Dispatcher_Tick;
|
||||||
|
|
||||||
var dataPackage = new DataPackage { RequestedOperation = DataPackageOperation.Copy };
|
var dataPackage = new DataPackage { RequestedOperation = DataPackageOperation.Copy };
|
||||||
dataPackage.SetText(Text);
|
dataPackage.SetText(Text);
|
||||||
Clipboard.SetContent(dataPackage);
|
Clipboard.SetContent(dataPackage);
|
||||||
|
_dispatcher.Start();
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void Dispatcher_Tick(object sender, object e)
|
||||||
|
{
|
||||||
|
Clipboard.SetContent(null);
|
||||||
|
_dispatcher.Stop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using Windows.UI.Xaml;
|
using Windows.UI.Xaml;
|
||||||
using GalaSoft.MvvmLight.Views;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using Microsoft.Xaml.Interactivity;
|
using Microsoft.Xaml.Interactivity;
|
||||||
|
|
||||||
namespace ModernKeePass.Actions
|
namespace ModernKeePass.Actions
|
||||||
@@ -24,10 +22,8 @@ namespace ModernKeePass.Actions
|
|||||||
var uri = new Uri(Url);
|
var uri = new Uri(Url);
|
||||||
return Windows.System.Launcher.LaunchUriAsync(uri).GetAwaiter().GetResult();
|
return Windows.System.Launcher.LaunchUriAsync(uri).GetAwaiter().GetResult();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
var dialogService = App.Services.GetRequiredService<IDialogService>();
|
|
||||||
dialogService.ShowError(ex, ex.Message, null, () => {}).Wait();
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -19,6 +19,21 @@
|
|||||||
public static string SaveSuspend => nameof(SaveSuspend);
|
public static string SaveSuspend => nameof(SaveSuspend);
|
||||||
public static string Sample => nameof(Sample);
|
public static string Sample => nameof(Sample);
|
||||||
public static string DefaultFileFormat => nameof(DefaultFileFormat);
|
public static string DefaultFileFormat => nameof(DefaultFileFormat);
|
||||||
|
public static string ClipboardTimeout => nameof(ClipboardTimeout);
|
||||||
|
public static string HistoryMaxCount => nameof(HistoryMaxCount);
|
||||||
|
|
||||||
|
public static class PasswordGenerationOptions
|
||||||
|
{
|
||||||
|
public static string UpperCasePattern => nameof(UpperCasePattern);
|
||||||
|
public static string LowerCasePattern => nameof(LowerCasePattern);
|
||||||
|
public static string DigitsPattern => nameof(DigitsPattern);
|
||||||
|
public static string MinusPattern => nameof(MinusPattern);
|
||||||
|
public static string UnderscorePattern => nameof(UnderscorePattern);
|
||||||
|
public static string SpacePattern => nameof(SpacePattern);
|
||||||
|
public static string SpecialPattern => nameof(SpecialPattern);
|
||||||
|
public static string BracketsPattern => nameof(BracketsPattern);
|
||||||
|
public static string PasswordLength => nameof(PasswordLength);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
140
WinAppCommon/Common/ObservableDictionary.cs
Normal file
140
WinAppCommon/Common/ObservableDictionary.cs
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Windows.Foundation.Collections;
|
||||||
|
|
||||||
|
namespace ModernKeePass.Common
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Implementation of IObservableMap that supports reentrancy for use as a default view
|
||||||
|
/// model.
|
||||||
|
/// </summary>
|
||||||
|
public class ObservableDictionary : IObservableMap<string, object>
|
||||||
|
{
|
||||||
|
private class ObservableDictionaryChangedEventArgs : IMapChangedEventArgs<string>
|
||||||
|
{
|
||||||
|
public ObservableDictionaryChangedEventArgs(CollectionChange change, string key)
|
||||||
|
{
|
||||||
|
CollectionChange = change;
|
||||||
|
Key = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CollectionChange CollectionChange { get; }
|
||||||
|
public string Key { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly Dictionary<string, object> _dictionary = new Dictionary<string, object>();
|
||||||
|
public event MapChangedEventHandler<string, object> MapChanged;
|
||||||
|
|
||||||
|
private void InvokeMapChanged(CollectionChange change, string key)
|
||||||
|
{
|
||||||
|
MapChanged?.Invoke(this, new ObservableDictionaryChangedEventArgs(change, key));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(string key, object value)
|
||||||
|
{
|
||||||
|
_dictionary.Add(key, value);
|
||||||
|
InvokeMapChanged(CollectionChange.ItemInserted, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(KeyValuePair<string, object> item)
|
||||||
|
{
|
||||||
|
Add(item.Key, item.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddRange(IEnumerable<KeyValuePair<string, object>> values)
|
||||||
|
{
|
||||||
|
foreach (var value in values)
|
||||||
|
{
|
||||||
|
Add(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Remove(string key)
|
||||||
|
{
|
||||||
|
if (_dictionary.Remove(key))
|
||||||
|
{
|
||||||
|
InvokeMapChanged(CollectionChange.ItemRemoved, key);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Remove(KeyValuePair<string, object> item)
|
||||||
|
{
|
||||||
|
object currentValue;
|
||||||
|
if (_dictionary.TryGetValue(item.Key, out currentValue) &&
|
||||||
|
Equals(item.Value, currentValue) && _dictionary.Remove(item.Key))
|
||||||
|
{
|
||||||
|
InvokeMapChanged(CollectionChange.ItemRemoved, item.Key);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object this[string key]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _dictionary[key];
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_dictionary[key] = value;
|
||||||
|
InvokeMapChanged(CollectionChange.ItemChanged, key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
var priorKeys = _dictionary.Keys.ToArray();
|
||||||
|
_dictionary.Clear();
|
||||||
|
foreach (var key in priorKeys)
|
||||||
|
{
|
||||||
|
InvokeMapChanged(CollectionChange.ItemRemoved, key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ICollection<string> Keys => _dictionary.Keys;
|
||||||
|
|
||||||
|
public bool ContainsKey(string key)
|
||||||
|
{
|
||||||
|
return _dictionary.ContainsKey(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetValue(string key, out object value)
|
||||||
|
{
|
||||||
|
return _dictionary.TryGetValue(key, out value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ICollection<object> Values => _dictionary.Values;
|
||||||
|
|
||||||
|
public bool Contains(KeyValuePair<string, object> item)
|
||||||
|
{
|
||||||
|
return _dictionary.Contains(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Count => _dictionary.Count;
|
||||||
|
|
||||||
|
public bool IsReadOnly => false;
|
||||||
|
|
||||||
|
public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
|
||||||
|
{
|
||||||
|
return _dictionary.GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
|
||||||
|
{
|
||||||
|
return _dictionary.GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CopyTo(KeyValuePair<string, object>[] array, int arrayIndex)
|
||||||
|
{
|
||||||
|
var arraySize = array.Length;
|
||||||
|
foreach (var pair in _dictionary)
|
||||||
|
{
|
||||||
|
if (arrayIndex >= arraySize) break;
|
||||||
|
array[arrayIndex++] = pair;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -4,7 +4,7 @@ using ModernKeePass.Domain.Interfaces;
|
|||||||
|
|
||||||
namespace ModernKeePass.Controls
|
namespace ModernKeePass.Controls
|
||||||
{
|
{
|
||||||
public class ListViewWithDisable: ListView
|
public class DisableListView: ListView
|
||||||
{
|
{
|
||||||
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
|
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
|
||||||
{
|
{
|
51
WinAppCommon/Controls/SelectableTemplateListView.cs
Normal file
51
WinAppCommon/Controls/SelectableTemplateListView.cs
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
using Windows.UI.Xaml;
|
||||||
|
using Windows.UI.Xaml.Controls;
|
||||||
|
|
||||||
|
namespace ModernKeePass.Controls
|
||||||
|
{
|
||||||
|
public class SelectableTemplateListView: ListView
|
||||||
|
{
|
||||||
|
public DataTemplate SelectedItemTemplate
|
||||||
|
{
|
||||||
|
get { return (DataTemplate)GetValue(SelectedItemTemplateProperty); }
|
||||||
|
set { SetValue(SelectedItemTemplateProperty, value); }
|
||||||
|
}
|
||||||
|
public static readonly DependencyProperty SelectedItemTemplateProperty =
|
||||||
|
DependencyProperty.Register(
|
||||||
|
nameof(SelectedItemTemplate),
|
||||||
|
typeof(DataTemplate),
|
||||||
|
typeof(PasswordBoxWithButton),
|
||||||
|
new PropertyMetadata(null, (o, args) => { }));
|
||||||
|
|
||||||
|
public SelectableTemplateListView()
|
||||||
|
{
|
||||||
|
ContainerContentChanging += SelectableTemplateListView_ContainerContentChanging;
|
||||||
|
SelectionChanged += SelectableTemplateListView_SelectionChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SelectableTemplateListView_ContainerContentChanging(ListViewBase sender, ContainerContentChangingEventArgs args)
|
||||||
|
{
|
||||||
|
args.ItemContainer.ContentTemplate = args.ItemContainer.IsSelected
|
||||||
|
? SelectedItemTemplate
|
||||||
|
: ItemTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SelectableTemplateListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||||
|
{
|
||||||
|
var listView = sender as ListView;
|
||||||
|
if (listView == null) return;
|
||||||
|
|
||||||
|
foreach (var item in e.AddedItems)
|
||||||
|
{
|
||||||
|
var listViewItem = listView.ContainerFromItem(item) as ListViewItem;
|
||||||
|
if (listViewItem != null) listViewItem.ContentTemplate = SelectedItemTemplate;
|
||||||
|
}
|
||||||
|
//Remove DataTemplate for unselected items
|
||||||
|
foreach (var item in e.RemovedItems)
|
||||||
|
{
|
||||||
|
var listViewItem = listView.ContainerFromItem(item) as ListViewItem;
|
||||||
|
if (listViewItem != null) listViewItem.ContentTemplate = ItemTemplate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -69,19 +69,6 @@ namespace ModernKeePass.Controls
|
|||||||
typeof(TextBoxWithButton),
|
typeof(TextBoxWithButton),
|
||||||
new PropertyMetadata(null, (o, args) => { }));
|
new PropertyMetadata(null, (o, args) => { }));
|
||||||
|
|
||||||
public bool IsButtonEnabled
|
|
||||||
{
|
|
||||||
get { return (bool)GetValue(IsButtonEnabledProperty); }
|
|
||||||
set { SetValue(IsButtonEnabledProperty, value); }
|
|
||||||
}
|
|
||||||
public static readonly DependencyProperty IsButtonEnabledProperty =
|
|
||||||
DependencyProperty.Register(
|
|
||||||
nameof(IsButtonEnabled),
|
|
||||||
typeof(bool),
|
|
||||||
typeof(TextBoxWithButton),
|
|
||||||
new PropertyMetadata(true, (o, args) => { }));
|
|
||||||
|
|
||||||
|
|
||||||
public TextBoxWithButton()
|
public TextBoxWithButton()
|
||||||
{
|
{
|
||||||
DefaultStyleKey = typeof(TextBoxWithButton);
|
DefaultStyleKey = typeof(TextBoxWithButton);
|
||||||
|
@@ -1,24 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Windows.UI.Xaml.Data;
|
|
||||||
|
|
||||||
namespace ModernKeePass.Converters
|
|
||||||
{
|
|
||||||
public class PluralizationConverter : IValueConverter
|
|
||||||
{
|
|
||||||
public object Convert(object value, Type targetType, object parameter, string language)
|
|
||||||
{
|
|
||||||
var pluralizationOptionString = parameter as string;
|
|
||||||
var pluralizationOptions = pluralizationOptionString?.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries);
|
|
||||||
if (pluralizationOptions == null || pluralizationOptions.Length != 2) return string.Empty;
|
|
||||||
var count = value is int ? (int) value : 0;
|
|
||||||
var text = count == 1 ? pluralizationOptions[0] : pluralizationOptions[1];
|
|
||||||
return $"{count} {text}";
|
|
||||||
}
|
|
||||||
|
|
||||||
// No need to implement this
|
|
||||||
public object ConvertBack(object value, Type targetType, object parameter, string language)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,20 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Windows.UI.Xaml.Data;
|
|
||||||
|
|
||||||
namespace ModernKeePass.Converters
|
|
||||||
{
|
|
||||||
public class TextToWidthConverter : IValueConverter
|
|
||||||
{
|
|
||||||
public object Convert(object value, Type targetType, object parameter, string language)
|
|
||||||
{
|
|
||||||
var fontSize = double.Parse(parameter as string);
|
|
||||||
var text = value as string;
|
|
||||||
return text?.Length * fontSize ?? 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public object ConvertBack(object value, Type targetType, object parameter, string language)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
10
WinAppCommon/Messages/EntryFieldNameChangedMessage.cs
Normal file
10
WinAppCommon/Messages/EntryFieldNameChangedMessage.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
namespace Messages
|
||||||
|
{
|
||||||
|
public class EntryFieldNameChangedMessage
|
||||||
|
{
|
||||||
|
public string OldName { get; set; }
|
||||||
|
public string NewName { get; set; }
|
||||||
|
public string Value { get; set; }
|
||||||
|
public bool IsProtected { get; set; }
|
||||||
|
}
|
||||||
|
}
|
9
WinAppCommon/Messages/EntryFieldValueChangedMessage.cs
Normal file
9
WinAppCommon/Messages/EntryFieldValueChangedMessage.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
namespace Messages
|
||||||
|
{
|
||||||
|
public class EntryFieldValueChangedMessage
|
||||||
|
{
|
||||||
|
public string FieldName { get; set; }
|
||||||
|
public string FieldValue { get; set; }
|
||||||
|
public bool IsProtected { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@@ -1,18 +0,0 @@
|
|||||||
using Windows.UI.Xaml;
|
|
||||||
using Windows.UI.Xaml.Controls;
|
|
||||||
|
|
||||||
namespace ModernKeePass.TemplateSelectors
|
|
||||||
{
|
|
||||||
public class FirstItemDataTemplateSelector: DataTemplateSelector
|
|
||||||
{
|
|
||||||
public DataTemplate FirstItem { get; set; }
|
|
||||||
public DataTemplate OtherItem { get; set; }
|
|
||||||
|
|
||||||
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
|
|
||||||
{
|
|
||||||
var itemsControl = ItemsControl.ItemsControlFromItemContainer(container);
|
|
||||||
var returnTemplate = itemsControl?.IndexFromContainer(container) == 0 ? FirstItem : OtherItem;
|
|
||||||
return returnTemplate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,18 +0,0 @@
|
|||||||
using Windows.UI.Xaml;
|
|
||||||
using Windows.UI.Xaml.Controls;
|
|
||||||
using ModernKeePass.Domain.Interfaces;
|
|
||||||
|
|
||||||
namespace ModernKeePass.TemplateSelectors
|
|
||||||
{
|
|
||||||
public class SelectableDataTemplateSelector: DataTemplateSelector
|
|
||||||
{
|
|
||||||
public DataTemplate TrueItem { get; set; }
|
|
||||||
public DataTemplate FalseItem { get; set; }
|
|
||||||
|
|
||||||
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
|
|
||||||
{
|
|
||||||
var isSelectableItem = item as ISelectableModel;
|
|
||||||
return isSelectableItem != null && isSelectableItem.IsSelected ? TrueItem : FalseItem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
51
WinAppCommon/ViewModels/Items/EntryFieldVm.cs
Normal file
51
WinAppCommon/ViewModels/Items/EntryFieldVm.cs
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using GalaSoft.MvvmLight;
|
||||||
|
using Messages;
|
||||||
|
using ModernKeePass.Domain.Enums;
|
||||||
|
|
||||||
|
namespace ModernKeePass.ViewModels.ListItems
|
||||||
|
{
|
||||||
|
public class EntryFieldVm: ViewModelBase
|
||||||
|
{
|
||||||
|
private string _name;
|
||||||
|
private string _value;
|
||||||
|
private bool _isProtected;
|
||||||
|
|
||||||
|
public string Name
|
||||||
|
{
|
||||||
|
get { return _name; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
var newName = EntryFieldName.StandardFieldNames.Contains(value) ? $"{value}_1" : value;
|
||||||
|
MessengerInstance.Send(new EntryFieldNameChangedMessage { OldName = Name, NewName = newName, Value = Value, IsProtected = IsProtected});
|
||||||
|
Set(nameof(Name), ref _name, newName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Value
|
||||||
|
{
|
||||||
|
get { return _value; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
MessengerInstance.Send(new EntryFieldValueChangedMessage { FieldName = Name, FieldValue = value, IsProtected = IsProtected });
|
||||||
|
Set(nameof(Value), ref _value, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool IsProtected
|
||||||
|
{
|
||||||
|
get { return _isProtected; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
MessengerInstance.Send(new EntryFieldValueChangedMessage { FieldName = Name, FieldValue = Value, IsProtected = value });
|
||||||
|
Set(nameof(IsProtected), ref _isProtected, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public EntryFieldVm(string fieldName, string fieldValue, bool isProtected)
|
||||||
|
{
|
||||||
|
_name = fieldName;
|
||||||
|
_value = fieldValue;
|
||||||
|
_isProtected = isProtected;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
37
WinAppCommon/ViewModels/Items/FieldVm.cs
Normal file
37
WinAppCommon/ViewModels/Items/FieldVm.cs
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
using GalaSoft.MvvmLight;
|
||||||
|
using Messages;
|
||||||
|
|
||||||
|
namespace ModernKeePass.ViewModels.ListItems
|
||||||
|
{
|
||||||
|
public class FieldVm: ViewModelBase
|
||||||
|
{
|
||||||
|
private string _name;
|
||||||
|
private string _value;
|
||||||
|
|
||||||
|
public string Name
|
||||||
|
{
|
||||||
|
get { return _name; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
MessengerInstance.Send(new EntryFieldNameChangedMessage { OldName = Name, NewName = value, Value = Value });
|
||||||
|
Set(nameof(Name), ref _name, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Value
|
||||||
|
{
|
||||||
|
get { return _value; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
MessengerInstance.Send(new EntryFieldValueChangedMessage { FieldName = Name, FieldValue = value });
|
||||||
|
Set(nameof(Value), ref _value, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public FieldVm(string fieldName, string fieldValue)
|
||||||
|
{
|
||||||
|
_name = fieldName;
|
||||||
|
_value = fieldValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -1,12 +1,10 @@
|
|||||||
using GalaSoft.MvvmLight;
|
using GalaSoft.MvvmLight;
|
||||||
using ModernKeePass.Domain.Dtos;
|
using ModernKeePass.Domain.Dtos;
|
||||||
using ModernKeePass.Domain.Interfaces;
|
|
||||||
|
|
||||||
namespace ModernKeePass.ViewModels.ListItems
|
namespace ModernKeePass.ViewModels.ListItems
|
||||||
{
|
{
|
||||||
public class RecentItemVm: ObservableObject, ISelectableModel
|
public class RecentItemVm: ObservableObject
|
||||||
{
|
{
|
||||||
private bool _isSelected;
|
|
||||||
private string _name;
|
private string _name;
|
||||||
private string _token;
|
private string _token;
|
||||||
private string _path;
|
private string _path;
|
||||||
@@ -29,12 +27,6 @@ namespace ModernKeePass.ViewModels.ListItems
|
|||||||
set { Set(() => Path, ref _path, value); }
|
set { Set(() => Path, ref _path, value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsSelected
|
|
||||||
{
|
|
||||||
get { return _isSelected; }
|
|
||||||
set { Set(() => IsSelected, ref _isSelected, value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public RecentItemVm(FileInfo file)
|
public RecentItemVm(FileInfo file)
|
||||||
{
|
{
|
||||||
Token = file.Id;
|
Token = file.Id;
|
||||||
|
37
WinAppCommon/ViewModels/Items/SettingsCredentialsVm.cs
Normal file
37
WinAppCommon/ViewModels/Items/SettingsCredentialsVm.cs
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
using GalaSoft.MvvmLight;
|
||||||
|
using MediatR;
|
||||||
|
using Messages;
|
||||||
|
using ModernKeePass.Application.Common.Interfaces;
|
||||||
|
using ModernKeePass.Application.Database.Commands.UpdateCredentials;
|
||||||
|
using ModernKeePass.Application.Database.Queries.GetDatabase;
|
||||||
|
|
||||||
|
namespace ModernKeePass.ViewModels.ListItems
|
||||||
|
{
|
||||||
|
public class SettingsCredentialsVm: ViewModelBase
|
||||||
|
{
|
||||||
|
private readonly IMediator _mediator;
|
||||||
|
private readonly IResourceProxy _resource;
|
||||||
|
private readonly INotificationService _notification;
|
||||||
|
|
||||||
|
public SettingsCredentialsVm(IMediator mediator, IResourceProxy resource, INotificationService notification)
|
||||||
|
{
|
||||||
|
_mediator = mediator;
|
||||||
|
_resource = resource;
|
||||||
|
_notification = notification;
|
||||||
|
|
||||||
|
MessengerInstance.Register<CredentialsSetMessage>(this, async message => await UpdateDatabaseCredentials(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task UpdateDatabaseCredentials(CredentialsSetMessage message)
|
||||||
|
{
|
||||||
|
await _mediator.Send(new UpdateCredentialsCommand
|
||||||
|
{
|
||||||
|
KeyFilePath = message.KeyFilePath,
|
||||||
|
Password = message.Password
|
||||||
|
});
|
||||||
|
var database = await _mediator.Send(new GetDatabaseQuery());
|
||||||
|
_notification.Show(database.Name, _resource.GetResourceValue("CompositeKeyUpdated"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
7
WinAppCommon/ViewModels/Items/SettingsHistoryVm.cs
Normal file
7
WinAppCommon/ViewModels/Items/SettingsHistoryVm.cs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
namespace ModernKeePass.ViewModels.ListItems
|
||||||
|
{
|
||||||
|
public class SettingsHistoryVm
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
57
WinAppCommon/ViewModels/Items/SettingsRecycleBinVm.cs
Normal file
57
WinAppCommon/ViewModels/Items/SettingsRecycleBinVm.cs
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Linq;
|
||||||
|
using GalaSoft.MvvmLight;
|
||||||
|
using MediatR;
|
||||||
|
using ModernKeePass.Application.Common.Interfaces;
|
||||||
|
using ModernKeePass.Application.Database.Models;
|
||||||
|
using ModernKeePass.Application.Database.Queries.GetDatabase;
|
||||||
|
using ModernKeePass.Application.Group.Queries.GetGroup;
|
||||||
|
using ModernKeePass.Application.Parameters.Commands.SetHasRecycleBin;
|
||||||
|
using ModernKeePass.Application.Parameters.Commands.SetRecycleBin;
|
||||||
|
|
||||||
|
namespace ModernKeePass.ViewModels.ListItems
|
||||||
|
{
|
||||||
|
public class SettingsRecycleBinVm: ObservableObject
|
||||||
|
{
|
||||||
|
private readonly IMediator _mediator;
|
||||||
|
private readonly DatabaseVm _database;
|
||||||
|
|
||||||
|
public bool HasRecycleBin
|
||||||
|
{
|
||||||
|
get { return _database.IsRecycleBinEnabled; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_mediator.Send(new SetHasRecycleBinCommand { HasRecycleBin = value }).Wait();
|
||||||
|
RaisePropertyChanged(nameof(HasRecycleBin));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsNewRecycleBin
|
||||||
|
{
|
||||||
|
get { return string.IsNullOrEmpty(_database.RecycleBinId); }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value) _mediator.Send(new SetRecycleBinCommand { RecycleBinId = null }).Wait();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObservableCollection<IEntityVm> Groups { get; }
|
||||||
|
|
||||||
|
public IEntityVm SelectedRecycleBin
|
||||||
|
{
|
||||||
|
get { return Groups.FirstOrDefault(g => g.Id == _database.RecycleBinId); }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (!IsNewRecycleBin) _mediator.Send(new SetRecycleBinCommand { RecycleBinId = value.Id }).Wait();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public SettingsRecycleBinVm(IMediator mediator)
|
||||||
|
{
|
||||||
|
_mediator = mediator;
|
||||||
|
_database = _mediator.Send(new GetDatabaseQuery()).GetAwaiter().GetResult();
|
||||||
|
var rootGroup = _mediator.Send(new GetGroupQuery { Id = _database.RootGroupId }).GetAwaiter().GetResult();
|
||||||
|
Groups = new ObservableCollection<IEntityVm>(rootGroup.SubGroups);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -1,37 +1,57 @@
|
|||||||
using System.Threading.Tasks;
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Linq;
|
||||||
using GalaSoft.MvvmLight;
|
using GalaSoft.MvvmLight;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
using Messages;
|
using ModernKeePass.Application.Database.Models;
|
||||||
using ModernKeePass.Application.Common.Interfaces;
|
|
||||||
using ModernKeePass.Application.Database.Commands.UpdateCredentials;
|
|
||||||
using ModernKeePass.Application.Database.Queries.GetDatabase;
|
using ModernKeePass.Application.Database.Queries.GetDatabase;
|
||||||
|
using ModernKeePass.Application.Parameters.Commands.SetCipher;
|
||||||
|
using ModernKeePass.Application.Parameters.Commands.SetCompression;
|
||||||
|
using ModernKeePass.Application.Parameters.Commands.SetKeyDerivation;
|
||||||
|
using ModernKeePass.Application.Parameters.Models;
|
||||||
|
using ModernKeePass.Application.Parameters.Queries.GetCiphers;
|
||||||
|
using ModernKeePass.Application.Parameters.Queries.GetCompressions;
|
||||||
|
using ModernKeePass.Application.Parameters.Queries.GetKeyDerivations;
|
||||||
|
|
||||||
namespace ModernKeePass.ViewModels.ListItems
|
namespace ModernKeePass.ViewModels.ListItems
|
||||||
{
|
{
|
||||||
public class SettingsSecurityVm: ViewModelBase
|
// TODO: implement Kdf settings
|
||||||
|
public class SettingsSecurityVm: ObservableObject
|
||||||
{
|
{
|
||||||
private readonly IMediator _mediator;
|
private readonly IMediator _mediator;
|
||||||
private readonly IResourceProxy _resource;
|
private readonly DatabaseVm _database;
|
||||||
private readonly INotificationService _notification;
|
|
||||||
|
|
||||||
public SettingsSecurityVm(IMediator mediator, IResourceProxy resource, INotificationService notification)
|
|
||||||
|
public ObservableCollection<CipherVm> Ciphers { get; }
|
||||||
|
public IEnumerable<string> Compressions => _mediator.Send(new GetCompressionsQuery()).GetAwaiter().GetResult();
|
||||||
|
public ObservableCollection<KeyDerivationVm> KeyDerivations { get; }
|
||||||
|
|
||||||
|
public CipherVm SelectedCipher
|
||||||
{
|
{
|
||||||
_mediator = mediator;
|
get { return Ciphers.FirstOrDefault(c => c.Id == _database.CipherId); }
|
||||||
_resource = resource;
|
set { _mediator.Send(new SetCipherCommand {CipherId = value.Id}).Wait(); }
|
||||||
_notification = notification;
|
|
||||||
|
|
||||||
MessengerInstance.Register<CredentialsSetMessage>(this, async message => await UpdateDatabaseCredentials(message));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task UpdateDatabaseCredentials(CredentialsSetMessage message)
|
public string SelectedCompression
|
||||||
{
|
{
|
||||||
await _mediator.Send(new UpdateCredentialsCommand
|
get { return Compressions.FirstOrDefault(c => c == _database.Compression); }
|
||||||
{
|
set { _mediator.Send(new SetCompressionCommand {Compression = value}).Wait(); }
|
||||||
KeyFilePath = message.KeyFilePath,
|
}
|
||||||
Password = message.Password
|
|
||||||
});
|
public KeyDerivationVm SelectedKeyDerivation
|
||||||
var database = await _mediator.Send(new GetDatabaseQuery());
|
{
|
||||||
_notification.Show(database.Name, _resource.GetResourceValue("CompositeKeyUpdated"));
|
get { return KeyDerivations.FirstOrDefault(c => c.Id == _database.KeyDerivationId); }
|
||||||
|
set { _mediator.Send(new SetKeyDerivationCommand {KeyDerivationId = value.Id}).Wait(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public SettingsSecurityVm(IMediator mediator)
|
||||||
|
{
|
||||||
|
_mediator = mediator;
|
||||||
|
_database = _mediator.Send(new GetDatabaseQuery()).GetAwaiter().GetResult();
|
||||||
|
var ciphers = _mediator.Send(new GetCiphersQuery()).GetAwaiter().GetResult();
|
||||||
|
Ciphers = new ObservableCollection<CipherVm>(ciphers);
|
||||||
|
var keyDerivations = _mediator.Send(new GetKeyDerivationsQuery()).GetAwaiter().GetResult();
|
||||||
|
KeyDerivations = new ObservableCollection<KeyDerivationVm>(keyDerivations);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -5,16 +5,15 @@ using GalaSoft.MvvmLight;
|
|||||||
using GalaSoft.MvvmLight.Command;
|
using GalaSoft.MvvmLight.Command;
|
||||||
using Messages;
|
using Messages;
|
||||||
using ModernKeePass.Application.Common.Interfaces;
|
using ModernKeePass.Application.Common.Interfaces;
|
||||||
using ModernKeePass.Domain.Interfaces;
|
|
||||||
using ModernKeePass.ViewModels.ListItems;
|
using ModernKeePass.ViewModels.ListItems;
|
||||||
|
|
||||||
namespace ModernKeePass.ViewModels
|
namespace ModernKeePass.ViewModels
|
||||||
{
|
{
|
||||||
public class RecentVm : ViewModelBase, IHasSelectableObject
|
public class RecentVm : ViewModelBase
|
||||||
{
|
{
|
||||||
private readonly IRecentProxy _recent;
|
private readonly IRecentProxy _recent;
|
||||||
private ISelectableModel _selectedItem;
|
|
||||||
private ObservableCollection<RecentItemVm> _recentItems;
|
private ObservableCollection<RecentItemVm> _recentItems;
|
||||||
|
private int _selectedIndex;
|
||||||
|
|
||||||
public ObservableCollection<RecentItemVm> RecentItems
|
public ObservableCollection<RecentItemVm> RecentItems
|
||||||
{
|
{
|
||||||
@@ -22,26 +21,14 @@ namespace ModernKeePass.ViewModels
|
|||||||
set { Set(() => RecentItems, ref _recentItems, value); }
|
set { Set(() => RecentItems, ref _recentItems, value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public ISelectableModel SelectedItem
|
|
||||||
{
|
|
||||||
get { return _selectedItem; }
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (_selectedItem == value) return;
|
|
||||||
if (_selectedItem != null)
|
|
||||||
{
|
|
||||||
_selectedItem.IsSelected = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Set(() => SelectedItem, ref _selectedItem, value);
|
|
||||||
|
|
||||||
if (_selectedItem == null) return;
|
|
||||||
_selectedItem.IsSelected = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ICommand ClearAllCommand { get; }
|
public ICommand ClearAllCommand { get; }
|
||||||
|
|
||||||
|
public int SelectedIndex
|
||||||
|
{
|
||||||
|
get { return _selectedIndex; }
|
||||||
|
set { Set(() => SelectedIndex, ref _selectedIndex, value); }
|
||||||
|
}
|
||||||
|
|
||||||
public RecentVm(IRecentProxy recent)
|
public RecentVm(IRecentProxy recent)
|
||||||
{
|
{
|
||||||
_recent = recent;
|
_recent = recent;
|
||||||
@@ -54,8 +41,7 @@ namespace ModernKeePass.ViewModels
|
|||||||
{
|
{
|
||||||
var recentItems = _recent.GetAll().Select(r => new RecentItemVm(r));
|
var recentItems = _recent.GetAll().Select(r => new RecentItemVm(r));
|
||||||
RecentItems = new ObservableCollection<RecentItemVm>(recentItems);
|
RecentItems = new ObservableCollection<RecentItemVm>(recentItems);
|
||||||
if (RecentItems.Count > 0)
|
if (RecentItems.Any()) SelectedIndex = 0;
|
||||||
SelectedItem = RecentItems[0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ClearAll()
|
private void ClearAll()
|
||||||
|
37
WinAppCommon/ViewModels/Settings/CredentialsVm.cs
Normal file
37
WinAppCommon/ViewModels/Settings/CredentialsVm.cs
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
using GalaSoft.MvvmLight;
|
||||||
|
using MediatR;
|
||||||
|
using Messages;
|
||||||
|
using ModernKeePass.Application.Common.Interfaces;
|
||||||
|
using ModernKeePass.Application.Database.Commands.UpdateCredentials;
|
||||||
|
using ModernKeePass.Application.Database.Queries.GetDatabase;
|
||||||
|
|
||||||
|
namespace ModernKeePass.ViewModels.Settings
|
||||||
|
{
|
||||||
|
public class CredentialsVm: ViewModelBase
|
||||||
|
{
|
||||||
|
private readonly IMediator _mediator;
|
||||||
|
private readonly IResourceProxy _resource;
|
||||||
|
private readonly INotificationService _notification;
|
||||||
|
|
||||||
|
public CredentialsVm(IMediator mediator, IResourceProxy resource, INotificationService notification)
|
||||||
|
{
|
||||||
|
_mediator = mediator;
|
||||||
|
_resource = resource;
|
||||||
|
_notification = notification;
|
||||||
|
|
||||||
|
MessengerInstance.Register<CredentialsSetMessage>(this, async message => await UpdateDatabaseCredentials(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task UpdateDatabaseCredentials(CredentialsSetMessage message)
|
||||||
|
{
|
||||||
|
await _mediator.Send(new UpdateCredentialsCommand
|
||||||
|
{
|
||||||
|
KeyFilePath = message.KeyFilePath,
|
||||||
|
Password = message.Password
|
||||||
|
});
|
||||||
|
var database = await _mediator.Send(new GetDatabaseQuery());
|
||||||
|
_notification.Show(database.Name, _resource.GetResourceValue("CompositeKeyUpdated"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
28
WinAppCommon/ViewModels/Settings/GeneralVm.cs
Normal file
28
WinAppCommon/ViewModels/Settings/GeneralVm.cs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
using ModernKeePass.Application.Common.Interfaces;
|
||||||
|
using ModernKeePass.Common;
|
||||||
|
|
||||||
|
namespace ModernKeePass.ViewModels.Settings
|
||||||
|
{
|
||||||
|
public class GeneralVm
|
||||||
|
{
|
||||||
|
private readonly ISettingsProxy _settings;
|
||||||
|
|
||||||
|
public bool IsSaveSuspend
|
||||||
|
{
|
||||||
|
get { return _settings.GetSetting(Constants.Settings.SaveSuspend, true); }
|
||||||
|
set { _settings.PutSetting(Constants.Settings.SaveSuspend, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int CopyExpiration
|
||||||
|
{
|
||||||
|
get { return _settings.GetSetting(Constants.Settings.ClipboardTimeout, 10); }
|
||||||
|
set { _settings.PutSetting(Constants.Settings.ClipboardTimeout, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public GeneralVm(ISettingsProxy settings)
|
||||||
|
{
|
||||||
|
_settings = settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user