Hosts file editor (#20462)

This commit is contained in:
Davide Giacometti
2022-10-13 13:05:43 +02:00
committed by GitHub
parent ab41b61e84
commit b2e1337d4e
67 changed files with 3858 additions and 13 deletions

View File

@@ -287,6 +287,22 @@ namespace Microsoft.PowerToys.Settings.UI.Library
}
}
private bool hosts = true;
[JsonPropertyName("Hosts")]
public bool Hosts
{
get => hosts;
set
{
if (hosts != value)
{
LogTelemetryEvent(value);
hosts = value;
}
}
}
public string ToJsonString()
{
return JsonSerializer.Serialize(this);

View File

@@ -0,0 +1,12 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace Settings.UI.Library.Enumerations
{
public enum AdditionalLinesPosition
{
Top = 0,
Bottom = 1,
}
}

View File

@@ -0,0 +1,27 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Text.Json.Serialization;
using Settings.UI.Library.Enumerations;
namespace Microsoft.PowerToys.Settings.UI.Library
{
public class HostsProperties
{
[JsonConverter(typeof(BoolPropertyJsonConverter))]
public bool ShowStartupWarning { get; set; }
[JsonConverter(typeof(BoolPropertyJsonConverter))]
public bool LaunchAdministrator { get; set; }
public AdditionalLinesPosition AdditionalLinesPosition { get; set; }
public HostsProperties()
{
ShowStartupWarning = true;
LaunchAdministrator = true;
AdditionalLinesPosition = AdditionalLinesPosition.Top;
}
}
}

View File

@@ -0,0 +1,46 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
namespace Microsoft.PowerToys.Settings.UI.Library
{
public class HostsSettings : BasePTModuleSettings, ISettingsConfig
{
public const string ModuleName = "Hosts";
[JsonPropertyName("properties")]
public HostsProperties Properties { get; set; }
public HostsSettings()
{
Properties = new HostsProperties();
Version = "1.0";
Name = ModuleName;
}
public virtual void Save(ISettingsUtils settingsUtils)
{
// Save settings to file
var options = new JsonSerializerOptions
{
WriteIndented = true,
};
if (settingsUtils == null)
{
throw new ArgumentNullException(nameof(settingsUtils));
}
settingsUtils.SaveSettings(JsonSerializer.Serialize(this, options), ModuleName);
}
public string GetModuleName() => Name;
public bool UpgradeSettingsConfiguration() => false;
}
}

View File

@@ -0,0 +1,115 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Runtime.CompilerServices;
using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.PowerToys.Settings.UI.Library.Helpers;
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
using Microsoft.PowerToys.Settings.UI.Library.ViewModels.Commands;
using Settings.UI.Library.Enumerations;
namespace Settings.UI.Library.ViewModels
{
public class HostsViewModel : Observable
{
private bool _isElevated;
private ISettingsUtils SettingsUtils { get; set; }
private GeneralSettings GeneralSettingsConfig { get; set; }
private HostsSettings Settings { get; set; }
private Func<string, int> SendConfigMSG { get; }
public ButtonClickCommand LaunchEventHandler => new ButtonClickCommand(Launch);
public bool IsEnabled
{
get => GeneralSettingsConfig.Enabled.Hosts;
set
{
if (value != GeneralSettingsConfig.Enabled.Hosts)
{
// Set the status in the general settings configuration
GeneralSettingsConfig.Enabled.Hosts = value;
OutGoingGeneralSettings snd = new OutGoingGeneralSettings(GeneralSettingsConfig);
SendConfigMSG(snd.ToString());
OnPropertyChanged(nameof(IsEnabled));
}
}
}
public bool LaunchAdministratorEnabled => IsEnabled && !_isElevated;
public bool ShowStartupWarning
{
get => Settings.Properties.ShowStartupWarning;
set
{
if (value != Settings.Properties.ShowStartupWarning)
{
Settings.Properties.ShowStartupWarning = value;
NotifyPropertyChanged();
}
}
}
public bool LaunchAdministrator
{
get => Settings.Properties.LaunchAdministrator;
set
{
if (value != Settings.Properties.LaunchAdministrator)
{
Settings.Properties.LaunchAdministrator = value;
NotifyPropertyChanged();
}
}
}
public int AdditionalLinesPosition
{
get => (int)Settings.Properties.AdditionalLinesPosition;
set
{
if (value != (int)Settings.Properties.AdditionalLinesPosition)
{
Settings.Properties.AdditionalLinesPosition = (AdditionalLinesPosition)value;
NotifyPropertyChanged();
}
}
}
public HostsViewModel(ISettingsUtils settingsUtils, ISettingsRepository<GeneralSettings> settingsRepository, ISettingsRepository<HostsSettings> moduleSettingsRepository, Func<string, int> ipcMSGCallBackFunc, bool isElevated)
{
SettingsUtils = settingsUtils;
GeneralSettingsConfig = settingsRepository.SettingsConfig;
Settings = moduleSettingsRepository.SettingsConfig;
SendConfigMSG = ipcMSGCallBackFunc;
_isElevated = isElevated;
}
public void Launch()
{
var actionName = "Launch";
if (!_isElevated && LaunchAdministrator)
{
actionName = "LaunchAdministrator";
}
SendConfigMSG("{\"action\":{\"Hosts\":{\"action_name\":\"" + actionName + "\", \"value\":\"\"}}}");
}
public void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
{
OnPropertyChanged(propertyName);
SettingsUtils.SaveSettings(Settings.ToJsonString(), HostsSettings.ModuleName);
}
}
}

View File

@@ -129,6 +129,7 @@ namespace Microsoft.PowerToys.Settings.UI
case "TextExtractor": StartupPage = typeof(Views.PowerOcrPage); break;
case "VideoConference": StartupPage = typeof(Views.VideoConferencePage); break;
case "MeasureTool": StartupPage = typeof(Views.MeasureToolPage); break;
case "Hosts": StartupPage = typeof(Views.HostsPage); break;
default: Debug.Assert(false, "Unexpected SettingsWindow argument value"); break;
}
}

View File

@@ -22,6 +22,7 @@ namespace Microsoft.PowerToys.Settings.UI.OOBE.Enums
TextExtractor,
VideoConference,
MeasureTool,
Hosts,
WhatsNew,
}
}

View File

@@ -0,0 +1,28 @@
<Page
x:Class="Microsoft.PowerToys.Settings.UI.OOBE.Views.OobeHosts"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Microsoft.PowerToys.Settings.UI.OOBE.Views"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:controls="using:Microsoft.PowerToys.Settings.UI.Controls"
xmlns:toolkitcontrols="using:CommunityToolkit.WinUI.UI.Controls">
<controls:OOBEPageControl x:Uid="Oobe_Hosts"
HeroImage="ms-appx:///Assets/Modules/OOBE/AlwaysOnTop.png">
<controls:OOBEPageControl.PageContent>
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal" Spacing="12" Margin="0,24,0,0">
<Button x:Uid="Launch_Hosts" Style="{StaticResource AccentButtonStyle}" Click="Launch_Hosts_Click" />
<Button x:Uid="OOBE_Settings"
Click="Launch_Settings_Click" />
<HyperlinkButton NavigateUri="https://aka.ms/PowerToysOverview_HostsFileEditor" Style="{StaticResource TextButtonStyle}">
<TextBlock x:Uid="LearnMore_Hosts"
TextWrapping="Wrap" />
</HyperlinkButton>
</StackPanel>
</StackPanel>
</controls:OOBEPageControl.PageContent>
</controls:OOBEPageControl>
</Page>

View File

@@ -0,0 +1,58 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.PowerToys.Settings.UI.OOBE.Enums;
using Microsoft.PowerToys.Settings.UI.OOBE.ViewModel;
using Microsoft.PowerToys.Settings.UI.Views;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Navigation;
namespace Microsoft.PowerToys.Settings.UI.OOBE.Views
{
public sealed partial class OobeHosts : Page
{
public OobePowerToysModule ViewModel { get; }
public OobeHosts()
{
InitializeComponent();
ViewModel = new OobePowerToysModule(OobeShellPage.OobeShellHandler.Modules[(int)PowerToysModules.Hosts]);
DataContext = ViewModel;
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
ViewModel.LogOpeningModuleEvent();
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
ViewModel.LogClosingModuleEvent();
}
private void Launch_Hosts_Click(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
{
bool launchAdmin = SettingsRepository<HostsSettings>.GetInstance(new SettingsUtils()).SettingsConfig.Properties.LaunchAdministrator;
var actionName = "Launch";
if (!App.IsElevated && launchAdmin)
{
actionName = "LaunchAdministrator";
}
ShellPage.SendDefaultIPCMessage("{\"action\":{\"Hosts\":{\"action_name\":\"" + actionName + "\", \"value\":\"\"}}}");
}
private void Launch_Settings_Click(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
{
if (OobeShellPage.OpenMainWindowCallback != null)
{
OobeShellPage.OpenMainWindowCallback(typeof(HostsPage));
}
ViewModel.LogOpeningSettingsEvent();
}
}
}

View File

@@ -75,6 +75,13 @@
ShowAsMonochrome="False" />
</NavigationViewItem.Icon>
</NavigationViewItem>
<NavigationViewItem x:Uid="Shell_Hosts" Tag="Hosts">
<NavigationViewItem.Icon>
<BitmapIcon
UriSource="ms-appx:///Assets/FluentIcons/FluentIconsAlwaysOnTop.png"
ShowAsMonochrome="False" />
</NavigationViewItem.Icon>
</NavigationViewItem>
<NavigationViewItem x:Uid="Shell_ImageResizer" Tag="ImageResizer">
<NavigationViewItem.Icon>
<BitmapIcon

View File

@@ -139,6 +139,12 @@ namespace Microsoft.PowerToys.Settings.UI.OOBE.Views
IsNew = true,
});
Modules.Insert((int)PowerToysModules.Hosts, new OobePowerToysModule()
{
ModuleName = "Hosts",
IsNew = true,
});
Modules.Insert((int)PowerToysModules.WhatsNew, new OobePowerToysModule()
{
ModuleName = "WhatsNew",
@@ -192,6 +198,7 @@ namespace Microsoft.PowerToys.Settings.UI.OOBE.Views
case "VideoConference": NavigationFrame.Navigate(typeof(OobeVideoConference)); break;
case "MouseUtils": NavigationFrame.Navigate(typeof(OobeMouseUtils)); break;
case "MeasureTool": NavigationFrame.Navigate(typeof(OobeMeasureTool)); break;
case "Hosts": NavigationFrame.Navigate(typeof(OobeHosts)); break;
}
}
}

View File

@@ -35,6 +35,10 @@
<Optimize>true</Optimize>
</PropertyGroup>
<ItemGroup>
<None Remove="OOBE\Views\OobeHosts.xaml" />
</ItemGroup>
<ItemGroup>
<Content Include="Assets\SplashScreen.scale-200.png" />
<Content Include="Assets\LockScreenLogo.scale-200.png" />
@@ -68,6 +72,9 @@
<None Update="icon.ico">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<Page Update="OOBE\Views\OobeHosts.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Page Update="OOBE\Views\OobePowerOCR.xaml">

View File

@@ -2554,4 +2554,72 @@ Activate by holding the key for the character you want to add an accent to, then
<data name="QuickAccent_SelectedLanguage_Italian.Content" xml:space="preserve">
<value>Italian</value>
</data>
<data name="Hosts.ModuleDescription" xml:space="preserve">
<value>Quick and simple utility for managing hosts file.</value>
<comment>"Hosts" refers to the system hosts file, do not loc</comment>
</data>
<data name="Hosts.ModuleTitle" xml:space="preserve">
<value>Hosts File Editor</value>
<comment>"Hosts" refers to the system hosts file, do not loc</comment>
</data>
<data name="Shell_Hosts.Content" xml:space="preserve">
<value>Hosts File Editor</value>
<comment>Products name: Navigation view item name for Hosts File Editor</comment>
</data>
<data name="Hosts_EnableToggleControl_HeaderText.Header" xml:space="preserve">
<value>Enable Hosts File Editor</value>
<comment>"Hosts File Editor" is the name of the utility</comment>
</data>
<data name="Hosts_Toggle_ShowStartupWarning.Header" xml:space="preserve">
<value>Show a warning at startup</value>
</data>
<data name="Hosts_Activation_GroupSettings.Header" xml:space="preserve">
<value>Activation</value>
</data>
<data name="Hosts_LaunchButtonControl.Description" xml:space="preserve">
<value>Manage your hosts file</value>
<comment>"Hosts" refers to the system hosts file, do not loc</comment>
</data>
<data name="Hosts_LaunchButtonControl.Header" xml:space="preserve">
<value>Launch Host File Editor</value>
<comment>"Host File Editor" is a product name</comment>
</data>
<data name="Hosts_LaunchButton_Accessible.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
<value>Launch Host File Editor</value>
<comment>"Host File Editor" is a product name</comment>
</data>
<data name="Hosts_AdditionalLinesPosition.Header" xml:space="preserve">
<value>Additional lines position</value>
</data>
<data name="Hosts_AdditionalLinesPosition_Bottom.Content" xml:space="preserve">
<value>Bottom</value>
</data>
<data name="Hosts_AdditionalLinesPosition_Top.Content" xml:space="preserve">
<value>Top</value>
</data>
<data name="Hosts_File_GroupSettings.Header" xml:space="preserve">
<value>File</value>
</data>
<data name="Launch_Hosts.Content" xml:space="preserve">
<value>Launch Hosts File Editor</value>
<comment>"Hosts File Editor" is the name of the utility</comment>
</data>
<data name="LearnMore_Hosts.Text" xml:space="preserve">
<value>Learn more about Hosts File Editor</value>
<comment>"Hosts File Editor" is the name of the utility</comment>
</data>
<data name="Oobe_Hosts.Description" xml:space="preserve">
<value>Hosts File Editor is a quick and simple utility for managing hosts file.</value>
<comment>"Hosts File Editor" is the name of the utility</comment>
</data>
<data name="Oobe_Hosts.Title" xml:space="preserve">
<value>Hosts File Editor</value>
<comment>"Hosts File Editor" is the name of the utility</comment>
</data>
<data name="Hosts_Toggle_LaunchAdministrator.Description" xml:space="preserve">
<value>Needs to be launched as administrator in order to make changes to the hosts file</value>
</data>
<data name="Hosts_Toggle_LaunchAdministrator.Header" xml:space="preserve">
<value>Launch as administrator</value>
</data>
</root>

View File

@@ -0,0 +1,79 @@
<Page
x:Class="Microsoft.PowerToys.Settings.UI.Views.HostsPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Microsoft.PowerToys.Settings.UI.Views"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controls="using:Microsoft.PowerToys.Settings.UI.Controls"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<controls:SettingsPageControl x:Uid="Hosts" IsTabStop="False"
ModuleImageSource="ms-appx:///Assets/Modules/AlwaysOnTop.png">
<controls:SettingsPageControl.ModuleContent>
<StackPanel Orientation="Vertical">
<controls:Setting x:Uid="Hosts_EnableToggleControl_HeaderText">
<controls:Setting.Icon>
<BitmapIcon UriSource="ms-appx:///Assets/FluentIcons/FluentIconsAlwaysOnTop.png" ShowAsMonochrome="False" />
</controls:Setting.Icon>
<controls:Setting.ActionContent>
<ToggleSwitch IsOn="{x:Bind ViewModel.IsEnabled, Mode=TwoWay}" x:Uid="ToggleSwitch"/>
</controls:Setting.ActionContent>
</controls:Setting>
<controls:SettingsGroup x:Uid="Hosts_Activation_GroupSettings"
IsEnabled="{x:Bind Mode=OneWay, Path=ViewModel.IsEnabled}">
<Button x:Uid="Hosts_LaunchButton_Accessible"
Style="{StaticResource SettingButtonStyle}"
Command="{x:Bind ViewModel.LaunchEventHandler}">
<controls:Setting x:Uid="Hosts_LaunchButtonControl"
Style="{StaticResource ExpanderHeaderSettingStyle}"
Icon="&#xEA37;">
<controls:Setting.ActionContent>
<FontIcon Glyph="&#xE8A7;"
FontSize="18"
FontFamily="{ThemeResource SymbolThemeFontFamily}" />
</controls:Setting.ActionContent>
</controls:Setting>
</Button>
<controls:Setting x:Uid="Hosts_Toggle_LaunchAdministrator"
Icon="&#xE7EF;"
IsEnabled="{x:Bind Mode=OneWay, Path=ViewModel.LaunchAdministratorEnabled}">
<controls:Setting.ActionContent>
<ToggleSwitch x:Uid="ToggleSwitch" IsOn="{x:Bind Mode=TwoWay, Path=ViewModel.LaunchAdministrator}" />
</controls:Setting.ActionContent>
</controls:Setting>
<controls:Setting x:Uid="Hosts_Toggle_ShowStartupWarning"
Icon="&#xE7BA;"
IsEnabled="{x:Bind Mode=OneWay, Path=ViewModel.IsEnabled}">
<controls:Setting.ActionContent>
<ToggleSwitch x:Uid="ToggleSwitch" IsOn="{x:Bind Mode=TwoWay, Path=ViewModel.ShowStartupWarning}" />
</controls:Setting.ActionContent>
</controls:Setting>
</controls:SettingsGroup>
<controls:SettingsGroup x:Uid="Hosts_File_GroupSettings"
IsEnabled="{x:Bind Mode=OneWay, Path=ViewModel.IsEnabled}">
<controls:Setting x:Uid="Hosts_AdditionalLinesPosition" Icon="&#xE8A5;" >
<controls:Setting.ActionContent>
<ComboBox MinWidth="{StaticResource SettingActionControlMinWidth}"
SelectedIndex="{x:Bind Path=ViewModel.AdditionalLinesPosition, Mode=TwoWay}" >
<ComboBoxItem x:Uid="Hosts_AdditionalLinesPosition_Top" />
<ComboBoxItem x:Uid="Hosts_AdditionalLinesPosition_Bottom" />
</ComboBox>
</controls:Setting.ActionContent>
</controls:Setting>
</controls:SettingsGroup>
</StackPanel>
</controls:SettingsPageControl.ModuleContent>
<controls:SettingsPageControl.PrimaryLinks>
<controls:PageLink x:Uid="LearnMore_Hosts" Link="https://aka.ms/PowerToysOverview_HostsFileEditor"/>
</controls:SettingsPageControl.PrimaryLinks>
</controls:SettingsPageControl>
</Page>

View File

@@ -0,0 +1,22 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.UI.Xaml.Controls;
using Settings.UI.Library.ViewModels;
namespace Microsoft.PowerToys.Settings.UI.Views
{
public sealed partial class HostsPage : Page
{
private HostsViewModel ViewModel { get; }
public HostsPage()
{
InitializeComponent();
var settingsUtils = new SettingsUtils();
ViewModel = new HostsViewModel(settingsUtils, SettingsRepository<GeneralSettings>.GetInstance(settingsUtils), SettingsRepository<HostsSettings>.GetInstance(settingsUtils), ShellPage.SendDefaultIPCMessage, App.IsElevated);
}
}
}

View File

@@ -76,6 +76,12 @@
</NavigationViewItem.Icon>
</NavigationViewItem>
<NavigationViewItem x:Uid="Shell_Hosts" helpers:NavHelper.NavigateTo="views:HostsPage" >
<NavigationViewItem.Icon>
<BitmapIcon ShowAsMonochrome="False" UriSource="ms-appx:///Assets/FluentIcons/FluentIconsSettings.png" />
</NavigationViewItem.Icon>
</NavigationViewItem>
<NavigationViewItem x:Uid="Shell_ImageResizer" helpers:NavHelper.NavigateTo="views:ImageResizerPage">
<NavigationViewItem.Icon>
<BitmapIcon ShowAsMonochrome="False" UriSource="ms-appx:///Assets/FluentIcons/FluentIconsImageResizer.png" />
@@ -137,9 +143,6 @@
<BitmapIcon ShowAsMonochrome="False" UriSource="ms-appx:///Assets/FluentIcons/FluentIconsVideoConferenceMute.png" />
</NavigationViewItem.Icon>
</NavigationViewItem>
</NavigationView.MenuItems>
<NavigationView.PaneFooter>
<StackPanel Orientation="Vertical">