2021-05-21 18:32:34 +08:00
// Copyright (c) Microsoft Corporation
2020-04-08 01:19:14 +08:00
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
2020-04-18 06:25:08 +08:00
using System ;
2021-05-21 18:32:34 +08:00
using System.Diagnostics ;
2020-10-22 03:32:53 +08:00
using System.Diagnostics.CodeAnalysis ;
2021-05-21 18:32:34 +08:00
using System.IO.Abstractions ;
2020-04-18 06:25:08 +08:00
using System.Runtime.CompilerServices ;
2020-10-23 00:45:48 +08:00
using Microsoft.PowerToys.Settings.UI.Library.Helpers ;
using Microsoft.PowerToys.Settings.UI.Library.Interfaces ;
using Microsoft.PowerToys.Settings.UI.Library.Utilities ;
using Microsoft.PowerToys.Settings.UI.Library.ViewModels.Commands ;
2020-03-12 14:25:24 +08:00
2020-10-23 00:45:48 +08:00
namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
2020-03-12 14:25:24 +08:00
{
public class GeneralViewModel : Observable
{
2020-09-24 04:20:32 +08:00
private GeneralSettings GeneralSettingsConfig { get ; set ; }
2020-09-22 01:14:44 +08:00
2021-05-21 18:32:34 +08:00
private UpdatingSettings UpdatingSettingsConfig { get ; set ; }
2020-10-10 08:58:52 +08:00
public ButtonClickCommand CheckForUpdatesEventHandler { get ; set ; }
2020-04-18 06:25:08 +08:00
public ButtonClickCommand RestartElevatedButtonEventHandler { get ; set ; }
2021-05-21 18:32:34 +08:00
public ButtonClickCommand UpdateNowButtonEventHandler { get ; set ; }
2020-08-14 06:02:05 +08:00
public Func < string , int > UpdateUIThemeCallBack { get ; }
2020-08-07 02:16:25 +08:00
2020-08-14 06:02:05 +08:00
public Func < string , int > SendConfigMSG { get ; }
2020-08-07 02:16:25 +08:00
2020-08-14 06:02:05 +08:00
public Func < string , int > SendRestartAsAdminConfigMSG { get ; }
public Func < string , int > SendCheckForUpdatesConfigMSG { get ; }
2020-08-20 06:59:10 +08:00
public string RunningAsUserDefaultText { get ; set ; }
2020-08-14 06:02:05 +08:00
2020-08-20 06:59:10 +08:00
public string RunningAsAdminDefaultText { get ; set ; }
2020-05-06 01:02:31 +08:00
2020-08-20 06:59:10 +08:00
private string _settingsConfigFileFolder = string . Empty ;
2020-08-14 06:02:05 +08:00
2021-05-21 18:32:34 +08:00
private IFileSystemWatcher _fileWatcher ;
public GeneralViewModel ( ISettingsRepository < GeneralSettings > settingsRepository , string runAsAdminText , string runAsUserText , bool isElevated , bool isAdmin , Func < string , int > updateTheme , Func < string , int > ipcMSGCallBackFunc , Func < string , int > ipcMSGRestartAsAdminMSGCallBackFunc , Func < string , int > ipcMSGCheckForUpdatesCallBackFunc , string configFileSubfolder = "" , Action dispatcherAction = null )
2020-03-12 14:25:24 +08:00
{
2020-10-10 08:58:52 +08:00
CheckForUpdatesEventHandler = new ButtonClickCommand ( CheckForUpdatesClick ) ;
RestartElevatedButtonEventHandler = new ButtonClickCommand ( RestartElevated ) ;
2021-05-21 18:32:34 +08:00
UpdateNowButtonEventHandler = new ButtonClickCommand ( UpdateNowClick ) ;
2020-04-18 06:25:08 +08:00
2020-09-24 04:20:32 +08:00
// To obtain the general settings configuration of PowerToys if it exists, else to create a new file and return the default configurations.
2020-10-20 04:32:05 +08:00
if ( settingsRepository = = null )
{
throw new ArgumentNullException ( nameof ( settingsRepository ) ) ;
}
2020-09-24 04:20:32 +08:00
GeneralSettingsConfig = settingsRepository . SettingsConfig ;
2021-05-21 18:32:34 +08:00
UpdatingSettingsConfig = UpdatingSettings . LoadSettings ( ) ;
if ( UpdatingSettingsConfig = = null )
{
UpdatingSettingsConfig = new UpdatingSettings ( ) ;
}
2020-04-18 06:25:08 +08:00
2020-08-14 06:02:05 +08:00
// set the callback functions value to hangle outgoing IPC message.
SendConfigMSG = ipcMSGCallBackFunc ;
SendCheckForUpdatesConfigMSG = ipcMSGCheckForUpdatesCallBackFunc ;
SendRestartAsAdminConfigMSG = ipcMSGRestartAsAdminMSGCallBackFunc ;
// set the callback function value to update the UI theme.
UpdateUIThemeCallBack = updateTheme ;
2020-10-20 04:32:05 +08:00
UpdateUIThemeCallBack ( GeneralSettingsConfig . Theme ) ;
2020-08-14 06:02:05 +08:00
// Update Settings file folder:
2020-08-20 06:59:10 +08:00
_settingsConfigFileFolder = configFileSubfolder ;
2020-08-14 06:02:05 +08:00
2020-10-20 04:32:05 +08:00
// Using Invariant here as these are internal strings and fxcop
// expects strings to be normalized to uppercase. While the theme names
// are represented in lowercase everywhere else, we'll use uppercase
// normalization for switch statements
switch ( GeneralSettingsConfig . Theme . ToUpperInvariant ( ) )
2020-04-18 06:25:08 +08:00
{
2020-10-20 04:32:05 +08:00
case "LIGHT" :
2020-04-18 06:25:08 +08:00
_isLightThemeRadioButtonChecked = true ;
break ;
2020-10-20 04:32:05 +08:00
case "DARK" :
2020-04-18 06:25:08 +08:00
_isDarkThemeRadioButtonChecked = true ;
break ;
2020-10-20 04:32:05 +08:00
case "SYSTEM" :
2020-04-18 06:25:08 +08:00
_isSystemThemeRadioButtonChecked = true ;
break ;
}
2020-09-24 04:20:32 +08:00
_startup = GeneralSettingsConfig . Startup ;
_autoDownloadUpdates = GeneralSettingsConfig . AutoDownloadUpdates ;
2020-08-14 06:02:05 +08:00
_isElevated = isElevated ;
2020-09-24 04:20:32 +08:00
_runElevated = GeneralSettingsConfig . RunElevated ;
2020-05-16 00:38:47 +08:00
2020-08-14 06:02:05 +08:00
RunningAsUserDefaultText = runAsUserText ;
RunningAsAdminDefaultText = runAsAdminText ;
2020-05-16 00:38:47 +08:00
2020-08-14 06:02:05 +08:00
_isAdmin = isAdmin ;
2021-05-21 18:32:34 +08:00
_updatingState = UpdatingSettingsConfig . State ;
_newAvailableVersion = UpdatingSettingsConfig . NewVersion ;
_newAvailableVersionLink = UpdatingSettingsConfig . ReleasePageLink ;
_updateCheckedDate = UpdatingSettingsConfig . LastCheckedDateLocalized ;
if ( dispatcherAction ! = null )
{
_fileWatcher = Helper . GetFileWatcher ( string . Empty , UpdatingSettings . SettingsFile , dispatcherAction ) ;
}
2020-04-18 06:25:08 +08:00
}
2020-10-10 08:58:52 +08:00
private bool _startup ;
private bool _isElevated ;
private bool _runElevated ;
private bool _isAdmin ;
private bool _isDarkThemeRadioButtonChecked ;
private bool _isLightThemeRadioButtonChecked ;
private bool _isSystemThemeRadioButtonChecked ;
private bool _autoDownloadUpdates ;
2020-08-14 06:02:05 +08:00
2021-05-21 18:32:34 +08:00
private UpdatingSettings . UpdatingState _updatingState = UpdatingSettings . UpdatingState . UpToDate ;
private string _newAvailableVersion = string . Empty ;
private string _newAvailableVersionLink = string . Empty ;
2020-12-18 00:38:23 +08:00
private string _updateCheckedDate = string . Empty ;
2020-09-04 16:56:52 +08:00
2021-05-21 18:32:34 +08:00
private bool _isNewVersionDownloading ;
private bool _isNewVersionChecked ;
2020-04-18 06:25:08 +08:00
// Gets or sets a value indicating whether run powertoys on start-up.
public bool Startup
{
get
{
return _startup ;
}
set
{
if ( _startup ! = value )
{
_startup = value ;
2020-09-24 04:20:32 +08:00
GeneralSettingsConfig . Startup = value ;
2020-10-20 04:32:05 +08:00
NotifyPropertyChanged ( ) ;
2020-04-18 06:25:08 +08:00
}
}
}
2020-05-16 00:38:47 +08:00
public string RunningAsText
2020-05-06 01:02:31 +08:00
{
get
{
if ( ! IsElevated )
{
2020-05-16 00:38:47 +08:00
return RunningAsUserDefaultText ;
2020-05-06 01:02:31 +08:00
}
else
{
2020-05-16 00:38:47 +08:00
return RunningAsAdminDefaultText ;
2020-05-06 01:02:31 +08:00
}
}
set
{
OnPropertyChanged ( "RunningAsAdminText" ) ;
}
}
2020-04-18 06:25:08 +08:00
// Gets or sets a value indicating whether the powertoy elevated.
public bool IsElevated
{
get
{
return _isElevated ;
}
set
{
if ( _isElevated ! = value )
{
_isElevated = value ;
2020-10-10 08:58:52 +08:00
OnPropertyChanged ( nameof ( IsElevated ) ) ;
OnPropertyChanged ( nameof ( IsAdminButtonEnabled ) ) ;
2020-05-06 01:02:31 +08:00
OnPropertyChanged ( "RunningAsAdminText" ) ;
2020-04-18 06:25:08 +08:00
}
}
}
2020-05-06 01:02:31 +08:00
public bool IsAdminButtonEnabled
{
get
{
return ! IsElevated ;
}
set
{
2020-10-10 08:58:52 +08:00
OnPropertyChanged ( nameof ( IsAdminButtonEnabled ) ) ;
2020-05-06 01:02:31 +08:00
}
}
2020-04-18 06:25:08 +08:00
// Gets or sets a value indicating whether powertoys should run elevated.
public bool RunElevated
{
get
{
return _runElevated ;
}
set
{
if ( _runElevated ! = value )
{
_runElevated = value ;
2020-09-24 04:20:32 +08:00
GeneralSettingsConfig . RunElevated = value ;
2020-10-20 04:32:05 +08:00
NotifyPropertyChanged ( ) ;
2020-04-18 06:25:08 +08:00
}
}
}
2020-05-14 17:36:27 +08:00
// Gets a value indicating whether the user is part of administrators group.
public bool IsAdmin
{
get
{
return _isAdmin ;
}
}
2020-05-03 18:17:06 +08:00
public bool AutoDownloadUpdates
{
get
{
return _autoDownloadUpdates ;
}
set
{
if ( _autoDownloadUpdates ! = value )
{
_autoDownloadUpdates = value ;
2020-09-24 04:20:32 +08:00
GeneralSettingsConfig . AutoDownloadUpdates = value ;
2020-10-20 04:32:05 +08:00
NotifyPropertyChanged ( ) ;
2020-05-03 18:17:06 +08:00
}
}
}
2021-01-12 23:34:02 +08:00
public static bool AutoUpdatesEnabled
{
get
{
return Helper . GetProductVersion ( ) ! = "v0.0.1" ;
}
}
2020-10-22 03:32:53 +08:00
[SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "This may throw if the XAML page is not initialized in tests (https://github.com/microsoft/PowerToys/pull/2676)")]
2020-04-18 06:25:08 +08:00
public bool IsDarkThemeRadioButtonChecked
{
get
{
return _isDarkThemeRadioButtonChecked ;
}
set
{
if ( value = = true )
{
2020-09-24 04:20:32 +08:00
GeneralSettingsConfig . Theme = "dark" ;
2020-04-18 06:25:08 +08:00
_isDarkThemeRadioButtonChecked = value ;
2020-05-06 01:02:31 +08:00
try
{
2020-09-24 04:20:32 +08:00
UpdateUIThemeCallBack ( GeneralSettingsConfig . Theme ) ;
2020-05-06 01:02:31 +08:00
}
2020-10-22 03:32:53 +08:00
catch ( Exception e )
2020-05-06 01:02:31 +08:00
{
2020-10-22 03:32:53 +08:00
Logger . LogError ( "Exception encountered when changing Settings theme" , e ) ;
2020-05-06 01:02:31 +08:00
}
2020-10-20 04:32:05 +08:00
NotifyPropertyChanged ( ) ;
2020-04-18 06:25:08 +08:00
}
}
}
2020-10-22 03:32:53 +08:00
[SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "This may throw if the XAML page is not initialized in tests (https://github.com/microsoft/PowerToys/pull/2676)")]
2020-04-18 06:25:08 +08:00
public bool IsLightThemeRadioButtonChecked
{
get
{
return _isLightThemeRadioButtonChecked ;
}
set
{
if ( value = = true )
{
2020-09-24 04:20:32 +08:00
GeneralSettingsConfig . Theme = "light" ;
2020-04-18 06:25:08 +08:00
_isLightThemeRadioButtonChecked = value ;
2020-05-06 01:02:31 +08:00
try
{
2020-09-24 04:20:32 +08:00
UpdateUIThemeCallBack ( GeneralSettingsConfig . Theme ) ;
2020-05-06 01:02:31 +08:00
}
2020-10-22 03:32:53 +08:00
catch ( Exception e )
2020-05-06 01:02:31 +08:00
{
2020-10-22 03:32:53 +08:00
Logger . LogError ( "Exception encountered when changing Settings theme" , e ) ;
2020-05-06 01:02:31 +08:00
}
2020-10-20 04:32:05 +08:00
NotifyPropertyChanged ( ) ;
2020-04-18 06:25:08 +08:00
}
}
}
2020-10-22 03:32:53 +08:00
[SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "This may throw if the XAML page is not initialized in tests (https://github.com/microsoft/PowerToys/pull/2676)")]
2020-04-18 06:25:08 +08:00
public bool IsSystemThemeRadioButtonChecked
{
get
{
return _isSystemThemeRadioButtonChecked ;
}
set
{
if ( value = = true )
{
2020-09-24 04:20:32 +08:00
GeneralSettingsConfig . Theme = "system" ;
2020-04-18 06:25:08 +08:00
_isSystemThemeRadioButtonChecked = value ;
2020-05-06 01:02:31 +08:00
try
{
2020-09-24 04:20:32 +08:00
UpdateUIThemeCallBack ( GeneralSettingsConfig . Theme ) ;
2020-05-06 01:02:31 +08:00
}
2020-10-22 03:32:53 +08:00
catch ( Exception e )
2020-05-06 01:02:31 +08:00
{
2020-10-22 03:32:53 +08:00
Logger . LogError ( "Exception encountered when changing Settings theme" , e ) ;
2020-05-06 01:02:31 +08:00
}
2020-10-20 04:32:05 +08:00
NotifyPropertyChanged ( ) ;
2020-04-18 06:25:08 +08:00
}
}
}
2020-10-10 08:58:52 +08:00
// FxCop suggests marking this member static, but it is accessed through
// an instance in autogenerated files (GeneralPage.g.cs) and will break
// the file if modified
#pragma warning disable CA1822 // Mark members as static
2020-05-06 01:02:31 +08:00
public string PowerToysVersion
2020-10-10 08:58:52 +08:00
#pragma warning restore CA1822 // Mark members as static
2020-05-06 01:02:31 +08:00
{
get
{
return Helper . GetProductVersion ( ) ;
}
2020-05-05 05:40:32 +08:00
}
2020-12-18 00:38:23 +08:00
public string UpdateCheckedDate
{
get
{
RequestUpdateCheckedDate ( ) ;
return _updateCheckedDate ;
}
set
{
if ( _updateCheckedDate ! = value )
{
_updateCheckedDate = value ;
NotifyPropertyChanged ( ) ;
}
}
}
2021-05-21 18:32:34 +08:00
public UpdatingSettings . UpdatingState PowerToysUpdatingState
{
get
{
return _updatingState ;
}
private set
{
if ( value ! = _updatingState )
{
_updatingState = value ;
NotifyPropertyChanged ( ) ;
}
}
}
public string PowerToysNewAvailableVersion
{
get
{
return _newAvailableVersion ;
}
private set
{
if ( value ! = _newAvailableVersion )
{
_newAvailableVersion = value ;
NotifyPropertyChanged ( ) ;
}
}
}
public string PowerToysNewAvailableVersionLink
{
get
{
return _newAvailableVersionLink ;
}
private set
{
if ( value ! = _newAvailableVersionLink )
{
_newAvailableVersionLink = value ;
NotifyPropertyChanged ( ) ;
}
}
}
public bool IsNewVersionDownloading
2020-09-04 16:56:52 +08:00
{
get
{
2021-05-21 18:32:34 +08:00
return _isNewVersionDownloading ;
2020-09-04 16:56:52 +08:00
}
set
{
2021-05-21 18:32:34 +08:00
if ( value ! = _isNewVersionDownloading )
2020-09-04 16:56:52 +08:00
{
2021-05-21 18:32:34 +08:00
_isNewVersionDownloading = value ;
2020-10-20 04:32:05 +08:00
NotifyPropertyChanged ( ) ;
2020-09-04 16:56:52 +08:00
}
}
}
2021-05-21 18:32:34 +08:00
public bool IsNewVersionCheckedAndUpToDate
{
get
{
return _isNewVersionChecked ;
}
}
public bool IsDownloadAllowed
{
get
{
return AutoUpdatesEnabled & & ! IsNewVersionDownloading ;
}
}
2020-10-20 04:32:05 +08:00
public void NotifyPropertyChanged ( [ CallerMemberName ] string propertyName = null )
2020-04-18 06:25:08 +08:00
{
// Notify UI of property change
OnPropertyChanged ( propertyName ) ;
2020-09-24 04:20:32 +08:00
OutGoingGeneralSettings outsettings = new OutGoingGeneralSettings ( GeneralSettingsConfig ) ;
2020-04-18 06:25:08 +08:00
2020-08-14 06:02:05 +08:00
SendConfigMSG ( outsettings . ToString ( ) ) ;
2020-04-18 06:25:08 +08:00
}
// callback function to launch the URL to check for updates.
2020-10-10 08:58:52 +08:00
private void CheckForUpdatesClick ( )
2020-04-18 06:25:08 +08:00
{
2021-08-12 19:53:51 +08:00
RefreshUpdatingState ( ) ;
2021-05-21 18:32:34 +08:00
IsNewVersionDownloading = string . IsNullOrEmpty ( UpdatingSettingsConfig . DownloadedInstallerFilename ) ;
NotifyPropertyChanged ( nameof ( IsDownloadAllowed ) ) ;
if ( _isNewVersionChecked )
{
_isNewVersionChecked = ! IsNewVersionDownloading ;
NotifyPropertyChanged ( nameof ( IsNewVersionCheckedAndUpToDate ) ) ;
}
2020-09-25 01:50:49 +08:00
GeneralSettingsConfig . CustomActionName = "check_for_updates" ;
2020-06-23 20:53:02 +08:00
2020-09-25 01:50:49 +08:00
OutGoingGeneralSettings outsettings = new OutGoingGeneralSettings ( GeneralSettingsConfig ) ;
2020-06-23 20:53:02 +08:00
GeneralSettingsCustomAction customaction = new GeneralSettingsCustomAction ( outsettings ) ;
2020-12-18 00:38:23 +08:00
SendCheckForUpdatesConfigMSG ( customaction . ToString ( ) ) ;
}
2021-05-21 18:32:34 +08:00
private void UpdateNowClick ( )
{
IsNewVersionDownloading = string . IsNullOrEmpty ( UpdatingSettingsConfig . DownloadedInstallerFilename ) ;
NotifyPropertyChanged ( nameof ( IsDownloadAllowed ) ) ;
Process . Start ( new ProcessStartInfo ( Helper . GetPowerToysInstallationFolder ( ) + "\\PowerToys.exe" ) { Arguments = "powertoys://update_now/" } ) ;
}
2021-01-12 23:34:02 +08:00
public void RequestUpdateCheckedDate ( )
2020-12-18 00:38:23 +08:00
{
GeneralSettingsConfig . CustomActionName = "request_update_state_date" ;
OutGoingGeneralSettings outsettings = new OutGoingGeneralSettings ( GeneralSettingsConfig ) ;
GeneralSettingsCustomAction customaction = new GeneralSettingsCustomAction ( outsettings ) ;
2020-08-14 06:02:05 +08:00
SendCheckForUpdatesConfigMSG ( customaction . ToString ( ) ) ;
2020-04-18 06:25:08 +08:00
}
2020-10-10 08:58:52 +08:00
public void RestartElevated ( )
2020-04-18 06:25:08 +08:00
{
2020-09-25 01:50:49 +08:00
GeneralSettingsConfig . CustomActionName = "restart_elevation" ;
2020-05-03 18:17:06 +08:00
2020-09-25 01:50:49 +08:00
OutGoingGeneralSettings outsettings = new OutGoingGeneralSettings ( GeneralSettingsConfig ) ;
2020-05-03 18:17:06 +08:00
GeneralSettingsCustomAction customaction = new GeneralSettingsCustomAction ( outsettings ) ;
2020-04-18 06:25:08 +08:00
2020-08-14 06:02:05 +08:00
SendRestartAsAdminConfigMSG ( customaction . ToString ( ) ) ;
2020-03-12 14:25:24 +08:00
}
2021-05-21 18:32:34 +08:00
public void RefreshUpdatingState ( )
{
var config = UpdatingSettings . LoadSettings ( ) ;
// Retry loading if failed
for ( int i = 0 ; i < 3 & & config = = null ; i + + )
{
System . Threading . Thread . Sleep ( 100 ) ;
config = UpdatingSettings . LoadSettings ( ) ;
}
if ( config = = null | | config . ToJsonString ( ) = = UpdatingSettingsConfig . ToJsonString ( ) )
{
return ;
}
UpdatingSettingsConfig = config ;
if ( PowerToysUpdatingState ! = config . State )
{
IsNewVersionDownloading = false ;
}
else
{
bool dateChanged = UpdateCheckedDate = = UpdatingSettingsConfig . LastCheckedDateLocalized ;
bool fileDownloaded = string . IsNullOrEmpty ( UpdatingSettingsConfig . DownloadedInstallerFilename ) ;
IsNewVersionDownloading = ! ( dateChanged | | fileDownloaded ) ;
}
PowerToysUpdatingState = UpdatingSettingsConfig . State ;
PowerToysNewAvailableVersion = UpdatingSettingsConfig . NewVersion ;
PowerToysNewAvailableVersionLink = UpdatingSettingsConfig . ReleasePageLink ;
UpdateCheckedDate = UpdatingSettingsConfig . LastCheckedDateLocalized ;
_isNewVersionChecked = PowerToysUpdatingState = = UpdatingSettings . UpdatingState . UpToDate & & ! IsNewVersionDownloading ;
NotifyPropertyChanged ( nameof ( IsNewVersionCheckedAndUpToDate ) ) ;
NotifyPropertyChanged ( nameof ( IsDownloadAllowed ) ) ;
}
2020-03-12 14:25:24 +08:00
}
}