From f6d25aa94c7d1861a4636000c640de001776791f Mon Sep 17 00:00:00 2001 From: Yusyuriv Date: Tue, 16 Apr 2024 13:00:19 +0600 Subject: [PATCH 01/21] Code cleanup: Flow.Launcher.Plugin.BrowserBookmark --- .../ChromeBookmarkLoader.cs | 35 +- .../ChromiumBookmarkLoader.cs | 137 +++--- .../Commands/BookmarkLoader.cs | 87 ++-- .../CustomChromiumBookmarkLoader.cs | 27 +- .../CustomFirefoxBookmarkLoader.cs | 39 +- .../EdgeBookmarkLoader.cs | 31 +- .../FirefoxBookmarkLoader.cs | 211 +++++---- .../IBookmarkLoader.cs | 11 +- .../Main.cs | 422 +++++++++--------- .../Models/Bookmark.cs | 33 +- .../Models/CustomBrowser.cs | 73 ++- .../Models/Settings.cs | 21 +- .../Views/CustomBrowserSetting.xaml | 1 - .../Views/CustomBrowserSetting.xaml.cs | 83 ++-- .../Views/SettingsControl.xaml.cs | 197 ++++---- 15 files changed, 693 insertions(+), 715 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/ChromeBookmarkLoader.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/ChromeBookmarkLoader.cs index 09755fe0c..65757b802 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/ChromeBookmarkLoader.cs +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/ChromeBookmarkLoader.cs @@ -3,23 +3,22 @@ using System; using System.Collections.Generic; using System.IO; -namespace Flow.Launcher.Plugin.BrowserBookmark -{ - public class ChromeBookmarkLoader : ChromiumBookmarkLoader - { - public override List GetBookmarks() - { - return LoadChromeBookmarks(); - } +namespace Flow.Launcher.Plugin.BrowserBookmark; - private List LoadChromeBookmarks() - { - var bookmarks = new List(); - var platformPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); - bookmarks.AddRange(LoadBookmarks(Path.Combine(platformPath, @"Google\Chrome\User Data"), "Google Chrome")); - bookmarks.AddRange(LoadBookmarks(Path.Combine(platformPath, @"Google\Chrome SxS\User Data"), "Google Chrome Canary")); - bookmarks.AddRange(LoadBookmarks(Path.Combine(platformPath, @"Chromium\User Data"), "Chromium")); - return bookmarks; - } +public class ChromeBookmarkLoader : ChromiumBookmarkLoader +{ + public override List GetBookmarks() + { + return LoadChromeBookmarks(); } -} \ No newline at end of file + + private List LoadChromeBookmarks() + { + var bookmarks = new List(); + var platformPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); + bookmarks.AddRange(LoadBookmarks(Path.Combine(platformPath, @"Google\Chrome\User Data"), "Google Chrome")); + bookmarks.AddRange(LoadBookmarks(Path.Combine(platformPath, @"Google\Chrome SxS\User Data"), "Google Chrome Canary")); + bookmarks.AddRange(LoadBookmarks(Path.Combine(platformPath, @"Chromium\User Data"), "Chromium")); + return bookmarks; + } +} diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/ChromiumBookmarkLoader.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/ChromiumBookmarkLoader.cs index 8ce597b30..48acf6109 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/ChromiumBookmarkLoader.cs +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/ChromiumBookmarkLoader.cs @@ -4,91 +4,90 @@ using System.IO; using System.Text.Json; using Flow.Launcher.Infrastructure.Logger; -namespace Flow.Launcher.Plugin.BrowserBookmark +namespace Flow.Launcher.Plugin.BrowserBookmark; + +public abstract class ChromiumBookmarkLoader : IBookmarkLoader { - public abstract class ChromiumBookmarkLoader : IBookmarkLoader + public abstract List GetBookmarks(); + + protected List LoadBookmarks(string browserDataPath, string name) { - public abstract List GetBookmarks(); + var bookmarks = new List(); + if (!Directory.Exists(browserDataPath)) return bookmarks; + var paths = Directory.GetDirectories(browserDataPath); - protected List LoadBookmarks(string browserDataPath, string name) + foreach (var profile in paths) { - var bookmarks = new List(); - if (!Directory.Exists(browserDataPath)) return bookmarks; - var paths = Directory.GetDirectories(browserDataPath); + var bookmarkPath = Path.Combine(profile, "Bookmarks"); + if (!File.Exists(bookmarkPath)) + continue; - foreach (var profile in paths) - { - var bookmarkPath = Path.Combine(profile, "Bookmarks"); - if (!File.Exists(bookmarkPath)) - continue; + Main.RegisterBookmarkFile(bookmarkPath); - Main.RegisterBookmarkFile(bookmarkPath); + var source = name + (Path.GetFileName(profile) == "Default" ? "" : $" ({Path.GetFileName(profile)})"); + bookmarks.AddRange(LoadBookmarksFromFile(bookmarkPath, source)); + } - var source = name + (Path.GetFileName(profile) == "Default" ? "" : $" ({Path.GetFileName(profile)})"); - bookmarks.AddRange(LoadBookmarksFromFile(bookmarkPath, source)); - } + return bookmarks; + } + protected List LoadBookmarksFromFile(string path, string source) + { + var bookmarks = new List(); + + if (!File.Exists(path)) return bookmarks; - } - protected List LoadBookmarksFromFile(string path, string source) - { - var bookmarks = new List(); - - if (!File.Exists(path)) - return bookmarks; - - using var jsonDocument = JsonDocument.Parse(File.ReadAllText(path)); - if (!jsonDocument.RootElement.TryGetProperty("roots", out var rootElement)) - return bookmarks; - EnumerateRoot(rootElement, bookmarks, source); + using var jsonDocument = JsonDocument.Parse(File.ReadAllText(path)); + if (!jsonDocument.RootElement.TryGetProperty("roots", out var rootElement)) return bookmarks; - } + EnumerateRoot(rootElement, bookmarks, source); + return bookmarks; + } - private void EnumerateRoot(JsonElement rootElement, ICollection bookmarks, string source) + private void EnumerateRoot(JsonElement rootElement, ICollection bookmarks, string source) + { + foreach (var folder in rootElement.EnumerateObject()) { - foreach (var folder in rootElement.EnumerateObject()) - { - if (folder.Value.ValueKind != JsonValueKind.Object) - continue; + if (folder.Value.ValueKind != JsonValueKind.Object) + continue; - // Fix for Opera. It stores bookmarks slightly different than chrome. See PR and bug report for this change for details. - // If various exceptions start to build up here consider splitting this Loader into multiple separate ones. - if (folder.Name == "custom_root") - EnumerateRoot(folder.Value, bookmarks, source); - else - EnumerateFolderBookmark(folder.Value, bookmarks, source); + // Fix for Opera. It stores bookmarks slightly different than chrome. See PR and bug report for this change for details. + // If various exceptions start to build up here consider splitting this Loader into multiple separate ones. + if (folder.Name == "custom_root") + EnumerateRoot(folder.Value, bookmarks, source); + else + EnumerateFolderBookmark(folder.Value, bookmarks, source); + } + } + + private void EnumerateFolderBookmark(JsonElement folderElement, ICollection bookmarks, + string source) + { + if (!folderElement.TryGetProperty("children", out var childrenElement)) + return; + foreach (var subElement in childrenElement.EnumerateArray()) + { + if (subElement.TryGetProperty("type", out var type)) + { + switch (type.GetString()) + { + case "folder": + case "workspace": // Edge Workspace + EnumerateFolderBookmark(subElement, bookmarks, source); + break; + default: + bookmarks.Add(new Bookmark( + subElement.GetProperty("name").GetString(), + subElement.GetProperty("url").GetString(), + source)); + break; + } } - } - - private void EnumerateFolderBookmark(JsonElement folderElement, ICollection bookmarks, - string source) - { - if (!folderElement.TryGetProperty("children", out var childrenElement)) - return; - foreach (var subElement in childrenElement.EnumerateArray()) + else { - if (subElement.TryGetProperty("type", out var type)) - { - switch (type.GetString()) - { - case "folder": - case "workspace": // Edge Workspace - EnumerateFolderBookmark(subElement, bookmarks, source); - break; - default: - bookmarks.Add(new Bookmark( - subElement.GetProperty("name").GetString(), - subElement.GetProperty("url").GetString(), - source)); - break; - } - } - else - { - Log.Error( - $"ChromiumBookmarkLoader: EnumerateFolderBookmark: type property not found for {subElement.GetString()}"); - } + Log.Error( + $"ChromiumBookmarkLoader: EnumerateFolderBookmark: type property not found for {subElement.GetString()}"); } } } diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Commands/BookmarkLoader.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Commands/BookmarkLoader.cs index d08c05b6b..3468015eb 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Commands/BookmarkLoader.cs +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Commands/BookmarkLoader.cs @@ -4,56 +4,55 @@ using Flow.Launcher.Infrastructure; using Flow.Launcher.Plugin.BrowserBookmark.Models; using Flow.Launcher.Plugin.SharedModels; -namespace Flow.Launcher.Plugin.BrowserBookmark.Commands +namespace Flow.Launcher.Plugin.BrowserBookmark.Commands; + +internal static class BookmarkLoader { - internal static class BookmarkLoader + internal static MatchResult MatchProgram(Bookmark bookmark, string queryString) { - internal static MatchResult MatchProgram(Bookmark bookmark, string queryString) - { - var match = StringMatcher.FuzzySearch(queryString, bookmark.Name); - if (match.IsSearchPrecisionScoreMet()) - return match; + var match = StringMatcher.FuzzySearch(queryString, bookmark.Name); + if (match.IsSearchPrecisionScoreMet()) + return match; - return StringMatcher.FuzzySearch(queryString, bookmark.Url); + return StringMatcher.FuzzySearch(queryString, bookmark.Url); + } + + internal static List LoadAllBookmarks(Settings setting) + { + var allBookmarks = new List(); + + if (setting.LoadChromeBookmark) + { + // Add Chrome bookmarks + var chromeBookmarks = new ChromeBookmarkLoader(); + allBookmarks.AddRange(chromeBookmarks.GetBookmarks()); } - internal static List LoadAllBookmarks(Settings setting) + if (setting.LoadFirefoxBookmark) { - var allBookmarks = new List(); - - if (setting.LoadChromeBookmark) - { - // Add Chrome bookmarks - var chromeBookmarks = new ChromeBookmarkLoader(); - allBookmarks.AddRange(chromeBookmarks.GetBookmarks()); - } - - if (setting.LoadFirefoxBookmark) - { - // Add Firefox bookmarks - var mozBookmarks = new FirefoxBookmarkLoader(); - allBookmarks.AddRange(mozBookmarks.GetBookmarks()); - } - - if (setting.LoadEdgeBookmark) - { - // Add Edge (Chromium) bookmarks - var edgeBookmarks = new EdgeBookmarkLoader(); - allBookmarks.AddRange(edgeBookmarks.GetBookmarks()); - } - - foreach (var browser in setting.CustomChromiumBrowsers) - { - IBookmarkLoader loader = browser.BrowserType switch - { - BrowserType.Chromium => new CustomChromiumBookmarkLoader(browser), - BrowserType.Firefox => new CustomFirefoxBookmarkLoader(browser), - _ => new CustomChromiumBookmarkLoader(browser), - }; - allBookmarks.AddRange(loader.GetBookmarks()); - } - - return allBookmarks.Distinct().ToList(); + // Add Firefox bookmarks + var mozBookmarks = new FirefoxBookmarkLoader(); + allBookmarks.AddRange(mozBookmarks.GetBookmarks()); } + + if (setting.LoadEdgeBookmark) + { + // Add Edge (Chromium) bookmarks + var edgeBookmarks = new EdgeBookmarkLoader(); + allBookmarks.AddRange(edgeBookmarks.GetBookmarks()); + } + + foreach (var browser in setting.CustomChromiumBrowsers) + { + IBookmarkLoader loader = browser.BrowserType switch + { + BrowserType.Chromium => new CustomChromiumBookmarkLoader(browser), + BrowserType.Firefox => new CustomFirefoxBookmarkLoader(browser), + _ => new CustomChromiumBookmarkLoader(browser), + }; + allBookmarks.AddRange(loader.GetBookmarks()); + } + + return allBookmarks.Distinct().ToList(); } } diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/CustomChromiumBookmarkLoader.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/CustomChromiumBookmarkLoader.cs index fa98f4d7c..005c83992 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/CustomChromiumBookmarkLoader.cs +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/CustomChromiumBookmarkLoader.cs @@ -1,19 +1,18 @@ using Flow.Launcher.Plugin.BrowserBookmark.Models; using System.Collections.Generic; -namespace Flow.Launcher.Plugin.BrowserBookmark -{ - public class CustomChromiumBookmarkLoader : ChromiumBookmarkLoader - { - public CustomChromiumBookmarkLoader(CustomBrowser browser) - { - BrowserName = browser.Name; - BrowserDataPath = browser.DataDirectoryPath; - } - public string BrowserDataPath { get; init; } - public string BookmarkFilePath { get; init; } - public string BrowserName { get; init; } +namespace Flow.Launcher.Plugin.BrowserBookmark; - public override List GetBookmarks() => BrowserDataPath != null ? LoadBookmarks(BrowserDataPath, BrowserName) : LoadBookmarksFromFile(BookmarkFilePath, BrowserName); +public class CustomChromiumBookmarkLoader : ChromiumBookmarkLoader +{ + public CustomChromiumBookmarkLoader(CustomBrowser browser) + { + BrowserName = browser.Name; + BrowserDataPath = browser.DataDirectoryPath; } -} \ No newline at end of file + public string BrowserDataPath { get; init; } + public string BookmarkFilePath { get; init; } + public string BrowserName { get; init; } + + public override List GetBookmarks() => BrowserDataPath != null ? LoadBookmarks(BrowserDataPath, BrowserName) : LoadBookmarksFromFile(BookmarkFilePath, BrowserName); +} diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/CustomFirefoxBookmarkLoader.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/CustomFirefoxBookmarkLoader.cs index 82bdc29f5..d0bb7b0cc 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/CustomFirefoxBookmarkLoader.cs +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/CustomFirefoxBookmarkLoader.cs @@ -2,26 +2,25 @@ using System.IO; using Flow.Launcher.Plugin.BrowserBookmark.Models; -namespace Flow.Launcher.Plugin.BrowserBookmark -{ - public class CustomFirefoxBookmarkLoader : FirefoxBookmarkLoaderBase - { - public CustomFirefoxBookmarkLoader(CustomBrowser browser) - { - BrowserName = browser.Name; - BrowserDataPath = browser.DataDirectoryPath; - } - - /// - /// Path to places.sqlite - /// - public string BrowserDataPath { get; init; } - - public string BrowserName { get; init; } +namespace Flow.Launcher.Plugin.BrowserBookmark; - public override List GetBookmarks() - { - return GetBookmarksFromPath(Path.Combine(BrowserDataPath, "places.sqlite")); - } +public class CustomFirefoxBookmarkLoader : FirefoxBookmarkLoaderBase +{ + public CustomFirefoxBookmarkLoader(CustomBrowser browser) + { + BrowserName = browser.Name; + BrowserDataPath = browser.DataDirectoryPath; + } + + /// + /// Path to places.sqlite + /// + public string BrowserDataPath { get; init; } + + public string BrowserName { get; init; } + + public override List GetBookmarks() + { + return GetBookmarksFromPath(Path.Combine(BrowserDataPath, "places.sqlite")); } } diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/EdgeBookmarkLoader.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/EdgeBookmarkLoader.cs index 79190f0ef..40123b022 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/EdgeBookmarkLoader.cs +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/EdgeBookmarkLoader.cs @@ -3,21 +3,20 @@ using System; using System.Collections.Generic; using System.IO; -namespace Flow.Launcher.Plugin.BrowserBookmark -{ - public class EdgeBookmarkLoader : ChromiumBookmarkLoader - { - private List LoadEdgeBookmarks() - { - var bookmarks = new List(); - var platformPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); - bookmarks.AddRange(LoadBookmarks(Path.Combine(platformPath, @"Microsoft\Edge\User Data"), "Microsoft Edge")); - bookmarks.AddRange(LoadBookmarks(Path.Combine(platformPath, @"Microsoft\Edge Dev\User Data"), "Microsoft Edge Dev")); - bookmarks.AddRange(LoadBookmarks(Path.Combine(platformPath, @"Microsoft\Edge SxS\User Data"), "Microsoft Edge Canary")); +namespace Flow.Launcher.Plugin.BrowserBookmark; - return bookmarks; - } - - public override List GetBookmarks() => LoadEdgeBookmarks(); +public class EdgeBookmarkLoader : ChromiumBookmarkLoader +{ + private List LoadEdgeBookmarks() + { + var bookmarks = new List(); + var platformPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); + bookmarks.AddRange(LoadBookmarks(Path.Combine(platformPath, @"Microsoft\Edge\User Data"), "Microsoft Edge")); + bookmarks.AddRange(LoadBookmarks(Path.Combine(platformPath, @"Microsoft\Edge Dev\User Data"), "Microsoft Edge Dev")); + bookmarks.AddRange(LoadBookmarks(Path.Combine(platformPath, @"Microsoft\Edge SxS\User Data"), "Microsoft Edge Canary")); + + return bookmarks; } -} \ No newline at end of file + + public override List GetBookmarks() => LoadEdgeBookmarks(); +} diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs index 3d061e758..9d9480f99 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs @@ -5,140 +5,133 @@ using System.Collections.Generic; using System.IO; using System.Linq; -namespace Flow.Launcher.Plugin.BrowserBookmark +namespace Flow.Launcher.Plugin.BrowserBookmark; + +public abstract class FirefoxBookmarkLoaderBase : IBookmarkLoader { - public abstract class FirefoxBookmarkLoaderBase : IBookmarkLoader + public abstract List GetBookmarks(); + + private const string QueryAllBookmarks = """ + SELECT moz_places.url, moz_bookmarks.title + FROM moz_places + INNER JOIN moz_bookmarks ON ( + moz_bookmarks.fk NOT NULL AND moz_bookmarks.title NOT NULL AND moz_bookmarks.fk = moz_places.id + ) + ORDER BY moz_places.visit_count DESC + """; + + private const string DbPathFormat = "Data Source ={0}"; + + protected static List GetBookmarksFromPath(string placesPath) { - public abstract List GetBookmarks(); + // Return empty list if the places.sqlite file cannot be found + if (string.IsNullOrEmpty(placesPath) || !File.Exists(placesPath)) + return new List(); - private const string queryAllBookmarks = @"SELECT moz_places.url, moz_bookmarks.title - FROM moz_places - INNER JOIN moz_bookmarks ON ( - moz_bookmarks.fk NOT NULL AND moz_bookmarks.title NOT NULL AND moz_bookmarks.fk = moz_places.id - ) - ORDER BY moz_places.visit_count DESC - "; + Main.RegisterBookmarkFile(placesPath); - private const string dbPathFormat = "Data Source ={0}"; + // create the connection string and init the connection + string dbPath = string.Format(DbPathFormat, placesPath); + using var dbConnection = new SqliteConnection(dbPath); + // Open connection to the database file and execute the query + dbConnection.Open(); + var reader = new SqliteCommand(QueryAllBookmarks, dbConnection).ExecuteReader(); - protected static List GetBookmarksFromPath(string placesPath) - { - // Return empty list if the places.sqlite file cannot be found - if (string.IsNullOrEmpty(placesPath) || !File.Exists(placesPath)) - return new List(); + // return results in List format + return reader + .Select( + x => new Bookmark( + x["title"] is DBNull ? string.Empty : x["title"].ToString(), + x["url"].ToString() + ) + ) + .ToList(); + } +} - var bookmarkList = new List(); - Main.RegisterBookmarkFile(placesPath); - - // create the connection string and init the connection - string dbPath = string.Format(dbPathFormat, placesPath); - using var dbConnection = new SqliteConnection(dbPath); - // Open connection to the database file and execute the query - dbConnection.Open(); - var reader = new SqliteCommand(queryAllBookmarks, dbConnection).ExecuteReader(); - - // return results in List format - bookmarkList = reader.Select( - x => new Bookmark(x["title"] is DBNull ? string.Empty : x["title"].ToString(), - x["url"].ToString()) - ).ToList(); - - return bookmarkList; - } +public class FirefoxBookmarkLoader : FirefoxBookmarkLoaderBase +{ + /// + /// Searches the places.sqlite db and returns all bookmarks + /// + public override List GetBookmarks() + { + return GetBookmarksFromPath(PlacesPath); } - - public class FirefoxBookmarkLoader : FirefoxBookmarkLoaderBase + /// + /// Path to places.sqlite + /// + private string PlacesPath { - /// - /// Searches the places.sqlite db and returns all bookmarks - /// - public override List GetBookmarks() + get { - return GetBookmarksFromPath(PlacesPath); - } - - /// - /// Path to places.sqlite - /// - private string PlacesPath - { - get - { - var profileFolderPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"Mozilla\Firefox"); - var profileIni = Path.Combine(profileFolderPath, @"profiles.ini"); + var profileFolderPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"Mozilla\Firefox"); + var profileIni = Path.Combine(profileFolderPath, @"profiles.ini"); - if (!File.Exists(profileIni)) - return string.Empty; + if (!File.Exists(profileIni)) + return string.Empty; - // get firefox default profile directory from profiles.ini - string ini; - using (var sReader = new StreamReader(profileIni)) - { - ini = sReader.ReadToEnd(); - } + // get firefox default profile directory from profiles.ini + using var sReader = new StreamReader(profileIni); + var ini = sReader.ReadToEnd(); - /* - Current profiles.ini structure example as of Firefox version 69.0.1 - - [Install736426B0AF4A39CB] - Default=Profiles/7789f565.default-release <== this is the default profile this plugin will get the bookmarks from. When opened Firefox will load the default profile - Locked=1 + /* + Current profiles.ini structure example as of Firefox version 69.0.1 - [Profile2] - Name=newblahprofile - IsRelative=0 - Path=C:\t6h2yuq8.newblahprofile <== Note this is a custom location path for the profile user can set, we need to cater for this in code. + [Install736426B0AF4A39CB] + Default=Profiles/7789f565.default-release <== this is the default profile this plugin will get the bookmarks from. When opened Firefox will load the default profile + Locked=1 - [Profile1] - Name=default - IsRelative=1 - Path=Profiles/cydum7q4.default - Default=1 + [Profile2] + Name=newblahprofile + IsRelative=0 + Path=C:\t6h2yuq8.newblahprofile <== Note this is a custom location path for the profile user can set, we need to cater for this in code. - [Profile0] - Name=default-release - IsRelative=1 - Path=Profiles/7789f565.default-release + [Profile1] + Name=default + IsRelative=1 + Path=Profiles/cydum7q4.default + Default=1 - [General] - StartWithLastProfile=1 - Version=2 - */ + [Profile0] + Name=default-release + IsRelative=1 + Path=Profiles/7789f565.default-release - var lines = ini.Split(new string[] - { - "\r\n" - }, StringSplitOptions.None).ToList(); + [General] + StartWithLastProfile=1 + Version=2 + */ + var lines = ini.Split("\r\n").ToList(); - var defaultProfileFolderNameRaw = lines.Where(x => x.Contains("Default=") && x != "Default=1").FirstOrDefault() ?? string.Empty; + var defaultProfileFolderNameRaw = lines.FirstOrDefault(x => x.Contains("Default=") && x != "Default=1") ?? string.Empty; - if (string.IsNullOrEmpty(defaultProfileFolderNameRaw)) - return string.Empty; + if (string.IsNullOrEmpty(defaultProfileFolderNameRaw)) + return string.Empty; - var defaultProfileFolderName = defaultProfileFolderNameRaw.Split('=').Last(); + var defaultProfileFolderName = defaultProfileFolderNameRaw.Split('=').Last(); - var indexOfDefaultProfileAtttributePath = lines.IndexOf("Path=" + defaultProfileFolderName); + var indexOfDefaultProfileAtttributePath = lines.IndexOf("Path=" + defaultProfileFolderName); - // Seen in the example above, the IsRelative attribute is always above the Path attribute - var relativeAttribute = lines[indexOfDefaultProfileAtttributePath - 1]; + // Seen in the example above, the IsRelative attribute is always above the Path attribute + var relativeAttribute = lines[indexOfDefaultProfileAtttributePath - 1]; - return relativeAttribute == "0" // See above, the profile is located in a custom location, path is not relative, so IsRelative=0 - ? defaultProfileFolderName + @"\places.sqlite" - : Path.Combine(profileFolderPath, defaultProfileFolderName) + @"\places.sqlite"; - } - } - } - - public static class Extensions - { - public static IEnumerable Select(this SqliteDataReader reader, Func projection) - { - while (reader.Read()) - { - yield return projection(reader); - } + return relativeAttribute == "0" // See above, the profile is located in a custom location, path is not relative, so IsRelative=0 + ? defaultProfileFolderName + @"\places.sqlite" + : Path.Combine(profileFolderPath, defaultProfileFolderName) + @"\places.sqlite"; + } + } +} + +public static class Extensions +{ + public static IEnumerable Select(this SqliteDataReader reader, Func projection) + { + while (reader.Read()) + { + yield return projection(reader); } } } diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/IBookmarkLoader.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/IBookmarkLoader.cs index 2c48cfd55..8a9727352 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/IBookmarkLoader.cs +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/IBookmarkLoader.cs @@ -1,10 +1,9 @@ using Flow.Launcher.Plugin.BrowserBookmark.Models; using System.Collections.Generic; -namespace Flow.Launcher.Plugin.BrowserBookmark +namespace Flow.Launcher.Plugin.BrowserBookmark; + +public interface IBookmarkLoader { - public interface IBookmarkLoader - { - public List GetBookmarks(); - } -} \ No newline at end of file + public List GetBookmarks(); +} diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Main.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Main.cs index a13d6c929..23efd29b9 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Main.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Windows; using System.Windows.Controls; using Flow.Launcher.Infrastructure.Logger; using Flow.Launcher.Plugin.BrowserBookmark.Commands; @@ -12,233 +11,234 @@ using System.Threading.Channels; using System.Threading.Tasks; using System.Threading; -namespace Flow.Launcher.Plugin.BrowserBookmark +namespace Flow.Launcher.Plugin.BrowserBookmark; + +public class Main : ISettingProvider, IPlugin, IReloadable, IPluginI18n, IContextMenu, IDisposable { - public class Main : ISettingProvider, IPlugin, IReloadable, IPluginI18n, IContextMenu, IDisposable + private static PluginInitContext _context; + + private static List _cachedBookmarks = new List(); + + private static Settings _settings; + + private static bool _initialized = false; + + public void Init(PluginInitContext context) { - private static PluginInitContext context; + _context = context; - private static List cachedBookmarks = new List(); + _settings = context.API.LoadSettingJsonStorage(); - private static Settings _settings; + LoadBookmarksIfEnabled(); + } - private static bool initialized = false; - - public void Init(PluginInitContext context) + private static void LoadBookmarksIfEnabled() + { + if (_context.CurrentPluginMetadata.Disabled) { - Main.context = context; + // Don't load or monitor files if disabled + return; + } - _settings = context.API.LoadSettingJsonStorage(); + _cachedBookmarks = BookmarkLoader.LoadAllBookmarks(_settings); + _ = MonitorRefreshQueueAsync(); + _initialized = true; + } + public List Query(Query query) + { + // For when the plugin being previously disabled and is now reenabled + if (!_initialized) + { LoadBookmarksIfEnabled(); } - private static void LoadBookmarksIfEnabled() + string param = query.Search.TrimStart(); + + // Should top results be returned? (true if no search parameters have been passed) + var topResults = string.IsNullOrEmpty(param); + + + if (!topResults) { - if (context.CurrentPluginMetadata.Disabled) - { - // Don't load or monitor files if disabled - return; - } - - cachedBookmarks = BookmarkLoader.LoadAllBookmarks(_settings); - _ = MonitorRefreshQueueAsync(); - initialized = true; - } - - public List Query(Query query) - { - // For when the plugin being previously disabled and is now renabled - if (!initialized) - { - LoadBookmarksIfEnabled(); - } - - string param = query.Search.TrimStart(); - - // Should top results be returned? (true if no search parameters have been passed) - var topResults = string.IsNullOrEmpty(param); - - - if (!topResults) - { - // Since we mixed chrome and firefox bookmarks, we should order them again - var returnList = cachedBookmarks.Select(c => new Result() - { - Title = c.Name, - SubTitle = c.Url, - IcoPath = @"Images\bookmark.png", - Score = BookmarkLoader.MatchProgram(c, param).Score, - Action = _ => + // Since we mixed chrome and firefox bookmarks, we should order them again + return _cachedBookmarks + .Select( + c => new Result { - context.API.OpenUrl(c.Url); - - return true; - }, - ContextData = new BookmarkAttributes - { - Url = c.Url - } - }).Where(r => r.Score > 0); - return returnList.ToList(); - } - else - { - return cachedBookmarks.Select(c => new Result() - { - Title = c.Name, - SubTitle = c.Url, - IcoPath = @"Images\bookmark.png", - Score = 5, - Action = _ => - { - context.API.OpenUrl(c.Url); - return true; - }, - ContextData = new BookmarkAttributes - { - Url = c.Url - } - }).ToList(); - } - } - - - private static Channel refreshQueue = Channel.CreateBounded(1); - - private static SemaphoreSlim fileMonitorSemaphore = new(1, 1); - - private static async Task MonitorRefreshQueueAsync() - { - if (fileMonitorSemaphore.CurrentCount < 1) - { - return; - } - await fileMonitorSemaphore.WaitAsync(); - var reader = refreshQueue.Reader; - while (await reader.WaitToReadAsync()) - { - if (reader.TryRead(out _)) - { - ReloadAllBookmarks(false); - } - } - fileMonitorSemaphore.Release(); - } - - private static readonly List Watchers = new(); - - internal static void RegisterBookmarkFile(string path) - { - var directory = Path.GetDirectoryName(path); - if (!Directory.Exists(directory) || !File.Exists(path)) - { - return; - } - if (Watchers.Any(x => x.Path.Equals(directory, StringComparison.OrdinalIgnoreCase))) - { - return; - } - - var watcher = new FileSystemWatcher(directory!); - watcher.Filter = Path.GetFileName(path); - - watcher.NotifyFilter = NotifyFilters.FileName | - NotifyFilters.LastWrite | - NotifyFilters.Size; - - watcher.Changed += static (_, _) => - { - refreshQueue.Writer.TryWrite(default); - }; - - watcher.Renamed += static (_, _) => - { - refreshQueue.Writer.TryWrite(default); - }; - - watcher.EnableRaisingEvents = true; - - Watchers.Add(watcher); - } - - public void ReloadData() - { - ReloadAllBookmarks(); - } - - public static void ReloadAllBookmarks(bool disposeFileWatchers = true) - { - cachedBookmarks.Clear(); - if (disposeFileWatchers) - DisposeFileWatchers(); - LoadBookmarksIfEnabled(); - } - - public string GetTranslatedPluginTitle() - { - return context.API.GetTranslation("flowlauncher_plugin_browserbookmark_plugin_name"); - } - - public string GetTranslatedPluginDescription() - { - return context.API.GetTranslation("flowlauncher_plugin_browserbookmark_plugin_description"); - } - - public Control CreateSettingPanel() - { - return new SettingsControl(_settings); - } - - public List LoadContextMenus(Result selectedResult) - { - return new List() - { - new Result - { - Title = context.API.GetTranslation("flowlauncher_plugin_browserbookmark_copyurl_title"), - SubTitle = context.API.GetTranslation("flowlauncher_plugin_browserbookmark_copyurl_subtitle"), - Action = _ => - { - try + Title = c.Name, + SubTitle = c.Url, + IcoPath = @"Images\bookmark.png", + Score = BookmarkLoader.MatchProgram(c, param).Score, + Action = _ => { - context.API.CopyToClipboard(((BookmarkAttributes)selectedResult.ContextData).Url); + _context.API.OpenUrl(c.Url); return true; - } - catch (Exception e) + }, + ContextData = new BookmarkAttributes { Url = c.Url } + } + ) + .Where(r => r.Score > 0) + .ToList(); + } + else + { + return _cachedBookmarks + .Select( + c => new Result + { + Title = c.Name, + SubTitle = c.Url, + IcoPath = @"Images\bookmark.png", + Score = 5, + Action = _ => { - var message = "Failed to set url in clipboard"; - Log.Exception("Main", message, e, "LoadContextMenus"); - - context.API.ShowMsg(message); - - return false; - } - }, - IcoPath = "Images\\copylink.png", - Glyph = new GlyphInfo(FontFamily: "/Resources/#Segoe Fluent Icons", Glyph: "\ue8c8") - } - }; - } - - internal class BookmarkAttributes - { - internal string Url { get; set; } - } - - public void Dispose() - { - DisposeFileWatchers(); - } - - private static void DisposeFileWatchers() - { - foreach (var watcher in Watchers) - { - watcher.Dispose(); - } - Watchers.Clear(); + _context.API.OpenUrl(c.Url); + return true; + }, + ContextData = new BookmarkAttributes { Url = c.Url } + } + ) + .ToList(); } } + + + private static Channel _refreshQueue = Channel.CreateBounded(1); + + private static SemaphoreSlim _fileMonitorSemaphore = new(1, 1); + + private static async Task MonitorRefreshQueueAsync() + { + if (_fileMonitorSemaphore.CurrentCount < 1) + { + return; + } + await _fileMonitorSemaphore.WaitAsync(); + var reader = _refreshQueue.Reader; + while (await reader.WaitToReadAsync()) + { + if (reader.TryRead(out _)) + { + ReloadAllBookmarks(false); + } + } + _fileMonitorSemaphore.Release(); + } + + private static readonly List Watchers = new(); + + internal static void RegisterBookmarkFile(string path) + { + var directory = Path.GetDirectoryName(path); + if (!Directory.Exists(directory) || !File.Exists(path)) + { + return; + } + if (Watchers.Any(x => x.Path.Equals(directory, StringComparison.OrdinalIgnoreCase))) + { + return; + } + + var watcher = new FileSystemWatcher(directory!); + watcher.Filter = Path.GetFileName(path); + + watcher.NotifyFilter = NotifyFilters.FileName | + NotifyFilters.LastWrite | + NotifyFilters.Size; + + watcher.Changed += static (_, _) => + { + _refreshQueue.Writer.TryWrite(default); + }; + + watcher.Renamed += static (_, _) => + { + _refreshQueue.Writer.TryWrite(default); + }; + + watcher.EnableRaisingEvents = true; + + Watchers.Add(watcher); + } + + public void ReloadData() + { + ReloadAllBookmarks(); + } + + public static void ReloadAllBookmarks(bool disposeFileWatchers = true) + { + _cachedBookmarks.Clear(); + if (disposeFileWatchers) + DisposeFileWatchers(); + LoadBookmarksIfEnabled(); + } + + public string GetTranslatedPluginTitle() + { + return _context.API.GetTranslation("flowlauncher_plugin_browserbookmark_plugin_name"); + } + + public string GetTranslatedPluginDescription() + { + return _context.API.GetTranslation("flowlauncher_plugin_browserbookmark_plugin_description"); + } + + public Control CreateSettingPanel() + { + return new SettingsControl(_settings); + } + + public List LoadContextMenus(Result selectedResult) + { + return new List() + { + new Result + { + Title = _context.API.GetTranslation("flowlauncher_plugin_browserbookmark_copyurl_title"), + SubTitle = _context.API.GetTranslation("flowlauncher_plugin_browserbookmark_copyurl_subtitle"), + Action = _ => + { + try + { + _context.API.CopyToClipboard(((BookmarkAttributes)selectedResult.ContextData).Url); + + return true; + } + catch (Exception e) + { + var message = "Failed to set url in clipboard"; + Log.Exception("Main", message, e, "LoadContextMenus"); + + _context.API.ShowMsg(message); + + return false; + } + }, + IcoPath = @"Images\copylink.png", + Glyph = new GlyphInfo(FontFamily: "/Resources/#Segoe Fluent Icons", Glyph: "\ue8c8") + } + }; + } + + internal class BookmarkAttributes + { + internal string Url { get; set; } + } + + public void Dispose() + { + DisposeFileWatchers(); + } + + private static void DisposeFileWatchers() + { + foreach (var watcher in Watchers) + { + watcher.Dispose(); + } + Watchers.Clear(); + } } diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Models/Bookmark.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Models/Bookmark.cs index c2fa9d977..c738da389 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Models/Bookmark.cs +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Models/Bookmark.cs @@ -1,22 +1,21 @@ using System.Collections.Generic; -namespace Flow.Launcher.Plugin.BrowserBookmark.Models +namespace Flow.Launcher.Plugin.BrowserBookmark.Models; + +// Source may be important in the future +public record Bookmark(string Name, string Url, string Source = "") { - // Source may be important in the future - public record Bookmark(string Name, string Url, string Source = "") + public override int GetHashCode() { - public override int GetHashCode() - { - var hashName = Name?.GetHashCode() ?? 0; - var hashUrl = Url?.GetHashCode() ?? 0; - return hashName ^ hashUrl; - } - - public virtual bool Equals(Bookmark other) - { - return other != null && Name == other.Name && Url == other.Url; - } - - public List CustomBrowsers { get; set; }= new(); + var hashName = Name?.GetHashCode() ?? 0; + var hashUrl = Url?.GetHashCode() ?? 0; + return hashName ^ hashUrl; } -} \ No newline at end of file + + public virtual bool Equals(Bookmark other) + { + return other != null && Name == other.Name && Url == other.Url; + } + + public List CustomBrowsers { get; set; } = new(); +} diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Models/CustomBrowser.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Models/CustomBrowser.cs index 69bb56e48..74e0f299a 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Models/CustomBrowser.cs +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Models/CustomBrowser.cs @@ -1,45 +1,44 @@ -namespace Flow.Launcher.Plugin.BrowserBookmark.Models -{ - public class CustomBrowser : BaseModel - { - private string _name; - private string _dataDirectoryPath; - private BrowserType browserType = BrowserType.Chromium; +namespace Flow.Launcher.Plugin.BrowserBookmark.Models; - public string Name +public class CustomBrowser : BaseModel +{ + private string _name; + private string _dataDirectoryPath; + private BrowserType _browserType = BrowserType.Chromium; + + public string Name + { + get => _name; + set { - get => _name; - set - { - _name = value; - OnPropertyChanged(nameof(Name)); - } - } - - public string DataDirectoryPath - { - get => _dataDirectoryPath; - set - { - _dataDirectoryPath = value; - OnPropertyChanged(nameof(DataDirectoryPath)); - } - } - - public BrowserType BrowserType - { - get => browserType; - set - { - browserType = value; - OnPropertyChanged(nameof(BrowserType)); - } + _name = value; + OnPropertyChanged(); } } - public enum BrowserType + public string DataDirectoryPath { - Chromium, - Firefox, + get => _dataDirectoryPath; + set + { + _dataDirectoryPath = value; + OnPropertyChanged(); + } + } + + public BrowserType BrowserType + { + get => _browserType; + set + { + _browserType = value; + OnPropertyChanged(); + } } } + +public enum BrowserType +{ + Chromium, + Firefox, +} diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Models/Settings.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Models/Settings.cs index dc1016b4e..86532d275 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Models/Settings.cs +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Models/Settings.cs @@ -1,17 +1,16 @@ using System.Collections.ObjectModel; -namespace Flow.Launcher.Plugin.BrowserBookmark.Models +namespace Flow.Launcher.Plugin.BrowserBookmark.Models; + +public class Settings : BaseModel { - public class Settings : BaseModel - { - public bool OpenInNewBrowserWindow { get; set; } = true; + public bool OpenInNewBrowserWindow { get; set; } = true; - public string BrowserPath { get; set; } + public string BrowserPath { get; set; } - public bool LoadChromeBookmark { get; set; } = true; - public bool LoadFirefoxBookmark { get; set; } = true; - public bool LoadEdgeBookmark { get; set; } = true; + public bool LoadChromeBookmark { get; set; } = true; + public bool LoadFirefoxBookmark { get; set; } = true; + public bool LoadEdgeBookmark { get; set; } = true; - public ObservableCollection CustomChromiumBrowsers { get; set; } = new(); - } -} \ No newline at end of file + public ObservableCollection CustomChromiumBrowsers { get; set; } = new(); +} diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Views/CustomBrowserSetting.xaml b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Views/CustomBrowserSetting.xaml index 392c9e0a7..f5017ced5 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Views/CustomBrowserSetting.xaml +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Views/CustomBrowserSetting.xaml @@ -63,7 +63,6 @@ +/// Interaction logic for CustomBrowserSetting.xaml +/// +public partial class CustomBrowserSettingWindow : Window { - /// - /// Interaction logic for CustomBrowserSetting.xaml - /// - public partial class CustomBrowserSettingWindow : Window + private CustomBrowser _currentCustomBrowser; + public CustomBrowserSettingWindow(CustomBrowser browser) { - private CustomBrowser currentCustomBrowser; - public CustomBrowserSettingWindow(CustomBrowser browser) + InitializeComponent(); + _currentCustomBrowser = browser; + DataContext = new CustomBrowser { - InitializeComponent(); - currentCustomBrowser = browser; - DataContext = new CustomBrowser - { - Name = browser.Name, - DataDirectoryPath = browser.DataDirectoryPath, - BrowserType = browser.BrowserType, - }; - } - - private void ConfirmEditCustomBrowser(object sender, RoutedEventArgs e) - { - CustomBrowser editBrowser = (CustomBrowser)DataContext; - currentCustomBrowser.Name = editBrowser.Name; - currentCustomBrowser.DataDirectoryPath = editBrowser.DataDirectoryPath; - currentCustomBrowser.BrowserType = editBrowser.BrowserType; - DialogResult = true; - Close(); - } + Name = browser.Name, + DataDirectoryPath = browser.DataDirectoryPath, + BrowserType = browser.BrowserType, + }; + } - private void CancelEditCustomBrowser(object sender, RoutedEventArgs e) - { - Close(); - } + private void ConfirmEditCustomBrowser(object sender, RoutedEventArgs e) + { + CustomBrowser editBrowser = (CustomBrowser)DataContext; + _currentCustomBrowser.Name = editBrowser.Name; + _currentCustomBrowser.DataDirectoryPath = editBrowser.DataDirectoryPath; + _currentCustomBrowser.BrowserType = editBrowser.BrowserType; + DialogResult = true; + Close(); + } - private void WindowKeyDown(object sender, System.Windows.Input.KeyEventArgs e) - { - if (e.Key == Key.Enter) - { - ConfirmEditCustomBrowser(sender, e); - } - } + private void CancelEditCustomBrowser(object sender, RoutedEventArgs e) + { + Close(); + } - private void OnSelectPathClick(object sender, RoutedEventArgs e) + private void WindowKeyDown(object sender, System.Windows.Input.KeyEventArgs e) + { + if (e.Key == Key.Enter) { - var dialog = new FolderBrowserDialog(); - dialog.ShowDialog(); - CustomBrowser editBrowser = (CustomBrowser)DataContext; - editBrowser.DataDirectoryPath = dialog.SelectedPath; + ConfirmEditCustomBrowser(sender, e); } } + + private void OnSelectPathClick(object sender, RoutedEventArgs e) + { + var dialog = new FolderBrowserDialog(); + dialog.ShowDialog(); + CustomBrowser editBrowser = (CustomBrowser)DataContext; + editBrowser.DataDirectoryPath = dialog.SelectedPath; + } } diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Views/SettingsControl.xaml.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Views/SettingsControl.xaml.cs index 2947c2cb5..4bdab89a9 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Views/SettingsControl.xaml.cs +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Views/SettingsControl.xaml.cs @@ -4,119 +4,116 @@ using System.Windows.Input; using System.ComponentModel; using System.Threading.Tasks; -namespace Flow.Launcher.Plugin.BrowserBookmark.Views +namespace Flow.Launcher.Plugin.BrowserBookmark.Views; + +public partial class SettingsControl : INotifyPropertyChanged { - public partial class SettingsControl : INotifyPropertyChanged + public Settings Settings { get; } + + public CustomBrowser SelectedCustomBrowser { get; set; } + + public bool LoadChromeBookmark { - public Settings Settings { get; } - - public CustomBrowser SelectedCustomBrowser { get; set; } - - public bool LoadChromeBookmark + get => Settings.LoadChromeBookmark; + set { - get => Settings.LoadChromeBookmark; - set + Settings.LoadChromeBookmark = value; + _ = Task.Run(() => Main.ReloadAllBookmarks()); + } + } + + public bool LoadFirefoxBookmark + { + get => Settings.LoadFirefoxBookmark; + set + { + Settings.LoadFirefoxBookmark = value; + _ = Task.Run(() => Main.ReloadAllBookmarks()); + } + } + + public bool LoadEdgeBookmark + { + get => Settings.LoadEdgeBookmark; + set + { + Settings.LoadEdgeBookmark = value; + _ = Task.Run(() => Main.ReloadAllBookmarks()); + } + } + + public bool OpenInNewBrowserWindow + { + get => Settings.OpenInNewBrowserWindow; + set + { + Settings.OpenInNewBrowserWindow = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(OpenInNewBrowserWindow))); + } + } + + public SettingsControl(Settings settings) + { + Settings = settings; + InitializeComponent(); + } + + public event PropertyChangedEventHandler PropertyChanged; + + private void NewCustomBrowser(object sender, RoutedEventArgs e) + { + var newBrowser = new CustomBrowser(); + var window = new CustomBrowserSettingWindow(newBrowser); + window.ShowDialog(); + if (newBrowser is not { - Settings.LoadChromeBookmark = value; - _ = Task.Run(() => Main.ReloadAllBookmarks()); - } - } - - public bool LoadFirefoxBookmark + Name: null, + DataDirectoryPath: null + }) { - get => Settings.LoadFirefoxBookmark; - set - { - Settings.LoadFirefoxBookmark = value; - _ = Task.Run(() => Main.ReloadAllBookmarks()); - } + Settings.CustomChromiumBrowsers.Add(newBrowser); + _ = Task.Run(() => Main.ReloadAllBookmarks()); } + } - public bool LoadEdgeBookmark + private void DeleteCustomBrowser(object sender, RoutedEventArgs e) + { + if (CustomBrowsers.SelectedItem is CustomBrowser selectedCustomBrowser) { - get => Settings.LoadEdgeBookmark; - set - { - Settings.LoadEdgeBookmark = value; - _ = Task.Run(() => Main.ReloadAllBookmarks()); - } + Settings.CustomChromiumBrowsers.Remove(selectedCustomBrowser); + _ = Task.Run(() => Main.ReloadAllBookmarks()); } + } - public bool OpenInNewBrowserWindow + private void MouseDoubleClickOnSelectedCustomBrowser(object sender, MouseButtonEventArgs e) + { + EditSelectedCustomBrowser(); + } + + private void Others_Click(object sender, RoutedEventArgs e) + { + CustomBrowsersList.Visibility = CustomBrowsersList.Visibility switch { - get => Settings.OpenInNewBrowserWindow; - set - { - Settings.OpenInNewBrowserWindow = value; - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(OpenInNewBrowserWindow))); - } - } + Visibility.Collapsed => Visibility.Visible, + _ => Visibility.Collapsed + }; + } - public SettingsControl(Settings settings) + private void EditCustomBrowser(object sender, RoutedEventArgs e) + { + EditSelectedCustomBrowser(); + } + + private void EditSelectedCustomBrowser() + { + if (SelectedCustomBrowser is null) + return; + + var window = new CustomBrowserSettingWindow(SelectedCustomBrowser); + var result = window.ShowDialog() ?? false; + if (result) { - Settings = settings; - InitializeComponent(); - } - - public event PropertyChangedEventHandler PropertyChanged; - - private void NewCustomBrowser(object sender, RoutedEventArgs e) - { - var newBrowser = new CustomBrowser(); - var window = new CustomBrowserSettingWindow(newBrowser); - window.ShowDialog(); - if (newBrowser is not - { - Name: null, - DataDirectoryPath: null - }) - { - Settings.CustomChromiumBrowsers.Add(newBrowser); - _ = Task.Run(() => Main.ReloadAllBookmarks()); - } - } - - private void DeleteCustomBrowser(object sender, RoutedEventArgs e) - { - if (CustomBrowsers.SelectedItem is CustomBrowser selectedCustomBrowser) - { - Settings.CustomChromiumBrowsers.Remove(selectedCustomBrowser); - _ = Task.Run(() => Main.ReloadAllBookmarks()); - } - } - - private void MouseDoubleClickOnSelectedCustomBrowser(object sender, MouseButtonEventArgs e) - { - EditSelectedCustomBrowser(); - } - - private void Others_Click(object sender, RoutedEventArgs e) - { - - if (CustomBrowsersList.Visibility == Visibility.Collapsed) - { - CustomBrowsersList.Visibility = Visibility.Visible; - } - else - CustomBrowsersList.Visibility = Visibility.Collapsed; - } - - private void EditCustomBrowser(object sender, RoutedEventArgs e) - { - EditSelectedCustomBrowser(); - } - - private void EditSelectedCustomBrowser() - { - if (SelectedCustomBrowser is null) - return; - - var window = new CustomBrowserSettingWindow(SelectedCustomBrowser); - var result = window.ShowDialog() ?? false; - if (result) - { - _ = Task.Run(() => Main.ReloadAllBookmarks()); - } + _ = Task.Run(() => Main.ReloadAllBookmarks()); } } } From 6373778b3a3f8276cdcd1b1209b8c10ce27644b1 Mon Sep 17 00:00:00 2001 From: Yusyuriv Date: Tue, 16 Apr 2024 13:16:52 +0600 Subject: [PATCH 02/21] Fix Firefox bookmark SQL query formatting --- .../FirefoxBookmarkLoader.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs index 9d9480f99..cdbcfbef2 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs @@ -14,9 +14,9 @@ public abstract class FirefoxBookmarkLoaderBase : IBookmarkLoader private const string QueryAllBookmarks = """ SELECT moz_places.url, moz_bookmarks.title FROM moz_places - INNER JOIN moz_bookmarks ON ( - moz_bookmarks.fk NOT NULL AND moz_bookmarks.title NOT NULL AND moz_bookmarks.fk = moz_places.id - ) + INNER JOIN moz_bookmarks ON ( + moz_bookmarks.fk NOT NULL AND moz_bookmarks.title NOT NULL AND moz_bookmarks.fk = moz_places.id + ) ORDER BY moz_places.visit_count DESC """; From 7393b27976ddb8c79c6f46cc1b9e912d239a40fd Mon Sep 17 00:00:00 2001 From: Yusyuriv Date: Tue, 16 Apr 2024 13:44:33 +0600 Subject: [PATCH 03/21] Fix a typo in variable name in FirefoxBookmarkLoader.cs --- .../FirefoxBookmarkLoader.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs index cdbcfbef2..35ad32fb3 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs @@ -113,10 +113,10 @@ public class FirefoxBookmarkLoader : FirefoxBookmarkLoaderBase var defaultProfileFolderName = defaultProfileFolderNameRaw.Split('=').Last(); - var indexOfDefaultProfileAtttributePath = lines.IndexOf("Path=" + defaultProfileFolderName); + var indexOfDefaultProfileAttributePath = lines.IndexOf("Path=" + defaultProfileFolderName); // Seen in the example above, the IsRelative attribute is always above the Path attribute - var relativeAttribute = lines[indexOfDefaultProfileAtttributePath - 1]; + var relativeAttribute = lines[indexOfDefaultProfileAttributePath - 1]; return relativeAttribute == "0" // See above, the profile is located in a custom location, path is not relative, so IsRelative=0 ? defaultProfileFolderName + @"\places.sqlite" From 148afc401d63bd0a96d6bf0879c703523ecd9dd5 Mon Sep 17 00:00:00 2001 From: Yusyuriv Date: Wed, 17 Apr 2024 08:56:38 +0600 Subject: [PATCH 04/21] Add a hyphen in a word inside a comment in BrowserBookmark/Main.cs --- Plugins/Flow.Launcher.Plugin.BrowserBookmark/Main.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Main.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Main.cs index 23efd29b9..a48d70f2d 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Main.cs @@ -47,7 +47,7 @@ public class Main : ISettingProvider, IPlugin, IReloadable, IPluginI18n, IContex public List Query(Query query) { - // For when the plugin being previously disabled and is now reenabled + // For when the plugin being previously disabled and is now re-enabled if (!_initialized) { LoadBookmarksIfEnabled(); From 420446da7cc61283e1d3234b3a079456435243fd Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Tue, 30 Apr 2024 22:54:46 +0800 Subject: [PATCH 05/21] Update expect.txt --- .github/actions/spelling/expect.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index c4b1ee849..8a048c711 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -74,6 +74,7 @@ WCA_ACCENT_POLICY HGlobal dopusrt firefox +Firefox msedge svgc ime From 507a126076c257df30bade5799f7251428aab27b Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Wed, 1 May 2024 11:11:01 +0800 Subject: [PATCH 06/21] Try to add terms in allow.txt --- .github/actions/spelling/allow.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/actions/spelling/allow.txt b/.github/actions/spelling/allow.txt index 00cc67ea0..a36a6af3e 100644 --- a/.github/actions/spelling/allow.txt +++ b/.github/actions/spelling/allow.txt @@ -3,3 +3,6 @@ https ssh ubuntu runcount +Firefox +Português +Português (Brasil) From abe187a15e16dc36ce10df7c95ee0cca51316360 Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Fri, 3 May 2024 00:38:46 +0800 Subject: [PATCH 07/21] Use keyboard keys markup --- README.md | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 9ebbe246c..a19d99987 100644 --- a/README.md +++ b/README.md @@ -28,11 +28,10 @@ Dedicated to making your work flow more seamless. Search everything from applica -- Use the F1 key to open/hide the preview panel. +- Use F1 to toggle the preview panel. - Media files will be displayed as large images, otherwise a large icon and entire path will be displayed. - Turn on preview permanently via Settings (Always Preview). -- Use hotkeys (Ctrl+Plus,Minus / Ctrl+],[) to adjust flow's search window width and height quickly if the preview area is too narrow. -- This feature is currently in its early stages. +- Use hotkeys (Ctrl++/- and Ctrl+[/]) to adjust flow's search window width and height quickly if the preview area is too narrow. ### Everything Plugin Merged Into Explorer @@ -52,7 +51,7 @@ Dedicated to making your work flow more seamless. Search everything from applica - Drag an item to Discord or computer location. -- The target program determines whether the drop is to copy or move the item (can change via CTRL or Alt), and the operation is displayed on the mouse cursor. +- The target program determines whether the drop is to copy or move the item (can change via Ctrl or Alt), and the operation is displayed on the mouse cursor. ### Custom Shortcut @@ -156,7 +155,7 @@ And you can download [early access version](https://github.com/Flow-Launcher/Pre - Run batch and PowerShell commands as Administrator or a different user. -- Ctrl+Enter to Run as Administrator. +- Ctrl+Shift+Enter to Run as Administrator. ### Explorer @@ -206,7 +205,7 @@ And you can download [early access version](https://github.com/Flow-Launcher/Pre - Pause hotkey activation when you are playing games. -- When in search window use Ctrl+F12 to toggle on/off. +- When in search window use Ctrl+F12 to toggle on/off. - Type `Toggle Game Mode` @@ -271,22 +270,22 @@ And you can download [early access version](https://github.com/Flow-Launcher/Pre | ------------------------------------------------------------------ | ---------------------------------------------- | | Alt+ Space | Open search window (default and configurable) | | Enter | Execute | -| Ctrl+Shift+Enter | Run as admin | +| Ctrl+Shift+Enter | Run as admin | | | Scroll up & down | | | Back to result / Open Context Menu | -| Ctrl +O , Shift +Enter | Open Context Menu | +| Ctrl +O , Shift +Enter | Open Context Menu | | Tab | Autocomplete | | F1 | Toggle Preview Panel (default and configurable)| | Esc | Back to results / hide search window | -| Ctrl +C | Copy the actual folder / file | -| Ctrl +I | Open flow's settings | -| Ctrl +R | Run the current query again (refresh results) | +| Ctrl +C | Copy the actual folder / file | +| Ctrl +I | Open flow's settings | +| Ctrl +R | Run the current query again (refresh results) | | F5 | Reload all plugin data | -| Ctrl + F12 | Toggle Game Mode when in search window | -| Ctrl + +,- | Quickly change maximum results shown | -| Ctrl + [,] | Quickly change search window width | -| Ctrl + H | Open search history | -| Ctrl + Backspace | Back to previous directory | +| Ctrl + F12 | Toggle Game Mode when in search window | +| Ctrl + +,- | Quickly change maximum results shown | +| Ctrl + [,] | Quickly change search window width | +| Ctrl + H | Open search history | +| Ctrl + Backspace | Back to previous directory | ## System Command List From 5678790ce565c57ca94dd9cd58036ae8c57b5333 Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Fri, 3 May 2024 00:44:31 +0800 Subject: [PATCH 08/21] Remove outdated info --- README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/README.md b/README.md index a19d99987..128ae46bd 100644 --- a/README.md +++ b/README.md @@ -66,10 +66,6 @@ Dedicated to making your work flow more seamless. Search everything from applica - Support for .url files, flow can now search installed steam/epic games. - Improved UWP indexing. -### Improved Memory Usage - -- Fixed a memory leak and reduced overall memory usage. - ### Improved Plugin / Plugin Store - Search plugins in the Plugin Store and existing plugin tab. From c500e396495843954fa8195fbc1fac0cca96400c Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Fri, 3 May 2024 00:56:23 +0800 Subject: [PATCH 09/21] Refactor installation guide --- README.md | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 128ae46bd..b2b8c5a75 100644 --- a/README.md +++ b/README.md @@ -99,11 +99,25 @@ Dedicated to making your work flow more seamless. Search everything from applica ### Installation -| [Windows 7+ installer](https://github.com/Flow-Launcher/Flow.Launcher/releases/latest/download/Flow-Launcher-Setup.exe) | [Portable](https://github.com/Flow-Launcher/Flow.Launcher/releases/latest/download/Flow-Launcher-Portable.zip) | -| :----------------------------------------------------------: | :----------------------------------------------------------: | +[Windows 7+ Installer](https://github.com/Flow-Launcher/Flow.Launcher/releases/latest/download/Flow-Launcher-Setup.exe) or [Portable Version](https://github.com/Flow-Launcher/Flow.Launcher/releases/latest/download/Flow-Launcher-Portable.zip) -| `winget install "Flow Launcher"` | `scoop install Flow-Launcher` | `choco install Flow-Launcher` | -| :------------------------------: | :------------------------------: | :------------------------------: | + +#### Winget + +``` +winget install "Flow Launcher" +``` +#### Scoop + +``` +scoop install Flow-Launcher +``` + +#### Chocolatey + +``` +choco install Flow-Launcher +``` > When installing for the first time Windows may raise an issue about security due to code not being signed, if you downloaded from this repo then you are good to continue the set up. From c1ffd1ca8fddd5065ebfaeb6bca5ac0cf94f9f8b Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Fri, 3 May 2024 01:09:04 +0800 Subject: [PATCH 10/21] Add language list --- README.md | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b2b8c5a75..3c1d2c4f3 100644 --- a/README.md +++ b/README.md @@ -196,12 +196,40 @@ And you can download [early access version](https://github.com/Flow-Launcher/Pre - There are various themes and you also can make your own. -### 💬 Language +### 💬 Languages - Supports languages from Chinese to Italian and more. -- Supports Pinyin search. +- Supports Pinyin (拼音) search. - [Crowdin](https://crowdin.com/project/flow-launcher) support for language translations. + +Supported languages +- English +- 中文 +- 中文(繁体) +- Українська +- Русский +- Français +- 日本語 +- Dutch +- Polski +- Dansk +- de, Deutsch +- ko, 한국어 +- Srpski +- Português +- Português (Brasil) +- Spanish +- es-419, Spanish (Latin America) +- Italiano +- Norsk Bokmål +- Slovenčina +- Türkçe +- čeština +- اللغة العربية +- Tiếng Việt + + ### Portable - Fully portable. From 79eaef533d549a0f3cfe4ff00529cc9a3ced9d5d Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Fri, 3 May 2024 01:13:28 +0800 Subject: [PATCH 11/21] Update wording & add description --- README.md | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 3c1d2c4f3..f33bd00a3 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,10 @@

-Dedicated to making your work flow more seamless. Search everything from applications, files, bookmarks, YouTube, Twitter and more. Flow will continue to evolve, designed to be open and built with the community at heart. +A open source launcher app.

+ +

+Dedicated to making your work flow more seamless. Search everything from applications, files, bookmarks, YouTube, Twitter and more. Flow will continue to evolve, designed to be open and built with the community at heart.

Remember to star it, flow will love you more :)

@@ -31,7 +34,7 @@ Dedicated to making your work flow more seamless. Search everything from applica - Use F1 to toggle the preview panel. - Media files will be displayed as large images, otherwise a large icon and entire path will be displayed. - Turn on preview permanently via Settings (Always Preview). -- Use hotkeys (Ctrl++/- and Ctrl+[/]) to adjust flow's search window width and height quickly if the preview area is too narrow. +- Use Ctrl++/- and Ctrl+[/] to adjust search window width and height quickly if the preview area is too narrow. ### Everything Plugin Merged Into Explorer @@ -44,14 +47,14 @@ Dedicated to making your work flow more seamless. Search everything from applica -- Display the date and time when the search window is triggered. +- Display date and time in search window. ### Drag & Drop -- Drag an item to Discord or computer location. -- The target program determines whether the drop is to copy or move the item (can change via Ctrl or Alt), and the operation is displayed on the mouse cursor. +- Drag a file/folder to File Exlporer, or even Discord. +- Copy/move behavior can be change via Ctrl or Shift, and the operation is displayed on the mouse cursor. ### Custom Shortcut @@ -62,11 +65,11 @@ Dedicated to making your work flow more seamless. Search everything from applica ### Improved Program Plugin -- PATH is now indexed +- PATH is now indexed. - Support for .url files, flow can now search installed steam/epic games. - Improved UWP indexing. -### Improved Plugin / Plugin Store +### Improved Plugin Store - Search plugins in the Plugin Store and existing plugin tab. - Categorised sections in Plugin Store to easily see new and updated plugins. @@ -78,7 +81,7 @@ Dedicated to making your work flow more seamless. Search everything from applica - The design has been adjusted to align to the overall look and feel of flow. - Simplified the information displayed on buttons -🚂[Full Changelogs](https://github.com/Flow-Launcher/Flow.Launcher/releases) +🚂[Full Changelog](https://github.com/Flow-Launcher/Flow.Launcher/releases) @@ -243,7 +246,7 @@ And you can download [early access version](https://github.com/Flow-Launcher/Pre - Pause hotkey activation when you are playing games. -- When in search window use Ctrl+F12 to toggle on/off. +- When in search window use Ctrl+F12 to toggle on/off. - Type `Toggle Game Mode` From 48384a8beaa0cc159b468d9e6821cc87a6a441de Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Fri, 3 May 2024 01:17:18 +0800 Subject: [PATCH 12/21] collapsed language list --- README.md | 54 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index f33bd00a3..8b16a3035 100644 --- a/README.md +++ b/README.md @@ -205,33 +205,35 @@ And you can download [early access version](https://github.com/Flow-Launcher/Pre - Supports Pinyin (拼音) search. - [Crowdin](https://crowdin.com/project/flow-launcher) support for language translations. - +
Supported languages -- English -- 中文 -- 中文(繁体) -- Українська -- Русский -- Français -- 日本語 -- Dutch -- Polski -- Dansk -- de, Deutsch -- ko, 한국어 -- Srpski -- Português -- Português (Brasil) -- Spanish -- es-419, Spanish (Latin America) -- Italiano -- Norsk Bokmål -- Slovenčina -- Türkçe -- čeština -- اللغة العربية -- Tiếng Việt - +
    +
  • English
  • +
  • 中文
  • +
  • 中文(繁体)
  • +
  • Українська
  • +
  • Русский
  • +
  • Français
  • +
  • 日本語
  • +
  • Dutch
  • +
  • Polski
  • +
  • Dansk
  • +
  • de, Deutsch
  • +
  • ko, 한국어
  • +
  • Srpski
  • +
  • Português
  • +
  • Português (Brasil)
  • +
  • Spanish
  • +
  • es-419, Spanish (Latin America)
  • +
  • Italiano
  • +
  • Norsk Bokmål
  • +
  • Slovenčina
  • +
  • Türkçe
  • +
  • čeština
  • +
  • اللغة العربية
  • +
  • Tiếng Việt
  • +
+
### Portable From 28c261238b9245660e8010e2a600f31504a8c50f Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Fri, 3 May 2024 01:22:52 +0800 Subject: [PATCH 13/21] Fix double key --- README.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 8b16a3035..55b6a369a 100644 --- a/README.md +++ b/README.md @@ -313,22 +313,22 @@ And you can download [early access version](https://github.com/Flow-Launcher/Pre | ------------------------------------------------------------------ | ---------------------------------------------- | | Alt+ Space | Open search window (default and configurable) | | Enter | Execute | -| Ctrl+Shift+Enter | Run as admin | +| Ctrl+Shift+Enter | Run as admin | | | Scroll up & down | | | Back to result / Open Context Menu | -| Ctrl +O , Shift +Enter | Open Context Menu | +| Ctrl +O , Shift +Enter | Open Context Menu | | Tab | Autocomplete | | F1 | Toggle Preview Panel (default and configurable)| | Esc | Back to results / hide search window | -| Ctrl +C | Copy the actual folder / file | -| Ctrl +I | Open flow's settings | -| Ctrl +R | Run the current query again (refresh results) | +| Ctrl +C | Copy the actual folder / file | +| Ctrl +I | Open flow's settings | +| Ctrl +R | Run the current query again (refresh results) | | F5 | Reload all plugin data | -| Ctrl + F12 | Toggle Game Mode when in search window | -| Ctrl + +,- | Quickly change maximum results shown | -| Ctrl + [,] | Quickly change search window width | -| Ctrl + H | Open search history | -| Ctrl + Backspace | Back to previous directory | +| Ctrl + F12 | Toggle Game Mode when in search window | +| Ctrl + +,- | Quickly change maximum results shown | +| Ctrl + [,] | Quickly change search window width | +| Ctrl + H | Open search history | +| Ctrl + Backspace | Back to previous directory | ## System Command List From 8ea781266bd7f4951597eb36773178c4e8a9b3dd Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Fri, 3 May 2024 13:16:38 +0800 Subject: [PATCH 14/21] Update Hotkeys guide --- README.md | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 55b6a369a..0f4e08f63 100644 --- a/README.md +++ b/README.md @@ -309,26 +309,28 @@ And you can download [early access version](https://github.com/Flow-Launcher/Pre ## ⌨️ Hotkeys -| Hotkey | Description | -| ------------------------------------------------------------------ | ---------------------------------------------- | -| Alt+ Space | Open search window (default and configurable) | -| Enter | Execute | -| Ctrl+Shift+Enter | Run as admin | -| | Scroll up & down | -| | Back to result / Open Context Menu | -| Ctrl +O , Shift +Enter | Open Context Menu | -| Tab | Autocomplete | -| F1 | Toggle Preview Panel (default and configurable)| -| Esc | Back to results / hide search window | -| Ctrl +C | Copy the actual folder / file | -| Ctrl +I | Open flow's settings | -| Ctrl +R | Run the current query again (refresh results) | -| F5 | Reload all plugin data | -| Ctrl + F12 | Toggle Game Mode when in search window | -| Ctrl + +,- | Quickly change maximum results shown | -| Ctrl + [,] | Quickly change search window width | -| Ctrl + H | Open search history | -| Ctrl + Backspace | Back to previous directory | +| Hotkey | Description | +| ------------------------------------------------------------------------- | ----------------------------------------------- | +| Alt+Space | Open search window (default and configurable) | +| Enter | Execute | +| Ctrl+Enter | Open containing folder | +| Ctrl+Shift+Enter | Run as admin | +| /, Shift+Tab/Tab | Previous / Next result | +| / | Back to result / Open Context Menu | +| Ctrl+O , Shift+Enter | Open Context Menu | +| Ctrl+Tab | Autocomplete | +| F1 | Toggle Preview Panel (default and configurable) | +| Esc | Back to results / hide search window | +| Ctrl+C | Copy folder / file | +| Ctrl+Shift+C | Copy folder / file path | +| Ctrl+I | Open Flow's settings | +| Ctrl+R | Run the current query again (refresh results) | +| F5 | Reload all plugin data | +| Ctrl+F12 | Toggle Game Mode when in search window | +| Ctrl++,- | Adjust maximum results shown | +| Ctrl+[,] | Adjust search window width | +| Ctrl+H | Open search history | +| Ctrl+Backspace | Back to previous directory | ## System Command List From 95eeb61c457e9789fa7e3ffe8acaf4bbdef895ab Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Fri, 3 May 2024 13:23:48 +0800 Subject: [PATCH 15/21] Add default hotkey for prev/next page command --- Flow.Launcher.Infrastructure/UserSettings/Settings.cs | 4 ++-- README.md | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs index 58b1cc467..7bb8fe200 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs @@ -27,8 +27,8 @@ namespace Flow.Launcher.Infrastructure.UserSettings public string SelectNextItemHotkey2 { get; set; } = $""; public string SelectPrevItemHotkey { get; set; } = $"Shift + Tab"; public string SelectPrevItemHotkey2 { get; set; } = $""; - public string SelectNextPageHotkey { get; set; } = $""; - public string SelectPrevPageHotkey { get; set; } = $""; + public string SelectNextPageHotkey { get; set; } = $"PageUp"; + public string SelectPrevPageHotkey { get; set; } = $"PageDown"; public string OpenContextMenuHotkey { get; set; } = $"Ctrl+O"; public string SettingWindowHotkey { get; set; } = $"Ctrl+I"; diff --git a/README.md b/README.md index 0f4e08f63..d61ba666b 100644 --- a/README.md +++ b/README.md @@ -104,12 +104,12 @@ Dedicated to making your work flow more seamless. Search everything from applica [Windows 7+ Installer](https://github.com/Flow-Launcher/Flow.Launcher/releases/latest/download/Flow-Launcher-Setup.exe) or [Portable Version](https://github.com/Flow-Launcher/Flow.Launcher/releases/latest/download/Flow-Launcher-Portable.zip) - #### Winget ``` winget install "Flow Launcher" ``` + #### Scoop ``` @@ -299,6 +299,7 @@ And you can download [early access version](https://github.com/Flow-Launcher/Pre ### 🛒 Plugin Store + - You can view the full plugin list or quickly install a plugin via the Plugin Store menu inside Settings @@ -331,6 +332,7 @@ And you can download [early access version](https://github.com/Flow-Launcher/Pre | Ctrl+[,] | Adjust search window width | | Ctrl+H | Open search history | | Ctrl+Backspace | Back to previous directory | +| PageUp/PageDown | Previous / Next Page | ## System Command List @@ -357,8 +359,6 @@ And you can download [early access version](https://github.com/Flow-Launcher/Pre | Flow Launcher UserData Folder | Open the location where Flow Launcher's settings are stored | | Toggle Game Mode | Toggle Game Mode | - - ### 💁‍♂️ Tips - [More tips](https://flowlauncher.com/docs/#/usage-tips) From fc6de49b4a49b7c88b0fd070611e220048b1ff0c Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Fri, 3 May 2024 13:26:46 +0800 Subject: [PATCH 16/21] Use desc in scoop --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d61ba666b..a161f8c9b 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@

-A open source launcher app.

+A quick file search and app launcher for Windows with community-made plugins。

Dedicated to making your work flow more seamless. Search everything from applications, files, bookmarks, YouTube, Twitter and more. Flow will continue to evolve, designed to be open and built with the community at heart.

From 31561be4d5bea7040c6e50fcbd9b488303b84d3c Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Fri, 3 May 2024 13:48:48 +0800 Subject: [PATCH 17/21] Merge new features into features --- README.md | 84 ++++++++++++++++--------------------------------------- 1 file changed, 24 insertions(+), 60 deletions(-) diff --git a/README.md b/README.md index a161f8c9b..7f94e48ac 100644 --- a/README.md +++ b/README.md @@ -25,66 +25,6 @@ Dedicated to making your work flow more seamless. Search everything from applica -## 🎅 New Features🤶 - -### Preview Panel - - - -- Use F1 to toggle the preview panel. -- Media files will be displayed as large images, otherwise a large icon and entire path will be displayed. -- Turn on preview permanently via Settings (Always Preview). -- Use Ctrl++/- and Ctrl+[/] to adjust search window width and height quickly if the preview area is too narrow. - -### Everything Plugin Merged Into Explorer - - - -- Switch easily between Everything and Windows Search to take advantage of both search engines (remember to remove existing Everything plugin). -- Use features available to both Everything and Explorer plugins - -### Date & Time Display In Search Window - - - -- Display date and time in search window. - -### Drag & Drop - - - -- Drag a file/folder to File Exlporer, or even Discord. -- Copy/move behavior can be change via Ctrl or Shift, and the operation is displayed on the mouse cursor. - -### Custom Shortcut - - - - -- New shortcut functionality to set additional action keywords or search terms. - -### Improved Program Plugin - -- PATH is now indexed. -- Support for .url files, flow can now search installed steam/epic games. -- Improved UWP indexing. - -### Improved Plugin Store - -- Search plugins in the Plugin Store and existing plugin tab. -- Categorised sections in Plugin Store to easily see new and updated plugins. - -### Improved Non-C# Plugin's Panel Design - - - -- The design has been adjusted to align to the overall look and feel of flow. -- Simplified the information displayed on buttons - -🚂[Full Changelog](https://github.com/Flow-Launcher/Flow.Launcher/releases) - - -

Getting StartedFeatures • @@ -135,6 +75,7 @@ And you can download [early access version](https://github.com/Flow-Launcher/Pre - Search for apps, files or file contents. +- Supports Everything and Windows Index. @@ -176,6 +117,13 @@ And you can download [early access version](https://github.com/Flow-Launcher/Pre - Save file or folder locations for quick access. +#### Drag & Drop + + + +- Drag a file/folder to File Exlporer, 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 @@ -188,6 +136,16 @@ And you can download [early access version](https://github.com/Flow-Launcher/Pre - Prioritise the order of each plugin's results. +### Preview Panel + + + +- Use F1 to toggle the preview panel. +- Media files will be displayed as large images, otherwise a large icon and full path will be displayed. +- Turn on preview permanently via Settings (Always Preview). +- Use Ctrl++/- and Ctrl+[/] to adjust search window width and height quickly if the preview area is too narrow. + + ### Customizations @@ -199,6 +157,12 @@ And you can download [early access version](https://github.com/Flow-Launcher/Pre - There are various themes and you also can make your own. +#### Date & Time Display In Search Window + + + +- Display date and time in search window. + ### 💬 Languages - Supports languages from Chinese to Italian and more. From 4667bda4966b8f87ef79f0937af8c7f68616013d Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Fri, 3 May 2024 14:05:04 +0800 Subject: [PATCH 18/21] Use "Previous" instead of "Prev" --- Flow.Launcher/Languages/en.xaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml index bda86e481..fd24f825e 100644 --- a/Flow.Launcher/Languages/en.xaml +++ b/Flow.Launcher/Languages/en.xaml @@ -185,9 +185,9 @@ Auto Complete Runs autocomplete for the selected items. Select Next Item - Select Prev Item + Select Previous Item Next Page - Prev Page + Previous Page Open Context Menu Open Setting Window Copy File Path @@ -195,6 +195,7 @@ Toggle History Open Containing Folder Run As Admin + Refresh Search Results Reload Plugins Data Quick Adjust Window Width Quick Adjust Window Height From f93da0044cbadb947610cea780ee71c9caef2901 Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Fri, 3 May 2024 14:05:11 +0800 Subject: [PATCH 19/21] Fix gamemode hotkey and add requery hotkey --- Flow.Launcher/SettingWindow.xaml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Flow.Launcher/SettingWindow.xaml b/Flow.Launcher/SettingWindow.xaml index 84b91e312..119268d6b 100644 --- a/Flow.Launcher/SettingWindow.xaml +++ b/Flow.Launcher/SettingWindow.xaml @@ -2802,7 +2802,13 @@ Title="{DynamicResource ToggleGameModeHotkey}" Icon="" Type="Inside"> - + + + + Date: Fri, 3 May 2024 17:53:50 +1000 Subject: [PATCH 20/21] Fix README.md typo --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7f94e48ac..858d39d1c 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@

-A quick file search and app launcher for Windows with community-made plugins。

+A quick file search and app launcher for Windows with community-made plugins.

Dedicated to making your work flow more seamless. Search everything from applications, files, bookmarks, YouTube, Twitter and more. Flow will continue to evolve, designed to be open and built with the community at heart.

@@ -64,7 +64,7 @@ choco install Flow-Launcher > When installing for the first time Windows may raise an issue about security due to code not being signed, if you downloaded from this repo then you are good to continue the set up. -And you can download [early access version](https://github.com/Flow-Launcher/Prereleases/releases). +Or download the [early access version](https://github.com/Flow-Launcher/Prereleases/releases). From be1c3f7fe725acc5611971f276a7e625e09f3d9a Mon Sep 17 00:00:00 2001 From: DB p Date: Thu, 16 May 2024 17:04:29 +0900 Subject: [PATCH 21/21] Block Mouse Hover --- Flow.Launcher/MainWindow.xaml | 1 + Flow.Launcher/MainWindow.xaml.cs | 23 ++++++++++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/Flow.Launcher/MainWindow.xaml b/Flow.Launcher/MainWindow.xaml index 2e6e973a7..34b6dfcdc 100644 --- a/Flow.Launcher/MainWindow.xaml +++ b/Flow.Launcher/MainWindow.xaml @@ -25,6 +25,7 @@ LocationChanged="OnLocationChanged" Opacity="{Binding MainWindowOpacity, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" PreviewKeyDown="OnKeyDown" + PreviewKeyUp="OnKeyUp" ResizeMode="NoResize" ShowInTaskbar="False" SizeToContent="Height" diff --git a/Flow.Launcher/MainWindow.xaml.cs b/Flow.Launcher/MainWindow.xaml.cs index 76e587cdc..9c5ed46c0 100644 --- a/Flow.Launcher/MainWindow.xaml.cs +++ b/Flow.Launcher/MainWindow.xaml.cs @@ -47,6 +47,7 @@ namespace Flow.Launcher private MainViewModel _viewModel; private bool _animating; MediaPlayer animationSound = new MediaPlayer(); + private bool isArrowKeyPressed = false; #endregion @@ -109,9 +110,11 @@ namespace Flow.Launcher private void OnInitialized(object sender, EventArgs e) { } - private void OnLoaded(object sender, RoutedEventArgs _) { + // MouseEventHandler + PreviewMouseMove += MainPreviewMouseMove; + CheckFirstLaunch(); HideStartup(); // show notify icon when flowlauncher is hidden @@ -406,6 +409,7 @@ namespace Flow.Launcher if (_animating) return; + isArrowKeyPressed = true; _animating = true; UpdatePosition(); @@ -494,6 +498,7 @@ namespace Flow.Launcher windowsb.Completed += (_, _) => _animating = false; _settings.WindowLeft = Left; _settings.WindowTop = Top; + isArrowKeyPressed = false; if (QueryTextBox.Text.Length == 0) { @@ -644,10 +649,12 @@ namespace Flow.Launcher switch (e.Key) { case Key.Down: + isArrowKeyPressed = true; _viewModel.SelectNextItemCommand.Execute(null); e.Handled = true; break; case Key.Up: + isArrowKeyPressed = true; _viewModel.SelectPrevItemCommand.Execute(null); e.Handled = true; break; @@ -698,7 +705,21 @@ namespace Flow.Launcher } } + private void OnKeyUp(object sender, KeyEventArgs e) + { + if (e.Key == Key.Up || e.Key == Key.Down) + { + isArrowKeyPressed = false; + } + } + private void MainPreviewMouseMove(object sender, System.Windows.Input.MouseEventArgs e) + { + if (isArrowKeyPressed) + { + e.Handled = true; // Ignore Mouse Hover when press Arrowkeys + } + } public void PreviewReset() { _viewModel.ResetPreview();