Major OpenDatabaseUserControl refactor, now has proper ViewModel

Status text and password box border colors are updated according to database status
Update composite key in Settings work
Some code cleanup
This commit is contained in:
2017-11-07 18:45:35 +01:00
committed by BONNEVILLE Geoffroy
parent c3b8c97eea
commit 10a4941b26
24 changed files with 261 additions and 106 deletions

View File

@@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14 # Visual Studio 14
VisualStudioVersion = 14.0.25420.1 VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ModernKeePass", "ModernKeePass\ModernKeePass.csproj", "{A0CFC681-769B-405A-8482-0CDEE595A91F}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ModernKeePassApp", "ModernKeePass\ModernKeePassApp.csproj", "{A0CFC681-769B-405A-8482-0CDEE595A91F}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ModernKeePassLib", "ModernKeePassLib\ModernKeePassLib.csproj", "{2E710089-9559-4967-846C-E763DD1F3ACB}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ModernKeePassLib", "ModernKeePassLib\ModernKeePassLib.csproj", "{2E710089-9559-4967-846C-E763DD1F3ACB}"
EndProject EndProject

View File

@@ -34,3 +34,4 @@ Translation/TrlUtil.vshost.exe.manifest
*.nupkg *.nupkg
.vs/ .vs/
/UpgradeLog.htm /UpgradeLog.htm
ModernKeePass_StoreKey.pfx

View File

@@ -53,8 +53,6 @@ namespace ModernKeePass.Common
} }
} }
public StorageFile KeyFile { get; set; }
public PwUuid DataCipher public PwUuid DataCipher
{ {
get { return _pwDatabase.DataCipherUuid; } get { return _pwDatabase.DataCipherUuid; }
@@ -72,20 +70,18 @@ namespace ModernKeePass.Common
get { return _pwDatabase.KdfParameters; } get { return _pwDatabase.KdfParameters; }
set { _pwDatabase.KdfParameters = value; } set { _pwDatabase.KdfParameters = value; }
} }
/// <summary> /// <summary>
/// Open a KeePass database /// Open a KeePass database
/// </summary> /// </summary>
/// <param name="password">The database password</param> /// <param name="key">The database composite key</param>
/// <param name="createNew">True to create a new database before opening it</param> /// <param name="createNew">True to create a new database before opening it</param>
/// <returns>An error message, if any</returns> /// <returns>An error message, if any</returns>
public string Open(string password, bool createNew = false) public string Open(CompositeKey key, bool createNew = false)
{ {
var key = new CompositeKey();
try try
{ {
if (password != null) key.AddUserKey(new KcpPassword(password)); if (key == null) return "No composite key";
if (KeyFile != null) key.AddUserKey(new KcpKeyFile(IOConnectionInfo.FromFile(KeyFile)));
var ioConnection = IOConnectionInfo.FromFile(DatabaseFile); var ioConnection = IOConnectionInfo.FromFile(DatabaseFile);
if (createNew) _pwDatabase.New(ioConnection, key); if (createNew) _pwDatabase.New(ioConnection, key);
else _pwDatabase.Open(ioConnection, key, new NullStatusLogger()); else _pwDatabase.Open(ioConnection, key, new NullStatusLogger());
@@ -152,5 +148,10 @@ namespace ModernKeePass.Common
RecycleBin.IsSelected = true; RecycleBin.IsSelected = true;
RecycleBin.IconSymbol = Symbol.Delete; RecycleBin.IconSymbol = Symbol.Delete;
} }
public void UpdateCompositeKey(CompositeKey key)
{
_pwDatabase.MasterKey = key;
}
} }
} }

View File

@@ -8,7 +8,7 @@ namespace ModernKeePass.Common
{ {
public event PropertyChangedEventHandler PropertyChanged; public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = "") protected void OnPropertyChanged(string propertyName = "")
{ {
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
} }

View File

@@ -8,16 +8,22 @@
xmlns:core="using:Microsoft.Xaml.Interactions.Core" xmlns:core="using:Microsoft.Xaml.Interactions.Core"
xmlns:actions="using:ModernKeePass.Actions" xmlns:actions="using:ModernKeePass.Actions"
xmlns:converters="using:ModernKeePass.Converters" xmlns:converters="using:ModernKeePass.Converters"
xmlns:viewModels="using:ModernKeePass.ViewModels"
mc:Ignorable="d" mc:Ignorable="d"
d:DesignHeight="120" d:DesignHeight="120"
d:DesignWidth="550" > d:DesignWidth="550" >
<UserControl.Resources> <UserControl.Resources>
<SolidColorBrush x:Key="ErrorColorBrush" Color="Red"/> <SolidColorBrush x:Key="ErrorColorBrush" Color="Red"/>
<converters:ProgressBarLegalValuesConverter x:Key="ProgressBarLegalValuesConverter"/> <converters:ProgressBarLegalValuesConverter x:Key="ProgressBarLegalValuesConverter"/>
<converters:DoubleToForegroungBrushComplexityConverter x:Key="DoubleToForegroungBrushComplexityConverter"/> <converters:DoubleToSolidColorBrushConverter x:Key="DoubleToForegroungBrushConverter"/>
<converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/> <converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
<converters:DiscreteIntToSolidColorBrushConverter x:Key="DiscreteIntToSolidColorBrushConverter"/>
</UserControl.Resources> </UserControl.Resources>
<Grid> <Grid x:Name="Grid">
<!-- DataContext is not set at the root of the control because of issues happening when displaying it -->
<Grid.DataContext>
<viewModels:CompositeKeyVm />
</Grid.DataContext>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="50" /> <ColumnDefinition Width="50" />
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*" />
@@ -27,22 +33,22 @@
<RowDefinition Height="40" /> <RowDefinition Height="40" />
<RowDefinition Height="*" /> <RowDefinition Height="*" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<CheckBox x:Name="PasswordCheckBox" Grid.Row="0" Grid.Column="0" /> <CheckBox Grid.Row="0" Grid.Column="0" IsChecked="{Binding HasPassword, Mode=TwoWay}" />
<PasswordBox Grid.Row="0" Grid.Column="1" x:Name="PasswordBox" PasswordChanged="PasswordBox_OnPasswordChanged" Password="{Binding Password, ElementName=UserControl, Mode=TwoWay}" Height="30" IsEnabled="{Binding IsChecked, ElementName=PasswordCheckBox}" IsPasswordRevealButtonEnabled="True" KeyDown="PasswordBox_KeyDown" PlaceholderText="Password" > <PasswordBox Grid.Row="0" Grid.Column="1" x:Name="PasswordBox" Password="{Binding Password, Mode=TwoWay}" Height="30" IsEnabled="{Binding HasPassword}" IsPasswordRevealButtonEnabled="True" KeyDown="PasswordBox_KeyDown" PlaceholderText="Password" BorderBrush="{Binding StatusType, Converter={StaticResource DiscreteIntToSolidColorBrushConverter}}" >
<interactivity:Interaction.Behaviors> <interactivity:Interaction.Behaviors>
<core:DataTriggerBehavior Binding="{Binding IsChecked, ElementName=PasswordCheckBox}" Value="True"> <core:DataTriggerBehavior Binding="{Binding HasPassword}" Value="True">
<actions:SetupFocusAction TargetObject="{Binding ElementName=PasswordBox}" /> <actions:SetupFocusAction TargetObject="{Binding ElementName=PasswordBox}" />
</core:DataTriggerBehavior> </core:DataTriggerBehavior>
</interactivity:Interaction.Behaviors> </interactivity:Interaction.Behaviors>
</PasswordBox> </PasswordBox>
<ProgressBar x:Name="progressBar" Grid.Row="0" Grid.Column="1" <ProgressBar Grid.Row="0" Grid.Column="1"
Maximum="128" Width="500" VerticalAlignment="Bottom" Maximum="128" VerticalAlignment="Bottom"
Value="{Binding PasswordComplexityIndicator, ElementName=UserControl, ConverterParameter=0\,128, Converter={StaticResource ProgressBarLegalValuesConverter}}" Value="{Binding PasswordComplexityIndicator, ConverterParameter=0\,128, Converter={StaticResource ProgressBarLegalValuesConverter}}"
Foreground="{Binding PasswordComplexityIndicator, ElementName=UserControl, ConverterParameter=128, Converter={StaticResource DoubleToForegroungBrushComplexityConverter}}" Foreground="{Binding PasswordComplexityIndicator, ConverterParameter=128, Converter={StaticResource DoubleToForegroungBrushConverter}}"
Visibility="{Binding CreateNew, ElementName=UserControl, Converter={StaticResource BooleanToVisibilityConverter}}" /> Visibility="{Binding ShowComplexityIndicator, ElementName=UserControl, Converter={StaticResource BooleanToVisibilityConverter}}" />
<CheckBox x:Name="KeyFileCheckBox" Grid.Row="1" Grid.Column="0" /> <CheckBox Grid.Row="1" Grid.Column="0" IsChecked="{Binding HasKeyFile, Mode=TwoWay}" />
<HyperlinkButton Grid.Row="1" Grid.Column="1" Margin="-15,0,0,0" Content="Select key file from disk..." IsEnabled="{Binding IsChecked, ElementName=KeyFileCheckBox}" Click="KeyFileButton_Click" /> <HyperlinkButton Grid.Row="1" Grid.Column="1" Margin="-15,0,0,0" Content="Select key file from disk..." IsEnabled="{Binding HasKeyFile}" Click="KeyFileButton_Click" />
<Button Grid.Column="0" Grid.Row="2" Content="OK" Click="OpenButton_OnClick" Background="{ThemeResource ListViewItemSelectedPointerOverBorderThemeBrush}" Foreground="{ThemeResource TextBoxBackgroundThemeBrush}" /> <Button Grid.Column="0" Grid.Row="2" Content="OK" Click="OpenButton_OnClick" Background="{ThemeResource ListViewItemSelectedPointerOverBorderThemeBrush}" Foreground="{ThemeResource TextBoxBackgroundThemeBrush}" IsEnabled="{Binding IsValid}" />
<TextBlock Grid.Column="1" Grid.Row="2" x:Name="StatusTextBlock" Height="28" FontSize="14" FontWeight="Light" TextWrapping="WrapWholeWords" HorizontalAlignment="Right" /> <TextBlock Grid.Column="1" Grid.Row="2" Height="28" FontSize="14" FontWeight="Light" HorizontalAlignment="Right" Text="{Binding Status}" Foreground="{Binding StatusType, Converter={StaticResource DiscreteIntToSolidColorBrushConverter}}" />
</Grid> </Grid>
</UserControl> </UserControl>

View File

@@ -1,23 +1,19 @@
using System; using System;
using System.ComponentModel;
using Windows.Storage.Pickers; using Windows.Storage.Pickers;
using Windows.System; using Windows.System;
using Windows.UI.Xaml; using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Input;
using ModernKeePass.Common; using ModernKeePass.Common;
using ModernKeePass.Events; using ModernKeePass.Events;
using ModernKeePassLib.Cryptography; using ModernKeePass.ViewModels;
// Pour en savoir plus sur le modèle d'élément Contrôle utilisateur, consultez la page http://go.microsoft.com/fwlink/?LinkId=234236 // Pour en savoir plus sur le modèle d'élément Contrôle utilisateur, consultez la page http://go.microsoft.com/fwlink/?LinkId=234236
namespace ModernKeePass.Controls namespace ModernKeePass.Controls
{ {
public sealed partial class OpenDatabaseUserControl: INotifyPropertyChanged public sealed partial class OpenDatabaseUserControl
{ {
public event PropertyChangedEventHandler PropertyChanged; public CompositeKeyVm Model => Grid.DataContext as CompositeKeyVm;
public double PasswordComplexityIndicator { get; private set; }
public bool CreateNew public bool CreateNew
{ {
@@ -31,22 +27,19 @@ namespace ModernKeePass.Controls
typeof(OpenDatabaseUserControl), typeof(OpenDatabaseUserControl),
new PropertyMetadata(false, (o, args) => { })); new PropertyMetadata(false, (o, args) => { }));
public string Password public bool UpdateKey
{ {
get { return (string) GetValue(PasswordProperty); } get { return (bool)GetValue(UpdateKeyProperty); }
set { SetValue(PasswordProperty, value); } set { SetValue(UpdateKeyProperty, value); }
} }
public static readonly DependencyProperty PasswordProperty = public static readonly DependencyProperty UpdateKeyProperty =
DependencyProperty.Register( DependencyProperty.Register(
"Password", "UpdateKey",
typeof(string), typeof(bool),
typeof(OpenDatabaseUserControl), typeof(OpenDatabaseUserControl),
new PropertyMetadata(string.Empty, (o, args) => { })); new PropertyMetadata(false, (o, args) => { }));
private void NotifyPropertyChanged(string propertyName) public bool ShowComplexityIndicator => CreateNew || UpdateKey;
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public OpenDatabaseUserControl() public OpenDatabaseUserControl()
{ {
@@ -61,26 +54,17 @@ namespace ModernKeePass.Controls
private void OpenButton_OnClick(object sender, RoutedEventArgs e) private void OpenButton_OnClick(object sender, RoutedEventArgs e)
{ {
ValidationChecking?.Invoke(this, new EventArgs()); ValidationChecking?.Invoke(this, new EventArgs());
var app = (App)Application.Current;
StatusTextBlock.Text = app.Database.Open(PasswordCheckBox.IsChecked.HasValue && PasswordCheckBox.IsChecked.Value ? PasswordBox.Password : null, CreateNew); if (UpdateKey) Model.UpdateKey();
if (app.Database.Status == DatabaseHelper.DatabaseStatus.Opened) else if (Model.OpenDatabase(CreateNew) == DatabaseHelper.DatabaseStatus.Opened)
{ {
ValidationChecked?.Invoke(this, new PasswordEventArgs(app.Database.RootGroup)); ValidationChecked?.Invoke(this, new PasswordEventArgs(Model.RootGroup));
}
else
{
VisualStateManager.GoToState(PasswordBox, "Error", true);
} }
} }
private void PasswordBox_KeyDown(object sender, KeyRoutedEventArgs e) private void PasswordBox_KeyDown(object sender, KeyRoutedEventArgs e)
{ {
if (e.Key == VirtualKey.Enter) OpenButton_OnClick(null, null); if (e.Key == VirtualKey.Enter) OpenButton_OnClick(null, null);
else
{
VisualStateManager.GoToState(PasswordBox, "Normal", true);
StatusTextBlock.Text = string.Empty;
}
} }
private async void KeyFileButton_Click(object sender, RoutedEventArgs e) private async void KeyFileButton_Click(object sender, RoutedEventArgs e)
@@ -94,18 +78,7 @@ namespace ModernKeePass.Controls
picker.FileTypeFilter.Add(".key"); picker.FileTypeFilter.Add(".key");
// Application now has read/write access to the picked file // Application now has read/write access to the picked file
var file = await picker.PickSingleFileAsync(); Model.KeyFile = await picker.PickSingleFileAsync();
if (file == null) return;
var app = (App)Application.Current;
app.Database.KeyFile = file;
StatusTextBlock.Text = $"Key file: {file.Name}";
}
private void PasswordBox_OnPasswordChanged(object sender, RoutedEventArgs e)
{
var passwordBox = sender as PasswordBox;
PasswordComplexityIndicator = QualityEstimation.EstimatePasswordBits(passwordBox?.Password.ToCharArray());
NotifyPropertyChanged("PasswordComplexityIndicator");
} }
} }
} }

View File

@@ -0,0 +1,27 @@
using System;
using Windows.UI;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Media;
namespace ModernKeePass.Converters
{
public class DiscreteIntToSolidColorBrushConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
var status = System.Convert.ToInt32(value);
switch (status)
{
case 1: return new SolidColorBrush(Colors.Red);
case 3: return new SolidColorBrush(Colors.Yellow);
case 5: return new SolidColorBrush(Colors.Green);
default: return new SolidColorBrush(Colors.Black);
}
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
}

View File

@@ -5,7 +5,7 @@ using Windows.UI.Xaml.Media;
namespace ModernKeePass.Converters namespace ModernKeePass.Converters
{ {
public class DoubleToForegroungBrushComplexityConverter : IValueConverter public class DoubleToSolidColorBrushConverter : IValueConverter
{ {
public object Convert(object value, Type targetType, object parameter, string language) public object Convert(object value, Type targetType, object parameter, string language)
{ {
@@ -21,7 +21,6 @@ namespace ModernKeePass.Converters
{ {
return new SolidColorBrush(Color.FromArgb(255, 0, byte.MaxValue, 0)); return new SolidColorBrush(Color.FromArgb(255, 0, byte.MaxValue, 0));
} }
} }
public object ConvertBack(object value, Type targetType, object parameter, string language) public object ConvertBack(object value, Type targetType, object parameter, string language)

View File

@@ -121,6 +121,7 @@
<Compile Include="Common\RelayCommand.cs" /> <Compile Include="Common\RelayCommand.cs" />
<Compile Include="Common\SuspensionManager.cs" /> <Compile Include="Common\SuspensionManager.cs" />
<Compile Include="Common\ToastNotificationHelper.cs" /> <Compile Include="Common\ToastNotificationHelper.cs" />
<Compile Include="Converters\DiscreteIntToSolidColorBrushConverter.cs" />
<Compile Include="Converters\NullToBooleanConverter.cs" /> <Compile Include="Converters\NullToBooleanConverter.cs" />
<Compile Include="Interfaces\IHasSelectableObject.cs" /> <Compile Include="Interfaces\IHasSelectableObject.cs" />
<Compile Include="Interfaces\ISelectableModel.cs" /> <Compile Include="Interfaces\ISelectableModel.cs" />
@@ -128,6 +129,9 @@
<Compile Include="Pages\SettingsPageFrames\SettingsDatabasePage.xaml.cs"> <Compile Include="Pages\SettingsPageFrames\SettingsDatabasePage.xaml.cs">
<DependentUpon>SettingsDatabasePage.xaml</DependentUpon> <DependentUpon>SettingsDatabasePage.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="Pages\SettingsPageFrames\SettingsSecurityPage.xaml.cs">
<DependentUpon>SettingsSecurityPage.xaml</DependentUpon>
</Compile>
<Compile Include="TemplateSelectors\FirstItemDataTemplateSelector.cs" /> <Compile Include="TemplateSelectors\FirstItemDataTemplateSelector.cs" />
<Compile Include="Controls\ListViewWithDisable.cs" /> <Compile Include="Controls\ListViewWithDisable.cs" />
<Compile Include="Controls\OpenDatabaseUserControl.xaml.cs"> <Compile Include="Controls\OpenDatabaseUserControl.xaml.cs">
@@ -136,7 +140,7 @@
<Compile Include="Controls\TextBoxWithButton.cs" /> <Compile Include="Controls\TextBoxWithButton.cs" />
<Compile Include="Converters\BooleanToVisibilityConverter.cs" /> <Compile Include="Converters\BooleanToVisibilityConverter.cs" />
<Compile Include="Converters\ColorToBrushConverter.cs" /> <Compile Include="Converters\ColorToBrushConverter.cs" />
<Compile Include="Converters\DoubleToForegroungBrushComplexityConverter.cs" /> <Compile Include="Converters\DoubleToSolidColorBrushConverter.cs" />
<Compile Include="Converters\InverseBooleanToVisibilityConverter.cs" /> <Compile Include="Converters\InverseBooleanToVisibilityConverter.cs" />
<Compile Include="Converters\BooleanToFontStyleConverter.cs" /> <Compile Include="Converters\BooleanToFontStyleConverter.cs" />
<Compile Include="Converters\PluralizationConverter.cs" /> <Compile Include="Converters\PluralizationConverter.cs" />
@@ -162,6 +166,7 @@
<DependentUpon>WelcomePage.xaml</DependentUpon> <DependentUpon>WelcomePage.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="ViewModels\AboutVm.cs" /> <Compile Include="ViewModels\AboutVm.cs" />
<Compile Include="ViewModels\CompositeKeyVm.cs" />
<Compile Include="ViewModels\Items\ListMenuItemVm.cs" /> <Compile Include="ViewModels\Items\ListMenuItemVm.cs" />
<Compile Include="ViewModels\Items\MainMenuItemVm.cs" /> <Compile Include="ViewModels\Items\MainMenuItemVm.cs" />
<Compile Include="ViewModels\Items\RecentItemVm.cs" /> <Compile Include="ViewModels\Items\RecentItemVm.cs" />
@@ -183,13 +188,13 @@
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ViewModels\EntryVm.cs" /> <Compile Include="ViewModels\EntryVm.cs" />
<Compile Include="ViewModels\GroupVm.cs" /> <Compile Include="ViewModels\GroupVm.cs" />
<Compile Include="ViewModels\Items\SettingsVM.cs" /> <Compile Include="ViewModels\SettingsVm.cs" />
<Compile Include="ViewModels\MainVm.cs" /> <Compile Include="ViewModels\MainVm.cs" />
<Compile Include="ViewModels\NewVm.cs" /> <Compile Include="ViewModels\NewVm.cs" />
<Compile Include="ViewModels\OpenVm.cs" /> <Compile Include="ViewModels\OpenVm.cs" />
<Compile Include="ViewModels\RecentVm.cs" /> <Compile Include="ViewModels\RecentVm.cs" />
<Compile Include="ViewModels\SaveVm.cs" /> <Compile Include="ViewModels\SaveVm.cs" />
<Compile Include="ViewModels\SettingsDatabaseVm.cs" /> <Compile Include="ViewModels\Items\SettingsDatabaseVm.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<AppxManifest Include="Package.appxmanifest"> <AppxManifest Include="Package.appxmanifest">
@@ -257,6 +262,10 @@
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>
<Page Include="Pages\SettingsPageFrames\SettingsSecurityPage.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Styles\HamburgerButtonStyle.xaml"> <Page Include="Styles\HamburgerButtonStyle.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>

View File

@@ -0,0 +1,3 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeInspection/CSharpLanguageProject/LanguageLevel/@EntryValue">CSharp70</s:String>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=viewmodels_005Citems/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

View File

@@ -16,7 +16,7 @@
<converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/> <converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
<converters:InverseBooleanToVisibilityConverter x:Key="InverseBooleanToVisibilityConverter"/> <converters:InverseBooleanToVisibilityConverter x:Key="InverseBooleanToVisibilityConverter"/>
<converters:ProgressBarLegalValuesConverter x:Key="ProgressBarLegalValuesConverter"/> <converters:ProgressBarLegalValuesConverter x:Key="ProgressBarLegalValuesConverter"/>
<converters:DoubleToForegroungBrushComplexityConverter x:Key="DoubleToForegroungBrushComplexityConverter"/> <converters:DoubleToSolidColorBrushConverter x:Key="DoubleToForegroungBrushComplexityConverter"/>
<converters:NullToBooleanConverter x:Key="NullToBooleanConverter"/> <converters:NullToBooleanConverter x:Key="NullToBooleanConverter"/>
<Style TargetType="PasswordBox" x:Name="PasswordBoxWithButtonStyle"> <Style TargetType="PasswordBox" x:Name="PasswordBoxWithButtonStyle">
<Setter Property="MinWidth" Value="{ThemeResource TextControlThemeMinWidth}" /> <Setter Property="MinWidth" Value="{ThemeResource TextControlThemeMinWidth}" />

View File

@@ -23,7 +23,7 @@
<Border HorizontalAlignment="Left" BorderThickness="1" BorderBrush="AliceBlue" Width="550" Visibility="{Binding ShowPasswordBox, Converter={StaticResource BooleanToVisibilityConverter}}"> <Border HorizontalAlignment="Left" BorderThickness="1" BorderBrush="AliceBlue" Width="550" Visibility="{Binding ShowPasswordBox, Converter={StaticResource BooleanToVisibilityConverter}}">
<StackPanel Margin="25,0,25,0"> <StackPanel Margin="25,0,25,0">
<TextBlock Text="{Binding Name}" /> <TextBlock Text="{Binding Name}" />
<local:OpenDatabaseUserControl Password="{Binding Password, Mode=TwoWay}" CreateNew="True" > <local:OpenDatabaseUserControl CreateNew="True" >
<interactivity:Interaction.Behaviors> <interactivity:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="ValidationChecked"> <core:EventTriggerBehavior EventName="ValidationChecked">
<core:NavigateToPageAction TargetPage="ModernKeePass.Pages.GroupDetailPage" /> <core:NavigateToPageAction TargetPage="ModernKeePass.Pages.GroupDetailPage" />

View File

@@ -34,7 +34,7 @@
</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" />
<local:OpenDatabaseUserControl Grid.Row="2" x:Name="DatabaseUserControl" HorizontalAlignment="Stretch" MinWidth="400" Margin="0,10,0,0" Visibility="{Binding IsSelected, Converter={StaticResource BooleanToVisibilityConverter}}" ValidationChecking="OpenDatabaseUserControl_OnValidationChecking" > <local:OpenDatabaseUserControl Grid.Row="2" x:Name="DatabaseUserControl" HorizontalAlignment="Stretch" MinWidth="400" Margin="0,10,0,0" Visibility="{Binding IsSelected, Converter={StaticResource BooleanToVisibilityConverter}}" ValidationChecking="OpenDatabaseUserControl_OnValidationChecking">
<interactivity:Interaction.Behaviors> <interactivity:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="ValidationChecked"> <core:EventTriggerBehavior EventName="ValidationChecked">
<core:NavigateToPageAction TargetPage="ModernKeePass.Pages.GroupDetailPage" /> <core:NavigateToPageAction TargetPage="ModernKeePass.Pages.GroupDetailPage" />

View File

@@ -1,10 +1,8 @@
using System; // Pour en savoir plus sur le modèle d'élément Page vierge, consultez la page http://go.microsoft.com/fwlink/?LinkId=234238
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
using ModernKeePass.ViewModels;
// Pour en savoir plus sur le modèle d'élément Page vierge, consultez la page http://go.microsoft.com/fwlink/?LinkId=234238 using System;
using Windows.UI.Xaml;
using ModernKeePass.ViewModels;
namespace ModernKeePass.Pages namespace ModernKeePass.Pages
{ {
@@ -13,25 +11,17 @@ namespace ModernKeePass.Pages
/// </summary> /// </summary>
public sealed partial class RecentDatabasesPage public sealed partial class RecentDatabasesPage
{ {
private Frame _mainFrame;
public RecentVm Model => (RecentVm)DataContext; public RecentVm Model => (RecentVm)DataContext;
public RecentDatabasesPage() public RecentDatabasesPage()
{ {
InitializeComponent(); InitializeComponent();
} }
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
_mainFrame = e.Parameter as Frame;
}
private void OpenDatabaseUserControl_OnValidationChecking(object sender, EventArgs e) private void OpenDatabaseUserControl_OnValidationChecking(object sender, EventArgs e)
{ {
var app = (App)Application.Current; var app = (App)Application.Current;
app.Database.DatabaseFile = Model.SelectedItem.DatabaseFile; app.Database.DatabaseFile = ((RecentItemVm)Model.SelectedItem).DatabaseFile;
} }
} }
} }

View File

@@ -0,0 +1,14 @@
<Page
x:Class="ModernKeePass.Pages.SettingsSecurityPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:ModernKeePass.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<TextBlock Text="Change database security options" />
<local:OpenDatabaseUserControl UpdateKey="True" />
</StackPanel>
</Page>

View File

@@ -0,0 +1,15 @@
// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238
namespace ModernKeePass.Pages
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class SettingsSecurityPage
{
public SettingsSecurityPage()
{
InitializeComponent();
}
}
}

View File

@@ -0,0 +1,113 @@
using Windows.Storage;
using Windows.UI.Xaml;
using ModernKeePass.Common;
using ModernKeePassLib.Cryptography;
using ModernKeePassLib.Keys;
using ModernKeePassLib.Serialization;
namespace ModernKeePass.ViewModels
{
public class CompositeKeyVm: NotifyPropertyChangedBase
{
public enum StatusTypes
{
Normal = 0,
Error = 1,
Warning = 3,
Success = 5
}
private readonly App _app = Application.Current as App;
private bool _hasPassword;
private bool _hasKeyFile;
private string _password;
private string _status;
private StatusTypes _statusType;
private StorageFile _keyFile;
public bool HasPassword
{
get { return _hasPassword; }
set
{
SetProperty(ref _hasPassword, value);
OnPropertyChanged("IsValid");
}
}
public bool HasKeyFile
{
get { return _hasKeyFile; }
set
{
SetProperty(ref _hasKeyFile, value);
OnPropertyChanged("IsValid");
}
}
public bool IsValid => HasPassword || HasKeyFile;
public string Status
{
get { return _status; }
set { SetProperty(ref _status, value); }
}
public int StatusType
{
get { return (int)_statusType; }
set { SetProperty(ref _statusType, (StatusTypes)value); }
}
public string Password
{
get { return _password; }
set
{
_password = value;
OnPropertyChanged("PasswordComplexityIndicator");
StatusType = (int)StatusTypes.Normal;
}
}
public StorageFile KeyFile
{
get { return _keyFile; }
set
{
_keyFile = value;
UpdateStatus($"Key file: {value.Name}", StatusTypes.Normal);
}
}
public GroupVm RootGroup { get; set; }
public double PasswordComplexityIndicator => QualityEstimation.EstimatePasswordBits(Password?.ToCharArray());
public DatabaseHelper.DatabaseStatus OpenDatabase(bool createNew)
{
UpdateStatus(_app.Database.Open(CreateCompositeKey(), createNew), StatusTypes.Error);
RootGroup = _app.Database.RootGroup;
return _app.Database.Status;
}
public void UpdateKey()
{
_app.Database.UpdateCompositeKey(CreateCompositeKey());
UpdateStatus("Database composite key updated.", StatusTypes.Success);
}
private void UpdateStatus(string text, StatusTypes type)
{
Status = text;
StatusType = (int)type;
}
private CompositeKey CreateCompositeKey()
{
var compositeKey = new CompositeKey();
if (HasPassword) compositeKey.AddUserKey(new KcpPassword(Password));
if (HasKeyFile) compositeKey.AddUserKey(new KcpKeyFile(IOConnectionInfo.FromFile(KeyFile)));
return compositeKey;
}
}
}

View File

@@ -150,7 +150,7 @@ namespace ModernKeePass.ViewModels
public event PropertyChangedEventHandler PropertyChanged; public event PropertyChangedEventHandler PropertyChanged;
private readonly PwEntry _pwEntry; private readonly PwEntry _pwEntry;
private readonly App _app = (App)Application.Current; private readonly App _app = Application.Current as App;
private bool _isEditMode; private bool _isEditMode;
private bool _isRevealPassword; private bool _isRevealPassword;
private double _passwordLength = 25; private double _passwordLength = 25;

View File

@@ -86,7 +86,7 @@ namespace ModernKeePass.ViewModels
} }
private readonly PwGroup _pwGroup; private readonly PwGroup _pwGroup;
private readonly App _app = (App)Application.Current; private readonly App _app = Application.Current as App;
private bool _isEditMode; private bool _isEditMode;
public GroupVm() {} public GroupVm() {}

View File

@@ -1,13 +1,15 @@
using Windows.Storage; using Windows.Storage;
using ModernKeePass.Common; using ModernKeePass.Common;
using Windows.Storage.AccessCache; using Windows.Storage.AccessCache;
using ModernKeePass.Interfaces;
namespace ModernKeePass.ViewModels namespace ModernKeePass.ViewModels
{ {
public class RecentItemVm: NotifyPropertyChangedBase public class RecentItemVm: NotifyPropertyChangedBase, ISelectableModel
{ {
private bool _isSelected; private bool _isSelected;
public RecentItemVm() {}
public RecentItemVm(AccessListEntry entry, StorageFile file) public RecentItemVm(AccessListEntry entry, StorageFile file)
{ {
Token = entry.Token; Token = entry.Token;
@@ -15,15 +17,15 @@ namespace ModernKeePass.ViewModels
DatabaseFile = file; DatabaseFile = file;
} }
public StorageFile DatabaseFile { get; private set; } public StorageFile DatabaseFile { get; }
public string Token { get; private set; } public string Token { get; }
public string Name { get; private set; } = "Recent file"; public string Name { get; }
public string Path => DatabaseFile.Path; public string Path => DatabaseFile?.Path;
public bool IsSelected public bool IsSelected
{ {
get { return _isSelected; } get { return _isSelected; }
internal set { SetProperty(ref _isSelected, value); } set { SetProperty(ref _isSelected, value); }
} }
} }
} }

View File

@@ -14,7 +14,7 @@ namespace ModernKeePass.ViewModels
{ {
public class SettingsDatabaseVm: NotifyPropertyChangedBase, IHasSelectableObject public class SettingsDatabaseVm: NotifyPropertyChangedBase, IHasSelectableObject
{ {
private readonly App _app = (App)Application.Current; private readonly App _app = Application.Current as App;
private readonly ApplicationDataContainer _localSettings = ApplicationData.Current.LocalSettings; private readonly ApplicationDataContainer _localSettings = ApplicationData.Current.LocalSettings;
private GroupVm _selectedItem; private GroupVm _selectedItem;

View File

@@ -20,9 +20,9 @@ namespace ModernKeePass.ViewModels
public OpenVm() public OpenVm()
{ {
var database = ((App)Application.Current).Database; var app = Application.Current as App;
if (database == null || database.Status != DatabaseHelper.DatabaseStatus.Opening) return; if (app?.Database == null || app.Database.Status != DatabaseHelper.DatabaseStatus.Opening) return;
OpenFile(database.DatabaseFile); OpenFile(app.Database.DatabaseFile);
} }
public event PropertyChangedEventHandler PropertyChanged; public event PropertyChangedEventHandler PropertyChanged;

View File

@@ -2,12 +2,13 @@
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using Windows.Storage.AccessCache; using Windows.Storage.AccessCache;
using ModernKeePass.Common; using ModernKeePass.Common;
using ModernKeePass.Interfaces;
namespace ModernKeePass.ViewModels namespace ModernKeePass.ViewModels
{ {
public class RecentVm : NotifyPropertyChangedBase public class RecentVm : NotifyPropertyChangedBase, IHasSelectableObject
{ {
private RecentItemVm _selectedItem; private ISelectableModel _selectedItem;
private ObservableCollection<RecentItemVm> _recentItems = new ObservableCollection<RecentItemVm>(); private ObservableCollection<RecentItemVm> _recentItems = new ObservableCollection<RecentItemVm>();
public ObservableCollection<RecentItemVm> RecentItems public ObservableCollection<RecentItemVm> RecentItems
@@ -16,7 +17,7 @@ namespace ModernKeePass.ViewModels
set { SetProperty(ref _recentItems, value); } set { SetProperty(ref _recentItems, value); }
} }
public RecentItemVm SelectedItem public ISelectableModel SelectedItem
{ {
get { return _selectedItem; } get { return _selectedItem; }
set set

View File

@@ -37,6 +37,7 @@ namespace ModernKeePass.ViewModels
MenuItems = new ObservableCollection<ListMenuItemVm> MenuItems = new ObservableCollection<ListMenuItemVm>
{ {
new ListMenuItemVm { Title = "Database", SymbolIcon = Symbol.Setting, PageType = typeof(SettingsDatabasePage), IsSelected = true }, new ListMenuItemVm { Title = "Database", SymbolIcon = Symbol.Setting, PageType = typeof(SettingsDatabasePage), IsSelected = true },
new ListMenuItemVm { Title = "Security", SymbolIcon = Symbol.Permissions, PageType = typeof(SettingsSecurityPage) },
//new ListMenuItemVm { Title = "General", SymbolIcon = Symbol.Edit, PageType = typeof(SettingsGeneralPage) } //new ListMenuItemVm { Title = "General", SymbolIcon = Symbol.Edit, PageType = typeof(SettingsGeneralPage) }
}; };
SelectedItem = MenuItems.FirstOrDefault(m => m.IsSelected); SelectedItem = MenuItems.FirstOrDefault(m => m.IsSelected);