2022-12-14 16:52:00 +01:00
// Copyright (c) Microsoft Corporation
2022-10-13 13:05:43 +02:00
// 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 ;
2022-12-14 16:52:00 +01:00
using System.Collections.Generic ;
2022-10-13 13:05:43 +02:00
using System.Collections.ObjectModel ;
2023-09-08 17:25:36 +02:00
using System.IO ;
2022-10-13 13:05:43 +02:00
using System.Linq ;
2023-02-27 19:11:57 +01:00
using System.Linq.Expressions ;
2022-10-13 13:05:43 +02:00
using System.Threading.Tasks ;
2024-09-16 16:09:43 -04:00
2022-10-13 13:05:43 +02:00
using CommunityToolkit.Mvvm.ComponentModel ;
using CommunityToolkit.Mvvm.Input ;
using CommunityToolkit.WinUI ;
2023-09-14 18:41:31 +02:00
using CommunityToolkit.WinUI.Collections ;
2024-04-26 19:41:44 +02:00
using HostsUILib.Exceptions ;
using HostsUILib.Helpers ;
using HostsUILib.Models ;
using HostsUILib.Settings ;
2022-10-13 13:05:43 +02:00
using Microsoft.UI.Dispatching ;
2024-09-16 16:09:43 -04:00
2024-04-26 19:41:44 +02:00
using static HostsUILib . Settings . IUserSettings ;
2022-10-13 13:05:43 +02:00
2024-04-26 19:41:44 +02:00
namespace HostsUILib.ViewModels
2022-10-13 13:05:43 +02:00
{
2024-06-03 11:26:05 +02:00
public partial class MainViewModel : ObservableObject
2022-10-13 13:05:43 +02:00
{
private readonly IHostsService _hostsService ;
2023-02-27 19:11:57 +01:00
private readonly IUserSettings _userSettings ;
2024-06-03 11:26:05 +02:00
private readonly IDuplicateService _duplicateService ;
2022-10-13 13:05:43 +02:00
private readonly DispatcherQueue _dispatcherQueue = DispatcherQueue . GetForCurrentThread ( ) ;
2023-02-27 19:11:57 +01:00
private bool _readingHosts ;
2022-10-13 13:05:43 +02:00
[ObservableProperty]
private Entry _selected ;
[ObservableProperty]
private bool _error ;
2023-09-08 17:25:36 +02:00
[ObservableProperty]
private string _errorMessage ;
2023-11-03 17:10:26 +01:00
[ObservableProperty]
private bool _isReadOnly ;
2022-10-13 13:05:43 +02:00
[ObservableProperty]
private bool _fileChanged ;
[ObservableProperty]
private string _addressFilter ;
[ObservableProperty]
private string _hostsFilter ;
[ObservableProperty]
private string _commentFilter ;
[ObservableProperty]
private string _additionalLines ;
2023-02-22 17:19:01 +01:00
[ObservableProperty]
private bool _isLoading ;
2023-02-27 19:11:57 +01:00
[ObservableProperty]
private bool _filtered ;
2022-10-13 13:05:43 +02:00
2023-06-05 12:02:32 +02:00
[ObservableProperty]
2023-02-27 19:11:57 +01:00
private bool _showOnlyDuplicates ;
2022-10-13 13:05:43 +02:00
2023-06-23 21:54:45 +02:00
[ObservableProperty]
private bool _showSplittedEntriesTooltip ;
2023-06-05 12:02:32 +02:00
partial void OnShowOnlyDuplicatesChanged ( bool value )
2023-02-27 19:11:57 +01:00
{
2023-06-05 12:02:32 +02:00
ApplyFilters ( ) ;
2023-02-27 19:11:57 +01:00
}
2022-10-13 13:05:43 +02:00
2023-02-27 19:11:57 +01:00
private ObservableCollection < Entry > _entries ;
2022-10-13 13:05:43 +02:00
2023-02-27 19:11:57 +01:00
public AdvancedCollectionView Entries { get ; set ; }
2022-10-13 13:05:43 +02:00
2023-06-11 17:59:30 +02:00
public int NextId = > _entries ? . Count > 0 ? _entries . Max ( e = > e . Id ) + 1 : 0 ;
2022-10-24 20:09:00 +02:00
2024-04-26 19:41:44 +02:00
public IUserSettings UserSettings = > _userSettings ;
public static MainViewModel Instance { get ; set ; }
private OpenSettingsFunction _openSettingsFunction ;
2024-06-03 11:26:05 +02:00
public MainViewModel (
IHostsService hostService ,
IUserSettings userSettings ,
IDuplicateService duplicateService ,
ILogger logger ,
OpenSettingsFunction openSettingsFunction )
2022-10-13 13:05:43 +02:00
{
_hostsService = hostService ;
2023-02-27 19:11:57 +01:00
_userSettings = userSettings ;
2024-06-03 11:26:05 +02:00
_duplicateService = duplicateService ;
2022-10-13 13:05:43 +02:00
2023-02-27 19:11:57 +01:00
_hostsService . FileChanged + = ( s , e ) = > _dispatcherQueue . TryEnqueue ( ( ) = > FileChanged = true ) ;
_userSettings . LoopbackDuplicatesChanged + = ( s , e ) = > ReadHosts ( ) ;
2024-04-26 19:41:44 +02:00
LoggerInstance . Logger = logger ;
_openSettingsFunction = openSettingsFunction ;
2022-10-13 13:05:43 +02:00
}
public void Add ( Entry entry )
{
entry . PropertyChanged + = Entry_PropertyChanged ;
_entries . Add ( entry ) ;
2024-06-03 11:26:05 +02:00
_duplicateService . CheckDuplicates ( entry . Address , entry . SplittedHosts ) ;
2022-10-13 13:05:43 +02:00
}
public void Update ( int index , Entry entry )
{
2023-02-27 19:11:57 +01:00
var existingEntry = Entries [ index ] as Entry ;
2022-12-14 16:52:00 +01:00
var oldAddress = existingEntry . Address ;
var oldHosts = existingEntry . SplittedHosts ;
2022-10-13 13:05:43 +02:00
existingEntry . Address = entry . Address ;
existingEntry . Comment = entry . Comment ;
existingEntry . Hosts = entry . Hosts ;
existingEntry . Active = entry . Active ;
2022-12-14 16:52:00 +01:00
2024-06-03 11:26:05 +02:00
_duplicateService . CheckDuplicates ( oldAddress , oldHosts ) ;
_duplicateService . CheckDuplicates ( entry . Address , entry . SplittedHosts ) ;
2022-10-13 13:05:43 +02:00
}
public void DeleteSelected ( )
{
2022-12-14 16:52:00 +01:00
var address = Selected . Address ;
var hosts = Selected . SplittedHosts ;
2022-10-13 13:05:43 +02:00
_entries . Remove ( Selected ) ;
2024-06-03 11:26:05 +02:00
_duplicateService . CheckDuplicates ( address , hosts ) ;
2022-10-13 13:05:43 +02:00
}
public void UpdateAdditionalLines ( string lines )
{
2023-06-05 12:02:32 +02:00
AdditionalLines = lines ;
2023-09-08 17:25:36 +02:00
_ = Task . Run ( SaveAsync ) ;
2022-10-13 13:05:43 +02:00
}
2023-02-27 19:11:57 +01:00
public void Move ( int oldIndex , int newIndex )
{
if ( Filtered )
{
return ;
}
// Swap the IDs
var entry1 = _entries [ oldIndex ] ;
var entry2 = _entries [ newIndex ] ;
( entry2 . Id , entry1 . Id ) = ( entry1 . Id , entry2 . Id ) ;
// Move entries in the UI
_entries . Move ( oldIndex , newIndex ) ;
}
2024-02-14 16:12:59 +01:00
[RelayCommand]
public void DeleteEntry ( Entry entry )
{
if ( entry is not null )
{
var address = entry . Address ;
var hosts = entry . SplittedHosts ;
_entries . Remove ( entry ) ;
2024-06-03 11:26:05 +02:00
_duplicateService . CheckDuplicates ( address , hosts ) ;
2024-02-14 16:12:59 +01:00
}
}
2023-02-27 19:11:57 +01:00
[RelayCommand]
2022-10-13 13:05:43 +02:00
public void ReadHosts ( )
{
2023-02-27 19:11:57 +01:00
if ( _readingHosts )
{
return ;
}
_dispatcherQueue . TryEnqueue ( ( ) = >
{
FileChanged = false ;
IsLoading = true ;
} ) ;
2022-10-13 13:05:43 +02:00
Task . Run ( async ( ) = >
{
2023-02-27 19:11:57 +01:00
_readingHosts = true ;
2023-06-23 21:54:45 +02:00
var data = await _hostsService . ReadAsync ( ) ;
2022-10-13 13:05:43 +02:00
await _dispatcherQueue . EnqueueAsync ( ( ) = >
{
2023-06-23 21:54:45 +02:00
ShowSplittedEntriesTooltip = data . SplittedEntries ;
AdditionalLines = data . AdditionalLines ;
_entries = new ObservableCollection < Entry > ( data . Entries ) ;
2022-10-13 13:05:43 +02:00
foreach ( var e in _entries )
{
e . PropertyChanged + = Entry_PropertyChanged ;
}
_entries . CollectionChanged + = Entries_CollectionChanged ;
Add the Command Palette module (#37908)
Windows Command Palette ("CmdPal") is the next iteration of PowerToys Run. With extensibility at its core, the Command Palette is your one-stop launcher to start _anything_.
By default, CmdPal is bound to <kbd>Win+Alt+Space</kbd>.


----
This brings the current preview version of CmdPal into the upstream PowerToys repo. There are still lots of bugs to work out, but it's reached the state we're ready to start sharing it with the world. From here, we can further collaborate with the community on the features that are important, and ensuring that we've got a most robust API to enable developers to build whatever extensions they want.
Most of the built-in PT Run modules have already been ported to CmdPal's extension API. Those include:
* Installed apps
* Shell commands
* File search (powered by the indexer)
* Windows Registry search
* Web search
* Windows Terminal Profiles
* Windows Services
* Windows settings
There are a couple new extensions built-in
* You can now search for packages on `winget` and install them right from the palette. This also powers searching for extensions for the palette
* The calculator has an entirely new implementation. This is currently less feature complete than the original PT Run one - we're looking forward to updating it to be more complete for future ingestion in Windows
* "Bookmarks" allow you to save shortcuts to files, folders, and webpages as top-level commands in the palette.
We've got a bunch of other samples too, in this repo and elsewhere
### PowerToys specific notes
CmdPal will eventually graduate out of PowerToys to live as its own application, which is why it's implemented just a little differently than most other modules. Enabling CmdPal will install its `msix` package.
The CI was minorly changed to support CmdPal version numbers independent of PowerToys itself. It doesn't make sense for us to start CmdPal at v0.90, and in the future, we want to be able to rev CmdPal independently of PT itself.
Closes #3200, closes #3600, closes #7770, closes #34273, closes #36471, closes #20976, closes #14495
-----
TODOs et al
**Blocking:**
- [ ] Images and descriptions in Settings and OOBE need to be properly defined, as mentioned before
- [ ] Niels is on it
- [x] Doesn't start properly from PowerToys unless the fix PR is merged.
- https://github.com/zadjii-msft/PowerToys/pull/556 merged
- [x] I seem to lose focus a lot when I press on some limits, like between the search bar and the results.
- This is https://github.com/zadjii-msft/PowerToys/issues/427
- [x] Turned off an extension like Calculator and it was still working.
- Need to get rid of that toggle, it doesn't do anything currently
- [x] `ListViewModel.<FetchItems>` crash
- Pretty confident that was fixed in https://github.com/zadjii-msft/PowerToys/pull/553
**Not blocking / improvements:**
- Show the shortcut through settings, as mentioned before, or create a button that would open CmdPalette settings.
- When PowerToys starts, CmdPalette is always shown if enabled. That's weird when just starting PowerToys/ logging in to the computer with PowerToys auto-start activated. I think this should at least be a setting.
- Needing to double press a result for it to do the default action seems quirky. If one is already selected, I think just pressing should be enough for it to do the action.
- This is currently a setting, though we're thinking of changing the setting even more: https://github.com/zadjii-msft/PowerToys/issues/392
- There's no URI extension. Was surprised when typing a URL that it only proposed a web search.
- [x] There's no System commands extension. Was expecting to be able to quickly restart the computer by typing restart but it wasn't there.
- This is in PR https://github.com/zadjii-msft/PowerToys/pull/452
---------
Co-authored-by: joadoumie <98557455+joadoumie@users.noreply.github.com>
Co-authored-by: Jordi Adoumie <jordiadoumie@microsoft.com>
Co-authored-by: Mike Griese <zadjii@gmail.com>
Co-authored-by: Niels Laute <niels.laute@live.nl>
Co-authored-by: Michael Hawker <24302614+michael-hawker@users.noreply.github.com>
Co-authored-by: Stefan Markovic <57057282+stefansjfw@users.noreply.github.com>
Co-authored-by: Seraphima <zykovas91@gmail.com>
Co-authored-by: Jaime Bernardo <jaime@janeasystems.com>
Co-authored-by: Kristen Schau <47155823+krschau@users.noreply.github.com>
Co-authored-by: Eric Johnson <ericjohnson327@gmail.com>
Co-authored-by: Ethan Fang <ethanfang@microsoft.com>
Co-authored-by: Yu Leng (from Dev Box) <yuleng@microsoft.com>
Co-authored-by: Clint Rutkas <clint@rutkas.com>
2025-03-19 03:39:57 -05:00
#pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code
2023-02-27 19:11:57 +01:00
Entries = new AdvancedCollectionView ( _entries , true ) ;
Add the Command Palette module (#37908)
Windows Command Palette ("CmdPal") is the next iteration of PowerToys Run. With extensibility at its core, the Command Palette is your one-stop launcher to start _anything_.
By default, CmdPal is bound to <kbd>Win+Alt+Space</kbd>.


----
This brings the current preview version of CmdPal into the upstream PowerToys repo. There are still lots of bugs to work out, but it's reached the state we're ready to start sharing it with the world. From here, we can further collaborate with the community on the features that are important, and ensuring that we've got a most robust API to enable developers to build whatever extensions they want.
Most of the built-in PT Run modules have already been ported to CmdPal's extension API. Those include:
* Installed apps
* Shell commands
* File search (powered by the indexer)
* Windows Registry search
* Web search
* Windows Terminal Profiles
* Windows Services
* Windows settings
There are a couple new extensions built-in
* You can now search for packages on `winget` and install them right from the palette. This also powers searching for extensions for the palette
* The calculator has an entirely new implementation. This is currently less feature complete than the original PT Run one - we're looking forward to updating it to be more complete for future ingestion in Windows
* "Bookmarks" allow you to save shortcuts to files, folders, and webpages as top-level commands in the palette.
We've got a bunch of other samples too, in this repo and elsewhere
### PowerToys specific notes
CmdPal will eventually graduate out of PowerToys to live as its own application, which is why it's implemented just a little differently than most other modules. Enabling CmdPal will install its `msix` package.
The CI was minorly changed to support CmdPal version numbers independent of PowerToys itself. It doesn't make sense for us to start CmdPal at v0.90, and in the future, we want to be able to rev CmdPal independently of PT itself.
Closes #3200, closes #3600, closes #7770, closes #34273, closes #36471, closes #20976, closes #14495
-----
TODOs et al
**Blocking:**
- [ ] Images and descriptions in Settings and OOBE need to be properly defined, as mentioned before
- [ ] Niels is on it
- [x] Doesn't start properly from PowerToys unless the fix PR is merged.
- https://github.com/zadjii-msft/PowerToys/pull/556 merged
- [x] I seem to lose focus a lot when I press on some limits, like between the search bar and the results.
- This is https://github.com/zadjii-msft/PowerToys/issues/427
- [x] Turned off an extension like Calculator and it was still working.
- Need to get rid of that toggle, it doesn't do anything currently
- [x] `ListViewModel.<FetchItems>` crash
- Pretty confident that was fixed in https://github.com/zadjii-msft/PowerToys/pull/553
**Not blocking / improvements:**
- Show the shortcut through settings, as mentioned before, or create a button that would open CmdPalette settings.
- When PowerToys starts, CmdPalette is always shown if enabled. That's weird when just starting PowerToys/ logging in to the computer with PowerToys auto-start activated. I think this should at least be a setting.
- Needing to double press a result for it to do the default action seems quirky. If one is already selected, I think just pressing should be enough for it to do the action.
- This is currently a setting, though we're thinking of changing the setting even more: https://github.com/zadjii-msft/PowerToys/issues/392
- There's no URI extension. Was surprised when typing a URL that it only proposed a web search.
- [x] There's no System commands extension. Was expecting to be able to quickly restart the computer by typing restart but it wasn't there.
- This is in PR https://github.com/zadjii-msft/PowerToys/pull/452
---------
Co-authored-by: joadoumie <98557455+joadoumie@users.noreply.github.com>
Co-authored-by: Jordi Adoumie <jordiadoumie@microsoft.com>
Co-authored-by: Mike Griese <zadjii@gmail.com>
Co-authored-by: Niels Laute <niels.laute@live.nl>
Co-authored-by: Michael Hawker <24302614+michael-hawker@users.noreply.github.com>
Co-authored-by: Stefan Markovic <57057282+stefansjfw@users.noreply.github.com>
Co-authored-by: Seraphima <zykovas91@gmail.com>
Co-authored-by: Jaime Bernardo <jaime@janeasystems.com>
Co-authored-by: Kristen Schau <47155823+krschau@users.noreply.github.com>
Co-authored-by: Eric Johnson <ericjohnson327@gmail.com>
Co-authored-by: Ethan Fang <ethanfang@microsoft.com>
Co-authored-by: Yu Leng (from Dev Box) <yuleng@microsoft.com>
Co-authored-by: Clint Rutkas <clint@rutkas.com>
2025-03-19 03:39:57 -05:00
#pragma warning restore IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code
2023-02-27 19:11:57 +01:00
Entries . SortDescriptions . Add ( new SortDescription ( nameof ( Entry . Id ) , SortDirection . Ascending ) ) ;
ApplyFilters ( ) ;
2022-12-14 16:52:00 +01:00
OnPropertyChanged ( nameof ( Entries ) ) ;
2023-02-22 17:19:01 +01:00
IsLoading = false ;
2022-10-13 13:05:43 +02:00
} ) ;
2023-02-27 19:11:57 +01:00
_readingHosts = false ;
2023-02-22 17:19:01 +01:00
2024-06-03 11:26:05 +02:00
_duplicateService . Initialize ( _entries ) ;
2022-10-13 13:05:43 +02:00
} ) ;
}
2023-02-27 19:11:57 +01:00
[RelayCommand]
2022-10-13 13:05:43 +02:00
public void ApplyFilters ( )
{
2023-02-27 19:11:57 +01:00
var expressions = new List < Expression < Func < object , bool > > > ( 4 ) ;
2023-06-05 12:02:32 +02:00
if ( ! string . IsNullOrWhiteSpace ( AddressFilter ) )
2022-10-13 13:05:43 +02:00
{
2023-06-05 12:02:32 +02:00
expressions . Add ( e = > ( ( Entry ) e ) . Address . Contains ( AddressFilter , StringComparison . OrdinalIgnoreCase ) ) ;
2022-10-13 13:05:43 +02:00
}
2022-12-14 16:52:00 +01:00
2023-06-05 12:02:32 +02:00
if ( ! string . IsNullOrWhiteSpace ( HostsFilter ) )
2023-02-27 19:11:57 +01:00
{
2023-06-05 12:02:32 +02:00
expressions . Add ( e = > ( ( Entry ) e ) . Hosts . Contains ( HostsFilter , StringComparison . OrdinalIgnoreCase ) ) ;
2023-02-27 19:11:57 +01:00
}
2022-12-14 16:52:00 +01:00
2023-06-05 12:02:32 +02:00
if ( ! string . IsNullOrWhiteSpace ( CommentFilter ) )
2023-02-27 19:11:57 +01:00
{
2023-06-05 12:02:32 +02:00
expressions . Add ( e = > ( ( Entry ) e ) . Comment . Contains ( CommentFilter , StringComparison . OrdinalIgnoreCase ) ) ;
2023-02-27 19:11:57 +01:00
}
2023-06-05 12:02:32 +02:00
if ( ShowOnlyDuplicates )
2023-02-27 19:11:57 +01:00
{
expressions . Add ( e = > ( ( Entry ) e ) . Duplicate ) ;
}
Expression < Func < object , bool > > filterExpression = null ;
foreach ( var e in expressions )
{
filterExpression = filterExpression = = null ? e : filterExpression . And ( e ) ;
}
Filtered = filterExpression ! = null ;
Entries . Filter = Filtered ? filterExpression . Compile ( ) . Invoke : null ;
Entries . RefreshFilter ( ) ;
2022-10-13 13:05:43 +02:00
}
2023-02-27 19:11:57 +01:00
[RelayCommand]
2022-10-13 13:05:43 +02:00
public void ClearFilters ( )
{
AddressFilter = null ;
HostsFilter = null ;
CommentFilter = null ;
2022-12-14 16:52:00 +01:00
ShowOnlyDuplicates = false ;
2023-06-11 17:59:30 +02:00
ApplyFilters ( ) ;
2022-10-13 13:05:43 +02:00
}
public async Task PingSelectedAsync ( )
{
2023-06-05 12:02:32 +02:00
var selected = Selected ;
2022-10-13 13:05:43 +02:00
selected . Ping = null ;
selected . Pinging = true ;
2023-06-05 12:02:32 +02:00
selected . Ping = await _hostsService . PingAsync ( Selected . Address ) ;
2022-10-13 13:05:43 +02:00
selected . Pinging = false ;
}
2023-02-27 19:11:57 +01:00
[RelayCommand]
2022-10-13 13:05:43 +02:00
public void OpenSettings ( )
{
2024-04-26 19:41:44 +02:00
_openSettingsFunction ( ) ;
2022-10-13 13:05:43 +02:00
}
2023-02-27 19:11:57 +01:00
[RelayCommand]
2022-10-24 20:09:00 +02:00
public void OpenHostsFile ( )
{
_hostsService . OpenHostsFile ( ) ;
}
2023-11-03 17:10:26 +01:00
[RelayCommand]
public void OverwriteHosts ( )
{
2024-08-16 20:36:26 +02:00
_hostsService . RemoveReadOnlyAttribute ( ) ;
2023-11-03 17:10:26 +01:00
_ = Task . Run ( SaveAsync ) ;
}
2022-10-13 13:05:43 +02:00
private void Entry_PropertyChanged ( object sender , System . ComponentModel . PropertyChangedEventArgs e )
{
2023-02-27 19:11:57 +01:00
if ( Filtered & & ( e . PropertyName = = nameof ( Entry . Hosts )
| | e . PropertyName = = nameof ( Entry . Address )
| | e . PropertyName = = nameof ( Entry . Comment )
| | e . PropertyName = = nameof ( Entry . Duplicate ) ) )
{
Entries . RefreshFilter ( ) ;
}
2023-11-21 16:06:01 +01:00
// Ping and duplicate should not trigger a file save
2022-12-14 16:52:00 +01:00
if ( e . PropertyName = = nameof ( Entry . Ping )
| | e . PropertyName = = nameof ( Entry . Pinging )
| | e . PropertyName = = nameof ( Entry . Duplicate ) )
2022-10-13 13:05:43 +02:00
{
return ;
}
2023-09-08 17:25:36 +02:00
_ = Task . Run ( SaveAsync ) ;
2022-10-13 13:05:43 +02:00
}
private void Entries_CollectionChanged ( object sender , System . Collections . Specialized . NotifyCollectionChangedEventArgs e )
{
2023-09-08 17:25:36 +02:00
_ = Task . Run ( SaveAsync ) ;
2022-10-13 13:05:43 +02:00
}
2023-09-08 17:25:36 +02:00
private async Task SaveAsync ( )
{
bool error = true ;
string errorMessage = string . Empty ;
2023-11-03 17:10:26 +01:00
bool isReadOnly = false ;
2023-09-08 17:25:36 +02:00
try
{
await _hostsService . WriteAsync ( AdditionalLines , _entries ) ;
error = false ;
}
catch ( NotRunningElevatedException )
{
var resourceLoader = ResourceLoaderInstance . ResourceLoader ;
errorMessage = resourceLoader . GetString ( "FileSaveError_NotElevated" ) ;
}
2023-11-03 17:10:26 +01:00
catch ( ReadOnlyHostsException )
{
isReadOnly = true ;
var resourceLoader = ResourceLoaderInstance . ResourceLoader ;
errorMessage = resourceLoader . GetString ( "FileSaveError_ReadOnly" ) ;
}
2023-09-08 17:25:36 +02:00
catch ( IOException ex ) when ( ( ex . HResult & 0x0000FFFF ) = = 32 )
{
// There are some edge cases where a big hosts file is being locked by svchost.exe https://github.com/microsoft/PowerToys/issues/28066
var resourceLoader = ResourceLoaderInstance . ResourceLoader ;
errorMessage = resourceLoader . GetString ( "FileSaveError_FileInUse" ) ;
}
catch ( Exception ex )
{
2024-04-26 19:41:44 +02:00
LoggerInstance . Logger . LogError ( "Failed to save hosts file" , ex ) ;
2023-09-08 17:25:36 +02:00
var resourceLoader = ResourceLoaderInstance . ResourceLoader ;
errorMessage = resourceLoader . GetString ( "FileSaveError_Generic" ) ;
}
await _dispatcherQueue . EnqueueAsync ( ( ) = >
{
Error = error ;
ErrorMessage = errorMessage ;
2023-11-03 17:10:26 +01:00
IsReadOnly = isReadOnly ;
2023-09-08 17:25:36 +02:00
} ) ;
}
2022-10-13 13:05:43 +02:00
}
}