mirror of
https://github.com/Flow-Launcher/Flow.Launcher.git
synced 2026-03-11 08:54:32 +00:00
Merge pull request #2652 from Flow-Launcher/code-cleanup/Flow.Launcher.Plugin.BrowserBookmark
Code cleanup: Flow.Launcher.Plugin.BrowserBookmark
This commit is contained in:
commit
3554136a55
17 changed files with 695 additions and 713 deletions
3
.github/actions/spelling/allow.txt
vendored
3
.github/actions/spelling/allow.txt
vendored
|
|
@ -3,3 +3,6 @@ https
|
|||
ssh
|
||||
ubuntu
|
||||
runcount
|
||||
Firefox
|
||||
Português
|
||||
Português (Brasil)
|
||||
|
|
|
|||
1
.github/actions/spelling/expect.txt
vendored
1
.github/actions/spelling/expect.txt
vendored
|
|
@ -74,6 +74,7 @@ WCA_ACCENT_POLICY
|
|||
HGlobal
|
||||
dopusrt
|
||||
firefox
|
||||
Firefox
|
||||
msedge
|
||||
svgc
|
||||
ime
|
||||
|
|
|
|||
|
|
@ -3,23 +3,22 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Flow.Launcher.Plugin.BrowserBookmark
|
||||
{
|
||||
public class ChromeBookmarkLoader : ChromiumBookmarkLoader
|
||||
{
|
||||
public override List<Bookmark> GetBookmarks()
|
||||
{
|
||||
return LoadChromeBookmarks();
|
||||
}
|
||||
namespace Flow.Launcher.Plugin.BrowserBookmark;
|
||||
|
||||
private List<Bookmark> LoadChromeBookmarks()
|
||||
{
|
||||
var bookmarks = new List<Bookmark>();
|
||||
var platformPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
||||
bookmarks.AddRange(LoadBookmarks(Path.Combine(platformPath, @"Google\Chrome\User Data"), "Google Chrome"));
|
||||
bookmarks.AddRange(LoadBookmarks(Path.Combine(platformPath, @"Google\Chrome SxS\User Data"), "Google Chrome Canary"));
|
||||
bookmarks.AddRange(LoadBookmarks(Path.Combine(platformPath, @"Chromium\User Data"), "Chromium"));
|
||||
return bookmarks;
|
||||
}
|
||||
public class ChromeBookmarkLoader : ChromiumBookmarkLoader
|
||||
{
|
||||
public override List<Bookmark> GetBookmarks()
|
||||
{
|
||||
return LoadChromeBookmarks();
|
||||
}
|
||||
}
|
||||
|
||||
private List<Bookmark> LoadChromeBookmarks()
|
||||
{
|
||||
var bookmarks = new List<Bookmark>();
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,91 +4,90 @@ using System.IO;
|
|||
using System.Text.Json;
|
||||
using Flow.Launcher.Infrastructure.Logger;
|
||||
|
||||
namespace Flow.Launcher.Plugin.BrowserBookmark
|
||||
namespace Flow.Launcher.Plugin.BrowserBookmark;
|
||||
|
||||
public abstract class ChromiumBookmarkLoader : IBookmarkLoader
|
||||
{
|
||||
public abstract class ChromiumBookmarkLoader : IBookmarkLoader
|
||||
public abstract List<Bookmark> GetBookmarks();
|
||||
|
||||
protected List<Bookmark> LoadBookmarks(string browserDataPath, string name)
|
||||
{
|
||||
public abstract List<Bookmark> GetBookmarks();
|
||||
var bookmarks = new List<Bookmark>();
|
||||
if (!Directory.Exists(browserDataPath)) return bookmarks;
|
||||
var paths = Directory.GetDirectories(browserDataPath);
|
||||
|
||||
protected List<Bookmark> LoadBookmarks(string browserDataPath, string name)
|
||||
foreach (var profile in paths)
|
||||
{
|
||||
var bookmarks = new List<Bookmark>();
|
||||
if (!Directory.Exists(browserDataPath)) return bookmarks;
|
||||
var paths = Directory.GetDirectories(browserDataPath);
|
||||
var bookmarkPath = Path.Combine(profile, "Bookmarks");
|
||||
if (!File.Exists(bookmarkPath))
|
||||
continue;
|
||||
|
||||
foreach (var profile in paths)
|
||||
{
|
||||
var bookmarkPath = Path.Combine(profile, "Bookmarks");
|
||||
if (!File.Exists(bookmarkPath))
|
||||
continue;
|
||||
Main.RegisterBookmarkFile(bookmarkPath);
|
||||
|
||||
Main.RegisterBookmarkFile(bookmarkPath);
|
||||
var source = name + (Path.GetFileName(profile) == "Default" ? "" : $" ({Path.GetFileName(profile)})");
|
||||
bookmarks.AddRange(LoadBookmarksFromFile(bookmarkPath, source));
|
||||
}
|
||||
|
||||
var source = name + (Path.GetFileName(profile) == "Default" ? "" : $" ({Path.GetFileName(profile)})");
|
||||
bookmarks.AddRange(LoadBookmarksFromFile(bookmarkPath, source));
|
||||
}
|
||||
return bookmarks;
|
||||
}
|
||||
|
||||
protected List<Bookmark> LoadBookmarksFromFile(string path, string source)
|
||||
{
|
||||
var bookmarks = new List<Bookmark>();
|
||||
|
||||
if (!File.Exists(path))
|
||||
return bookmarks;
|
||||
}
|
||||
|
||||
protected List<Bookmark> LoadBookmarksFromFile(string path, string source)
|
||||
{
|
||||
var bookmarks = new List<Bookmark>();
|
||||
|
||||
if (!File.Exists(path))
|
||||
return bookmarks;
|
||||
|
||||
using var jsonDocument = JsonDocument.Parse(File.ReadAllText(path));
|
||||
if (!jsonDocument.RootElement.TryGetProperty("roots", out var rootElement))
|
||||
return bookmarks;
|
||||
EnumerateRoot(rootElement, bookmarks, source);
|
||||
using var jsonDocument = JsonDocument.Parse(File.ReadAllText(path));
|
||||
if (!jsonDocument.RootElement.TryGetProperty("roots", out var rootElement))
|
||||
return bookmarks;
|
||||
}
|
||||
EnumerateRoot(rootElement, bookmarks, source);
|
||||
return bookmarks;
|
||||
}
|
||||
|
||||
private void EnumerateRoot(JsonElement rootElement, ICollection<Bookmark> bookmarks, string source)
|
||||
private void EnumerateRoot(JsonElement rootElement, ICollection<Bookmark> 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<Bookmark> bookmarks,
|
||||
string source)
|
||||
{
|
||||
if (!folderElement.TryGetProperty("children", out var childrenElement))
|
||||
return;
|
||||
foreach (var subElement in childrenElement.EnumerateArray())
|
||||
{
|
||||
if (subElement.TryGetProperty("type", out var type))
|
||||
{
|
||||
switch (type.GetString())
|
||||
{
|
||||
case "folder":
|
||||
case "workspace": // Edge Workspace
|
||||
EnumerateFolderBookmark(subElement, bookmarks, source);
|
||||
break;
|
||||
default:
|
||||
bookmarks.Add(new Bookmark(
|
||||
subElement.GetProperty("name").GetString(),
|
||||
subElement.GetProperty("url").GetString(),
|
||||
source));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void EnumerateFolderBookmark(JsonElement folderElement, ICollection<Bookmark> bookmarks,
|
||||
string source)
|
||||
{
|
||||
if (!folderElement.TryGetProperty("children", out var childrenElement))
|
||||
return;
|
||||
foreach (var subElement in childrenElement.EnumerateArray())
|
||||
else
|
||||
{
|
||||
if (subElement.TryGetProperty("type", out var type))
|
||||
{
|
||||
switch (type.GetString())
|
||||
{
|
||||
case "folder":
|
||||
case "workspace": // Edge Workspace
|
||||
EnumerateFolderBookmark(subElement, bookmarks, source);
|
||||
break;
|
||||
default:
|
||||
bookmarks.Add(new Bookmark(
|
||||
subElement.GetProperty("name").GetString(),
|
||||
subElement.GetProperty("url").GetString(),
|
||||
source));
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Error(
|
||||
$"ChromiumBookmarkLoader: EnumerateFolderBookmark: type property not found for {subElement.GetString()}");
|
||||
}
|
||||
Log.Error(
|
||||
$"ChromiumBookmarkLoader: EnumerateFolderBookmark: type property not found for {subElement.GetString()}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,56 +4,55 @@ using Flow.Launcher.Infrastructure;
|
|||
using Flow.Launcher.Plugin.BrowserBookmark.Models;
|
||||
using Flow.Launcher.Plugin.SharedModels;
|
||||
|
||||
namespace Flow.Launcher.Plugin.BrowserBookmark.Commands
|
||||
namespace Flow.Launcher.Plugin.BrowserBookmark.Commands;
|
||||
|
||||
internal static class BookmarkLoader
|
||||
{
|
||||
internal static class BookmarkLoader
|
||||
internal static MatchResult MatchProgram(Bookmark bookmark, string queryString)
|
||||
{
|
||||
internal static MatchResult MatchProgram(Bookmark bookmark, string queryString)
|
||||
{
|
||||
var match = StringMatcher.FuzzySearch(queryString, bookmark.Name);
|
||||
if (match.IsSearchPrecisionScoreMet())
|
||||
return match;
|
||||
var match = StringMatcher.FuzzySearch(queryString, bookmark.Name);
|
||||
if (match.IsSearchPrecisionScoreMet())
|
||||
return match;
|
||||
|
||||
return StringMatcher.FuzzySearch(queryString, bookmark.Url);
|
||||
return StringMatcher.FuzzySearch(queryString, bookmark.Url);
|
||||
}
|
||||
|
||||
internal static List<Bookmark> LoadAllBookmarks(Settings setting)
|
||||
{
|
||||
var allBookmarks = new List<Bookmark>();
|
||||
|
||||
if (setting.LoadChromeBookmark)
|
||||
{
|
||||
// Add Chrome bookmarks
|
||||
var chromeBookmarks = new ChromeBookmarkLoader();
|
||||
allBookmarks.AddRange(chromeBookmarks.GetBookmarks());
|
||||
}
|
||||
|
||||
internal static List<Bookmark> LoadAllBookmarks(Settings setting)
|
||||
if (setting.LoadFirefoxBookmark)
|
||||
{
|
||||
var allBookmarks = new List<Bookmark>();
|
||||
|
||||
if (setting.LoadChromeBookmark)
|
||||
{
|
||||
// Add Chrome bookmarks
|
||||
var chromeBookmarks = new ChromeBookmarkLoader();
|
||||
allBookmarks.AddRange(chromeBookmarks.GetBookmarks());
|
||||
}
|
||||
|
||||
if (setting.LoadFirefoxBookmark)
|
||||
{
|
||||
// Add Firefox bookmarks
|
||||
var mozBookmarks = new FirefoxBookmarkLoader();
|
||||
allBookmarks.AddRange(mozBookmarks.GetBookmarks());
|
||||
}
|
||||
|
||||
if (setting.LoadEdgeBookmark)
|
||||
{
|
||||
// Add Edge (Chromium) bookmarks
|
||||
var edgeBookmarks = new EdgeBookmarkLoader();
|
||||
allBookmarks.AddRange(edgeBookmarks.GetBookmarks());
|
||||
}
|
||||
|
||||
foreach (var browser in setting.CustomChromiumBrowsers)
|
||||
{
|
||||
IBookmarkLoader loader = browser.BrowserType switch
|
||||
{
|
||||
BrowserType.Chromium => new CustomChromiumBookmarkLoader(browser),
|
||||
BrowserType.Firefox => new CustomFirefoxBookmarkLoader(browser),
|
||||
_ => new CustomChromiumBookmarkLoader(browser),
|
||||
};
|
||||
allBookmarks.AddRange(loader.GetBookmarks());
|
||||
}
|
||||
|
||||
return allBookmarks.Distinct().ToList();
|
||||
// Add Firefox bookmarks
|
||||
var mozBookmarks = new FirefoxBookmarkLoader();
|
||||
allBookmarks.AddRange(mozBookmarks.GetBookmarks());
|
||||
}
|
||||
|
||||
if (setting.LoadEdgeBookmark)
|
||||
{
|
||||
// Add Edge (Chromium) bookmarks
|
||||
var edgeBookmarks = new EdgeBookmarkLoader();
|
||||
allBookmarks.AddRange(edgeBookmarks.GetBookmarks());
|
||||
}
|
||||
|
||||
foreach (var browser in setting.CustomChromiumBrowsers)
|
||||
{
|
||||
IBookmarkLoader loader = browser.BrowserType switch
|
||||
{
|
||||
BrowserType.Chromium => new CustomChromiumBookmarkLoader(browser),
|
||||
BrowserType.Firefox => new CustomFirefoxBookmarkLoader(browser),
|
||||
_ => new CustomChromiumBookmarkLoader(browser),
|
||||
};
|
||||
allBookmarks.AddRange(loader.GetBookmarks());
|
||||
}
|
||||
|
||||
return allBookmarks.Distinct().ToList();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,18 @@
|
|||
using Flow.Launcher.Plugin.BrowserBookmark.Models;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Flow.Launcher.Plugin.BrowserBookmark
|
||||
{
|
||||
public class CustomChromiumBookmarkLoader : ChromiumBookmarkLoader
|
||||
{
|
||||
public CustomChromiumBookmarkLoader(CustomBrowser browser)
|
||||
{
|
||||
BrowserName = browser.Name;
|
||||
BrowserDataPath = browser.DataDirectoryPath;
|
||||
}
|
||||
public string BrowserDataPath { get; init; }
|
||||
public string BookmarkFilePath { get; init; }
|
||||
public string BrowserName { get; init; }
|
||||
namespace Flow.Launcher.Plugin.BrowserBookmark;
|
||||
|
||||
public override List<Bookmark> GetBookmarks() => BrowserDataPath != null ? LoadBookmarks(BrowserDataPath, BrowserName) : LoadBookmarksFromFile(BookmarkFilePath, BrowserName);
|
||||
public class CustomChromiumBookmarkLoader : ChromiumBookmarkLoader
|
||||
{
|
||||
public CustomChromiumBookmarkLoader(CustomBrowser browser)
|
||||
{
|
||||
BrowserName = browser.Name;
|
||||
BrowserDataPath = browser.DataDirectoryPath;
|
||||
}
|
||||
}
|
||||
public string BrowserDataPath { get; init; }
|
||||
public string BookmarkFilePath { get; init; }
|
||||
public string BrowserName { get; init; }
|
||||
|
||||
public override List<Bookmark> GetBookmarks() => BrowserDataPath != null ? LoadBookmarks(BrowserDataPath, BrowserName) : LoadBookmarksFromFile(BookmarkFilePath, BrowserName);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,26 +2,25 @@
|
|||
using System.IO;
|
||||
using Flow.Launcher.Plugin.BrowserBookmark.Models;
|
||||
|
||||
namespace Flow.Launcher.Plugin.BrowserBookmark
|
||||
{
|
||||
public class CustomFirefoxBookmarkLoader : FirefoxBookmarkLoaderBase
|
||||
{
|
||||
public CustomFirefoxBookmarkLoader(CustomBrowser browser)
|
||||
{
|
||||
BrowserName = browser.Name;
|
||||
BrowserDataPath = browser.DataDirectoryPath;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Path to places.sqlite
|
||||
/// </summary>
|
||||
public string BrowserDataPath { get; init; }
|
||||
|
||||
public string BrowserName { get; init; }
|
||||
namespace Flow.Launcher.Plugin.BrowserBookmark;
|
||||
|
||||
public override List<Bookmark> GetBookmarks()
|
||||
{
|
||||
return GetBookmarksFromPath(Path.Combine(BrowserDataPath, "places.sqlite"));
|
||||
}
|
||||
public class CustomFirefoxBookmarkLoader : FirefoxBookmarkLoaderBase
|
||||
{
|
||||
public CustomFirefoxBookmarkLoader(CustomBrowser browser)
|
||||
{
|
||||
BrowserName = browser.Name;
|
||||
BrowserDataPath = browser.DataDirectoryPath;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Path to places.sqlite
|
||||
/// </summary>
|
||||
public string BrowserDataPath { get; init; }
|
||||
|
||||
public string BrowserName { get; init; }
|
||||
|
||||
public override List<Bookmark> GetBookmarks()
|
||||
{
|
||||
return GetBookmarksFromPath(Path.Combine(BrowserDataPath, "places.sqlite"));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,21 +3,20 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Flow.Launcher.Plugin.BrowserBookmark
|
||||
{
|
||||
public class EdgeBookmarkLoader : ChromiumBookmarkLoader
|
||||
{
|
||||
private List<Bookmark> LoadEdgeBookmarks()
|
||||
{
|
||||
var bookmarks = new List<Bookmark>();
|
||||
var platformPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
||||
bookmarks.AddRange(LoadBookmarks(Path.Combine(platformPath, @"Microsoft\Edge\User Data"), "Microsoft Edge"));
|
||||
bookmarks.AddRange(LoadBookmarks(Path.Combine(platformPath, @"Microsoft\Edge Dev\User Data"), "Microsoft Edge Dev"));
|
||||
bookmarks.AddRange(LoadBookmarks(Path.Combine(platformPath, @"Microsoft\Edge SxS\User Data"), "Microsoft Edge Canary"));
|
||||
namespace Flow.Launcher.Plugin.BrowserBookmark;
|
||||
|
||||
return bookmarks;
|
||||
}
|
||||
|
||||
public override List<Bookmark> GetBookmarks() => LoadEdgeBookmarks();
|
||||
public class EdgeBookmarkLoader : ChromiumBookmarkLoader
|
||||
{
|
||||
private List<Bookmark> LoadEdgeBookmarks()
|
||||
{
|
||||
var bookmarks = new List<Bookmark>();
|
||||
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<Bookmark> GetBookmarks() => LoadEdgeBookmarks();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,140 +5,133 @@ using System.Collections.Generic;
|
|||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Flow.Launcher.Plugin.BrowserBookmark
|
||||
namespace Flow.Launcher.Plugin.BrowserBookmark;
|
||||
|
||||
public abstract class FirefoxBookmarkLoaderBase : IBookmarkLoader
|
||||
{
|
||||
public abstract class FirefoxBookmarkLoaderBase : IBookmarkLoader
|
||||
{
|
||||
public abstract List<Bookmark> GetBookmarks();
|
||||
public abstract List<Bookmark> 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<Bookmark> GetBookmarksFromPath(string placesPath)
|
||||
{
|
||||
// Return empty list if the places.sqlite file cannot be found
|
||||
if (string.IsNullOrEmpty(placesPath) || !File.Exists(placesPath))
|
||||
return new List<Bookmark>();
|
||||
protected static List<Bookmark> GetBookmarksFromPath(string placesPath)
|
||||
{
|
||||
// Return empty list if the places.sqlite file cannot be found
|
||||
if (string.IsNullOrEmpty(placesPath) || !File.Exists(placesPath))
|
||||
return new List<Bookmark>();
|
||||
|
||||
var bookmarkList = new List<Bookmark>();
|
||||
Main.RegisterBookmarkFile(placesPath);
|
||||
|
||||
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();
|
||||
|
||||
// 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<Bookmark> format
|
||||
bookmarkList = reader.Select(
|
||||
x => new Bookmark(x["title"] is DBNull ? string.Empty : x["title"].ToString(),
|
||||
x["url"].ToString())
|
||||
).ToList();
|
||||
// return results in List<Bookmark> format
|
||||
return reader
|
||||
.Select(
|
||||
x => new Bookmark(
|
||||
x["title"] is DBNull ? string.Empty : x["title"].ToString(),
|
||||
x["url"].ToString()
|
||||
)
|
||||
)
|
||||
.ToList();
|
||||
}
|
||||
}
|
||||
|
||||
return bookmarkList;
|
||||
}
|
||||
|
||||
public class FirefoxBookmarkLoader : FirefoxBookmarkLoaderBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Searches the places.sqlite db and returns all bookmarks
|
||||
/// </summary>
|
||||
public override List<Bookmark> GetBookmarks()
|
||||
{
|
||||
return GetBookmarksFromPath(PlacesPath);
|
||||
}
|
||||
|
||||
|
||||
public class FirefoxBookmarkLoader : FirefoxBookmarkLoaderBase
|
||||
/// <summary>
|
||||
/// Path to places.sqlite
|
||||
/// </summary>
|
||||
private string PlacesPath
|
||||
{
|
||||
/// <summary>
|
||||
/// Searches the places.sqlite db and returns all bookmarks
|
||||
/// </summary>
|
||||
public override List<Bookmark> GetBookmarks()
|
||||
get
|
||||
{
|
||||
return GetBookmarksFromPath(PlacesPath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Path to places.sqlite
|
||||
/// </summary>
|
||||
private string PlacesPath
|
||||
{
|
||||
get
|
||||
{
|
||||
var profileFolderPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"Mozilla\Firefox");
|
||||
var profileIni = Path.Combine(profileFolderPath, @"profiles.ini");
|
||||
var profileFolderPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"Mozilla\Firefox");
|
||||
var profileIni = Path.Combine(profileFolderPath, @"profiles.ini");
|
||||
|
||||
if (!File.Exists(profileIni))
|
||||
return string.Empty;
|
||||
if (!File.Exists(profileIni))
|
||||
return string.Empty;
|
||||
|
||||
// get firefox default profile directory from profiles.ini
|
||||
string ini;
|
||||
using (var sReader = new StreamReader(profileIni))
|
||||
{
|
||||
ini = sReader.ReadToEnd();
|
||||
}
|
||||
// get firefox default profile directory from profiles.ini
|
||||
using var sReader = new StreamReader(profileIni);
|
||||
var ini = sReader.ReadToEnd();
|
||||
|
||||
/*
|
||||
Current profiles.ini structure example as of Firefox version 69.0.1
|
||||
|
||||
[Install736426B0AF4A39CB]
|
||||
Default=Profiles/7789f565.default-release <== this is the default profile this plugin will get the bookmarks from. When opened Firefox will load the default profile
|
||||
Locked=1
|
||||
/*
|
||||
Current profiles.ini structure example as of Firefox version 69.0.1
|
||||
|
||||
[Profile2]
|
||||
Name=newblahprofile
|
||||
IsRelative=0
|
||||
Path=C:\t6h2yuq8.newblahprofile <== Note this is a custom location path for the profile user can set, we need to cater for this in code.
|
||||
[Install736426B0AF4A39CB]
|
||||
Default=Profiles/7789f565.default-release <== this is the default profile this plugin will get the bookmarks from. When opened Firefox will load the default profile
|
||||
Locked=1
|
||||
|
||||
[Profile1]
|
||||
Name=default
|
||||
IsRelative=1
|
||||
Path=Profiles/cydum7q4.default
|
||||
Default=1
|
||||
[Profile2]
|
||||
Name=newblahprofile
|
||||
IsRelative=0
|
||||
Path=C:\t6h2yuq8.newblahprofile <== Note this is a custom location path for the profile user can set, we need to cater for this in code.
|
||||
|
||||
[Profile0]
|
||||
Name=default-release
|
||||
IsRelative=1
|
||||
Path=Profiles/7789f565.default-release
|
||||
[Profile1]
|
||||
Name=default
|
||||
IsRelative=1
|
||||
Path=Profiles/cydum7q4.default
|
||||
Default=1
|
||||
|
||||
[General]
|
||||
StartWithLastProfile=1
|
||||
Version=2
|
||||
*/
|
||||
[Profile0]
|
||||
Name=default-release
|
||||
IsRelative=1
|
||||
Path=Profiles/7789f565.default-release
|
||||
|
||||
var lines = ini.Split(new string[]
|
||||
{
|
||||
"\r\n"
|
||||
}, StringSplitOptions.None).ToList();
|
||||
[General]
|
||||
StartWithLastProfile=1
|
||||
Version=2
|
||||
*/
|
||||
var lines = ini.Split("\r\n").ToList();
|
||||
|
||||
var defaultProfileFolderNameRaw = lines.Where(x => x.Contains("Default=") && x != "Default=1").FirstOrDefault() ?? string.Empty;
|
||||
var defaultProfileFolderNameRaw = lines.FirstOrDefault(x => x.Contains("Default=") && x != "Default=1") ?? string.Empty;
|
||||
|
||||
if (string.IsNullOrEmpty(defaultProfileFolderNameRaw))
|
||||
return string.Empty;
|
||||
if (string.IsNullOrEmpty(defaultProfileFolderNameRaw))
|
||||
return string.Empty;
|
||||
|
||||
var defaultProfileFolderName = defaultProfileFolderNameRaw.Split('=').Last();
|
||||
var defaultProfileFolderName = defaultProfileFolderNameRaw.Split('=').Last();
|
||||
|
||||
var indexOfDefaultProfileAtttributePath = lines.IndexOf("Path=" + defaultProfileFolderName);
|
||||
var indexOfDefaultProfileAttributePath = lines.IndexOf("Path=" + defaultProfileFolderName);
|
||||
|
||||
// Seen in the example above, the IsRelative attribute is always above the Path attribute
|
||||
var relativeAttribute = lines[indexOfDefaultProfileAtttributePath - 1];
|
||||
// Seen in the example above, the IsRelative attribute is always above the Path attribute
|
||||
var relativeAttribute = lines[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 IEnumerable<T> Select<T>(this SqliteDataReader reader, Func<SqliteDataReader, T> projection)
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
yield return projection(reader);
|
||||
}
|
||||
return relativeAttribute == "0" // See above, the profile is located in a custom location, path is not relative, so IsRelative=0
|
||||
? defaultProfileFolderName + @"\places.sqlite"
|
||||
: Path.Combine(profileFolderPath, defaultProfileFolderName) + @"\places.sqlite";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class Extensions
|
||||
{
|
||||
public static IEnumerable<T> Select<T>(this SqliteDataReader reader, Func<SqliteDataReader, T> projection)
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
yield return projection(reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Bookmark> GetBookmarks();
|
||||
}
|
||||
}
|
||||
public List<Bookmark> GetBookmarks();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using Flow.Launcher.Infrastructure.Logger;
|
||||
using Flow.Launcher.Plugin.BrowserBookmark.Commands;
|
||||
|
|
@ -12,233 +11,234 @@ using System.Threading.Channels;
|
|||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
|
||||
namespace Flow.Launcher.Plugin.BrowserBookmark
|
||||
namespace Flow.Launcher.Plugin.BrowserBookmark;
|
||||
|
||||
public class Main : ISettingProvider, IPlugin, IReloadable, IPluginI18n, IContextMenu, IDisposable
|
||||
{
|
||||
public class Main : ISettingProvider, IPlugin, IReloadable, IPluginI18n, IContextMenu, IDisposable
|
||||
private static PluginInitContext _context;
|
||||
|
||||
private static List<Bookmark> _cachedBookmarks = new List<Bookmark>();
|
||||
|
||||
private static Settings _settings;
|
||||
|
||||
private static bool _initialized = false;
|
||||
|
||||
public void Init(PluginInitContext context)
|
||||
{
|
||||
private static PluginInitContext context;
|
||||
_context = context;
|
||||
|
||||
private static List<Bookmark> cachedBookmarks = new List<Bookmark>();
|
||||
_settings = context.API.LoadSettingJsonStorage<Settings>();
|
||||
|
||||
private static Settings _settings;
|
||||
LoadBookmarksIfEnabled();
|
||||
}
|
||||
|
||||
private static bool initialized = false;
|
||||
|
||||
public void Init(PluginInitContext context)
|
||||
private static void LoadBookmarksIfEnabled()
|
||||
{
|
||||
if (_context.CurrentPluginMetadata.Disabled)
|
||||
{
|
||||
Main.context = context;
|
||||
// Don't load or monitor files if disabled
|
||||
return;
|
||||
}
|
||||
|
||||
_settings = context.API.LoadSettingJsonStorage<Settings>();
|
||||
_cachedBookmarks = BookmarkLoader.LoadAllBookmarks(_settings);
|
||||
_ = MonitorRefreshQueueAsync();
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
public List<Result> Query(Query query)
|
||||
{
|
||||
// For when the plugin being previously disabled and is now re-enabled
|
||||
if (!_initialized)
|
||||
{
|
||||
LoadBookmarksIfEnabled();
|
||||
}
|
||||
|
||||
private static void LoadBookmarksIfEnabled()
|
||||
string param = query.Search.TrimStart();
|
||||
|
||||
// Should top results be returned? (true if no search parameters have been passed)
|
||||
var topResults = string.IsNullOrEmpty(param);
|
||||
|
||||
|
||||
if (!topResults)
|
||||
{
|
||||
if (context.CurrentPluginMetadata.Disabled)
|
||||
{
|
||||
// Don't load or monitor files if disabled
|
||||
return;
|
||||
}
|
||||
|
||||
cachedBookmarks = BookmarkLoader.LoadAllBookmarks(_settings);
|
||||
_ = MonitorRefreshQueueAsync();
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
public List<Result> Query(Query query)
|
||||
{
|
||||
// For when the plugin being previously disabled and is now renabled
|
||||
if (!initialized)
|
||||
{
|
||||
LoadBookmarksIfEnabled();
|
||||
}
|
||||
|
||||
string param = query.Search.TrimStart();
|
||||
|
||||
// Should top results be returned? (true if no search parameters have been passed)
|
||||
var topResults = string.IsNullOrEmpty(param);
|
||||
|
||||
|
||||
if (!topResults)
|
||||
{
|
||||
// Since we mixed chrome and firefox bookmarks, we should order them again
|
||||
var returnList = cachedBookmarks.Select(c => new Result()
|
||||
{
|
||||
Title = c.Name,
|
||||
SubTitle = c.Url,
|
||||
IcoPath = @"Images\bookmark.png",
|
||||
Score = BookmarkLoader.MatchProgram(c, param).Score,
|
||||
Action = _ =>
|
||||
// Since we mixed chrome and firefox bookmarks, we should order them again
|
||||
return _cachedBookmarks
|
||||
.Select(
|
||||
c => new Result
|
||||
{
|
||||
context.API.OpenUrl(c.Url);
|
||||
|
||||
return true;
|
||||
},
|
||||
ContextData = new BookmarkAttributes
|
||||
{
|
||||
Url = c.Url
|
||||
}
|
||||
}).Where(r => r.Score > 0);
|
||||
return returnList.ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
return cachedBookmarks.Select(c => new Result()
|
||||
{
|
||||
Title = c.Name,
|
||||
SubTitle = c.Url,
|
||||
IcoPath = @"Images\bookmark.png",
|
||||
Score = 5,
|
||||
Action = _ =>
|
||||
{
|
||||
context.API.OpenUrl(c.Url);
|
||||
return true;
|
||||
},
|
||||
ContextData = new BookmarkAttributes
|
||||
{
|
||||
Url = c.Url
|
||||
}
|
||||
}).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static Channel<byte> refreshQueue = Channel.CreateBounded<byte>(1);
|
||||
|
||||
private static SemaphoreSlim fileMonitorSemaphore = new(1, 1);
|
||||
|
||||
private static async Task MonitorRefreshQueueAsync()
|
||||
{
|
||||
if (fileMonitorSemaphore.CurrentCount < 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
await fileMonitorSemaphore.WaitAsync();
|
||||
var reader = refreshQueue.Reader;
|
||||
while (await reader.WaitToReadAsync())
|
||||
{
|
||||
if (reader.TryRead(out _))
|
||||
{
|
||||
ReloadAllBookmarks(false);
|
||||
}
|
||||
}
|
||||
fileMonitorSemaphore.Release();
|
||||
}
|
||||
|
||||
private static readonly List<FileSystemWatcher> Watchers = new();
|
||||
|
||||
internal static void RegisterBookmarkFile(string path)
|
||||
{
|
||||
var directory = Path.GetDirectoryName(path);
|
||||
if (!Directory.Exists(directory) || !File.Exists(path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (Watchers.Any(x => x.Path.Equals(directory, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var watcher = new FileSystemWatcher(directory!);
|
||||
watcher.Filter = Path.GetFileName(path);
|
||||
|
||||
watcher.NotifyFilter = NotifyFilters.FileName |
|
||||
NotifyFilters.LastWrite |
|
||||
NotifyFilters.Size;
|
||||
|
||||
watcher.Changed += static (_, _) =>
|
||||
{
|
||||
refreshQueue.Writer.TryWrite(default);
|
||||
};
|
||||
|
||||
watcher.Renamed += static (_, _) =>
|
||||
{
|
||||
refreshQueue.Writer.TryWrite(default);
|
||||
};
|
||||
|
||||
watcher.EnableRaisingEvents = true;
|
||||
|
||||
Watchers.Add(watcher);
|
||||
}
|
||||
|
||||
public void ReloadData()
|
||||
{
|
||||
ReloadAllBookmarks();
|
||||
}
|
||||
|
||||
public static void ReloadAllBookmarks(bool disposeFileWatchers = true)
|
||||
{
|
||||
cachedBookmarks.Clear();
|
||||
if (disposeFileWatchers)
|
||||
DisposeFileWatchers();
|
||||
LoadBookmarksIfEnabled();
|
||||
}
|
||||
|
||||
public string GetTranslatedPluginTitle()
|
||||
{
|
||||
return context.API.GetTranslation("flowlauncher_plugin_browserbookmark_plugin_name");
|
||||
}
|
||||
|
||||
public string GetTranslatedPluginDescription()
|
||||
{
|
||||
return context.API.GetTranslation("flowlauncher_plugin_browserbookmark_plugin_description");
|
||||
}
|
||||
|
||||
public Control CreateSettingPanel()
|
||||
{
|
||||
return new SettingsControl(_settings);
|
||||
}
|
||||
|
||||
public List<Result> LoadContextMenus(Result selectedResult)
|
||||
{
|
||||
return new List<Result>()
|
||||
{
|
||||
new Result
|
||||
{
|
||||
Title = context.API.GetTranslation("flowlauncher_plugin_browserbookmark_copyurl_title"),
|
||||
SubTitle = context.API.GetTranslation("flowlauncher_plugin_browserbookmark_copyurl_subtitle"),
|
||||
Action = _ =>
|
||||
{
|
||||
try
|
||||
Title = c.Name,
|
||||
SubTitle = c.Url,
|
||||
IcoPath = @"Images\bookmark.png",
|
||||
Score = BookmarkLoader.MatchProgram(c, param).Score,
|
||||
Action = _ =>
|
||||
{
|
||||
context.API.CopyToClipboard(((BookmarkAttributes)selectedResult.ContextData).Url);
|
||||
_context.API.OpenUrl(c.Url);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
},
|
||||
ContextData = new BookmarkAttributes { Url = c.Url }
|
||||
}
|
||||
)
|
||||
.Where(r => r.Score > 0)
|
||||
.ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
return _cachedBookmarks
|
||||
.Select(
|
||||
c => new Result
|
||||
{
|
||||
Title = c.Name,
|
||||
SubTitle = c.Url,
|
||||
IcoPath = @"Images\bookmark.png",
|
||||
Score = 5,
|
||||
Action = _ =>
|
||||
{
|
||||
var message = "Failed to set url in clipboard";
|
||||
Log.Exception("Main", message, e, "LoadContextMenus");
|
||||
|
||||
context.API.ShowMsg(message);
|
||||
|
||||
return false;
|
||||
}
|
||||
},
|
||||
IcoPath = "Images\\copylink.png",
|
||||
Glyph = new GlyphInfo(FontFamily: "/Resources/#Segoe Fluent Icons", Glyph: "\ue8c8")
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
internal class BookmarkAttributes
|
||||
{
|
||||
internal string Url { get; set; }
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
DisposeFileWatchers();
|
||||
}
|
||||
|
||||
private static void DisposeFileWatchers()
|
||||
{
|
||||
foreach (var watcher in Watchers)
|
||||
{
|
||||
watcher.Dispose();
|
||||
}
|
||||
Watchers.Clear();
|
||||
_context.API.OpenUrl(c.Url);
|
||||
return true;
|
||||
},
|
||||
ContextData = new BookmarkAttributes { Url = c.Url }
|
||||
}
|
||||
)
|
||||
.ToList();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static Channel<byte> _refreshQueue = Channel.CreateBounded<byte>(1);
|
||||
|
||||
private static SemaphoreSlim _fileMonitorSemaphore = new(1, 1);
|
||||
|
||||
private static async Task MonitorRefreshQueueAsync()
|
||||
{
|
||||
if (_fileMonitorSemaphore.CurrentCount < 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
await _fileMonitorSemaphore.WaitAsync();
|
||||
var reader = _refreshQueue.Reader;
|
||||
while (await reader.WaitToReadAsync())
|
||||
{
|
||||
if (reader.TryRead(out _))
|
||||
{
|
||||
ReloadAllBookmarks(false);
|
||||
}
|
||||
}
|
||||
_fileMonitorSemaphore.Release();
|
||||
}
|
||||
|
||||
private static readonly List<FileSystemWatcher> Watchers = new();
|
||||
|
||||
internal static void RegisterBookmarkFile(string path)
|
||||
{
|
||||
var directory = Path.GetDirectoryName(path);
|
||||
if (!Directory.Exists(directory) || !File.Exists(path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (Watchers.Any(x => x.Path.Equals(directory, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var watcher = new FileSystemWatcher(directory!);
|
||||
watcher.Filter = Path.GetFileName(path);
|
||||
|
||||
watcher.NotifyFilter = NotifyFilters.FileName |
|
||||
NotifyFilters.LastWrite |
|
||||
NotifyFilters.Size;
|
||||
|
||||
watcher.Changed += static (_, _) =>
|
||||
{
|
||||
_refreshQueue.Writer.TryWrite(default);
|
||||
};
|
||||
|
||||
watcher.Renamed += static (_, _) =>
|
||||
{
|
||||
_refreshQueue.Writer.TryWrite(default);
|
||||
};
|
||||
|
||||
watcher.EnableRaisingEvents = true;
|
||||
|
||||
Watchers.Add(watcher);
|
||||
}
|
||||
|
||||
public void ReloadData()
|
||||
{
|
||||
ReloadAllBookmarks();
|
||||
}
|
||||
|
||||
public static void ReloadAllBookmarks(bool disposeFileWatchers = true)
|
||||
{
|
||||
_cachedBookmarks.Clear();
|
||||
if (disposeFileWatchers)
|
||||
DisposeFileWatchers();
|
||||
LoadBookmarksIfEnabled();
|
||||
}
|
||||
|
||||
public string GetTranslatedPluginTitle()
|
||||
{
|
||||
return _context.API.GetTranslation("flowlauncher_plugin_browserbookmark_plugin_name");
|
||||
}
|
||||
|
||||
public string GetTranslatedPluginDescription()
|
||||
{
|
||||
return _context.API.GetTranslation("flowlauncher_plugin_browserbookmark_plugin_description");
|
||||
}
|
||||
|
||||
public Control CreateSettingPanel()
|
||||
{
|
||||
return new SettingsControl(_settings);
|
||||
}
|
||||
|
||||
public List<Result> LoadContextMenus(Result selectedResult)
|
||||
{
|
||||
return new List<Result>()
|
||||
{
|
||||
new Result
|
||||
{
|
||||
Title = _context.API.GetTranslation("flowlauncher_plugin_browserbookmark_copyurl_title"),
|
||||
SubTitle = _context.API.GetTranslation("flowlauncher_plugin_browserbookmark_copyurl_subtitle"),
|
||||
Action = _ =>
|
||||
{
|
||||
try
|
||||
{
|
||||
_context.API.CopyToClipboard(((BookmarkAttributes)selectedResult.ContextData).Url);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
var message = "Failed to set url in clipboard";
|
||||
Log.Exception("Main", message, e, "LoadContextMenus");
|
||||
|
||||
_context.API.ShowMsg(message);
|
||||
|
||||
return false;
|
||||
}
|
||||
},
|
||||
IcoPath = @"Images\copylink.png",
|
||||
Glyph = new GlyphInfo(FontFamily: "/Resources/#Segoe Fluent Icons", Glyph: "\ue8c8")
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
internal class BookmarkAttributes
|
||||
{
|
||||
internal string Url { get; set; }
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
DisposeFileWatchers();
|
||||
}
|
||||
|
||||
private static void DisposeFileWatchers()
|
||||
{
|
||||
foreach (var watcher in Watchers)
|
||||
{
|
||||
watcher.Dispose();
|
||||
}
|
||||
Watchers.Clear();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,22 +1,21 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Flow.Launcher.Plugin.BrowserBookmark.Models
|
||||
namespace Flow.Launcher.Plugin.BrowserBookmark.Models;
|
||||
|
||||
// Source may be important in the future
|
||||
public record Bookmark(string Name, string Url, string Source = "")
|
||||
{
|
||||
// Source may be important in the future
|
||||
public record Bookmark(string Name, string Url, string Source = "")
|
||||
public override int GetHashCode()
|
||||
{
|
||||
public override int GetHashCode()
|
||||
{
|
||||
var hashName = Name?.GetHashCode() ?? 0;
|
||||
var hashUrl = Url?.GetHashCode() ?? 0;
|
||||
return hashName ^ hashUrl;
|
||||
}
|
||||
|
||||
public virtual bool Equals(Bookmark other)
|
||||
{
|
||||
return other != null && Name == other.Name && Url == other.Url;
|
||||
}
|
||||
|
||||
public List<CustomBrowser> CustomBrowsers { get; set; }= new();
|
||||
var hashName = Name?.GetHashCode() ?? 0;
|
||||
var hashUrl = Url?.GetHashCode() ?? 0;
|
||||
return hashName ^ hashUrl;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual bool Equals(Bookmark other)
|
||||
{
|
||||
return other != null && Name == other.Name && Url == other.Url;
|
||||
}
|
||||
|
||||
public List<CustomBrowser> CustomBrowsers { get; set; } = new();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,45 +1,44 @@
|
|||
namespace Flow.Launcher.Plugin.BrowserBookmark.Models
|
||||
{
|
||||
public class CustomBrowser : BaseModel
|
||||
{
|
||||
private string _name;
|
||||
private string _dataDirectoryPath;
|
||||
private BrowserType browserType = BrowserType.Chromium;
|
||||
namespace Flow.Launcher.Plugin.BrowserBookmark.Models;
|
||||
|
||||
public string Name
|
||||
public class CustomBrowser : BaseModel
|
||||
{
|
||||
private string _name;
|
||||
private string _dataDirectoryPath;
|
||||
private BrowserType _browserType = BrowserType.Chromium;
|
||||
|
||||
public string Name
|
||||
{
|
||||
get => _name;
|
||||
set
|
||||
{
|
||||
get => _name;
|
||||
set
|
||||
{
|
||||
_name = value;
|
||||
OnPropertyChanged(nameof(Name));
|
||||
}
|
||||
}
|
||||
|
||||
public string DataDirectoryPath
|
||||
{
|
||||
get => _dataDirectoryPath;
|
||||
set
|
||||
{
|
||||
_dataDirectoryPath = value;
|
||||
OnPropertyChanged(nameof(DataDirectoryPath));
|
||||
}
|
||||
}
|
||||
|
||||
public BrowserType BrowserType
|
||||
{
|
||||
get => browserType;
|
||||
set
|
||||
{
|
||||
browserType = value;
|
||||
OnPropertyChanged(nameof(BrowserType));
|
||||
}
|
||||
_name = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public enum BrowserType
|
||||
public string DataDirectoryPath
|
||||
{
|
||||
Chromium,
|
||||
Firefox,
|
||||
get => _dataDirectoryPath;
|
||||
set
|
||||
{
|
||||
_dataDirectoryPath = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public BrowserType BrowserType
|
||||
{
|
||||
get => _browserType;
|
||||
set
|
||||
{
|
||||
_browserType = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum BrowserType
|
||||
{
|
||||
Chromium,
|
||||
Firefox,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<CustomBrowser> CustomChromiumBrowsers { get; set; } = new();
|
||||
}
|
||||
}
|
||||
public ObservableCollection<CustomBrowser> CustomChromiumBrowsers { get; set; } = new();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,7 +63,6 @@
|
|||
<StackPanel Margin="26,0,26,0">
|
||||
<StackPanel Margin="0,0,0,12">
|
||||
<TextBlock
|
||||
Grid.Column="0"
|
||||
Margin="0,0,0,0"
|
||||
FontSize="20"
|
||||
FontWeight="SemiBold"
|
||||
|
|
|
|||
|
|
@ -3,55 +3,54 @@ using System.Windows;
|
|||
using System.Windows.Input;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Flow.Launcher.Plugin.BrowserBookmark.Views
|
||||
namespace Flow.Launcher.Plugin.BrowserBookmark.Views;
|
||||
|
||||
/// <summary>
|
||||
/// Interaction logic for CustomBrowserSetting.xaml
|
||||
/// </summary>
|
||||
public partial class CustomBrowserSettingWindow : Window
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for CustomBrowserSetting.xaml
|
||||
/// </summary>
|
||||
public partial class CustomBrowserSettingWindow : Window
|
||||
private CustomBrowser _currentCustomBrowser;
|
||||
public CustomBrowserSettingWindow(CustomBrowser browser)
|
||||
{
|
||||
private CustomBrowser currentCustomBrowser;
|
||||
public CustomBrowserSettingWindow(CustomBrowser browser)
|
||||
InitializeComponent();
|
||||
_currentCustomBrowser = browser;
|
||||
DataContext = new CustomBrowser
|
||||
{
|
||||
InitializeComponent();
|
||||
currentCustomBrowser = browser;
|
||||
DataContext = new CustomBrowser
|
||||
{
|
||||
Name = browser.Name,
|
||||
DataDirectoryPath = browser.DataDirectoryPath,
|
||||
BrowserType = browser.BrowserType,
|
||||
};
|
||||
}
|
||||
|
||||
private void ConfirmEditCustomBrowser(object sender, RoutedEventArgs e)
|
||||
{
|
||||
CustomBrowser editBrowser = (CustomBrowser)DataContext;
|
||||
currentCustomBrowser.Name = editBrowser.Name;
|
||||
currentCustomBrowser.DataDirectoryPath = editBrowser.DataDirectoryPath;
|
||||
currentCustomBrowser.BrowserType = editBrowser.BrowserType;
|
||||
DialogResult = true;
|
||||
Close();
|
||||
}
|
||||
Name = browser.Name,
|
||||
DataDirectoryPath = browser.DataDirectoryPath,
|
||||
BrowserType = browser.BrowserType,
|
||||
};
|
||||
}
|
||||
|
||||
private void CancelEditCustomBrowser(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
private void ConfirmEditCustomBrowser(object sender, RoutedEventArgs e)
|
||||
{
|
||||
CustomBrowser editBrowser = (CustomBrowser)DataContext;
|
||||
_currentCustomBrowser.Name = editBrowser.Name;
|
||||
_currentCustomBrowser.DataDirectoryPath = editBrowser.DataDirectoryPath;
|
||||
_currentCustomBrowser.BrowserType = editBrowser.BrowserType;
|
||||
DialogResult = true;
|
||||
Close();
|
||||
}
|
||||
|
||||
private void WindowKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
|
||||
{
|
||||
if (e.Key == Key.Enter)
|
||||
{
|
||||
ConfirmEditCustomBrowser(sender, e);
|
||||
}
|
||||
}
|
||||
private void CancelEditCustomBrowser(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
private void OnSelectPathClick(object sender, RoutedEventArgs e)
|
||||
private void WindowKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
|
||||
{
|
||||
if (e.Key == Key.Enter)
|
||||
{
|
||||
var dialog = new FolderBrowserDialog();
|
||||
dialog.ShowDialog();
|
||||
CustomBrowser editBrowser = (CustomBrowser)DataContext;
|
||||
editBrowser.DataDirectoryPath = dialog.SelectedPath;
|
||||
ConfirmEditCustomBrowser(sender, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSelectPathClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var dialog = new FolderBrowserDialog();
|
||||
dialog.ShowDialog();
|
||||
CustomBrowser editBrowser = (CustomBrowser)DataContext;
|
||||
editBrowser.DataDirectoryPath = dialog.SelectedPath;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,119 +4,116 @@ using System.Windows.Input;
|
|||
using System.ComponentModel;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Flow.Launcher.Plugin.BrowserBookmark.Views
|
||||
namespace Flow.Launcher.Plugin.BrowserBookmark.Views;
|
||||
|
||||
public partial class SettingsControl : INotifyPropertyChanged
|
||||
{
|
||||
public partial class SettingsControl : INotifyPropertyChanged
|
||||
public Settings Settings { get; }
|
||||
|
||||
public CustomBrowser SelectedCustomBrowser { get; set; }
|
||||
|
||||
public bool LoadChromeBookmark
|
||||
{
|
||||
public Settings Settings { get; }
|
||||
|
||||
public CustomBrowser SelectedCustomBrowser { get; set; }
|
||||
|
||||
public bool LoadChromeBookmark
|
||||
get => Settings.LoadChromeBookmark;
|
||||
set
|
||||
{
|
||||
get => Settings.LoadChromeBookmark;
|
||||
set
|
||||
Settings.LoadChromeBookmark = value;
|
||||
_ = Task.Run(() => Main.ReloadAllBookmarks());
|
||||
}
|
||||
}
|
||||
|
||||
public bool LoadFirefoxBookmark
|
||||
{
|
||||
get => Settings.LoadFirefoxBookmark;
|
||||
set
|
||||
{
|
||||
Settings.LoadFirefoxBookmark = value;
|
||||
_ = Task.Run(() => Main.ReloadAllBookmarks());
|
||||
}
|
||||
}
|
||||
|
||||
public bool LoadEdgeBookmark
|
||||
{
|
||||
get => Settings.LoadEdgeBookmark;
|
||||
set
|
||||
{
|
||||
Settings.LoadEdgeBookmark = value;
|
||||
_ = Task.Run(() => Main.ReloadAllBookmarks());
|
||||
}
|
||||
}
|
||||
|
||||
public bool OpenInNewBrowserWindow
|
||||
{
|
||||
get => Settings.OpenInNewBrowserWindow;
|
||||
set
|
||||
{
|
||||
Settings.OpenInNewBrowserWindow = value;
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(OpenInNewBrowserWindow)));
|
||||
}
|
||||
}
|
||||
|
||||
public SettingsControl(Settings settings)
|
||||
{
|
||||
Settings = settings;
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
private void NewCustomBrowser(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var newBrowser = new CustomBrowser();
|
||||
var window = new CustomBrowserSettingWindow(newBrowser);
|
||||
window.ShowDialog();
|
||||
if (newBrowser is not
|
||||
{
|
||||
Settings.LoadChromeBookmark = value;
|
||||
_ = Task.Run(() => Main.ReloadAllBookmarks());
|
||||
}
|
||||
}
|
||||
|
||||
public bool LoadFirefoxBookmark
|
||||
Name: null,
|
||||
DataDirectoryPath: null
|
||||
})
|
||||
{
|
||||
get => Settings.LoadFirefoxBookmark;
|
||||
set
|
||||
{
|
||||
Settings.LoadFirefoxBookmark = value;
|
||||
_ = Task.Run(() => Main.ReloadAllBookmarks());
|
||||
}
|
||||
Settings.CustomChromiumBrowsers.Add(newBrowser);
|
||||
_ = Task.Run(() => Main.ReloadAllBookmarks());
|
||||
}
|
||||
}
|
||||
|
||||
public bool LoadEdgeBookmark
|
||||
private void DeleteCustomBrowser(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (CustomBrowsers.SelectedItem is CustomBrowser selectedCustomBrowser)
|
||||
{
|
||||
get => Settings.LoadEdgeBookmark;
|
||||
set
|
||||
{
|
||||
Settings.LoadEdgeBookmark = value;
|
||||
_ = Task.Run(() => Main.ReloadAllBookmarks());
|
||||
}
|
||||
Settings.CustomChromiumBrowsers.Remove(selectedCustomBrowser);
|
||||
_ = Task.Run(() => Main.ReloadAllBookmarks());
|
||||
}
|
||||
}
|
||||
|
||||
public bool OpenInNewBrowserWindow
|
||||
private void MouseDoubleClickOnSelectedCustomBrowser(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
EditSelectedCustomBrowser();
|
||||
}
|
||||
|
||||
private void Others_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
CustomBrowsersList.Visibility = CustomBrowsersList.Visibility switch
|
||||
{
|
||||
get => Settings.OpenInNewBrowserWindow;
|
||||
set
|
||||
{
|
||||
Settings.OpenInNewBrowserWindow = value;
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(OpenInNewBrowserWindow)));
|
||||
}
|
||||
}
|
||||
Visibility.Collapsed => Visibility.Visible,
|
||||
_ => Visibility.Collapsed
|
||||
};
|
||||
}
|
||||
|
||||
public SettingsControl(Settings settings)
|
||||
private void EditCustomBrowser(object sender, RoutedEventArgs e)
|
||||
{
|
||||
EditSelectedCustomBrowser();
|
||||
}
|
||||
|
||||
private void EditSelectedCustomBrowser()
|
||||
{
|
||||
if (SelectedCustomBrowser is null)
|
||||
return;
|
||||
|
||||
var window = new CustomBrowserSettingWindow(SelectedCustomBrowser);
|
||||
var result = window.ShowDialog() ?? false;
|
||||
if (result)
|
||||
{
|
||||
Settings = settings;
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
private void NewCustomBrowser(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var newBrowser = new CustomBrowser();
|
||||
var window = new CustomBrowserSettingWindow(newBrowser);
|
||||
window.ShowDialog();
|
||||
if (newBrowser is not
|
||||
{
|
||||
Name: null,
|
||||
DataDirectoryPath: null
|
||||
})
|
||||
{
|
||||
Settings.CustomChromiumBrowsers.Add(newBrowser);
|
||||
_ = Task.Run(() => Main.ReloadAllBookmarks());
|
||||
}
|
||||
}
|
||||
|
||||
private void DeleteCustomBrowser(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (CustomBrowsers.SelectedItem is CustomBrowser selectedCustomBrowser)
|
||||
{
|
||||
Settings.CustomChromiumBrowsers.Remove(selectedCustomBrowser);
|
||||
_ = Task.Run(() => Main.ReloadAllBookmarks());
|
||||
}
|
||||
}
|
||||
|
||||
private void MouseDoubleClickOnSelectedCustomBrowser(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
EditSelectedCustomBrowser();
|
||||
}
|
||||
|
||||
private void Others_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
|
||||
if (CustomBrowsersList.Visibility == Visibility.Collapsed)
|
||||
{
|
||||
CustomBrowsersList.Visibility = Visibility.Visible;
|
||||
}
|
||||
else
|
||||
CustomBrowsersList.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
|
||||
private void EditCustomBrowser(object sender, RoutedEventArgs e)
|
||||
{
|
||||
EditSelectedCustomBrowser();
|
||||
}
|
||||
|
||||
private void EditSelectedCustomBrowser()
|
||||
{
|
||||
if (SelectedCustomBrowser is null)
|
||||
return;
|
||||
|
||||
var window = new CustomBrowserSettingWindow(SelectedCustomBrowser);
|
||||
var result = window.ShowDialog() ?? false;
|
||||
if (result)
|
||||
{
|
||||
_ = Task.Run(() => Main.ReloadAllBookmarks());
|
||||
}
|
||||
_ = Task.Run(() => Main.ReloadAllBookmarks());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue