Skip to content

Commit e5d95f3

Browse files
committed
refactor relaycommands with mvvmtoolkit sourcegenerator to prevent potential null reference
1 parent 337e6ca commit e5d95f3

File tree

1 file changed

+127
-145
lines changed

1 file changed

+127
-145
lines changed

Flow.Launcher/ViewModel/MainViewModel.cs

Lines changed: 127 additions & 145 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,6 @@ public MainViewModel(Settings settings)
7777
_userSelectedRecord = _userSelectedRecordStorage.Load();
7878
_topMostRecord = _topMostRecordStorage.Load();
7979

80-
InitializeKeyCommands();
8180

8281
ContextMenu = new ResultsViewModel(Settings)
8382
{
@@ -167,160 +166,161 @@ private void RegisterResultsUpdatedEvent()
167166
}
168167
}
169168

169+
[RelayCommand]
170+
private async Task ReloadPluginDataAsync()
171+
{
172+
Hide();
170173

171-
172-
private void InitializeKeyCommands()
174+
await PluginManager.ReloadDataAsync().ConfigureAwait(false);
175+
Notification.Show(InternationalizationManager.Instance.GetTranslation("success"), InternationalizationManager.Instance.GetTranslation("completedSuccessfully"));
176+
}
177+
[RelayCommand]
178+
private void LoadHistory()
173179
{
174-
EscCommand = new RelayCommand(_ =>
180+
if (SelectedIsFromQueryResults())
175181
{
176-
if (!SelectedIsFromQueryResults())
177-
{
178-
SelectedResults = Results;
179-
}
180-
else
181-
{
182-
Hide();
183-
}
184-
});
185-
186-
ClearQueryCommand = new RelayCommand(_ =>
182+
SelectedResults = History;
183+
History.SelectedIndex = _history.Items.Count - 1;
184+
}
185+
else
187186
{
188-
if (!string.IsNullOrEmpty(QueryText))
189-
{
190-
ChangeQueryText(string.Empty);
191-
192-
// Push Event to UI SystemQuery has changed
193-
//OnPropertyChanged(nameof(SystemQueryText));
194-
}
195-
});
196-
197-
SelectNextItemCommand = new RelayCommand(_ => { SelectedResults.SelectNextResult(); });
198-
199-
SelectPrevItemCommand = new RelayCommand(_ => { SelectedResults.SelectPrevResult(); });
200-
201-
SelectNextPageCommand = new RelayCommand(_ => { SelectedResults.SelectNextPage(); });
187+
SelectedResults = Results;
188+
}
189+
}
190+
[RelayCommand]
191+
private void LoadContextMenu()
192+
{
193+
if (SelectedIsFromQueryResults())
194+
{
195+
// When switch to ContextMenu from QueryResults, but no item being chosen, should do nothing
196+
// i.e. Shift+Enter/Ctrl+O right after Alt + Space should do nothing
197+
if (SelectedResults.SelectedItem != null)
198+
SelectedResults = ContextMenu;
199+
}
200+
else
201+
{
202+
SelectedResults = Results;
203+
}
204+
}
205+
[RelayCommand]
206+
private void Backspace(object index)
207+
{
208+
var query = QueryBuilder.Build(QueryText.Trim(), PluginManager.NonGlobalPlugins);
202209

203-
SelectPrevPageCommand = new RelayCommand(_ => { SelectedResults.SelectPrevPage(); });
210+
// GetPreviousExistingDirectory does not require trailing '\', otherwise will return empty string
211+
var path = FilesFolders.GetPreviousExistingDirectory((_) => true, query.Search.TrimEnd('\\'));
204212

205-
SelectFirstResultCommand = new RelayCommand(_ => SelectedResults.SelectFirstResult());
213+
var actionKeyword = string.IsNullOrEmpty(query.ActionKeyword) ? string.Empty : $"{query.ActionKeyword} ";
206214

207-
StartHelpCommand = new RelayCommand(_ =>
208-
{
209-
PluginManager.API.OpenUrl("https://github.com/Flow-Launcher/Flow.Launcher/wiki/Flow-Launcher/");
210-
});
211-
OpenSettingCommand = new RelayCommand(_ => { App.API.OpenSettingDialog(); });
212-
OpenResultCommand = new AsyncRelayCommand(async _ =>
215+
ChangeQueryText($"{actionKeyword}{path}");
216+
}
217+
[RelayCommand]
218+
private void AutocompleteQuery()
219+
{
220+
var result = SelectedResults.SelectedItem?.Result;
221+
if (result != null && SelectedIsFromQueryResults()) // SelectedItem returns null if selection is empty.
213222
{
214-
var results = SelectedResults;
223+
var autoCompleteText = result.Title;
215224

216-
var result = results.SelectedItem?.Result;
217-
if (result == null)
225+
if (!string.IsNullOrEmpty(result.AutoCompleteText))
218226
{
219-
return;
227+
autoCompleteText = result.AutoCompleteText;
220228
}
221-
var hideWindow = await result.ExecuteAsync(new ActionContext
229+
else if (!string.IsNullOrEmpty(SelectedResults.SelectedItem?.QuerySuggestionText))
222230
{
223-
SpecialKeyState = GlobalHotkey.CheckModifiers()
224-
}).ConfigureAwait(false);
225-
226-
if (hideWindow)
227-
{
228-
Hide();
231+
autoCompleteText = SelectedResults.SelectedItem.QuerySuggestionText;
229232
}
230233

231-
if (SelectedIsFromQueryResults())
234+
var specialKeyState = GlobalHotkey.CheckModifiers();
235+
if (specialKeyState.ShiftPressed)
232236
{
233-
_userSelectedRecord.Add(result);
234-
_history.Add(result.OriginQuery.RawQuery);
237+
autoCompleteText = result.SubTitle;
235238
}
236-
else
237-
{
238-
SelectedResults = Results;
239-
}
240-
});
241239

242-
AutocompleteQueryCommand = new RelayCommand(_ =>
240+
ChangeQueryText(autoCompleteText);
241+
}
242+
}
243+
[RelayCommand]
244+
private async Task OpenResult()
245+
{
246+
var results = SelectedResults;
247+
248+
var result = results.SelectedItem?.Result;
249+
if (result == null)
243250
{
244-
var result = SelectedResults.SelectedItem?.Result;
245-
if (result != null && SelectedIsFromQueryResults()) // SelectedItem returns null if selection is empty.
251+
return;
252+
}
253+
var hideWindow = await result.ExecuteAsync(new ActionContext
246254
{
247-
var autoCompleteText = result.Title;
248-
249-
if (!string.IsNullOrEmpty(result.AutoCompleteText))
250-
{
251-
autoCompleteText = result.AutoCompleteText;
252-
}
253-
else if (!string.IsNullOrEmpty(SelectedResults.SelectedItem?.QuerySuggestionText))
254-
{
255-
autoCompleteText = SelectedResults.SelectedItem.QuerySuggestionText;
256-
}
257-
258-
var specialKeyState = GlobalHotkey.CheckModifiers();
259-
if (specialKeyState.ShiftPressed)
260-
{
261-
autoCompleteText = result.SubTitle;
262-
}
263-
264-
ChangeQueryText(autoCompleteText);
265-
}
266-
});
255+
SpecialKeyState = GlobalHotkey.CheckModifiers()
256+
})
257+
.ConfigureAwait(false);
267258

268-
BackspaceCommand = new RelayCommand(index =>
259+
if (hideWindow)
269260
{
270-
var query = QueryBuilder.Build(QueryText.Trim(), PluginManager.NonGlobalPlugins);
261+
Hide();
262+
}
271263

272-
// GetPreviousExistingDirectory does not require trailing '\', otherwise will return empty string
273-
var path = FilesFolders.GetPreviousExistingDirectory((_) => true, query.Search.TrimEnd('\\'));
264+
if (SelectedIsFromQueryResults())
265+
{
266+
_userSelectedRecord.Add(result);
267+
_history.Add(result.OriginQuery.RawQuery);
268+
}
269+
else
270+
{
271+
SelectedResults = Results;
272+
}
273+
}
274+
[RelayCommand]
275+
private void OpenSetting()
276+
{
277+
App.API.OpenSettingDialog();
278+
}
274279

275-
var actionKeyword = string.IsNullOrEmpty(query.ActionKeyword) ? string.Empty : $"{query.ActionKeyword} ";
280+
[RelayCommand]
281+
private void SelectHelp()
282+
{
283+
PluginManager.API.OpenUrl("https://github.com/Flow-Launcher/Flow.Launcher/wiki/Flow-Launcher/");
284+
}
276285

277-
ChangeQueryText($"{actionKeyword}{path}");
278-
});
286+
[RelayCommand]
287+
private void SelectFirstResult()
288+
{
289+
SelectedResults.SelectFirstResult();
290+
}
291+
[RelayCommand]
292+
private void SelectPrevPage()
293+
{
294+
SelectedResults.SelectPrevPage();
295+
}
279296

280-
LoadContextMenuCommand = new RelayCommand(_ =>
281-
{
282-
if (SelectedIsFromQueryResults())
283-
{
284-
// When switch to ContextMenu from QueryResults, but no item being chosen, should do nothing
285-
// i.e. Shift+Enter/Ctrl+O right after Alt + Space should do nothing
286-
if (SelectedResults.SelectedItem != null)
287-
SelectedResults = ContextMenu;
288-
}
289-
else
290-
{
291-
SelectedResults = Results;
292-
}
293-
});
297+
[RelayCommand]
298+
private void SelectNextPage()
299+
{
300+
SelectedResults.SelectNextPage();
301+
}
302+
[RelayCommand]
303+
private void SelectPrevItem()
304+
{
305+
SelectedResults.SelectPrevResult();
306+
}
307+
[RelayCommand]
308+
private void SelectNextItem()
309+
{
310+
SelectedResults.SelectNextResult();
311+
}
294312

295-
LoadHistoryCommand = new RelayCommand(_ =>
313+
[RelayCommand]
314+
private void Esc()
315+
{
316+
if (!SelectedIsFromQueryResults())
296317
{
297-
if (SelectedIsFromQueryResults())
298-
{
299-
SelectedResults = History;
300-
History.SelectedIndex = _history.Items.Count - 1;
301-
}
302-
else
303-
{
304-
SelectedResults = Results;
305-
}
306-
});
307-
308-
ReloadPluginDataCommand = new RelayCommand(_ =>
318+
SelectedResults = Results;
319+
}
320+
else
309321
{
310322
Hide();
311-
312-
_ = PluginManager
313-
.ReloadDataAsync()
314-
.ContinueWith(_ =>
315-
Application.Current.Dispatcher.Invoke(() =>
316-
{
317-
Notification.Show(
318-
InternationalizationManager.Instance.GetTranslation("success"),
319-
InternationalizationManager.Instance.GetTranslation("completedSuccessfully")
320-
);
321-
}), TaskScheduler.Default)
322-
.ConfigureAwait(false);
323-
});
323+
}
324324
}
325325

326326
#endregion
@@ -416,6 +416,7 @@ private void DecreaseMaxResult()
416416
/// but we don't want to move cursor to end when query is updated from TextBox
417417
/// </summary>
418418
/// <param name="queryText"></param>
419+
/// <param name="reQuery">Force query even when Query Text doesn't change</param>
419420
public void ChangeQueryText(string queryText, bool reQuery = false)
420421
{
421422
if (QueryText != queryText)
@@ -494,25 +495,6 @@ public double MainWindowWidth
494495

495496
public string PluginIconPath { get; set; } = null;
496497

497-
public ICommand EscCommand { get; set; }
498-
public ICommand BackspaceCommand { get; set; }
499-
public ICommand SelectNextItemCommand { get; set; }
500-
public ICommand SelectPrevItemCommand { get; set; }
501-
public ICommand SelectNextPageCommand { get; set; }
502-
public ICommand SelectPrevPageCommand { get; set; }
503-
public ICommand SelectFirstResultCommand { get; set; }
504-
public ICommand StartHelpCommand { get; set; }
505-
public ICommand LoadContextMenuCommand { get; set; }
506-
public ICommand LoadHistoryCommand { get; set; }
507-
public ICommand OpenResultCommand { get; set; }
508-
public ICommand OpenSettingCommand { get; set; }
509-
public ICommand ReloadPluginDataCommand { get; set; }
510-
public ICommand ClearQueryCommand { get; private set; }
511-
512-
public ICommand CopyToClipboard { get; set; }
513-
514-
public ICommand AutocompleteQueryCommand { get; set; }
515-
516498
public string OpenResultCommandModifiers { get; private set; }
517499

518500
public string Image => Constant.QueryTextBoxIconImagePath;

0 commit comments

Comments
 (0)