[Hosts]Fix first entry insert and improve UI for empty hosts file (#26671)

This commit is contained in:
Davide Giacometti
2023-06-11 17:59:30 +02:00
committed by GitHub
parent 852778daa5
commit 97578a1b97
3 changed files with 245 additions and 179 deletions

View File

@@ -135,6 +135,9 @@
<data name="AddEntryBtn.[using:Microsoft.UI.Xaml.Controls]ToolTipService.ToolTip" xml:space="preserve"> <data name="AddEntryBtn.[using:Microsoft.UI.Xaml.Controls]ToolTipService.ToolTip" xml:space="preserve">
<value>New entry (CTRL+N)</value> <value>New entry (CTRL+N)</value>
</data> </data>
<data name="AddEntryLink.Content" xml:space="preserve">
<value>Add an entry</value>
</data>
<data name="AdditionalLinesBtn.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve"> <data name="AdditionalLinesBtn.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
<value>Additional content</value> <value>Additional content</value>
</data> </data>
@@ -167,6 +170,9 @@
<data name="ClearFiltersBtn.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve"> <data name="ClearFiltersBtn.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
<value>Clear filters</value> <value>Clear filters</value>
</data> </data>
<data name="ClearFiltersLink.Content" xml:space="preserve">
<value>Clear filters</value>
</data>
<data name="Comment.Header" xml:space="preserve"> <data name="Comment.Header" xml:space="preserve">
<value>Comment</value> <value>Comment</value>
<comment>"Comment" refers to the comment of the entry</comment> <comment>"Comment" refers to the comment of the entry</comment>
@@ -193,6 +199,13 @@
<data name="Edit.Text" xml:space="preserve"> <data name="Edit.Text" xml:space="preserve">
<value>Edit</value> <value>Edit</value>
</data> </data>
<data name="EmptyFilterResults.Text" xml:space="preserve">
<value>No filter results</value>
</data>
<data name="EmptyHosts.Text" xml:space="preserve">
<value>No entries in the hosts file</value>
<comment>"Hosts" refers to the system hosts file, do not loc</comment>
</data>
<data name="Entries.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve"> <data name="Entries.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
<value>Entries</value> <value>Entries</value>
</data> </data>

View File

@@ -77,7 +77,7 @@ namespace Hosts.ViewModels
public AdvancedCollectionView Entries { get; set; } public AdvancedCollectionView Entries { get; set; }
public int NextId => _entries.Max(e => e.Id) + 1; public int NextId => _entries?.Count > 0 ? _entries.Max(e => e.Id) + 1 : 0;
public MainViewModel(IHostsService hostService, IUserSettings userSettings) public MainViewModel(IHostsService hostService, IUserSettings userSettings)
{ {
@@ -235,8 +235,7 @@ namespace Hosts.ViewModels
HostsFilter = null; HostsFilter = null;
CommentFilter = null; CommentFilter = null;
ShowOnlyDuplicates = false; ShowOnlyDuplicates = false;
Entries.Filter = null; ApplyFilters();
Entries.RefreshFilter();
} }
public async Task PingSelectedAsync() public async Task PingSelectedAsync()

View File

@@ -30,6 +30,11 @@
x:Key="BoolToInvertedVisibilityConverter" x:Key="BoolToInvertedVisibilityConverter"
TrueValue="Collapsed" TrueValue="Collapsed"
FalseValue="Visible" /> FalseValue="Visible" />
<converters:DoubleToVisibilityConverter
x:Key="DoubleToVisibilityConverter"
FalseValue="Visible"
GreaterThan="0"
TrueValue="Collapsed" />
</Page.Resources> </Page.Resources>
<Grid> <Grid>
@@ -43,7 +48,7 @@
<Button <Button
x:Uid="AddEntryBtn" x:Uid="AddEntryBtn"
Height="36" Height="36"
Margin="16,0,0,0" Margin="18,0,0,0"
Command="{x:Bind NewDialogCommand}"> Command="{x:Bind NewDialogCommand}">
<StackPanel <StackPanel
Orientation="Horizontal" Orientation="Horizontal"
@@ -64,7 +69,7 @@
</Button> </Button>
<StackPanel <StackPanel
Padding="0,0,16,0" Padding="0,0,18,0"
HorizontalAlignment="Right" HorizontalAlignment="Right"
Orientation="Horizontal"> Orientation="Horizontal">
<Button <Button
@@ -189,179 +194,228 @@
CanDragItems="{x:Bind ViewModel.Filtered, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}" CanDragItems="{x:Bind ViewModel.Filtered, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}"
CanReorderItems="{x:Bind ViewModel.Filtered, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}" CanReorderItems="{x:Bind ViewModel.Filtered, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}"
--> -->
<ListView <Grid
x:Name="Entries"
x:Uid="Entries"
Grid.Row="1" Grid.Row="1"
Margin="16,8,16,16"
Background="{ThemeResource LayerFillColorDefaultBrush}"
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
BorderThickness="1"
CornerRadius="8"
IsItemClickEnabled="True"
ItemClick="Entries_ItemClick"
KeyDown="Entries_KeyDown"
GotFocus="Entries_GotFocus"
ItemsSource="{x:Bind ViewModel.Entries, Mode=TwoWay}"
SelectedItem="{x:Bind ViewModel.Selected, Mode=TwoWay}"
Visibility="{x:Bind ViewModel.IsLoading, Converter={StaticResource BoolToInvertedVisibilityConverter}, Mode=OneWay}"> Visibility="{x:Bind ViewModel.IsLoading, Converter={StaticResource BoolToInvertedVisibilityConverter}, Mode=OneWay}">
<ListView.ItemTemplate> <ListView
<DataTemplate x:DataType="models:Entry"> x:Name="Entries"
<Grid x:Uid="Entries"
AutomationProperties.Name="{x:Bind Address, Mode=OneWay}" Grid.Row="1"
Background="Transparent" Margin="16,8,16,16"
IsRightTapEnabled="True" Background="{ThemeResource LayerFillColorDefaultBrush}"
RightTapped="Grid_RightTapped"> BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
<Grid.ColumnDefinitions> BorderThickness="1"
<ColumnDefinition Width="300" /> CornerRadius="8"
<ColumnDefinition Width="*" /> IsItemClickEnabled="True"
<ColumnDefinition Width="Auto" /> ItemClick="Entries_ItemClick"
<ColumnDefinition Width="Auto" /> KeyDown="Entries_KeyDown"
<ColumnDefinition Width="Auto" /> GotFocus="Entries_GotFocus"
</Grid.ColumnDefinitions> ItemsSource="{x:Bind ViewModel.Entries, Mode=TwoWay}"
<FlyoutBase.AttachedFlyout> SelectedItem="{x:Bind ViewModel.Selected, Mode=TwoWay}"
<MenuFlyout Opened="MenuFlyout_Opened"> Visibility="{x:Bind ViewModel.IsLoading, Converter={StaticResource BoolToInvertedVisibilityConverter}, Mode=OneWay}">
<MenuFlyoutItem <ListView.ItemTemplate>
x:Uid="Edit" <DataTemplate x:DataType="models:Entry">
Click="Edit_Click" <Grid
Icon="Edit"> AutomationProperties.Name="{x:Bind Address, Mode=OneWay}"
<MenuFlyoutItem.KeyboardAccelerators> Background="Transparent"
<KeyboardAccelerator IsRightTapEnabled="True"
Modifiers="Control" RightTapped="Grid_RightTapped">
Key="E" /> <Grid.ColumnDefinitions>
</MenuFlyoutItem.KeyboardAccelerators> <ColumnDefinition Width="300" />
</MenuFlyoutItem> <ColumnDefinition Width="*" />
<MenuFlyoutItem <ColumnDefinition Width="Auto" />
x:Uid="Ping" <ColumnDefinition Width="Auto" />
Click="Ping_Click" <ColumnDefinition Width="Auto" />
Icon="TwoBars"> </Grid.ColumnDefinitions>
<MenuFlyoutItem.KeyboardAccelerators> <FlyoutBase.AttachedFlyout>
<KeyboardAccelerator <MenuFlyout Opened="MenuFlyout_Opened">
Modifiers="Control" <MenuFlyoutItem
Key="P" /> x:Uid="Edit"
</MenuFlyoutItem.KeyboardAccelerators> Click="Edit_Click"
</MenuFlyoutItem> Icon="Edit">
<MenuFlyoutItem <MenuFlyoutItem.KeyboardAccelerators>
x:Uid="MoveUp" <KeyboardAccelerator
Click="ReorderButtonUp_Click" Modifiers="Control"
IsEnabled="{Binding DataContext.Filtered, ElementName=Page, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}"> Key="E" />
<MenuFlyoutItem.Icon> </MenuFlyoutItem.KeyboardAccelerators>
<FontIcon Glyph="&#xE74A;" /> </MenuFlyoutItem>
</MenuFlyoutItem.Icon> <MenuFlyoutItem
</MenuFlyoutItem> x:Uid="Ping"
<MenuFlyoutItem Click="Ping_Click"
x:Uid="MoveDown" Icon="TwoBars">
Click="ReorderButtonDown_Click" <MenuFlyoutItem.KeyboardAccelerators>
IsEnabled="{Binding DataContext.Filtered, ElementName=Page, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}"> <KeyboardAccelerator
<MenuFlyoutItem.Icon> Modifiers="Control"
<FontIcon Glyph="&#xE74B;" /> Key="P" />
</MenuFlyoutItem.Icon> </MenuFlyoutItem.KeyboardAccelerators>
</MenuFlyoutItem> </MenuFlyoutItem>
<MenuFlyoutSeparator /> <MenuFlyoutItem
<MenuFlyoutItem x:Uid="MoveUp"
x:Uid="Delete" Click="ReorderButtonUp_Click"
Click="Delete_Click" IsEnabled="{Binding DataContext.Filtered, ElementName=Page, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
Icon="Delete"> <MenuFlyoutItem.Icon>
<MenuFlyoutItem.KeyboardAccelerators> <FontIcon Glyph="&#xE74A;" />
<KeyboardAccelerator Key="Delete" /> </MenuFlyoutItem.Icon>
</MenuFlyoutItem.KeyboardAccelerators> </MenuFlyoutItem>
</MenuFlyoutItem> <MenuFlyoutItem
</MenuFlyout> x:Uid="MoveDown"
</FlyoutBase.AttachedFlyout> Click="ReorderButtonDown_Click"
<TextBlock IsEnabled="{Binding DataContext.Filtered, ElementName=Page, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
Grid.Column="0" <MenuFlyoutItem.Icon>
VerticalAlignment="Center" <FontIcon Glyph="&#xE74B;" />
Text="{x:Bind Address, Mode=OneWay}" </MenuFlyoutItem.Icon>
TextWrapping="Wrap" /> </MenuFlyoutItem>
<TextBlock <MenuFlyoutSeparator />
Grid.Column="1" <MenuFlyoutItem
VerticalAlignment="Center" x:Uid="Delete"
Foreground="{ThemeResource TextFillColorSecondaryBrush}" Click="Delete_Click"
Style="{StaticResource CaptionTextBlockStyle}" Icon="Delete">
Text="{x:Bind helpers:StringHelper.GetHostsWithComment(Hosts, Comment), Mode=OneWay}" <MenuFlyoutItem.KeyboardAccelerators>
TextWrapping="WrapWholeWords" /> <KeyboardAccelerator Key="Delete" />
<ProgressRing </MenuFlyoutItem.KeyboardAccelerators>
Grid.Column="2" </MenuFlyoutItem>
Width="20" </MenuFlyout>
Height="20" </FlyoutBase.AttachedFlyout>
Margin="0,0,8,0" <TextBlock
IsActive="{x:Bind Pinging, Mode=OneWay}" /> Grid.Column="0"
<FontIcon VerticalAlignment="Center"
x:Uid="PingIcon" Text="{x:Bind Address, Mode=OneWay}"
x:Name="PingIcon" TextWrapping="Wrap" />
Grid.Column="2" <TextBlock
Margin="0,0,8,0" Grid.Column="1"
FontFamily="{ThemeResource SymbolThemeFontFamily}" VerticalAlignment="Center"
FontSize="18" Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Visibility="Collapsed"> Style="{StaticResource CaptionTextBlockStyle}"
<i:Interaction.Behaviors> Text="{x:Bind helpers:StringHelper.GetHostsWithComment(Hosts, Comment), Mode=OneWay}"
<ic:DataTriggerBehavior TextWrapping="WrapWholeWords" />
Binding="{x:Bind Ping, Mode=OneWay}" <ProgressRing
ComparisonCondition="Equal" Grid.Column="2"
Value="True"> Width="20"
<ic:ChangePropertyAction Height="20"
PropertyName="Glyph" Margin="0,0,8,0"
TargetObject="{Binding ElementName=PingIcon}" IsActive="{x:Bind Pinging, Mode=OneWay}" />
Value="&#xe8fb;" /> <FontIcon
<ic:ChangePropertyAction x:Uid="PingIcon"
PropertyName="Visibility" x:Name="PingIcon"
TargetObject="{Binding ElementName=PingIcon}" Grid.Column="2"
Value="Visible" /> Margin="0,0,8,0"
<ic:ChangePropertyAction FontFamily="{ThemeResource SymbolThemeFontFamily}"
PropertyName="Foreground" FontSize="18"
TargetObject="{Binding ElementName=PingIcon}" Visibility="Collapsed">
Value="{StaticResource SystemFillColorSuccessBrush}" /> <i:Interaction.Behaviors>
</ic:DataTriggerBehavior> <ic:DataTriggerBehavior
<ic:DataTriggerBehavior Binding="{x:Bind Ping, Mode=OneWay}"
Binding="{x:Bind Ping, Mode=OneWay}" ComparisonCondition="Equal"
ComparisonCondition="Equal" Value="True">
Value="False"> <ic:ChangePropertyAction
<ic:ChangePropertyAction PropertyName="Glyph"
PropertyName="Glyph" TargetObject="{Binding ElementName=PingIcon}"
TargetObject="{Binding ElementName=PingIcon}" Value="&#xe8fb;" />
Value="&#xe894;" /> <ic:ChangePropertyAction
<ic:ChangePropertyAction PropertyName="Visibility"
PropertyName="Visibility" TargetObject="{Binding ElementName=PingIcon}"
TargetObject="{Binding ElementName=PingIcon}" Value="Visible" />
Value="Visible" /> <ic:ChangePropertyAction
<ic:ChangePropertyAction PropertyName="Foreground"
PropertyName="Foreground" TargetObject="{Binding ElementName=PingIcon}"
TargetObject="{Binding ElementName=PingIcon}" Value="{StaticResource SystemFillColorSuccessBrush}" />
Value="{StaticResource SystemFillColorCriticalBrush}" /> </ic:DataTriggerBehavior>
</ic:DataTriggerBehavior> <ic:DataTriggerBehavior
<ic:DataTriggerBehavior Binding="{x:Bind Ping, Mode=OneWay}"
Binding="{x:Bind Ping, Mode=OneWay}" ComparisonCondition="Equal"
ComparisonCondition="Equal" Value="False">
Value="{x:Null}"> <ic:ChangePropertyAction
<ic:ChangePropertyAction PropertyName="Glyph"
PropertyName="Visibility" TargetObject="{Binding ElementName=PingIcon}"
TargetObject="{Binding ElementName=PingIcon}" Value="&#xe894;" />
Value="Collapsed" /> <ic:ChangePropertyAction
</ic:DataTriggerBehavior> PropertyName="Visibility"
</i:Interaction.Behaviors> TargetObject="{Binding ElementName=PingIcon}"
</FontIcon> Value="Visible" />
<FontIcon <ic:ChangePropertyAction
x:Uid="DuplicateEntryIcon" PropertyName="Foreground"
Grid.Column="3" TargetObject="{Binding ElementName=PingIcon}"
Margin="0,0,8,0" Value="{StaticResource SystemFillColorCriticalBrush}" />
Foreground="{StaticResource SystemControlErrorTextForegroundBrush}" </ic:DataTriggerBehavior>
FontFamily="{ThemeResource SymbolThemeFontFamily}" <ic:DataTriggerBehavior
FontSize="18" Binding="{x:Bind Ping, Mode=OneWay}"
Glyph="&#xe7BA;" ComparisonCondition="Equal"
Visibility="{x:Bind Duplicate, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}" /> Value="{x:Null}">
<ToggleSwitch <ic:ChangePropertyAction
x:Uid="ActiveToggle" PropertyName="Visibility"
Grid.Column="4" TargetObject="{Binding ElementName=PingIcon}"
Width="40" Value="Collapsed" />
MinWidth="0" </ic:DataTriggerBehavior>
HorizontalAlignment="Right" </i:Interaction.Behaviors>
IsOn="{x:Bind Active, Mode=TwoWay}" </FontIcon>
OffContent="" <FontIcon
OnContent="" /> x:Uid="DuplicateEntryIcon"
</Grid> Grid.Column="3"
</DataTemplate> Margin="0,0,8,0"
</ListView.ItemTemplate> Foreground="{StaticResource SystemControlErrorTextForegroundBrush}"
</ListView> FontFamily="{ThemeResource SymbolThemeFontFamily}"
FontSize="18"
Glyph="&#xe7BA;"
Visibility="{x:Bind Duplicate, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}" />
<ToggleSwitch
x:Uid="ActiveToggle"
Grid.Column="4"
Width="40"
MinWidth="0"
HorizontalAlignment="Right"
IsOn="{x:Bind Active, Mode=TwoWay}"
OffContent=""
OnContent="" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<StackPanel
HorizontalAlignment="Center"
VerticalAlignment="Center"
Visibility="{x:Bind ViewModel.Entries.Count, Mode=OneWay, Converter={StaticResource DoubleToVisibilityConverter}}">
<StackPanel
HorizontalAlignment="Center"
VerticalAlignment="Center"
Spacing="8"
Visibility="{x:Bind ViewModel.Filtered, Mode=OneWay, Converter={StaticResource BoolToInvertedVisibilityConverter}}">
<FontIcon
FontFamily="{StaticResource SymbolThemeFontFamily}"
FontSize="32"
Glyph="&#xe774;" />
<TextBlock
x:Uid="EmptyHosts"
HorizontalAlignment="Center"
TextWrapping="Wrap"
Foreground="{ThemeResource TextFillColorSecondaryBrush}" />
<HyperlinkButton
x:Uid="AddEntryLink"
HorizontalAlignment="Center"
Command="{x:Bind NewDialogCommand}" />
</StackPanel>
<StackPanel
HorizontalAlignment="Center"
VerticalAlignment="Center"
Spacing="8"
Visibility="{x:Bind ViewModel.Filtered, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}">
<FontIcon
FontFamily="{StaticResource SymbolThemeFontFamily}"
FontSize="32"
Glyph="&#xf78b;" />
<TextBlock
x:Uid="EmptyFilterResults"
HorizontalAlignment="Center"
TextWrapping="Wrap"
Foreground="{ThemeResource TextFillColorSecondaryBrush}" />
<HyperlinkButton
x:Uid="ClearFiltersLink"
HorizontalAlignment="Center"
Command="{x:Bind ViewModel.ClearFiltersCommand}" />
</StackPanel>
</StackPanel>
</Grid>
<ProgressRing <ProgressRing
Width="48" Width="48"