Merge pull request #1600 from VictoriousRaptor/FixProgramSource

[Dev] Refactor AddProgramSource dialog and bugfix
This commit is contained in:
Jeremy Wu 2022-12-13 09:08:37 +11:00 committed by GitHub
commit 71a1ca7a1d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 163 additions and 114 deletions

View file

@ -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 @@
<WindowChrome.WindowChrome>
<WindowChrome CaptionHeight="32" ResizeBorderThickness="{x:Static SystemParameters.WindowResizeBorderThickness}" />
</WindowChrome.WindowChrome>
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
@ -98,11 +104,14 @@
HorizontalAlignment="Stretch"
Click="BrowseButton_Click"
Content="{DynamicResource flowlauncher_plugin_program_browse}"
Visibility="{Binding IsCustomSource, Converter={StaticResource BooleanToVisibilityConverter}}"
DockPanel.Dock="Right" />
<TextBox
Name="Directory"
Width="350"
Margin="10"
Text="{Binding Location, Mode=TwoWay}"
IsReadOnly="{Binding IsNotCustomSource}"
HorizontalAlignment="Stretch"
VerticalAlignment="Center" />
</DockPanel>
@ -119,6 +128,7 @@
Grid.Row="1"
Grid.Column="1"
Margin="10,0"
IsChecked="{Binding Enabled, Mode=TwoWay}"
VerticalAlignment="Center" />
</Grid>
</StackPanel>
@ -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}" />
</StackPanel>
</Border>

View file

@ -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
/// </summary>
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 @@ namespace Flow.Launcher.Plugin.Program
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();
}

View file

@ -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;
}
}
}

View file

@ -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));
}
}
}

View file

@ -83,7 +83,7 @@ namespace Flow.Launcher.Plugin.Program.Views.Models
public override int GetHashCode()
{
return HashCode.Combine(UniqueIdentifier);
return uniqueIdentifier.GetHashCode();
}
}
}

View file

@ -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 @@
<GridViewColumn Header="{DynamicResource flowlauncher_plugin_program_location}">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Location, ConverterParameter=(null), Converter={program:LocationConverter}}" TextTrimming="CharacterEllipsis" />
<TextBlock Text="{Binding Location}" TextTrimming="CharacterEllipsis" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>

View file

@ -9,7 +9,7 @@ using Flow.Launcher.Plugin.Program.Views.Commands;
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 @@ namespace Flow.Launcher.Plugin.Program.Views
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 @@ namespace Flow.Launcher.Plugin.Program.Views
}
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 @@ namespace Flow.Launcher.Plugin.Program.Views
}
ReIndexing();
}
programSourceView.SelectedIndex = selectedIndex;
}
}