Merge branch 'dev' into quicklook

This commit is contained in:
VictoriousRaptor 2024-06-01 14:35:39 +08:00
commit 5ec474cf38
19 changed files with 194 additions and 144 deletions

View file

@ -49,7 +49,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Ben.Demystifier" Version="0.4.1" /> <PackageReference Include="Ben.Demystifier" Version="0.4.1" />
<PackageReference Include="FastCache.Cached" Version="1.8.2" /> <PackageReference Include="BitFaster.Caching" Version="2.5.0" />
<PackageReference Include="Fody" Version="6.5.5"> <PackageReference Include="Fody" Version="6.5.5">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>

View file

@ -3,33 +3,23 @@ using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks;
using System.Windows.Media; using System.Windows.Media;
using FastCache; using BitFaster.Caching.Lfu;
using FastCache.Services;
namespace Flow.Launcher.Infrastructure.Image namespace Flow.Launcher.Infrastructure.Image
{ {
public class ImageUsage
{
public int usage;
public ImageSource imageSource;
public ImageUsage(int usage, ImageSource image)
{
this.usage = usage;
imageSource = image;
}
}
public class ImageCache public class ImageCache
{ {
private const int MaxCached = 150; private const int MaxCached = 150;
public void Initialize(Dictionary<(string, bool), int> usage) private ConcurrentLfu<(string, bool), ImageSource> CacheManager { get; set; } = new(MaxCached);
public void Initialize(IEnumerable<(string, bool)> usage)
{ {
foreach (var key in usage.Keys) foreach (var key in usage)
{ {
Cached<ImageUsage>.Save(key, new ImageUsage(usage[key], null), TimeSpan.MaxValue, MaxCached); CacheManager.AddOrUpdate(key, null);
} }
} }
@ -37,48 +27,42 @@ namespace Flow.Launcher.Infrastructure.Image
{ {
get get
{ {
if (!Cached<ImageUsage>.TryGet((path, isFullImage), out var value)) return CacheManager.TryGet((path, isFullImage), out var value) ? value : null;
{
return null;
}
value.Value.usage++;
return value.Value.imageSource;
} }
set set
{ {
if (Cached<ImageUsage>.TryGet((path, isFullImage), out var cached)) CacheManager.AddOrUpdate((path, isFullImage), value);
{
cached.Value.imageSource = value;
cached.Value.usage++;
}
Cached<ImageUsage>.Save((path, isFullImage), new ImageUsage(0, value), TimeSpan.MaxValue,
MaxCached);
} }
} }
public async ValueTask<ImageSource> GetOrAddAsync(string key,
Func<(string, bool), Task<ImageSource>> valueFactory,
bool isFullImage = false)
{
return await CacheManager.GetOrAddAsync((key, isFullImage), valueFactory);
}
public bool ContainsKey(string key, bool isFullImage) public bool ContainsKey(string key, bool isFullImage)
{ {
return Cached<ImageUsage>.TryGet((key, isFullImage), out _); return CacheManager.TryGet((key, isFullImage), out _);
} }
public bool TryGetValue(string key, bool isFullImage, out ImageSource image) public bool TryGetValue(string key, bool isFullImage, out ImageSource image)
{ {
if (Cached<ImageUsage>.TryGet((key, isFullImage), out var value)) if (CacheManager.TryGet((key, isFullImage), out var value))
{ {
image = value.Value.imageSource; image = value;
value.Value.usage++;
return image != null; return image != null;
} }
image = null; image = null;
return false; return false;
} }
public int CacheSize() public int CacheSize()
{ {
return CacheManager.TotalCount<(string, bool), ImageUsage>(); return CacheManager.Count;
} }
/// <summary> /// <summary>
@ -86,14 +70,14 @@ namespace Flow.Launcher.Infrastructure.Image
/// </summary> /// </summary>
public int UniqueImagesInCache() public int UniqueImagesInCache()
{ {
return CacheManager.EnumerateEntries<(string, bool), ImageUsage>().Select(x => x.Value.imageSource) return CacheManager.Select(x => x.Value)
.Distinct() .Distinct()
.Count(); .Count();
} }
public IEnumerable<Cached<(string, bool), ImageUsage>> EnumerateEntries() public IEnumerable<KeyValuePair<(string, bool), ImageSource>> EnumerateEntries()
{ {
return CacheManager.EnumerateEntries<(string, bool), ImageUsage>(); return CacheManager;
} }
} }
} }

View file

@ -5,6 +5,7 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows.Documents;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
using Flow.Launcher.Infrastructure.Logger; using Flow.Launcher.Infrastructure.Logger;
@ -17,7 +18,7 @@ namespace Flow.Launcher.Infrastructure.Image
{ {
private static readonly ImageCache ImageCache = new(); private static readonly ImageCache ImageCache = new();
private static SemaphoreSlim storageLock { get; } = new SemaphoreSlim(1, 1); private static SemaphoreSlim storageLock { get; } = new SemaphoreSlim(1, 1);
private static BinaryStorage<Dictionary<(string, bool), int>> _storage; private static BinaryStorage<List<(string, bool)>> _storage;
private static readonly ConcurrentDictionary<string, string> GuidToKey = new(); private static readonly ConcurrentDictionary<string, string> GuidToKey = new();
private static IImageHashGenerator _hashGenerator; private static IImageHashGenerator _hashGenerator;
private static readonly bool EnableImageHash = true; private static readonly bool EnableImageHash = true;
@ -31,12 +32,12 @@ namespace Flow.Launcher.Infrastructure.Image
public static async Task InitializeAsync() public static async Task InitializeAsync()
{ {
_storage = new BinaryStorage<Dictionary<(string, bool), int>>("Image"); _storage = new BinaryStorage<List<(string, bool)>>("Image");
_hashGenerator = new ImageHashGenerator(); _hashGenerator = new ImageHashGenerator();
var usage = await LoadStorageToConcurrentDictionaryAsync(); var usage = await LoadStorageToConcurrentDictionaryAsync();
ImageCache.Initialize(usage.ToDictionary(x => x.Key, x => x.Value)); ImageCache.Initialize(usage);
foreach (var icon in new[] { Constant.DefaultIcon, Constant.MissingImgIcon }) foreach (var icon in new[] { Constant.DefaultIcon, Constant.MissingImgIcon })
{ {
@ -49,7 +50,7 @@ namespace Flow.Launcher.Infrastructure.Image
{ {
await Stopwatch.NormalAsync("|ImageLoader.Initialize|Preload images cost", async () => await Stopwatch.NormalAsync("|ImageLoader.Initialize|Preload images cost", async () =>
{ {
foreach (var ((path, isFullImage), _) in usage) foreach (var (path, isFullImage) in usage)
{ {
await LoadAsync(path, isFullImage); await LoadAsync(path, isFullImage);
} }
@ -66,9 +67,8 @@ namespace Flow.Launcher.Infrastructure.Image
try try
{ {
await _storage.SaveAsync(ImageCache.EnumerateEntries() await _storage.SaveAsync(ImageCache.EnumerateEntries()
.ToDictionary( .Select(x => x.Key)
x => x.Key, .ToList());
x => x.Value.usage));
} }
finally finally
{ {
@ -76,14 +76,12 @@ namespace Flow.Launcher.Infrastructure.Image
} }
} }
private static async Task<ConcurrentDictionary<(string, bool), int>> LoadStorageToConcurrentDictionaryAsync() private static async Task<List<(string, bool)>> LoadStorageToConcurrentDictionaryAsync()
{ {
await storageLock.WaitAsync(); await storageLock.WaitAsync();
try try
{ {
var loaded = await _storage.TryLoadAsync(new Dictionary<(string, bool), int>()); return await _storage.TryLoadAsync(new List<(string, bool)>());
return new ConcurrentDictionary<(string, bool), int>(loaded);
} }
finally finally
{ {

View file

@ -67,7 +67,7 @@ namespace Flow.Launcher.Infrastructure.Storage
} }
catch (System.Exception e) catch (System.Exception e)
{ {
Log.Exception($"|BinaryStorage.Deserialize|Deserialize error for file <{FilePath}>", e); // Log.Exception($"|BinaryStorage.Deserialize|Deserialize error for file <{FilePath}>", e);
return defaultData; return defaultData;
} }
} }

View file

@ -88,8 +88,8 @@ namespace Flow.Launcher.Infrastructure.UserSettings
public double SettingWindowWidth { get; set; } = 1000; public double SettingWindowWidth { get; set; } = 1000;
public double SettingWindowHeight { get; set; } = 700; public double SettingWindowHeight { get; set; } = 700;
public double SettingWindowTop { get; set; } public double? SettingWindowTop { get; set; } = null;
public double SettingWindowLeft { get; set; } public double? SettingWindowLeft { get; set; } = null;
public System.Windows.WindowState SettingWindowState { get; set; } = WindowState.Normal; public System.Windows.WindowState SettingWindowState { get; set; } = WindowState.Normal;
public int CustomExplorerIndex { get; set; } = 0; public int CustomExplorerIndex { get; set; } = 0;

View file

@ -111,6 +111,12 @@
</Content> </Content>
</ItemGroup> </ItemGroup>
<ItemGroup>
<None Update="Resources\dev.ico">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<Target Name="PreBuild" BeforeTargets="PreBuildEvent"> <Target Name="PreBuild" BeforeTargets="PreBuildEvent">
<Exec Command="taskkill /f /fi &quot;IMAGENAME eq Flow.Launcher.exe&quot;" /> <Exec Command="taskkill /f /fi &quot;IMAGENAME eq Flow.Launcher.exe&quot;" />
</Target> </Target>

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View file

@ -344,8 +344,22 @@
<ContentControl> <ContentControl>
<ContentControl.Style> <ContentControl.Style>
<Style TargetType="ContentControl"> <Style TargetType="ContentControl">
<Setter Property="Visibility" Value="Collapsed" /> <Setter Property="Visibility" Value="Visible" />
<Style.Triggers> <Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding ElementName=ResultListBox, Path=Items.Count}" Value="0" />
<Condition Binding="{Binding ElementName=ContextMenu, Path=Visibility}" Value="Collapsed" />
<Condition Binding="{Binding ElementName=History, Path=Visibility}" Value="Collapsed" />
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter Property="Visibility" Value="Collapsed" />
<Setter Property="Margin" Value="0" />
<Setter Property="Height" Value="0" />
</MultiDataTrigger.Setters>
</MultiDataTrigger>
</Style.Triggers>
<!--<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=ResultListBox, Path=Visibility}" Value="Visible"> <DataTrigger Binding="{Binding ElementName=ResultListBox, Path=Visibility}" Value="Visible">
<Setter Property="Visibility" Value="Visible" /> <Setter Property="Visibility" Value="Visible" />
</DataTrigger> </DataTrigger>
@ -355,7 +369,7 @@
<DataTrigger Binding="{Binding ElementName=History, Path=Visibility}" Value="Visible"> <DataTrigger Binding="{Binding ElementName=History, Path=Visibility}" Value="Visible">
<Setter Property="Visibility" Value="Visible" /> <Setter Property="Visibility" Value="Visible" />
</DataTrigger> </DataTrigger>
</Style.Triggers> </Style.Triggers>-->
</Style> </Style>
</ContentControl.Style> </ContentControl.Style>
<Rectangle <Rectangle
@ -368,7 +382,7 @@
</Grid> </Grid>
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="*" MinWidth="100" /> <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>
@ -439,6 +453,7 @@
Style="{DynamicResource PreviewArea}" Style="{DynamicResource PreviewArea}"
Visibility="{Binding InternalPreviewVisible, Converter={StaticResource BoolToVisibilityConverter}}"> Visibility="{Binding InternalPreviewVisible, Converter={StaticResource BoolToVisibilityConverter}}">
<Border <Border
MinHeight="380"
d:DataContext="{d:DesignInstance vm:ResultViewModel}" d:DataContext="{d:DesignInstance vm:ResultViewModel}"
DataContext="{Binding SelectedItem, ElementName=ResultListBox}" DataContext="{Binding SelectedItem, ElementName=ResultListBox}"
Style="{DynamicResource PreviewBorderStyle}" Style="{DynamicResource PreviewBorderStyle}"
@ -514,6 +529,8 @@
</Grid> </Grid>
</Border> </Border>
<Border <Border
MinHeight="380"
MaxHeight="{Binding ElementName=ResultListBox, Path=ActualHeight}"
d:DataContext="{d:DesignInstance vm:ResultViewModel}" d:DataContext="{d:DesignInstance vm:ResultViewModel}"
DataContext="{Binding SelectedItem, ElementName=ResultListBox}" DataContext="{Binding SelectedItem, ElementName=ResultListBox}"
Style="{DynamicResource PreviewBorderStyle}" Style="{DynamicResource PreviewBorderStyle}"

View file

@ -85,15 +85,26 @@ namespace Flow.Launcher
private const int WM_ENTERSIZEMOVE = 0x0231; private const int WM_ENTERSIZEMOVE = 0x0231;
private const int WM_EXITSIZEMOVE = 0x0232; private const int WM_EXITSIZEMOVE = 0x0232;
private int _initialWidth;
private int _initialHeight;
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{ {
if (msg == WM_ENTERSIZEMOVE) if (msg == WM_ENTERSIZEMOVE)
{ {
_initialWidth = (int)Width;
_initialHeight = (int)Height;
handled = true; handled = true;
} }
if (msg == WM_EXITSIZEMOVE) if (msg == WM_EXITSIZEMOVE)
{ {
OnResizeEnd(); if ( _initialHeight != (int)Height)
{
OnResizeEnd();
}
if (_initialWidth != (int)Width)
{
FlowMainWindow.SizeToContent = SizeToContent.Height;
}
handled = true; handled = true;
} }
return IntPtr.Zero; return IntPtr.Zero;
@ -120,9 +131,8 @@ namespace Flow.Launcher
_settings.MaxResultsToShow = Convert.ToInt32(Math.Truncate(itemCount)); _settings.MaxResultsToShow = Convert.ToInt32(Math.Truncate(itemCount));
} }
} }
_viewModel.MainWindowWidth = Width;
FlowMainWindow.SizeToContent = SizeToContent.Height; FlowMainWindow.SizeToContent = SizeToContent.Height;
_viewModel.MainWindowWidth = Width;
} }
private void OnCopy(object sender, ExecutedRoutedEventArgs e) private void OnCopy(object sender, ExecutedRoutedEventArgs e)
@ -169,7 +179,6 @@ namespace Flow.Launcher
{ {
// MouseEventHandler // MouseEventHandler
PreviewMouseMove += MainPreviewMouseMove; PreviewMouseMove += MainPreviewMouseMove;
CheckFirstLaunch(); CheckFirstLaunch();
HideStartup(); HideStartup();
// show notify icon when flowlauncher is hidden // show notify icon when flowlauncher is hidden
@ -332,11 +341,10 @@ namespace Flow.Launcher
_notifyIcon = new NotifyIcon _notifyIcon = new NotifyIcon
{ {
Text = Infrastructure.Constant.FlowLauncherFullName, Text = Infrastructure.Constant.FlowLauncherFullName,
Icon = Properties.Resources.app, Icon = Constant.Version == "1.0.0" ? Properties.Resources.dev : Properties.Resources.app,
Visible = !_settings.HideNotifyIcon Visible = !_settings.HideNotifyIcon
}; };
var openIcon = new FontIcon var openIcon = new FontIcon
{ {
Glyph = "\ue71e" Glyph = "\ue71e"

View file

@ -77,5 +77,13 @@ namespace Flow.Launcher.Properties {
return ((System.Drawing.Icon)(obj)); return ((System.Drawing.Icon)(obj));
} }
} }
internal static System.Drawing.Icon dev
{
get
{
object obj = ResourceManager.GetObject("dev", resourceCulture);
return ((System.Drawing.Icon)(obj));
}
}
} }
} }

View file

@ -112,15 +112,18 @@
<value>2.0</value> <value>2.0</value>
</resheader> </resheader>
<resheader name="reader"> <resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader> </resheader>
<resheader name="writer"> <resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader> </resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> <assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="app" type="System.Resources.ResXFileRef, System.Windows.Forms"> <data name="app" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\app.ico;System.Drawing.Icon, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> <value>..\Resources\app.ico;System.Drawing.Icon, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data> </data>
<data name="dev" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Images\dev.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="gamemode" type="System.Resources.ResXFileRef, System.Windows.Forms"> <data name="gamemode" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Images\gamemode.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> <value>..\Images\gamemode.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data> </data>

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

View file

@ -110,15 +110,15 @@ public partial class SettingWindow
public void InitializePosition() public void InitializePosition()
{ {
if (_settings.SettingWindowTop == null) if (_settings.SettingWindowTop == null || _settings.SettingWindowLeft == null)
{ {
Top = WindowTop(); Top = WindowTop();
Left = WindowLeft(); Left = WindowLeft();
} }
else else
{ {
Top = _settings.SettingWindowTop; Top = _settings.SettingWindowTop.Value;
Left = _settings.SettingWindowLeft; Left = _settings.SettingWindowLeft.Value;
} }
WindowState = _settings.SettingWindowState; WindowState = _settings.SettingWindowState;
} }

View file

@ -28,8 +28,8 @@
<Setter Property="BorderThickness" Value="0" /> <Setter Property="BorderThickness" Value="0" />
<Setter Property="FontSize" Value="28" /> <Setter Property="FontSize" Value="28" />
<Setter Property="FontWeight" Value="Regular" /> <Setter Property="FontWeight" Value="Regular" />
<Setter Property="Margin" Value="16,7,0,7" /> <Setter Property="Margin" Value="16 7 0 7" />
<Setter Property="Padding" Value="0,4,68,0" /> <Setter Property="Padding" Value="0 4 68 0" />
<Setter Property="Background" Value="Transparent" /> <Setter Property="Background" Value="Transparent" />
<Setter Property="Height" Value="48" /> <Setter Property="Height" Value="48" />
<Setter Property="Foreground" Value="#E3E0E3" /> <Setter Property="Foreground" Value="#E3E0E3" />
@ -69,7 +69,7 @@
<!-- Further font customisations are dynamically loaded in Theme.cs --> <!-- Further font customisations are dynamically loaded in Theme.cs -->
<Style x:Key="BaseQueryBoxBgStyle" TargetType="{x:Type Border}"> <Style x:Key="BaseQueryBoxBgStyle" TargetType="{x:Type Border}">
<Setter Property="Margin" Value="0,2,0,0" /> <Setter Property="Margin" Value="0 2 0 0" />
</Style> </Style>
<Style <Style
x:Key="QueryBoxBgStyle" x:Key="QueryBoxBgStyle"
@ -81,9 +81,9 @@
TargetType="{x:Type TextBox}"> TargetType="{x:Type TextBox}">
<Setter Property="Foreground" Value="DarkGray" /> <Setter Property="Foreground" Value="DarkGray" />
<Setter Property="Height" Value="48" /> <Setter Property="Height" Value="48" />
<Setter Property="Margin" Value="16,7,0,7" /> <Setter Property="Margin" Value="16 7 0 7" />
<Setter Property="Background" Value="Transparent" /> <Setter Property="Background" Value="Transparent" />
<Setter Property="Padding" Value="0,4,68,0" /> <Setter Property="Padding" Value="0 4 68 0" />
<Setter Property="HorizontalAlignment" Value="Stretch" /> <Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="VerticalAlignment" Value="Center" /> <Setter Property="VerticalAlignment" Value="Center" />
</Style> </Style>
@ -91,7 +91,7 @@
<Style x:Key="BaseWindowBorderStyle" TargetType="{x:Type Border}"> <Style x:Key="BaseWindowBorderStyle" TargetType="{x:Type Border}">
<Setter Property="BorderThickness" Value="0" /> <Setter Property="BorderThickness" Value="0" />
<Setter Property="Background" Value="#2F2F2F" /> <Setter Property="Background" Value="#2F2F2F" />
<Setter Property="Padding" Value="0,0,0,0" /> <Setter Property="Padding" Value="0 0 0 0" />
<Setter Property="CornerRadius" Value="5" /> <Setter Property="CornerRadius" Value="5" />
<Setter Property="UseLayoutRounding" Value="True" /> <Setter Property="UseLayoutRounding" Value="True" />
<Setter Property="SnapsToDevicePixels" Value="True" /> <Setter Property="SnapsToDevicePixels" Value="True" />
@ -115,7 +115,7 @@
<Setter Property="HorizontalAlignment" Value="Right" /> <Setter Property="HorizontalAlignment" Value="Right" />
<Setter Property="VerticalAlignment" Value="Center" /> <Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Height" Value="Auto" /> <Setter Property="Height" Value="Auto" />
<Setter Property="Margin" Value="0,0,66,0" /> <Setter Property="Margin" Value="0 0 66 0" />
<Setter Property="Visibility" Value="Collapsed" /> <Setter Property="Visibility" Value="Collapsed" />
</Style> </Style>
<Style x:Key="BaseClockBox" TargetType="{x:Type TextBlock}"> <Style x:Key="BaseClockBox" TargetType="{x:Type TextBlock}">
@ -123,7 +123,7 @@
<Setter Property="Foreground" Value="#8f8f8f" /> <Setter Property="Foreground" Value="#8f8f8f" />
<Setter Property="HorizontalAlignment" Value="Right" /> <Setter Property="HorizontalAlignment" Value="Right" />
<Setter Property="VerticalAlignment" Value="Center" /> <Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Margin" Value="0,0,0,0" /> <Setter Property="Margin" Value="0 0 0 0" />
<Style.Triggers> <Style.Triggers>
<DataTrigger Binding="{Binding ElementName=DateBox, Path=Visibility}" Value="Visible"> <DataTrigger Binding="{Binding ElementName=DateBox, Path=Visibility}" Value="Visible">
<Setter Property="FontSize" Value="14" /> <Setter Property="FontSize" Value="14" />
@ -135,7 +135,7 @@
<Setter Property="Foreground" Value="#8f8f8f" /> <Setter Property="Foreground" Value="#8f8f8f" />
<Setter Property="HorizontalAlignment" Value="Right" /> <Setter Property="HorizontalAlignment" Value="Right" />
<Setter Property="VerticalAlignment" Value="Center" /> <Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Margin" Value="0,0,0,0" /> <Setter Property="Margin" Value="0 0 0 0" />
<Style.Triggers> <Style.Triggers>
<DataTrigger Binding="{Binding ElementName=ClockBox, Path=Visibility}" Value="Visible"> <DataTrigger Binding="{Binding ElementName=ClockBox, Path=Visibility}" Value="Visible">
<Setter Property="FontSize" Value="14" /> <Setter Property="FontSize" Value="14" />
@ -188,7 +188,7 @@
<!-- Item Style --> <!-- Item Style -->
<Style x:Key="ProgressBarResult" TargetType="{x:Type ProgressBar}"> <Style x:Key="ProgressBarResult" TargetType="{x:Type ProgressBar}">
<Setter Property="Height" Value="18" /> <Setter Property="Height" Value="18" />
<Setter Property="Margin" Value="0,0,0,4" /> <Setter Property="Margin" Value="0 0 0 4" />
<Setter Property="VerticalAlignment" Value="Center" /> <Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Maximum" Value="100" /> <Setter Property="Maximum" Value="100" />
<Setter Property="Minimum" Value="0" /> <Setter Property="Minimum" Value="0" />
@ -214,7 +214,7 @@
<Style x:Key="BaseItemNumberStyle" TargetType="{x:Type TextBlock}"> <Style x:Key="BaseItemNumberStyle" TargetType="{x:Type TextBlock}">
<Setter Property="VerticalAlignment" Value="Center" /> <Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="HorizontalAlignment" Value="Center" /> <Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="Margin" Value="3,0,0,0" /> <Setter Property="Margin" Value="3 0 0 0" />
<Setter Property="FontSize" Value="22" /> <Setter Property="FontSize" Value="22" />
</Style> </Style>
<Style x:Key="BaseGlyphStyle" TargetType="{x:Type TextBlock}"> <Style x:Key="BaseGlyphStyle" TargetType="{x:Type TextBlock}">
@ -255,7 +255,7 @@
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled" /> <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled" />
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto" /> <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto" />
<Setter Property="Margin" Value="{DynamicResource ResultMargin}" /> <Setter Property="Margin" Value="{DynamicResource ResultMargin}" />
<Setter Property="Padding" Value="0,0,0,0" /> <Setter Property="Padding" Value="0 0 0 0" />
<Setter Property="Template"> <Setter Property="Template">
<Setter.Value> <Setter.Value>
@ -265,12 +265,12 @@
<Style TargetType="ScrollViewer"> <Style TargetType="ScrollViewer">
<Style.Triggers> <Style.Triggers>
<Trigger Property="ComputedVerticalScrollBarVisibility" Value="Visible"> <Trigger Property="ComputedVerticalScrollBarVisibility" Value="Visible">
<Setter Property="Margin" Value="0,0,0,0" /> <Setter Property="Margin" Value="0 0 0 0" />
<Setter Property="Padding" Value="0,0,0,0" /> <Setter Property="Padding" Value="0 0 0 0" />
</Trigger> </Trigger>
<Trigger Property="ComputedVerticalScrollBarVisibility" Value="Collapsed"> <Trigger Property="ComputedVerticalScrollBarVisibility" Value="Collapsed">
<Setter Property="Margin" Value="0,0,0,0" /> <Setter Property="Margin" Value="0 0 0 0" />
<Setter Property="Padding" Value="0,0,0,0" /> <Setter Property="Padding" Value="0 0 0 0" />
</Trigger> </Trigger>
</Style.Triggers> </Style.Triggers>
</Style> </Style>
@ -312,7 +312,7 @@
x:Name="PART_VerticalScrollBar" x:Name="PART_VerticalScrollBar"
Grid.Row="0" Grid.Row="0"
Grid.Column="0" Grid.Column="0"
Margin="0,0,0,0" Margin="0 0 0 0"
HorizontalAlignment="Right" HorizontalAlignment="Right"
AutomationProperties.AutomationId="VerticalScrollBar" AutomationProperties.AutomationId="VerticalScrollBar"
Cursor="Arrow" Cursor="Arrow"
@ -368,22 +368,7 @@
</Setter.Value> </Setter.Value>
</Setter> </Setter>
</Style> </Style>
<Style x:Key="BaseSeparatorStyle" TargetType="Rectangle"> <Style x:Key="BaseSeparatorStyle" TargetType="Rectangle" />
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding ElementName=ResultListBox, Path=Items.Count}" Value="0" />
<Condition Binding="{Binding ElementName=ContextMenu, Path=Visibility}" Value="Collapsed" />
<Condition Binding="{Binding ElementName=History, Path=Visibility}" Value="Collapsed" />
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter Property="Visibility" Value="Collapsed" />
<Setter Property="Margin" Value="0" />
<Setter Property="Height" Value="0" />
</MultiDataTrigger.Setters>
</MultiDataTrigger>
</Style.Triggers>
</Style>
<Style x:Key="HighlightStyle"> <Style x:Key="HighlightStyle">
<Setter Property="Inline.FontWeight" Value="Bold" /> <Setter Property="Inline.FontWeight" Value="Bold" />
</Style> </Style>
@ -413,15 +398,15 @@
<Style x:Key="BaseSearchIconPosition" TargetType="{x:Type Canvas}"> <Style x:Key="BaseSearchIconPosition" TargetType="{x:Type Canvas}">
<Setter Property="Width" Value="32" /> <Setter Property="Width" Value="32" />
<Setter Property="Height" Value="32" /> <Setter Property="Height" Value="32" />
<Setter Property="Margin" Value="0,2,18,0" /> <Setter Property="Margin" Value="0 2 18 0" />
<Setter Property="Background" Value="Transparent" /> <Setter Property="Background" Value="Transparent" />
<Setter Property="HorizontalAlignment" Value="Right" /> <Setter Property="HorizontalAlignment" Value="Right" />
</Style> </Style>
<Style x:Key="BasePreviewBorderStyle" TargetType="{x:Type Border}"> <Style x:Key="BasePreviewBorderStyle" TargetType="{x:Type Border}">
<Setter Property="BorderThickness" Value="1,0,0,0" /> <Setter Property="BorderThickness" Value="1 0 0 0" />
<Setter Property="BorderBrush" Value="#FFEAEAEA" /> <Setter Property="BorderBrush" Value="#FFEAEAEA" />
<Setter Property="Background" Value="Transparent" /> <Setter Property="Background" Value="Transparent" />
<Setter Property="Margin" Value="0,0,10,10" /> <Setter Property="Margin" Value="0 0 10 10" />
</Style> </Style>
<Style x:Key="BasePreviewGlyph" TargetType="{x:Type TextBlock}"> <Style x:Key="BasePreviewGlyph" TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#555555" /> <Setter Property="Foreground" Value="#555555" />
@ -447,7 +432,7 @@
<Style x:Key="PreviewSep" TargetType="{x:Type Separator}"> <Style x:Key="PreviewSep" TargetType="{x:Type Separator}">
<Setter Property="Visibility" Value="Visible" /> <Setter Property="Visibility" Value="Visible" />
<Setter Property="Background" Value="{Binding ElementName=MiddleSeparator, Path=Fill}" /> <Setter Property="Background" Value="{Binding ElementName=MiddleSeparator, Path=Fill}" />
<Setter Property="Margin" Value="0,15,0,5" /> <Setter Property="Margin" Value="0 15 0 5" />
<Style.Triggers> <Style.Triggers>
<DataTrigger Binding="{Binding ElementName=PreviewSubTitle, UpdateSourceTrigger=PropertyChanged, Path=Text.Length}" Value="0"> <DataTrigger Binding="{Binding ElementName=PreviewSubTitle, UpdateSourceTrigger=PropertyChanged, Path=Text.Length}" Value="0">
<Setter Property="Visibility" Value="Collapsed" /> <Setter Property="Visibility" Value="Collapsed" />
@ -483,7 +468,7 @@
<Style x:Key="PluginActivationIcon" TargetType="{x:Type Image}"> <Style x:Key="PluginActivationIcon" TargetType="{x:Type Image}">
<Setter Property="Width" Value="32" /> <Setter Property="Width" Value="32" />
<Setter Property="Height" Value="32" /> <Setter Property="Height" Value="32" />
<Setter Property="Margin" Value="0,0,18,0" /> <Setter Property="Margin" Value="0 0 18 0" />
<Setter Property="VerticalAlignment" Value="Center" /> <Setter Property="VerticalAlignment" Value="Center" />
</Style> </Style>
@ -495,7 +480,7 @@
<Style x:Key="SearchIconPosition" TargetType="{x:Type Canvas}"> <Style x:Key="SearchIconPosition" TargetType="{x:Type Canvas}">
<Setter Property="Width" Value="32" /> <Setter Property="Width" Value="32" />
<Setter Property="Height" Value="32" /> <Setter Property="Height" Value="32" />
<Setter Property="Margin" Value="0,2,18,0" /> <Setter Property="Margin" Value="0 2 18 0" />
<Setter Property="Background" Value="Transparent" /> <Setter Property="Background" Value="Transparent" />
<Setter Property="HorizontalAlignment" Value="Right" /> <Setter Property="HorizontalAlignment" Value="Right" />
</Style> </Style>
@ -503,7 +488,7 @@
x:Key="ClockPanelPosition" x:Key="ClockPanelPosition"
BasedOn="{StaticResource BaseClockPanelPosition}" BasedOn="{StaticResource BaseClockPanelPosition}"
TargetType="{x:Type Canvas}"> TargetType="{x:Type Canvas}">
<Setter Property="Margin" Value="0,2,66,0" /> <Setter Property="Margin" Value="0 2 66 0" />
</Style> </Style>
<Style <Style
x:Key="ItemHotkeyStyle" x:Key="ItemHotkeyStyle"
@ -536,7 +521,7 @@
<Style x:Key="BasePreviewItemTitleStyle" TargetType="{x:Type TextBlock}"> <Style x:Key="BasePreviewItemTitleStyle" TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#8f8f8f" /> <Setter Property="Foreground" Value="#8f8f8f" />
<Setter Property="FontSize" Value="15" /> <Setter Property="FontSize" Value="15" />
<Setter Property="Margin" Value="0,6,0,0" /> <Setter Property="Margin" Value="0 6 0 0" />
<Setter Property="HorizontalAlignment" Value="Stretch" /> <Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="TextAlignment" Value="Center" /> <Setter Property="TextAlignment" Value="Center" />
<Setter Property="TextWrapping" Value="Wrap" /> <Setter Property="TextWrapping" Value="Wrap" />
@ -545,7 +530,7 @@
<Setter Property="Foreground" Value="#8f8f8f" /> <Setter Property="Foreground" Value="#8f8f8f" />
<Setter Property="FontSize" Value="12" /> <Setter Property="FontSize" Value="12" />
<Setter Property="FontWeight" Value="Normal" /> <Setter Property="FontWeight" Value="Normal" />
<Setter Property="Margin" Value="0,6,0,10" /> <Setter Property="Margin" Value="0 6 0 10" />
<Setter Property="HorizontalAlignment" Value="Stretch" /> <Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="LineHeight" Value="18" /> <Setter Property="LineHeight" Value="18" />
<Setter Property="TextAlignment" Value="Left" /> <Setter Property="TextAlignment" Value="Left" />

View file

@ -143,15 +143,21 @@ namespace Flow.Launcher.ViewModel
ContextMenu = new ResultsViewModel(Settings) ContextMenu = new ResultsViewModel(Settings)
{ {
LeftClickResultCommand = OpenResultCommand, RightClickResultCommand = LoadContextMenuCommand LeftClickResultCommand = OpenResultCommand,
RightClickResultCommand = LoadContextMenuCommand,
IsPreviewOn = Settings.AlwaysPreview
}; };
Results = new ResultsViewModel(Settings) Results = new ResultsViewModel(Settings)
{ {
LeftClickResultCommand = OpenResultCommand, RightClickResultCommand = LoadContextMenuCommand LeftClickResultCommand = OpenResultCommand,
RightClickResultCommand = LoadContextMenuCommand,
IsPreviewOn = Settings.AlwaysPreview
}; };
History = new ResultsViewModel(Settings) History = new ResultsViewModel(Settings)
{ {
LeftClickResultCommand = OpenResultCommand, RightClickResultCommand = LoadContextMenuCommand LeftClickResultCommand = OpenResultCommand,
RightClickResultCommand = LoadContextMenuCommand,
IsPreviewOn = Settings.AlwaysPreview
}; };
_selectedResults = Results; _selectedResults = Results;

View file

@ -1,4 +1,5 @@
using Flow.Launcher.Infrastructure.UserSettings; using System;
using Flow.Launcher.Infrastructure.UserSettings;
using Flow.Launcher.Plugin; using Flow.Launcher.Plugin;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Specialized; using System.Collections.Specialized;
@ -49,7 +50,25 @@ namespace Flow.Launcher.ViewModel
#region Properties #region Properties
public double MaxHeight => MaxResults * _settings.ItemHeightSize; public bool IsPreviewOn { get; set; }
public double MaxHeight
{
get
{
var newResultsCount = MaxResults;
if (IsPreviewOn)
{
newResultsCount = (int)Math.Ceiling(380 / _settings.ItemHeightSize);
if (newResultsCount < MaxResults)
{
newResultsCount = MaxResults;
}
}
return newResultsCount * _settings.ItemHeightSize;
}
}
public double ItemHeightSize public double ItemHeightSize
{ {
get => _settings.ItemHeightSize; get => _settings.ItemHeightSize;

View file

@ -52,13 +52,13 @@ public class SettingWindowViewModel : BaseModel
set => Settings.SettingWindowHeight = value; set => Settings.SettingWindowHeight = value;
} }
public double SettingWindowTop public double? SettingWindowTop
{ {
get => Settings.SettingWindowTop; get => Settings.SettingWindowTop;
set => Settings.SettingWindowTop = value; set => Settings.SettingWindowTop = value;
} }
public double SettingWindowLeft public double? SettingWindowLeft
{ {
get => Settings.SettingWindowLeft; get => Settings.SettingWindowLeft;
set => Settings.SettingWindowLeft = value; set => Settings.SettingWindowLeft = value;

View file

@ -13,37 +13,41 @@
Margin="20 0 10 0" Margin="20 0 10 0"
VerticalAlignment="Stretch"> VerticalAlignment="Stretch">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="*" /> <RowDefinition />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<StackPanel Grid.Row="0" VerticalAlignment="Center"> <Grid Grid.Row="0" VerticalAlignment="Center">
<Grid.RowDefinitions>
<RowDefinition MinHeight="96" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Image <Image
Margin="0 16 0 0" Grid.Row="0"
HorizontalAlignment="Stretch" Margin="0 12 0 0"
Source="{Binding PreviewImage, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}}" Source="{Binding PreviewImage, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}}">
StretchDirection="DownOnly">
<Image.Style> <Image.Style>
<Style TargetType="Image"> <Style TargetType="Image">
<Setter Property="MaxWidth" Value="96" />
<Setter Property="MaxHeight" Value="320" />
<Style.Triggers> <Style.Triggers>
<DataTrigger Binding="{Binding UseBigThumbnail}" Value="True"> <DataTrigger Binding="{Binding UseBigThumbnail}" Value="False">
<Setter Property="MaxWidth" Value="{Binding ElementName=PreviewGrid, Path=ActualWidth}" /> <Setter Property="MaxWidth" Value="96" />
<Setter Property="MaxHeight" Value="{Binding ElementName=PreviewGrid, Path=ActualHeight}" /> <Setter Property="MaxHeight" Value="96" />
</DataTrigger> </DataTrigger>
</Style.Triggers> </Style.Triggers>
</Style> </Style>
</Image.Style> </Image.Style>
</Image> </Image>
<TextBlock <Grid Grid.Row="1">
Margin="0 6 0 16" <TextBlock
HorizontalAlignment="Stretch" Margin="0 6 0 16"
Style="{DynamicResource PreviewItemTitleStyle}" HorizontalAlignment="Stretch"
Text="{Binding Result.Title}" VerticalAlignment="Top"
TextAlignment="Center" Style="{DynamicResource PreviewItemTitleStyle}"
TextWrapping="Wrap" /> Text="{Binding Result.Title}"
</StackPanel> TextAlignment="Center"
<StackPanel Grid.Row="1"> TextWrapping="Wrap" />
</Grid>
</Grid>
<StackPanel Grid.Row="2">
<StackPanel.Style> <StackPanel.Style>
<Style TargetType="StackPanel"> <Style TargetType="StackPanel">
<Style.Triggers> <Style.Triggers>
@ -53,10 +57,22 @@
</Style.Triggers> </Style.Triggers>
</Style> </Style>
</StackPanel.Style> </StackPanel.Style>
<Separator /> <Rectangle
<TextBlock Style="{DynamicResource PreviewItemSubTitleStyle}" Text="{Binding Result.SubTitle}" /> Width="Auto"
Margin="0 0 0 0"
HorizontalAlignment="Stretch"
Style="{DynamicResource SeparatorStyle}" />
<TextBlock
Margin="0 8 0 8"
Style="{DynamicResource PreviewItemSubTitleStyle}"
Text="{Binding Result.SubTitle}" />
<Rectangle
Width="Auto"
Margin="0 0 0 0"
HorizontalAlignment="Stretch"
Style="{DynamicResource SeparatorStyle}" />
<StackPanel Visibility="{Binding FileInfoVisibility, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}}"> <StackPanel Visibility="{Binding FileInfoVisibility, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}}">
<Grid Margin="0 10 0 0"> <Grid Margin="0 10 0 10">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="100" /> <ColumnDefinition Width="100" />
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*" />
@ -70,7 +86,7 @@
<TextBlock <TextBlock
Grid.Row="0" Grid.Row="0"
Grid.Column="0" Grid.Column="0"
Margin="0 0 8 0" Margin="0 0 0 0"
VerticalAlignment="Top" VerticalAlignment="Top"
Style="{DynamicResource PreviewItemSubTitleStyle}" Style="{DynamicResource PreviewItemSubTitleStyle}"
Text="{DynamicResource FileSize}" Text="{DynamicResource FileSize}"

View file

@ -121,7 +121,7 @@ Or download the [early access version](https://github.com/Flow-Launcher/Prerelea
<img src="https://user-images.githubusercontent.com/6903107/207159486-1993510f-09f2-4e33-bba7-4ca59ca1bc5a.png" width="500"> <img src="https://user-images.githubusercontent.com/6903107/207159486-1993510f-09f2-4e33-bba7-4ca59ca1bc5a.png" width="500">
- Drag a file/folder to File Exlporer, or even Discord. - Drag a file/folder to File Explorer, or even Discord.
- Copy/move behavior can be change via <kbd>Ctrl</kbd> or <kbd>Shift</kbd>, and the operation is displayed on the mouse cursor. - Copy/move behavior can be change via <kbd>Ctrl</kbd> or <kbd>Shift</kbd>, and the operation is displayed on the mouse cursor.
### Windows & Control Panel Settings ### Windows & Control Panel Settings