diff --git a/.github/actions/spelling/allow.txt b/.github/actions/spelling/allow.txt index 670a7a799..60142b346 100644 --- a/.github/actions/spelling/allow.txt +++ b/.github/actions/spelling/allow.txt @@ -4,4 +4,8 @@ ssh ubuntu runcount Firefox +Português +Português (Brasil) +favicons +moz workaround diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index 0fea6d9ab..81b9aba97 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -104,3 +104,7 @@ metadatas WMP VSTHRD CJK +Msix +dummyprofile +browserbookmark +copyurl diff --git a/.github/actions/spelling/patterns.txt b/.github/actions/spelling/patterns.txt index eb8534c49..faf1c3978 100644 --- a/.github/actions/spelling/patterns.txt +++ b/.github/actions/spelling/patterns.txt @@ -124,6 +124,10 @@ # version suffix v# (?:(?<=[A-Z]{2})V|(?<=[a-z]{2}|[A-Z]{2})v)\d+(?:\b|(?=[a-zA-Z_])) +# Non-English +[a-zA-Z]*[ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź][a-zA-Z]{3}[a-zA-ZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź]* + + \bjjw24\b \bappref-ms\b \bTobiasSekan\b @@ -143,3 +147,4 @@ \bXing\s*Kong\s*Jian\s*Dao\b \bDa\s*Niu\b \bXiao\s*Lang\b +\b[Ss]ettings [Ss]ettings\b diff --git a/Directory.Build.props b/Directory.Build.props index fa499273c..a5545af12 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,5 +1,7 @@ true + + false \ No newline at end of file diff --git a/Flow.Launcher.Core/Resource/LocalizationConverter.cs b/Flow.Launcher.Core/Resource/LocalizationConverter.cs deleted file mode 100644 index fdda33926..000000000 --- a/Flow.Launcher.Core/Resource/LocalizationConverter.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System; -using System.ComponentModel; -using System.Globalization; -using System.Reflection; -using System.Windows.Data; - -namespace Flow.Launcher.Core.Resource -{ - [Obsolete("LocalizationConverter is obsolete. Use with Flow.Launcher.Localization NuGet package instead.")] - public class LocalizationConverter : IValueConverter - { - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - if (targetType == typeof(string) && value != null) - { - FieldInfo fi = value.GetType().GetField(value.ToString()); - if (fi != null) - { - string localizedDescription = string.Empty; - var attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false); - if ((attributes.Length > 0) && (!String.IsNullOrEmpty(attributes[0].Description))) - { - localizedDescription = attributes[0].Description; - } - - return (!String.IsNullOrEmpty(localizedDescription)) ? localizedDescription : value.ToString(); - } - } - - return string.Empty; - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - throw new NotImplementedException(); - } - } -} diff --git a/Flow.Launcher.Infrastructure/UI/EnumBindingSource.cs b/Flow.Launcher.Infrastructure/UI/EnumBindingSource.cs deleted file mode 100644 index f9504e6d9..000000000 --- a/Flow.Launcher.Infrastructure/UI/EnumBindingSource.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System; -using System.Windows.Markup; - -namespace Flow.Launcher.Infrastructure.UI -{ - [Obsolete("EnumBindingSourceExtension is obsolete. Use with Flow.Launcher.Localization NuGet package instead.")] - public class EnumBindingSourceExtension : MarkupExtension - { - private Type _enumType; - public Type EnumType - { - get { return _enumType; } - set - { - if (value != _enumType) - { - if (value != null) - { - Type enumType = Nullable.GetUnderlyingType(value) ?? value; - if (!enumType.IsEnum) - { - throw new ArgumentException("Type must represent an enum."); - } - } - - _enumType = value; - } - } - } - - public EnumBindingSourceExtension() { } - - public EnumBindingSourceExtension(Type enumType) - { - EnumType = enumType; - } - - public override object ProvideValue(IServiceProvider serviceProvider) - { - if (_enumType == null) - { - throw new InvalidOperationException("The EnumType must be specified."); - } - - Type actualEnumType = Nullable.GetUnderlyingType(_enumType) ?? _enumType; - Array enumValues = Enum.GetValues(actualEnumType); - - if (actualEnumType == _enumType) - { - return enumValues; - } - - Array tempArray = Array.CreateInstance(actualEnumType, enumValues.Length + 1); - enumValues.CopyTo(tempArray, 1); - return tempArray; - } - } -} diff --git a/Flow.Launcher/Flow.Launcher.csproj b/Flow.Launcher/Flow.Launcher.csproj index 51f287ab9..a4cf567c0 100644 --- a/Flow.Launcher/Flow.Launcher.csproj +++ b/Flow.Launcher/Flow.Launcher.csproj @@ -136,7 +136,6 @@ - diff --git a/Flow.Launcher/SettingPages/Views/SettingsPanePlugins.xaml b/Flow.Launcher/SettingPages/Views/SettingsPanePlugins.xaml index 52d77f914..aa7c219e5 100644 --- a/Flow.Launcher/SettingPages/Views/SettingsPanePlugins.xaml +++ b/Flow.Launcher/SettingPages/Views/SettingsPanePlugins.xaml @@ -122,6 +122,7 @@ FontSize="14" ItemContainerStyle="{StaticResource PluginList}" ItemsSource="{Binding Source={StaticResource PluginCollectionView}}" + Loaded="PluginListBox_Loaded" ScrollViewer.CanContentScroll="False" ScrollViewer.HorizontalScrollBarVisibility="Disabled" SnapsToDevicePixels="True" diff --git a/Flow.Launcher/SettingPages/Views/SettingsPanePlugins.xaml.cs b/Flow.Launcher/SettingPages/Views/SettingsPanePlugins.xaml.cs index f486a3443..e77a30843 100644 --- a/Flow.Launcher/SettingPages/Views/SettingsPanePlugins.xaml.cs +++ b/Flow.Launcher/SettingPages/Views/SettingsPanePlugins.xaml.cs @@ -1,4 +1,6 @@ using System.ComponentModel; +using System.Windows; +using System.Windows.Controls; using System.Windows.Data; using System.Windows.Input; using System.Windows.Navigation; @@ -33,6 +35,14 @@ public partial class SettingsPanePlugins base.OnNavigatedTo(e); } + private void PluginListBox_Loaded(object sender, RoutedEventArgs e) + { + // After list is loaded, we need to clear selection to make sure all items can be mouse hovered + // because the selected item cannot be hovered. + if (sender is not ListBox listBox) return; + listBox.SelectedIndex = -1; + } + private void ViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == nameof(SettingsPanePluginsViewModel.FilterText)) diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/ChromiumBookmarkLoader.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/ChromiumBookmarkLoader.cs index 6e6b2e5f4..6dc0f7a9a 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/ChromiumBookmarkLoader.cs +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/ChromiumBookmarkLoader.cs @@ -45,7 +45,7 @@ public abstract class ChromiumBookmarkLoader : IBookmarkLoader } catch (Exception ex) { - Main._context.API.LogException(ClassName, $"Failed to register bookmark file monitoring: {bookmarkPath}", ex); + Main.Context.API.LogException(ClassName, $"Failed to register bookmark file monitoring: {bookmarkPath}", ex); continue; } @@ -58,7 +58,7 @@ public abstract class ChromiumBookmarkLoader : IBookmarkLoader var faviconDbPath = Path.Combine(profile, "Favicons"); if (File.Exists(faviconDbPath)) { - Main._context.API.StopwatchLogInfo(ClassName, $"Load {profileBookmarks.Count} favicons cost", () => + Main.Context.API.StopwatchLogInfo(ClassName, $"Load {profileBookmarks.Count} favicons cost", () => { LoadFaviconsFromDb(faviconDbPath, profileBookmarks); }); @@ -125,7 +125,7 @@ public abstract class ChromiumBookmarkLoader : IBookmarkLoader } else { - Main._context.API.LogError(ClassName, $"type property not found for {subElement.GetString()}"); + Main.Context.API.LogError(ClassName, $"type property not found for {subElement.GetString()}"); } } } @@ -190,7 +190,7 @@ public abstract class ChromiumBookmarkLoader : IBookmarkLoader } catch (Exception ex) { - Main._context.API.LogException(ClassName, $"Failed to extract bookmark favicon: {bookmark.Url}", ex); + Main.Context.API.LogException(ClassName, $"Failed to extract bookmark favicon: {bookmark.Url}", ex); } finally { diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Commands/BookmarkLoader.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Commands/BookmarkLoader.cs index 758ce68ae..b76adae93 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Commands/BookmarkLoader.cs +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Commands/BookmarkLoader.cs @@ -9,11 +9,11 @@ internal static class BookmarkLoader { internal static MatchResult MatchProgram(Bookmark bookmark, string queryString) { - var match = Main._context.API.FuzzySearch(queryString, bookmark.Name); + var match = Main.Context.API.FuzzySearch(queryString, bookmark.Name); if (match.IsSearchPrecisionScoreMet()) return match; - return Main._context.API.FuzzySearch(queryString, bookmark.Url); + return Main.Context.API.FuzzySearch(queryString, bookmark.Url); } internal static List LoadAllBookmarks(Settings setting) diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs index ec3b867ea..6a099cb07 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs @@ -2,6 +2,7 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; +using System.IO.Compression; using System.Linq; using System.Threading.Tasks; using Flow.Launcher.Plugin.BrowserBookmark.Helper; @@ -49,7 +50,7 @@ public abstract class FirefoxBookmarkLoaderBase : IBookmarkLoader } catch (Exception ex) { - Main._context.API.LogException(ClassName, $"Failed to register Firefox bookmark file monitoring: {placesPath}", ex); + Main.Context.API.LogException(ClassName, $"Failed to register Firefox bookmark file monitoring: {placesPath}", ex); return bookmarks; } @@ -84,7 +85,7 @@ public abstract class FirefoxBookmarkLoaderBase : IBookmarkLoader var faviconDbPath = Path.Combine(Path.GetDirectoryName(placesPath), "favicons.sqlite"); if (File.Exists(faviconDbPath)) { - Main._context.API.StopwatchLogInfo(ClassName, $"Load {bookmarks.Count} favicons cost", () => + Main.Context.API.StopwatchLogInfo(ClassName, $"Load {bookmarks.Count} favicons cost", () => { LoadFaviconsFromDb(faviconDbPath, bookmarks); }); @@ -98,7 +99,7 @@ public abstract class FirefoxBookmarkLoaderBase : IBookmarkLoader } catch (Exception ex) { - Main._context.API.LogException(ClassName, $"Failed to load Firefox bookmarks: {placesPath}", ex); + Main.Context.API.LogException(ClassName, $"Failed to load Firefox bookmarks: {placesPath}", ex); } // Delete temporary file @@ -111,7 +112,7 @@ public abstract class FirefoxBookmarkLoaderBase : IBookmarkLoader } catch (Exception ex) { - Main._context.API.LogException(ClassName, $"Failed to delete temporary favicon DB: {tempDbPath}", ex); + Main.Context.API.LogException(ClassName, $"Failed to delete temporary favicon DB: {tempDbPath}", ex); } return bookmarks; @@ -134,10 +135,6 @@ public abstract class FirefoxBookmarkLoaderBase : IBookmarkLoader try { - if (string.IsNullOrEmpty(bookmark.Url)) - return; - - // Extract domain from URL if (!Uri.TryCreate(bookmark.Url, UriKind.Absolute, out Uri uri)) return; @@ -146,47 +143,53 @@ public abstract class FirefoxBookmarkLoaderBase : IBookmarkLoader // Query for latest Firefox version favicon structure using var cmd = connection.CreateCommand(); cmd.CommandText = @" - SELECT i.data + SELECT i.id, i.data FROM moz_icons i JOIN moz_icons_to_pages ip ON i.id = ip.icon_id JOIN moz_pages_w_icons p ON ip.page_id = p.id - WHERE p.page_url LIKE @url - AND i.data IS NOT NULL - ORDER BY i.width DESC -- Select largest icon available + WHERE p.page_url LIKE @domain + ORDER BY i.width DESC LIMIT 1"; - cmd.Parameters.AddWithValue("@url", $"%{domain}%"); + cmd.Parameters.AddWithValue("@domain", $"%{domain}%"); using var reader = cmd.ExecuteReader(); - if (!reader.Read() || reader.IsDBNull(0)) + if (!reader.Read() || reader.IsDBNull(1)) return; + var iconId = reader.GetInt64(0).ToString(); var imageData = (byte[])reader["data"]; if (imageData is not { Length: > 0 }) return; - string faviconPath; - if (FaviconHelper.IsSvgData(imageData)) + // Check if the image data is compressed (GZip) + if (imageData.Length > 2 && imageData[0] == 0x1f && imageData[1] == 0x8b) { - faviconPath = Path.Combine(_faviconCacheDir, $"firefox_{domain}.svg"); - } - else - { - faviconPath = Path.Combine(_faviconCacheDir, $"firefox_{domain}.png"); + using var inputStream = new MemoryStream(imageData); + using var gZipStream = new GZipStream(inputStream, CompressionMode.Decompress); + using var outputStream = new MemoryStream(); + gZipStream.CopyTo(outputStream); + imageData = outputStream.ToArray(); } - // Filter out duplicate favicons - if (savedPaths.TryAdd(faviconPath, true)) + // Convert the image data to WebP format + var webpData = FaviconHelper.TryConvertToWebp(imageData); + if (webpData != null) { - FaviconHelper.SaveBitmapData(imageData, faviconPath); - } + var faviconPath = Path.Combine(_faviconCacheDir, $"firefox_{domain}_{iconId}.webp"); - bookmark.FaviconPath = faviconPath; + if (savedPaths.TryAdd(faviconPath, true)) + { + FaviconHelper.SaveBitmapData(webpData, faviconPath); + } + + bookmark.FaviconPath = faviconPath; + } } catch (Exception ex) { - Main._context.API.LogException(ClassName, $"Failed to extract Firefox favicon: {bookmark.Url}", ex); + Main.Context.API.LogException(ClassName, $"Failed to extract Firefox favicon: {bookmark.Url}", ex); } finally { diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj index 953b7a54e..7d3cf164c 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj @@ -45,12 +45,14 @@ $(OutputPath)runtimes\linux-musl-arm; $(OutputPath)runtimes\linux-musl-arm64; $(OutputPath)runtimes\linux-musl-x64; + $(OutputPath)runtimes\linux-musl-s390x; $(OutputPath)runtimes\linux-ppc64le; $(OutputPath)runtimes\linux-s390x; $(OutputPath)runtimes\linux-x64; $(OutputPath)runtimes\linux-x86; $(OutputPath)runtimes\maccatalyst-arm64; $(OutputPath)runtimes\maccatalyst-x64; + $(OutputPath)runtimes\osx; $(OutputPath)runtimes\osx-arm64; $(OutputPath)runtimes\osx-x64"/> @@ -64,12 +66,14 @@ $(PublishDir)runtimes\linux-musl-arm; $(PublishDir)runtimes\linux-musl-arm64; $(PublishDir)runtimes\linux-musl-x64; + $(PublishDir)runtimes\linux-musl-s390x; $(PublishDir)runtimes\linux-ppc64le; $(PublishDir)runtimes\linux-s390x; $(PublishDir)runtimes\linux-x64; $(PublishDir)runtimes\linux-x86; $(PublishDir)runtimes\maccatalyst-arm64; $(PublishDir)runtimes\maccatalyst-x64; + $(PublishDir)runtimes\osx; $(PublishDir)runtimes\osx-arm64; $(PublishDir)runtimes\osx-x64"/> @@ -81,7 +85,6 @@ - @@ -96,7 +99,10 @@ - + + + + diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Helper/FaviconHelper.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Helper/FaviconHelper.cs index a879dcefd..7f17dc6bf 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Helper/FaviconHelper.cs +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Helper/FaviconHelper.cs @@ -1,5 +1,7 @@ using System; using System.IO; +using SkiaSharp; +using Svg.Skia; namespace Flow.Launcher.Plugin.BrowserBookmark.Helper; @@ -27,9 +29,9 @@ public static class FaviconHelper } catch (Exception ex1) { - Main._context.API.LogException(ClassName, $"Failed to delete temporary favicon DB: {tempDbPath}", ex1); + Main.Context.API.LogException(ClassName, $"Failed to delete temporary favicon DB: {tempDbPath}", ex1); } - Main._context.API.LogException(ClassName, $"Failed to copy favicon DB: {dbPath}", ex); + Main.Context.API.LogException(ClassName, $"Failed to copy favicon DB: {dbPath}", ex); return; } @@ -39,7 +41,7 @@ public static class FaviconHelper } catch (Exception ex) { - Main._context.API.LogException(ClassName, $"Failed to connect to SQLite: {tempDbPath}", ex); + Main.Context.API.LogException(ClassName, $"Failed to connect to SQLite: {tempDbPath}", ex); } // Delete temporary file @@ -49,7 +51,7 @@ public static class FaviconHelper } catch (Exception ex) { - Main._context.API.LogException(ClassName, $"Failed to delete temporary favicon DB: {tempDbPath}", ex); + Main.Context.API.LogException(ClassName, $"Failed to delete temporary favicon DB: {tempDbPath}", ex); } } @@ -61,16 +63,62 @@ public static class FaviconHelper } catch (Exception ex) { - Main._context.API.LogException(ClassName, $"Failed to save image: {outputPath}", ex); + Main.Context.API.LogException(ClassName, $"Failed to save image: {outputPath}", ex); } } - public static bool IsSvgData(byte[] data) + public static byte[] TryConvertToWebp(byte[] data) { - if (data.Length < 5) - return false; - string start = System.Text.Encoding.ASCII.GetString(data, 0, Math.Min(100, data.Length)); - return start.Contains("(); @@ -42,7 +42,7 @@ public class Main : ISettingProvider, IPlugin, IReloadable, IPluginI18n, IContex private static void LoadBookmarksIfEnabled() { - if (_context.CurrentPluginMetadata.Disabled) + if (Context.CurrentPluginMetadata.Disabled) { // Don't load or monitor files if disabled return; @@ -84,7 +84,7 @@ public class Main : ISettingProvider, IPlugin, IReloadable, IPluginI18n, IContex Score = BookmarkLoader.MatchProgram(c, param).Score, Action = _ => { - _context.API.OpenUrl(c.Url); + Context.API.OpenUrl(c.Url); return true; }, @@ -108,7 +108,7 @@ public class Main : ISettingProvider, IPlugin, IReloadable, IPluginI18n, IContex Score = 5, Action = _ => { - _context.API.OpenUrl(c.Url); + Context.API.OpenUrl(c.Url); return true; }, ContextData = new BookmarkAttributes { Url = c.Url } @@ -192,12 +192,12 @@ public class Main : ISettingProvider, IPlugin, IReloadable, IPluginI18n, IContex public string GetTranslatedPluginTitle() { - return _context.API.GetTranslation("flowlauncher_plugin_browserbookmark_plugin_name"); + return Localize.flowlauncher_plugin_browserbookmark_plugin_name(); } public string GetTranslatedPluginDescription() { - return _context.API.GetTranslation("flowlauncher_plugin_browserbookmark_plugin_description"); + return Localize.flowlauncher_plugin_browserbookmark_plugin_description(); } public Control CreateSettingPanel() @@ -211,20 +211,20 @@ public class Main : ISettingProvider, IPlugin, IReloadable, IPluginI18n, IContex { new() { - Title = _context.API.GetTranslation("flowlauncher_plugin_browserbookmark_copyurl_title"), - SubTitle = _context.API.GetTranslation("flowlauncher_plugin_browserbookmark_copyurl_subtitle"), + Title = Localize.flowlauncher_plugin_browserbookmark_copyurl_title(), + SubTitle = Localize.flowlauncher_plugin_browserbookmark_copyurl_subtitle(), Action = _ => { try { - _context.API.CopyToClipboard(((BookmarkAttributes)selectedResult.ContextData).Url); + Context.API.CopyToClipboard(((BookmarkAttributes)selectedResult.ContextData).Url); return true; } catch (Exception e) { - _context.API.LogException(ClassName, "Failed to set url in clipboard", e); - _context.API.ShowMsgError(_context.API.GetTranslation("flowlauncher_plugin_browserbookmark_copy_failed")); + Context.API.LogException(ClassName, "Failed to set url in clipboard", e); + Context.API.ShowMsgError(Localize.flowlauncher_plugin_browserbookmark_copy_failed()); return false; } }, diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Models/CustomBrowser.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Models/CustomBrowser.cs index 74e0f299a..af1e3fee4 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Models/CustomBrowser.cs +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Models/CustomBrowser.cs @@ -1,4 +1,7 @@ -namespace Flow.Launcher.Plugin.BrowserBookmark.Models; +using System.Collections.Generic; +using Flow.Launcher.Localization.Attributes; + +namespace Flow.Launcher.Plugin.BrowserBookmark.Models; public class CustomBrowser : BaseModel { @@ -11,8 +14,11 @@ public class CustomBrowser : BaseModel get => _name; set { - _name = value; - OnPropertyChanged(); + if (_name != value) + { + _name = value; + OnPropertyChanged(); + } } } @@ -21,24 +27,36 @@ public class CustomBrowser : BaseModel get => _dataDirectoryPath; set { - _dataDirectoryPath = value; - OnPropertyChanged(); + if (_dataDirectoryPath != value) + { + _dataDirectoryPath = value; + OnPropertyChanged(); + } } } + public List AllBrowserTypes { get; } = BrowserTypeLocalized.GetValues(); + public BrowserType BrowserType { get => _browserType; set { - _browserType = value; - OnPropertyChanged(); + if (_browserType != value) + { + _browserType = value; + OnPropertyChanged(); + } } } } +[EnumLocalize] public enum BrowserType { + [EnumLocalizeValue("Chromium")] Chromium, + + [EnumLocalizeValue("Firefox")] Firefox, } diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Views/CustomBrowserSetting.xaml b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Views/CustomBrowserSetting.xaml index 80b004ff9..f67d359bf 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Views/CustomBrowserSetting.xaml +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Views/CustomBrowserSetting.xaml @@ -5,7 +5,6 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:Flow.Launcher.Plugin.BrowserBookmark.Models" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:ui="clr-namespace:Flow.Launcher.Infrastructure.UI;assembly=Flow.Launcher.Infrastructure" Title="{DynamicResource flowlauncher_plugin_browserbookmark_bookmarkDataSetting}" Width="550" Background="{DynamicResource PopuBGColor}" @@ -142,8 +141,10 @@ Margin="5 10 10 0" HorizontalAlignment="Left" VerticalAlignment="Center" - ItemsSource="{Binding Source={ui:EnumBindingSource {x:Type local:BrowserType}}}" - SelectedItem="{Binding BrowserType}" /> + DisplayMemberPath="Display" + ItemsSource="{Binding AllBrowserTypes}" + SelectedValue="{Binding BrowserType}" + SelectedValuePath="Value" /> - @@ -63,6 +62,7 @@ + diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/ar.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/ar.xaml index 3219d647e..d38f136a6 100644 --- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/ar.xaml +++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/ar.xaml @@ -1,15 +1,15 @@  - آلة حاسبة - تمكنك من إجراء العمليات الحسابية. (جرب 5*3-2 في Flow Launcher) + آلة حاسبة + تمكنك من إجراء العمليات الحسابية. (جرب 5*3-2 في Flow Launcher) ليست رقمًا (NaN) التعبير خاطئ أو غير مكتمل (هل نسيت بعض الأقواس؟) نسخ هذا الرقم إلى الحافظة - فاصل عشري - الفاصل العشري الذي سيتم استخدامه في الناتج. - استخدام إعدادات النظام المحلية - فاصلة (,) - نقطة (.) + فاصل عشري + الفاصل العشري الذي سيتم استخدامه في الناتج. + استخدام إعدادات النظام المحلية + فاصلة (,) + نقطة (.) أقصى عدد من المنازل العشرية diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/cs.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/cs.xaml index ed8cb3fdb..56b908031 100644 --- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/cs.xaml +++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/cs.xaml @@ -1,15 +1,15 @@  - Kalkulačka - Umožňuje provádět matematické výpočty.(Try 5*3-2 v průtokovém spouštěči) + Kalkulačka + Umožňuje provádět matematické výpočty.(Try 5*3-2 v průtokovém spouštěči) Není číslo (NaN) Nesprávný nebo neúplný výraz (Nezapomněli jste na závorky?) Kopírování výsledku do schránky - Oddělovač desetinných míst - Oddělovač desetinných míst použitý ve výsledku. - Použít podle systému - Čárka (,) - Tečka (.) + Oddělovač desetinných míst + Oddělovač desetinných míst použitý ve výsledku. + Použít podle systému + Čárka (,) + Tečka (.) Desetinná místa diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/da.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/da.xaml index 15598118c..c5690a3d5 100644 --- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/da.xaml +++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/da.xaml @@ -1,15 +1,15 @@  - Calculator - Allows to do mathematical calculations.(Try 5*3-2 in Flow Launcher) + Calculator + Allows to do mathematical calculations.(Try 5*3-2 in Flow Launcher) Not a number (NaN) Expression wrong or incomplete (Did you forget some parentheses?) Copy this number to the clipboard - Decimal separator - The decimal separator to be used in the output. - Use system locale - Comma (,) - Dot (.) + Decimal separator + The decimal separator to be used in the output. + Use system locale + Comma (,) + Dot (.) Max. decimal places diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/de.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/de.xaml index d8da714dc..9b8654962 100644 --- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/de.xaml +++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/de.xaml @@ -1,15 +1,15 @@  - Rechner - Ermöglicht mathematische Berechnungen. (Versuchen Sie 5*3-2 in Flow Launcher) + Rechner + Ermöglicht mathematische Berechnungen. (Versuchen Sie 5*3-2 in Flow Launcher) Nicht eine Zahl (NaN) Ausdruck falsch oder unvollständig (Haben Sie einige Klammern vergessen?) Diese Zahl in die Zwischenablage kopieren - Dezimaltrennzeichen - Das Dezimaltrennzeichen, das in der Ausgabe verwendet werden soll. - Systemgebietsschema verwenden - Komma (,) - Punkt (.) + Dezimaltrennzeichen + Das Dezimaltrennzeichen, das in der Ausgabe verwendet werden soll. + Systemgebietsschema verwenden + Komma (,) + Punkt (.) Max. Dezimalstellen diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/en.xaml index e646bab0e..b71e5d8a0 100644 --- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/en.xaml +++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/en.xaml @@ -3,16 +3,16 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:system="clr-namespace:System;assembly=mscorlib"> - Calculator - Allows to do mathematical calculations.(Try 5*3-2 in Flow Launcher) + Calculator + Perform mathematical calculations (including hexadecimal values). Use ',' or '.' as thousand separator or decimal place. Not a number (NaN) Expression wrong or incomplete (Did you forget some parentheses?) Copy this number to the clipboard - Decimal separator - The decimal separator to be used in the output. - Use system locale - Comma (,) - Dot (.) + Decimal separator + The decimal separator to be used in the output. + Use system locale + Comma (,) + Dot (.) Max. decimal places Copy failed, please try later \ No newline at end of file diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/es-419.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/es-419.xaml index 685bc136c..6b69c06a4 100644 --- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/es-419.xaml +++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/es-419.xaml @@ -1,15 +1,15 @@  - Calculadora - Permite hacer cálculos matemáticos. (Pruebe con 5*3-2 en Flow Launcher) + Calculadora + Permite hacer cálculos matemáticos. (Pruebe con 5*3-2 en Flow Launcher) No es un número (NaN) Expresión incorrecta o incompleta (¿Olvidó algún paréntesis?) Copiar este número al portapapeles - Separador decimal - El separador decimal que se usará en el resultado. - Usar configuración del sistema - Coma (,) - Punto (.) + Separador decimal + El separador decimal que se usará en el resultado. + Usar configuración del sistema + Coma (,) + Punto (.) Número máximo de decimales diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/es.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/es.xaml index 657c471d5..3dfdff680 100644 --- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/es.xaml +++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/es.xaml @@ -1,15 +1,15 @@  - Calculadora - Permite hacer cálculos matemáticos. (Pruebe 5*3-2 en Flow Launcher) + Calculadora + Permite hacer cálculos matemáticos. (Pruebe 5*3-2 en Flow Launcher) No es un número (NaN) Expresión incorrecta o incompleta (¿Ha olvidado algunos paréntesis?) Copiar este número al portapapeles - Separador decimal - El separador decimal que se utilizará en la salida. - Usar configuración regional del sistema - Coma (,) - Punto (.) + Separador decimal + El separador decimal que se utilizará en la salida. + Usar configuración regional del sistema + Coma (,) + Punto (.) Número máximo de decimales diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/fr.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/fr.xaml index c462ccc43..a86c020be 100644 --- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/fr.xaml +++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/fr.xaml @@ -1,15 +1,15 @@  - Calculatrice - Permet de faire des calculs mathématiques.(Essayez 5*3-2 dans Flow Launcher) + Calculatrice + Permet de faire des calculs mathématiques.(Essayez 5*3-2 dans Flow Launcher) Pas un nombre (NaN) Expression incorrecte ou incomplète (avez-vous oublié certaines parenthèses ?) Copier ce chiffre dans le presse-papiers - Séparateur décimal - Le séparateur décimal à utiliser dans la sortie. - Utiliser les paramètres régionaux du système - Virgule (,) - Point (.) + Séparateur décimal + Le séparateur décimal à utiliser dans la sortie. + Utiliser les paramètres régionaux du système + Virgule (,) + Point (.) Décimales max. diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/he.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/he.xaml index 9fe80bc47..1d297381c 100644 --- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/he.xaml +++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/he.xaml @@ -1,15 +1,15 @@  - מחשבון - מאפשר לבצע חישובים מתמטיים. (נסה 5*3-2 ב-Flow Launcher) + מחשבון + מאפשר לבצע חישובים מתמטיים. (נסה 5*3-2 ב-Flow Launcher) לא מספר (NaN) הביטוי שגוי או לא שלם (האם שכחת סוגריים?) העתק מספר זה ללוח - מפריד עשרוני - מפריד עשרוני שישמש בתוצאה. - השתמש בהגדרת מערכת - פסיק (,) - נקודה (.) + מפריד עשרוני + מפריד עשרוני שישמש בתוצאה. + השתמש בהגדרת מערכת + פסיק (,) + נקודה (.) מספר מקסימלי של מקומות עשרוניים diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/it.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/it.xaml index fa4651a97..27bd75304 100644 --- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/it.xaml +++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/it.xaml @@ -1,15 +1,15 @@  - Calcolatrice - Consente di eseguire calcoli matematici (provare 5*3-2 in Flow Launcher) + Calcolatrice + Consente di eseguire calcoli matematici (provare 5*3-2 in Flow Launcher) Non è un numero (NaN) Espressione sbagliata o incompleta (avete dimenticato delle parentesi?) Copiare questo numero negli appunti - Separatore decimale - Il separatore decimale da usare nell'output. - Usa il locale del sistema - Virgola (,) - Punto (.) + Separatore decimale + Il separatore decimale da usare nell'output. + Usa il locale del sistema + Virgola (,) + Punto (.) Max. cifre decimali diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/ja.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/ja.xaml index 757394b4c..30bae550a 100644 --- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/ja.xaml +++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/ja.xaml @@ -1,15 +1,15 @@  - 電卓 - 数式の計算ができます(Flow Launcherで「5*3-2」と入力してみてください) + 電卓 + 数式の計算ができます(Flow Launcherで「5*3-2」と入力してみてください) Not a number (NaN) Expression wrong or incomplete (Did you forget some parentheses?) この数字をクリップボードにコピーします - Decimal separator - The decimal separator to be used in the output. - Use system locale - Comma (,) - Dot (.) + Decimal separator + The decimal separator to be used in the output. + Use system locale + Comma (,) + Dot (.) Max. decimal places diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/ko.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/ko.xaml index ee2ae77a1..30e9b40a0 100644 --- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/ko.xaml +++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/ko.xaml @@ -1,15 +1,15 @@  - 계산기 - 수학 계산을 할 수 있습니다. Flow Launcher에서 5*3-2를 입력해보세요. + 계산기 + 수학 계산을 할 수 있습니다. Flow Launcher에서 5*3-2를 입력해보세요. 숫자가 아님 (NaN) 표현식이 잘못되었거나 불완전합니다. (괄호를 깜빡하셨나요?) 해당 숫자를 클립보드에 복사 - 소수 구분자 - 출력에 사용할 소수점 구분자 - 시스템 설정 사용 - 쉼표 (,) - 마침표 (.) + 소수 구분자 + 출력에 사용할 소수점 구분자 + 시스템 설정 사용 + 쉼표 (,) + 마침표 (.) 최대 소수점 아래 자릿 수 diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/nb.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/nb.xaml index 527df1d21..be233767f 100644 --- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/nb.xaml +++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/nb.xaml @@ -1,15 +1,15 @@  - Kalkulator - Lar deg gjøre matematiske beregninger. (Prøv 5*3-2 i Flow Launcher) + Kalkulator + Lar deg gjøre matematiske beregninger. (Prøv 5*3-2 i Flow Launcher) Ikke et tall (NaN) Uttrykk feil eller ufullstendig (glem noen parenteser?) Kopier dette nummeret til utklippstavlen - Desimalskille - Desimalskilletegnet som skal brukes i utdataene. - Bruk systemets nasjonale innstilling - Komma (,) - Prikk (.) + Desimalskille + Desimalskilletegnet som skal brukes i utdataene. + Bruk systemets nasjonale innstilling + Komma (,) + Prikk (.) Maks. desimaler diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/nl.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/nl.xaml index 15598118c..c5690a3d5 100644 --- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/nl.xaml +++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/nl.xaml @@ -1,15 +1,15 @@  - Calculator - Allows to do mathematical calculations.(Try 5*3-2 in Flow Launcher) + Calculator + Allows to do mathematical calculations.(Try 5*3-2 in Flow Launcher) Not a number (NaN) Expression wrong or incomplete (Did you forget some parentheses?) Copy this number to the clipboard - Decimal separator - The decimal separator to be used in the output. - Use system locale - Comma (,) - Dot (.) + Decimal separator + The decimal separator to be used in the output. + Use system locale + Comma (,) + Dot (.) Max. decimal places diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/pl.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/pl.xaml index f697d2e6d..75b52685a 100644 --- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/pl.xaml +++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/pl.xaml @@ -1,15 +1,15 @@  - Kalkulator - Szybkie wykonywanie obliczeń matematycznych. (Spróbuj wpisać 5*3-2 w oknie Flow Launchera) + Kalkulator + Szybkie wykonywanie obliczeń matematycznych. (Spróbuj wpisać 5*3-2 w oknie Flow Launchera) Nie liczba (NaN) Wyrażenie niepoprawne lub niekompletne (Czy zapomniałeś o nawiasach?) Skopiuj ten numer do schowka - Separator dziesiętny - Separator dziesiętny używany w wyniku. - Użyj ustawień regionalnych systemu - Przecinek (,) - Kropka (.) + Separator dziesiętny + Separator dziesiętny używany w wyniku. + Użyj ustawień regionalnych systemu + Przecinek (,) + Kropka (.) Maks. liczba miejsc po przecinku diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/pt-br.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/pt-br.xaml index 6dd903fa4..9b6f3708a 100644 --- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/pt-br.xaml +++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/pt-br.xaml @@ -1,15 +1,15 @@  - Calculadora - Permite fazer cálculos matemáticos.(Tente 5*3-2 no Flow Launcher) + Calculadora + Permite fazer cálculos matemáticos.(Tente 5*3-2 no Flow Launcher) Não é um número (NaN) Expressão errada ou incompleta (Você esqueceu de adicionar parênteses?) Copiar este numero para a área de transferência - Separador decimal - O separador decimal a ser usado no resultado. - Use system locale - Vírgula (,) - Ponto (.) + Separador decimal + O separador decimal a ser usado no resultado. + Use system locale + Vírgula (,) + Ponto (.) Max. decimal places diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/pt-pt.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/pt-pt.xaml index b751f3f39..7b48d6fe9 100644 --- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/pt-pt.xaml +++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/pt-pt.xaml @@ -1,15 +1,15 @@  - Calculadora - Permite a execução de cálculos matemáticos (experimente 5*3-2) + Calculadora + Permite a execução de cálculos matemáticos (experimente 5*3-2) Não é número (NN) Expressão errada ou incompleta (esqueceu-se de algum parêntese?) Copiar número para a área de transferência - Separador decimal - O separador decimal para utilizar no resultado. - Utilizar definições do sistema - Vírgula (,) - Ponto (.) + Separador decimal + O separador decimal para utilizar no resultado. + Utilizar definições do sistema + Vírgula (,) + Ponto (.) Número máximo de casas decimais diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/ru.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/ru.xaml index 30c557536..d1d03d604 100644 --- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/ru.xaml +++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/ru.xaml @@ -1,15 +1,15 @@  - Калькулятор - Позволяет выполнять математические вычисления. (Попробуйте 5*3-2 в Flow Launcher) + Калькулятор + Позволяет выполнять математические вычисления. (Попробуйте 5*3-2 в Flow Launcher) Не является числом (NaN) Выражение неправильное или неполное (Вы забыли скобки?) Скопировать этот номер в буфер обмена - Десятичный разделитель - Десятичный разделитель, который будет использоваться в результате. - Использовать системный язык - Запятая (,) - Точка (.) + Десятичный разделитель + Десятичный разделитель, который будет использоваться в результате. + Использовать системный язык + Запятая (,) + Точка (.) Макс. число знаков после запятой diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/sk.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/sk.xaml index d8d3a586f..b1cf4a735 100644 --- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/sk.xaml +++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/sk.xaml @@ -1,15 +1,15 @@  - Kalkulačka - Spracúva matematické operácie. (Skúste 5*3-2 vo Flow Launcheri) + Kalkulačka + Spracúva matematické operácie. (Skúste 5*3-2 vo Flow Launcheri) Nie je číslo (NaN) Nesprávny alebo neúplný výraz (Nezabudli ste na zátvorky?) Kopírovať výsledok do schránky - Oddeľovač desatinných miest - Oddeľovač desatinných miest použitý vo výsledku. - Použiť podľa systému - Čiarka (,) - Bodka (.) + Oddeľovač desatinných miest + Oddeľovač desatinných miest použitý vo výsledku. + Použiť podľa systému + Čiarka (,) + Bodka (.) Desatinné miesta diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/sr.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/sr.xaml index 15598118c..c5690a3d5 100644 --- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/sr.xaml +++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/sr.xaml @@ -1,15 +1,15 @@  - Calculator - Allows to do mathematical calculations.(Try 5*3-2 in Flow Launcher) + Calculator + Allows to do mathematical calculations.(Try 5*3-2 in Flow Launcher) Not a number (NaN) Expression wrong or incomplete (Did you forget some parentheses?) Copy this number to the clipboard - Decimal separator - The decimal separator to be used in the output. - Use system locale - Comma (,) - Dot (.) + Decimal separator + The decimal separator to be used in the output. + Use system locale + Comma (,) + Dot (.) Max. decimal places diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/tr.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/tr.xaml index 345c81433..f307c65e2 100644 --- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/tr.xaml +++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/tr.xaml @@ -1,15 +1,15 @@  - Hesap Makinesi - Matematiksel hesaplamalar yapmaya yarar. (5*3-2 yazmayı deneyin) + Hesap Makinesi + Matematiksel hesaplamalar yapmaya yarar. (5*3-2 yazmayı deneyin) Sayı değil (NaN) İfade hatalı ya da eksik. (Parantez koymayı mı unuttunuz?) Bu sayıyı panoya kopyala - Ondalık ayracı - Ondalık kısımları ayırmak için kullanılacak işaret. - Sistem yerelleştirme ayarını kullan - Virgül (,) - Nokta (.) + Ondalık ayracı + Ondalık kısımları ayırmak için kullanılacak işaret. + Sistem yerelleştirme ayarını kullan + Virgül (,) + Nokta (.) Maks. ondalık basamak diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/uk-UA.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/uk-UA.xaml index 014755929..9f60f570a 100644 --- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/uk-UA.xaml +++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/uk-UA.xaml @@ -1,15 +1,15 @@  - Калькулятор - Дозволяє виконувати математичні обчислення (спробуйте 5*3-2 у Flow Launcher) + Калькулятор + Дозволяє виконувати математичні обчислення (спробуйте 5*3-2 у Flow Launcher) Не є числом (NaN) Вираз неправильний або неповний (Ви забули якісь дужки?) Скопіюйте це число в буфер обміну - Десятковий роздільник - Десятковий роздільник, який буде використовуватися у виведенні. - Використовувати системну локаль - Кома (,) - Крапка (.) + Десятковий роздільник + Десятковий роздільник, який буде використовуватися у виведенні. + Використовувати системну локаль + Кома (,) + Крапка (.) Макс. кількість знаків після коми diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/vi.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/vi.xaml index 82ebbbe93..688623b04 100644 --- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/vi.xaml +++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/vi.xaml @@ -1,15 +1,15 @@  - Máy tính - Cho phép thực hiện các phép tính toán học. (Thử 5*3-2 trong Flow Launcher) + Máy tính + Cho phép thực hiện các phép tính toán học. (Thử 5*3-2 trong Flow Launcher) Không phải là số (NaN) Biểu thức sai hoặc không đầy đủ (Bạn có quên một số dấu ngoặc đơn không?) Sao chép số này vào clipboard - Dấu tách thập phân - Dấu phân cách thập phân được sử dụng ở đầu ra. - Sử dụng ngôn ngữ hệ thống - Dấu phẩy (,) - dấu chấm (.) + Dấu tách thập phân + Dấu phân cách thập phân được sử dụng ở đầu ra. + Sử dụng ngôn ngữ hệ thống + Dấu phẩy (,) + dấu chấm (.) Tối đa. chữ số thập phân diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/zh-cn.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/zh-cn.xaml index aada17d5a..85159ed4f 100644 --- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/zh-cn.xaml +++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/zh-cn.xaml @@ -1,15 +1,15 @@  - 计算器 - 为 Flow Launcher 提供数学计算能力。(试着在 Flow Launcher 输入 5*3-2) + 计算器 + 为 Flow Launcher 提供数学计算能力。(试着在 Flow Launcher 输入 5*3-2) 请输入数字 表达错误或不完整(您是否忘记了一些括号?) 将结果复制到剪贴板 - 十进制分隔符 - 在输出中使用的十进制分隔符 - 使用系统区域设置 - 逗号(,) - 点(.) + 十进制分隔符 + 在输出中使用的十进制分隔符 + 使用系统区域设置 + 逗号(,) + 点(.) 小数点后最大位数 diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/zh-tw.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/zh-tw.xaml index 83df3e7cd..d3d448e1c 100644 --- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/zh-tw.xaml +++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/zh-tw.xaml @@ -1,15 +1,15 @@  - 計算機 - 為 Flow Launcher 提供數學計算功能。(試著在 Flow Launcher 輸入 5*3-2) + 計算機 + 為 Flow Launcher 提供數學計算功能。(試著在 Flow Launcher 輸入 5*3-2) 不是一個數 (NaN) Expression wrong or incomplete (Did you forget some parentheses?) 複製此數至剪貼簿 - 小數點分隔符號 - The decimal separator to be used in the output. - 使用系統區域設定 - 逗號 (,) - 點 (.) + 小數點分隔符號 + The decimal separator to be used in the output. + 使用系統區域設定 + 逗號 (,) + 點 (.) 小數點後最大位數 diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Main.cs b/Plugins/Flow.Launcher.Plugin.Calculator/Main.cs index 3d06c4ce0..6878c54b4 100644 --- a/Plugins/Flow.Launcher.Plugin.Calculator/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Calculator/Main.cs @@ -1,36 +1,41 @@ using System; using System.Collections.Generic; using System.Globalization; +using System.Linq; using System.Runtime.InteropServices; using System.Text.RegularExpressions; using System.Windows.Controls; using Mages.Core; -using Flow.Launcher.Plugin.Calculator.ViewModels; using Flow.Launcher.Plugin.Calculator.Views; +using Flow.Launcher.Plugin.Calculator.ViewModels; namespace Flow.Launcher.Plugin.Calculator { public class Main : IPlugin, IPluginI18n, ISettingProvider { - private static readonly Regex RegValidExpressChar = new Regex( - @"^(" + - @"ceil|floor|exp|pi|e|max|min|det|abs|log|ln|sqrt|" + - @"sin|cos|tan|arcsin|arccos|arctan|" + - @"eigval|eigvec|eig|sum|polar|plot|round|sort|real|zeta|" + - @"bin2dec|hex2dec|oct2dec|" + - @"factorial|sign|isprime|isinfty|" + - @"==|~=|&&|\|\||(?:\<|\>)=?|" + - @"[ei]|[0-9]|0x[\da-fA-F]+|[\+\%\-\*\/\^\., ""]|[\(\)\|\!\[\]]" + - @")+$", RegexOptions.Compiled); - private static readonly Regex RegBrackets = new Regex(@"[\(\)\[\]]", RegexOptions.Compiled); + private static readonly Regex RegValidExpressChar = MainRegexHelper.GetRegValidExpressChar(); + private static readonly Regex RegBrackets = MainRegexHelper.GetRegBrackets(); + private static readonly Regex ThousandGroupRegex = MainRegexHelper.GetThousandGroupRegex(); + private static readonly Regex NumberRegex = MainRegexHelper.GetNumberRegex(); + private static Engine MagesEngine; - private const string comma = ","; - private const string dot = "."; + private const string Comma = ","; + private const string Dot = "."; - private PluginInitContext Context { get; set; } + internal static PluginInitContext Context { get; set; } = null!; - private static Settings _settings; - private static SettingsViewModel _viewModel; + private Settings _settings; + private SettingsViewModel _viewModel; + + /// + /// Holds the formatting information for a single query. + /// This is used to ensure thread safety by keeping query state local. + /// + private class ParsingContext + { + public string InputDecimalSeparator { get; set; } + public bool InputUsesGroupSeparators { get; set; } + } public void Init(PluginInitContext context) { @@ -54,33 +59,24 @@ namespace Flow.Launcher.Plugin.Calculator return new List(); } + var context = new ParsingContext(); + try { - string expression; - - switch (_settings.DecimalSeparator) - { - case DecimalSeparator.Comma: - case DecimalSeparator.UseSystemLocale when CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator == ",": - expression = query.Search.Replace(",", "."); - break; - default: - expression = query.Search; - break; - } + var expression = NumberRegex.Replace(query.Search, m => NormalizeNumber(m.Value, context)); var result = MagesEngine.Interpret(expression); if (result?.ToString() == "NaN") - result = Context.API.GetTranslation("flowlauncher_plugin_calculator_not_a_number"); + result = Localize.flowlauncher_plugin_calculator_not_a_number(); if (result is Function) - result = Context.API.GetTranslation("flowlauncher_plugin_calculator_expression_not_complete"); + result = Localize.flowlauncher_plugin_calculator_expression_not_complete(); if (!string.IsNullOrEmpty(result?.ToString())) { decimal roundedResult = Math.Round(Convert.ToDecimal(result), _settings.MaxDecimalPlaces, MidpointRounding.AwayFromZero); - string newResult = ChangeDecimalSeparator(roundedResult, GetDecimalSeparator()); + string newResult = FormatResult(roundedResult, context); return new List { @@ -89,7 +85,7 @@ namespace Flow.Launcher.Plugin.Calculator Title = newResult, IcoPath = "Images/calculator.png", Score = 300, - SubTitle = Context.API.GetTranslation("flowlauncher_plugin_calculator_copy_number_to_clipboard"), + SubTitle = Localize.flowlauncher_plugin_calculator_copy_number_to_clipboard(), CopyText = newResult, Action = c => { @@ -100,7 +96,7 @@ namespace Flow.Launcher.Plugin.Calculator } catch (ExternalException) { - Context.API.ShowMsgBox(Context.API.GetTranslation("flowlauncher_plugin_calculator_failed_to_copy")); + Context.API.ShowMsgBox(Localize.flowlauncher_plugin_calculator_failed_to_copy()); return false; } } @@ -116,9 +112,137 @@ namespace Flow.Launcher.Plugin.Calculator return new List(); } + /// + /// Parses a string representation of a number, detecting its format. It uses structural analysis + /// and falls back to system culture for truly ambiguous cases (e.g., "1,234"). + /// It populates the provided ParsingContext with the detected format for later use. + /// + /// A normalized number string with '.' as the decimal separator for the Mages engine. + private string NormalizeNumber(string numberStr, ParsingContext context) + { + var systemGroupSep = CultureInfo.CurrentCulture.NumberFormat.NumberGroupSeparator; + int dotCount = numberStr.Count(f => f == '.'); + int commaCount = numberStr.Count(f => f == ','); + + // Case 1: Unambiguous mixed separators (e.g., "1.234,56") + if (dotCount > 0 && commaCount > 0) + { + context.InputUsesGroupSeparators = true; + if (numberStr.LastIndexOf('.') > numberStr.LastIndexOf(',')) + { + context.InputDecimalSeparator = Dot; + return numberStr.Replace(Comma, string.Empty); + } + else + { + context.InputDecimalSeparator = Comma; + return numberStr.Replace(Dot, string.Empty).Replace(Comma, Dot); + } + } + + // Case 2: Only dots + if (dotCount > 0) + { + if (dotCount > 1) + { + context.InputUsesGroupSeparators = true; + return numberStr.Replace(Dot, string.Empty); + } + // A number is ambiguous if it has a single Dot in the thousands position, + // and does not start with a "0." or "." + bool isAmbiguous = numberStr.Length - numberStr.LastIndexOf('.') == 4 + && !numberStr.StartsWith("0.") + && !numberStr.StartsWith("."); + if (isAmbiguous) + { + if (systemGroupSep == Dot) + { + context.InputUsesGroupSeparators = true; + return numberStr.Replace(Dot, string.Empty); + } + else + { + context.InputDecimalSeparator = Dot; + return numberStr; + } + } + else // Unambiguous decimal (e.g., "12.34" or "0.123" or ".123") + { + context.InputDecimalSeparator = Dot; + return numberStr; + } + } + + // Case 3: Only commas + if (commaCount > 0) + { + if (commaCount > 1) + { + context.InputUsesGroupSeparators = true; + return numberStr.Replace(Comma, string.Empty); + } + // A number is ambiguous if it has a single Comma in the thousands position, + // and does not start with a "0," or "," + bool isAmbiguous = numberStr.Length - numberStr.LastIndexOf(',') == 4 + && !numberStr.StartsWith("0,") + && !numberStr.StartsWith(","); + if (isAmbiguous) + { + if (systemGroupSep == Comma) + { + context.InputUsesGroupSeparators = true; + return numberStr.Replace(Comma, string.Empty); + } + else + { + context.InputDecimalSeparator = Comma; + return numberStr.Replace(Comma, Dot); + } + } + else // Unambiguous decimal (e.g., "12,34" or "0,123" or ",123") + { + context.InputDecimalSeparator = Comma; + return numberStr.Replace(Comma, Dot); + } + } + + // Case 4: No separators + return numberStr; + } + + private string FormatResult(decimal roundedResult, ParsingContext context) + { + string decimalSeparator = context.InputDecimalSeparator ?? GetDecimalSeparator(); + string groupSeparator = GetGroupSeparator(decimalSeparator); + + string resultStr = roundedResult.ToString(CultureInfo.InvariantCulture); + + string[] parts = resultStr.Split('.'); + string integerPart = parts[0]; + string fractionalPart = parts.Length > 1 ? parts[1] : string.Empty; + + if (context.InputUsesGroupSeparators && integerPart.Length > 3) + { + integerPart = ThousandGroupRegex.Replace(integerPart, groupSeparator); + } + + if (!string.IsNullOrEmpty(fractionalPart)) + { + return integerPart + decimalSeparator + fractionalPart; + } + + return integerPart; + } + + private string GetGroupSeparator(string decimalSeparator) + { + // This logic is now independent of the system's group separator + // to ensure consistent output for unit testing. + return decimalSeparator == Dot ? Comma : Dot; + } + private bool CanCalculate(Query query) { - // Don't execute when user only input "e" or "i" keyword if (query.Search.Length < 2) { return false; @@ -134,40 +258,22 @@ namespace Flow.Launcher.Plugin.Calculator return false; } - if ((query.Search.Contains(dot) && GetDecimalSeparator() != dot) || - (query.Search.Contains(comma) && GetDecimalSeparator() != comma)) - return false; - return true; } - private string ChangeDecimalSeparator(decimal value, string newDecimalSeparator) - { - if (String.IsNullOrEmpty(newDecimalSeparator)) - { - return value.ToString(); - } - - var numberFormatInfo = new NumberFormatInfo - { - NumberDecimalSeparator = newDecimalSeparator - }; - return value.ToString(numberFormatInfo); - } - - private static string GetDecimalSeparator() + private string GetDecimalSeparator() { string systemDecimalSeparator = CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator; return _settings.DecimalSeparator switch { DecimalSeparator.UseSystemLocale => systemDecimalSeparator, - DecimalSeparator.Dot => dot, - DecimalSeparator.Comma => comma, + DecimalSeparator.Dot => Dot, + DecimalSeparator.Comma => Comma, _ => systemDecimalSeparator, }; } - private bool IsBracketComplete(string query) + private static bool IsBracketComplete(string query) { var matchs = RegBrackets.Matches(query); var leftBracketCount = 0; @@ -188,17 +294,22 @@ namespace Flow.Launcher.Plugin.Calculator public string GetTranslatedPluginTitle() { - return Context.API.GetTranslation("flowlauncher_plugin_caculator_plugin_name"); + return Localize.flowlauncher_plugin_calculator_plugin_name(); } public string GetTranslatedPluginDescription() { - return Context.API.GetTranslation("flowlauncher_plugin_caculator_plugin_description"); + return Localize.flowlauncher_plugin_calculator_plugin_description(); } public Control CreateSettingPanel() { - return new CalculatorSettings(_viewModel); + return new CalculatorSettings(_settings); + } + + public void OnCultureInfoChanged(CultureInfo newCulture) + { + DecimalSeparatorLocalized.UpdateLabels(_viewModel.AllDecimalSeparator); } } } diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/MainRegexHelper.cs b/Plugins/Flow.Launcher.Plugin.Calculator/MainRegexHelper.cs new file mode 100644 index 000000000..f4e2090e7 --- /dev/null +++ b/Plugins/Flow.Launcher.Plugin.Calculator/MainRegexHelper.cs @@ -0,0 +1,19 @@ +using System.Text.RegularExpressions; + +namespace Flow.Launcher.Plugin.Calculator; + +internal static partial class MainRegexHelper +{ + + [GeneratedRegex(@"[\(\)\[\]]", RegexOptions.Compiled)] + public static partial Regex GetRegBrackets(); + + [GeneratedRegex(@"^(ceil|floor|exp|pi|e|max|min|det|abs|log|ln|sqrt|sin|cos|tan|arcsin|arccos|arctan|eigval|eigvec|eig|sum|polar|plot|round|sort|real|zeta|bin2dec|hex2dec|oct2dec|factorial|sign|isprime|isinfty|==|~=|&&|\|\||(?:\<|\>)=?|[ei]|[0-9]|0x[\da-fA-F]+|[\+\%\-\*\/\^\., ""]|[\(\)\|\!\[\]])+$", RegexOptions.Compiled)] + public static partial Regex GetRegValidExpressChar(); + + [GeneratedRegex(@"[\d\.,]+", RegexOptions.Compiled)] + public static partial Regex GetNumberRegex(); + + [GeneratedRegex(@"\B(?=(\d{3})+(?!\d))", RegexOptions.Compiled)] + public static partial Regex GetThousandGroupRegex(); +} diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/NumberTranslator.cs b/Plugins/Flow.Launcher.Plugin.Calculator/NumberTranslator.cs deleted file mode 100644 index 4eacb9d34..000000000 --- a/Plugins/Flow.Launcher.Plugin.Calculator/NumberTranslator.cs +++ /dev/null @@ -1,91 +0,0 @@ -using System.Globalization; -using System.Text; -using System.Text.RegularExpressions; - -namespace Flow.Launcher.Plugin.Calculator -{ - /// - /// Tries to convert all numbers in a text from one culture format to another. - /// - public class NumberTranslator - { - private readonly CultureInfo sourceCulture; - private readonly CultureInfo targetCulture; - private readonly Regex splitRegexForSource; - private readonly Regex splitRegexForTarget; - - private NumberTranslator(CultureInfo sourceCulture, CultureInfo targetCulture) - { - this.sourceCulture = sourceCulture; - this.targetCulture = targetCulture; - - this.splitRegexForSource = GetSplitRegex(this.sourceCulture); - this.splitRegexForTarget = GetSplitRegex(this.targetCulture); - } - - /// - /// Create a new - returns null if no number conversion - /// is required between the cultures. - /// - /// source culture - /// target culture - /// - public static NumberTranslator Create(CultureInfo sourceCulture, CultureInfo targetCulture) - { - bool conversionRequired = sourceCulture.NumberFormat.NumberDecimalSeparator != targetCulture.NumberFormat.NumberDecimalSeparator - || sourceCulture.NumberFormat.PercentGroupSeparator != targetCulture.NumberFormat.PercentGroupSeparator - || sourceCulture.NumberFormat.NumberGroupSizes != targetCulture.NumberFormat.NumberGroupSizes; - return conversionRequired - ? new NumberTranslator(sourceCulture, targetCulture) - : null; - } - - /// - /// Translate from source to target culture. - /// - /// - /// - public string Translate(string input) - { - return this.Translate(input, this.sourceCulture, this.targetCulture, this.splitRegexForSource); - } - - /// - /// Translate from target to source culture. - /// - /// - /// - public string TranslateBack(string input) - { - return this.Translate(input, this.targetCulture, this.sourceCulture, this.splitRegexForTarget); - } - - private string Translate(string input, CultureInfo cultureFrom, CultureInfo cultureTo, Regex splitRegex) - { - var outputBuilder = new StringBuilder(); - - string[] tokens = splitRegex.Split(input); - foreach (string token in tokens) - { - decimal number; - outputBuilder.Append( - decimal.TryParse(token, NumberStyles.Number, cultureFrom, out number) - ? number.ToString(cultureTo) - : token); - } - - return outputBuilder.ToString(); - } - - private Regex GetSplitRegex(CultureInfo culture) - { - var splitPattern = $"((?:\\d|{Regex.Escape(culture.NumberFormat.NumberDecimalSeparator)}"; - if (!string.IsNullOrEmpty(culture.NumberFormat.NumberGroupSeparator)) - { - splitPattern += $"|{Regex.Escape(culture.NumberFormat.NumberGroupSeparator)}"; - } - splitPattern += ")+)"; - return new Regex(splitPattern); - } - } -} diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/ViewModels/SettingsViewModel.cs b/Plugins/Flow.Launcher.Plugin.Calculator/ViewModels/SettingsViewModel.cs index 09f745669..87ae72fb6 100644 --- a/Plugins/Flow.Launcher.Plugin.Calculator/ViewModels/SettingsViewModel.cs +++ b/Plugins/Flow.Launcher.Plugin.Calculator/ViewModels/SettingsViewModel.cs @@ -12,6 +12,21 @@ namespace Flow.Launcher.Plugin.Calculator.ViewModels public Settings Settings { get; init; } - public IEnumerable MaxDecimalPlacesRange => Enumerable.Range(1, 20); + public static IEnumerable MaxDecimalPlacesRange => Enumerable.Range(1, 20); + + public List AllDecimalSeparator { get; } = DecimalSeparatorLocalized.GetValues(); + + public DecimalSeparator SelectedDecimalSeparator + { + get => Settings.DecimalSeparator; + set + { + if (Settings.DecimalSeparator != value) + { + Settings.DecimalSeparator = value; + OnPropertyChanged(); + } + } + } } } diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Views/CalculatorSettings.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Views/CalculatorSettings.xaml index ceee3897c..8d240ef39 100644 --- a/Plugins/Flow.Launcher.Plugin.Calculator/Views/CalculatorSettings.xaml +++ b/Plugins/Flow.Launcher.Plugin.Calculator/Views/CalculatorSettings.xaml @@ -3,20 +3,14 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:calculator="clr-namespace:Flow.Launcher.Plugin.Calculator" - xmlns:core="clr-namespace:Flow.Launcher.Core.Resource;assembly=Flow.Launcher.Core" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:ui="clr-namespace:Flow.Launcher.Infrastructure.UI;assembly=Flow.Launcher.Infrastructure" xmlns:viewModels="clr-namespace:Flow.Launcher.Plugin.Calculator.ViewModels" + d:DataContext="{d:DesignInstance Type=viewModels:SettingsViewModel}" d:DesignHeight="450" d:DesignWidth="800" - Loaded="CalculatorSettings_Loaded" mc:Ignorable="d"> - - - - @@ -33,7 +27,7 @@ Margin="{StaticResource SettingPanelItemRightTopBottomMargin}" VerticalAlignment="Center" FontSize="14" - Text="{DynamicResource flowlauncher_plugin_calculator_output_decimal_seperator}" /> + Text="{DynamicResource flowlauncher_plugin_calculator_output_decimal_separator}" /> - - - - - - + DisplayMemberPath="Display" + ItemsSource="{Binding AllDecimalSeparator}" + SelectedValue="{Binding SelectedDecimalSeparator, Mode=TwoWay}" + SelectedValuePath="Value" /> LoadContextMenus(Result selectedResult) @@ -84,7 +81,7 @@ namespace Flow.Launcher.Plugin.Explorer Context.API.GetTranslation("plugin_explorer_addfilefoldersuccess_detail"), Constants.ExplorerIconImageFullPath); - ViewModel.Save(); + return true; }, @@ -108,7 +105,7 @@ namespace Flow.Launcher.Plugin.Explorer Context.API.GetTranslation("plugin_explorer_removefilefoldersuccess_detail"), Constants.ExplorerIconImageFullPath); - ViewModel.Save(); + return true; }, diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj b/Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj index b444fb8f6..2f24015ad 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj @@ -47,6 +47,7 @@ + diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Helper/SortOptionTranslationHelper.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Helper/SortOptionTranslationHelper.cs deleted file mode 100644 index 72f58f5b6..000000000 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Helper/SortOptionTranslationHelper.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Flow.Launcher.Plugin.Everything.Everything; -using JetBrains.Annotations; -using System; - -namespace Flow.Launcher.Plugin.Explorer.Helper; - -public static class SortOptionTranslationHelper -{ - [CanBeNull] - public static IPublicAPI API { get; internal set; } - - public static string GetTranslatedName(this SortOption sortOption) - { - const string prefix = "flowlauncher_plugin_everything_sort_by_"; - - ArgumentNullException.ThrowIfNull(API); - - var enumName = Enum.GetName(sortOption); - var splited = enumName!.Split('_'); - var name = string.Join('_', splited[..^1]); - var direction = splited[^1]; - - return $"{API.GetTranslation(prefix + name.ToLower())} {API.GetTranslation(prefix + direction.ToLower())}"; - } -} diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml index a2e26a0f0..16ef037cc 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml @@ -150,19 +150,32 @@ Warning: Everything service is not running Error while querying Everything Sort By - Name - Path - Size - Extension - Type Name - Date Created - Date Modified - Attributes - File List FileName - Run Count - Date Recently Changed - Date Accessed - Date Run + Name ↑ + Name ↓ + Path ↑ + Path ↓ + Size ↑ + Size ↓ + Extension ↑ + Extension ↓ + Type Name ↑ + Type Name ↓ + Date Created ↑ + Date Created ↓ + Date Modified ↑ + Date Modified ↓ + Attributes ↑ + Attributes ↓ + File List FileName ↑ + File List FileName ↓ + Run Count ↑ + Run Count ↓ + Date Recently Changed ↑ + Date Recently Changed ↓ + Date Accessed ↑ + Date Accessed ↓ + Date Run ↑ + Date Run ↓ Warning: This is not a Fast Sort option, searches may be slow diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Main.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Main.cs index fbaefa9d6..d93c6c77b 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Main.cs @@ -1,4 +1,4 @@ -using Flow.Launcher.Plugin.Explorer.Helper; +using Flow.Launcher.Plugin.Explorer.Helper; using Flow.Launcher.Plugin.Explorer.Search; using Flow.Launcher.Plugin.Explorer.Search.Everything; using Flow.Launcher.Plugin.Explorer.ViewModels; @@ -11,6 +11,7 @@ using System.Threading.Tasks; using System.Windows.Controls; using Flow.Launcher.Plugin.Explorer.Exceptions; using System.Linq; +using System.Globalization; namespace Flow.Launcher.Plugin.Explorer { @@ -22,7 +23,7 @@ namespace Flow.Launcher.Plugin.Explorer private SettingsViewModel viewModel; - private IContextMenu contextMenu; + private ContextMenu contextMenu; private SearchManager searchManager; @@ -41,12 +42,9 @@ namespace Flow.Launcher.Plugin.Explorer FillQuickAccessLinkNames(); viewModel = new SettingsViewModel(context, Settings); - - contextMenu = new ContextMenu(Context, Settings, viewModel); + contextMenu = new ContextMenu(Context, Settings); searchManager = new SearchManager(Settings, Context); ResultManager.Init(Context, Settings); - - SortOptionTranslationHelper.API = context.API; EverythingApiDllImport.Load(Path.Combine(Context.CurrentPluginMetadata.PluginDirectory, "EverythingSDK", Environment.Is64BitProcess ? "x64" : "x86")); @@ -100,6 +98,12 @@ namespace Flow.Launcher.Plugin.Explorer return Context.API.GetTranslation("plugin_explorer_plugin_description"); } + public void OnCultureInfoChanged(CultureInfo newCulture) + { + // Update labels for setting view model + EverythingSortOptionLocalized.UpdateLabels(viewModel.AllEverythingSortOptions); + } + private static void FillQuickAccessLinkNames() { // Legacy version does not have names for quick access links, so we fill them with the path name. diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs index 6159c9355..fd62566d5 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs @@ -1,5 +1,4 @@ -using Flow.Launcher.Plugin.Everything.Everything; -using Flow.Launcher.Plugin.Explorer.Search.Everything.Exceptions; +using Flow.Launcher.Plugin.Explorer.Search.Everything.Exceptions; using System; using System.Collections.Generic; using System.Runtime.CompilerServices; @@ -36,7 +35,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search.Everything /// /// Checks whether the sort option is Fast Sort. /// - public static bool IsFastSortOption(SortOption sortOption) + public static bool IsFastSortOption(EverythingSortOption sortOption) { var fastSortOptionEnabled = EverythingApiDllImport.Everything_IsFastSort(sortOption); @@ -112,7 +111,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search.Everything EverythingApiDllImport.Everything_SetSort(option.SortOption); EverythingApiDllImport.Everything_SetMatchPath(option.IsFullPathSearch); - if (option.SortOption == SortOption.RUN_COUNT_DESCENDING) + if (option.SortOption == EverythingSortOption.RUN_COUNT_DESCENDING) { EverythingApiDllImport.Everything_SetRequestFlags(EVERYTHING_REQUEST_FULL_PATH_AND_FILE_NAME | EVERYTHING_REQUEST_RUN_COUNT); } diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiDllImport.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiDllImport.cs index 5b80819fa..c952a980c 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiDllImport.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiDllImport.cs @@ -1,5 +1,4 @@ -using Flow.Launcher.Plugin.Everything.Everything; -using System; +using System; using System.IO; using System.Runtime.InteropServices; using System.Text; @@ -114,11 +113,11 @@ namespace Flow.Launcher.Plugin.Explorer.Search.Everything // Everything 1.4 [DllImport(DLL)] - public static extern void Everything_SetSort(SortOption dwSortType); + public static extern void Everything_SetSort(EverythingSortOption dwSortType); [DllImport(DLL)] - public static extern bool Everything_IsFastSort(SortOption dwSortType); + public static extern bool Everything_IsFastSort(EverythingSortOption dwSortType); [DllImport(DLL)] - public static extern SortOption Everything_GetSort(); + public static extern EverythingSortOption Everything_GetSort(); [DllImport(DLL)] public static extern uint Everything_GetResultListSort(); [DllImport(DLL)] diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchOption.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchOption.cs index 92b8e9623..d8b670a08 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchOption.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchOption.cs @@ -1,10 +1,8 @@ -using Flow.Launcher.Plugin.Everything.Everything; - -namespace Flow.Launcher.Plugin.Explorer.Search.Everything +namespace Flow.Launcher.Plugin.Explorer.Search.Everything { public record struct EverythingSearchOption( string Keyword, - SortOption SortOption, + EverythingSortOption SortOption, bool IsContentSearch = false, string ContentSearchKeyword = default, string ParentPath = default, diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSortOption.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSortOption.cs new file mode 100644 index 000000000..6a3d7cb67 --- /dev/null +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSortOption.cs @@ -0,0 +1,59 @@ +using Flow.Launcher.Localization.Attributes; + +namespace Flow.Launcher.Plugin.Explorer.Search.Everything +{ + [EnumLocalize] + public enum EverythingSortOption : uint + { + [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_everything_sort_by_name_ascending))] + NAME_ASCENDING = 1u, + [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_everything_sort_by_name_descending))] + NAME_DESCENDING = 2u, + [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_everything_sort_by_path_ascending))] + PATH_ASCENDING = 3u, + [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_everything_sort_by_path_descending))] + PATH_DESCENDING = 4u, + [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_everything_sort_by_size_ascending))] + SIZE_ASCENDING = 5u, + [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_everything_sort_by_size_descending))] + SIZE_DESCENDING = 6u, + [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_everything_sort_by_extension_ascending))] + EXTENSION_ASCENDING = 7u, + [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_everything_sort_by_extension_descending))] + EXTENSION_DESCENDING = 8u, + [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_everything_sort_by_type_name_ascending))] + TYPE_NAME_ASCENDING = 9u, + [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_everything_sort_by_type_name_descending))] + TYPE_NAME_DESCENDING = 10u, + [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_everything_sort_by_date_created_ascending))] + DATE_CREATED_ASCENDING = 11u, + [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_everything_sort_by_date_created_descending))] + DATE_CREATED_DESCENDING = 12u, + [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_everything_sort_by_date_modified_ascending))] + DATE_MODIFIED_ASCENDING = 13u, + [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_everything_sort_by_date_modified_descending))] + DATE_MODIFIED_DESCENDING = 14u, + [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_everything_sort_by_attributes_ascending))] + ATTRIBUTES_ASCENDING = 15u, + [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_everything_sort_by_attributes_descending))] + ATTRIBUTES_DESCENDING = 16u, + [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_everything_sort_by_file_list_filename_ascending))] + FILE_LIST_FILENAME_ASCENDING = 17u, + [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_everything_sort_by_file_list_filename_descending))] + FILE_LIST_FILENAME_DESCENDING = 18u, + [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_everything_sort_by_run_count_descending))] + RUN_COUNT_DESCENDING = 20u, + [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_everything_sort_by_date_recently_changed_ascending))] + DATE_RECENTLY_CHANGED_ASCENDING = 21u, + [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_everything_sort_by_date_recently_changed_descending))] + DATE_RECENTLY_CHANGED_DESCENDING = 22u, + [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_everything_sort_by_date_accessed_ascending))] + DATE_ACCESSED_ASCENDING = 23u, + [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_everything_sort_by_date_accessed_descending))] + DATE_ACCESSED_DESCENDING = 24u, + [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_everything_sort_by_date_run_ascending))] + DATE_RUN_ASCENDING = 25u, + [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_everything_sort_by_date_run_descending))] + DATE_RUN_DESCENDING = 26u + } +} diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/SortOption.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/SortOption.cs deleted file mode 100644 index 3c2fc3660..000000000 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/SortOption.cs +++ /dev/null @@ -1,31 +0,0 @@ -namespace Flow.Launcher.Plugin.Everything.Everything -{ - public enum SortOption : uint - { - NAME_ASCENDING = 1u, - NAME_DESCENDING = 2u, - PATH_ASCENDING = 3u, - PATH_DESCENDING = 4u, - SIZE_ASCENDING = 5u, - SIZE_DESCENDING = 6u, - EXTENSION_ASCENDING = 7u, - EXTENSION_DESCENDING = 8u, - TYPE_NAME_ASCENDING = 9u, - TYPE_NAME_DESCENDING = 10u, - DATE_CREATED_ASCENDING = 11u, - DATE_CREATED_DESCENDING = 12u, - DATE_MODIFIED_ASCENDING = 13u, - DATE_MODIFIED_DESCENDING = 14u, - ATTRIBUTES_ASCENDING = 15u, - ATTRIBUTES_DESCENDING = 16u, - FILE_LIST_FILENAME_ASCENDING = 17u, - FILE_LIST_FILENAME_DESCENDING = 18u, - RUN_COUNT_DESCENDING = 20u, - DATE_RECENTLY_CHANGED_ASCENDING = 21u, - DATE_RECENTLY_CHANGED_DESCENDING = 22u, - DATE_ACCESSED_ASCENDING = 23u, - DATE_ACCESSED_DESCENDING = 24u, - DATE_RUN_ASCENDING = 25u, - DATE_RUN_DESCENDING = 26u - } -} diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs index 77540f3a8..672e81d03 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs @@ -1,5 +1,4 @@ -using Flow.Launcher.Plugin.Everything.Everything; -using Flow.Launcher.Plugin.Explorer.Search; +using Flow.Launcher.Plugin.Explorer.Search; using Flow.Launcher.Plugin.Explorer.Search.Everything; using Flow.Launcher.Plugin.Explorer.Search.QuickAccessLinks; using Flow.Launcher.Plugin.Explorer.Search.WindowsIndex; @@ -145,10 +144,7 @@ namespace Flow.Launcher.Plugin.Explorer public string EverythingInstalledPath { get; set; } - [JsonIgnore] - public SortOption[] SortOptions { get; set; } = Enum.GetValues(); - - public SortOption SortOption { get; set; } = SortOption.NAME_ASCENDING; + public EverythingSortOption SortOption { get; set; } = EverythingSortOption.NAME_ASCENDING; public bool EnableEverythingContentSearch { get; set; } = false; diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs b/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs index bb17fc76c..9a2d30cb0 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs @@ -593,6 +593,22 @@ namespace Flow.Launcher.Plugin.Explorer.ViewModels #region Everything FastSortWarning + public List AllEverythingSortOptions = EverythingSortOptionLocalized.GetValues(); + + public EverythingSortOption SelectedEverythingSortOption + { + get => Settings.SortOption; + set + { + if (value == Settings.SortOption) + return; + Settings.SortOption = value; + OnPropertyChanged(); + OnPropertyChanged(nameof(FastSortWarningVisibility)); + OnPropertyChanged(nameof(SortOptionWarningMessage)); + } + } + public Visibility FastSortWarningVisibility { get @@ -613,6 +629,7 @@ namespace Flow.Launcher.Plugin.Explorer.ViewModels } } } + public string SortOptionWarningMessage { get @@ -622,15 +639,15 @@ namespace Flow.Launcher.Plugin.Explorer.ViewModels // this method is used to determine if Everything service is running because as at Everything v1.4.1 // the sdk does not provide a dedicated interface to determine if it is running. return EverythingApi.IsFastSortOption(Settings.SortOption) ? string.Empty - : Context.API.GetTranslation("flowlauncher_plugin_everything_nonfastsort_warning"); + : Localize.flowlauncher_plugin_everything_nonfastsort_warning(); } catch (IPCErrorException) { - return Context.API.GetTranslation("flowlauncher_plugin_everything_is_not_running"); + return Localize.flowlauncher_plugin_everything_is_not_running(); } catch (DllNotFoundException) { - return Context.API.GetTranslation("flowlauncher_plugin_everything_sdk_issue"); + return Localize.flowlauncher_plugin_everything_sdk_issue(); } } } diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Views/Converters/EverythingEnumNameConverter.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Views/Converters/EverythingEnumNameConverter.cs deleted file mode 100644 index e24b21dcd..000000000 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Views/Converters/EverythingEnumNameConverter.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Flow.Launcher.Plugin.Everything.Everything; -using Flow.Launcher.Plugin.Explorer.Helper; -using System; -using System.Globalization; -using System.Windows.Data; - -namespace Flow.Launcher.Plugin.Explorer.Views.Converters; - -public class EnumNameConverter : IValueConverter -{ - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - return value is SortOption option ? option.GetTranslatedName() : value; - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - throw new NotImplementedException(); - } -} \ No newline at end of file diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Views/ExplorerSettings.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Views/ExplorerSettings.xaml index 59373b4de..08abc3ba6 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Views/ExplorerSettings.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Views/ExplorerSettings.xaml @@ -2,7 +2,6 @@ x:Class="Flow.Launcher.Plugin.Explorer.Views.ExplorerSettings" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" - xmlns:converters="clr-namespace:Flow.Launcher.Plugin.Explorer.Views.Converters" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:qa="clr-namespace:Flow.Launcher.Plugin.Explorer.Search.QuickAccessLinks" @@ -74,8 +73,6 @@ - -