diff --git a/.github/actions/spelling/allow.txt b/.github/actions/spelling/allow.txt index 00cc67ea00f..a36a6af3efa 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) diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index c4b1ee8494d..8a048c711b2 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 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..35ad32fb3d4 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 ( + 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 - "; + ) + 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 indexOfDefaultProfileAttributePath = lines.IndexOf("Path=" + defaultProfileFolderName); + + // Seen in the example above, the IsRelative attribute is always above the Path attribute + 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" + : 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..a48d70f2d46 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 re-enabled + 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()); } } }