Merge pull request #4023 from Flow-Launcher/shell_setting_panel_enhancement

Refactor ShellSettings with Binding & Fix IsEnabled logic
This commit is contained in:
Jack Ye 2025-09-30 20:50:16 +08:00 committed by GitHub
commit 7f0851bcb1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 284 additions and 167 deletions

View file

@ -0,0 +1,25 @@
using System;
using System.Globalization;
using System.Windows.Data;
namespace Flow.Launcher.Plugin.Shell.Converters;
public class LeaveShellOpenOrCloseShellAfterPressEnabledConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (
values.Length != 2 ||
values[0] is not bool closeShellAfterPressOrLeaveShellOpen ||
values[1] is not Shell shell
)
return Binding.DoNothing;
return (!closeShellAfterPressOrLeaveShellOpen) && shell != Shell.RunCommand;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}

View file

@ -6,6 +6,7 @@ using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Flow.Launcher.Plugin.SharedCommands;
using Flow.Launcher.Plugin.Shell.Views;
using WindowsInput;
using WindowsInput.Native;
using Control = System.Windows.Controls.Control;
@ -383,9 +384,16 @@ namespace Flow.Launcher.Plugin.Shell
Context = context;
_settings = context.API.LoadSettingJsonStorage<Settings>();
context.API.RegisterGlobalKeyboardCallback(API_GlobalKeyboardEvent);
// Since the old Settings class set default value of ShowOnlyMostUsedCMDsNumber to 0 which is a wrong value,
// we need to fix it here to make sure the default value is 5
// todo: remove this code block after release v2.2.0
if (_settings.ShowOnlyMostUsedCMDsNumber == 0)
{
_settings.ShowOnlyMostUsedCMDsNumber = 5;
}
}
bool API_GlobalKeyboardEvent(int keyevent, int vkcode, SpecialKeyState state)
private bool API_GlobalKeyboardEvent(int keyevent, int vkcode, SpecialKeyState state)
{
if (!Context.CurrentPluginMetadata.Disabled && _settings.ReplaceWinR)
{

View file

@ -1,24 +1,121 @@
using System.Collections.Generic;
using Flow.Launcher.Localization.Attributes;
namespace Flow.Launcher.Plugin.Shell
{
public class Settings
public class Settings : BaseModel
{
public Shell Shell { get; set; } = Shell.Cmd;
private Shell _shell = Shell.Cmd;
public Shell Shell
{
get => _shell;
set
{
if (_shell != value)
{
_shell = value;
OnPropertyChanged();
}
}
}
public bool ReplaceWinR { get; set; } = false;
private bool _replaceWinR = false;
public bool ReplaceWinR
{
get => _replaceWinR;
set
{
if (_replaceWinR != value)
{
_replaceWinR = value;
OnPropertyChanged();
}
}
}
public bool CloseShellAfterPress { get; set; } = false;
private bool _closeShellAfterPress = false;
public bool CloseShellAfterPress
{
get => _closeShellAfterPress;
set
{
if (_closeShellAfterPress != value)
{
_closeShellAfterPress = value;
OnPropertyChanged();
}
}
}
public bool LeaveShellOpen { get; set; }
private bool _leaveShellOpen;
public bool LeaveShellOpen
{
get => _leaveShellOpen;
set
{
if (_leaveShellOpen != value)
{
_leaveShellOpen = value;
OnPropertyChanged();
}
}
}
public bool RunAsAdministrator { get; set; } = true;
private bool _runAsAdministrator = true;
public bool RunAsAdministrator
{
get => _runAsAdministrator;
set
{
if (_runAsAdministrator != value)
{
_runAsAdministrator = value;
OnPropertyChanged();
}
}
}
public bool UseWindowsTerminal { get; set; } = false;
private bool _useWindowsTerminal = false;
public bool UseWindowsTerminal
{
get => _useWindowsTerminal;
set
{
if (_useWindowsTerminal != value)
{
_useWindowsTerminal = value;
OnPropertyChanged();
}
}
}
public bool ShowOnlyMostUsedCMDs { get; set; }
private bool _showOnlyMostUsedCMDs;
public bool ShowOnlyMostUsedCMDs
{
get => _showOnlyMostUsedCMDs;
set
{
if (_showOnlyMostUsedCMDs != value)
{
_showOnlyMostUsedCMDs = value;
OnPropertyChanged();
}
}
}
public int ShowOnlyMostUsedCMDsNumber { get; set; }
private int _showOnlyMostUsedCMDsNumber = 5;
public int ShowOnlyMostUsedCMDsNumber
{
get => _showOnlyMostUsedCMDsNumber;
set
{
if (_showOnlyMostUsedCMDsNumber != value)
{
_showOnlyMostUsedCMDsNumber = value;
OnPropertyChanged();
}
}
}
public Dictionary<string, int> CommandHistory { get; set; } = [];
@ -31,11 +128,19 @@ namespace Flow.Launcher.Plugin.Shell
}
}
[EnumLocalize]
public enum Shell
{
[EnumLocalizeValue("CMD")]
Cmd = 0,
[EnumLocalizeValue("PowerShell")]
Powershell = 1,
[EnumLocalizeValue("RunCommand")]
RunCommand = 2,
[EnumLocalizeValue("Pwsh")]
Pwsh = 3,
}
}

View file

@ -1,142 +0,0 @@
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
namespace Flow.Launcher.Plugin.Shell
{
public partial class CMDSetting : UserControl
{
private readonly Settings _settings;
public CMDSetting(Settings settings)
{
InitializeComponent();
_settings = settings;
}
private void CMDSetting_OnLoaded(object sender, RoutedEventArgs re)
{
ReplaceWinR.IsChecked = _settings.ReplaceWinR;
CloseShellAfterPress.IsChecked = _settings.CloseShellAfterPress;
LeaveShellOpen.IsChecked = _settings.LeaveShellOpen;
AlwaysRunAsAdministrator.IsChecked = _settings.RunAsAdministrator;
UseWindowsTerminal.IsChecked = _settings.UseWindowsTerminal;
LeaveShellOpen.IsEnabled = _settings.Shell != Shell.RunCommand;
ShowOnlyMostUsedCMDs.IsChecked = _settings.ShowOnlyMostUsedCMDs;
if (ShowOnlyMostUsedCMDs.IsChecked != true)
ShowOnlyMostUsedCMDsNumber.IsEnabled = false;
ShowOnlyMostUsedCMDsNumber.ItemsSource = new List<int>() { 5, 10, 20 };
if (_settings.ShowOnlyMostUsedCMDsNumber == 0)
{
ShowOnlyMostUsedCMDsNumber.SelectedIndex = 0;
_settings.ShowOnlyMostUsedCMDsNumber = (int)ShowOnlyMostUsedCMDsNumber.SelectedItem;
}
CloseShellAfterPress.Checked += (o, e) =>
{
_settings.CloseShellAfterPress = true;
LeaveShellOpen.IsChecked = false;
LeaveShellOpen.IsEnabled = false;
};
CloseShellAfterPress.Unchecked += (o, e) =>
{
_settings.CloseShellAfterPress = false;
LeaveShellOpen.IsEnabled = true;
};
LeaveShellOpen.Checked += (o, e) =>
{
_settings.LeaveShellOpen = true;
CloseShellAfterPress.IsChecked = false;
CloseShellAfterPress.IsEnabled = false;
};
LeaveShellOpen.Unchecked += (o, e) =>
{
_settings.LeaveShellOpen = false;
CloseShellAfterPress.IsEnabled = true;
};
AlwaysRunAsAdministrator.Checked += (o, e) =>
{
_settings.RunAsAdministrator = true;
};
AlwaysRunAsAdministrator.Unchecked += (o, e) =>
{
_settings.RunAsAdministrator = false;
};
UseWindowsTerminal.Checked += (o, e) =>
{
_settings.UseWindowsTerminal = true;
};
UseWindowsTerminal.Unchecked += (o, e) =>
{
_settings.UseWindowsTerminal = false;
};
ReplaceWinR.Checked += (o, e) =>
{
_settings.ReplaceWinR = true;
};
ReplaceWinR.Unchecked += (o, e) =>
{
_settings.ReplaceWinR = false;
};
ShellComboBox.SelectedIndex = _settings.Shell switch
{
Shell.Cmd => 0,
Shell.Powershell => 1,
Shell.Pwsh => 2,
_ => ShellComboBox.Items.Count - 1
};
ShellComboBox.SelectionChanged += (o, e) =>
{
_settings.Shell = ShellComboBox.SelectedIndex switch
{
0 => Shell.Cmd,
1 => Shell.Powershell,
2 => Shell.Pwsh,
_ => Shell.RunCommand
};
LeaveShellOpen.IsEnabled = _settings.Shell != Shell.RunCommand;
};
ShowOnlyMostUsedCMDs.Checked += (o, e) =>
{
_settings.ShowOnlyMostUsedCMDs = true;
ShowOnlyMostUsedCMDsNumber.IsEnabled = true;
};
ShowOnlyMostUsedCMDs.Unchecked += (o, e) =>
{
_settings.ShowOnlyMostUsedCMDs = false;
ShowOnlyMostUsedCMDsNumber.IsEnabled = false;
};
ShowOnlyMostUsedCMDsNumber.SelectedItem = _settings.ShowOnlyMostUsedCMDsNumber;
ShowOnlyMostUsedCMDsNumber.SelectionChanged += (o, e) =>
{
_settings.ShowOnlyMostUsedCMDsNumber = (int)ShowOnlyMostUsedCMDsNumber.SelectedItem;
};
}
}
}

View file

@ -0,0 +1,78 @@
using System.Collections.Generic;
namespace Flow.Launcher.Plugin.Shell.ViewModels;
public class ShellSettingViewModel : BaseModel
{
public Settings Settings { get; }
public List<ShellLocalized> AllShells { get; } = ShellLocalized.GetValues();
public Shell SelectedShell
{
get => Settings.Shell;
set
{
if (Settings.Shell != value)
{
Settings.Shell = value;
OnPropertyChanged();
}
}
}
public List<int> OnlyMostUsedCMDsNumbers { get; } = [5, 10, 20];
public int SelectedOnlyMostUsedCMDsNumber
{
get => Settings.ShowOnlyMostUsedCMDsNumber;
set
{
if (Settings.ShowOnlyMostUsedCMDsNumber != value)
{
Settings.ShowOnlyMostUsedCMDsNumber = value;
OnPropertyChanged();
}
}
}
public bool CloseShellAfterPress
{
get => Settings.CloseShellAfterPress;
set
{
if (Settings.CloseShellAfterPress != value)
{
Settings.CloseShellAfterPress = value;
OnPropertyChanged();
// Only allow CloseShellAfterPress to be true when LeaveShellOpen is false
if (value)
{
LeaveShellOpen = false;
}
}
}
}
public bool LeaveShellOpen
{
get => Settings.LeaveShellOpen;
set
{
if (Settings.LeaveShellOpen != value)
{
Settings.LeaveShellOpen = value;
OnPropertyChanged();
// Only allow LeaveShellOpen to be true when CloseShellAfterPress is false
if (value)
{
CloseShellAfterPress = false;
}
}
}
}
public ShellSettingViewModel(Settings settings)
{
Settings = settings;
}
}

View file

@ -1,13 +1,19 @@
<UserControl
x:Class="Flow.Launcher.Plugin.Shell.CMDSetting"
x:Class="Flow.Launcher.Plugin.Shell.Views.CMDSetting"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="clr-namespace:Flow.Launcher.Plugin.Shell.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="clr-namespace:Flow.Launcher.Plugin.Shell.ViewModels"
d:DataContext="{d:DesignInstance vm:ShellSettingViewModel}"
d:DesignHeight="300"
d:DesignWidth="300"
Loaded="CMDSetting_OnLoaded"
mc:Ignorable="d">
<UserControl.Resources>
<converters:LeaveShellOpenOrCloseShellAfterPressEnabledConverter x:Key="LeaveShellOpenOrCloseShellAfterPressEnabledConverter" />
</UserControl.Resources>
<Grid Margin="{StaticResource SettingPanelMargin}" VerticalAlignment="Top">
<Grid.RowDefinitions>
<RowDefinition />
@ -23,50 +29,72 @@
Grid.Row="0"
Margin="{StaticResource SettingPanelItemRightTopBottomMargin}"
HorizontalAlignment="Left"
Content="{DynamicResource flowlauncher_plugin_cmd_relace_winr}" />
Content="{DynamicResource flowlauncher_plugin_cmd_relace_winr}"
IsChecked="{Binding Settings.ReplaceWinR, Mode=TwoWay}" />
<CheckBox
x:Name="CloseShellAfterPress"
Grid.Row="1"
Margin="{StaticResource SettingPanelItemRightTopBottomMargin}"
HorizontalAlignment="Left"
Content="{DynamicResource flowlauncher_plugin_cmd_close_cmd_after_press}" />
Content="{DynamicResource flowlauncher_plugin_cmd_close_cmd_after_press}"
IsChecked="{Binding CloseShellAfterPress, Mode=TwoWay}">
<CheckBox.IsEnabled>
<MultiBinding Converter="{StaticResource LeaveShellOpenOrCloseShellAfterPressEnabledConverter}">
<Binding Mode="OneWay" Path="LeaveShellOpen" />
<Binding Mode="OneWay" Path="SelectedShell" />
</MultiBinding>
</CheckBox.IsEnabled>
</CheckBox>
<CheckBox
x:Name="LeaveShellOpen"
Grid.Row="2"
Margin="{StaticResource SettingPanelItemRightTopBottomMargin}"
HorizontalAlignment="Left"
Content="{DynamicResource flowlauncher_plugin_cmd_leave_cmd_open}" />
Content="{DynamicResource flowlauncher_plugin_cmd_leave_cmd_open}"
IsChecked="{Binding LeaveShellOpen, Mode=TwoWay}">
<CheckBox.IsEnabled>
<MultiBinding Converter="{StaticResource LeaveShellOpenOrCloseShellAfterPressEnabledConverter}">
<Binding Mode="OneWay" Path="CloseShellAfterPress" />
<Binding Mode="OneWay" Path="SelectedShell" />
</MultiBinding>
</CheckBox.IsEnabled>
</CheckBox>
<CheckBox
x:Name="AlwaysRunAsAdministrator"
Grid.Row="3"
Margin="{StaticResource SettingPanelItemRightTopBottomMargin}"
HorizontalAlignment="Left"
Content="{DynamicResource flowlauncher_plugin_cmd_always_run_as_administrator}" />
Content="{DynamicResource flowlauncher_plugin_cmd_always_run_as_administrator}"
IsChecked="{Binding Settings.RunAsAdministrator, Mode=TwoWay}" />
<CheckBox
x:Name="UseWindowsTerminal"
Grid.Row="4"
Margin="{StaticResource SettingPanelItemRightTopBottomMargin}"
HorizontalAlignment="Left"
Content="{DynamicResource flowlauncher_plugin_cmd_use_windows_terminal}" />
Content="{DynamicResource flowlauncher_plugin_cmd_use_windows_terminal}"
IsChecked="{Binding Settings.UseWindowsTerminal, Mode=TwoWay}" />
<ComboBox
x:Name="ShellComboBox"
Grid.Row="5"
Margin="{StaticResource SettingPanelItemRightTopBottomMargin}"
HorizontalAlignment="Left">
<ComboBoxItem>CMD</ComboBoxItem>
<ComboBoxItem>PowerShell</ComboBoxItem>
<ComboBoxItem>Pwsh</ComboBoxItem>
<ComboBoxItem>RunCommand</ComboBoxItem>
</ComboBox>
HorizontalAlignment="Left"
DisplayMemberPath="Display"
ItemsSource="{Binding AllShells, Mode=OneTime}"
SelectedValue="{Binding SelectedShell, Mode=TwoWay}"
SelectedValuePath="Value" />
<StackPanel Grid.Row="6" Orientation="Horizontal">
<CheckBox
x:Name="ShowOnlyMostUsedCMDs"
Margin="{StaticResource SettingPanelItemRightTopBottomMargin}"
Content="{DynamicResource flowlauncher_plugin_cmd_history}" />
Content="{DynamicResource flowlauncher_plugin_cmd_history}"
IsChecked="{Binding Settings.ShowOnlyMostUsedCMDs, Mode=TwoWay}" />
<ComboBox
x:Name="ShowOnlyMostUsedCMDsNumber"
Margin="{StaticResource SettingPanelItemRightTopBottomMargin}"
HorizontalAlignment="Left" />
HorizontalAlignment="Left"
IsEnabled="{Binding Settings.ShowOnlyMostUsedCMDs, Mode=OneWay}"
ItemsSource="{Binding OnlyMostUsedCMDsNumbers, Mode=OneTime}"
SelectedItem="{Binding SelectedOnlyMostUsedCMDsNumber, Mode=TwoWay}" />
</StackPanel>
</Grid>
</UserControl>

View file

@ -0,0 +1,15 @@
using System.Windows.Controls;
using Flow.Launcher.Plugin.Shell.ViewModels;
namespace Flow.Launcher.Plugin.Shell.Views
{
public partial class CMDSetting : UserControl
{
public CMDSetting(Settings settings)
{
var viewModel = new ShellSettingViewModel(settings);
DataContext = viewModel;
InitializeComponent();
}
}
}