mirror of
https://github.com/Flow-Launcher/Flow.Launcher.git
synced 2026-03-11 08:54:32 +00:00
Rewrite Explorer View Logic based on MVVM Pattern to avoid complicated View Logic
This commit is contained in:
parent
9b471de3cf
commit
d5e1b7cb22
15 changed files with 401 additions and 345 deletions
|
|
@ -181,6 +181,13 @@ namespace Flow.Launcher.Plugin
|
|||
/// <param name="newActionKeyword">The actionkeyword that is supposed to be removed</param>
|
||||
void RemoveActionKeyword(string pluginId, string oldActionKeyword);
|
||||
|
||||
/// <summary>
|
||||
/// Check whether specific ActionKeyword is assigned to any of the plugin
|
||||
/// </summary>
|
||||
/// <param name="actionKeyword">The actionkeyword for checking</param>
|
||||
/// <returns>True if the actionkeyword is already assigned, False otherwise</returns>
|
||||
bool ActionKeywordAssigned(string actionKeyword);
|
||||
|
||||
/// <summary>
|
||||
/// Log debug message
|
||||
/// Message will only be logged in Debug mode
|
||||
|
|
|
|||
|
|
@ -142,6 +142,8 @@ namespace Flow.Launcher
|
|||
public void AddActionKeyword(string pluginId, string newActionKeyword) =>
|
||||
PluginManager.AddActionKeyword(pluginId, newActionKeyword);
|
||||
|
||||
public bool ActionKeywordAssigned(string actionKeyword) => PluginManager.ActionKeywordRegistered(actionKeyword);
|
||||
|
||||
public void RemoveActionKeyword(string pluginId, string oldActionKeyword) =>
|
||||
PluginManager.RemoveActionKeyword(pluginId, oldActionKeyword);
|
||||
|
||||
|
|
|
|||
|
|
@ -50,5 +50,4 @@
|
|||
<ProjectReference Include="..\..\Flow.Launcher.Infrastructure\Flow.Launcher.Infrastructure.csproj" />
|
||||
<ProjectReference Include="..\..\Flow.Launcher.Plugin\Flow.Launcher.Plugin.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -20,6 +20,7 @@
|
|||
<system:String x:Key="plugin_explorer_delete">Delete</system:String>
|
||||
<system:String x:Key="plugin_explorer_edit">Edit</system:String>
|
||||
<system:String x:Key="plugin_explorer_add">Add</system:String>
|
||||
<system:String x:Key="plugin_explorer_generalsetting_header">General Setting</system:String>
|
||||
<system:String x:Key="plugin_explorer_manageactionkeywords_header">Customise Action Keywords</system:String>
|
||||
<system:String x:Key="plugin_explorer_quickaccesslinks_header">Quick Access Links</system:String>
|
||||
<system:String x:Key="plugin_explorer_indexsearchexcludedpaths_header">Index Search Excluded Paths</system:String>
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ namespace Flow.Launcher.Plugin.Explorer
|
|||
if (Settings.QuickFolderAccessLinks.Any())
|
||||
{
|
||||
Settings.QuickAccessLinks = Settings.QuickFolderAccessLinks;
|
||||
Settings.QuickFolderAccessLinks = new List<AccessLink>();
|
||||
Settings.QuickFolderAccessLinks = new();
|
||||
}
|
||||
|
||||
contextMenu = new ContextMenu(Context, Settings, viewModel);
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search.QuickAccessLinks
|
|||
{
|
||||
private const int quickAccessResultScore = 100;
|
||||
|
||||
internal static List<Result> AccessLinkListMatched(Query query, List<AccessLink> accessLinks)
|
||||
internal static List<Result> AccessLinkListMatched(Query query, IEnumerable<AccessLink> accessLinks)
|
||||
{
|
||||
if (string.IsNullOrEmpty(query.Search))
|
||||
return new List<Result>();
|
||||
|
|
@ -29,7 +29,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search.QuickAccessLinks
|
|||
}).ToList();
|
||||
}
|
||||
|
||||
internal static List<Result> AccessLinkListAll(Query query, List<AccessLink> accessLinks)
|
||||
internal static List<Result> AccessLinkListAll(Query query, IEnumerable<AccessLink> accessLinks)
|
||||
=> accessLinks
|
||||
.OrderBy(x => x.Type)
|
||||
.ThenBy(x => x.Name)
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex
|
|||
string searchString,
|
||||
Func<CSearchQueryHelper> createQueryHelper,
|
||||
Func<string, string> constructQuery,
|
||||
List<AccessLink> exclusionList,
|
||||
IEnumerable<AccessLink> exclusionList,
|
||||
CancellationToken token)
|
||||
{
|
||||
var regexMatch = Regex.Match(searchString, ReservedStringPattern);
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ using Flow.Launcher.Plugin.Explorer.Search.QuickAccessLinks;
|
|||
using Flow.Launcher.Plugin.Explorer.Search.WindowsIndex;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
|
|
@ -14,14 +15,14 @@ namespace Flow.Launcher.Plugin.Explorer
|
|||
{
|
||||
public int MaxResult { get; set; } = 100;
|
||||
|
||||
public List<AccessLink> QuickAccessLinks { get; set; } = new List<AccessLink>();
|
||||
public ObservableCollection<AccessLink> QuickAccessLinks { get; set; } = new ();
|
||||
|
||||
// as at v1.7.0 this is to maintain backwards compatibility, need to be removed afterwards.
|
||||
public List<AccessLink> QuickFolderAccessLinks { get; set; } = new List<AccessLink>();
|
||||
public ObservableCollection<AccessLink> QuickFolderAccessLinks { get; set; } = new ();
|
||||
|
||||
public bool UseWindowsIndexForDirectorySearch { get; set; } = true;
|
||||
|
||||
public List<AccessLink> IndexSearchExcludedSubdirectoryPaths { get; set; } = new List<AccessLink>();
|
||||
public ObservableCollection<AccessLink> IndexSearchExcludedSubdirectoryPaths { get; set; } = new ObservableCollection<AccessLink>();
|
||||
|
||||
public string SearchActionKeyword { get; set; } = Query.GlobalPluginWildcardSign;
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,57 @@
|
|||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Flow.Launcher.Plugin.Explorer.Views
|
||||
{
|
||||
public class ActionKeywordModel : INotifyPropertyChanged
|
||||
{
|
||||
private static Settings _settings;
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
public static void Init(Settings settings)
|
||||
{
|
||||
_settings = settings;
|
||||
}
|
||||
|
||||
internal ActionKeywordModel(Settings.ActionKeyword actionKeyword, string description)
|
||||
{
|
||||
KeywordProperty = actionKeyword;
|
||||
Description = description;
|
||||
}
|
||||
|
||||
public string Description { get; private init; }
|
||||
|
||||
internal Settings.ActionKeyword KeywordProperty { get; }
|
||||
|
||||
private void OnPropertyChanged([CallerMemberName] string propertyName = "")
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
|
||||
private string? keyword;
|
||||
|
||||
public string Keyword
|
||||
{
|
||||
get => keyword ??= _settings.GetActionKeyword(KeywordProperty);
|
||||
set
|
||||
{
|
||||
keyword = value;
|
||||
_settings.SetActionKeyword(KeywordProperty, value);
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
private bool? enabled;
|
||||
|
||||
public bool Enabled
|
||||
{
|
||||
get => enabled ??= _settings.GetActionKeywordEnabled(KeywordProperty);
|
||||
set
|
||||
{
|
||||
enabled = value;
|
||||
_settings.SetActionKeywordEnabled(KeywordProperty, value);
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
using System;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace Flow.Launcher.Plugin.Explorer.ViewModels
|
||||
{
|
||||
internal class RelayCommand : ICommand
|
||||
{
|
||||
private Action<object> _action;
|
||||
|
||||
public RelayCommand(Action<object> action)
|
||||
{
|
||||
_action = action;
|
||||
}
|
||||
|
||||
public virtual bool CanExecute(object parameter)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public event EventHandler CanExecuteChanged;
|
||||
|
||||
public virtual void Execute(object parameter)
|
||||
{
|
||||
_action?.Invoke(parameter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,8 +2,13 @@
|
|||
using Flow.Launcher.Infrastructure.Storage;
|
||||
using Flow.Launcher.Plugin.Explorer.Search;
|
||||
using Flow.Launcher.Plugin.Explorer.Search.QuickAccessLinks;
|
||||
using Flow.Launcher.Plugin.Explorer.Views;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace Flow.Launcher.Plugin.Explorer.ViewModels
|
||||
{
|
||||
|
|
@ -25,6 +30,175 @@ namespace Flow.Launcher.Plugin.Explorer.ViewModels
|
|||
Context.API.SaveSettingJsonStorage<Settings>();
|
||||
}
|
||||
|
||||
|
||||
public AccessLink SelectedQuickAccessLink { get; set; }
|
||||
public AccessLink SelectedIndexSearchExcludedPath { get; set; }
|
||||
public ActionKeywordModel SelectedActionKeyword { get; set; }
|
||||
|
||||
|
||||
|
||||
public ICommand RemoveLinkCommand => new RelayCommand(RemoveLink);
|
||||
public ICommand EditLinkCommand => new RelayCommand(EditLink);
|
||||
public ICommand AddLinkCommand => new RelayCommand(AddLink);
|
||||
|
||||
public ICommand EditActionKeywordCommand => new RelayCommand(EditActionKeyword);
|
||||
|
||||
private void EditActionKeyword(object obj)
|
||||
{
|
||||
if (SelectedActionKeyword is not ActionKeywordModel actionKeyword)
|
||||
{
|
||||
ShowUnselectedMessage();
|
||||
return;
|
||||
}
|
||||
|
||||
var actionKeywordWindow = new ActionKeywordSetting(actionKeyword, Context.API);
|
||||
|
||||
if (actionKeywordWindow.ShowDialog() ?? false)
|
||||
{
|
||||
if (actionKeyword.Enabled && !actionKeywordWindow.KeywordEnabled)
|
||||
{
|
||||
Context.API.RemoveActionKeyword(Context.CurrentPluginMetadata.ID, actionKeyword.Keyword);
|
||||
}
|
||||
else if (!actionKeyword.Enabled && actionKeywordWindow.KeywordEnabled)
|
||||
{
|
||||
Context.API.AddActionKeyword(Context.CurrentPluginMetadata.ID, actionKeyword.Keyword);
|
||||
}
|
||||
else if (actionKeyword.Enabled && actionKeywordWindow.KeywordEnabled)
|
||||
{
|
||||
// same keyword will have dialog result false
|
||||
Context.API.RemoveActionKeyword(Context.CurrentPluginMetadata.ID, actionKeyword.Keyword);
|
||||
Context.API.AddActionKeyword(Context.CurrentPluginMetadata.ID, actionKeywordWindow.ActionKeyword);
|
||||
}
|
||||
|
||||
(actionKeyword.Keyword, actionKeyword.Enabled) = (actionKeywordWindow.ActionKeyword, actionKeywordWindow.KeywordEnabled);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private AccessLink? PromptUserSelectPath(ResultType type, string initialDirectory = null)
|
||||
{
|
||||
AccessLink newAccessLink = null;
|
||||
|
||||
if (type is ResultType.Folder)
|
||||
{
|
||||
var folderBrowserDialog = new FolderBrowserDialog();
|
||||
|
||||
if (initialDirectory is not null)
|
||||
folderBrowserDialog.InitialDirectory = initialDirectory;
|
||||
|
||||
if (folderBrowserDialog.ShowDialog() != DialogResult.OK)
|
||||
return newAccessLink;
|
||||
|
||||
newAccessLink = new AccessLink { Path = folderBrowserDialog.SelectedPath };
|
||||
}
|
||||
else if (type is ResultType.File)
|
||||
{
|
||||
var openFileDialog = new OpenFileDialog();
|
||||
if (initialDirectory is not null)
|
||||
openFileDialog.InitialDirectory = initialDirectory;
|
||||
|
||||
if (openFileDialog.ShowDialog() != DialogResult.OK)
|
||||
return newAccessLink;
|
||||
|
||||
newAccessLink = new AccessLink { Path = openFileDialog.FileName };
|
||||
}
|
||||
return newAccessLink;
|
||||
}
|
||||
|
||||
private void EditLink(object obj)
|
||||
{
|
||||
if (obj is not string container) return;
|
||||
|
||||
AccessLink selectedLink;
|
||||
ObservableCollection<AccessLink> collection;
|
||||
|
||||
switch (container)
|
||||
{
|
||||
case "QuickAccessLink":
|
||||
if (SelectedQuickAccessLink == null)
|
||||
{
|
||||
ShowUnselectedMessage();
|
||||
return;
|
||||
}
|
||||
selectedLink = SelectedQuickAccessLink;
|
||||
collection = Settings.QuickAccessLinks;
|
||||
break;
|
||||
case "IndexSearchExcludedPaths":
|
||||
if (SelectedIndexSearchExcludedPath == null)
|
||||
{
|
||||
ShowUnselectedMessage();
|
||||
return;
|
||||
}
|
||||
selectedLink = SelectedIndexSearchExcludedPath;
|
||||
collection = Settings.IndexSearchExcludedSubdirectoryPaths;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
var link = PromptUserSelectPath(selectedLink.Type,
|
||||
selectedLink.Type == ResultType.Folder
|
||||
? selectedLink.Path
|
||||
: Path.GetDirectoryName(selectedLink.Path));
|
||||
|
||||
if (link is null)
|
||||
return;
|
||||
|
||||
collection.Remove(selectedLink);
|
||||
collection.Add(link);
|
||||
}
|
||||
|
||||
private void ShowUnselectedMessage()
|
||||
{
|
||||
string warning = Context.API.GetTranslation("plugin_explorer_make_selection_warning");
|
||||
MessageBox.Show(warning);
|
||||
}
|
||||
|
||||
private void AddLink(object obj)
|
||||
{
|
||||
if (obj is not string container) return;
|
||||
|
||||
var folderBrowserDialog = new FolderBrowserDialog();
|
||||
|
||||
if (folderBrowserDialog.ShowDialog() != DialogResult.OK)
|
||||
return;
|
||||
|
||||
var newAccessLink = new AccessLink { Path = folderBrowserDialog.SelectedPath };
|
||||
|
||||
|
||||
switch (container)
|
||||
{
|
||||
case "QuickAccessLink":
|
||||
if (SelectedQuickAccessLink == null) return;
|
||||
Settings.QuickAccessLinks.Add(newAccessLink);
|
||||
break;
|
||||
case "IndexSearchExcludedPaths":
|
||||
if (SelectedIndexSearchExcludedPath == null) return;
|
||||
Settings.IndexSearchExcludedSubdirectoryPaths.Add(newAccessLink);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
internal void RemoveLinkFromQuickAccess(AccessLink selectedRow) => Settings.QuickAccessLinks.Remove(selectedRow);
|
||||
|
||||
internal void RemoveAccessLinkFromExcludedIndexPaths(AccessLink selectedRow) => Settings.IndexSearchExcludedSubdirectoryPaths.Remove(selectedRow);
|
||||
|
|
@ -41,16 +215,11 @@ namespace Flow.Launcher.Plugin.Explorer.ViewModels
|
|||
Process.Start(psi);
|
||||
}
|
||||
|
||||
internal void UpdateActionKeyword(Settings.ActionKeyword modifiedActionKeyword, string newActionKeyword, string oldActionKeyword)
|
||||
{
|
||||
internal void UpdateActionKeyword(Settings.ActionKeyword modifiedActionKeyword, string newActionKeyword, string oldActionKeyword) =>
|
||||
PluginManager.ReplaceActionKeyword(Context.CurrentPluginMetadata.ID, oldActionKeyword, newActionKeyword);
|
||||
}
|
||||
|
||||
internal bool IsActionKeywordAlreadyAssigned(string newActionKeyword)
|
||||
{
|
||||
return PluginManager.ActionKeywordRegistered(newActionKeyword);
|
||||
}
|
||||
internal bool IsActionKeywordAlreadyAssigned(string newActionKeyword) => PluginManager.ActionKeywordRegistered(newActionKeyword);
|
||||
|
||||
internal bool IsNewActionKeywordGlobal(string newActionKeyword) => newActionKeyword == Query.GlobalPluginWildcardSign;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -96,7 +96,7 @@
|
|||
Name="ChkActionKeywordEnabled"
|
||||
Width="auto"
|
||||
VerticalAlignment="Center"
|
||||
IsChecked="{Binding Enabled}"
|
||||
IsChecked="{Binding KeywordEnabled}"
|
||||
ToolTip="{DynamicResource plugin_explorer_actionkeyword_enabled_tooltip}" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
|
|
|
|||
|
|
@ -13,9 +13,7 @@ namespace Flow.Launcher.Plugin.Explorer.Views
|
|||
/// </summary>
|
||||
public partial class ActionKeywordSetting : Window
|
||||
{
|
||||
private SettingsViewModel settingsViewModel;
|
||||
|
||||
public ActionKeywordView CurrentActionKeyword { get; set; }
|
||||
public ActionKeywordModel CurrentActionKeyword { get; set; }
|
||||
|
||||
public string ActionKeyword
|
||||
{
|
||||
|
|
@ -23,24 +21,22 @@ namespace Flow.Launcher.Plugin.Explorer.Views
|
|||
set
|
||||
{
|
||||
// Set Enable to be true if user change ActionKeyword
|
||||
Enabled = true;
|
||||
KeywordEnabled = true;
|
||||
actionKeyword = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Enabled { get; set; }
|
||||
public bool KeywordEnabled { get; set; }
|
||||
|
||||
private string actionKeyword;
|
||||
private readonly IPublicAPI api;
|
||||
|
||||
public ActionKeywordSetting(SettingsViewModel settingsViewModel,
|
||||
ActionKeywordView selectedActionKeyword)
|
||||
public ActionKeywordSetting(ActionKeywordModel selectedActionKeyword, IPublicAPI api)
|
||||
{
|
||||
this.settingsViewModel = settingsViewModel;
|
||||
|
||||
CurrentActionKeyword = selectedActionKeyword;
|
||||
|
||||
this.api = api;
|
||||
ActionKeyword = selectedActionKeyword.Keyword;
|
||||
Enabled = selectedActionKeyword.Enabled;
|
||||
KeywordEnabled = selectedActionKeyword.Enabled;
|
||||
|
||||
InitializeComponent();
|
||||
|
||||
|
|
@ -52,56 +48,43 @@ namespace Flow.Launcher.Plugin.Explorer.Views
|
|||
if (string.IsNullOrEmpty(ActionKeyword))
|
||||
ActionKeyword = Query.GlobalPluginWildcardSign;
|
||||
|
||||
if (CurrentActionKeyword.Keyword == ActionKeyword && CurrentActionKeyword.Enabled == Enabled)
|
||||
if (CurrentActionKeyword.Keyword == ActionKeyword && CurrentActionKeyword.Enabled == KeywordEnabled)
|
||||
{
|
||||
DialogResult = false;
|
||||
Close();
|
||||
return;
|
||||
}
|
||||
|
||||
if (ActionKeyword == "")
|
||||
{
|
||||
ActionKeyword = "*";
|
||||
}
|
||||
|
||||
if (ActionKeyword == Query.GlobalPluginWildcardSign)
|
||||
switch (CurrentActionKeyword.KeywordProperty)
|
||||
{
|
||||
case Settings.ActionKeyword.FileContentSearchActionKeyword:
|
||||
MessageBox.Show(settingsViewModel.Context.API.GetTranslation("plugin_explorer_globalActionKeywordInvalid"));
|
||||
MessageBox.Show(api.GetTranslation("plugin_explorer_globalActionKeywordInvalid"));
|
||||
return;
|
||||
case Settings.ActionKeyword.QuickAccessActionKeyword:
|
||||
MessageBox.Show(settingsViewModel.Context.API.GetTranslation("plugin_explorer_quickaccess_globalActionKeywordInvalid"));
|
||||
MessageBox.Show(api.GetTranslation("plugin_explorer_quickaccess_globalActionKeywordInvalid"));
|
||||
return;
|
||||
}
|
||||
|
||||
var oldActionKeyword = CurrentActionKeyword.Keyword;
|
||||
|
||||
if (!Enabled || !settingsViewModel.IsActionKeywordAlreadyAssigned(ActionKeyword))
|
||||
if (!KeywordEnabled || !api.ActionKeywordAssigned(ActionKeyword))
|
||||
{
|
||||
// Update View Data
|
||||
CurrentActionKeyword.Keyword = Enabled == true ? ActionKeyword : Query.GlobalPluginWildcardSign;
|
||||
CurrentActionKeyword.Enabled = Enabled;
|
||||
|
||||
switch (Enabled)
|
||||
{
|
||||
// reset to global so it does not take up an action keyword when disabled
|
||||
// not for null Enable plugin
|
||||
case false when oldActionKeyword != Query.GlobalPluginWildcardSign:
|
||||
settingsViewModel.UpdateActionKeyword(CurrentActionKeyword.KeywordProperty,
|
||||
Query.GlobalPluginWildcardSign, oldActionKeyword);
|
||||
break;
|
||||
default:
|
||||
settingsViewModel.UpdateActionKeyword(CurrentActionKeyword.KeywordProperty,
|
||||
CurrentActionKeyword.Keyword, oldActionKeyword);
|
||||
break;
|
||||
}
|
||||
|
||||
DialogResult = true;
|
||||
Close();
|
||||
return;
|
||||
}
|
||||
|
||||
// The keyword is not valid, so show message
|
||||
MessageBox.Show(settingsViewModel.Context.API.GetTranslation("newActionKeywordsHasBeenAssigned"));
|
||||
MessageBox.Show(api.GetTranslation("newActionKeywordsHasBeenAssigned"));
|
||||
}
|
||||
|
||||
private void BtnCancel_OnClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
DialogResult = false;
|
||||
Close();
|
||||
}
|
||||
private void TxtCurrentActionKeyword_OnKeyDown(object sender, KeyEventArgs e)
|
||||
|
|
|
|||
|
|
@ -4,13 +4,13 @@
|
|||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:qa="clr-namespace:Flow.Launcher.Plugin.Explorer.Search.QuickAccessLinks"
|
||||
xmlns:viewModels="clr-namespace:Flow.Launcher.Plugin.Explorer.ViewModels"
|
||||
xmlns:views="clr-namespace:Flow.Launcher.Plugin.Explorer.Views"
|
||||
xmlns:qa="clr-namespace:Flow.Launcher.Plugin.Explorer.Search.QuickAccessLinks"
|
||||
d:DataContext="{d:DesignInstance viewModels:SettingsViewModel}"
|
||||
d:DesignHeight="450"
|
||||
d:DesignWidth="800"
|
||||
mc:Ignorable="d"
|
||||
d:DataContext="{d:DesignInstance viewModels:SettingsViewModel}">
|
||||
mc:Ignorable="d">
|
||||
<UserControl.Resources>
|
||||
<DataTemplate x:Key="ListViewTemplateAccessLinks" DataType="qa:AccessLink">
|
||||
<TextBlock Margin="0,5,0,5" Text="{Binding Path, Mode=OneTime}" />
|
||||
|
|
@ -37,7 +37,7 @@
|
|||
<TextBlock
|
||||
Margin="250,5,0,0"
|
||||
IsEnabled="{Binding Enabled}"
|
||||
Text="{Binding Keyword, Mode=OneTime}">
|
||||
Text="{Binding Keyword}">
|
||||
<TextBlock.Style>
|
||||
<Style TargetType="{x:Type TextBlock}">
|
||||
<Style.Triggers>
|
||||
|
|
@ -59,94 +59,111 @@
|
|||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="100" />
|
||||
</Grid.RowDefinitions>
|
||||
<ScrollViewer
|
||||
Grid.Row="0"
|
||||
Margin="20,35,0,0"
|
||||
HorizontalScrollBarVisibility="Hidden"
|
||||
VerticalScrollBarVisibility="Auto">
|
||||
<StackPanel Grid.Row="0" Margin="20,35,0,0">
|
||||
<StackPanel>
|
||||
<Expander
|
||||
Header="{DynamicResource plugin_explorer_generalsetting_header}">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<ComboBox
|
||||
Width="200"
|
||||
ItemsSource="{Binding Settings.SortOptions, Mode=OneWay}"
|
||||
SelectedItem="{Binding Settings.SortOption}" />
|
||||
</StackPanel>
|
||||
</Expander>
|
||||
<Expander
|
||||
Name="expActionKeywords"
|
||||
Collapsed="expActionKeywords_Collapsed"
|
||||
Height="auto"
|
||||
Expanded="expActionKeywords_Click"
|
||||
Header="{DynamicResource plugin_explorer_manageactionkeywords_header}">
|
||||
<ListView x:Name="lbxActionKeywords" ItemTemplate="{StaticResource ListViewActionKeywords}" />
|
||||
<DockPanel HorizontalAlignment="Stretch">
|
||||
<ListView
|
||||
x:Name="lbxActionKeywords"
|
||||
DockPanel.Dock="Top"
|
||||
ItemTemplate="{StaticResource ListViewActionKeywords}"
|
||||
SelectedItem="{Binding SelectedActionKeyword}"/>
|
||||
<Button
|
||||
MinWidth="100"
|
||||
Margin="10"
|
||||
Command="{Binding EditActionKeywordCommand}"
|
||||
Content="{DynamicResource plugin_explorer_edit}" />
|
||||
</DockPanel>
|
||||
</Expander>
|
||||
<Expander
|
||||
Name="expAccessLinks"
|
||||
Margin="0,10,0,0"
|
||||
Collapsed="expAccessLinks_Collapsed"
|
||||
Expanded="expAccessLinks_Click"
|
||||
Header="{DynamicResource plugin_explorer_quickaccesslinks_header}">
|
||||
<ListView
|
||||
x:Name="lbxAccessLinks"
|
||||
AllowDrop="True"
|
||||
DragEnter="lbxAccessLinks_DragEnter"
|
||||
Drop="lbxAccessLinks_Drop"
|
||||
ItemTemplate="{StaticResource ListViewTemplateAccessLinks}" />
|
||||
<DockPanel HorizontalAlignment="Stretch">
|
||||
<ListView
|
||||
x:Name="lbxAccessLinks"
|
||||
Height="200"
|
||||
AllowDrop="True"
|
||||
DockPanel.Dock="Top"
|
||||
ItemTemplate="{StaticResource ListViewTemplateAccessLinks}"
|
||||
ItemsSource="{Binding Settings.QuickAccessLinks}"
|
||||
SelectedItem="{Binding SelectedQuickAccessLink}" />
|
||||
<StackPanel
|
||||
HorizontalAlignment="Right"
|
||||
DockPanel.Dock="Bottom"
|
||||
Orientation="Horizontal">
|
||||
<Button
|
||||
MinWidth="100"
|
||||
Margin="10"
|
||||
Command="{Binding RemoveLinkCommand}"
|
||||
CommandParameter="QuickAccessLink"
|
||||
Content="{DynamicResource plugin_explorer_delete}" />
|
||||
<Button
|
||||
MinWidth="100"
|
||||
Margin="10"
|
||||
Command="{Binding EditLinkCommand}"
|
||||
CommandParameter="QuickAccessLink"
|
||||
Content="{DynamicResource plugin_explorer_edit}" />
|
||||
<Button
|
||||
MinWidth="100"
|
||||
Margin="10"
|
||||
Command="{Binding AddLinkCommand}"
|
||||
CommandParameter="QuickAccessLink"
|
||||
Content="{DynamicResource plugin_explorer_add}" />
|
||||
</StackPanel>
|
||||
</DockPanel>
|
||||
</Expander>
|
||||
<Expander
|
||||
x:Name="expExcludedPaths"
|
||||
Margin="0,10,0,0"
|
||||
Collapsed="expExcludedPaths_Collapsed"
|
||||
Expanded="expExcludedPaths_Click"
|
||||
Header="{DynamicResource plugin_explorer_indexsearchexcludedpaths_header}">
|
||||
<ListView
|
||||
x:Name="lbxExcludedPaths"
|
||||
AllowDrop="True"
|
||||
DragEnter="lbxAccessLinks_DragEnter"
|
||||
Drop="lbxAccessLinks_Drop"
|
||||
ItemTemplate="{StaticResource ListViewActionKeywords}" />
|
||||
<DockPanel HorizontalAlignment="Stretch">
|
||||
<ListView
|
||||
Name="lbxExcludedPaths"
|
||||
AllowDrop="True"
|
||||
DockPanel.Dock="Top"
|
||||
ItemTemplate="{StaticResource ListViewActionKeywords}"
|
||||
ItemsSource="{Binding Settings.IndexSearchExcludedSubdirectoryPaths}"
|
||||
SelectedItem="{Binding SelectedIndexSearchExcludedPath}" />
|
||||
<StackPanel
|
||||
HorizontalAlignment="Right"
|
||||
DockPanel.Dock="Bottom"
|
||||
Orientation="Horizontal">
|
||||
<Button
|
||||
MinWidth="100"
|
||||
Margin="10"
|
||||
Command="{Binding RemoveLinkCommand}"
|
||||
CommandParameter="IndexSearchExcludedPaths"
|
||||
Content="{DynamicResource plugin_explorer_delete}" />
|
||||
<Button
|
||||
MinWidth="100"
|
||||
Margin="10"
|
||||
Command="{Binding EditLinkCommand}"
|
||||
CommandParameter="IndexSearchExcludedPaths"
|
||||
Content="{DynamicResource plugin_explorer_edit}" />
|
||||
<Button
|
||||
MinWidth="100"
|
||||
Margin="10"
|
||||
Command="{Binding AddLinkCommand}"
|
||||
CommandParameter="IndexSearchExcludedPaths"
|
||||
Content="{DynamicResource plugin_explorer_add}" />
|
||||
</StackPanel>
|
||||
</DockPanel>
|
||||
</Expander>
|
||||
<ComboBox Grid.Row="4"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
SelectedItem="{Binding Settings.SortOption}"
|
||||
ItemsSource="{Binding Settings.SortOptions, Mode=OneWay}">
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
<Grid Grid.Row="1">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="450" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<StackPanel
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
HorizontalAlignment="Left"
|
||||
Orientation="Horizontal">
|
||||
<Button
|
||||
x:Name="btnIndexingOptions"
|
||||
MinWidth="130"
|
||||
Margin="10"
|
||||
Click="btnOpenIndexingOptions_Click"
|
||||
Content="{DynamicResource plugin_explorer_manageindexoptions}" />
|
||||
</StackPanel>
|
||||
<StackPanel
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Right"
|
||||
Orientation="Horizontal">
|
||||
<Button
|
||||
x:Name="btnDelete"
|
||||
MinWidth="100"
|
||||
Margin="10"
|
||||
Click="btnDelete_Click"
|
||||
Content="{DynamicResource plugin_explorer_delete}" />
|
||||
<Button
|
||||
x:Name="btnEdit"
|
||||
MinWidth="100"
|
||||
Margin="10"
|
||||
Click="btnEdit_Click"
|
||||
Content="{DynamicResource plugin_explorer_edit}" />
|
||||
<Button
|
||||
x:Name="btnAdd"
|
||||
MinWidth="100"
|
||||
Margin="10"
|
||||
Click="btnAdd_Click"
|
||||
Content="{DynamicResource plugin_explorer_add}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
|
@ -21,12 +21,12 @@ namespace Flow.Launcher.Plugin.Explorer.Views
|
|||
{
|
||||
private readonly SettingsViewModel viewModel;
|
||||
|
||||
private List<ActionKeywordView> actionKeywordsListView;
|
||||
private List<ActionKeywordModel> actionKeywordsListView;
|
||||
|
||||
public ExplorerSettings(SettingsViewModel viewModel)
|
||||
{
|
||||
DataContext = viewModel;
|
||||
|
||||
|
||||
InitializeComponent();
|
||||
|
||||
this.viewModel = viewModel;
|
||||
|
|
@ -35,7 +35,7 @@ namespace Flow.Launcher.Plugin.Explorer.Views
|
|||
|
||||
lbxExcludedPaths.ItemsSource = this.viewModel.Settings.IndexSearchExcludedSubdirectoryPaths;
|
||||
|
||||
actionKeywordsListView = new List<ActionKeywordView>
|
||||
actionKeywordsListView = new List<ActionKeywordModel>
|
||||
{
|
||||
new(Settings.ActionKeyword.SearchActionKeyword,
|
||||
viewModel.Context.API.GetTranslation("plugin_explorer_actionkeywordview_search")),
|
||||
|
|
@ -51,208 +51,42 @@ namespace Flow.Launcher.Plugin.Explorer.Views
|
|||
|
||||
lbxActionKeywords.ItemsSource = actionKeywordsListView;
|
||||
|
||||
ActionKeywordView.Init(viewModel.Settings);
|
||||
ActionKeywordModel.Init(viewModel.Settings);
|
||||
|
||||
RefreshView();
|
||||
}
|
||||
|
||||
public void RefreshView()
|
||||
{
|
||||
lbxAccessLinks.Items.SortDescriptions.Add(new SortDescription("Path", ListSortDirection.Ascending));
|
||||
|
||||
lbxExcludedPaths.Items.SortDescriptions.Add(new SortDescription("Path", ListSortDirection.Ascending));
|
||||
|
||||
SetButtonVisibilityToHidden();
|
||||
|
||||
if (expAccessLinks.IsExpanded || expExcludedPaths.IsExpanded || expActionKeywords.IsExpanded)
|
||||
{
|
||||
if (!expActionKeywords.IsExpanded)
|
||||
btnAdd.Visibility = Visibility.Visible;
|
||||
|
||||
if (expActionKeywords.IsExpanded
|
||||
&& btnEdit.Visibility == Visibility.Hidden)
|
||||
btnEdit.Visibility = Visibility.Visible;
|
||||
|
||||
if (lbxAccessLinks.Items.Count == 0 && lbxExcludedPaths.Items.Count == 0
|
||||
&& btnDelete.Visibility == Visibility.Visible
|
||||
&& btnEdit.Visibility == Visibility.Visible)
|
||||
{
|
||||
btnDelete.Visibility = Visibility.Hidden;
|
||||
btnEdit.Visibility = Visibility.Hidden;
|
||||
}
|
||||
|
||||
if (expAccessLinks.IsExpanded
|
||||
&& lbxAccessLinks.Items.Count > 0
|
||||
&& btnDelete.Visibility == Visibility.Hidden
|
||||
&& btnEdit.Visibility == Visibility.Hidden)
|
||||
{
|
||||
btnDelete.Visibility = Visibility.Visible;
|
||||
btnEdit.Visibility = Visibility.Visible;
|
||||
}
|
||||
|
||||
if (expExcludedPaths.IsExpanded
|
||||
&& lbxExcludedPaths.Items.Count > 0
|
||||
&& btnDelete.Visibility == Visibility.Hidden
|
||||
&& btnEdit.Visibility == Visibility.Hidden)
|
||||
{
|
||||
btnDelete.Visibility = Visibility.Visible;
|
||||
btnEdit.Visibility = Visibility.Visible;
|
||||
}
|
||||
}
|
||||
|
||||
lbxAccessLinks.Items.Refresh();
|
||||
|
||||
lbxExcludedPaths.Items.Refresh();
|
||||
|
||||
lbxActionKeywords.Items.Refresh();
|
||||
}
|
||||
|
||||
|
||||
private void expActionKeywords_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (expActionKeywords.IsExpanded)
|
||||
expActionKeywords.Height = 205;
|
||||
|
||||
if (expExcludedPaths.IsExpanded)
|
||||
expExcludedPaths.IsExpanded = false;
|
||||
|
||||
if (expAccessLinks.IsExpanded)
|
||||
expAccessLinks.IsExpanded = false;
|
||||
|
||||
RefreshView();
|
||||
}
|
||||
|
||||
private void expActionKeywords_Collapsed(object sender, RoutedEventArgs e)
|
||||
{
|
||||
expActionKeywords.Height = double.NaN;
|
||||
SetButtonVisibilityToHidden();
|
||||
}
|
||||
|
||||
private void expAccessLinks_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (expAccessLinks.IsExpanded)
|
||||
expAccessLinks.Height = 205;
|
||||
|
||||
if (expExcludedPaths.IsExpanded)
|
||||
expExcludedPaths.IsExpanded = false;
|
||||
|
||||
if (expActionKeywords.IsExpanded)
|
||||
expActionKeywords.IsExpanded = false;
|
||||
|
||||
RefreshView();
|
||||
}
|
||||
|
||||
private void expAccessLinks_Collapsed(object sender, RoutedEventArgs e)
|
||||
{
|
||||
expAccessLinks.Height = double.NaN;
|
||||
SetButtonVisibilityToHidden();
|
||||
}
|
||||
|
||||
private void expExcludedPaths_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (expExcludedPaths.IsExpanded)
|
||||
expAccessLinks.Height = double.NaN;
|
||||
|
||||
if (expAccessLinks.IsExpanded)
|
||||
expAccessLinks.IsExpanded = false;
|
||||
|
||||
if (expActionKeywords.IsExpanded)
|
||||
expActionKeywords.IsExpanded = false;
|
||||
|
||||
RefreshView();
|
||||
}
|
||||
|
||||
private void expExcludedPaths_Collapsed(object sender, RoutedEventArgs e)
|
||||
{
|
||||
SetButtonVisibilityToHidden();
|
||||
}
|
||||
|
||||
private void btnDelete_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var selectedRow = lbxAccessLinks.SelectedItem as AccessLink ?? lbxExcludedPaths.SelectedItem as AccessLink;
|
||||
|
||||
if (selectedRow != null)
|
||||
{
|
||||
string msg = string.Format(viewModel.Context.API.GetTranslation("plugin_explorer_delete_folder_link"),
|
||||
selectedRow.Path);
|
||||
|
||||
if (MessageBox.Show(msg, string.Empty, MessageBoxButton.YesNo) == MessageBoxResult.Yes)
|
||||
{
|
||||
if (expAccessLinks.IsExpanded)
|
||||
viewModel.RemoveLinkFromQuickAccess(selectedRow);
|
||||
|
||||
if (expExcludedPaths.IsExpanded)
|
||||
viewModel.RemoveAccessLinkFromExcludedIndexPaths(selectedRow);
|
||||
|
||||
RefreshView();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
string warning = viewModel.Context.API.GetTranslation("plugin_explorer_select_folder_link_warning");
|
||||
MessageBox.Show(warning);
|
||||
}
|
||||
}
|
||||
|
||||
private void btnEdit_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (lbxActionKeywords.SelectedItem is ActionKeywordView)
|
||||
{
|
||||
var selectedActionKeyword = lbxActionKeywords.SelectedItem as ActionKeywordView;
|
||||
|
||||
var actionKeywordWindow = new ActionKeywordSetting(viewModel,
|
||||
selectedActionKeyword);
|
||||
|
||||
actionKeywordWindow.ShowDialog();
|
||||
|
||||
RefreshView();
|
||||
}
|
||||
else
|
||||
{
|
||||
var selectedRow = lbxAccessLinks.SelectedItem as AccessLink ??
|
||||
lbxExcludedPaths.SelectedItem as AccessLink;
|
||||
|
||||
if (selectedRow != null)
|
||||
{
|
||||
var folderBrowserDialog = new FolderBrowserDialog();
|
||||
folderBrowserDialog.SelectedPath = selectedRow.Path;
|
||||
if (folderBrowserDialog.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
if (expAccessLinks.IsExpanded)
|
||||
{
|
||||
var link = viewModel.Settings.QuickAccessLinks.First(x => x.Path == selectedRow.Path);
|
||||
link.Path = folderBrowserDialog.SelectedPath;
|
||||
}
|
||||
|
||||
if (expExcludedPaths.IsExpanded)
|
||||
{
|
||||
var link = viewModel.Settings.IndexSearchExcludedSubdirectoryPaths.First(x =>
|
||||
x.Path == selectedRow.Path);
|
||||
link.Path = folderBrowserDialog.SelectedPath;
|
||||
}
|
||||
}
|
||||
|
||||
RefreshView();
|
||||
}
|
||||
else
|
||||
{
|
||||
string warning = viewModel.Context.API.GetTranslation("plugin_explorer_make_selection_warning");
|
||||
MessageBox.Show(warning);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void btnAdd_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var folderBrowserDialog = new FolderBrowserDialog();
|
||||
if (folderBrowserDialog.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
var newAccessLink = new AccessLink {Path = folderBrowserDialog.SelectedPath};
|
||||
|
||||
AddAccessLink(newAccessLink);
|
||||
}
|
||||
|
||||
RefreshView();
|
||||
}
|
||||
|
||||
private void lbxAccessLinks_Drop(object sender, DragEventArgs e)
|
||||
{
|
||||
|
|
@ -261,18 +95,16 @@ namespace Flow.Launcher.Plugin.Explorer.Views
|
|||
if (files != null && files.Count() > 0)
|
||||
{
|
||||
if (expAccessLinks.IsExpanded && viewModel.Settings.QuickAccessLinks == null)
|
||||
viewModel.Settings.QuickAccessLinks = new List<AccessLink>();
|
||||
viewModel.Settings.QuickAccessLinks = new();
|
||||
|
||||
foreach (string s in files)
|
||||
{
|
||||
if (Directory.Exists(s))
|
||||
{
|
||||
var newFolderLink = new AccessLink {Path = s};
|
||||
var newFolderLink = new AccessLink { Path = s };
|
||||
|
||||
AddAccessLink(newFolderLink);
|
||||
}
|
||||
|
||||
RefreshView();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -283,7 +115,7 @@ namespace Flow.Launcher.Plugin.Explorer.Views
|
|||
&& !viewModel.Settings.QuickAccessLinks.Any(x => x.Path == newAccessLink.Path))
|
||||
{
|
||||
if (viewModel.Settings.QuickAccessLinks == null)
|
||||
viewModel.Settings.QuickAccessLinks = new List<AccessLink>();
|
||||
viewModel.Settings.QuickAccessLinks = new();
|
||||
|
||||
viewModel.Settings.QuickAccessLinks.Add(newAccessLink);
|
||||
}
|
||||
|
|
@ -292,7 +124,7 @@ namespace Flow.Launcher.Plugin.Explorer.Views
|
|||
&& !viewModel.Settings.IndexSearchExcludedSubdirectoryPaths.Any(x => x.Path == newAccessLink.Path))
|
||||
{
|
||||
if (viewModel.Settings.IndexSearchExcludedSubdirectoryPaths == null)
|
||||
viewModel.Settings.IndexSearchExcludedSubdirectoryPaths = new List<AccessLink>();
|
||||
viewModel.Settings.IndexSearchExcludedSubdirectoryPaths = new ();
|
||||
|
||||
viewModel.Settings.IndexSearchExcludedSubdirectoryPaths.Add(newAccessLink);
|
||||
}
|
||||
|
|
@ -314,44 +146,5 @@ namespace Flow.Launcher.Plugin.Explorer.Views
|
|||
{
|
||||
SettingsViewModel.OpenWindowsIndexingOptions();
|
||||
}
|
||||
|
||||
public void SetButtonVisibilityToHidden()
|
||||
{
|
||||
btnDelete.Visibility = Visibility.Hidden;
|
||||
btnEdit.Visibility = Visibility.Hidden;
|
||||
btnAdd.Visibility = Visibility.Hidden;
|
||||
}
|
||||
}
|
||||
|
||||
public class ActionKeywordView
|
||||
{
|
||||
private static Settings _settings;
|
||||
|
||||
public static void Init(Settings settings)
|
||||
{
|
||||
_settings = settings;
|
||||
}
|
||||
|
||||
internal ActionKeywordView(Settings.ActionKeyword actionKeyword, string description)
|
||||
{
|
||||
KeywordProperty = actionKeyword;
|
||||
Description = description;
|
||||
}
|
||||
|
||||
public string Description { get; private init; }
|
||||
|
||||
internal Settings.ActionKeyword KeywordProperty { get; }
|
||||
|
||||
public string Keyword
|
||||
{
|
||||
get => _settings.GetActionKeyword(KeywordProperty);
|
||||
set => _settings.SetActionKeyword(KeywordProperty, value);
|
||||
}
|
||||
|
||||
public bool Enabled
|
||||
{
|
||||
get => _settings.GetActionKeywordEnabled(KeywordProperty);
|
||||
set => _settings.SetActionKeywordEnabled(KeywordProperty, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue