2022-12-04 07:47:48 +00:00
#nullable enable
2020-06-08 08:41:59 +00:00
using Flow.Launcher.Plugin.Explorer.Search ;
2022-07-04 00:50:02 +00:00
using Flow.Launcher.Plugin.Explorer.Search.Everything ;
using Flow.Launcher.Plugin.Explorer.Search.Everything.Exceptions ;
2021-01-26 09:48:06 +00:00
using Flow.Launcher.Plugin.Explorer.Search.QuickAccessLinks ;
2022-07-01 04:56:15 +00:00
using Flow.Launcher.Plugin.Explorer.Views ;
2022-07-04 00:50:02 +00:00
using System ;
using System.Collections.Generic ;
2020-06-08 08:41:59 +00:00
using System.Diagnostics ;
2022-12-04 17:38:19 +00:00
using System.Diagnostics.CodeAnalysis ;
2022-07-01 04:56:15 +00:00
using System.IO ;
2022-07-04 00:50:02 +00:00
using System.Linq ;
using System.Windows ;
2022-07-01 04:56:15 +00:00
using System.Windows.Forms ;
using System.Windows.Input ;
2022-07-04 00:50:02 +00:00
using MessageBox = System . Windows . Forms . MessageBox ;
2020-05-11 13:15:15 +00:00
namespace Flow.Launcher.Plugin.Explorer.ViewModels
{
2022-07-04 00:50:02 +00:00
public class SettingsViewModel : BaseModel
2020-05-11 13:15:15 +00:00
{
2022-03-25 21:19:00 +00:00
public Settings Settings { get ; set ; }
2020-05-11 13:15:15 +00:00
2020-06-08 04:20:22 +00:00
internal PluginInitContext Context { get ; set ; }
2022-07-04 00:50:02 +00:00
public IReadOnlyList < EnumBindingModel < Settings . IndexSearchEngineOption > > IndexSearchEngines { get ; set ; }
public IReadOnlyList < EnumBindingModel < Settings . ContentIndexSearchEngineOption > > ContentIndexSearchEngines { get ; set ; }
public IReadOnlyList < EnumBindingModel < Settings . PathEnumerationEngineOption > > PathEnumerationEngines { get ; set ; }
2021-05-11 12:18:57 +00:00
public SettingsViewModel ( PluginInitContext context , Settings settings )
2020-05-11 13:15:15 +00:00
{
2020-06-08 04:20:22 +00:00
Context = context ;
2021-05-11 12:18:57 +00:00
Settings = settings ;
2022-07-04 00:50:02 +00:00
InitializeEngineSelection ( ) ;
InitializeActionKeywordModels ( ) ;
2020-05-11 13:15:15 +00:00
}
2021-01-02 14:01:15 +00:00
2020-05-11 13:15:15 +00:00
public void Save ( )
{
2021-05-13 11:29:21 +00:00
Context . API . SaveSettingJsonStorage < Settings > ( ) ;
2020-05-11 13:15:15 +00:00
}
2020-06-08 04:20:22 +00:00
2022-07-04 00:50:02 +00:00
#region Engine Selection
2022-07-01 04:56:15 +00:00
2022-07-04 00:50:02 +00:00
private EnumBindingModel < Settings . IndexSearchEngineOption > _selectedIndexSearchEngine ;
private EnumBindingModel < Settings . ContentIndexSearchEngineOption > _selectedContentSearchEngine ;
private EnumBindingModel < Settings . PathEnumerationEngineOption > _selectedPathEnumerationEngine ;
2022-07-01 04:56:15 +00:00
2022-07-04 00:50:02 +00:00
public EnumBindingModel < Settings . IndexSearchEngineOption > SelectedIndexSearchEngine
{
get = > _selectedIndexSearchEngine ;
set
{
_selectedIndexSearchEngine = value ;
Settings . IndexSearchEngine = value . Value ;
OnPropertyChanged ( ) ;
}
}
public EnumBindingModel < Settings . ContentIndexSearchEngineOption > SelectedContentSearchEngine
{
get = > _selectedContentSearchEngine ;
set
{
_selectedContentSearchEngine = value ;
Settings . ContentSearchEngine = value . Value ;
OnPropertyChanged ( ) ;
}
}
2022-07-01 04:56:15 +00:00
2022-07-04 00:50:02 +00:00
public EnumBindingModel < Settings . PathEnumerationEngineOption > SelectedPathEnumerationEngine
{
get = > _selectedPathEnumerationEngine ;
set
{
_selectedPathEnumerationEngine = value ;
Settings . PathEnumerationEngine = value . Value ;
OnPropertyChanged ( ) ;
}
}
2022-12-04 17:38:19 +00:00
[ MemberNotNull ( nameof ( IndexSearchEngines ) ,
nameof ( ContentIndexSearchEngines ) ,
nameof ( PathEnumerationEngines ) ,
nameof ( _selectedIndexSearchEngine ) ,
nameof ( _selectedContentSearchEngine ) ,
nameof ( _selectedPathEnumerationEngine ) ) ]
2022-07-04 00:50:02 +00:00
private void InitializeEngineSelection ( )
{
IndexSearchEngines = EnumBindingModel < Settings . IndexSearchEngineOption > . CreateList ( ) ;
ContentIndexSearchEngines = EnumBindingModel < Settings . ContentIndexSearchEngineOption > . CreateList ( ) ;
PathEnumerationEngines = EnumBindingModel < Settings . PathEnumerationEngineOption > . CreateList ( ) ;
2022-12-04 17:38:19 +00:00
_selectedIndexSearchEngine = IndexSearchEngines . First ( x = > x . Value = = Settings . IndexSearchEngine ) ;
_selectedContentSearchEngine = ContentIndexSearchEngines . First ( x = > x . Value = = Settings . ContentSearchEngine ) ;
_selectedPathEnumerationEngine = PathEnumerationEngines . First ( x = > x . Value = = Settings . PathEnumerationEngine ) ;
2022-07-04 00:50:02 +00:00
}
#endregion
#region ActionKeyword
2022-12-04 17:38:19 +00:00
[MemberNotNull(nameof(ActionKeywordsModels))]
2022-07-04 00:50:02 +00:00
private void InitializeActionKeywordModels ( )
{
ActionKeywordsModels = new List < ActionKeywordModel >
{
new ( Settings . ActionKeyword . SearchActionKeyword ,
2022-12-21 07:51:53 +00:00
"plugin_explorer_actionkeywordview_search" ) ,
2022-07-04 00:50:02 +00:00
new ( Settings . ActionKeyword . FileContentSearchActionKeyword ,
2022-12-21 07:51:53 +00:00
"plugin_explorer_actionkeywordview_filecontentsearch" ) ,
2022-07-04 00:50:02 +00:00
new ( Settings . ActionKeyword . PathSearchActionKeyword ,
2022-12-21 07:51:53 +00:00
"plugin_explorer_actionkeywordview_pathsearch" ) ,
2022-07-04 00:50:02 +00:00
new ( Settings . ActionKeyword . IndexSearchActionKeyword ,
2022-12-21 07:51:53 +00:00
"plugin_explorer_actionkeywordview_indexsearch" ) ,
2022-07-04 00:50:02 +00:00
new ( Settings . ActionKeyword . QuickAccessActionKeyword ,
2022-12-21 07:51:53 +00:00
"plugin_explorer_actionkeywordview_quickaccess" )
2022-07-04 00:50:02 +00:00
} ;
}
public IReadOnlyList < ActionKeywordModel > ActionKeywordsModels { get ; set ; }
2022-12-04 07:47:48 +00:00
public ActionKeywordModel ? SelectedActionKeyword { get ; set ; }
2022-07-01 04:56:15 +00:00
public ICommand EditActionKeywordCommand = > new RelayCommand ( EditActionKeyword ) ;
private void EditActionKeyword ( object obj )
{
2022-12-04 07:47:48 +00:00
if ( SelectedActionKeyword is not { } actionKeyword )
2022-07-01 04:56:15 +00:00
{
ShowUnselectedMessage ( ) ;
return ;
}
var actionKeywordWindow = new ActionKeywordSetting ( actionKeyword , Context . API ) ;
2022-07-04 00:50:02 +00:00
if ( ! ( actionKeywordWindow . ShowDialog ( ) ? ? false ) )
2022-07-01 04:56:15 +00:00
{
2022-07-04 00:50:02 +00:00
return ;
}
switch ( actionKeyword . Enabled , actionKeywordWindow . KeywordEnabled )
{
case ( true , false ) :
2022-07-01 04:56:15 +00:00
Context . API . RemoveActionKeyword ( Context . CurrentPluginMetadata . ID , actionKeyword . Keyword ) ;
2022-07-04 00:50:02 +00:00
break ;
case ( true , true ) :
2022-07-01 04:56:15 +00:00
// same keyword will have dialog result false
Context . API . RemoveActionKeyword ( Context . CurrentPluginMetadata . ID , actionKeyword . Keyword ) ;
Context . API . AddActionKeyword ( Context . CurrentPluginMetadata . ID , actionKeywordWindow . ActionKeyword ) ;
2022-07-04 00:50:02 +00:00
break ;
case ( false , true ) :
2022-12-04 07:47:48 +00:00
Context . API . AddActionKeyword ( Context . CurrentPluginMetadata . ID , actionKeywordWindow . ActionKeyword ) ;
2022-07-04 00:50:02 +00:00
break ;
case ( false , false ) :
throw new ArgumentException (
$"Both false in {nameof(actionKeyword)}.{nameof(actionKeyword.Enabled)} and {nameof(actionKeywordWindow)}.{nameof(actionKeywordWindow.KeywordEnabled)} should suggest that the ShowDialog() result is false" ) ;
2022-07-01 04:56:15 +00:00
}
2022-07-04 00:50:02 +00:00
( actionKeyword . Keyword , actionKeyword . Enabled ) = ( actionKeywordWindow . ActionKeyword , actionKeywordWindow . KeywordEnabled ) ;
2022-07-01 04:56:15 +00:00
}
2022-07-04 00:50:02 +00:00
#endregion
2022-07-01 04:56:15 +00:00
2022-07-04 00:50:02 +00:00
#region AccessLinks
2022-07-01 04:56:15 +00:00
2022-12-04 07:47:48 +00:00
public AccessLink ? SelectedQuickAccessLink { get ; set ; }
public AccessLink ? SelectedIndexSearchExcludedPath { get ; set ; }
2022-07-01 04:56:15 +00:00
2022-07-04 00:50:02 +00:00
public ICommand RemoveLinkCommand = > new RelayCommand ( RemoveLink ) ;
public ICommand EditLinkCommand = > new RelayCommand ( EditLink ) ;
public ICommand AddLinkCommand = > new RelayCommand ( AddLink ) ;
2022-07-01 04:56:15 +00:00
2022-07-04 00:50:02 +00:00
public void AppendLink ( string containerName , AccessLink link )
{
var container = containerName switch
{
"QuickAccessLink" = > Settings . QuickAccessLinks ,
2022-11-04 06:29:18 +00:00
"IndexSearchExcludedPaths" = > Settings . IndexSearchExcludedSubdirectoryPaths ,
2022-07-04 00:50:02 +00:00
_ = > throw new ArgumentException ( $"Unknown container name: {containerName}" )
} ;
container . Add ( link ) ;
2022-07-01 04:56:15 +00:00
}
2022-07-04 00:50:02 +00:00
private void EditLink ( object commandParameter )
2022-07-01 04:56:15 +00:00
{
2022-12-04 07:47:48 +00:00
var ( selectedLink , collection ) = commandParameter switch
2022-07-04 00:50:02 +00:00
{
"QuickAccessLink" = > ( SelectedQuickAccessLink , Settings . QuickAccessLinks ) ,
2022-11-04 06:29:18 +00:00
"IndexSearchExcludedPaths" = > ( SelectedIndexSearchExcludedPath , Settings . IndexSearchExcludedSubdirectoryPaths ) ,
2022-07-04 00:50:02 +00:00
_ = > throw new ArgumentOutOfRangeException ( nameof ( commandParameter ) )
} ;
2022-07-01 04:56:15 +00:00
2022-07-04 00:50:02 +00:00
if ( selectedLink is null )
2022-07-01 04:56:15 +00:00
{
2022-07-04 00:50:02 +00:00
ShowUnselectedMessage ( ) ;
return ;
2022-07-01 04:56:15 +00:00
}
2022-07-04 00:50:02 +00:00
var path = PromptUserSelectPath ( selectedLink . Type ,
2022-07-01 04:56:15 +00:00
selectedLink . Type = = ResultType . Folder
? selectedLink . Path
: Path . GetDirectoryName ( selectedLink . Path ) ) ;
2022-07-04 00:50:02 +00:00
if ( path is null )
2022-07-01 04:56:15 +00:00
return ;
collection . Remove ( selectedLink ) ;
2022-07-04 00:50:02 +00:00
collection . Add ( new AccessLink
{
Path = path , Type = selectedLink . Type ,
} ) ;
2022-07-01 04:56:15 +00:00
}
private void ShowUnselectedMessage ( )
{
2022-07-04 00:50:02 +00:00
var warning = Context . API . GetTranslation ( "plugin_explorer_make_selection_warning" ) ;
2022-07-01 04:56:15 +00:00
MessageBox . Show ( warning ) ;
}
2022-07-04 00:50:02 +00:00
private void AddLink ( object commandParameter )
2022-07-01 04:56:15 +00:00
{
2022-07-04 00:50:02 +00:00
var container = commandParameter switch
{
"QuickAccessLink" = > Settings . QuickAccessLinks ,
"IndexSearchExcludedPaths" = > Settings . IndexSearchExcludedSubdirectoryPaths ,
_ = > throw new ArgumentOutOfRangeException ( nameof ( commandParameter ) )
} ;
ArgumentNullException . ThrowIfNull ( container ) ;
2022-07-01 04:56:15 +00:00
var folderBrowserDialog = new FolderBrowserDialog ( ) ;
if ( folderBrowserDialog . ShowDialog ( ) ! = DialogResult . OK )
return ;
2022-07-04 00:50:02 +00:00
var newAccessLink = new AccessLink
2022-07-01 04:56:15 +00:00
{
2022-07-04 00:50:02 +00:00
Path = folderBrowserDialog . SelectedPath
} ;
container . Add ( newAccessLink ) ;
2022-07-01 04:56:15 +00:00
}
private void RemoveLink ( object obj )
{
if ( obj is not string container ) return ;
switch ( container )
{
case "QuickAccessLink" :
if ( SelectedQuickAccessLink = = null ) return ;
Settings . QuickAccessLinks . Remove ( SelectedQuickAccessLink ) ;
break ;
case "IndexSearchExcludedPaths" :
if ( SelectedIndexSearchExcludedPath = = null ) return ;
Settings . IndexSearchExcludedSubdirectoryPaths . Remove ( SelectedIndexSearchExcludedPath ) ;
break ;
}
Save ( ) ;
}
2022-07-04 00:50:02 +00:00
#endregion
2022-12-04 07:47:48 +00:00
private string? PromptUserSelectPath ( ResultType type , string? initialDirectory = null )
2022-07-04 00:50:02 +00:00
{
2022-12-04 07:47:48 +00:00
string? path = null ;
2022-07-04 00:50:02 +00:00
if ( type is ResultType . Folder )
{
var folderBrowserDialog = new FolderBrowserDialog ( ) ;
if ( initialDirectory is not null )
folderBrowserDialog . InitialDirectory = initialDirectory ;
if ( folderBrowserDialog . ShowDialog ( ) ! = DialogResult . OK )
return path ;
path = folderBrowserDialog . SelectedPath ;
}
else if ( type is ResultType . File )
{
var openFileDialog = new OpenFileDialog ( ) ;
if ( initialDirectory is not null )
openFileDialog . InitialDirectory = initialDirectory ;
2022-07-01 04:56:15 +00:00
2022-07-04 00:50:02 +00:00
if ( openFileDialog . ShowDialog ( ) ! = DialogResult . OK )
return path ;
2022-07-01 04:56:15 +00:00
2022-07-04 00:50:02 +00:00
path = openFileDialog . FileName ;
}
return path ;
}
2020-06-08 04:20:22 +00:00
2020-06-08 08:41:59 +00:00
2022-03-25 21:19:00 +00:00
internal static void OpenWindowsIndexingOptions ( )
2020-06-08 08:41:59 +00:00
{
var psi = new ProcessStartInfo
{
FileName = "control.exe" ,
UseShellExecute = true ,
Arguments = Constants . WindowsIndexingOptions
} ;
Process . Start ( psi ) ;
}
2020-07-18 14:12:11 +00:00
2022-12-19 20:07:07 +00:00
private ICommand ? _openFileEditorPathCommand ;
2022-08-17 00:52:53 +00:00
2022-12-19 20:07:07 +00:00
public ICommand OpenFileEditorPath = > _openFileEditorPathCommand ? ? = new RelayCommand ( _ = >
2022-07-04 00:50:02 +00:00
{
var path = PromptUserSelectPath ( ResultType . File , Settings . EditorPath ! = null ? Path . GetDirectoryName ( Settings . EditorPath ) : null ) ;
if ( path is null )
return ;
2020-07-18 14:12:11 +00:00
2022-12-19 20:07:07 +00:00
FileEditorPath = path ;
} ) ;
private ICommand ? _openFolderEditorPathCommand ;
public ICommand OpenFolderEditorPath = > _openFolderEditorPathCommand ? ? = new RelayCommand ( _ = >
{
var path = PromptUserSelectPath ( ResultType . File , Settings . FolderEditorPath ! = null ? Path . GetDirectoryName ( Settings . FolderEditorPath ) : null ) ;
if ( path is null )
return ;
FolderEditorPath = path ;
2022-07-04 00:50:02 +00:00
} ) ;
2020-08-25 22:06:10 +00:00
2022-12-04 17:38:19 +00:00
private ICommand ? _openShellPathCommand ;
2022-08-17 00:52:53 +00:00
public ICommand OpenShellPath = > _openShellPathCommand ? ? = new RelayCommand ( _ = >
{
var path = PromptUserSelectPath ( ResultType . File , Settings . EditorPath ! = null ? Path . GetDirectoryName ( Settings . EditorPath ) : null ) ;
if ( path is null )
return ;
ShellPath = path ;
} ) ;
2022-12-19 20:07:07 +00:00
public string FileEditorPath
2022-07-04 00:50:02 +00:00
{
get = > Settings . EditorPath ;
set
{
Settings . EditorPath = value ;
OnPropertyChanged ( ) ;
}
}
2022-12-19 20:07:07 +00:00
public string FolderEditorPath
{
get = > Settings . FolderEditorPath ;
set
{
Settings . FolderEditorPath = value ;
OnPropertyChanged ( ) ;
}
}
2022-08-17 00:52:53 +00:00
public string ShellPath
{
get = > Settings . ShellPath ;
set
{
Settings . ShellPath = value ;
OnPropertyChanged ( ) ;
}
}
2022-07-04 00:50:02 +00:00
#region Everything FastSortWarning
2022-03-13 03:27:46 +00:00
2022-07-04 00:50:02 +00:00
public Visibility FastSortWarningVisibility
{
2022-03-13 03:27:46 +00:00
get
{
2022-07-04 00:50:02 +00:00
try
{
return EverythingApi . IsFastSortOption ( Settings . SortOption ) ? Visibility . Collapsed : Visibility . Visible ;
}
catch ( IPCErrorException )
{
// this error occurs if the Everything service is not running, in this instance show the warning and
// update the message to let user know in the settings panel.
return Visibility . Visible ;
}
2022-11-29 03:38:17 +00:00
catch ( DllNotFoundException )
{
return Visibility . Collapsed ;
}
2022-03-13 03:27:46 +00:00
}
2022-07-04 00:50:02 +00:00
}
public string SortOptionWarningMessage
{
get
2022-03-13 03:27:46 +00:00
{
2022-07-04 00:50:02 +00:00
try
{
// this method is used to determine if Everything service is running because as at Everything v1.4.1
// the sdk does not provide a dedicated interface to determine if it is running.
return EverythingApi . IsFastSortOption ( Settings . SortOption ) ? string . Empty
: Context . API . GetTranslation ( "flowlauncher_plugin_everything_nonfastsort_warning" ) ;
}
catch ( IPCErrorException )
{
return Context . API . GetTranslation ( "flowlauncher_plugin_everything_is_not_running" ) ;
}
2022-11-29 03:38:17 +00:00
catch ( DllNotFoundException )
{
return Context . API . GetTranslation ( "flowlauncher_plugin_everything_sdk_issue" ) ;
}
2022-03-13 03:27:46 +00:00
}
}
2022-07-04 00:50:02 +00:00
2022-08-17 01:32:49 +00:00
public string EverythingInstalledPath
{
get = > Settings . EverythingInstalledPath ;
set
{
Settings . EverythingInstalledPath = value ;
OnPropertyChanged ( ) ;
}
}
2022-07-04 00:50:02 +00:00
#endregion
2020-05-11 13:15:15 +00:00
}
2022-11-04 06:29:18 +00:00
}