mirror of
https://github.com/Flow-Launcher/Flow.Launcher.git
synced 2026-03-11 08:54:32 +00:00
Merge pull request #3631 from Flow-Launcher/file_tooltip
Support More Information for Files, Folders and Volumes Tooltips & Add Custom Preview Panel Support for Folder Results
This commit is contained in:
commit
d04f493e57
7 changed files with 330 additions and 50 deletions
|
|
@ -46,6 +46,7 @@
|
||||||
<system:String x:Key="plugin_explorer_shell_path">Shell Path</system:String>
|
<system:String x:Key="plugin_explorer_shell_path">Shell Path</system:String>
|
||||||
<system:String x:Key="plugin_explorer_indexsearchexcludedpaths_header">Index Search Excluded Paths</system:String>
|
<system:String x:Key="plugin_explorer_indexsearchexcludedpaths_header">Index Search Excluded Paths</system:String>
|
||||||
<system:String x:Key="plugin_explorer_use_location_as_working_dir">Use search result's location as the working directory of the executable</system:String>
|
<system:String x:Key="plugin_explorer_use_location_as_working_dir">Use search result's location as the working directory of the executable</system:String>
|
||||||
|
<system:String x:Key="plugin_explorer_display_more_info_in_tooltip">Display more information like size and age in tooltips</system:String>
|
||||||
<system:String x:Key="plugin_explorer_default_open_in_file_manager">Hit Enter to open folder in Default File Manager</system:String>
|
<system:String x:Key="plugin_explorer_default_open_in_file_manager">Hit Enter to open folder in Default File Manager</system:String>
|
||||||
<system:String x:Key="plugin_explorer_usewindowsindexfordirectorysearch">Use Index Search For Path Search</system:String>
|
<system:String x:Key="plugin_explorer_usewindowsindexfordirectorysearch">Use Index Search For Path Search</system:String>
|
||||||
<system:String x:Key="plugin_explorer_manageindexoptions">Indexing Options</system:String>
|
<system:String x:Key="plugin_explorer_manageindexoptions">Indexing Options</system:String>
|
||||||
|
|
@ -82,6 +83,9 @@
|
||||||
<!-- Plugin Tooltip -->
|
<!-- Plugin Tooltip -->
|
||||||
<system:String x:Key="plugin_explorer_plugin_ToolTipOpenDirectory">Ctrl + Enter to open the directory</system:String>
|
<system:String x:Key="plugin_explorer_plugin_ToolTipOpenDirectory">Ctrl + Enter to open the directory</system:String>
|
||||||
<system:String x:Key="plugin_explorer_plugin_ToolTipOpenContainingFolder">Ctrl + Enter to open the containing folder</system:String>
|
<system:String x:Key="plugin_explorer_plugin_ToolTipOpenContainingFolder">Ctrl + Enter to open the containing folder</system:String>
|
||||||
|
<system:String x:Key="plugin_explorer_plugin_tooltip_more_info">{0}{4}Size: {1}{4}Date created: {2}{4}Date modified: {3}</system:String>
|
||||||
|
<system:String x:Key="plugin_explorer_plugin_tooltip_more_info_unknown">Unknown</system:String>
|
||||||
|
<system:String x:Key="plugin_explorer_plugin_tooltip_more_info_volume">{0}{3}Space free: {1}{3}Total size: {2}</system:String>
|
||||||
|
|
||||||
<!-- Context menu items -->
|
<!-- Context menu items -->
|
||||||
<system:String x:Key="plugin_explorer_copypath">Copy path</system:String>
|
<system:String x:Key="plugin_explorer_copypath">Copy path</system:String>
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,8 @@ namespace Flow.Launcher.Plugin.Explorer.Search
|
||||||
{
|
{
|
||||||
public static class ResultManager
|
public static class ResultManager
|
||||||
{
|
{
|
||||||
|
private static readonly string ClassName = nameof(ResultManager);
|
||||||
|
|
||||||
private static readonly string[] SizeUnits = { "B", "KB", "MB", "GB", "TB" };
|
private static readonly string[] SizeUnits = { "B", "KB", "MB", "GB", "TB" };
|
||||||
private static PluginInitContext Context;
|
private static PluginInitContext Context;
|
||||||
private static Settings Settings { get; set; }
|
private static Settings Settings { get; set; }
|
||||||
|
|
@ -99,10 +101,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search
|
||||||
AutoCompleteText = GetAutoCompleteText(title, query, path, ResultType.Folder),
|
AutoCompleteText = GetAutoCompleteText(title, query, path, ResultType.Folder),
|
||||||
TitleHighlightData = Context.API.FuzzySearch(query.Search, title).MatchData,
|
TitleHighlightData = Context.API.FuzzySearch(query.Search, title).MatchData,
|
||||||
CopyText = path,
|
CopyText = path,
|
||||||
Preview = new Result.PreviewInfo
|
PreviewPanel = new Lazy<UserControl>(() => new PreviewPanel(Settings, path, ResultType.Folder)),
|
||||||
{
|
|
||||||
FilePath = path,
|
|
||||||
},
|
|
||||||
Action = c =>
|
Action = c =>
|
||||||
{
|
{
|
||||||
if (c.SpecialKeyState.ToModifierKeys() == ModifierKeys.Alt)
|
if (c.SpecialKeyState.ToModifierKeys() == ModifierKeys.Alt)
|
||||||
|
|
@ -163,7 +162,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search
|
||||||
},
|
},
|
||||||
Score = score,
|
Score = score,
|
||||||
TitleToolTip = Main.Context.API.GetTranslation("plugin_explorer_plugin_ToolTipOpenDirectory"),
|
TitleToolTip = Main.Context.API.GetTranslation("plugin_explorer_plugin_ToolTipOpenDirectory"),
|
||||||
SubTitleToolTip = path,
|
SubTitleToolTip = Settings.DisplayMoreInformationInToolTip ? GetFolderMoreInfoTooltip(path) : path,
|
||||||
ContextData = new SearchResult { Type = ResultType.Folder, FullPath = path, WindowsIndexed = windowsIndexed }
|
ContextData = new SearchResult { Type = ResultType.Folder, FullPath = path, WindowsIndexed = windowsIndexed }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -184,6 +183,10 @@ namespace Flow.Launcher.Plugin.Explorer.Search
|
||||||
if (progressValue >= 90)
|
if (progressValue >= 90)
|
||||||
progressBarColor = "#da2626";
|
progressBarColor = "#da2626";
|
||||||
|
|
||||||
|
var tooltip = Settings.DisplayMoreInformationInToolTip
|
||||||
|
? GetVolumeMoreInfoTooltip(path, freespace, totalspace)
|
||||||
|
: path;
|
||||||
|
|
||||||
return new Result
|
return new Result
|
||||||
{
|
{
|
||||||
Title = title,
|
Title = title,
|
||||||
|
|
@ -202,8 +205,8 @@ namespace Flow.Launcher.Plugin.Explorer.Search
|
||||||
OpenFolder(path);
|
OpenFolder(path);
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
TitleToolTip = path,
|
TitleToolTip = tooltip,
|
||||||
SubTitleToolTip = path,
|
SubTitleToolTip = tooltip,
|
||||||
ContextData = new SearchResult { Type = ResultType.Volume, FullPath = path, WindowsIndexed = windowsIndexed }
|
ContextData = new SearchResult { Type = ResultType.Volume, FullPath = path, WindowsIndexed = windowsIndexed }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -269,7 +272,6 @@ namespace Flow.Launcher.Plugin.Explorer.Search
|
||||||
bool isMedia = IsMedia(Path.GetExtension(filePath));
|
bool isMedia = IsMedia(Path.GetExtension(filePath));
|
||||||
var title = Path.GetFileName(filePath);
|
var title = Path.GetFileName(filePath);
|
||||||
|
|
||||||
|
|
||||||
/* Preview Detail */
|
/* Preview Detail */
|
||||||
|
|
||||||
var result = new Result
|
var result = new Result
|
||||||
|
|
@ -287,7 +289,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search
|
||||||
TitleHighlightData = Context.API.FuzzySearch(query.Search, title).MatchData,
|
TitleHighlightData = Context.API.FuzzySearch(query.Search, title).MatchData,
|
||||||
Score = score,
|
Score = score,
|
||||||
CopyText = filePath,
|
CopyText = filePath,
|
||||||
PreviewPanel = new Lazy<UserControl>(() => new PreviewPanel(Settings, filePath)),
|
PreviewPanel = new Lazy<UserControl>(() => new PreviewPanel(Settings, filePath, ResultType.File)),
|
||||||
Action = c =>
|
Action = c =>
|
||||||
{
|
{
|
||||||
if (c.SpecialKeyState.ToModifierKeys() == ModifierKeys.Alt)
|
if (c.SpecialKeyState.ToModifierKeys() == ModifierKeys.Alt)
|
||||||
|
|
@ -318,7 +320,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
TitleToolTip = Main.Context.API.GetTranslation("plugin_explorer_plugin_ToolTipOpenContainingFolder"),
|
TitleToolTip = Main.Context.API.GetTranslation("plugin_explorer_plugin_ToolTipOpenContainingFolder"),
|
||||||
SubTitleToolTip = filePath,
|
SubTitleToolTip = Settings.DisplayMoreInformationInToolTip ? GetFileMoreInfoTooltip(filePath) : filePath,
|
||||||
ContextData = new SearchResult { Type = ResultType.File, FullPath = filePath, WindowsIndexed = windowsIndexed }
|
ContextData = new SearchResult { Type = ResultType.File, FullPath = filePath, WindowsIndexed = windowsIndexed }
|
||||||
};
|
};
|
||||||
return result;
|
return result;
|
||||||
|
|
@ -349,6 +351,46 @@ namespace Flow.Launcher.Plugin.Explorer.Search
|
||||||
_ = Task.Run(() => EverythingApi.IncrementRunCounterAsync(fileOrFolder));
|
_ = Task.Run(() => EverythingApi.IncrementRunCounterAsync(fileOrFolder));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string GetFileMoreInfoTooltip(string filePath)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var fileSize = PreviewPanel.GetFileSize(filePath);
|
||||||
|
var fileCreatedAt = PreviewPanel.GetFileCreatedAt(filePath, Settings.PreviewPanelDateFormat, Settings.PreviewPanelTimeFormat, Settings.ShowFileAgeInPreviewPanel);
|
||||||
|
var fileModifiedAt = PreviewPanel.GetFileLastModifiedAt(filePath, Settings.PreviewPanelDateFormat, Settings.PreviewPanelTimeFormat, Settings.ShowFileAgeInPreviewPanel);
|
||||||
|
return string.Format(Context.API.GetTranslation("plugin_explorer_plugin_tooltip_more_info"),
|
||||||
|
filePath, fileSize, fileCreatedAt, fileModifiedAt, Environment.NewLine);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Context.API.LogException(ClassName, $"Failed to load tooltip for {filePath}", e);
|
||||||
|
return filePath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetFolderMoreInfoTooltip(string folderPath)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var folderSize = PreviewPanel.GetFolderSize(folderPath);
|
||||||
|
var folderCreatedAt = PreviewPanel.GetFolderCreatedAt(folderPath, Settings.PreviewPanelDateFormat, Settings.PreviewPanelTimeFormat, Settings.ShowFileAgeInPreviewPanel);
|
||||||
|
var folderModifiedAt = PreviewPanel.GetFolderLastModifiedAt(folderPath, Settings.PreviewPanelDateFormat, Settings.PreviewPanelTimeFormat, Settings.ShowFileAgeInPreviewPanel);
|
||||||
|
return string.Format(Context.API.GetTranslation("plugin_explorer_plugin_tooltip_more_info"),
|
||||||
|
folderPath, folderSize, folderCreatedAt, folderModifiedAt, Environment.NewLine);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Context.API.LogException(ClassName, $"Failed to load tooltip for {folderPath}", e);
|
||||||
|
return folderPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetVolumeMoreInfoTooltip(string volumePath, string freespace, string totalspace)
|
||||||
|
{
|
||||||
|
return string.Format(Context.API.GetTranslation("plugin_explorer_plugin_tooltip_more_info_volume"),
|
||||||
|
volumePath, freespace, totalspace, Environment.NewLine);
|
||||||
|
}
|
||||||
|
|
||||||
private static readonly string[] MediaExtensions = { ".jpg", ".png", ".avi", ".mkv", ".bmp", ".gif", ".wmv", ".mp3", ".flac", ".mp4" };
|
private static readonly string[] MediaExtensions = { ".jpg", ".png", ".avi", ".mkv", ".bmp", ".gif", ".wmv", ".mp3", ".flac", ".mp4" };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,8 @@ namespace Flow.Launcher.Plugin.Explorer
|
||||||
|
|
||||||
public bool DefaultOpenFolderInFileManager { get; set; } = false;
|
public bool DefaultOpenFolderInFileManager { get; set; } = false;
|
||||||
|
|
||||||
|
public bool DisplayMoreInformationInToolTip { get; set; } = false;
|
||||||
|
|
||||||
public string SearchActionKeyword { get; set; } = Query.GlobalPluginWildcardSign;
|
public string SearchActionKeyword { get; set; } = Query.GlobalPluginWildcardSign;
|
||||||
|
|
||||||
public bool SearchActionKeywordEnabled { get; set; } = true;
|
public bool SearchActionKeywordEnabled { get; set; } = true;
|
||||||
|
|
|
||||||
|
|
@ -244,6 +244,21 @@ namespace Flow.Launcher.Plugin.Explorer.ViewModels
|
||||||
"yyyy-MM-dd",
|
"yyyy-MM-dd",
|
||||||
"yyyy-MM-dd ddd",
|
"yyyy-MM-dd ddd",
|
||||||
"yyyy-MM-dd, dddd",
|
"yyyy-MM-dd, dddd",
|
||||||
|
"dd/MMM/yyyy",
|
||||||
|
"dd/MMM/yyyy ddd",
|
||||||
|
"dd/MMM/yyyy, dddd",
|
||||||
|
"dd-MMM-yyyy",
|
||||||
|
"dd-MMM-yyyy ddd",
|
||||||
|
"dd-MMM-yyyy, dddd",
|
||||||
|
"dd.MMM.yyyy",
|
||||||
|
"dd.MMM.yyyy ddd",
|
||||||
|
"dd.MMM.yyyy, dddd",
|
||||||
|
"MMM/dd/yyyy",
|
||||||
|
"MMM/dd/yyyy ddd",
|
||||||
|
"MMM/dd/yyyy, dddd",
|
||||||
|
"yyyy-MMM-dd",
|
||||||
|
"yyyy-MMM-dd ddd",
|
||||||
|
"yyyy-MMM-dd, dddd",
|
||||||
};
|
};
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
|
||||||
|
|
@ -205,6 +205,7 @@
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="Auto" />
|
<ColumnDefinition Width="Auto" />
|
||||||
|
|
@ -228,16 +229,25 @@
|
||||||
Content="{DynamicResource plugin_explorer_default_open_in_file_manager}"
|
Content="{DynamicResource plugin_explorer_default_open_in_file_manager}"
|
||||||
IsChecked="{Binding Settings.DefaultOpenFolderInFileManager}" />
|
IsChecked="{Binding Settings.DefaultOpenFolderInFileManager}" />
|
||||||
|
|
||||||
<TextBlock
|
<CheckBox
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
|
Grid.ColumnSpan="2"
|
||||||
|
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
Content="{DynamicResource plugin_explorer_display_more_info_in_tooltip}"
|
||||||
|
IsChecked="{Binding Settings.DisplayMoreInformationInToolTip}" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="3"
|
||||||
|
Grid.Column="0"
|
||||||
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Foreground="{DynamicResource Color05B}"
|
Foreground="{DynamicResource Color05B}"
|
||||||
Text="{DynamicResource plugin_explorer_file_editor_path}" />
|
Text="{DynamicResource plugin_explorer_file_editor_path}" />
|
||||||
<StackPanel
|
<StackPanel
|
||||||
Grid.Row="2"
|
Grid.Row="3"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Margin="{StaticResource SettingPanelItemLeftTopBottomMargin}"
|
Margin="{StaticResource SettingPanelItemLeftTopBottomMargin}"
|
||||||
Orientation="Horizontal">
|
Orientation="Horizontal">
|
||||||
|
|
@ -256,7 +266,7 @@
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="3"
|
Grid.Row="4"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
|
|
@ -264,7 +274,7 @@
|
||||||
Foreground="{DynamicResource Color05B}"
|
Foreground="{DynamicResource Color05B}"
|
||||||
Text="{DynamicResource plugin_explorer_folder_editor_path}" />
|
Text="{DynamicResource plugin_explorer_folder_editor_path}" />
|
||||||
<StackPanel
|
<StackPanel
|
||||||
Grid.Row="3"
|
Grid.Row="4"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Margin="{StaticResource SettingPanelItemLeftTopBottomMargin}"
|
Margin="{StaticResource SettingPanelItemLeftTopBottomMargin}"
|
||||||
Orientation="Horizontal">
|
Orientation="Horizontal">
|
||||||
|
|
@ -283,7 +293,7 @@
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="4"
|
Grid.Row="5"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
|
|
@ -291,7 +301,7 @@
|
||||||
Foreground="{DynamicResource Color05B}"
|
Foreground="{DynamicResource Color05B}"
|
||||||
Text="{DynamicResource plugin_explorer_shell_path}" />
|
Text="{DynamicResource plugin_explorer_shell_path}" />
|
||||||
<StackPanel
|
<StackPanel
|
||||||
Grid.Row="4"
|
Grid.Row="5"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Margin="{StaticResource SettingPanelItemLeftTopBottomMargin}"
|
Margin="{StaticResource SettingPanelItemLeftTopBottomMargin}"
|
||||||
Orientation="Horizontal">
|
Orientation="Horizontal">
|
||||||
|
|
@ -310,14 +320,14 @@
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="5"
|
Grid.Row="6"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Foreground="{DynamicResource Color05B}"
|
Foreground="{DynamicResource Color05B}"
|
||||||
Text="{DynamicResource plugin_explorer_Index_Search_Engine}" />
|
Text="{DynamicResource plugin_explorer_Index_Search_Engine}" />
|
||||||
<ComboBox
|
<ComboBox
|
||||||
Grid.Row="5"
|
Grid.Row="6"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Margin="{StaticResource SettingPanelItemLeftTopBottomMargin}"
|
Margin="{StaticResource SettingPanelItemLeftTopBottomMargin}"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
|
|
@ -327,14 +337,14 @@
|
||||||
SelectedItem="{Binding SelectedIndexSearchEngine}" />
|
SelectedItem="{Binding SelectedIndexSearchEngine}" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="6"
|
Grid.Row="7"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Foreground="{DynamicResource Color05B}"
|
Foreground="{DynamicResource Color05B}"
|
||||||
Text="{DynamicResource plugin_explorer_Content_Search_Engine}" />
|
Text="{DynamicResource plugin_explorer_Content_Search_Engine}" />
|
||||||
<ComboBox
|
<ComboBox
|
||||||
Grid.Row="6"
|
Grid.Row="7"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Margin="{StaticResource SettingPanelItemLeftTopBottomMargin}"
|
Margin="{StaticResource SettingPanelItemLeftTopBottomMargin}"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
|
|
@ -344,14 +354,14 @@
|
||||||
SelectedItem="{Binding SelectedContentSearchEngine}" />
|
SelectedItem="{Binding SelectedContentSearchEngine}" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="7"
|
Grid.Row="8"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Foreground="{DynamicResource Color05B}"
|
Foreground="{DynamicResource Color05B}"
|
||||||
Text="{DynamicResource plugin_explorer_Directory_Recursive_Search_Engine}" />
|
Text="{DynamicResource plugin_explorer_Directory_Recursive_Search_Engine}" />
|
||||||
<ComboBox
|
<ComboBox
|
||||||
Grid.Row="7"
|
Grid.Row="8"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Margin="{StaticResource SettingPanelItemLeftTopBottomMargin}"
|
Margin="{StaticResource SettingPanelItemLeftTopBottomMargin}"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
|
|
@ -361,14 +371,14 @@
|
||||||
SelectedItem="{Binding SelectedPathEnumerationEngine}" />
|
SelectedItem="{Binding SelectedPathEnumerationEngine}" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="8"
|
Grid.Row="9"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Foreground="{DynamicResource Color05B}"
|
Foreground="{DynamicResource Color05B}"
|
||||||
Text="{DynamicResource plugin_explorer_Excluded_File_Types}" />
|
Text="{DynamicResource plugin_explorer_Excluded_File_Types}" />
|
||||||
<TextBox
|
<TextBox
|
||||||
Grid.Row="8"
|
Grid.Row="9"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
MinWidth="{StaticResource SettingPanelTextBoxMinWidth}"
|
MinWidth="{StaticResource SettingPanelTextBoxMinWidth}"
|
||||||
Margin="{StaticResource SettingPanelItemLeftTopBottomMargin}"
|
Margin="{StaticResource SettingPanelItemLeftTopBottomMargin}"
|
||||||
|
|
@ -377,14 +387,14 @@
|
||||||
ToolTip="{DynamicResource plugin_explorer_Excluded_File_Types_Tooltip}" />
|
ToolTip="{DynamicResource plugin_explorer_Excluded_File_Types_Tooltip}" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="9"
|
Grid.Row="10"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Foreground="{DynamicResource Color05B}"
|
Foreground="{DynamicResource Color05B}"
|
||||||
Text="{DynamicResource plugin_explorer_Maximum_Results}" />
|
Text="{DynamicResource plugin_explorer_Maximum_Results}" />
|
||||||
<TextBox
|
<TextBox
|
||||||
Grid.Row="9"
|
Grid.Row="10"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
MinWidth="{StaticResource SettingPanelTextBoxMinWidth}"
|
MinWidth="{StaticResource SettingPanelTextBoxMinWidth}"
|
||||||
Margin="{StaticResource SettingPanelItemLeftTopBottomMargin}"
|
Margin="{StaticResource SettingPanelItemLeftTopBottomMargin}"
|
||||||
|
|
@ -396,7 +406,7 @@
|
||||||
ToolTip="{DynamicResource plugin_explorer_Maximum_Results_Tooltip}" />
|
ToolTip="{DynamicResource plugin_explorer_Maximum_Results_Tooltip}" />
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
Grid.Row="10"
|
Grid.Row="11"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Grid.ColumnSpan="2"
|
Grid.ColumnSpan="2"
|
||||||
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
||||||
|
|
|
||||||
|
|
@ -117,7 +117,7 @@
|
||||||
HorizontalAlignment="Right"
|
HorizontalAlignment="Right"
|
||||||
VerticalAlignment="Top"
|
VerticalAlignment="Top"
|
||||||
Style="{DynamicResource PreviewItemSubTitleStyle}"
|
Style="{DynamicResource PreviewItemSubTitleStyle}"
|
||||||
Text="{Binding FileSize, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}}"
|
Text="{Binding FileSize, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}, Mode=OneWay}"
|
||||||
TextWrapping="Wrap"
|
TextWrapping="Wrap"
|
||||||
Visibility="{Binding FileSizeVisibility, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}}" />
|
Visibility="{Binding FileSizeVisibility, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}}" />
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,9 @@
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
|
|
@ -16,8 +18,10 @@ namespace Flow.Launcher.Plugin.Explorer.Views;
|
||||||
|
|
||||||
public partial class PreviewPanel : UserControl, INotifyPropertyChanged
|
public partial class PreviewPanel : UserControl, INotifyPropertyChanged
|
||||||
{
|
{
|
||||||
|
private static readonly string ClassName = nameof(PreviewPanel);
|
||||||
|
|
||||||
private string FilePath { get; }
|
private string FilePath { get; }
|
||||||
public string FileSize { get; } = "";
|
public string FileSize { get; private set; } = Main.Context.API.GetTranslation("plugin_explorer_plugin_tooltip_more_info_unknown");
|
||||||
public string CreatedAt { get; } = "";
|
public string CreatedAt { get; } = "";
|
||||||
public string LastModifiedAt { get; } = "";
|
public string LastModifiedAt { get; } = "";
|
||||||
private ImageSource _previewImage = new BitmapImage();
|
private ImageSource _previewImage = new BitmapImage();
|
||||||
|
|
@ -50,7 +54,7 @@ public partial class PreviewPanel : UserControl, INotifyPropertyChanged
|
||||||
? Visibility.Visible
|
? Visibility.Visible
|
||||||
: Visibility.Collapsed;
|
: Visibility.Collapsed;
|
||||||
|
|
||||||
public PreviewPanel(Settings settings, string filePath)
|
public PreviewPanel(Settings settings, string filePath, ResultType type)
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
|
|
@ -60,33 +64,32 @@ public partial class PreviewPanel : UserControl, INotifyPropertyChanged
|
||||||
|
|
||||||
if (Settings.ShowFileSizeInPreviewPanel)
|
if (Settings.ShowFileSizeInPreviewPanel)
|
||||||
{
|
{
|
||||||
var fileSize = new FileInfo(filePath).Length;
|
if (type == ResultType.File)
|
||||||
FileSize = ResultManager.ToReadableSize(fileSize, 2);
|
{
|
||||||
|
FileSize = GetFileSize(filePath);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_ = Task.Run(() =>
|
||||||
|
{
|
||||||
|
FileSize = GetFolderSize(filePath);
|
||||||
|
OnPropertyChanged(nameof(FileSize));
|
||||||
|
}).ConfigureAwait(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Settings.ShowCreatedDateInPreviewPanel)
|
if (Settings.ShowCreatedDateInPreviewPanel)
|
||||||
{
|
{
|
||||||
DateTime createdDate = File.GetCreationTime(filePath);
|
CreatedAt = type == ResultType.File ?
|
||||||
string formattedDate = createdDate.ToString(
|
GetFileCreatedAt(filePath, Settings.PreviewPanelDateFormat, Settings.PreviewPanelTimeFormat, Settings.ShowFileAgeInPreviewPanel) :
|
||||||
$"{Settings.PreviewPanelDateFormat} {Settings.PreviewPanelTimeFormat}",
|
GetFolderCreatedAt(filePath, Settings.PreviewPanelDateFormat, Settings.PreviewPanelTimeFormat, Settings.ShowFileAgeInPreviewPanel);
|
||||||
CultureInfo.CurrentCulture
|
|
||||||
);
|
|
||||||
|
|
||||||
string result = formattedDate;
|
|
||||||
if (Settings.ShowFileAgeInPreviewPanel) result = $"{GetFileAge(createdDate)} - {formattedDate}";
|
|
||||||
CreatedAt = result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Settings.ShowModifiedDateInPreviewPanel)
|
if (Settings.ShowModifiedDateInPreviewPanel)
|
||||||
{
|
{
|
||||||
DateTime lastModifiedDate = File.GetLastWriteTime(filePath);
|
LastModifiedAt = type == ResultType.File ?
|
||||||
string formattedDate = lastModifiedDate.ToString(
|
GetFileLastModifiedAt(filePath, Settings.PreviewPanelDateFormat, Settings.PreviewPanelTimeFormat, Settings.ShowFileAgeInPreviewPanel) :
|
||||||
$"{Settings.PreviewPanelDateFormat} {Settings.PreviewPanelTimeFormat}",
|
GetFolderLastModifiedAt(filePath, Settings.PreviewPanelDateFormat, Settings.PreviewPanelTimeFormat, Settings.ShowFileAgeInPreviewPanel);
|
||||||
CultureInfo.CurrentCulture
|
|
||||||
);
|
|
||||||
string result = formattedDate;
|
|
||||||
if (Settings.ShowFileAgeInPreviewPanel) result = $"{GetFileAge(lastModifiedDate)} - {formattedDate}";
|
|
||||||
LastModifiedAt = result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = LoadImageAsync();
|
_ = LoadImageAsync();
|
||||||
|
|
@ -96,7 +99,211 @@ public partial class PreviewPanel : UserControl, INotifyPropertyChanged
|
||||||
{
|
{
|
||||||
PreviewImage = await Main.Context.API.LoadImageAsync(FilePath, true).ConfigureAwait(false);
|
PreviewImage = await Main.Context.API.LoadImageAsync(FilePath, true).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string GetFileSize(string filePath)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var fileInfo = new FileInfo(filePath);
|
||||||
|
return ResultManager.ToReadableSize(fileInfo.Length, 2);
|
||||||
|
}
|
||||||
|
catch (FileNotFoundException)
|
||||||
|
{
|
||||||
|
Main.Context.API.LogError(ClassName, $"File not found: {filePath}");
|
||||||
|
return Main.Context.API.GetTranslation("plugin_explorer_plugin_tooltip_more_info_unknown");
|
||||||
|
}
|
||||||
|
catch (UnauthorizedAccessException)
|
||||||
|
{
|
||||||
|
Main.Context.API.LogError(ClassName, $"Access denied to file: {filePath}");
|
||||||
|
return Main.Context.API.GetTranslation("plugin_explorer_plugin_tooltip_more_info_unknown");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Main.Context.API.LogException(ClassName, $"Failed to get file size for {filePath}", e);
|
||||||
|
return Main.Context.API.GetTranslation("plugin_explorer_plugin_tooltip_more_info_unknown");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetFileCreatedAt(string filePath, string previewPanelDateFormat, string previewPanelTimeFormat, bool showFileAgeInPreviewPanel)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var createdDate = File.GetCreationTime(filePath);
|
||||||
|
var formattedDate = createdDate.ToString(
|
||||||
|
$"{previewPanelDateFormat} {previewPanelTimeFormat}",
|
||||||
|
CultureInfo.CurrentCulture
|
||||||
|
);
|
||||||
|
|
||||||
|
var result = formattedDate;
|
||||||
|
if (showFileAgeInPreviewPanel) result = $"{GetFileAge(createdDate)} - {formattedDate}";
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (FileNotFoundException)
|
||||||
|
{
|
||||||
|
Main.Context.API.LogError(ClassName, $"File not found: {filePath}");
|
||||||
|
return Main.Context.API.GetTranslation("plugin_explorer_plugin_tooltip_more_info_unknown");
|
||||||
|
}
|
||||||
|
catch (UnauthorizedAccessException)
|
||||||
|
{
|
||||||
|
Main.Context.API.LogError(ClassName, $"Access denied to file: {filePath}");
|
||||||
|
return Main.Context.API.GetTranslation("plugin_explorer_plugin_tooltip_more_info_unknown");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Main.Context.API.LogException(ClassName, $"Failed to get file created date for {filePath}", e);
|
||||||
|
return Main.Context.API.GetTranslation("plugin_explorer_plugin_tooltip_more_info_unknown");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetFileLastModifiedAt(string filePath, string previewPanelDateFormat, string previewPanelTimeFormat, bool showFileAgeInPreviewPanel)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var lastModifiedDate = File.GetLastWriteTime(filePath);
|
||||||
|
var formattedDate = lastModifiedDate.ToString(
|
||||||
|
$"{previewPanelDateFormat} {previewPanelTimeFormat}",
|
||||||
|
CultureInfo.CurrentCulture
|
||||||
|
);
|
||||||
|
|
||||||
|
var result = formattedDate;
|
||||||
|
if (showFileAgeInPreviewPanel) result = $"{GetFileAge(lastModifiedDate)} - {formattedDate}";
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (FileNotFoundException)
|
||||||
|
{
|
||||||
|
Main.Context.API.LogError(ClassName, $"File not found: {filePath}");
|
||||||
|
return Main.Context.API.GetTranslation("plugin_explorer_plugin_tooltip_more_info_unknown");
|
||||||
|
}
|
||||||
|
catch (UnauthorizedAccessException)
|
||||||
|
{
|
||||||
|
Main.Context.API.LogError(ClassName, $"Access denied to file: {filePath}");
|
||||||
|
return Main.Context.API.GetTranslation("plugin_explorer_plugin_tooltip_more_info_unknown");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Main.Context.API.LogException(ClassName, $"Failed to get file modified date for {filePath}", e);
|
||||||
|
return Main.Context.API.GetTranslation("plugin_explorer_plugin_tooltip_more_info_unknown");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetFolderSize(string folderPath)
|
||||||
|
{
|
||||||
|
using var timeoutCts = new CancellationTokenSource(TimeSpan.FromSeconds(3));
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Use parallel enumeration for better performance
|
||||||
|
var directoryInfo = new DirectoryInfo(folderPath);
|
||||||
|
long size = directoryInfo.EnumerateFiles("*", SearchOption.AllDirectories)
|
||||||
|
.AsParallel()
|
||||||
|
.WithCancellation(timeoutCts.Token)
|
||||||
|
.Sum(file => file.Length);
|
||||||
|
|
||||||
|
return ResultManager.ToReadableSize(size, 2);
|
||||||
|
}
|
||||||
|
catch (FileNotFoundException)
|
||||||
|
{
|
||||||
|
Main.Context.API.LogError(ClassName, $"Folder not found: {folderPath}");
|
||||||
|
return Main.Context.API.GetTranslation("plugin_explorer_plugin_tooltip_more_info_unknown");
|
||||||
|
}
|
||||||
|
catch (UnauthorizedAccessException)
|
||||||
|
{
|
||||||
|
Main.Context.API.LogError(ClassName, $"Access denied to folder: {folderPath}");
|
||||||
|
return Main.Context.API.GetTranslation("plugin_explorer_plugin_tooltip_more_info_unknown");
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException)
|
||||||
|
{
|
||||||
|
Main.Context.API.LogError(ClassName, $"Operation timed out while calculating folder size for {folderPath}");
|
||||||
|
return Main.Context.API.GetTranslation("plugin_explorer_plugin_tooltip_more_info_unknown");
|
||||||
|
}
|
||||||
|
// For parallel operations, AggregateException may be thrown if any of the tasks fail
|
||||||
|
catch (AggregateException ae)
|
||||||
|
{
|
||||||
|
switch (ae.InnerException)
|
||||||
|
{
|
||||||
|
case FileNotFoundException:
|
||||||
|
Main.Context.API.LogError(ClassName, $"Folder not found: {folderPath}");
|
||||||
|
return Main.Context.API.GetTranslation("plugin_explorer_plugin_tooltip_more_info_unknown");
|
||||||
|
case UnauthorizedAccessException:
|
||||||
|
Main.Context.API.LogError(ClassName, $"Access denied to folder: {folderPath}");
|
||||||
|
return Main.Context.API.GetTranslation("plugin_explorer_plugin_tooltip_more_info_unknown");
|
||||||
|
case OperationCanceledException:
|
||||||
|
Main.Context.API.LogError(ClassName, $"Operation timed out while calculating folder size for {folderPath}");
|
||||||
|
return Main.Context.API.GetTranslation("plugin_explorer_plugin_tooltip_more_info_unknown");
|
||||||
|
default:
|
||||||
|
Main.Context.API.LogException(ClassName, $"Failed to get folder size for {folderPath}", ae);
|
||||||
|
return Main.Context.API.GetTranslation("plugin_explorer_plugin_tooltip_more_info_unknown");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Main.Context.API.LogException(ClassName, $"Failed to get folder size for {folderPath}", e);
|
||||||
|
return Main.Context.API.GetTranslation("plugin_explorer_plugin_tooltip_more_info_unknown");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetFolderCreatedAt(string folderPath, string previewPanelDateFormat, string previewPanelTimeFormat, bool showFileAgeInPreviewPanel)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var createdDate = Directory.GetCreationTime(folderPath);
|
||||||
|
var formattedDate = createdDate.ToString(
|
||||||
|
$"{previewPanelDateFormat} {previewPanelTimeFormat}",
|
||||||
|
CultureInfo.CurrentCulture
|
||||||
|
);
|
||||||
|
|
||||||
|
var result = formattedDate;
|
||||||
|
if (showFileAgeInPreviewPanel) result = $"{GetFileAge(createdDate)} - {formattedDate}";
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (FileNotFoundException)
|
||||||
|
{
|
||||||
|
Main.Context.API.LogError(ClassName, $"Folder not found: {folderPath}");
|
||||||
|
return Main.Context.API.GetTranslation("plugin_explorer_plugin_tooltip_more_info_unknown");
|
||||||
|
}
|
||||||
|
catch (UnauthorizedAccessException)
|
||||||
|
{
|
||||||
|
Main.Context.API.LogError(ClassName, $"Access denied to folder: {folderPath}");
|
||||||
|
return Main.Context.API.GetTranslation("plugin_explorer_plugin_tooltip_more_info_unknown");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Main.Context.API.LogException(ClassName, $"Failed to get folder created date for {folderPath}", e);
|
||||||
|
return Main.Context.API.GetTranslation("plugin_explorer_plugin_tooltip_more_info_unknown");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetFolderLastModifiedAt(string folderPath, string previewPanelDateFormat, string previewPanelTimeFormat, bool showFileAgeInPreviewPanel)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var lastModifiedDate = Directory.GetLastWriteTime(folderPath);
|
||||||
|
var formattedDate = lastModifiedDate.ToString(
|
||||||
|
$"{previewPanelDateFormat} {previewPanelTimeFormat}",
|
||||||
|
CultureInfo.CurrentCulture
|
||||||
|
);
|
||||||
|
|
||||||
|
var result = formattedDate;
|
||||||
|
if (showFileAgeInPreviewPanel) result = $"{GetFileAge(lastModifiedDate)} - {formattedDate}";
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (FileNotFoundException)
|
||||||
|
{
|
||||||
|
Main.Context.API.LogError(ClassName, $"Folder not found: {folderPath}");
|
||||||
|
return Main.Context.API.GetTranslation("plugin_explorer_plugin_tooltip_more_info_unknown");
|
||||||
|
}
|
||||||
|
catch (UnauthorizedAccessException)
|
||||||
|
{
|
||||||
|
Main.Context.API.LogError(ClassName, $"Access denied to folder: {folderPath}");
|
||||||
|
return Main.Context.API.GetTranslation("plugin_explorer_plugin_tooltip_more_info_unknown");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Main.Context.API.LogException(ClassName, $"Failed to get folder modified date for {folderPath}", e);
|
||||||
|
return Main.Context.API.GetTranslation("plugin_explorer_plugin_tooltip_more_info_unknown");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static string GetFileAge(DateTime fileDateTime)
|
private static string GetFileAge(DateTime fileDateTime)
|
||||||
{
|
{
|
||||||
var now = DateTime.Now;
|
var now = DateTime.Now;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue