mirror of
https://github.com/Flow-Launcher/Flow.Launcher.git
synced 2026-03-11 08:54:32 +00:00
Merge pull request #3370 from Jack251970/history_preview1
Support Preview Panel for History Results
This commit is contained in:
commit
350276dbf5
7 changed files with 193 additions and 122 deletions
|
|
@ -32,6 +32,7 @@ namespace Flow.Launcher.Infrastructure
|
||||||
public static readonly string MissingImgIcon = Path.Combine(ImagesDirectory, "app_missing_img.png");
|
public static readonly string MissingImgIcon = Path.Combine(ImagesDirectory, "app_missing_img.png");
|
||||||
public static readonly string LoadingImgIcon = Path.Combine(ImagesDirectory, "loading.png");
|
public static readonly string LoadingImgIcon = Path.Combine(ImagesDirectory, "loading.png");
|
||||||
public static readonly string ImageIcon = Path.Combine(ImagesDirectory, "image.png");
|
public static readonly string ImageIcon = Path.Combine(ImagesDirectory, "image.png");
|
||||||
|
public static readonly string HistoryIcon = Path.Combine(ImagesDirectory, "history.png");
|
||||||
|
|
||||||
public static string PythonPath;
|
public static string PythonPath;
|
||||||
public static string NodePath;
|
public static string NodePath;
|
||||||
|
|
|
||||||
|
|
@ -216,7 +216,7 @@
|
||||||
|
|
||||||
<Border MouseDown="OnMouseDown" Style="{DynamicResource WindowBorderStyle}">
|
<Border MouseDown="OnMouseDown" Style="{DynamicResource WindowBorderStyle}">
|
||||||
<StackPanel Orientation="Vertical">
|
<StackPanel Orientation="Vertical">
|
||||||
<Grid>
|
<Grid x:Name="QueryBoxArea">
|
||||||
<Border MinHeight="30" Style="{DynamicResource QueryBoxBgStyle}">
|
<Border MinHeight="30" Style="{DynamicResource QueryBoxBgStyle}">
|
||||||
<Grid>
|
<Grid>
|
||||||
<TextBox
|
<TextBox
|
||||||
|
|
@ -339,7 +339,7 @@
|
||||||
Y2="0" />
|
Y2="0" />
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<Grid ClipToBounds="True">
|
<Grid x:Name="MiddleSeparatorArea" ClipToBounds="True">
|
||||||
<ContentControl>
|
<ContentControl>
|
||||||
<ContentControl.Style>
|
<ContentControl.Style>
|
||||||
<Style TargetType="ContentControl">
|
<Style TargetType="ContentControl">
|
||||||
|
|
@ -379,7 +379,7 @@
|
||||||
</ContentControl>
|
</ContentControl>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<Border Style="{DynamicResource WindowRadius}">
|
<Border x:Name="ResultPreviewAreaBoarder" Style="{DynamicResource WindowRadius}">
|
||||||
<Border.Clip>
|
<Border.Clip>
|
||||||
<MultiBinding Converter="{StaticResource BorderClipConverter}">
|
<MultiBinding Converter="{StaticResource BorderClipConverter}">
|
||||||
<Binding Path="ActualWidth" RelativeSource="{RelativeSource Self}" />
|
<Binding Path="ActualWidth" RelativeSource="{RelativeSource Self}" />
|
||||||
|
|
@ -387,12 +387,14 @@
|
||||||
<Binding Path="CornerRadius" RelativeSource="{RelativeSource Self}" />
|
<Binding Path="CornerRadius" RelativeSource="{RelativeSource Self}" />
|
||||||
</MultiBinding>
|
</MultiBinding>
|
||||||
</Border.Clip>
|
</Border.Clip>
|
||||||
<Grid>
|
|
||||||
|
<Grid x:Name="ResultPreviewArea">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="*" MinWidth="80" />
|
<ColumnDefinition Width="*" MinWidth="80" />
|
||||||
<ColumnDefinition Width="Auto" />
|
<ColumnDefinition Width="Auto" />
|
||||||
<ColumnDefinition Width="0.85*" MinWidth="244" />
|
<ColumnDefinition Width="0.85*" MinWidth="244" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
<StackPanel
|
<StackPanel
|
||||||
x:Name="ResultArea"
|
x:Name="ResultArea"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
|
|
@ -419,7 +421,9 @@
|
||||||
RightClickResultCommand="{Binding RightClickResultCommand}" />
|
RightClickResultCommand="{Binding RightClickResultCommand}" />
|
||||||
</ContentControl>
|
</ContentControl>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<GridSplitter
|
<GridSplitter
|
||||||
|
x:Name="PreviewMiddleSeparator"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Margin="0"
|
Margin="0"
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
|
|
@ -433,6 +437,7 @@
|
||||||
</ControlTemplate>
|
</ControlTemplate>
|
||||||
</GridSplitter.Template>
|
</GridSplitter.Template>
|
||||||
</GridSplitter>
|
</GridSplitter>
|
||||||
|
|
||||||
<Grid
|
<Grid
|
||||||
x:Name="Preview"
|
x:Name="Preview"
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
|
|
@ -442,7 +447,7 @@
|
||||||
<Border
|
<Border
|
||||||
MinHeight="380"
|
MinHeight="380"
|
||||||
d:DataContext="{d:DesignInstance vm:ResultViewModel}"
|
d:DataContext="{d:DesignInstance vm:ResultViewModel}"
|
||||||
DataContext="{Binding SelectedItem, ElementName=ResultListBox}"
|
DataContext="{Binding PreviewSelectedItem, Mode=OneWay}"
|
||||||
Visibility="{Binding ShowDefaultPreview}">
|
Visibility="{Binding ShowDefaultPreview}">
|
||||||
<Grid
|
<Grid
|
||||||
Margin="0 0 10 5"
|
Margin="0 0 10 5"
|
||||||
|
|
@ -519,7 +524,7 @@
|
||||||
MaxHeight="{Binding ElementName=ResultListBox, Path=ActualHeight}"
|
MaxHeight="{Binding ElementName=ResultListBox, Path=ActualHeight}"
|
||||||
Padding="0 0 10 10"
|
Padding="0 0 10 10"
|
||||||
d:DataContext="{d:DesignInstance vm:ResultViewModel}"
|
d:DataContext="{d:DesignInstance vm:ResultViewModel}"
|
||||||
DataContext="{Binding SelectedItem, ElementName=ResultListBox}"
|
DataContext="{Binding PreviewSelectedItem, Mode=OneWay}"
|
||||||
Visibility="{Binding ShowCustomizedPreview}">
|
Visibility="{Binding ShowCustomizedPreview}">
|
||||||
<ContentControl Content="{Binding Result.PreviewPanel.Value}" />
|
<ContentControl Content="{Binding Result.PreviewPanel.Value}" />
|
||||||
</Border>
|
</Border>
|
||||||
|
|
|
||||||
|
|
@ -326,7 +326,7 @@ namespace Flow.Launcher
|
||||||
e.Handled = true;
|
e.Handled = true;
|
||||||
break;
|
break;
|
||||||
case Key.Right:
|
case Key.Right:
|
||||||
if (_viewModel.SelectedIsFromQueryResults()
|
if (_viewModel.QueryResultsSelected()
|
||||||
&& QueryTextBox.CaretIndex == QueryTextBox.Text.Length
|
&& QueryTextBox.CaretIndex == QueryTextBox.Text.Length
|
||||||
&& !string.IsNullOrEmpty(QueryTextBox.Text))
|
&& !string.IsNullOrEmpty(QueryTextBox.Text))
|
||||||
{
|
{
|
||||||
|
|
@ -336,7 +336,7 @@ namespace Flow.Launcher
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case Key.Left:
|
case Key.Left:
|
||||||
if (!_viewModel.SelectedIsFromQueryResults() && QueryTextBox.CaretIndex == 0)
|
if (!_viewModel.QueryResultsSelected() && QueryTextBox.CaretIndex == 0)
|
||||||
{
|
{
|
||||||
_viewModel.EscCommand.Execute(null);
|
_viewModel.EscCommand.Execute(null);
|
||||||
e.Handled = true;
|
e.Handled = true;
|
||||||
|
|
@ -346,7 +346,7 @@ namespace Flow.Launcher
|
||||||
case Key.Back:
|
case Key.Back:
|
||||||
if (specialKeyState.CtrlPressed)
|
if (specialKeyState.CtrlPressed)
|
||||||
{
|
{
|
||||||
if (_viewModel.SelectedIsFromQueryResults()
|
if (_viewModel.QueryResultsSelected()
|
||||||
&& QueryTextBox.Text.Length > 0
|
&& QueryTextBox.Text.Length > 0
|
||||||
&& QueryTextBox.CaretIndex == QueryTextBox.Text.Length)
|
&& QueryTextBox.CaretIndex == QueryTextBox.Text.Length)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -390,6 +390,7 @@
|
||||||
<Style.Triggers>
|
<Style.Triggers>
|
||||||
<MultiDataTrigger>
|
<MultiDataTrigger>
|
||||||
<MultiDataTrigger.Conditions>
|
<MultiDataTrigger.Conditions>
|
||||||
|
<Condition Binding="{Binding ElementName=History, Path=Visibility}" Value="Collapsed" />
|
||||||
<Condition Binding="{Binding ElementName=ResultListBox, Path=Items.Count}" Value="0" />
|
<Condition Binding="{Binding ElementName=ResultListBox, Path=Items.Count}" Value="0" />
|
||||||
</MultiDataTrigger.Conditions>
|
</MultiDataTrigger.Conditions>
|
||||||
<MultiDataTrigger.Setters>
|
<MultiDataTrigger.Setters>
|
||||||
|
|
@ -431,12 +432,12 @@
|
||||||
</DataTrigger>
|
</DataTrigger>
|
||||||
</Style.Triggers>
|
</Style.Triggers>
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
<Style
|
<Style
|
||||||
x:Key="PreviewBorderStyle"
|
x:Key="PreviewBorderStyle"
|
||||||
BasedOn="{StaticResource BasePreviewBorderStyle}"
|
BasedOn="{StaticResource BasePreviewBorderStyle}"
|
||||||
TargetType="{x:Type Border}">
|
TargetType="{x:Type Border}">
|
||||||
<Setter Property="BorderBrush" Value="Gray" />
|
<Setter Property="BorderBrush" Value="Gray" />
|
||||||
|
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
<Style x:Key="PreviewArea" TargetType="{x:Type Grid}">
|
<Style x:Key="PreviewArea" TargetType="{x:Type Grid}">
|
||||||
|
|
@ -446,8 +447,8 @@
|
||||||
<MultiDataTrigger.Conditions>
|
<MultiDataTrigger.Conditions>
|
||||||
<!--
|
<!--
|
||||||
<Condition Binding="{Binding ElementName=ResultListBox, Path=Visibility}" Value="Collapsed" />
|
<Condition Binding="{Binding ElementName=ResultListBox, Path=Visibility}" Value="Collapsed" />
|
||||||
<Condition Binding="{Binding ElementName=ContextMenu, Path=Visibility}" Value="Collapsed" />
|
<Condition Binding="{Binding ElementName=ContextMenu, Path=Visibility}" Value="Collapsed" />-->
|
||||||
<Condition Binding="{Binding ElementName=History, Path=Visibility}" Value="Collapsed" />-->
|
<Condition Binding="{Binding ElementName=History, Path=Visibility}" Value="Collapsed" />
|
||||||
<Condition Binding="{Binding ElementName=ResultListBox, Path=Items.Count}" Value="0" />
|
<Condition Binding="{Binding ElementName=ResultListBox, Path=Items.Count}" Value="0" />
|
||||||
</MultiDataTrigger.Conditions>
|
</MultiDataTrigger.Conditions>
|
||||||
<MultiDataTrigger.Setters>
|
<MultiDataTrigger.Setters>
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,8 @@ namespace Flow.Launcher.ViewModel
|
||||||
private ChannelWriter<ResultsForUpdate> _resultsUpdateChannelWriter;
|
private ChannelWriter<ResultsForUpdate> _resultsUpdateChannelWriter;
|
||||||
private Task _resultsViewUpdateTask;
|
private Task _resultsViewUpdateTask;
|
||||||
|
|
||||||
|
private readonly IReadOnlyList<Result> _emptyResult = new List<Result>();
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Constructor
|
#region Constructor
|
||||||
|
|
@ -162,7 +164,21 @@ namespace Flow.Launcher.ViewModel
|
||||||
switch (args.PropertyName)
|
switch (args.PropertyName)
|
||||||
{
|
{
|
||||||
case nameof(Results.SelectedItem):
|
case nameof(Results.SelectedItem):
|
||||||
UpdatePreview();
|
_selectedItemFromQueryResults = true;
|
||||||
|
PreviewSelectedItem = Results.SelectedItem;
|
||||||
|
_ = UpdatePreviewAsync();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
History.PropertyChanged += (_, args) =>
|
||||||
|
{
|
||||||
|
switch (args.PropertyName)
|
||||||
|
{
|
||||||
|
case nameof(History.SelectedItem):
|
||||||
|
_selectedItemFromQueryResults = false;
|
||||||
|
PreviewSelectedItem = History.SelectedItem;
|
||||||
|
_ = UpdatePreviewAsync();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -265,7 +281,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
private void LoadHistory()
|
private void LoadHistory()
|
||||||
{
|
{
|
||||||
if (SelectedIsFromQueryResults())
|
if (QueryResultsSelected())
|
||||||
{
|
{
|
||||||
SelectedResults = History;
|
SelectedResults = History;
|
||||||
History.SelectedIndex = _history.Items.Count - 1;
|
History.SelectedIndex = _history.Items.Count - 1;
|
||||||
|
|
@ -279,7 +295,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
public void ReQuery()
|
public void ReQuery()
|
||||||
{
|
{
|
||||||
if (SelectedIsFromQueryResults())
|
if (QueryResultsSelected())
|
||||||
{
|
{
|
||||||
_ = QueryResultsAsync(isReQuery: true);
|
_ = QueryResultsAsync(isReQuery: true);
|
||||||
}
|
}
|
||||||
|
|
@ -320,7 +336,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
private void LoadContextMenu()
|
private void LoadContextMenu()
|
||||||
{
|
{
|
||||||
if (SelectedIsFromQueryResults())
|
if (QueryResultsSelected())
|
||||||
{
|
{
|
||||||
// When switch to ContextMenu from QueryResults, but no item being chosen, should do nothing
|
// When switch to ContextMenu from QueryResults, but no item being chosen, should do nothing
|
||||||
// i.e. Shift+Enter/Ctrl+O right after Alt + Space should do nothing
|
// i.e. Shift+Enter/Ctrl+O right after Alt + Space should do nothing
|
||||||
|
|
@ -350,7 +366,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
private void AutocompleteQuery()
|
private void AutocompleteQuery()
|
||||||
{
|
{
|
||||||
var result = SelectedResults.SelectedItem?.Result;
|
var result = SelectedResults.SelectedItem?.Result;
|
||||||
if (result != null && SelectedIsFromQueryResults()) // SelectedItem returns null if selection is empty.
|
if (result != null && QueryResultsSelected()) // SelectedItem returns null if selection is empty.
|
||||||
{
|
{
|
||||||
var autoCompleteText = result.Title;
|
var autoCompleteText = result.Title;
|
||||||
|
|
||||||
|
|
@ -402,7 +418,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
})
|
})
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
if (SelectedIsFromQueryResults())
|
if (QueryResultsSelected())
|
||||||
{
|
{
|
||||||
_userSelectedRecord.Add(result);
|
_userSelectedRecord.Add(result);
|
||||||
// origin query is null when user select the context menu item directly of one item from query list
|
// origin query is null when user select the context menu item directly of one item from query list
|
||||||
|
|
@ -481,7 +497,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
{
|
{
|
||||||
if (_history.Items.Count > 0
|
if (_history.Items.Count > 0
|
||||||
&& QueryText == string.Empty
|
&& QueryText == string.Empty
|
||||||
&& SelectedIsFromQueryResults())
|
&& QueryResultsSelected())
|
||||||
{
|
{
|
||||||
lastHistoryIndex = 1;
|
lastHistoryIndex = 1;
|
||||||
ReverseHistory();
|
ReverseHistory();
|
||||||
|
|
@ -501,7 +517,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
private void Esc()
|
private void Esc()
|
||||||
{
|
{
|
||||||
if (!SelectedIsFromQueryResults())
|
if (!QueryResultsSelected())
|
||||||
{
|
{
|
||||||
SelectedResults = Results;
|
SelectedResults = Results;
|
||||||
}
|
}
|
||||||
|
|
@ -513,7 +529,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
|
|
||||||
public void BackToQueryResults()
|
public void BackToQueryResults()
|
||||||
{
|
{
|
||||||
if (!SelectedIsFromQueryResults())
|
if (!QueryResultsSelected())
|
||||||
{
|
{
|
||||||
SelectedResults = Results;
|
SelectedResults = Results;
|
||||||
}
|
}
|
||||||
|
|
@ -644,13 +660,16 @@ namespace Flow.Launcher.ViewModel
|
||||||
|
|
||||||
private ResultsViewModel SelectedResults
|
private ResultsViewModel SelectedResults
|
||||||
{
|
{
|
||||||
get { return _selectedResults; }
|
get => _selectedResults;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
|
var isReturningFromQueryResults = QueryResultsSelected();
|
||||||
var isReturningFromContextMenu = ContextMenuSelected();
|
var isReturningFromContextMenu = ContextMenuSelected();
|
||||||
|
var isReturningFromHistory = HistorySelected();
|
||||||
_selectedResults = value;
|
_selectedResults = value;
|
||||||
if (SelectedIsFromQueryResults())
|
if (QueryResultsSelected())
|
||||||
{
|
{
|
||||||
|
Results.Visibility = Visibility.Visible;
|
||||||
ContextMenu.Visibility = Visibility.Collapsed;
|
ContextMenu.Visibility = Visibility.Collapsed;
|
||||||
History.Visibility = Visibility.Collapsed;
|
History.Visibility = Visibility.Collapsed;
|
||||||
|
|
||||||
|
|
@ -668,10 +687,27 @@ namespace Flow.Launcher.ViewModel
|
||||||
{
|
{
|
||||||
ChangeQueryText(_queryTextBeforeLeaveResults);
|
ChangeQueryText(_queryTextBeforeLeaveResults);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we are returning from history and we have not set select item yet,
|
||||||
|
// we need to clear the preview selected item
|
||||||
|
if (isReturningFromHistory && _selectedItemFromQueryResults.HasValue && (!_selectedItemFromQueryResults.Value))
|
||||||
|
{
|
||||||
|
PreviewSelectedItem = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Results.Visibility = Visibility.Collapsed;
|
Results.Visibility = Visibility.Collapsed;
|
||||||
|
if (HistorySelected())
|
||||||
|
{
|
||||||
|
ContextMenu.Visibility = Visibility.Collapsed;
|
||||||
|
History.Visibility = Visibility.Visible;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ContextMenu.Visibility = Visibility.Visible;
|
||||||
|
History.Visibility = Visibility.Collapsed;
|
||||||
|
}
|
||||||
_queryTextBeforeLeaveResults = QueryText;
|
_queryTextBeforeLeaveResults = QueryText;
|
||||||
|
|
||||||
// Because of Fody's optimization
|
// Because of Fody's optimization
|
||||||
|
|
@ -686,6 +722,16 @@ namespace Flow.Launcher.ViewModel
|
||||||
{
|
{
|
||||||
QueryText = string.Empty;
|
QueryText = string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (HistorySelected())
|
||||||
|
{
|
||||||
|
// If we are returning from query results and we have not set select item yet,
|
||||||
|
// we need to clear the preview selected item
|
||||||
|
if (isReturningFromQueryResults && _selectedItemFromQueryResults.HasValue && _selectedItemFromQueryResults.Value)
|
||||||
|
{
|
||||||
|
PreviewSelectedItem = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_selectedResults.Visibility = Visibility.Visible;
|
_selectedResults.Visibility = Visibility.Visible;
|
||||||
|
|
@ -785,6 +831,22 @@ namespace Flow.Launcher.ViewModel
|
||||||
|
|
||||||
#region Preview
|
#region Preview
|
||||||
|
|
||||||
|
private static readonly int ResultAreaColumnPreviewShown = 1;
|
||||||
|
private static readonly int ResultAreaColumnPreviewHidden = 3;
|
||||||
|
|
||||||
|
private bool? _selectedItemFromQueryResults;
|
||||||
|
|
||||||
|
private ResultViewModel _previewSelectedItem;
|
||||||
|
public ResultViewModel PreviewSelectedItem
|
||||||
|
{
|
||||||
|
get => _previewSelectedItem;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_previewSelectedItem = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public bool InternalPreviewVisible
|
public bool InternalPreviewVisible
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|
@ -803,18 +865,14 @@ namespace Flow.Launcher.ViewModel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly int ResultAreaColumnPreviewShown = 1;
|
|
||||||
|
|
||||||
private static readonly int ResultAreaColumnPreviewHidden = 3;
|
|
||||||
|
|
||||||
public int ResultAreaColumn { get; set; } = ResultAreaColumnPreviewShown;
|
public int ResultAreaColumn { get; set; } = ResultAreaColumnPreviewShown;
|
||||||
|
|
||||||
// This is not a reliable indicator of whether external preview is visible due to the
|
// This is not a reliable indicator of whether external preview is visible due to the
|
||||||
// ability of manually closing/exiting the external preview program which, does not inform flow that
|
// ability of manually closing/exiting the external preview program which, does not inform flow that
|
||||||
// preview is no longer available.
|
// preview is no longer available.
|
||||||
public bool ExternalPreviewVisible { get; set; } = false;
|
public bool ExternalPreviewVisible { get; private set; }
|
||||||
|
|
||||||
private void ShowPreview()
|
private async Task ShowPreviewAsync()
|
||||||
{
|
{
|
||||||
var useExternalPreview = PluginManager.UseExternalPreview();
|
var useExternalPreview = PluginManager.UseExternalPreview();
|
||||||
|
|
||||||
|
|
@ -825,13 +883,15 @@ namespace Flow.Launcher.ViewModel
|
||||||
// Internal preview may still be on when user switches to external
|
// Internal preview may still be on when user switches to external
|
||||||
if (InternalPreviewVisible)
|
if (InternalPreviewVisible)
|
||||||
HideInternalPreview();
|
HideInternalPreview();
|
||||||
OpenExternalPreview(path);
|
|
||||||
|
_ = OpenExternalPreviewAsync(path);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case true
|
case true
|
||||||
when !CanExternalPreviewSelectedResult(out var _):
|
when !CanExternalPreviewSelectedResult(out var _):
|
||||||
if (ExternalPreviewVisible)
|
if (ExternalPreviewVisible)
|
||||||
CloseExternalPreview();
|
await CloseExternalPreviewAsync();
|
||||||
|
|
||||||
ShowInternalPreview();
|
ShowInternalPreview();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -844,7 +904,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
private void HidePreview()
|
private void HidePreview()
|
||||||
{
|
{
|
||||||
if (PluginManager.UseExternalPreview())
|
if (PluginManager.UseExternalPreview())
|
||||||
CloseExternalPreview();
|
_ = CloseExternalPreviewAsync();
|
||||||
|
|
||||||
if (InternalPreviewVisible)
|
if (InternalPreviewVisible)
|
||||||
HideInternalPreview();
|
HideInternalPreview();
|
||||||
|
|
@ -859,31 +919,31 @@ namespace Flow.Launcher.ViewModel
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ShowPreview();
|
_ = ShowPreviewAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OpenExternalPreview(string path, bool sendFailToast = true)
|
private async Task OpenExternalPreviewAsync(string path, bool sendFailToast = true)
|
||||||
{
|
{
|
||||||
_ = PluginManager.OpenExternalPreviewAsync(path, sendFailToast).ConfigureAwait(false);
|
await PluginManager.OpenExternalPreviewAsync(path, sendFailToast).ConfigureAwait(false);
|
||||||
ExternalPreviewVisible = true;
|
ExternalPreviewVisible = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CloseExternalPreview()
|
private async Task CloseExternalPreviewAsync()
|
||||||
{
|
{
|
||||||
_ = PluginManager.CloseExternalPreviewAsync().ConfigureAwait(false);
|
await PluginManager.CloseExternalPreviewAsync().ConfigureAwait(false);
|
||||||
ExternalPreviewVisible = false;
|
ExternalPreviewVisible = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void SwitchExternalPreview(string path, bool sendFailToast = true)
|
private static async Task SwitchExternalPreviewAsync(string path, bool sendFailToast = true)
|
||||||
{
|
{
|
||||||
_ = PluginManager.SwitchExternalPreviewAsync(path,sendFailToast).ConfigureAwait(false);
|
await PluginManager.SwitchExternalPreviewAsync(path, sendFailToast).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ShowInternalPreview()
|
private void ShowInternalPreview()
|
||||||
{
|
{
|
||||||
ResultAreaColumn = ResultAreaColumnPreviewShown;
|
ResultAreaColumn = ResultAreaColumnPreviewShown;
|
||||||
Results.SelectedItem?.LoadPreviewImage();
|
PreviewSelectedItem?.LoadPreviewImage();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HideInternalPreview()
|
private void HideInternalPreview()
|
||||||
|
|
@ -897,20 +957,18 @@ namespace Flow.Launcher.ViewModel
|
||||||
{
|
{
|
||||||
case true
|
case true
|
||||||
when PluginManager.AllowAlwaysPreview() && CanExternalPreviewSelectedResult(out var path):
|
when PluginManager.AllowAlwaysPreview() && CanExternalPreviewSelectedResult(out var path):
|
||||||
OpenExternalPreview(path);
|
_ = OpenExternalPreviewAsync(path);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case true:
|
case true:
|
||||||
ShowInternalPreview();
|
ShowInternalPreview();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case false:
|
case false:
|
||||||
HidePreview();
|
HidePreview();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdatePreview()
|
private async Task UpdatePreviewAsync()
|
||||||
{
|
{
|
||||||
switch (PluginManager.UseExternalPreview())
|
switch (PluginManager.UseExternalPreview())
|
||||||
{
|
{
|
||||||
|
|
@ -918,44 +976,48 @@ namespace Flow.Launcher.ViewModel
|
||||||
when CanExternalPreviewSelectedResult(out var path):
|
when CanExternalPreviewSelectedResult(out var path):
|
||||||
if (ExternalPreviewVisible)
|
if (ExternalPreviewVisible)
|
||||||
{
|
{
|
||||||
SwitchExternalPreview(path, false);
|
_ = SwitchExternalPreviewAsync(path, false);
|
||||||
}
|
}
|
||||||
else if (InternalPreviewVisible)
|
else if (InternalPreviewVisible)
|
||||||
{
|
{
|
||||||
HideInternalPreview();
|
HideInternalPreview();
|
||||||
OpenExternalPreview(path);
|
_ = OpenExternalPreviewAsync(path);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case true
|
case true
|
||||||
when !CanExternalPreviewSelectedResult(out var _):
|
when !CanExternalPreviewSelectedResult(out var _):
|
||||||
if (ExternalPreviewVisible)
|
if (ExternalPreviewVisible)
|
||||||
{
|
{
|
||||||
CloseExternalPreview();
|
await CloseExternalPreviewAsync();
|
||||||
ShowInternalPreview();
|
ShowInternalPreview();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case false
|
case false
|
||||||
when InternalPreviewVisible:
|
when InternalPreviewVisible:
|
||||||
Results.SelectedItem?.LoadPreviewImage();
|
PreviewSelectedItem?.LoadPreviewImage();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool CanExternalPreviewSelectedResult(out string path)
|
private bool CanExternalPreviewSelectedResult(out string path)
|
||||||
{
|
{
|
||||||
path = Results.SelectedItem?.Result?.Preview.FilePath;
|
path = QueryResultsPreviewed() ? Results.SelectedItem?.Result?.Preview.FilePath : string.Empty;
|
||||||
return !string.IsNullOrEmpty(path);
|
return !string.IsNullOrEmpty(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool QueryResultsPreviewed()
|
||||||
|
{
|
||||||
|
var previewed = PreviewSelectedItem == Results.SelectedItem;
|
||||||
|
return previewed;
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Query
|
#region Query
|
||||||
|
|
||||||
public void Query(bool isReQuery = false)
|
private void Query(bool isReQuery = false)
|
||||||
{
|
{
|
||||||
if (SelectedIsFromQueryResults())
|
if (QueryResultsSelected())
|
||||||
{
|
{
|
||||||
_ = QueryResultsAsync(isReQuery);
|
_ = QueryResultsAsync(isReQuery);
|
||||||
}
|
}
|
||||||
|
|
@ -1027,6 +1089,11 @@ namespace Flow.Launcher.ViewModel
|
||||||
Title = string.Format(title, h.Query),
|
Title = string.Format(title, h.Query),
|
||||||
SubTitle = string.Format(time, h.ExecutedDateTime),
|
SubTitle = string.Format(time, h.ExecutedDateTime),
|
||||||
IcoPath = "Images\\history.png",
|
IcoPath = "Images\\history.png",
|
||||||
|
Preview = new Result.PreviewInfo
|
||||||
|
{
|
||||||
|
PreviewImagePath = Constant.HistoryIcon,
|
||||||
|
Description = string.Format(time, h.ExecutedDateTime)
|
||||||
|
},
|
||||||
OriginQuery = new Query { RawQuery = h.Query },
|
OriginQuery = new Query { RawQuery = h.Query },
|
||||||
Action = _ =>
|
Action = _ =>
|
||||||
{
|
{
|
||||||
|
|
@ -1053,8 +1120,6 @@ namespace Flow.Launcher.ViewModel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly IReadOnlyList<Result> _emptyResult = new List<Result>();
|
|
||||||
|
|
||||||
private async Task QueryResultsAsync(bool isReQuery = false, bool reSelect = true)
|
private async Task QueryResultsAsync(bool isReQuery = false, bool reSelect = true)
|
||||||
{
|
{
|
||||||
_updateSource?.Cancel();
|
_updateSource?.Cancel();
|
||||||
|
|
@ -1318,7 +1383,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
return menu;
|
return menu;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal bool SelectedIsFromQueryResults()
|
internal bool QueryResultsSelected()
|
||||||
{
|
{
|
||||||
var selected = SelectedResults == Results;
|
var selected = SelectedResults == Results;
|
||||||
return selected;
|
return selected;
|
||||||
|
|
@ -1352,6 +1417,18 @@ namespace Flow.Launcher.ViewModel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if Flow Launcher should ignore any hotkeys
|
||||||
|
/// </summary>
|
||||||
|
public bool ShouldIgnoreHotkeys()
|
||||||
|
{
|
||||||
|
return Settings.IgnoreHotkeysOnFullscreen && Win32Helper.IsForegroundWindowFullscreen() || GameModeStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Public Methods
|
||||||
|
|
||||||
public void Show()
|
public void Show()
|
||||||
{
|
{
|
||||||
Application.Current.Dispatcher.Invoke(() =>
|
Application.Current.Dispatcher.Invoke(() =>
|
||||||
|
|
@ -1388,10 +1465,10 @@ namespace Flow.Launcher.ViewModel
|
||||||
|
|
||||||
if (ExternalPreviewVisible)
|
if (ExternalPreviewVisible)
|
||||||
{
|
{
|
||||||
CloseExternalPreview();
|
await CloseExternalPreviewAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!SelectedIsFromQueryResults())
|
if (!QueryResultsSelected())
|
||||||
{
|
{
|
||||||
SelectedResults = Results;
|
SelectedResults = Results;
|
||||||
}
|
}
|
||||||
|
|
@ -1401,10 +1478,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
{
|
{
|
||||||
ChangeQueryText(string.Empty);
|
ChangeQueryText(string.Empty);
|
||||||
await Task.Delay(1); // Wait for one frame to ensure UI reflects changes
|
await Task.Delay(1); // Wait for one frame to ensure UI reflects changes
|
||||||
Application.Current.Dispatcher.Invoke(() =>
|
Application.Current.Dispatcher.Invoke(Application.Current.MainWindow.UpdateLayout); // Force UI update
|
||||||
{
|
|
||||||
Application.Current.MainWindow.UpdateLayout(); // Force UI update
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (Settings.LastQueryMode)
|
switch (Settings.LastQueryMode)
|
||||||
|
|
@ -1463,17 +1537,8 @@ namespace Flow.Launcher.ViewModel
|
||||||
#pragma warning restore VSTHRD100 // Avoid async void methods
|
#pragma warning restore VSTHRD100 // Avoid async void methods
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks if Flow Launcher should ignore any hotkeys
|
/// Save history, user selected records and top most records
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool ShouldIgnoreHotkeys()
|
|
||||||
{
|
|
||||||
return Settings.IgnoreHotkeysOnFullscreen && Win32Helper.IsForegroundWindowFullscreen() || GameModeStatus;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Public Methods
|
|
||||||
|
|
||||||
public void Save()
|
public void Save()
|
||||||
{
|
{
|
||||||
_historyItemsStorage.Save();
|
_historyItemsStorage.Save();
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing.Text;
|
||||||
|
using System.IO;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
|
|
@ -6,25 +9,20 @@ using Flow.Launcher.Infrastructure.Image;
|
||||||
using Flow.Launcher.Infrastructure.Logger;
|
using Flow.Launcher.Infrastructure.Logger;
|
||||||
using Flow.Launcher.Infrastructure.UserSettings;
|
using Flow.Launcher.Infrastructure.UserSettings;
|
||||||
using Flow.Launcher.Plugin;
|
using Flow.Launcher.Plugin;
|
||||||
using System.IO;
|
|
||||||
using System.Drawing.Text;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Flow.Launcher.ViewModel
|
namespace Flow.Launcher.ViewModel
|
||||||
{
|
{
|
||||||
public class ResultViewModel : BaseModel
|
public class ResultViewModel : BaseModel
|
||||||
{
|
{
|
||||||
private static PrivateFontCollection fontCollection = new();
|
private static readonly PrivateFontCollection FontCollection = new();
|
||||||
private static Dictionary<string, string> fonts = new();
|
private static readonly Dictionary<string, string> Fonts = new();
|
||||||
|
|
||||||
public ResultViewModel(Result result, Settings settings)
|
public ResultViewModel(Result result, Settings settings)
|
||||||
{
|
{
|
||||||
Settings = settings;
|
Settings = settings;
|
||||||
|
|
||||||
if (result == null)
|
if (result == null) return;
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Result = result;
|
Result = result;
|
||||||
|
|
||||||
if (Result.Glyph is { FontFamily: not null } glyph)
|
if (Result.Glyph is { FontFamily: not null } glyph)
|
||||||
|
|
@ -39,20 +37,20 @@ namespace Flow.Launcher.ViewModel
|
||||||
fontFamilyPath = Path.Combine(Result.PluginDirectory, fontFamilyPath);
|
fontFamilyPath = Path.Combine(Result.PluginDirectory, fontFamilyPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fonts.ContainsKey(fontFamilyPath))
|
if (Fonts.TryGetValue(fontFamilyPath, out var value))
|
||||||
{
|
{
|
||||||
Glyph = glyph with
|
Glyph = glyph with
|
||||||
{
|
{
|
||||||
FontFamily = fonts[fontFamilyPath]
|
FontFamily = value
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fontCollection.AddFontFile(fontFamilyPath);
|
FontCollection.AddFontFile(fontFamilyPath);
|
||||||
fonts[fontFamilyPath] = $"{Path.GetDirectoryName(fontFamilyPath)}/#{fontCollection.Families[^1].Name}";
|
Fonts[fontFamilyPath] = $"{Path.GetDirectoryName(fontFamilyPath)}/#{FontCollection.Families[^1].Name}";
|
||||||
Glyph = glyph with
|
Glyph = glyph with
|
||||||
{
|
{
|
||||||
FontFamily = fonts[fontFamilyPath]
|
FontFamily = Fonts[fontFamilyPath]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -61,7 +59,6 @@ namespace Flow.Launcher.ViewModel
|
||||||
Glyph = glyph;
|
Glyph = glyph;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Settings Settings { get; }
|
public Settings Settings { get; }
|
||||||
|
|
@ -95,14 +92,10 @@ namespace Flow.Launcher.ViewModel
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (PreviewImageAvailable)
|
if (PreviewImageAvailable)
|
||||||
{
|
|
||||||
return Visibility.Visible;
|
return Visibility.Visible;
|
||||||
}
|
|
||||||
else
|
// Fall back to icon
|
||||||
{
|
return ShowIcon;
|
||||||
// Fall back to icon
|
|
||||||
return ShowIcon;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -111,9 +104,8 @@ namespace Flow.Launcher.ViewModel
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (Result.RoundedIcon)
|
if (Result.RoundedIcon)
|
||||||
{
|
|
||||||
return IconXY / 2;
|
return IconXY / 2;
|
||||||
}
|
|
||||||
return IconXY;
|
return IconXY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -148,31 +140,40 @@ namespace Flow.Launcher.ViewModel
|
||||||
? Result.SubTitle
|
? Result.SubTitle
|
||||||
: Result.SubTitleToolTip;
|
: Result.SubTitleToolTip;
|
||||||
|
|
||||||
private volatile bool ImageLoaded;
|
private volatile bool _imageLoaded;
|
||||||
private volatile bool PreviewImageLoaded;
|
private volatile bool _previewImageLoaded;
|
||||||
|
|
||||||
private ImageSource image = ImageLoader.LoadingImage;
|
private ImageSource _image = ImageLoader.LoadingImage;
|
||||||
private ImageSource previewImage = ImageLoader.LoadingImage;
|
private ImageSource _previewImage = ImageLoader.LoadingImage;
|
||||||
|
|
||||||
public ImageSource Image
|
public ImageSource Image
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (!ImageLoaded)
|
if (!_imageLoaded)
|
||||||
{
|
{
|
||||||
ImageLoaded = true;
|
_imageLoaded = true;
|
||||||
_ = LoadImageAsync();
|
_ = LoadImageAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
return image;
|
return _image;
|
||||||
}
|
}
|
||||||
private set => image = value;
|
private set => _image = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ImageSource PreviewImage
|
public ImageSource PreviewImage
|
||||||
{
|
{
|
||||||
get => previewImage;
|
get
|
||||||
private set => previewImage = value;
|
{
|
||||||
|
if (!_previewImageLoaded)
|
||||||
|
{
|
||||||
|
_previewImageLoaded = true;
|
||||||
|
_ = LoadPreviewImageAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
return _previewImage;
|
||||||
|
}
|
||||||
|
private set => _previewImage = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -188,8 +189,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var image = icon();
|
return icon();
|
||||||
return image;
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
|
@ -208,7 +208,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
var iconDelegate = Result.Icon;
|
var iconDelegate = Result.Icon;
|
||||||
if (ImageLoader.TryGetValue(imagePath, false, out ImageSource img))
|
if (ImageLoader.TryGetValue(imagePath, false, out ImageSource img))
|
||||||
{
|
{
|
||||||
image = img;
|
_image = img;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -223,7 +223,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
var iconDelegate = Result.Preview.PreviewDelegate ?? Result.Icon;
|
var iconDelegate = Result.Preview.PreviewDelegate ?? Result.Icon;
|
||||||
if (ImageLoader.TryGetValue(imagePath, true, out ImageSource img))
|
if (ImageLoader.TryGetValue(imagePath, true, out ImageSource img))
|
||||||
{
|
{
|
||||||
previewImage = img;
|
_previewImage = img;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -234,13 +234,10 @@ namespace Flow.Launcher.ViewModel
|
||||||
|
|
||||||
public void LoadPreviewImage()
|
public void LoadPreviewImage()
|
||||||
{
|
{
|
||||||
if (ShowDefaultPreview == Visibility.Visible)
|
if (ShowDefaultPreview == Visibility.Visible && !_previewImageLoaded && ShowPreviewImage == Visibility.Visible)
|
||||||
{
|
{
|
||||||
if (!PreviewImageLoaded && ShowPreviewImage == Visibility.Visible)
|
_previewImageLoaded = true;
|
||||||
{
|
_ = LoadPreviewImageAsync();
|
||||||
PreviewImageLoaded = true;
|
|
||||||
_ = LoadPreviewImageAsync();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,4 @@
|
||||||
using System;
|
using System;
|
||||||
using Flow.Launcher.Infrastructure.UserSettings;
|
|
||||||
using Flow.Launcher.Plugin;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Specialized;
|
using System.Collections.Specialized;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
@ -10,6 +8,8 @@ using System.Windows.Controls;
|
||||||
using System.Windows.Data;
|
using System.Windows.Data;
|
||||||
using System.Windows.Documents;
|
using System.Windows.Documents;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
|
using Flow.Launcher.Infrastructure.UserSettings;
|
||||||
|
using Flow.Launcher.Plugin;
|
||||||
|
|
||||||
namespace Flow.Launcher.ViewModel
|
namespace Flow.Launcher.ViewModel
|
||||||
{
|
{
|
||||||
|
|
@ -28,6 +28,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
Results = new ResultCollection();
|
Results = new ResultCollection();
|
||||||
BindingOperations.EnableCollectionSynchronization(Results, _collectionLock);
|
BindingOperations.EnableCollectionSynchronization(Results, _collectionLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResultsViewModel(Settings settings) : this()
|
public ResultsViewModel(Settings settings) : this()
|
||||||
{
|
{
|
||||||
_settings = settings;
|
_settings = settings;
|
||||||
|
|
@ -219,7 +220,6 @@ namespace Flow.Launcher.ViewModel
|
||||||
if (newRawResults.Count == 0)
|
if (newRawResults.Count == 0)
|
||||||
return Results;
|
return Results;
|
||||||
|
|
||||||
|
|
||||||
var newResults = newRawResults.Select(r => new ResultViewModel(r, _settings));
|
var newResults = newRawResults.Select(r => new ResultViewModel(r, _settings));
|
||||||
|
|
||||||
return Results.Where(r => r.Result.PluginID != resultId)
|
return Results.Where(r => r.Result.PluginID != resultId)
|
||||||
|
|
@ -241,6 +241,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region FormattedText Dependency Property
|
#region FormattedText Dependency Property
|
||||||
|
|
||||||
public static readonly DependencyProperty FormattedTextProperty = DependencyProperty.RegisterAttached(
|
public static readonly DependencyProperty FormattedTextProperty = DependencyProperty.RegisterAttached(
|
||||||
"FormattedText",
|
"FormattedText",
|
||||||
typeof(Inline),
|
typeof(Inline),
|
||||||
|
|
@ -259,8 +260,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
|
|
||||||
private static void FormattedTextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
private static void FormattedTextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||||
{
|
{
|
||||||
var textBlock = d as TextBlock;
|
if (d is not TextBlock textBlock) return;
|
||||||
if (textBlock == null) return;
|
|
||||||
|
|
||||||
var inline = (Inline)e.NewValue;
|
var inline = (Inline)e.NewValue;
|
||||||
|
|
||||||
|
|
@ -269,6 +269,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
|
|
||||||
textBlock.Inlines.Add(inline);
|
textBlock.Inlines.Add(inline);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
public class ResultCollection : List<ResultViewModel>, INotifyCollectionChanged
|
public class ResultCollection : List<ResultViewModel>, INotifyCollectionChanged
|
||||||
|
|
@ -279,7 +280,6 @@ namespace Flow.Launcher.ViewModel
|
||||||
|
|
||||||
public event NotifyCollectionChangedEventHandler CollectionChanged;
|
public event NotifyCollectionChangedEventHandler CollectionChanged;
|
||||||
|
|
||||||
|
|
||||||
protected void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
|
protected void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
|
||||||
{
|
{
|
||||||
CollectionChanged?.Invoke(this, e);
|
CollectionChanged?.Invoke(this, e);
|
||||||
|
|
@ -297,6 +297,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
// wpf use DirectX / double buffered already, so just reset all won't cause ui flickering
|
// wpf use DirectX / double buffered already, so just reset all won't cause ui flickering
|
||||||
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
|
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddAll(List<ResultViewModel> Items)
|
private void AddAll(List<ResultViewModel> Items)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < Items.Count; i++)
|
for (int i = 0; i < Items.Count; i++)
|
||||||
|
|
@ -308,6 +309,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, i));
|
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveAll(int Capacity = 512)
|
public void RemoveAll(int Capacity = 512)
|
||||||
{
|
{
|
||||||
Clear();
|
Clear();
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue