mirror of
https://github.com/wismna/ModernKeePass.git
synced 2025-10-03 15:40:18 -04:00
Basic CSV Import working
This commit is contained in:
@@ -1,13 +1,35 @@
|
|||||||
using Windows.Storage;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Windows.Storage;
|
||||||
using ModernKeePass.Interfaces;
|
using ModernKeePass.Interfaces;
|
||||||
|
|
||||||
namespace ModernKeePass.ImportFormats
|
namespace ModernKeePass.ImportFormats
|
||||||
{
|
{
|
||||||
public class CsvImportFormat: IFormat
|
public class CsvImportFormat: IFormat
|
||||||
{
|
{
|
||||||
public IPwEntity Import(IStorageFile source)
|
public bool HasHeaderRow { get; set; } = true;
|
||||||
|
public char Delimiter { get; set; } = ';';
|
||||||
|
public char LineDelimiter { get; set; } = '\n';
|
||||||
|
|
||||||
|
public async Task<List<Dictionary<string, string>>> Import(IStorageFile source)
|
||||||
{
|
{
|
||||||
throw new System.NotImplementedException();
|
var parsedResult = new List<Dictionary<string, string>>();
|
||||||
|
var content = await FileIO.ReadLinesAsync(source);
|
||||||
|
foreach (var line in content)
|
||||||
|
{
|
||||||
|
var fields = line.Split(Delimiter);
|
||||||
|
var recordItem = new Dictionary<string, string>();
|
||||||
|
var i = 0;
|
||||||
|
foreach (var field in fields)
|
||||||
|
{
|
||||||
|
recordItem.Add(i.ToString(), field);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
parsedResult.Add(recordItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
return parsedResult;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,13 +1,16 @@
|
|||||||
using Windows.Storage;
|
using Windows.Storage;
|
||||||
using ModernKeePass.Interfaces;
|
using ModernKeePass.Interfaces;
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace ModernKeePass.ImportFormats
|
namespace ModernKeePass.ImportFormats
|
||||||
{
|
{
|
||||||
public class NullImportFormat: IFormat
|
public class NullImportFormat: IFormat
|
||||||
{
|
{
|
||||||
public IPwEntity Import(IStorageFile source)
|
public Task<List<Dictionary<string, string>>> Import(IStorageFile source)
|
||||||
{
|
{
|
||||||
throw new System.NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,9 +1,11 @@
|
|||||||
using Windows.Storage;
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Windows.Storage;
|
||||||
|
|
||||||
namespace ModernKeePass.Interfaces
|
namespace ModernKeePass.Interfaces
|
||||||
{
|
{
|
||||||
public interface IFormat
|
public interface IFormat
|
||||||
{
|
{
|
||||||
IPwEntity Import(IStorageFile source);
|
Task<List<Dictionary<string, string>>> Import(IStorageFile source);
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,9 +1,11 @@
|
|||||||
using Windows.Storage;
|
using System.Threading.Tasks;
|
||||||
|
using Windows.Storage;
|
||||||
|
using ModernKeePass.ViewModels;
|
||||||
|
|
||||||
namespace ModernKeePass.Interfaces
|
namespace ModernKeePass.Interfaces
|
||||||
{
|
{
|
||||||
public interface IImportService<in T> where T: IFormat
|
public interface IImportService<in T> where T: IFormat
|
||||||
{
|
{
|
||||||
void Import(T format, IStorageFile source, IDatabaseService database);
|
Task Import(T format, IStorageFile source, GroupVm group);
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,23 +1,24 @@
|
|||||||
using ModernKeePass.Interfaces;
|
using System.Threading.Tasks;
|
||||||
using Windows.Storage;
|
using Windows.Storage;
|
||||||
|
using ModernKeePass.Interfaces;
|
||||||
using ModernKeePass.ViewModels;
|
using ModernKeePass.ViewModels;
|
||||||
|
|
||||||
namespace ModernKeePass.Services
|
namespace ModernKeePass.Services
|
||||||
{
|
{
|
||||||
public class ImportService : IImportService<IFormat>
|
public class ImportService : IImportService<IFormat>
|
||||||
{
|
{
|
||||||
public void Import(IFormat format, IStorageFile source, IDatabaseService databaseService)
|
public async Task Import(IFormat format, IStorageFile source, GroupVm group)
|
||||||
{
|
{
|
||||||
var entities = (GroupVm)format.Import(source);
|
var data = await format.Import(source);
|
||||||
|
|
||||||
foreach (var entry in entities.Entries)
|
foreach (var entity in data)
|
||||||
{
|
{
|
||||||
databaseService.RootGroup.Entries.Add(entry);
|
var entry = group.AddNewEntry();
|
||||||
}
|
entry.Name = entity["0"];
|
||||||
|
entry.UserName = entity["1"];
|
||||||
foreach (var subGroup in entities.Groups)
|
entry.Password = entity["2"];
|
||||||
{
|
if (entity.Count > 3) entry.Url = entity["3"];
|
||||||
databaseService.RootGroup.Groups.Add(subGroup);
|
if (entity.Count > 4) entry.Notes = entity["4"];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -255,4 +255,7 @@
|
|||||||
<data name="ToastSavedMessage" xml:space="preserve">
|
<data name="ToastSavedMessage" xml:space="preserve">
|
||||||
<value>Database successfully saved!</value>
|
<value>Database successfully saved!</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="NewImportFormatHelpCSV" xml:space="preserve">
|
||||||
|
<value>The CSV file needs to be formatted as such: Name of the account;Login;Password;URL;Comments</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@@ -486,4 +486,10 @@
|
|||||||
<data name="NewImportCheckbox.Content" xml:space="preserve">
|
<data name="NewImportCheckbox.Content" xml:space="preserve">
|
||||||
<value>Import existing data</value>
|
<value>Import existing data</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="NewImportFile.Content" xml:space="preserve">
|
||||||
|
<value>Select a file to import...</value>
|
||||||
|
</data>
|
||||||
|
<data name="NewImportFormat.Text" xml:space="preserve">
|
||||||
|
<value>Format</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@@ -255,4 +255,7 @@
|
|||||||
<data name="ToastSavedMessage" xml:space="preserve">
|
<data name="ToastSavedMessage" xml:space="preserve">
|
||||||
<value>Base de données sauvegardée avec succès !</value>
|
<value>Base de données sauvegardée avec succès !</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="NewImportFormatHelpCSV" xml:space="preserve">
|
||||||
|
<value>Le fichier CSV doit être formatté de la façon suivante: Nom du compte;Login;Mot de passe;URL;Commentaires</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@@ -486,4 +486,13 @@
|
|||||||
<data name="NewImportCheckbox.Content" xml:space="preserve">
|
<data name="NewImportCheckbox.Content" xml:space="preserve">
|
||||||
<value>Importer des données existantes</value>
|
<value>Importer des données existantes</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="NewImportFile.Content" xml:space="preserve">
|
||||||
|
<value>Sélectionnez un fichier à importer...</value>
|
||||||
|
</data>
|
||||||
|
<data name="NewImportFormat.Text" xml:space="preserve">
|
||||||
|
<value>Format</value>
|
||||||
|
</data>
|
||||||
|
<data name="NewImportFormatHelp.Text" xml:space="preserve">
|
||||||
|
<value>Le fichier CSV doit être formatté de la façon suivante: Nom du compte;Login;Mot de passe:URL;Commentaires</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@@ -1,7 +1,7 @@
|
|||||||
using System;
|
using Windows.Storage;
|
||||||
using Windows.Storage;
|
|
||||||
using Windows.UI.Xaml.Controls;
|
using Windows.UI.Xaml.Controls;
|
||||||
using ModernKeePass.Converters;
|
using ModernKeePass.Converters;
|
||||||
|
using ModernKeePass.ImportFormats;
|
||||||
using ModernKeePass.Interfaces;
|
using ModernKeePass.Interfaces;
|
||||||
using ModernKeePassLib;
|
using ModernKeePassLib;
|
||||||
|
|
||||||
@@ -9,41 +9,54 @@ namespace ModernKeePass.ViewModels
|
|||||||
{
|
{
|
||||||
public class NewVm : OpenVm
|
public class NewVm : OpenVm
|
||||||
{
|
{
|
||||||
|
private string _importFormatHelp;
|
||||||
public string Password { get; set; }
|
public string Password { get; set; }
|
||||||
|
|
||||||
public bool IsImportChecked { get; set; }
|
public bool IsImportChecked { get; set; }
|
||||||
|
|
||||||
public IStorageFile ImportFile { get; set; }
|
public IStorageFile ImportFile { get; set; }
|
||||||
|
|
||||||
|
public string ImportFileExtensionFilter { get; set; } = "*";
|
||||||
|
|
||||||
public IFormat ImportFormat { get; set; }
|
public IFormat ImportFormat { get; set; }
|
||||||
|
|
||||||
public void PopulateInitialData(IDatabaseService database, ISettingsService settings, IImportService<IFormat> importService)
|
public string ImportFormatHelp
|
||||||
{
|
{
|
||||||
if (settings.GetSetting<bool>("Sample") && !IsImportChecked) CreateSampleData(database);
|
get { return _importFormatHelp; }
|
||||||
else if (IsImportChecked && ImportFile != null) importService.Import(ImportFormat, ImportFile, database);
|
set
|
||||||
|
{
|
||||||
|
_importFormatHelp = value;
|
||||||
|
OnPropertyChanged(nameof(ImportFormatHelp));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CreateSampleData(IDatabaseService database)
|
public void PopulateInitialData(IDatabaseService database, ISettingsService settings, IImportService<IFormat> importService)
|
||||||
|
{
|
||||||
|
if (settings.GetSetting<bool>("Sample") && !IsImportChecked) CreateSampleData(database.RootGroup);
|
||||||
|
else if (IsImportChecked && ImportFile != null && ! (ImportFormat is NullImportFormat)) importService.Import(ImportFormat, ImportFile, database.RootGroup);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateSampleData(GroupVm group)
|
||||||
{
|
{
|
||||||
var converter = new IntToSymbolConverter();
|
var converter = new IntToSymbolConverter();
|
||||||
|
|
||||||
var bankingGroup = database.RootGroup.AddNewGroup("Banking");
|
var bankingGroup = group.AddNewGroup("Banking");
|
||||||
bankingGroup.IconId = (int)converter.ConvertBack(Symbol.Calculator, null, null, string.Empty);
|
bankingGroup.IconId = (int)converter.ConvertBack(Symbol.Calculator, null, null, string.Empty);
|
||||||
|
|
||||||
var emailGroup = database.RootGroup.AddNewGroup("Email");
|
var emailGroup = group.AddNewGroup("Email");
|
||||||
emailGroup.IconId = (int)converter.ConvertBack(Symbol.Mail, null, null, string.Empty);
|
emailGroup.IconId = (int)converter.ConvertBack(Symbol.Mail, null, null, string.Empty);
|
||||||
|
|
||||||
var internetGroup = database.RootGroup.AddNewGroup("Internet");
|
var internetGroup = group.AddNewGroup("Internet");
|
||||||
internetGroup.IconId = (int)converter.ConvertBack(Symbol.World, null, null, string.Empty);
|
internetGroup.IconId = (int)converter.ConvertBack(Symbol.World, null, null, string.Empty);
|
||||||
|
|
||||||
var sample1 = database.RootGroup.AddNewEntry();
|
var sample1 = group.AddNewEntry();
|
||||||
sample1.Name = "Sample Entry";
|
sample1.Name = "Sample Entry";
|
||||||
sample1.UserName = "Username";
|
sample1.UserName = "Username";
|
||||||
sample1.Url = PwDefs.HomepageUrl;
|
sample1.Url = PwDefs.HomepageUrl;
|
||||||
sample1.Password = "Password";
|
sample1.Password = "Password";
|
||||||
sample1.Notes = "You may safely delete this sample";
|
sample1.Notes = "You may safely delete this sample";
|
||||||
|
|
||||||
var sample2 = database.RootGroup.AddNewEntry();
|
var sample2 = group.AddNewEntry();
|
||||||
sample2.Name = "Sample Entry #2";
|
sample2.Name = "Sample Entry #2";
|
||||||
sample2.UserName = "Michael321";
|
sample2.UserName = "Michael321";
|
||||||
sample2.Url = PwDefs.HelpUrl + "kb/testform.html";
|
sample2.Url = PwDefs.HelpUrl + "kb/testform.html";
|
||||||
|
@@ -6,8 +6,6 @@
|
|||||||
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"
|
||||||
xmlns:viewModels="using:ModernKeePass.ViewModels"
|
xmlns:viewModels="using:ModernKeePass.ViewModels"
|
||||||
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
|
|
||||||
xmlns:core="using:Microsoft.Xaml.Interactions.Core"
|
|
||||||
xmlns:userControls="using:ModernKeePass.Views.UserControls"
|
xmlns:userControls="using:ModernKeePass.Views.UserControls"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
<Page.Resources>
|
<Page.Resources>
|
||||||
@@ -18,7 +16,7 @@
|
|||||||
</Page.DataContext>
|
</Page.DataContext>
|
||||||
|
|
||||||
<StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
<StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||||
<HyperlinkButton x:Uid="NewCreateButton" Click="ButtonBase_OnClick" Foreground="{StaticResource MainColor}" Style="{StaticResource MainColorHyperlinkButton}" />
|
<HyperlinkButton x:Uid="NewCreateButton" Click="CreateDatabaseButton_OnClick" Foreground="{StaticResource MainColor}" Style="{StaticResource MainColorHyperlinkButton}" />
|
||||||
<TextBlock Style="{StaticResource BodyTextBlockStyle}" Margin="15,0,0,30" x:Uid="NewCreateDesc" />
|
<TextBlock Style="{StaticResource BodyTextBlockStyle}" Margin="15,0,0,30" x:Uid="NewCreateDesc" />
|
||||||
<Border HorizontalAlignment="Left" BorderThickness="1" BorderBrush="AliceBlue" Width="550" Visibility="{Binding IsFileSelected, Converter={StaticResource BooleanToVisibilityConverter}}">
|
<Border HorizontalAlignment="Left" BorderThickness="1" BorderBrush="AliceBlue" Width="550" Visibility="{Binding IsFileSelected, Converter={StaticResource BooleanToVisibilityConverter}}">
|
||||||
<StackPanel Margin="25,0,25,0">
|
<StackPanel Margin="25,0,25,0">
|
||||||
@@ -26,16 +24,28 @@
|
|||||||
<userControls:CompositeKeyUserControl x:Uid="CompositeKeyNewButton" CreateNew="True" DatabaseFile="{Binding DatabaseFile}" ValidationChecked="CompositeKeyUserControl_OnValidationChecked" />
|
<userControls:CompositeKeyUserControl x:Uid="CompositeKeyNewButton" CreateNew="True" DatabaseFile="{Binding DatabaseFile}" ValidationChecked="CompositeKeyUserControl_OnValidationChecked" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Border>
|
</Border>
|
||||||
<CheckBox x:Name="CheckBox" x:Uid="NewImportCheckbox" IsChecked="{Binding IsImportChecked}" />
|
<CheckBox x:Name="CheckBox" x:Uid="NewImportCheckbox" Margin="15,10,0,0" IsChecked="{Binding IsImportChecked, Mode=TwoWay}" Visibility="{Binding IsFileSelected, Converter={StaticResource BooleanToVisibilityConverter}}" />
|
||||||
<Border HorizontalAlignment="Left" BorderThickness="1" BorderBrush="AliceBlue" Width="550" Visibility="{Binding IsChecked, Converter={StaticResource BooleanToVisibilityConverter}, ElementName=CheckBox}">
|
<Border HorizontalAlignment="Left" BorderThickness="1" BorderBrush="AliceBlue" Width="550" Visibility="{Binding IsChecked, Converter={StaticResource BooleanToVisibilityConverter}, ElementName=CheckBox}">
|
||||||
<StackPanel Margin="25,0,25,0">
|
<StackPanel Margin="25,0,25,0">
|
||||||
<HyperlinkButton Content="Select file..." Style="{StaticResource MainColorHyperlinkButton}" Click="ImportFileButton_OnClick" />
|
<StackPanel Orientation="Horizontal">
|
||||||
<StackPanel>
|
<TextBlock x:Uid="NewImportFormat" Margin="0,15,0,10" Style="{StaticResource BodyTextBlockStyle}" />
|
||||||
<TextBlock Text="Format" Style="{StaticResource BodyTextBlockStyle}" Margin="0,0,0,10" />
|
<ComboBox Style="{StaticResource MainColorComboBox}" Margin="15,15,0,0" SelectionChanged="ImportFormatComboBox_OnSelectionChanged">
|
||||||
<ComboBox Style="{StaticResource MainColorComboBox}" SelectionChanged="Selector_OnSelectionChanged">
|
|
||||||
<ComboBoxItem>CSV</ComboBoxItem>
|
<ComboBoxItem>CSV</ComboBoxItem>
|
||||||
</ComboBox>
|
</ComboBox>
|
||||||
|
<Button Margin="5,10,0,0" Style="{StaticResource TextBlockButtonStyle}">
|
||||||
|
<SymbolIcon Symbol="Help" RenderTransformOrigin="0.5,0.5" >
|
||||||
|
<SymbolIcon.RenderTransform>
|
||||||
|
<CompositeTransform ScaleX="0.7" ScaleY="0.7"/>
|
||||||
|
</SymbolIcon.RenderTransform>
|
||||||
|
</SymbolIcon>
|
||||||
|
<Button.Flyout>
|
||||||
|
<Flyout>
|
||||||
|
<TextBlock Text="{Binding ImportFormatHelp}" TextWrapping="WrapWholeWords" MaxWidth="400" />
|
||||||
|
</Flyout>
|
||||||
|
</Button.Flyout>
|
||||||
|
</Button>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
<HyperlinkButton x:Name="ImportFileLink" x:Uid="NewImportFile" Margin="-15,0,0,0" Style="{StaticResource MainColorHyperlinkButton}" Click="ImportFileButton_OnClick" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Border>
|
</Border>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
@@ -33,7 +33,7 @@ namespace ModernKeePass.Views
|
|||||||
_mainFrame = e.Parameter as Frame;
|
_mainFrame = e.Parameter as Frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void ButtonBase_OnClick(object sender, RoutedEventArgs e)
|
private async void CreateDatabaseButton_OnClick(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
var savePicker = new FileSavePicker
|
var savePicker = new FileSavePicker
|
||||||
{
|
{
|
||||||
@@ -47,6 +47,23 @@ namespace ModernKeePass.Views
|
|||||||
Model.OpenFile(file);
|
Model.OpenFile(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ImportFormatComboBox_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||||
|
{
|
||||||
|
var resources = new ResourcesService();
|
||||||
|
var comboBox = sender as ComboBox;
|
||||||
|
switch (comboBox?.SelectedIndex)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
Model.ImportFormat = new CsvImportFormat();
|
||||||
|
Model.ImportFileExtensionFilter = ".csv";
|
||||||
|
Model.ImportFormatHelp = resources.GetResourceValue("NewImportFormatHelpCSV");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Model.ImportFormat = new NullImportFormat();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async void ImportFileButton_OnClick(object sender, RoutedEventArgs e)
|
private async void ImportFileButton_OnClick(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
var picker =
|
var picker =
|
||||||
@@ -55,31 +72,18 @@ namespace ModernKeePass.Views
|
|||||||
ViewMode = PickerViewMode.List,
|
ViewMode = PickerViewMode.List,
|
||||||
SuggestedStartLocation = PickerLocationId.DocumentsLibrary
|
SuggestedStartLocation = PickerLocationId.DocumentsLibrary
|
||||||
};
|
};
|
||||||
picker.FileTypeFilter.Add(".csv");
|
if (!string.IsNullOrEmpty(Model.ImportFileExtensionFilter))
|
||||||
|
picker.FileTypeFilter.Add(Model.ImportFileExtensionFilter);
|
||||||
|
|
||||||
// Application now has read/write access to the picked file
|
// Application now has read/write access to the picked file
|
||||||
Model.ImportFile = await picker.PickSingleFileAsync();
|
Model.ImportFile = await picker.PickSingleFileAsync();
|
||||||
|
if (Model.ImportFile != null) ImportFileLink.Content = Model.ImportFile.Name;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CompositeKeyUserControl_OnValidationChecked(object sender, PasswordEventArgs e)
|
private void CompositeKeyUserControl_OnValidationChecked(object sender, PasswordEventArgs e)
|
||||||
{
|
{
|
||||||
Model.PopulateInitialData(DatabaseService.Instance, new SettingsService(), new ImportService());
|
Model.PopulateInitialData(DatabaseService.Instance, new SettingsService(), new ImportService());
|
||||||
|
|
||||||
_mainFrame.Navigate(typeof(GroupDetailPage), DatabaseService.Instance.RootGroup);
|
_mainFrame.Navigate(typeof(GroupDetailPage), DatabaseService.Instance.RootGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Selector_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
|
|
||||||
{
|
|
||||||
var comboBox = sender as ComboBox;
|
|
||||||
switch (comboBox?.SelectedIndex)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
Model.ImportFormat = new CsvImportFormat();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
Model.ImportFormat = new NullImportFormat();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -4,9 +4,9 @@
|
|||||||
<package id="HockeySDK.WINRT" version="4.1.6" targetFramework="win81" />
|
<package id="HockeySDK.WINRT" version="4.1.6" targetFramework="win81" />
|
||||||
<package id="Microsoft.Bcl.Build" version="1.0.21" targetFramework="win81" />
|
<package id="Microsoft.Bcl.Build" version="1.0.21" targetFramework="win81" />
|
||||||
<package id="Microsoft.Composition" version="1.0.31" targetFramework="win81" />
|
<package id="Microsoft.Composition" version="1.0.31" targetFramework="win81" />
|
||||||
<package id="Microsoft.NETCore.Platforms" version="2.1.0" targetFramework="win81" />
|
<package id="Microsoft.NETCore.Platforms" version="2.1.1" targetFramework="win81" />
|
||||||
<package id="Microsoft.NETCore.Portable.Compatibility" version="1.0.2" targetFramework="win81" />
|
<package id="Microsoft.NETCore.Portable.Compatibility" version="1.0.2" targetFramework="win81" />
|
||||||
<package id="Microsoft.NETCore.UniversalWindowsPlatform" version="6.1.5" 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="Microsoft.Toolkit.Uwp.Notifications" version="2.0.0" targetFramework="win81" />
|
||||||
<package id="ModernKeePassLib" version="2.39.1" targetFramework="win81" />
|
<package id="ModernKeePassLib" version="2.39.1" targetFramework="win81" />
|
||||||
<package id="NETStandard.Library" version="2.0.3" targetFramework="win81" />
|
<package id="NETStandard.Library" version="2.0.3" targetFramework="win81" />
|
||||||
|
@@ -8,7 +8,7 @@ You can get it [here](https://www.microsoft.com/en-us/store/p/modernkeepass/9mwq
|
|||||||
|
|
||||||
# Features
|
# Features
|
||||||
- Works on Windows 10, 8.1 and RT
|
- Works on Windows 10, 8.1 and RT
|
||||||
- Read and write support of KDBX files version 2, 3 and 4
|
- Full compatibility with classic KeePass databases: read and write support of KDBX files version 2, 3 and 4
|
||||||
- Open database with password and key file
|
- Open database with password and key file
|
||||||
- Create new databases
|
- Create new databases
|
||||||
- Create new key files
|
- Create new key files
|
||||||
@@ -25,6 +25,7 @@ You can get it [here](https://www.microsoft.com/en-us/store/p/modernkeepass/9mwq
|
|||||||
- 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
|
||||||
|
- Import existing CSV data
|
||||||
|
|
||||||
# Build and Test
|
# Build and Test
|
||||||
1. Clone the repository
|
1. Clone the repository
|
||||||
|
Reference in New Issue
Block a user