diff --git a/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj b/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj index e36b9c5e0..7d6448c43 100644 --- a/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj +++ b/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj @@ -49,7 +49,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Flow.Launcher.Infrastructure/Image/ImageCache.cs b/Flow.Launcher.Infrastructure/Image/ImageCache.cs index 55545b9a7..ddbab4ef0 100644 --- a/Flow.Launcher.Infrastructure/Image/ImageCache.cs +++ b/Flow.Launcher.Infrastructure/Image/ImageCache.cs @@ -3,33 +3,23 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Threading; +using System.Threading.Tasks; using System.Windows.Media; -using FastCache; -using FastCache.Services; +using BitFaster.Caching.Lfu; 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 { 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.Save(key, new ImageUsage(usage[key], null), TimeSpan.MaxValue, MaxCached); + CacheManager.AddOrUpdate(key, null); } } @@ -37,48 +27,42 @@ namespace Flow.Launcher.Infrastructure.Image { get { - if (!Cached.TryGet((path, isFullImage), out var value)) - { - return null; - } - - value.Value.usage++; - return value.Value.imageSource; + return CacheManager.TryGet((path, isFullImage), out var value) ? value : null; } set { - if (Cached.TryGet((path, isFullImage), out var cached)) - { - cached.Value.imageSource = value; - cached.Value.usage++; - } - - Cached.Save((path, isFullImage), new ImageUsage(0, value), TimeSpan.MaxValue, - MaxCached); + CacheManager.AddOrUpdate((path, isFullImage), value); } } + public async ValueTask GetOrAddAsync(string key, + Func<(string, bool), Task> valueFactory, + bool isFullImage = false) + { + return await CacheManager.GetOrAddAsync((key, isFullImage), valueFactory); + } + public bool ContainsKey(string key, bool isFullImage) { - return Cached.TryGet((key, isFullImage), out _); + return CacheManager.TryGet((key, isFullImage), out _); } public bool TryGetValue(string key, bool isFullImage, out ImageSource image) { - if (Cached.TryGet((key, isFullImage), out var value)) + if (CacheManager.TryGet((key, isFullImage), out var value)) { - image = value.Value.imageSource; - value.Value.usage++; + image = value; return image != null; } + image = null; return false; } public int CacheSize() { - return CacheManager.TotalCount<(string, bool), ImageUsage>(); + return CacheManager.Count; } /// @@ -86,14 +70,14 @@ namespace Flow.Launcher.Infrastructure.Image /// public int UniqueImagesInCache() { - return CacheManager.EnumerateEntries<(string, bool), ImageUsage>().Select(x => x.Value.imageSource) + return CacheManager.Select(x => x.Value) .Distinct() .Count(); } - public IEnumerable> EnumerateEntries() + public IEnumerable> EnumerateEntries() { - return CacheManager.EnumerateEntries<(string, bool), ImageUsage>(); + return CacheManager; } } } diff --git a/Flow.Launcher.Infrastructure/Image/ImageLoader.cs b/Flow.Launcher.Infrastructure/Image/ImageLoader.cs index 75c2a4ec9..612f495be 100644 --- a/Flow.Launcher.Infrastructure/Image/ImageLoader.cs +++ b/Flow.Launcher.Infrastructure/Image/ImageLoader.cs @@ -5,6 +5,7 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; +using System.Windows.Documents; using System.Windows.Media; using System.Windows.Media.Imaging; using Flow.Launcher.Infrastructure.Logger; @@ -17,7 +18,7 @@ namespace Flow.Launcher.Infrastructure.Image { private static readonly ImageCache ImageCache = new(); private static SemaphoreSlim storageLock { get; } = new SemaphoreSlim(1, 1); - private static BinaryStorage> _storage; + private static BinaryStorage> _storage; private static readonly ConcurrentDictionary GuidToKey = new(); private static IImageHashGenerator _hashGenerator; private static readonly bool EnableImageHash = true; @@ -31,12 +32,12 @@ namespace Flow.Launcher.Infrastructure.Image public static async Task InitializeAsync() { - _storage = new BinaryStorage>("Image"); + _storage = new BinaryStorage>("Image"); _hashGenerator = new ImageHashGenerator(); 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 }) { @@ -49,7 +50,7 @@ namespace Flow.Launcher.Infrastructure.Image { 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); } @@ -66,9 +67,8 @@ namespace Flow.Launcher.Infrastructure.Image try { await _storage.SaveAsync(ImageCache.EnumerateEntries() - .ToDictionary( - x => x.Key, - x => x.Value.usage)); + .Select(x => x.Key) + .ToList()); } finally { @@ -76,14 +76,12 @@ namespace Flow.Launcher.Infrastructure.Image } } - private static async Task> LoadStorageToConcurrentDictionaryAsync() + private static async Task> LoadStorageToConcurrentDictionaryAsync() { await storageLock.WaitAsync(); try { - var loaded = await _storage.TryLoadAsync(new Dictionary<(string, bool), int>()); - - return new ConcurrentDictionary<(string, bool), int>(loaded); + return await _storage.TryLoadAsync(new List<(string, bool)>()); } finally { diff --git a/Flow.Launcher.Infrastructure/Storage/BinaryStorage.cs b/Flow.Launcher.Infrastructure/Storage/BinaryStorage.cs index a679643fd..2a439b8cc 100644 --- a/Flow.Launcher.Infrastructure/Storage/BinaryStorage.cs +++ b/Flow.Launcher.Infrastructure/Storage/BinaryStorage.cs @@ -67,7 +67,7 @@ namespace Flow.Launcher.Infrastructure.Storage } 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; } } diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs index 7396a5bb2..44e104895 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs @@ -88,8 +88,8 @@ namespace Flow.Launcher.Infrastructure.UserSettings public double SettingWindowWidth { get; set; } = 1000; public double SettingWindowHeight { get; set; } = 700; - public double SettingWindowTop { get; set; } - public double SettingWindowLeft { get; set; } + public double? SettingWindowTop { get; set; } = null; + public double? SettingWindowLeft { get; set; } = null; public System.Windows.WindowState SettingWindowState { get; set; } = WindowState.Normal; public int CustomExplorerIndex { get; set; } = 0; diff --git a/Flow.Launcher/Flow.Launcher.csproj b/Flow.Launcher/Flow.Launcher.csproj index 53c1bafc7..848c52f1f 100644 --- a/Flow.Launcher/Flow.Launcher.csproj +++ b/Flow.Launcher/Flow.Launcher.csproj @@ -111,6 +111,12 @@ + + + PreserveNewest + + + diff --git a/Flow.Launcher/Images/dev.ico b/Flow.Launcher/Images/dev.ico new file mode 100644 index 000000000..aba4eb2f9 Binary files /dev/null and b/Flow.Launcher/Images/dev.ico differ diff --git a/Flow.Launcher/MainWindow.xaml.cs b/Flow.Launcher/MainWindow.xaml.cs index efeed5148..22799a63d 100644 --- a/Flow.Launcher/MainWindow.xaml.cs +++ b/Flow.Launcher/MainWindow.xaml.cs @@ -341,11 +341,10 @@ namespace Flow.Launcher _notifyIcon = new NotifyIcon { Text = Infrastructure.Constant.FlowLauncherFullName, - Icon = Properties.Resources.app, + Icon = Constant.Version == "1.0.0" ? Properties.Resources.dev : Properties.Resources.app, Visible = !_settings.HideNotifyIcon }; - var openIcon = new FontIcon { Glyph = "\ue71e" diff --git a/Flow.Launcher/Properties/Resources.Designer.cs b/Flow.Launcher/Properties/Resources.Designer.cs index 43927cb98..ce4d4fe13 100644 --- a/Flow.Launcher/Properties/Resources.Designer.cs +++ b/Flow.Launcher/Properties/Resources.Designer.cs @@ -77,5 +77,13 @@ namespace Flow.Launcher.Properties { return ((System.Drawing.Icon)(obj)); } } + internal static System.Drawing.Icon dev + { + get + { + object obj = ResourceManager.GetObject("dev", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } } } diff --git a/Flow.Launcher/Properties/Resources.resx b/Flow.Launcher/Properties/Resources.resx index 2126cb185..d608b69d5 100644 --- a/Flow.Launcher/Properties/Resources.resx +++ b/Flow.Launcher/Properties/Resources.resx @@ -112,15 +112,18 @@ 2.0 - System.Resources.ResXResourceReader, System.Windows.Forms, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - + ..\Resources\app.ico;System.Drawing.Icon, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Images\dev.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + ..\Images\gamemode.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a diff --git a/Flow.Launcher/Resources/dev.ico b/Flow.Launcher/Resources/dev.ico new file mode 100644 index 000000000..5d06b9f28 Binary files /dev/null and b/Flow.Launcher/Resources/dev.ico differ diff --git a/Flow.Launcher/SettingWindow.xaml.cs b/Flow.Launcher/SettingWindow.xaml.cs index 957379ce4..de4fd1f91 100644 --- a/Flow.Launcher/SettingWindow.xaml.cs +++ b/Flow.Launcher/SettingWindow.xaml.cs @@ -110,15 +110,15 @@ public partial class SettingWindow public void InitializePosition() { - if (_settings.SettingWindowTop == null) + if (_settings.SettingWindowTop == null || _settings.SettingWindowLeft == null) { Top = WindowTop(); Left = WindowLeft(); } else { - Top = _settings.SettingWindowTop; - Left = _settings.SettingWindowLeft; + Top = _settings.SettingWindowTop.Value; + Left = _settings.SettingWindowLeft.Value; } WindowState = _settings.SettingWindowState; } diff --git a/Flow.Launcher/ViewModel/SettingWindowViewModel.cs b/Flow.Launcher/ViewModel/SettingWindowViewModel.cs index 481802045..04dd6312b 100644 --- a/Flow.Launcher/ViewModel/SettingWindowViewModel.cs +++ b/Flow.Launcher/ViewModel/SettingWindowViewModel.cs @@ -52,13 +52,13 @@ public class SettingWindowViewModel : BaseModel set => Settings.SettingWindowHeight = value; } - public double SettingWindowTop + public double? SettingWindowTop { get => Settings.SettingWindowTop; set => Settings.SettingWindowTop = value; } - public double SettingWindowLeft + public double? SettingWindowLeft { get => Settings.SettingWindowLeft; set => Settings.SettingWindowLeft = value; diff --git a/README.md b/README.md index 858d39d1c..866cdf8b3 100644 --- a/README.md +++ b/README.md @@ -121,7 +121,7 @@ Or download the [early access version](https://github.com/Flow-Launcher/Prerelea -- 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 Ctrl or Shift, and the operation is displayed on the mouse cursor. ### Windows & Control Panel Settings