TextBoxWithButton control correctly updates field value

Create Group now allows inline input of the group name
This commit is contained in:
Geoffroy BONNEVILLE
2020-05-05 15:27:34 +02:00
parent 2f30389f6c
commit 5ce0262318
8 changed files with 91 additions and 27 deletions

View File

@@ -291,7 +291,7 @@
TextWrapping="NoWrap" TextWrapping="NoWrap"
VerticalAlignment="Stretch" VerticalAlignment="Stretch"
Margin="0" Margin="0"
Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay, Path=Text}" /> Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay, Path=Text, UpdateSourceTrigger=PropertyChanged}" />
<Button x:Name="ActionButton" <Button x:Name="ActionButton"
AutomationProperties.AccessibilityView="Raw" AutomationProperties.AccessibilityView="Raw"
Background="Transparent" Background="Transparent"
@@ -301,7 +301,8 @@
Style="{StaticResource ActionButtonStyle}" Style="{StaticResource ActionButtonStyle}"
Content="{TemplateBinding ButtonSymbol}" Content="{TemplateBinding ButtonSymbol}"
IsEnabled="{TemplateBinding IsButtonEnabled}" IsEnabled="{TemplateBinding IsButtonEnabled}"
Command="{TemplateBinding ButtonCommand}"> Command="{TemplateBinding ButtonCommand}"
CommandParameter="{TemplateBinding ButtonCommandParameter}">
<ToolTipService.ToolTip> <ToolTipService.ToolTip>
<ToolTip Content="{TemplateBinding ButtonTooltip}" /> <ToolTip Content="{TemplateBinding ButtonTooltip}" />
</ToolTipService.ToolTip> </ToolTipService.ToolTip>

View File

@@ -513,4 +513,7 @@
<data name="SettingsSaveDatabaseSuspendDesc.Text" xml:space="preserve"> <data name="SettingsSaveDatabaseSuspendDesc.Text" xml:space="preserve">
<value>This settings is generally recommended. If you enable it, database will automatically be saved on application suspension and closing, provided your database is less than 1MB big. Saving bigger databases may take too long and Windows may then forcibly kill the app before saving is finished, resulting in your changes not being saved.</value> <value>This settings is generally recommended. If you enable it, database will automatically be saved on application suspension and closing, provided your database is less than 1MB big. Saving bigger databases may take too long and Windows may then forcibly kill the app before saving is finished, resulting in your changes not being saved.</value>
</data> </data>
<data name="NewGroupTextBox" xml:space="preserve">
<value>New group name</value>
</data>
</root> </root>

View File

@@ -516,4 +516,7 @@
<data name="CompositeKeyConfirmPassword.PlaceholderText" xml:space="preserve"> <data name="CompositeKeyConfirmPassword.PlaceholderText" xml:space="preserve">
<value>Confirmer le mot de passe</value> <value>Confirmer le mot de passe</value>
</data> </data>
<data name="NewGroupTextBox" xml:space="preserve">
<value>Nom du groupe</value>
</data>
</root> </root>

View File

@@ -1,5 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.Linq; using System.Linq;
@@ -27,7 +26,6 @@ using ModernKeePass.Application.Group.Commands.SortGroups;
using ModernKeePass.Application.Group.Commands.UpdateGroup; using ModernKeePass.Application.Group.Commands.UpdateGroup;
using ModernKeePass.Application.Group.Models; using ModernKeePass.Application.Group.Models;
using ModernKeePass.Application.Group.Queries.GetGroup; using ModernKeePass.Application.Group.Queries.GetGroup;
using ModernKeePass.Application.Group.Queries.SearchEntries;
using ModernKeePass.Common; using ModernKeePass.Common;
using ModernKeePass.Domain.Enums; using ModernKeePass.Domain.Enums;
using ModernKeePass.Domain.Exceptions; using ModernKeePass.Domain.Exceptions;
@@ -92,7 +90,7 @@ namespace ModernKeePass.ViewModels
public RelayCommand SortGroupsCommand { get; } public RelayCommand SortGroupsCommand { get; }
public RelayCommand<string> MoveCommand { get; } public RelayCommand<string> MoveCommand { get; }
public RelayCommand CreateEntryCommand { get; } public RelayCommand CreateEntryCommand { get; }
public RelayCommand CreateGroupCommand { get; } public RelayCommand<string> CreateGroupCommand { get; }
public RelayCommand DeleteCommand { get; set; } public RelayCommand DeleteCommand { get; set; }
public RelayCommand GoBackCommand { get; set; } public RelayCommand GoBackCommand { get; set; }
public RelayCommand GoToParentCommand { get; set; } public RelayCommand GoToParentCommand { get; set; }
@@ -122,7 +120,7 @@ namespace ModernKeePass.ViewModels
SortGroupsCommand = new RelayCommand(async () => await SortGroupsAsync(), () => IsEditMode); SortGroupsCommand = new RelayCommand(async () => await SortGroupsAsync(), () => IsEditMode);
MoveCommand = new RelayCommand<string>(async destination => await Move(destination), destination => IsNotRoot && !string.IsNullOrEmpty(destination) && destination != Id); MoveCommand = new RelayCommand<string>(async destination => await Move(destination), destination => IsNotRoot && !string.IsNullOrEmpty(destination) && destination != Id);
CreateEntryCommand = new RelayCommand(async () => await AddNewEntry(), () => !IsInRecycleBin && Database.RecycleBinId != Id); CreateEntryCommand = new RelayCommand(async () => await AddNewEntry(), () => !IsInRecycleBin && Database.RecycleBinId != Id);
CreateGroupCommand = new RelayCommand(async () => await AddNewGroup(), () => !IsInRecycleBin && Database.RecycleBinId != Id); CreateGroupCommand = new RelayCommand<string>(async newGroupName => await AddNewGroup(newGroupName), _ => !IsInRecycleBin && Database.RecycleBinId != Id);
DeleteCommand = new RelayCommand(async () => await AskForDelete(),() => IsNotRoot); DeleteCommand = new RelayCommand(async () => await AskForDelete(),() => IsNotRoot);
GoBackCommand = new RelayCommand(() => _navigation.GoBack()); GoBackCommand = new RelayCommand(() => _navigation.GoBack());
GoToParentCommand= new RelayCommand(() => GoToGroup(_parent.Id), () => _parent != null); GoToParentCommand= new RelayCommand(() => GoToGroup(_parent.Id), () => _parent != null);
@@ -163,7 +161,7 @@ namespace ModernKeePass.ViewModels
public async Task AddNewGroup(string name = "") public async Task AddNewGroup(string name = "")
{ {
var group = await _mediator.Send(new CreateGroupCommand {Name = name, ParentGroup = _group}); var group = await _mediator.Send(new CreateGroupCommand {Name = name, ParentGroup = _group});
GoToGroup(group.Id, true); Groups.Add(group);
} }
public async Task AddNewEntry() public async Task AddNewEntry()

View File

@@ -8,6 +8,8 @@
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"
xmlns:actions="using:ModernKeePass.Actions"
xmlns:controls="using:ModernKeePass.Controls"
mc:Ignorable="d"> mc:Ignorable="d">
<UserControl.Resources> <UserControl.Resources>
<converters:IconToSymbolConverter x:Key="IconToSymbolConverter"/> <converters:IconToSymbolConverter x:Key="IconToSymbolConverter"/>
@@ -111,19 +113,18 @@
<ListView.ItemTemplateSelector> <ListView.ItemTemplateSelector>
<templateSelectors:SelectableDataTemplateSelector FalseItem="{StaticResource IsNormal}" TrueItem="{StaticResource IsSpecial}" /> <templateSelectors:SelectableDataTemplateSelector FalseItem="{StaticResource IsNormal}" TrueItem="{StaticResource IsSpecial}" />
</ListView.ItemTemplateSelector> </ListView.ItemTemplateSelector>
<ListView.FooterTemplate> <ListView.HeaderTemplate>
<DataTemplate> <DataTemplate>
<StackPanel Orientation="Vertical"> <StackPanel Orientation="Vertical" Visibility="{Binding IsButtonVisible, ElementName=UserControl}">
<Border BorderBrush="DarkGray" BorderThickness="0,0,0,1" /> <Button x:Name="NewGroupButton"
<Button Padding="0" Margin="0" Padding="0" Margin="0"
Height="{StaticResource MenuWidth}" Height="{StaticResource MenuWidth}"
Visibility="{Binding IsButtonVisible, ElementName=UserControl}" Visibility="{Binding IsButtonVisible, ElementName=UserControl}"
Style="{StaticResource NoBorderButtonStyle}" Style="{StaticResource NoBorderButtonStyle}"
Background="Transparent" Background="Transparent"
BorderThickness="0" BorderThickness="0"
Width="{StaticResource ExpandedMenuSize}" Width="{StaticResource ExpandedMenuSize}"
HorizontalContentAlignment="Left" HorizontalContentAlignment="Left">
Command="{Binding ActionButtonCommand, ElementName=UserControl}">
<StackPanel Orientation="Horizontal" Margin="17,0,5,0"> <StackPanel Orientation="Horizontal" Margin="17,0,5,0">
<SymbolIcon Symbol="Add"> <SymbolIcon Symbol="Add">
<ToolTipService.ToolTip> <ToolTipService.ToolTip>
@@ -132,7 +133,42 @@
</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="30,0,20,0" />
</StackPanel> </StackPanel>
<interactivity:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="Click">
<core:ChangePropertyAction TargetObject="{Binding ElementName=NewGroupTextBox}" PropertyName="Visibility" Value="Visible" />
<core:ChangePropertyAction TargetObject="{Binding ElementName=NewGroupButton}" PropertyName="Visibility" Value="Collapsed" />
<actions:SetupFocusAction TargetObject="{Binding ElementName=NewGroupTextBox}" />
</core:EventTriggerBehavior>
</interactivity:Interaction.Behaviors>
</Button> </Button>
<controls:TextBoxWithButton
x:Uid="NewGroupTextBox"
x:Name="NewGroupTextBox"
Margin="0,5,0,5"
Visibility="Collapsed"
Width="280"
HorizontalAlignment="Center"
ButtonCommand="{Binding ActionButtonCommand, ElementName=UserControl}"
ButtonCommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=Text}"
Style="{StaticResource TextBoxWithButtonStyle}"
KeyDown="NewGroupTextBox_OnKeyDown"
ButtonSymbol="&#xE111;">
<interactivity:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="LostFocus">
<core:ChangePropertyAction TargetObject="{Binding ElementName=NewGroupButton}" PropertyName="Visibility" Value="Visible" />
<core:ChangePropertyAction TargetObject="{Binding ElementName=NewGroupTextBox}" PropertyName="Visibility" Value="Collapsed" />
<core:ChangePropertyAction TargetObject="{Binding ElementName=NewGroupTextBox}" PropertyName="Text" Value="" />
</core:EventTriggerBehavior>
</interactivity:Interaction.Behaviors>
</controls:TextBoxWithButton>
<Border BorderBrush="DarkGray" BorderThickness="0,0,0,1" />
</StackPanel>
</DataTemplate>
</ListView.HeaderTemplate>
<ListView.FooterTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<Border BorderBrush="DarkGray" BorderThickness="0,0,0,1" />
<Button Padding="0" Margin="0" <Button Padding="0" Margin="0"
Height="{StaticResource MenuWidth}" Height="{StaticResource MenuWidth}"
Style="{StaticResource NoBorderButtonStyle}" Style="{StaticResource NoBorderButtonStyle}"

View File

@@ -1,9 +1,12 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Windows.Input; using System.Windows.Input;
using Windows.System;
using Windows.UI.Xaml; using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;
using ModernKeePass.Application.Common.Interfaces; using ModernKeePass.Application.Common.Interfaces;
using ModernKeePass.Controls;
// The User Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234236 // The User Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234236
@@ -11,11 +14,6 @@ namespace ModernKeePass.Views.UserControls
{ {
public sealed partial class HamburgerMenuUserControl public sealed partial class HamburgerMenuUserControl
{ {
public HamburgerMenuUserControl()
{
InitializeComponent();
}
public string HeaderLabel public string HeaderLabel
{ {
get { return (string)GetValue(HeaderLabelProperty); } get { return (string)GetValue(HeaderLabelProperty); }
@@ -112,9 +110,14 @@ namespace ModernKeePass.Views.UserControls
typeof(ICommand), typeof(ICommand),
typeof(HamburgerMenuUserControl), typeof(HamburgerMenuUserControl),
new PropertyMetadata(null, (o, args) => { })); new PropertyMetadata(null, (o, args) => { }));
public event EventHandler<SelectionChangedEventArgs> SelectionChanged; public event EventHandler<SelectionChangedEventArgs> SelectionChanged;
public HamburgerMenuUserControl()
{
InitializeComponent();
}
private void Selector_OnSelectionChanged(object sender, SelectionChangedEventArgs e) private void Selector_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{ {
SelectionChanged?.Invoke(sender, e); SelectionChanged?.Invoke(sender, e);
@@ -126,5 +129,14 @@ namespace ModernKeePass.Views.UserControls
if (parent == null) return; if (parent == null) return;
VisualStateManager.GoToState(this, parent.ActualWidth <= 640 ? "Hidden" : "Collapsed", true); VisualStateManager.GoToState(this, parent.ActualWidth <= 640 ? "Hidden" : "Collapsed", true);
} }
private void NewGroupTextBox_OnKeyDown(object sender, KeyRoutedEventArgs e)
{
if (e.Key != VirtualKey.Enter) return;
var textBox = sender as TextBoxWithButton;
ActionButtonCommand.Execute(textBox?.Text);
// Stop the event from triggering twice
e.Handled = true;
}
} }
} }

View File

@@ -124,7 +124,6 @@
<core:EventTriggerBehavior EventName="Click"> <core:EventTriggerBehavior EventName="Click">
<core:ChangePropertyAction TargetObject="{Binding ElementName=SearchBox}" PropertyName="Visibility" Value="Visible" /> <core:ChangePropertyAction TargetObject="{Binding ElementName=SearchBox}" PropertyName="Visibility" Value="Visible" />
<core:ChangePropertyAction TargetObject="{Binding ElementName=SearchButton}" PropertyName="Visibility" Value="Collapsed" /> <core:ChangePropertyAction TargetObject="{Binding ElementName=SearchButton}" PropertyName="Visibility" Value="Collapsed" />
<!-- TODO: make this work -->
<actions:SetupFocusAction TargetObject="{Binding ElementName=SearchBox}" /> <actions:SetupFocusAction TargetObject="{Binding ElementName=SearchBox}" />
</core:EventTriggerBehavior> </core:EventTriggerBehavior>
</interactivity:Interaction.Behaviors> </interactivity:Interaction.Behaviors>

View File

@@ -57,6 +57,18 @@ namespace ModernKeePass.Controls
typeof(TextBoxWithButton), typeof(TextBoxWithButton),
new PropertyMetadata(null, (o, args) => { })); new PropertyMetadata(null, (o, args) => { }));
public string ButtonCommandParameter
{
get { return (string)GetValue(ButtonCommandParameterProperty); }
set { SetValue(ButtonCommandParameterProperty, value); }
}
public static readonly DependencyProperty ButtonCommandParameterProperty =
DependencyProperty.Register(
nameof(ButtonCommandParameter),
typeof(string),
typeof(TextBoxWithButton),
new PropertyMetadata(null, (o, args) => { }));
public bool IsButtonEnabled public bool IsButtonEnabled
{ {
get { return (bool)GetValue(IsButtonEnabledProperty); } get { return (bool)GetValue(IsButtonEnabledProperty); }