diff --git a/Plugins/Flow.Launcher.Plugin.Program/AddProgramSource.xaml b/Plugins/Flow.Launcher.Plugin.Program/AddProgramSource.xaml index 9ee97e3e953..9848f51cfe0 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/AddProgramSource.xaml +++ b/Plugins/Flow.Launcher.Plugin.Program/AddProgramSource.xaml @@ -4,7 +4,10 @@ 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:vm="clr-namespace:Flow.Launcher.Plugin.Program.ViewModels" + mc:Ignorable="d" Title="{DynamicResource flowlauncher_plugin_program_directory}" + d:DataContext="{d:DesignInstance vm:AddProgramSourceViewModel}" Width="Auto" Height="276" Background="{DynamicResource PopuBGColor}" @@ -15,6 +18,9 @@ + + + @@ -98,11 +104,14 @@ HorizontalAlignment="Stretch" Click="BrowseButton_Click" Content="{DynamicResource flowlauncher_plugin_program_browse}" + Visibility="{Binding IsCustomSource, Converter={StaticResource BooleanToVisibilityConverter}}" DockPanel.Dock="Right" /> @@ -119,6 +128,7 @@ Grid.Row="1" Grid.Column="1" Margin="10,0" + IsChecked="{Binding Enabled, Mode=TwoWay}" VerticalAlignment="Center" /> @@ -142,7 +152,7 @@ MinWidth="140" Margin="5,0,10,0" Click="BtnAdd_OnClick" - Content="{DynamicResource flowlauncher_plugin_program_update}" + Content="{Binding AddBtnText}" Style="{DynamicResource AccentButtonStyle}" /> diff --git a/Plugins/Flow.Launcher.Plugin.Program/AddProgramSource.xaml.cs b/Plugins/Flow.Launcher.Plugin.Program/AddProgramSource.xaml.cs index e88c9b988d1..be8b768bd8f 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/AddProgramSource.xaml.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/AddProgramSource.xaml.cs @@ -1,8 +1,5 @@ using System.Windows; -using System.Windows.Forms; -using Flow.Launcher.Plugin.Program.Views.Models; -using Flow.Launcher.Plugin.Program.Views; -using System.Linq; +using Flow.Launcher.Plugin.Program.ViewModels; namespace Flow.Launcher.Plugin.Program { @@ -11,41 +8,18 @@ namespace Flow.Launcher.Plugin.Program /// public partial class AddProgramSource : Window { - private PluginInitContext _context; - private ProgramSource _editing; - private Settings _settings; - private bool update; + private readonly AddProgramSourceViewModel ViewModel; - public AddProgramSource(PluginInitContext context, Settings settings) + public AddProgramSource(AddProgramSourceViewModel viewModel) { + ViewModel = viewModel; + DataContext = viewModel; InitializeComponent(); - _context = context; - _settings = settings; - Directory.Focus(); - Chkbox.IsChecked = true; - update = false; - btnAdd.Content = _context.API.GetTranslation("flowlauncher_plugin_program_add"); - } - - public AddProgramSource(PluginInitContext context, Settings settings, ProgramSource source) - { - InitializeComponent(); - _context = context; - _editing = source; - _settings = settings; - update = true; - Chkbox.IsChecked = _editing.Enabled; - Directory.Text = _editing.Location; } private void BrowseButton_Click(object sender, RoutedEventArgs e) { - var dialog = new FolderBrowserDialog(); - DialogResult result = dialog.ShowDialog(); - if (result == System.Windows.Forms.DialogResult.OK) - { - Directory.Text = dialog.SelectedPath; - } + ViewModel.Browse(); } private void BtnCancel_OnClick(object sender, RoutedEventArgs e) @@ -55,51 +29,12 @@ private void BtnCancel_OnClick(object sender, RoutedEventArgs e) private void BtnAdd_OnClick(object sender, RoutedEventArgs e) { - string path = Directory.Text; - bool modified = false; - if (!System.IO.Directory.Exists(path)) + var (modified, msg) = ViewModel.AddOrUpdate(); + if (modified == false && msg != null) { - System.Windows.MessageBox.Show(_context.API.GetTranslation("flowlauncher_plugin_program_invalid_path")); + MessageBox.Show(msg); // Invalid return; } - if (!update) - { - if (!ProgramSetting.ProgramSettingDisplayList.Any(x => x.UniqueIdentifier.Equals(path, System.StringComparison.OrdinalIgnoreCase))) - { - var source = new ProgramSource(path); - modified = true; - _settings.ProgramSources.Insert(0, source); - ProgramSetting.ProgramSettingDisplayList.Add(source); - } - else - { - System.Windows.MessageBox.Show(_context.API.GetTranslation("flowlauncher_plugin_program_duplicate_program_source")); - return; - } - } - else - { - // Separate checks to avoid changing UniqueIdentifier of UWP - if (!_editing.Location.Equals(path, System.StringComparison.OrdinalIgnoreCase)) - { - if (ProgramSetting.ProgramSettingDisplayList - .Any(x => x.UniqueIdentifier.Equals(path, System.StringComparison.OrdinalIgnoreCase))) - { - // Check if the new location is used - // No need to check win32 or uwp, just override them - System.Windows.MessageBox.Show(_context.API.GetTranslation("flowlauncher_plugin_program_duplicate_program_source")); - return; - } - modified = true; - _editing.Location = path; // Changes UniqueIdentifier internally - } - if (_editing.Enabled != Chkbox.IsChecked) - { - modified = true; - _editing.Enabled = Chkbox.IsChecked ?? true; - } - } - DialogResult = modified; Close(); } diff --git a/Plugins/Flow.Launcher.Plugin.Program/LocationConverter.cs b/Plugins/Flow.Launcher.Plugin.Program/LocationConverter.cs deleted file mode 100644 index 41384aa8379..00000000000 --- a/Plugins/Flow.Launcher.Plugin.Program/LocationConverter.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System; -using System.Globalization; -using System.Windows.Data; -using System.Windows.Markup; - -namespace Flow.Launcher.Plugin.Program -{ - public class LocationConverter : MarkupExtension, IValueConverter - { - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - var text = value as string; - if (string.IsNullOrEmpty(text)) - { - return string.Empty; - } - else - { - return text; - } - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - throw new NotSupportedException(); - } - - public override object ProvideValue(IServiceProvider serviceProvider) - { - return this; - } - } -} diff --git a/Plugins/Flow.Launcher.Plugin.Program/ViewModels/AddProgramSourceViewModel.cs b/Plugins/Flow.Launcher.Plugin.Program/ViewModels/AddProgramSourceViewModel.cs new file mode 100644 index 00000000000..1bb1ca13c80 --- /dev/null +++ b/Plugins/Flow.Launcher.Plugin.Program/ViewModels/AddProgramSourceViewModel.cs @@ -0,0 +1,131 @@ +using System; +using System.IO; +using System.Linq; +using System.Windows.Forms; +using Flow.Launcher.Plugin.Program.Views; +using Flow.Launcher.Plugin.Program.Views.Models; + +namespace Flow.Launcher.Plugin.Program.ViewModels +{ + public class AddProgramSourceViewModel : BaseModel + { + private readonly Settings Settings; + + private bool enabled = true; + public bool Enabled + { + get => enabled; + set + { + enabled = value; + StatusModified = true; + } + } + + private string location = string.Empty; + public string Location + { + get => location; + set + { + location = value; + LocationModified = true; + OnPropertyChanged(); + } + } + + public ProgramSource Source { get; init; } + public IPublicAPI API { get; init; } + public string AddBtnText { get; init; } + private bool LocationModified = false; + private bool StatusModified = false; + public bool IsCustomSource { get; init; } = true; + public bool IsNotCustomSource => !IsCustomSource; + + public AddProgramSourceViewModel(PluginInitContext context, Settings settings) + { + API = context.API; + Settings = settings; + AddBtnText = API.GetTranslation("flowlauncher_plugin_program_add"); + } + + public AddProgramSourceViewModel(PluginInitContext context, Settings settings, ProgramSource programSource) : this(context, settings) + { + Source = programSource; + enabled = Source.Enabled; + location = Source.Location; + AddBtnText = API.GetTranslation("flowlauncher_plugin_program_update"); + IsCustomSource = Settings.ProgramSources.Any(x => x.UniqueIdentifier == Source.UniqueIdentifier); + } + + public void Browse() + { + var dialog = new FolderBrowserDialog(); + DialogResult result = dialog.ShowDialog(); + if (result == DialogResult.OK) + { + Location = dialog.SelectedPath; + } + } + + public (bool modified, string message) AddProgramSource() + { + if (!Directory.Exists(Location)) + { + return (false, API.GetTranslation("flowlauncher_plugin_program_invalid_path")); + } + else if (DuplicateSource(Location)) + { + return (false, API.GetTranslation("flowlauncher_plugin_program_duplicate_program_source")); + } + else + { + var source = new ProgramSource(Location, Enabled); + Settings.ProgramSources.Insert(0, source); + ProgramSetting.ProgramSettingDisplayList.Add(source); + return (true, null); + } + } + + public (bool modified, string message) UpdateProgramSource() + { + if (LocationModified) + { + if (!Directory.Exists(Location)) + { + return (false, API.GetTranslation("flowlauncher_plugin_program_invalid_path")); + } + else if (DuplicateSource(Location)) + { + return (false, API.GetTranslation("flowlauncher_plugin_program_duplicate_program_source")); + } + else + { + Source.Location = Location; // Changes UniqueIdentifier internally + } + } + if (StatusModified) + { + Source.Enabled = Enabled; + } + return (StatusModified || LocationModified, null); + } + + public (bool modified, string message) AddOrUpdate() + { + if (Source == null) + { + return AddProgramSource(); + } + else + { + return UpdateProgramSource(); + } + } + + public static bool DuplicateSource(string location) + { + return ProgramSetting.ProgramSettingDisplayList.Any(x => x.UniqueIdentifier.Equals(location, StringComparison.OrdinalIgnoreCase)); + } + } +} diff --git a/Plugins/Flow.Launcher.Plugin.Program/Views/Models/ProgramSource.cs b/Plugins/Flow.Launcher.Plugin.Program/Views/Models/ProgramSource.cs index 571dc00174e..93c33e9ad18 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Views/Models/ProgramSource.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Views/Models/ProgramSource.cs @@ -83,7 +83,7 @@ public bool Equals(IProgram program) public override int GetHashCode() { - return HashCode.Combine(UniqueIdentifier); + return uniqueIdentifier.GetHashCode(); } } } diff --git a/Plugins/Flow.Launcher.Plugin.Program/Views/ProgramSetting.xaml b/Plugins/Flow.Launcher.Plugin.Program/Views/ProgramSetting.xaml index ab32dade270..957042de5d3 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Views/ProgramSetting.xaml +++ b/Plugins/Flow.Launcher.Plugin.Program/Views/ProgramSetting.xaml @@ -4,7 +4,6 @@ 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:program="clr-namespace:Flow.Launcher.Plugin.Program" Height="520" DataContext="{Binding RelativeSource={RelativeSource Self}}" mc:Ignorable="d"> @@ -180,7 +179,7 @@ - + diff --git a/Plugins/Flow.Launcher.Plugin.Program/Views/ProgramSetting.xaml.cs b/Plugins/Flow.Launcher.Plugin.Program/Views/ProgramSetting.xaml.cs index b14979337a2..7da224b698f 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Views/ProgramSetting.xaml.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Views/ProgramSetting.xaml.cs @@ -9,7 +9,7 @@ using Flow.Launcher.Plugin.Program.Programs; using System.ComponentModel; using System.Windows.Data; -using System; +using Flow.Launcher.Plugin.Program.ViewModels; namespace Flow.Launcher.Plugin.Program.Views { @@ -136,7 +136,8 @@ private async void ReIndexing() private void btnAddProgramSource_OnClick(object sender, RoutedEventArgs e) { - var add = new AddProgramSource(context, _settings); + var vm = new AddProgramSourceViewModel(context, _settings); + var add = new AddProgramSource(vm); if (add.ShowDialog() ?? false) { ReIndexing(); @@ -171,7 +172,12 @@ private void EditProgramSource(ProgramSource selectedProgramSource) } else { - var add = new AddProgramSource(context, _settings, selectedProgramSource); + var vm = new AddProgramSourceViewModel(context, _settings, selectedProgramSource); + var add = new AddProgramSource(vm); + int selectedIndex = programSourceView.SelectedIndex; + // https://stackoverflow.com/questions/16789360/wpf-listbox-items-with-changing-hashcode + // Or it can't be unselected after changing Location + programSourceView.UnselectAll(); if (add.ShowDialog() ?? false) { if (selectedProgramSource.Enabled) @@ -186,6 +192,7 @@ private void EditProgramSource(ProgramSource selectedProgramSource) } ReIndexing(); } + programSourceView.SelectedIndex = selectedIndex; } }