[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,186 +194,235 @@
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" Visibility="{x:Bind ViewModel.IsLoading, Converter={StaticResource BoolToInvertedVisibilityConverter}, Mode=OneWay}">
Background="{ThemeResource LayerFillColorDefaultBrush}" <ListView
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}" x:Name="Entries"
BorderThickness="1" x:Uid="Entries"
CornerRadius="8" Grid.Row="1"
IsItemClickEnabled="True" Margin="16,8,16,16"
ItemClick="Entries_ItemClick" Background="{ThemeResource LayerFillColorDefaultBrush}"
KeyDown="Entries_KeyDown" BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
GotFocus="Entries_GotFocus" BorderThickness="1"
ItemsSource="{x:Bind ViewModel.Entries, Mode=TwoWay}" CornerRadius="8"
SelectedItem="{x:Bind ViewModel.Selected, Mode=TwoWay}" IsItemClickEnabled="True"
Visibility="{x:Bind ViewModel.IsLoading, Converter={StaticResource BoolToInvertedVisibilityConverter}, Mode=OneWay}"> ItemClick="Entries_ItemClick"
<ListView.ItemTemplate> KeyDown="Entries_KeyDown"
<DataTemplate x:DataType="models:Entry"> GotFocus="Entries_GotFocus"
<Grid ItemsSource="{x:Bind ViewModel.Entries, Mode=TwoWay}"
AutomationProperties.Name="{x:Bind Address, Mode=OneWay}" SelectedItem="{x:Bind ViewModel.Selected, Mode=TwoWay}"
Background="Transparent" Visibility="{x:Bind ViewModel.IsLoading, Converter={StaticResource BoolToInvertedVisibilityConverter}, Mode=OneWay}">
IsRightTapEnabled="True" <ListView.ItemTemplate>
RightTapped="Grid_RightTapped"> <DataTemplate x:DataType="models:Entry">
<Grid.ColumnDefinitions> <Grid
<ColumnDefinition Width="300" /> AutomationProperties.Name="{x:Bind Address, Mode=OneWay}"
<ColumnDefinition Width="*" /> Background="Transparent"
<ColumnDefinition Width="Auto" /> IsRightTapEnabled="True"
<ColumnDefinition Width="Auto" /> RightTapped="Grid_RightTapped">
<ColumnDefinition Width="Auto" /> <Grid.ColumnDefinitions>
</Grid.ColumnDefinitions> <ColumnDefinition Width="300" />
<FlyoutBase.AttachedFlyout> <ColumnDefinition Width="*" />
<MenuFlyout Opened="MenuFlyout_Opened"> <ColumnDefinition Width="Auto" />
<MenuFlyoutItem <ColumnDefinition Width="Auto" />
x:Uid="Edit" <ColumnDefinition Width="Auto" />
Click="Edit_Click" </Grid.ColumnDefinitions>
Icon="Edit"> <FlyoutBase.AttachedFlyout>
<MenuFlyoutItem.KeyboardAccelerators> <MenuFlyout Opened="MenuFlyout_Opened">
<KeyboardAccelerator <MenuFlyoutItem
Modifiers="Control" x:Uid="Edit"
Key="E" /> Click="Edit_Click"
</MenuFlyoutItem.KeyboardAccelerators> Icon="Edit">
</MenuFlyoutItem> <MenuFlyoutItem.KeyboardAccelerators>
<MenuFlyoutItem <KeyboardAccelerator
x:Uid="Ping" Modifiers="Control"
Click="Ping_Click" Key="E" />
Icon="TwoBars"> </MenuFlyoutItem.KeyboardAccelerators>
<MenuFlyoutItem.KeyboardAccelerators> </MenuFlyoutItem>
<KeyboardAccelerator <MenuFlyoutItem
Modifiers="Control" x:Uid="Ping"
Key="P" /> Click="Ping_Click"
</MenuFlyoutItem.KeyboardAccelerators> Icon="TwoBars">
</MenuFlyoutItem> <MenuFlyoutItem.KeyboardAccelerators>
<MenuFlyoutItem <KeyboardAccelerator
x:Uid="MoveUp" Modifiers="Control"
Click="ReorderButtonUp_Click" Key="P" />
IsEnabled="{Binding DataContext.Filtered, ElementName=Page, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}"> </MenuFlyoutItem.KeyboardAccelerators>
<MenuFlyoutItem.Icon> </MenuFlyoutItem>
<FontIcon Glyph="&#xE74A;" /> <MenuFlyoutItem
</MenuFlyoutItem.Icon> x:Uid="MoveUp"
</MenuFlyoutItem> Click="ReorderButtonUp_Click"
<MenuFlyoutItem IsEnabled="{Binding DataContext.Filtered, ElementName=Page, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
x:Uid="MoveDown" <MenuFlyoutItem.Icon>
Click="ReorderButtonDown_Click" <FontIcon Glyph="&#xE74A;" />
IsEnabled="{Binding DataContext.Filtered, ElementName=Page, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}"> </MenuFlyoutItem.Icon>
<MenuFlyoutItem.Icon> </MenuFlyoutItem>
<FontIcon Glyph="&#xE74B;" /> <MenuFlyoutItem
</MenuFlyoutItem.Icon> x:Uid="MoveDown"
</MenuFlyoutItem> Click="ReorderButtonDown_Click"
<MenuFlyoutSeparator /> IsEnabled="{Binding DataContext.Filtered, ElementName=Page, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
<MenuFlyoutItem <MenuFlyoutItem.Icon>
x:Uid="Delete" <FontIcon Glyph="&#xE74B;" />
Click="Delete_Click" </MenuFlyoutItem.Icon>
Icon="Delete"> </MenuFlyoutItem>
<MenuFlyoutItem.KeyboardAccelerators> <MenuFlyoutSeparator />
<KeyboardAccelerator Key="Delete" /> <MenuFlyoutItem
</MenuFlyoutItem.KeyboardAccelerators> x:Uid="Delete"
</MenuFlyoutItem> Click="Delete_Click"
</MenuFlyout> Icon="Delete">
</FlyoutBase.AttachedFlyout> <MenuFlyoutItem.KeyboardAccelerators>
<TextBlock <KeyboardAccelerator Key="Delete" />
Grid.Column="0" </MenuFlyoutItem.KeyboardAccelerators>
VerticalAlignment="Center" </MenuFlyoutItem>
Text="{x:Bind Address, Mode=OneWay}" </MenuFlyout>
TextWrapping="Wrap" /> </FlyoutBase.AttachedFlyout>
<TextBlock <TextBlock
Grid.Column="1" Grid.Column="0"
VerticalAlignment="Center" VerticalAlignment="Center"
Foreground="{ThemeResource TextFillColorSecondaryBrush}" Text="{x:Bind Address, Mode=OneWay}"
Style="{StaticResource CaptionTextBlockStyle}" TextWrapping="Wrap" />
Text="{x:Bind helpers:StringHelper.GetHostsWithComment(Hosts, Comment), Mode=OneWay}" <TextBlock
TextWrapping="WrapWholeWords" /> Grid.Column="1"
<ProgressRing VerticalAlignment="Center"
Grid.Column="2" Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Width="20" Style="{StaticResource CaptionTextBlockStyle}"
Height="20" Text="{x:Bind helpers:StringHelper.GetHostsWithComment(Hosts, Comment), Mode=OneWay}"
Margin="0,0,8,0" TextWrapping="WrapWholeWords" />
IsActive="{x:Bind Pinging, Mode=OneWay}" /> <ProgressRing
<FontIcon Grid.Column="2"
x:Uid="PingIcon" Width="20"
x:Name="PingIcon" Height="20"
Grid.Column="2" Margin="0,0,8,0"
Margin="0,0,8,0" IsActive="{x:Bind Pinging, Mode=OneWay}" />
FontFamily="{ThemeResource SymbolThemeFontFamily}" <FontIcon
FontSize="18" x:Uid="PingIcon"
Visibility="Collapsed"> x:Name="PingIcon"
<i:Interaction.Behaviors> Grid.Column="2"
<ic:DataTriggerBehavior Margin="0,0,8,0"
Binding="{x:Bind Ping, Mode=OneWay}" FontFamily="{ThemeResource SymbolThemeFontFamily}"
ComparisonCondition="Equal" FontSize="18"
Value="True"> Visibility="Collapsed">
<ic:ChangePropertyAction <i:Interaction.Behaviors>
PropertyName="Glyph" <ic:DataTriggerBehavior
TargetObject="{Binding ElementName=PingIcon}" Binding="{x:Bind Ping, Mode=OneWay}"
Value="&#xe8fb;" /> ComparisonCondition="Equal"
<ic:ChangePropertyAction Value="True">
PropertyName="Visibility" <ic:ChangePropertyAction
TargetObject="{Binding ElementName=PingIcon}" PropertyName="Glyph"
Value="Visible" /> TargetObject="{Binding ElementName=PingIcon}"
<ic:ChangePropertyAction Value="&#xe8fb;" />
PropertyName="Foreground" <ic:ChangePropertyAction
TargetObject="{Binding ElementName=PingIcon}" PropertyName="Visibility"
Value="{StaticResource SystemFillColorSuccessBrush}" /> TargetObject="{Binding ElementName=PingIcon}"
</ic:DataTriggerBehavior> Value="Visible" />
<ic:DataTriggerBehavior <ic:ChangePropertyAction
Binding="{x:Bind Ping, Mode=OneWay}" PropertyName="Foreground"
ComparisonCondition="Equal" TargetObject="{Binding ElementName=PingIcon}"
Value="False"> Value="{StaticResource SystemFillColorSuccessBrush}" />
<ic:ChangePropertyAction </ic:DataTriggerBehavior>
PropertyName="Glyph" <ic:DataTriggerBehavior
TargetObject="{Binding ElementName=PingIcon}" Binding="{x:Bind Ping, Mode=OneWay}"
Value="&#xe894;" /> ComparisonCondition="Equal"
<ic:ChangePropertyAction Value="False">
PropertyName="Visibility" <ic:ChangePropertyAction
TargetObject="{Binding ElementName=PingIcon}" PropertyName="Glyph"
Value="Visible" /> TargetObject="{Binding ElementName=PingIcon}"
<ic:ChangePropertyAction Value="&#xe894;" />
PropertyName="Foreground" <ic:ChangePropertyAction
TargetObject="{Binding ElementName=PingIcon}" PropertyName="Visibility"
Value="{StaticResource SystemFillColorCriticalBrush}" /> TargetObject="{Binding ElementName=PingIcon}"
</ic:DataTriggerBehavior> Value="Visible" />
<ic:DataTriggerBehavior <ic:ChangePropertyAction
Binding="{x:Bind Ping, Mode=OneWay}" PropertyName="Foreground"
ComparisonCondition="Equal" TargetObject="{Binding ElementName=PingIcon}"
Value="{x:Null}"> Value="{StaticResource SystemFillColorCriticalBrush}" />
<ic:ChangePropertyAction </ic:DataTriggerBehavior>
PropertyName="Visibility" <ic:DataTriggerBehavior
TargetObject="{Binding ElementName=PingIcon}" Binding="{x:Bind Ping, Mode=OneWay}"
Value="Collapsed" /> ComparisonCondition="Equal"
</ic:DataTriggerBehavior> Value="{x:Null}">
</i:Interaction.Behaviors> <ic:ChangePropertyAction
</FontIcon> PropertyName="Visibility"
<FontIcon TargetObject="{Binding ElementName=PingIcon}"
x:Uid="DuplicateEntryIcon" Value="Collapsed" />
Grid.Column="3" </ic:DataTriggerBehavior>
Margin="0,0,8,0" </i:Interaction.Behaviors>
Foreground="{StaticResource SystemControlErrorTextForegroundBrush}" </FontIcon>
FontFamily="{ThemeResource SymbolThemeFontFamily}" <FontIcon
FontSize="18" x:Uid="DuplicateEntryIcon"
Glyph="&#xe7BA;" Grid.Column="3"
Visibility="{x:Bind Duplicate, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}" /> Margin="0,0,8,0"
<ToggleSwitch Foreground="{StaticResource SystemControlErrorTextForegroundBrush}"
x:Uid="ActiveToggle" FontFamily="{ThemeResource SymbolThemeFontFamily}"
Grid.Column="4" FontSize="18"
Width="40" Glyph="&#xe7BA;"
MinWidth="0" Visibility="{x:Bind Duplicate, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}" />
HorizontalAlignment="Right" <ToggleSwitch
IsOn="{x:Bind Active, Mode=TwoWay}" x:Uid="ActiveToggle"
OffContent="" Grid.Column="4"
OnContent="" /> Width="40"
</Grid> MinWidth="0"
</DataTemplate> HorizontalAlignment="Right"
</ListView.ItemTemplate> IsOn="{x:Bind Active, Mode=TwoWay}"
</ListView> 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"
Height="48" Height="48"
Grid.Row="1" Grid.Row="1"
IsActive="{x:Bind ViewModel.IsLoading, Mode=OneWay}" /> IsActive="{x:Bind ViewModel.IsLoading, Mode=OneWay}" />
<ContentDialog <ContentDialog
x:Name="EntryDialog" x:Name="EntryDialog"
x:Uid="EntryDialog" x:Uid="EntryDialog"