From f6d25aa94c7d1861a4636000c640de001776791f Mon Sep 17 00:00:00 2001 From: Yusyuriv Date: Tue, 16 Apr 2024 13:00:19 +0600 Subject: [PATCH 01/33] Code cleanup: Flow.Launcher.Plugin.BrowserBookmark --- .../ChromeBookmarkLoader.cs | 31 +- .../ChromiumBookmarkLoader.cs | 129 ++++--- .../Commands/BookmarkLoader.cs | 81 ++-- .../CustomChromiumBookmarkLoader.cs | 25 +- .../CustomFirefoxBookmarkLoader.cs | 35 +- .../EdgeBookmarkLoader.cs | 27 +- .../FirefoxBookmarkLoader.cs | 233 ++++++------ .../IBookmarkLoader.cs | 11 +- .../Main.cs | 352 +++++++++--------- .../Models/Bookmark.cs | 31 +- .../Models/CustomBrowser.cs | 67 ++-- .../Models/Settings.cs | 21 +- .../Views/CustomBrowserSetting.xaml | 1 - .../Views/CustomBrowserSetting.xaml.cs | 83 ++--- .../Views/SettingsControl.xaml.cs | 169 +++++---- 15 files changed, 637 insertions(+), 659 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/ChromeBookmarkLoader.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/ChromeBookmarkLoader.cs index 09755fe0cb8..65757b80253 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/ChromeBookmarkLoader.cs +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/ChromeBookmarkLoader.cs @@ -3,23 +3,22 @@ using System.Collections.Generic; using System.IO; -namespace Flow.Launcher.Plugin.BrowserBookmark +namespace Flow.Launcher.Plugin.BrowserBookmark; + +public class ChromeBookmarkLoader : ChromiumBookmarkLoader { - public class ChromeBookmarkLoader : ChromiumBookmarkLoader + public override List GetBookmarks() { - public override List GetBookmarks() - { - return LoadChromeBookmarks(); - } + return LoadChromeBookmarks(); + } - 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; - } + 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; } -} \ No newline at end of file +} diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/ChromiumBookmarkLoader.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/ChromiumBookmarkLoader.cs index 8ce597b30e1..48acf61090b 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/ChromiumBookmarkLoader.cs +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/ChromiumBookmarkLoader.cs @@ -4,92 +4,91 @@ 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); - - foreach (var profile in paths) - { - var bookmarkPath = Path.Combine(profile, "Bookmarks"); - if (!File.Exists(bookmarkPath)) - continue; - - Main.RegisterBookmarkFile(bookmarkPath); + var bookmarkPath = Path.Combine(profile, "Bookmarks"); + if (!File.Exists(bookmarkPath)) + continue; - var source = name + (Path.GetFileName(profile) == "Default" ? "" : $" ({Path.GetFileName(profile)})"); - bookmarks.AddRange(LoadBookmarksFromFile(bookmarkPath, source)); - } + Main.RegisterBookmarkFile(bookmarkPath); - return bookmarks; + var source = name + (Path.GetFileName(profile) == "Default" ? "" : $" ({Path.GetFileName(profile)})"); + bookmarks.AddRange(LoadBookmarksFromFile(bookmarkPath, source)); } - protected List LoadBookmarksFromFile(string path, string source) - { - var bookmarks = new List(); + return bookmarks; + } - if (!File.Exists(path)) - return bookmarks; + protected List LoadBookmarksFromFile(string path, string source) + { + var bookmarks = new List(); - using var jsonDocument = JsonDocument.Parse(File.ReadAllText(path)); - if (!jsonDocument.RootElement.TryGetProperty("roots", out var rootElement)) - return bookmarks; - EnumerateRoot(rootElement, bookmarks, source); + if (!File.Exists(path)) return bookmarks; - } - private void EnumerateRoot(JsonElement rootElement, ICollection bookmarks, string 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) + { + 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) + private void EnumerateFolderBookmark(JsonElement folderElement, ICollection bookmarks, + string source) + { + if (!folderElement.TryGetProperty("children", out var childrenElement)) + return; + foreach (var subElement in childrenElement.EnumerateArray()) { - if (!folderElement.TryGetProperty("children", out var childrenElement)) - return; - foreach (var subElement in childrenElement.EnumerateArray()) + if (subElement.TryGetProperty("type", out var type)) { - 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 + switch (type.GetString()) { - Log.Error( - $"ChromiumBookmarkLoader: EnumerateFolderBookmark: type property not found for {subElement.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()}"); + } } } } diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Commands/BookmarkLoader.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Commands/BookmarkLoader.cs index d08c05b6ba1..3468015ebaf 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.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(); + internal static List LoadAllBookmarks(Settings setting) + { + var allBookmarks = new List(); - if (setting.LoadChromeBookmark) - { - // Add Chrome bookmarks - var chromeBookmarks = new ChromeBookmarkLoader(); - allBookmarks.AddRange(chromeBookmarks.GetBookmarks()); - } + 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.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()); - } + if (setting.LoadEdgeBookmark) + { + // Add Edge (Chromium) bookmarks + var edgeBookmarks = new EdgeBookmarkLoader(); + allBookmarks.AddRange(edgeBookmarks.GetBookmarks()); + } - foreach (var browser in setting.CustomChromiumBrowsers) + foreach (var browser in setting.CustomChromiumBrowsers) + { + IBookmarkLoader loader = browser.BrowserType switch { - 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(); + 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 fa98f4d7c98..005c83992bf 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 +namespace Flow.Launcher.Plugin.BrowserBookmark; + +public class CustomChromiumBookmarkLoader : ChromiumBookmarkLoader { - public class CustomChromiumBookmarkLoader : ChromiumBookmarkLoader + public CustomChromiumBookmarkLoader(CustomBrowser browser) { - 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; } - - public override List GetBookmarks() => BrowserDataPath != null ? LoadBookmarks(BrowserDataPath, BrowserName) : LoadBookmarksFromFile(BookmarkFilePath, BrowserName); + 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 82bdc29f54d..d0bb7b0cc71 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 +namespace Flow.Launcher.Plugin.BrowserBookmark; + +public class CustomFirefoxBookmarkLoader : FirefoxBookmarkLoaderBase { - public class CustomFirefoxBookmarkLoader : FirefoxBookmarkLoaderBase + public CustomFirefoxBookmarkLoader(CustomBrowser browser) { - public CustomFirefoxBookmarkLoader(CustomBrowser browser) - { - BrowserName = browser.Name; - BrowserDataPath = browser.DataDirectoryPath; - } - - /// - /// Path to places.sqlite - /// - public string BrowserDataPath { get; init; } - - public string BrowserName { get; init; } + BrowserName = browser.Name; + BrowserDataPath = browser.DataDirectoryPath; + } + + /// + /// Path to places.sqlite + /// + public string BrowserDataPath { get; init; } - public override List GetBookmarks() - { - return GetBookmarksFromPath(Path.Combine(BrowserDataPath, "places.sqlite")); - } + 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 79190f0ef29..40123b022e1 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/EdgeBookmarkLoader.cs +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/EdgeBookmarkLoader.cs @@ -3,21 +3,20 @@ using System.Collections.Generic; using System.IO; -namespace Flow.Launcher.Plugin.BrowserBookmark +namespace Flow.Launcher.Plugin.BrowserBookmark; + +public class EdgeBookmarkLoader : ChromiumBookmarkLoader { - public class EdgeBookmarkLoader : ChromiumBookmarkLoader + private List LoadEdgeBookmarks() { - 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")); + 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; - } - - public override List GetBookmarks() => LoadEdgeBookmarks(); + 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 3d061e75846..9d9480f99f5 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs @@ -5,140 +5,133 @@ 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(); + 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 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}"; + private const string DbPathFormat = "Data Source ={0}"; - 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(); - - 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; - } + 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(); + + 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 + return reader + .Select( + x => new Bookmark( + x["title"] is DBNull ? string.Empty : x["title"].ToString(), + x["url"].ToString() + ) + ) + .ToList(); } +} + +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"); - - 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(); - } - - /* - 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 - - [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. - - [Profile1] - Name=default - IsRelative=1 - Path=Profiles/cydum7q4.default - Default=1 - - [Profile0] - Name=default-release - IsRelative=1 - Path=Profiles/7789f565.default-release - - [General] - StartWithLastProfile=1 - Version=2 - */ - - var lines = ini.Split(new string[] - { - "\r\n" - }, StringSplitOptions.None).ToList(); - - var defaultProfileFolderNameRaw = lines.Where(x => x.Contains("Default=") && x != "Default=1").FirstOrDefault() ?? string.Empty; - - if (string.IsNullOrEmpty(defaultProfileFolderNameRaw)) - return string.Empty; - - var defaultProfileFolderName = defaultProfileFolderNameRaw.Split('=').Last(); - - 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]; - - 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"; - } + 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; + + // 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 + + [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. + + [Profile1] + Name=default + IsRelative=1 + Path=Profiles/cydum7q4.default + Default=1 + + [Profile0] + Name=default-release + IsRelative=1 + Path=Profiles/7789f565.default-release + + [General] + StartWithLastProfile=1 + Version=2 + */ + var lines = ini.Split("\r\n").ToList(); + + var defaultProfileFolderNameRaw = lines.FirstOrDefault(x => x.Contains("Default=") && x != "Default=1") ?? string.Empty; + + if (string.IsNullOrEmpty(defaultProfileFolderNameRaw)) + return string.Empty; + + var defaultProfileFolderName = defaultProfileFolderNameRaw.Split('=').Last(); + + 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]; + + 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 class Extensions +{ + public static IEnumerable Select(this SqliteDataReader reader, Func projection) { - public static IEnumerable Select(this SqliteDataReader reader, Func projection) + while (reader.Read()) { - while (reader.Read()) - { - yield return projection(reader); - } + yield return projection(reader); } } } diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/IBookmarkLoader.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/IBookmarkLoader.cs index 2c48cfd557e..8a972735275 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 a13d6c929fe..23efd29b9ef 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.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 PluginInitContext _context; - private static List cachedBookmarks = new List(); + private static List _cachedBookmarks = new List(); - private static Settings _settings; + private static Settings _settings; - private static bool initialized = false; + private static bool _initialized = false; - public void Init(PluginInitContext context) - { - Main.context = context; + public void Init(PluginInitContext context) + { + _context = context; - _settings = context.API.LoadSettingJsonStorage(); + _settings = context.API.LoadSettingJsonStorage(); - LoadBookmarksIfEnabled(); - } + LoadBookmarksIfEnabled(); + } - private static void LoadBookmarksIfEnabled() + private static void LoadBookmarksIfEnabled() + { + if (_context.CurrentPluginMetadata.Disabled) { - if (context.CurrentPluginMetadata.Disabled) - { - // Don't load or monitor files if disabled - return; - } - - cachedBookmarks = BookmarkLoader.LoadAllBookmarks(_settings); - _ = MonitorRefreshQueueAsync(); - initialized = true; + // Don't load or monitor files if disabled + return; } - public List Query(Query query) + _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) { - // For when the plugin being previously disabled and is now renabled - if (!initialized) - { - LoadBookmarksIfEnabled(); - } + LoadBookmarksIfEnabled(); + } - string param = query.Search.TrimStart(); + string param = query.Search.TrimStart(); - // Should top results be returned? (true if no search parameters have been passed) - var topResults = string.IsNullOrEmpty(param); + // 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 = _ => + if (!topResults) + { + // Since we mixed chrome and firefox bookmarks, we should order them again + return _cachedBookmarks + .Select( + c => new Result { - context.API.OpenUrl(c.Url); + Title = c.Name, + SubTitle = c.Url, + IcoPath = @"Images\bookmark.png", + Score = BookmarkLoader.MatchProgram(c, param).Score, + Action = _ => + { + _context.API.OpenUrl(c.Url); - return true; - }, - ContextData = new BookmarkAttributes - { - Url = 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 + ) + .Where(r => r.Score > 0) + .ToList(); + } + else + { + return _cachedBookmarks + .Select( + c => new Result { - Url = c.Url + 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(); - } + ) + .ToList(); } + } - private static Channel refreshQueue = Channel.CreateBounded(1); + private static Channel _refreshQueue = Channel.CreateBounded(1); - private static SemaphoreSlim fileMonitorSemaphore = new(1, 1); + private static SemaphoreSlim _fileMonitorSemaphore = new(1, 1); - private static async Task MonitorRefreshQueueAsync() + private static async Task MonitorRefreshQueueAsync() + { + if (_fileMonitorSemaphore.CurrentCount < 1) { - if (fileMonitorSemaphore.CurrentCount < 1) - { - return; - } - await fileMonitorSemaphore.WaitAsync(); - var reader = refreshQueue.Reader; - while (await reader.WaitToReadAsync()) - { - if (reader.TryRead(out _)) - { - ReloadAllBookmarks(false); - } - } - fileMonitorSemaphore.Release(); + return; } - - private static readonly List Watchers = new(); - - internal static void RegisterBookmarkFile(string path) + await _fileMonitorSemaphore.WaitAsync(); + var reader = _refreshQueue.Reader; + while (await reader.WaitToReadAsync()) { - var directory = Path.GetDirectoryName(path); - if (!Directory.Exists(directory) || !File.Exists(path)) + if (reader.TryRead(out _)) { - return; + ReloadAllBookmarks(false); } - 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); } + _fileMonitorSemaphore.Release(); + } - public void ReloadData() - { - ReloadAllBookmarks(); - } + private static readonly List Watchers = new(); - public static void ReloadAllBookmarks(bool disposeFileWatchers = true) + internal static void RegisterBookmarkFile(string path) + { + var directory = Path.GetDirectoryName(path); + if (!Directory.Exists(directory) || !File.Exists(path)) { - cachedBookmarks.Clear(); - if (disposeFileWatchers) - DisposeFileWatchers(); - LoadBookmarksIfEnabled(); + return; } - - public string GetTranslatedPluginTitle() + if (Watchers.Any(x => x.Path.Equals(directory, StringComparison.OrdinalIgnoreCase))) { - return context.API.GetTranslation("flowlauncher_plugin_browserbookmark_plugin_name"); + return; } - public string GetTranslatedPluginDescription() + var watcher = new FileSystemWatcher(directory!); + watcher.Filter = Path.GetFileName(path); + + watcher.NotifyFilter = NotifyFilters.FileName | + NotifyFilters.LastWrite | + NotifyFilters.Size; + + watcher.Changed += static (_, _) => { - return context.API.GetTranslation("flowlauncher_plugin_browserbookmark_plugin_description"); - } + _refreshQueue.Writer.TryWrite(default); + }; - public Control CreateSettingPanel() + watcher.Renamed += static (_, _) => { - return new SettingsControl(_settings); - } + _refreshQueue.Writer.TryWrite(default); + }; - public List LoadContextMenus(Result selectedResult) + 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() { - return new List() + new Result { - new Result + Title = _context.API.GetTranslation("flowlauncher_plugin_browserbookmark_copyurl_title"), + SubTitle = _context.API.GetTranslation("flowlauncher_plugin_browserbookmark_copyurl_subtitle"), + Action = _ => { - Title = context.API.GetTranslation("flowlauncher_plugin_browserbookmark_copyurl_title"), - SubTitle = context.API.GetTranslation("flowlauncher_plugin_browserbookmark_copyurl_subtitle"), - Action = _ => + try { - try - { - context.API.CopyToClipboard(((BookmarkAttributes)selectedResult.ContextData).Url); + _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") - } - }; - } + return true; + } + catch (Exception e) + { + var message = "Failed to set url in clipboard"; + Log.Exception("Main", message, e, "LoadContextMenus"); - internal class BookmarkAttributes - { - internal string Url { get; set; } - } + _context.API.ShowMsg(message); - public void Dispose() - { - DisposeFileWatchers(); - } + return false; + } + }, + IcoPath = @"Images\copylink.png", + Glyph = new GlyphInfo(FontFamily: "/Resources/#Segoe Fluent Icons", Glyph: "\ue8c8") + } + }; + } + + internal class BookmarkAttributes + { + internal string Url { get; set; } + } - private static void DisposeFileWatchers() + public void Dispose() + { + DisposeFileWatchers(); + } + + private static void DisposeFileWatchers() + { + foreach (var watcher in Watchers) { - foreach (var watcher in Watchers) - { - watcher.Dispose(); - } - Watchers.Clear(); + 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 c2fa9d9775a..c738da389c5 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; - } + var hashName = Name?.GetHashCode() ?? 0; + var hashUrl = Url?.GetHashCode() ?? 0; + return hashName ^ hashUrl; + } - public List CustomBrowsers { get; set; }= new(); + public virtual bool Equals(Bookmark other) + { + return other != null && Name == other.Name && Url == other.Url; } -} \ No newline at end of file + + 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 69bb56e4879..74e0f299aff 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 +namespace Flow.Launcher.Plugin.BrowserBookmark.Models; + +public class CustomBrowser : BaseModel { - public class CustomBrowser : BaseModel - { - private string _name; - private string _dataDirectoryPath; - private BrowserType browserType = BrowserType.Chromium; + private string _name; + private string _dataDirectoryPath; + private BrowserType _browserType = BrowserType.Chromium; - public string Name - { - get => _name; - set - { - _name = value; - OnPropertyChanged(nameof(Name)); - } - } - - public string DataDirectoryPath + public string Name + { + get => _name; + set { - get => _dataDirectoryPath; - set - { - _dataDirectoryPath = value; - OnPropertyChanged(nameof(DataDirectoryPath)); - } + _name = value; + OnPropertyChanged(); } - - public BrowserType BrowserType + } + + public string DataDirectoryPath + { + get => _dataDirectoryPath; + set { - get => browserType; - set - { - browserType = value; - OnPropertyChanged(nameof(BrowserType)); - } + _dataDirectoryPath = value; + OnPropertyChanged(); } } - public enum BrowserType + public BrowserType BrowserType { - Chromium, - Firefox, + 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 dc1016b4edf..86532d27598 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 392c9e0a78c..f5017ced5d8 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 - { - Name = browser.Name, - DataDirectoryPath = browser.DataDirectoryPath, - BrowserType = browser.BrowserType, - }; - } - - private void ConfirmEditCustomBrowser(object sender, RoutedEventArgs e) + InitializeComponent(); + _currentCustomBrowser = browser; + DataContext = new CustomBrowser { - 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 2947c2cb56f..4bdab89a945 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.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 Settings Settings { get; } - public CustomBrowser SelectedCustomBrowser { get; set; } + public CustomBrowser SelectedCustomBrowser { get; set; } - public bool LoadChromeBookmark + public bool LoadChromeBookmark + { + get => Settings.LoadChromeBookmark; + set { - get => Settings.LoadChromeBookmark; - set - { - Settings.LoadChromeBookmark = value; - _ = Task.Run(() => Main.ReloadAllBookmarks()); - } + Settings.LoadChromeBookmark = value; + _ = Task.Run(() => Main.ReloadAllBookmarks()); } + } - public bool LoadFirefoxBookmark + public bool LoadFirefoxBookmark + { + get => Settings.LoadFirefoxBookmark; + set { - get => Settings.LoadFirefoxBookmark; - set - { - Settings.LoadFirefoxBookmark = value; - _ = Task.Run(() => Main.ReloadAllBookmarks()); - } + Settings.LoadFirefoxBookmark = value; + _ = Task.Run(() => Main.ReloadAllBookmarks()); } + } - public bool LoadEdgeBookmark + public bool LoadEdgeBookmark + { + get => Settings.LoadEdgeBookmark; + set { - get => Settings.LoadEdgeBookmark; - set - { - Settings.LoadEdgeBookmark = value; - _ = Task.Run(() => Main.ReloadAllBookmarks()); - } + Settings.LoadEdgeBookmark = value; + _ = Task.Run(() => Main.ReloadAllBookmarks()); } + } - public bool OpenInNewBrowserWindow + public bool OpenInNewBrowserWindow + { + get => Settings.OpenInNewBrowserWindow; + set { - get => Settings.OpenInNewBrowserWindow; - set - { - Settings.OpenInNewBrowserWindow = value; - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(OpenInNewBrowserWindow))); - } + Settings.OpenInNewBrowserWindow = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(OpenInNewBrowserWindow))); } + } - public SettingsControl(Settings settings) - { - Settings = settings; - InitializeComponent(); - } + public SettingsControl(Settings settings) + { + Settings = settings; + InitializeComponent(); + } - public event PropertyChangedEventHandler PropertyChanged; + 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 - }) + private void NewCustomBrowser(object sender, RoutedEventArgs e) + { + var newBrowser = new CustomBrowser(); + var window = new CustomBrowserSettingWindow(newBrowser); + window.ShowDialog(); + if (newBrowser is not { - Settings.CustomChromiumBrowsers.Add(newBrowser); - _ = Task.Run(() => Main.ReloadAllBookmarks()); - } - } - - private void DeleteCustomBrowser(object sender, RoutedEventArgs e) + Name: null, + DataDirectoryPath: null + }) { - if (CustomBrowsers.SelectedItem is CustomBrowser selectedCustomBrowser) - { - Settings.CustomChromiumBrowsers.Remove(selectedCustomBrowser); - _ = Task.Run(() => Main.ReloadAllBookmarks()); - } + Settings.CustomChromiumBrowsers.Add(newBrowser); + _ = Task.Run(() => Main.ReloadAllBookmarks()); } - - private void MouseDoubleClickOnSelectedCustomBrowser(object sender, MouseButtonEventArgs e) + } + + private void DeleteCustomBrowser(object sender, RoutedEventArgs e) + { + if (CustomBrowsers.SelectedItem is CustomBrowser selectedCustomBrowser) { - EditSelectedCustomBrowser(); + Settings.CustomChromiumBrowsers.Remove(selectedCustomBrowser); + _ = Task.Run(() => Main.ReloadAllBookmarks()); } - - private void Others_Click(object sender, RoutedEventArgs e) - { + } - if (CustomBrowsersList.Visibility == Visibility.Collapsed) - { - CustomBrowsersList.Visibility = Visibility.Visible; - } - else - CustomBrowsersList.Visibility = Visibility.Collapsed; - } + private void MouseDoubleClickOnSelectedCustomBrowser(object sender, MouseButtonEventArgs e) + { + EditSelectedCustomBrowser(); + } - private void EditCustomBrowser(object sender, RoutedEventArgs e) + private void Others_Click(object sender, RoutedEventArgs e) + { + CustomBrowsersList.Visibility = CustomBrowsersList.Visibility switch { - EditSelectedCustomBrowser(); - } + Visibility.Collapsed => Visibility.Visible, + _ => Visibility.Collapsed + }; + } - private void EditSelectedCustomBrowser() - { - if (SelectedCustomBrowser is null) - return; + private void EditCustomBrowser(object sender, RoutedEventArgs e) + { + EditSelectedCustomBrowser(); + } - var window = new CustomBrowserSettingWindow(SelectedCustomBrowser); - var result = window.ShowDialog() ?? false; - if (result) - { - _ = Task.Run(() => Main.ReloadAllBookmarks()); - } + private void EditSelectedCustomBrowser() + { + if (SelectedCustomBrowser is null) + return; + + var window = new CustomBrowserSettingWindow(SelectedCustomBrowser); + var result = window.ShowDialog() ?? false; + if (result) + { + _ = 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/33] 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 9d9480f99f5..cdbcfbef290 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/33] 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 cdbcfbef290..35ad32fb3d4 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs @@ -113,10 +113,10 @@ Current profiles.ini structure example as of Firefox version 69.0.1 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/33] 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 23efd29b9ef..a48d70f2d46 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Main.cs @@ -47,7 +47,7 @@ private static void LoadBookmarksIfEnabled() 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 73de9a710300001f0c1e22852237521fe3b7d551 Mon Sep 17 00:00:00 2001 From: DB p Date: Mon, 29 Apr 2024 14:14:37 +0900 Subject: [PATCH 05/33] Testing --- Flow.Launcher/MainWindow.xaml | 10 ++-- Flow.Launcher/MainWindow.xaml.cs | 74 +++++++++++++++++++++++++++++ Flow.Launcher/SettingWindow.xaml | 2 +- Flow.Launcher/Themes/Win11Dark.xaml | 3 +- 4 files changed, 82 insertions(+), 7 deletions(-) diff --git a/Flow.Launcher/MainWindow.xaml b/Flow.Launcher/MainWindow.xaml index 2e6e973a720..db11d5d0c8d 100644 --- a/Flow.Launcher/MainWindow.xaml +++ b/Flow.Launcher/MainWindow.xaml @@ -15,7 +15,7 @@ MaxWidth="{Binding MainWindowWidth, Mode=OneWay}" d:DataContext="{d:DesignInstance Type=vm:MainViewModel}" AllowDrop="True" - AllowsTransparency="True" + AllowsTransparency="False" Background="Transparent" Closing="OnClosing" Deactivated="OnDeactivated" @@ -28,12 +28,14 @@ ResizeMode="NoResize" ShowInTaskbar="False" SizeToContent="Height" - Style="{DynamicResource WindowStyle}" Topmost="True" Visibility="{Binding MainWindowVisibility, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" WindowStartupLocation="Manual" - WindowStyle="None" + WindowStyle="SingleBorderWindow" mc:Ignorable="d"> + + + @@ -199,7 +201,7 @@ Modifiers="{Binding SelectPrevPageHotkey, Converter={StaticResource StringToKeyBindingConverter}, ConverterParameter='modifiers'}" /> - + diff --git a/Flow.Launcher/MainWindow.xaml.cs b/Flow.Launcher/MainWindow.xaml.cs index 76e587cdca5..69100b446a4 100644 --- a/Flow.Launcher/MainWindow.xaml.cs +++ b/Flow.Launcher/MainWindow.xaml.cs @@ -29,6 +29,9 @@ using System.Windows.Media; using System.Windows.Interop; using System.Runtime.InteropServices; +using System.Threading; +using System.Drawing.Printing; +using static Flow.Launcher.MainWindow.ParameterTypes; namespace Flow.Launcher { @@ -50,6 +53,74 @@ public partial class MainWindow #endregion + public class ParameterTypes + { + /* + [Flags] + enum DWM_SYSTEMBACKDROP_TYPE + { + DWMSBT_MAINWINDOW = 2, // Mica + DWMSBT_TRANSIENTWINDOW = 3, // Acrylic + DWMSBT_TABBEDWINDOW = 4 // Tabbed + } + */ + + [Flags] + public enum DWMWINDOWATTRIBUTE + { + DWMWA_USE_IMMERSIVE_DARK_MODE = 20, + DWMWA_SYSTEMBACKDROP_TYPE = 38, + DWMWA_TRANSITIONS_FORCEDISABLED = 3, + DWMWA_BORDER_COLOR + } + + [StructLayout(LayoutKind.Sequential)] + public struct MARGINS + { + public int cxLeftWidth; // width of left border that retains its size + public int cxRightWidth; // width of right border that retains its size + public int cyTopHeight; // height of top border that retains its size + public int cyBottomHeight; // height of bottom border that retains its size + }; + } + + public static class Methods + { + [DllImport("DwmApi.dll")] + static extern int DwmExtendFrameIntoClientArea( + IntPtr hwnd, + ref ParameterTypes.MARGINS pMarInset); + + [DllImport("dwmapi.dll")] + static extern int DwmSetWindowAttribute(IntPtr hwnd, ParameterTypes.DWMWINDOWATTRIBUTE dwAttribute, ref int pvAttribute, int cbAttribute); + + public static int ExtendFrame(IntPtr hwnd, ParameterTypes.MARGINS margins) + => DwmExtendFrameIntoClientArea(hwnd, ref margins); + + public static int SetWindowAttribute(IntPtr hwnd, ParameterTypes.DWMWINDOWATTRIBUTE attribute, int parameter) + => DwmSetWindowAttribute(hwnd, attribute, ref parameter, Marshal.SizeOf()); + } + + + private void RefreshFrame() + { + IntPtr mainWindowPtr = new WindowInteropHelper(this).Handle; + HwndSource mainWindowSrc = HwndSource.FromHwnd(mainWindowPtr); + mainWindowSrc.CompositionTarget.BackgroundColor = Color.FromArgb(0, 255, 181, 178); + + ParameterTypes.MARGINS margins = new ParameterTypes.MARGINS(); + margins.cxLeftWidth = -1; + margins.cxRightWidth = -1; + margins.cyTopHeight = -1; + margins.cyBottomHeight = -1; + Methods.ExtendFrame(mainWindowSrc.Handle, margins); + Methods.SetWindowAttribute(new WindowInteropHelper(this).Handle,DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE,1); + Methods.SetWindowAttribute(new WindowInteropHelper(this).Handle, DWMWINDOWATTRIBUTE.DWMWA_BORDER_COLOR, 0x00FF0000); + Methods.SetWindowAttribute(new WindowInteropHelper(this).Handle, DWMWINDOWATTRIBUTE.DWMWA_SYSTEMBACKDROP_TYPE, 3); + // Remove OS minimizing/maximizing animation + Methods.SetWindowAttribute(new WindowInteropHelper(this).Handle, DWMWINDOWATTRIBUTE.DWMWA_TRANSITIONS_FORCEDISABLED, 3); + } + public MainWindow(Settings settings, MainViewModel mainVM) { DataContext = mainVM; @@ -112,6 +183,9 @@ private void OnInitialized(object sender, EventArgs e) private void OnLoaded(object sender, RoutedEventArgs _) { + // Remove OS minimizing/maximizing animation + RefreshFrame(); + CheckFirstLaunch(); HideStartup(); // show notify icon when flowlauncher is hidden diff --git a/Flow.Launcher/SettingWindow.xaml b/Flow.Launcher/SettingWindow.xaml index 0a62a4bad9b..d2a20584b3a 100644 --- a/Flow.Launcher/SettingWindow.xaml +++ b/Flow.Launcher/SettingWindow.xaml @@ -31,7 +31,7 @@ WindowStartupLocation="Manual" mc:Ignorable="d"> - + diff --git a/Flow.Launcher/Themes/Win11Dark.xaml b/Flow.Launcher/Themes/Win11Dark.xaml index 5abb96cce0d..07da28ac384 100644 --- a/Flow.Launcher/Themes/Win11Dark.xaml +++ b/Flow.Launcher/Themes/Win11Dark.xaml @@ -28,7 +28,7 @@ x:Key="QuerySuggestionBoxStyle" BasedOn="{StaticResource BaseQuerySuggestionBoxStyle}" TargetType="{x:Type TextBox}"> - + @@ -41,7 +41,6 @@ - @@ -120,13 +122,15 @@ @@ -139,6 +143,7 @@ + @@ -413,7 +418,7 @@ @@ -495,7 +500,7 @@ @@ -503,7 +508,7 @@ x:Key="ClockPanelPosition" BasedOn="{StaticResource BaseClockPanelPosition}" TargetType="{x:Type Canvas}"> - + - - - - - - - - - - - - - #f1f1f1 - - - - - - - - - - 5 - 10 0 10 0 - 0 0 0 10 - - - - - - - - \ No newline at end of file diff --git a/Flow.Launcher/Themes/Circle Light.xaml b/Flow.Launcher/Themes/Circle Light.xaml deleted file mode 100644 index e52e3a9570f..00000000000 --- a/Flow.Launcher/Themes/Circle Light.xaml +++ /dev/null @@ -1,190 +0,0 @@ - - - - - - - - - - - - - - - - - #5046e5 - - - - - - - - - - 8 - 10 0 10 0 - 0 0 0 10 - - - - - - - - diff --git a/Flow.Launcher/Themes/Cyan Dark.xaml b/Flow.Launcher/Themes/Cyan Dark.xaml index 60bc090022f..106b1b6d90e 100644 --- a/Flow.Launcher/Themes/Cyan Dark.xaml +++ b/Flow.Launcher/Themes/Cyan Dark.xaml @@ -27,7 +27,7 @@ x:Key="ItemGlyph" BasedOn="{StaticResource BaseGlyphStyle}" TargetType="{x:Type TextBlock}"> - + - - - - - - - - - - - - - #545454 - - - - - - - - - - - - - - - - diff --git a/Flow.Launcher/Themes/Discord Dark.xaml b/Flow.Launcher/Themes/Discord Dark.xaml deleted file mode 100644 index 5315c7644a1..00000000000 --- a/Flow.Launcher/Themes/Discord Dark.xaml +++ /dev/null @@ -1,192 +0,0 @@ - - - - - 0 0 0 6 - - - - - - - - - - - - - - #49443c - - - - - - - - - - - - - - - diff --git a/Flow.Launcher/Themes/Dracula.xaml b/Flow.Launcher/Themes/Dracula.xaml index d150e7355fe..eb8cc9557fb 100644 --- a/Flow.Launcher/Themes/Dracula.xaml +++ b/Flow.Launcher/Themes/Dracula.xaml @@ -28,7 +28,6 @@ x:Key="QuerySuggestionBoxStyle" BasedOn="{StaticResource BaseQuerySuggestionBoxStyle}" TargetType="{x:Type TextBox}"> - @@ -98,7 +97,7 @@ - - - - - - - - - - - - - #192026 - - - - - - F1 M12000,12000z M0,0z M10354,10962C10326,10951 10279,10927 10249,10907 10216,10886 9476,10153 8370,9046 7366,8042 6541,7220 6536,7220 6532,7220 6498,7242 6461,7268 6213,7447 5883,7619 5592,7721 5194,7860 4802,7919 4360,7906 3612,7886 2953,7647 2340,7174 2131,7013 1832,6699 1664,6465 1394,6088 1188,5618 1097,5170 1044,4909 1030,4764 1030,4470 1030,4130 1056,3914 1135,3609 1263,3110 1511,2633 1850,2235 1936,2134 2162,1911 2260,1829 2781,1395 3422,1120 4090,1045 4271,1025 4667,1025 4848,1045 5505,1120 6100,1368 6630,1789 6774,1903 7081,2215 7186,2355 7362,2588 7467,2759 7579,2990 7802,3455 7911,3937 7911,4460 7911,4854 7861,5165 7737,5542 7684,5702 7675,5724 7602,5885 7517,6071 7390,6292 7270,6460 7242,6499 7220,6533 7220,6538 7220,6542 8046,7371 9055,8380 10441,9766 10898,10229 10924,10274 10945,10308 10966,10364 10976,10408 10990,10472 10991,10493 10980,10554 10952,10717 10840,10865 10690,10937 10621,10971 10607,10974 10510,10977 10425,10980 10395,10977 10354,10962z M4685,7050C5214,7001 5694,6809 6100,6484 6209,6396 6396,6209 6484,6100 7151,5267 7246,4110 6721,3190 6369,2571 5798,2137 5100,1956 4706,1855 4222,1855 3830,1957 3448,2056 3140,2210 2838,2453 2337,2855 2010,3427 1908,4080 1877,4274 1877,4656 1908,4850 1948,5105 2028,5370 2133,5590 2459,6272 3077,6782 3810,6973 3967,7014 4085,7034 4290,7053 4371,7061 4583,7059 4685,7050z - - - - - - - - \ No newline at end of file diff --git a/Flow.Launcher/Themes/Nord Darker.xaml b/Flow.Launcher/Themes/Nord Darker.xaml index d9ddb307664..bb5dbf87f2b 100644 --- a/Flow.Launcher/Themes/Nord Darker.xaml +++ b/Flow.Launcher/Themes/Nord Darker.xaml @@ -22,7 +22,6 @@ x:Key="QuerySuggestionBoxStyle" BasedOn="{StaticResource BaseQuerySuggestionBoxStyle}" TargetType="{x:Type TextBox}"> - diff --git a/Flow.Launcher/Themes/Pink.xaml b/Flow.Launcher/Themes/Pink.xaml deleted file mode 100644 index dc97e432055..00000000000 --- a/Flow.Launcher/Themes/Pink.xaml +++ /dev/null @@ -1,161 +0,0 @@ - - - - - 0 0 0 4 - - - - - - - - - - - - - #cc1081 - - - - - - - - - - - - \ No newline at end of file diff --git a/Flow.Launcher/Themes/SlimLight.xaml b/Flow.Launcher/Themes/SlimLight.xaml index dc08eec3003..078b07048c3 100644 --- a/Flow.Launcher/Themes/SlimLight.xaml +++ b/Flow.Launcher/Themes/SlimLight.xaml @@ -179,15 +179,28 @@ BasedOn="{StaticResource BaseClockBox}" TargetType="{x:Type TextBlock}"> - + + + + + + + + - - - - - - - - - - - - - - - #ccd0d4 - - - - - - - - - - - - - - - diff --git a/Flow.Launcher/Themes/Win11Dark.xaml b/Flow.Launcher/Themes/Win11Dark.xaml deleted file mode 100644 index 5abb96cce0d..00000000000 --- a/Flow.Launcher/Themes/Win11Dark.xaml +++ /dev/null @@ -1,195 +0,0 @@ - - - - - 0 0 0 8 - - - - - - - - - - - - - - - #198F8F8F - - - - - - - - - - - - - - - diff --git a/Flow.Launcher/Themes/Win11System.xaml b/Flow.Launcher/Themes/Win11System.xaml index 3025f9a07e2..2f677804c13 100644 --- a/Flow.Launcher/Themes/Win11System.xaml +++ b/Flow.Launcher/Themes/Win11System.xaml @@ -3,61 +3,70 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:m="http://schemas.modernwpf.com/2019" xmlns:system="clr-namespace:System;assembly=mscorlib"> + - 0 0 0 8 + + + - + TargetType="{x:Type Window}" /> + - - - - + + + + + + + 5 + 10 0 10 0 + 0 0 0 10 + - + \ No newline at end of file diff --git a/Flow.Launcher/Themes/Win11Light.xaml b/Flow.Launcher/Themes/Win11SystemFlat.xaml similarity index 69% rename from Flow.Launcher/Themes/Win11Light.xaml rename to Flow.Launcher/Themes/Win11SystemFlat.xaml index e6f376f8b34..2f5e0d237d2 100644 --- a/Flow.Launcher/Themes/Win11Light.xaml +++ b/Flow.Launcher/Themes/Win11SystemFlat.xaml @@ -1,6 +1,7 @@ @@ -10,23 +11,22 @@ x:Key="ItemGlyph" BasedOn="{StaticResource BaseGlyphStyle}" TargetType="{x:Type TextBlock}"> - + @@ -46,25 +45,15 @@ BasedOn="{StaticResource BaseWindowBorderStyle}" TargetType="{x:Type Border}"> - + - - - - - - - - - - + - #198F8F8F + @@ -164,46 +155,53 @@ x:Key="SearchIconStyle" BasedOn="{StaticResource BaseSearchIconStyle}" TargetType="{x:Type Path}"> - + + + + + + From 2b14bc460458e80ccd010f19f9f842af3f638188 Mon Sep 17 00:00:00 2001 From: DB p Date: Sat, 18 May 2024 20:35:04 +0900 Subject: [PATCH 25/33] Fix font Size --- Flow.Launcher/Themes/Win11SystemFlat.xaml | 1 - 1 file changed, 1 deletion(-) diff --git a/Flow.Launcher/Themes/Win11SystemFlat.xaml b/Flow.Launcher/Themes/Win11SystemFlat.xaml index 2f5e0d237d2..b4f1cfd8c55 100644 --- a/Flow.Launcher/Themes/Win11SystemFlat.xaml +++ b/Flow.Launcher/Themes/Win11SystemFlat.xaml @@ -27,7 +27,6 @@ - From 0d32d0f428e40e604f65eac5353a16737ff06e86 Mon Sep 17 00:00:00 2001 From: DB p Date: Mon, 20 May 2024 20:14:04 +0900 Subject: [PATCH 26/33] Move the Blur code to Theme --- Flow.Launcher.Core/Resource/Theme.cs | 73 +++++++++++++++++++++++- Flow.Launcher/MainWindow.xaml | 2 +- Flow.Launcher/MainWindow.xaml.cs | 71 +---------------------- Flow.Launcher/ViewModel/MainViewModel.cs | 4 +- 4 files changed, 76 insertions(+), 74 deletions(-) diff --git a/Flow.Launcher.Core/Resource/Theme.cs b/Flow.Launcher.Core/Resource/Theme.cs index 96338cf6a1a..fb7ee5603b0 100644 --- a/Flow.Launcher.Core/Resource/Theme.cs +++ b/Flow.Launcher.Core/Resource/Theme.cs @@ -12,6 +12,7 @@ using Flow.Launcher.Infrastructure; using Flow.Launcher.Infrastructure.Logger; using Flow.Launcher.Infrastructure.UserSettings; +using static Flow.Launcher.Core.Resource.Theme.ParameterTypes; namespace Flow.Launcher.Core.Resource { @@ -302,9 +303,78 @@ public void RemoveDropShadowEffectFromCurrentTheme() UpdateResourceDictionary(dict); } + public class ParameterTypes + { + /* + [Flags] + enum DWM_SYSTEMBACKDROP_TYPE + { + DWMSBT_MAINWINDOW = 2, // Mica + DWMSBT_TRANSIENTWINDOW = 3, // Acrylic + DWMSBT_TABBEDWINDOW = 4 // Tabbed + } + */ + + [Flags] + public enum DWMWINDOWATTRIBUTE + { + DWMWA_USE_IMMERSIVE_DARK_MODE = 20, + DWMWA_SYSTEMBACKDROP_TYPE = 38, + DWMWA_TRANSITIONS_FORCEDISABLED = 3, + DWMWA_BORDER_COLOR + } + + [StructLayout(LayoutKind.Sequential)] + public struct MARGINS + { + public int cxLeftWidth; // width of left border that retains its size + public int cxRightWidth; // width of right border that retains its size + public int cyTopHeight; // height of top border that retains its size + public int cyBottomHeight; // height of bottom border that retains its size + }; + } + + public static class Methods + { + [DllImport("DwmApi.dll")] + static extern int DwmExtendFrameIntoClientArea( + IntPtr hwnd, + ref ParameterTypes.MARGINS pMarInset); + + [DllImport("dwmapi.dll")] + static extern int DwmSetWindowAttribute(IntPtr hwnd, ParameterTypes.DWMWINDOWATTRIBUTE dwAttribute, ref int pvAttribute, int cbAttribute); + + public static int ExtendFrame(IntPtr hwnd, ParameterTypes.MARGINS margins) + => DwmExtendFrameIntoClientArea(hwnd, ref margins); + + public static int SetWindowAttribute(IntPtr hwnd, ParameterTypes.DWMWINDOWATTRIBUTE attribute, int parameter) + => DwmSetWindowAttribute(hwnd, attribute, ref parameter, Marshal.SizeOf()); + } + + Window mainWindow = Application.Current.MainWindow; + + public void RefreshFrame() + { + IntPtr mainWindowPtr = new WindowInteropHelper(mainWindow).Handle; + HwndSource mainWindowSrc = HwndSource.FromHwnd(mainWindowPtr); + mainWindowSrc.CompositionTarget.BackgroundColor = Color.FromArgb(0, 255, 181, 178); + + ParameterTypes.MARGINS margins = new ParameterTypes.MARGINS(); + margins.cxLeftWidth = -1; + margins.cxRightWidth = -1; + margins.cyTopHeight = -1; + margins.cyBottomHeight = -1; + Methods.ExtendFrame(mainWindowSrc.Handle, margins); + Methods.SetWindowAttribute(new WindowInteropHelper(mainWindow).Handle, DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE, 0); + Methods.SetWindowAttribute(new WindowInteropHelper(mainWindow).Handle, DWMWINDOWATTRIBUTE.DWMWA_BORDER_COLOR, 0x00FF0000); + Methods.SetWindowAttribute(new WindowInteropHelper(mainWindow).Handle, DWMWINDOWATTRIBUTE.DWMWA_SYSTEMBACKDROP_TYPE, 3); + // Remove OS minimizing/maximizing animation + Methods.SetWindowAttribute(new WindowInteropHelper(mainWindow).Handle, DWMWINDOWATTRIBUTE.DWMWA_TRANSITIONS_FORCEDISABLED, 3); + } + #region Blur Handling /* - Found on https://github.com/riverar/sample-win10-aeroglass + Found on https://github.com/riverar/sample-win10-aeroglass ***************** */ private enum AccentState { @@ -344,6 +414,7 @@ private enum WindowCompositionAttribute /// public void SetBlurForWindow() { + if (BlurEnabled) { SetWindowAccent(Application.Current.MainWindow, AccentState.ACCENT_ENABLE_BLURBEHIND); diff --git a/Flow.Launcher/MainWindow.xaml b/Flow.Launcher/MainWindow.xaml index c358e1a6a13..59c18aa2726 100644 --- a/Flow.Launcher/MainWindow.xaml +++ b/Flow.Launcher/MainWindow.xaml @@ -203,7 +203,7 @@ - + diff --git a/Flow.Launcher/MainWindow.xaml.cs b/Flow.Launcher/MainWindow.xaml.cs index 665f0cab1c2..6093fa0393b 100644 --- a/Flow.Launcher/MainWindow.xaml.cs +++ b/Flow.Launcher/MainWindow.xaml.cs @@ -31,7 +31,6 @@ using System.Runtime.InteropServices; using System.Threading; using System.Drawing.Printing; -using static Flow.Launcher.MainWindow.ParameterTypes; namespace Flow.Launcher { @@ -54,74 +53,6 @@ public partial class MainWindow #endregion - public class ParameterTypes - { - /* - [Flags] - enum DWM_SYSTEMBACKDROP_TYPE - { - DWMSBT_MAINWINDOW = 2, // Mica - DWMSBT_TRANSIENTWINDOW = 3, // Acrylic - DWMSBT_TABBEDWINDOW = 4 // Tabbed - } - */ - - [Flags] - public enum DWMWINDOWATTRIBUTE - { - DWMWA_USE_IMMERSIVE_DARK_MODE = 20, - DWMWA_SYSTEMBACKDROP_TYPE = 38, - DWMWA_TRANSITIONS_FORCEDISABLED = 3, - DWMWA_BORDER_COLOR - } - - [StructLayout(LayoutKind.Sequential)] - public struct MARGINS - { - public int cxLeftWidth; // width of left border that retains its size - public int cxRightWidth; // width of right border that retains its size - public int cyTopHeight; // height of top border that retains its size - public int cyBottomHeight; // height of bottom border that retains its size - }; - } - - public static class Methods - { - [DllImport("DwmApi.dll")] - static extern int DwmExtendFrameIntoClientArea( - IntPtr hwnd, - ref ParameterTypes.MARGINS pMarInset); - - [DllImport("dwmapi.dll")] - static extern int DwmSetWindowAttribute(IntPtr hwnd, ParameterTypes.DWMWINDOWATTRIBUTE dwAttribute, ref int pvAttribute, int cbAttribute); - - public static int ExtendFrame(IntPtr hwnd, ParameterTypes.MARGINS margins) - => DwmExtendFrameIntoClientArea(hwnd, ref margins); - - public static int SetWindowAttribute(IntPtr hwnd, ParameterTypes.DWMWINDOWATTRIBUTE attribute, int parameter) - => DwmSetWindowAttribute(hwnd, attribute, ref parameter, Marshal.SizeOf()); - } - - - private void RefreshFrame() - { - IntPtr mainWindowPtr = new WindowInteropHelper(this).Handle; - HwndSource mainWindowSrc = HwndSource.FromHwnd(mainWindowPtr); - mainWindowSrc.CompositionTarget.BackgroundColor = Color.FromArgb(0, 255, 181, 178); - - ParameterTypes.MARGINS margins = new ParameterTypes.MARGINS(); - margins.cxLeftWidth = -1; - margins.cxRightWidth = -1; - margins.cyTopHeight = -1; - margins.cyBottomHeight = -1; - Methods.ExtendFrame(mainWindowSrc.Handle, margins); - Methods.SetWindowAttribute(new WindowInteropHelper(this).Handle,DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE,0); - Methods.SetWindowAttribute(new WindowInteropHelper(this).Handle, DWMWINDOWATTRIBUTE.DWMWA_BORDER_COLOR, 0x00FF0000); - Methods.SetWindowAttribute(new WindowInteropHelper(this).Handle, DWMWINDOWATTRIBUTE.DWMWA_SYSTEMBACKDROP_TYPE, 2); - // Remove OS minimizing/maximizing animation - Methods.SetWindowAttribute(new WindowInteropHelper(this).Handle, DWMWINDOWATTRIBUTE.DWMWA_TRANSITIONS_FORCEDISABLED, 3); - } - public MainWindow(Settings settings, MainViewModel mainVM) { DataContext = mainVM; @@ -184,7 +115,7 @@ private void OnInitialized(object sender, EventArgs e) private void OnLoaded(object sender, RoutedEventArgs _) { // Remove OS minimizing/maximizing animation - RefreshFrame(); + ThemeManager.Instance.RefreshFrame(); // MouseEventHandler PreviewMouseMove += MainPreviewMouseMove; diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 67efc6a8657..550ebb64875 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -1107,7 +1107,7 @@ public void Show() { MainWindowVisibility = Visibility.Visible; - MainWindowOpacity = 1; + //MainWindowOpacity = 1; MainWindowVisibilityStatus = true; VisibilityChanged?.Invoke(this, new VisibilityChangedEventArgs { IsVisible = true }); @@ -1117,7 +1117,7 @@ public void Show() public async void Hide() { // Trick for no delay - MainWindowOpacity = 0; + //MainWindowOpacity = 0; lastContextMenuResult = new Result(); lastContextMenuResults = new List(); From edf36262cb4217c0b2431c156562a617bee404cd Mon Sep 17 00:00:00 2001 From: DB p Date: Tue, 21 May 2024 00:55:42 +0900 Subject: [PATCH 27/33] Add BlurTheme Logic --- Flow.Launcher.Core/Resource/Theme.cs | 114 ++++++++++---------------- Flow.Launcher/MainWindow.xaml | 11 ++- Flow.Launcher/MainWindow.xaml.cs | 19 ++++- Flow.Launcher/Resources/Dark.xaml | 1 + Flow.Launcher/Resources/Light.xaml | 1 + Flow.Launcher/Themes/Base.xaml | 5 ++ Flow.Launcher/Themes/BlurBlack.xaml | 4 + Flow.Launcher/Themes/Win11System.xaml | 6 ++ 8 files changed, 86 insertions(+), 75 deletions(-) diff --git a/Flow.Launcher.Core/Resource/Theme.cs b/Flow.Launcher.Core/Resource/Theme.cs index fb7ee5603b0..543c36af838 100644 --- a/Flow.Launcher.Core/Resource/Theme.cs +++ b/Flow.Launcher.Core/Resource/Theme.cs @@ -303,17 +303,10 @@ public void RemoveDropShadowEffectFromCurrentTheme() UpdateResourceDictionary(dict); } + + #region Blur Handling public class ParameterTypes { - /* - [Flags] - enum DWM_SYSTEMBACKDROP_TYPE - { - DWMSBT_MAINWINDOW = 2, // Mica - DWMSBT_TRANSIENTWINDOW = 3, // Acrylic - DWMSBT_TABBEDWINDOW = 4 // Tabbed - } - */ [Flags] public enum DWMWINDOWATTRIBUTE @@ -357,7 +350,7 @@ public void RefreshFrame() { IntPtr mainWindowPtr = new WindowInteropHelper(mainWindow).Handle; HwndSource mainWindowSrc = HwndSource.FromHwnd(mainWindowPtr); - mainWindowSrc.CompositionTarget.BackgroundColor = Color.FromArgb(0, 255, 181, 178); + //mainWindowSrc.CompositionTarget.BackgroundColor = Color.FromArgb(0, 255, 181, 178); ParameterTypes.MARGINS margins = new ParameterTypes.MARGINS(); margins.cxLeftWidth = -1; @@ -365,66 +358,57 @@ public void RefreshFrame() margins.cyTopHeight = -1; margins.cyBottomHeight = -1; Methods.ExtendFrame(mainWindowSrc.Handle, margins); - Methods.SetWindowAttribute(new WindowInteropHelper(mainWindow).Handle, DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE, 0); - Methods.SetWindowAttribute(new WindowInteropHelper(mainWindow).Handle, DWMWINDOWATTRIBUTE.DWMWA_BORDER_COLOR, 0x00FF0000); - Methods.SetWindowAttribute(new WindowInteropHelper(mainWindow).Handle, DWMWINDOWATTRIBUTE.DWMWA_SYSTEMBACKDROP_TYPE, 3); + // Remove OS minimizing/maximizing animation Methods.SetWindowAttribute(new WindowInteropHelper(mainWindow).Handle, DWMWINDOWATTRIBUTE.DWMWA_TRANSITIONS_FORCEDISABLED, 3); + Methods.SetWindowAttribute(new WindowInteropHelper(mainWindow).Handle, DWMWINDOWATTRIBUTE.DWMWA_BORDER_COLOR, 0x00FF0000); + SetBlurForWindow(); } - #region Blur Handling - /* - Found on https://github.com/riverar/sample-win10-aeroglass ***************** - */ - private enum AccentState - { - ACCENT_DISABLED = 0, - ACCENT_ENABLE_GRADIENT = 1, - ACCENT_ENABLE_TRANSPARENTGRADIENT = 2, - ACCENT_ENABLE_BLURBEHIND = 3, - ACCENT_INVALID_STATE = 4 - } - - [StructLayout(LayoutKind.Sequential)] - private struct AccentPolicy - { - public AccentState AccentState; - public int AccentFlags; - public int GradientColor; - public int AnimationId; - } - - [StructLayout(LayoutKind.Sequential)] - private struct WindowCompositionAttributeData - { - public WindowCompositionAttribute Attribute; - public IntPtr Data; - public int SizeOfData; - } - private enum WindowCompositionAttribute - { - WCA_ACCENT_POLICY = 19 - } - [DllImport("user32.dll")] - private static extern int SetWindowCompositionAttribute(IntPtr hwnd, ref WindowCompositionAttributeData data); /// /// Sets the blur for a window via SetWindowCompositionAttribute /// public void SetBlurForWindow() { - + //SetWindowAccent(); + var dict = GetThemeResourceDictionary(Settings.Theme); + var windowBorderStyle = dict["WindowBorderStyle"] as Style; if (BlurEnabled) { - SetWindowAccent(Application.Current.MainWindow, AccentState.ACCENT_ENABLE_BLURBEHIND); + + windowBorderStyle.Setters.Remove(windowBorderStyle.Setters.OfType().FirstOrDefault(x => x.Property.Name == "Background")); + windowBorderStyle.Setters.Add(new Setter(Border.BackgroundProperty, new SolidColorBrush(Colors.Transparent))); + mainWindow.WindowStyle = WindowStyle.SingleBorderWindow; + Methods.SetWindowAttribute(new WindowInteropHelper(mainWindow).Handle, DWMWINDOWATTRIBUTE.DWMWA_SYSTEMBACKDROP_TYPE, 3); + BlurColor(BlurMode()); } else { - SetWindowAccent(Application.Current.MainWindow, AccentState.ACCENT_DISABLED); + windowBorderStyle.Setters.Add(windowBorderStyle.Setters.OfType().FirstOrDefault(x => x.Property.Name == "Background")); + mainWindow.WindowStyle = WindowStyle.None; + Methods.SetWindowAttribute(new WindowInteropHelper(mainWindow).Handle, DWMWINDOWATTRIBUTE.DWMWA_SYSTEMBACKDROP_TYPE, 1); } + UpdateResourceDictionary(dict); } + public void BlurColor(string Color) + { + if (Color == "Light") + { + Methods.SetWindowAttribute(new WindowInteropHelper(mainWindow).Handle, DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE, 0); + } + else if (Color == "Dark") + { + Methods.SetWindowAttribute(new WindowInteropHelper(mainWindow).Handle, DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE, 1); + } + else if (Color == "Auto") + { + //Methods.SetWindowAttribute(new WindowInteropHelper(mainWindow).Handle, DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE, 1); + } + + } private bool IsBlurTheme() { if (Environment.OSVersion.Version >= new Version(6, 2)) @@ -439,29 +423,19 @@ private bool IsBlurTheme() return false; } - - private void SetWindowAccent(Window w, AccentState state) + public string BlurMode() { - var windowHelper = new WindowInteropHelper(w); - - windowHelper.EnsureHandle(); - - var accent = new AccentPolicy { AccentState = state }; - var accentStructSize = Marshal.SizeOf(accent); - - var accentPtr = Marshal.AllocHGlobal(accentStructSize); - Marshal.StructureToPtr(accent, accentPtr, false); - - var data = new WindowCompositionAttributeData + if (Environment.OSVersion.Version >= new Version(6, 2)) { - Attribute = WindowCompositionAttribute.WCA_ACCENT_POLICY, - SizeOfData = accentStructSize, - Data = accentPtr - }; + var resource = Application.Current.TryFindResource("BlurMode"); - SetWindowCompositionAttribute(windowHelper.Handle, ref data); + if (resource is string) + return (string)resource; + + return null; + } - Marshal.FreeHGlobal(accentPtr); + return null; } #endregion } diff --git a/Flow.Launcher/MainWindow.xaml b/Flow.Launcher/MainWindow.xaml index 59c18aa2726..4b2480d0550 100644 --- a/Flow.Launcher/MainWindow.xaml +++ b/Flow.Launcher/MainWindow.xaml @@ -32,10 +32,13 @@ Topmost="True" Visibility="{Binding MainWindowVisibility, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" WindowStartupLocation="Manual" - WindowStyle="SingleBorderWindow" + WindowStyle="None" mc:Ignorable="d"> - + @@ -203,9 +206,9 @@ - + - + diff --git a/Flow.Launcher/MainWindow.xaml.cs b/Flow.Launcher/MainWindow.xaml.cs index 6093fa0393b..ac82dbbffc3 100644 --- a/Flow.Launcher/MainWindow.xaml.cs +++ b/Flow.Launcher/MainWindow.xaml.cs @@ -31,6 +31,8 @@ using System.Runtime.InteropServices; using System.Threading; using System.Drawing.Printing; +using ModernWpf; +using ThemeManager = Flow.Launcher.Core.Resource.ThemeManager; namespace Flow.Launcher { @@ -63,8 +65,8 @@ public MainWindow(Settings settings, MainViewModel mainVM) InitializePosition(); animationSound.Open(new Uri(AppDomain.CurrentDomain.BaseDirectory + "Resources\\open.wav")); - DataObject.AddPastingHandler(QueryTextBox, OnPaste); + ModernWpf.ThemeManager.Current.ActualApplicationThemeChanged += OnThemeChanged; } public MainWindow() @@ -742,10 +744,25 @@ public void InitializeColorScheme() if (_settings.ColorScheme == Constant.Light) { ModernWpf.ThemeManager.Current.ApplicationTheme = ModernWpf.ApplicationTheme.Light; + ThemeManager.Instance.BlurColor("Light"); } else if (_settings.ColorScheme == Constant.Dark) { ModernWpf.ThemeManager.Current.ApplicationTheme = ModernWpf.ApplicationTheme.Dark; + ThemeManager.Instance.BlurColor("Dark"); + } + } + + private void OnThemeChanged(ModernWpf.ThemeManager sender, object args) + { + var newTheme = sender.ActualApplicationTheme; + if (newTheme == ApplicationTheme.Dark) + { + ThemeManager.Instance.BlurColor("Dark"); + } + else if (newTheme == ApplicationTheme.Light) + { + ThemeManager.Instance.BlurColor("Light"); } } diff --git a/Flow.Launcher/Resources/Dark.xaml b/Flow.Launcher/Resources/Dark.xaml index 740024ede8e..ecc667ae2ee 100644 --- a/Flow.Launcher/Resources/Dark.xaml +++ b/Flow.Launcher/Resources/Dark.xaml @@ -18,6 +18,7 @@ + #CC202020 #198F8F8F diff --git a/Flow.Launcher/Resources/Light.xaml b/Flow.Launcher/Resources/Light.xaml index fe0f2dbe13b..fa40ff39462 100644 --- a/Flow.Launcher/Resources/Light.xaml +++ b/Flow.Launcher/Resources/Light.xaml @@ -18,6 +18,7 @@ + #CCf3f3f3 #198F8F8F diff --git a/Flow.Launcher/Themes/Base.xaml b/Flow.Launcher/Themes/Base.xaml index af41ff4b38c..cc52e808c32 100644 --- a/Flow.Launcher/Themes/Base.xaml +++ b/Flow.Launcher/Themes/Base.xaml @@ -3,6 +3,11 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:system="clr-namespace:System;assembly=mscorlib" xmlns:userSettings="clr-namespace:Flow.Launcher.Infrastructure.UserSettings;assembly=Flow.Launcher.Infrastructure"> + + + 0 0 0 diff --git a/Flow.Launcher/Themes/BlurBlack.xaml b/Flow.Launcher/Themes/BlurBlack.xaml index 0f126429242..5cfef34783b 100644 --- a/Flow.Launcher/Themes/BlurBlack.xaml +++ b/Flow.Launcher/Themes/BlurBlack.xaml @@ -7,6 +7,10 @@ True + Dark + diff --git a/Flow.Launcher/Themes/Win11System.xaml b/Flow.Launcher/Themes/Win11System.xaml index 2f677804c13..4c28111d580 100644 --- a/Flow.Launcher/Themes/Win11System.xaml +++ b/Flow.Launcher/Themes/Win11System.xaml @@ -7,6 +7,12 @@ + True + Auto + + + red + 0.5 + diff --git a/Flow.Launcher/Themes/Win11System.xaml b/Flow.Launcher/Themes/Win11System.xaml index 4c28111d580..6ad2488efa5 100644 --- a/Flow.Launcher/Themes/Win11System.xaml +++ b/Flow.Launcher/Themes/Win11System.xaml @@ -9,9 +9,6 @@ True Auto -