Skip to content

Commit 71a1ca7

Browse files
authored
Merge pull request #1600 from VictoriousRaptor/FixProgramSource
[Dev] Refactor AddProgramSource dialog and bugfix
2 parents 6dd34b9 + ae8955b commit 71a1ca7

File tree

7 files changed

+163
-114
lines changed

7 files changed

+163
-114
lines changed

Plugins/Flow.Launcher.Plugin.Program/AddProgramSource.xaml

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@
44
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
55
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
66
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
7+
xmlns:vm="clr-namespace:Flow.Launcher.Plugin.Program.ViewModels"
8+
mc:Ignorable="d"
79
Title="{DynamicResource flowlauncher_plugin_program_directory}"
10+
d:DataContext="{d:DesignInstance vm:AddProgramSourceViewModel}"
811
Width="Auto"
912
Height="276"
1013
Background="{DynamicResource PopuBGColor}"
@@ -15,6 +18,9 @@
1518
<WindowChrome.WindowChrome>
1619
<WindowChrome CaptionHeight="32" ResizeBorderThickness="{x:Static SystemParameters.WindowResizeBorderThickness}" />
1720
</WindowChrome.WindowChrome>
21+
<Window.Resources>
22+
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
23+
</Window.Resources>
1824
<Grid>
1925
<Grid.RowDefinitions>
2026
<RowDefinition />
@@ -98,11 +104,14 @@
98104
HorizontalAlignment="Stretch"
99105
Click="BrowseButton_Click"
100106
Content="{DynamicResource flowlauncher_plugin_program_browse}"
107+
Visibility="{Binding IsCustomSource, Converter={StaticResource BooleanToVisibilityConverter}}"
101108
DockPanel.Dock="Right" />
102109
<TextBox
103110
Name="Directory"
104111
Width="350"
105112
Margin="10"
113+
Text="{Binding Location, Mode=TwoWay}"
114+
IsReadOnly="{Binding IsNotCustomSource}"
106115
HorizontalAlignment="Stretch"
107116
VerticalAlignment="Center" />
108117
</DockPanel>
@@ -119,6 +128,7 @@
119128
Grid.Row="1"
120129
Grid.Column="1"
121130
Margin="10,0"
131+
IsChecked="{Binding Enabled, Mode=TwoWay}"
122132
VerticalAlignment="Center" />
123133
</Grid>
124134
</StackPanel>
@@ -142,7 +152,7 @@
142152
MinWidth="140"
143153
Margin="5,0,10,0"
144154
Click="BtnAdd_OnClick"
145-
Content="{DynamicResource flowlauncher_plugin_program_update}"
155+
Content="{Binding AddBtnText}"
146156
Style="{DynamicResource AccentButtonStyle}" />
147157
</StackPanel>
148158
</Border>

Plugins/Flow.Launcher.Plugin.Program/AddProgramSource.xaml.cs

Lines changed: 9 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
using System.Windows;
2-
using System.Windows.Forms;
3-
using Flow.Launcher.Plugin.Program.Views.Models;
4-
using Flow.Launcher.Plugin.Program.Views;
5-
using System.Linq;
2+
using Flow.Launcher.Plugin.Program.ViewModels;
63

74
namespace Flow.Launcher.Plugin.Program
85
{
@@ -11,41 +8,18 @@ namespace Flow.Launcher.Plugin.Program
118
/// </summary>
129
public partial class AddProgramSource : Window
1310
{
14-
private PluginInitContext _context;
15-
private ProgramSource _editing;
16-
private Settings _settings;
17-
private bool update;
11+
private readonly AddProgramSourceViewModel ViewModel;
1812

19-
public AddProgramSource(PluginInitContext context, Settings settings)
13+
public AddProgramSource(AddProgramSourceViewModel viewModel)
2014
{
15+
ViewModel = viewModel;
16+
DataContext = viewModel;
2117
InitializeComponent();
22-
_context = context;
23-
_settings = settings;
24-
Directory.Focus();
25-
Chkbox.IsChecked = true;
26-
update = false;
27-
btnAdd.Content = _context.API.GetTranslation("flowlauncher_plugin_program_add");
28-
}
29-
30-
public AddProgramSource(PluginInitContext context, Settings settings, ProgramSource source)
31-
{
32-
InitializeComponent();
33-
_context = context;
34-
_editing = source;
35-
_settings = settings;
36-
update = true;
37-
Chkbox.IsChecked = _editing.Enabled;
38-
Directory.Text = _editing.Location;
3918
}
4019

4120
private void BrowseButton_Click(object sender, RoutedEventArgs e)
4221
{
43-
var dialog = new FolderBrowserDialog();
44-
DialogResult result = dialog.ShowDialog();
45-
if (result == System.Windows.Forms.DialogResult.OK)
46-
{
47-
Directory.Text = dialog.SelectedPath;
48-
}
22+
ViewModel.Browse();
4923
}
5024

5125
private void BtnCancel_OnClick(object sender, RoutedEventArgs e)
@@ -55,51 +29,12 @@ private void BtnCancel_OnClick(object sender, RoutedEventArgs e)
5529

5630
private void BtnAdd_OnClick(object sender, RoutedEventArgs e)
5731
{
58-
string path = Directory.Text;
59-
bool modified = false;
60-
if (!System.IO.Directory.Exists(path))
32+
var (modified, msg) = ViewModel.AddOrUpdate();
33+
if (modified == false && msg != null)
6134
{
62-
System.Windows.MessageBox.Show(_context.API.GetTranslation("flowlauncher_plugin_program_invalid_path"));
35+
MessageBox.Show(msg); // Invalid
6336
return;
6437
}
65-
if (!update)
66-
{
67-
if (!ProgramSetting.ProgramSettingDisplayList.Any(x => x.UniqueIdentifier.Equals(path, System.StringComparison.OrdinalIgnoreCase)))
68-
{
69-
var source = new ProgramSource(path);
70-
modified = true;
71-
_settings.ProgramSources.Insert(0, source);
72-
ProgramSetting.ProgramSettingDisplayList.Add(source);
73-
}
74-
else
75-
{
76-
System.Windows.MessageBox.Show(_context.API.GetTranslation("flowlauncher_plugin_program_duplicate_program_source"));
77-
return;
78-
}
79-
}
80-
else
81-
{
82-
// Separate checks to avoid changing UniqueIdentifier of UWP
83-
if (!_editing.Location.Equals(path, System.StringComparison.OrdinalIgnoreCase))
84-
{
85-
if (ProgramSetting.ProgramSettingDisplayList
86-
.Any(x => x.UniqueIdentifier.Equals(path, System.StringComparison.OrdinalIgnoreCase)))
87-
{
88-
// Check if the new location is used
89-
// No need to check win32 or uwp, just override them
90-
System.Windows.MessageBox.Show(_context.API.GetTranslation("flowlauncher_plugin_program_duplicate_program_source"));
91-
return;
92-
}
93-
modified = true;
94-
_editing.Location = path; // Changes UniqueIdentifier internally
95-
}
96-
if (_editing.Enabled != Chkbox.IsChecked)
97-
{
98-
modified = true;
99-
_editing.Enabled = Chkbox.IsChecked ?? true;
100-
}
101-
}
102-
10338
DialogResult = modified;
10439
Close();
10540
}

Plugins/Flow.Launcher.Plugin.Program/LocationConverter.cs

Lines changed: 0 additions & 33 deletions
This file was deleted.
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
using System;
2+
using System.IO;
3+
using System.Linq;
4+
using System.Windows.Forms;
5+
using Flow.Launcher.Plugin.Program.Views;
6+
using Flow.Launcher.Plugin.Program.Views.Models;
7+
8+
namespace Flow.Launcher.Plugin.Program.ViewModels
9+
{
10+
public class AddProgramSourceViewModel : BaseModel
11+
{
12+
private readonly Settings Settings;
13+
14+
private bool enabled = true;
15+
public bool Enabled
16+
{
17+
get => enabled;
18+
set
19+
{
20+
enabled = value;
21+
StatusModified = true;
22+
}
23+
}
24+
25+
private string location = string.Empty;
26+
public string Location
27+
{
28+
get => location;
29+
set
30+
{
31+
location = value;
32+
LocationModified = true;
33+
OnPropertyChanged();
34+
}
35+
}
36+
37+
public ProgramSource Source { get; init; }
38+
public IPublicAPI API { get; init; }
39+
public string AddBtnText { get; init; }
40+
private bool LocationModified = false;
41+
private bool StatusModified = false;
42+
public bool IsCustomSource { get; init; } = true;
43+
public bool IsNotCustomSource => !IsCustomSource;
44+
45+
public AddProgramSourceViewModel(PluginInitContext context, Settings settings)
46+
{
47+
API = context.API;
48+
Settings = settings;
49+
AddBtnText = API.GetTranslation("flowlauncher_plugin_program_add");
50+
}
51+
52+
public AddProgramSourceViewModel(PluginInitContext context, Settings settings, ProgramSource programSource) : this(context, settings)
53+
{
54+
Source = programSource;
55+
enabled = Source.Enabled;
56+
location = Source.Location;
57+
AddBtnText = API.GetTranslation("flowlauncher_plugin_program_update");
58+
IsCustomSource = Settings.ProgramSources.Any(x => x.UniqueIdentifier == Source.UniqueIdentifier);
59+
}
60+
61+
public void Browse()
62+
{
63+
var dialog = new FolderBrowserDialog();
64+
DialogResult result = dialog.ShowDialog();
65+
if (result == DialogResult.OK)
66+
{
67+
Location = dialog.SelectedPath;
68+
}
69+
}
70+
71+
public (bool modified, string message) AddProgramSource()
72+
{
73+
if (!Directory.Exists(Location))
74+
{
75+
return (false, API.GetTranslation("flowlauncher_plugin_program_invalid_path"));
76+
}
77+
else if (DuplicateSource(Location))
78+
{
79+
return (false, API.GetTranslation("flowlauncher_plugin_program_duplicate_program_source"));
80+
}
81+
else
82+
{
83+
var source = new ProgramSource(Location, Enabled);
84+
Settings.ProgramSources.Insert(0, source);
85+
ProgramSetting.ProgramSettingDisplayList.Add(source);
86+
return (true, null);
87+
}
88+
}
89+
90+
public (bool modified, string message) UpdateProgramSource()
91+
{
92+
if (LocationModified)
93+
{
94+
if (!Directory.Exists(Location))
95+
{
96+
return (false, API.GetTranslation("flowlauncher_plugin_program_invalid_path"));
97+
}
98+
else if (DuplicateSource(Location))
99+
{
100+
return (false, API.GetTranslation("flowlauncher_plugin_program_duplicate_program_source"));
101+
}
102+
else
103+
{
104+
Source.Location = Location; // Changes UniqueIdentifier internally
105+
}
106+
}
107+
if (StatusModified)
108+
{
109+
Source.Enabled = Enabled;
110+
}
111+
return (StatusModified || LocationModified, null);
112+
}
113+
114+
public (bool modified, string message) AddOrUpdate()
115+
{
116+
if (Source == null)
117+
{
118+
return AddProgramSource();
119+
}
120+
else
121+
{
122+
return UpdateProgramSource();
123+
}
124+
}
125+
126+
public static bool DuplicateSource(string location)
127+
{
128+
return ProgramSetting.ProgramSettingDisplayList.Any(x => x.UniqueIdentifier.Equals(location, StringComparison.OrdinalIgnoreCase));
129+
}
130+
}
131+
}

Plugins/Flow.Launcher.Plugin.Program/Views/Models/ProgramSource.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ public bool Equals(IProgram program)
8383

8484
public override int GetHashCode()
8585
{
86-
return HashCode.Combine(UniqueIdentifier);
86+
return uniqueIdentifier.GetHashCode();
8787
}
8888
}
8989
}

Plugins/Flow.Launcher.Plugin.Program/Views/ProgramSetting.xaml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
55
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
66
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
7-
xmlns:program="clr-namespace:Flow.Launcher.Plugin.Program"
87
Height="520"
98
DataContext="{Binding RelativeSource={RelativeSource Self}}"
109
mc:Ignorable="d">
@@ -180,7 +179,7 @@
180179
<GridViewColumn Header="{DynamicResource flowlauncher_plugin_program_location}">
181180
<GridViewColumn.CellTemplate>
182181
<DataTemplate>
183-
<TextBlock Text="{Binding Location, ConverterParameter=(null), Converter={program:LocationConverter}}" TextTrimming="CharacterEllipsis" />
182+
<TextBlock Text="{Binding Location}" TextTrimming="CharacterEllipsis" />
184183
</DataTemplate>
185184
</GridViewColumn.CellTemplate>
186185
</GridViewColumn>

Plugins/Flow.Launcher.Plugin.Program/Views/ProgramSetting.xaml.cs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
using Flow.Launcher.Plugin.Program.Programs;
1010
using System.ComponentModel;
1111
using System.Windows.Data;
12-
using System;
12+
using Flow.Launcher.Plugin.Program.ViewModels;
1313

1414
namespace Flow.Launcher.Plugin.Program.Views
1515
{
@@ -136,7 +136,8 @@ private async void ReIndexing()
136136

137137
private void btnAddProgramSource_OnClick(object sender, RoutedEventArgs e)
138138
{
139-
var add = new AddProgramSource(context, _settings);
139+
var vm = new AddProgramSourceViewModel(context, _settings);
140+
var add = new AddProgramSource(vm);
140141
if (add.ShowDialog() ?? false)
141142
{
142143
ReIndexing();
@@ -171,7 +172,12 @@ private void EditProgramSource(ProgramSource selectedProgramSource)
171172
}
172173
else
173174
{
174-
var add = new AddProgramSource(context, _settings, selectedProgramSource);
175+
var vm = new AddProgramSourceViewModel(context, _settings, selectedProgramSource);
176+
var add = new AddProgramSource(vm);
177+
int selectedIndex = programSourceView.SelectedIndex;
178+
// https://stackoverflow.com/questions/16789360/wpf-listbox-items-with-changing-hashcode
179+
// Or it can't be unselected after changing Location
180+
programSourceView.UnselectAll();
175181
if (add.ShowDialog() ?? false)
176182
{
177183
if (selectedProgramSource.Enabled)
@@ -186,6 +192,7 @@ private void EditProgramSource(ProgramSource selectedProgramSource)
186192
}
187193
ReIndexing();
188194
}
195+
programSourceView.SelectedIndex = selectedIndex;
189196
}
190197
}
191198

0 commit comments

Comments
 (0)