Merge pull request #695 from Flow-Launcher/BrowserBookmarkRefactor

Refactor Bookmark plugin
This commit is contained in:
Jeremy Wu 2021-10-12 08:43:13 +11:00 committed by GitHub
commit 8a33bf4a33
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 455 additions and 313 deletions

View file

@ -1,56 +0,0 @@
using BinaryAnalysis.UnidecodeSharp;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Flow.Launcher.Plugin.BrowserBookmark
{
public class Bookmark : IEquatable<Bookmark>, IEqualityComparer<Bookmark>
{
private string m_Name;
public string Name
{
get
{
return m_Name;
}
set
{
m_Name = value;
}
}
public string Url { get; set; }
public string Source { get; set; }
public int Score { get; set; }
/* TODO: since Source maybe unimportant, we just need to compare Name and Url */
public bool Equals(Bookmark other)
{
return Equals(this, other);
}
public bool Equals(Bookmark x, Bookmark y)
{
if (Object.ReferenceEquals(x, y)) return true;
if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
return false;
return x.Name == y.Name && x.Url == y.Url;
}
public int GetHashCode(Bookmark bookmark)
{
if (Object.ReferenceEquals(bookmark, null)) return 0;
int hashName = bookmark.Name == null ? 0 : bookmark.Name.GetHashCode();
int hashUrl = bookmark.Url == null ? 0 : bookmark.Url.GetHashCode();
return hashName ^ hashUrl;
}
public override int GetHashCode()
{
return GetHashCode(this);
}
}
}

View file

@ -0,0 +1,27 @@
using Flow.Launcher.Plugin.BrowserBookmark.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
namespace Flow.Launcher.Plugin.BrowserBookmark
{
public class ChromeBookmarkLoader : ChromiumBookmarkLoader
{
public override List<Bookmark> GetBookmarks()
{
return LoadChromeBookmarks();
}
private List<Bookmark> LoadChromeBookmarks()
{
var bookmarks = new List<Bookmark>();
String 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;
}
}
}

View file

@ -1,87 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
namespace Flow.Launcher.Plugin.BrowserBookmark
{
public class ChromeBookmarks
{
private List<Bookmark> bookmarks = new List<Bookmark>();
public List<Bookmark> GetBookmarks()
{
bookmarks.Clear();
LoadChromeBookmarks();
return bookmarks;
}
private void ParseChromeBookmarks(String path, string source)
{
if (!File.Exists(path)) return;
string all = File.ReadAllText(path);
Regex nameRegex = new Regex("\"name\": \"(?<name>.*?)\"");
MatchCollection nameCollection = nameRegex.Matches(all);
Regex typeRegex = new Regex("\"type\": \"(?<type>.*?)\"");
MatchCollection typeCollection = typeRegex.Matches(all);
Regex urlRegex = new Regex("\"url\": \"(?<url>.*?)\"");
MatchCollection urlCollection = urlRegex.Matches(all);
List<string> names = (from Match match in nameCollection select match.Groups["name"].Value).ToList();
List<string> types = (from Match match in typeCollection select match.Groups["type"].Value).ToList();
List<string> urls = (from Match match in urlCollection select match.Groups["url"].Value).ToList();
int urlIndex = 0;
for (int i = 0; i < names.Count; i++)
{
string name = DecodeUnicode(names[i]);
string type = types[i];
if (type == "url")
{
string url = urls[urlIndex];
urlIndex++;
if (url == null) continue;
if (url.StartsWith("javascript:", StringComparison.OrdinalIgnoreCase)) continue;
if (url.StartsWith("vbscript:", StringComparison.OrdinalIgnoreCase)) continue;
bookmarks.Add(new Bookmark()
{
Name = name,
Url = url,
Source = source
});
}
}
}
private void LoadChromeBookmarks(string path, string name)
{
if (!Directory.Exists(path)) return;
var paths = Directory.GetDirectories(path);
foreach (var profile in paths)
{
if (File.Exists(Path.Combine(profile, "Bookmarks")))
ParseChromeBookmarks(Path.Combine(profile, "Bookmarks"), name + (Path.GetFileName(profile) == "Default" ? "" : (" (" + Path.GetFileName(profile) + ")")));
}
}
private void LoadChromeBookmarks()
{
String platformPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
LoadChromeBookmarks(Path.Combine(platformPath, @"Google\Chrome\User Data"), "Google Chrome");
LoadChromeBookmarks(Path.Combine(platformPath, @"Google\Chrome SxS\User Data"), "Google Chrome Canary");
LoadChromeBookmarks(Path.Combine(platformPath, @"Chromium\User Data"), "Chromium");
}
private String DecodeUnicode(String dataStr)
{
Regex reg = new Regex(@"(?i)\\[uU]([0-9a-f]{4})");
return reg.Replace(dataStr, m => ((char)Convert.ToInt32(m.Groups[1].Value, 16)).ToString());
}
}
}

View file

@ -0,0 +1,65 @@
using Flow.Launcher.Plugin.BrowserBookmark.Models;
using Microsoft.AspNetCore.Authentication;
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
namespace Flow.Launcher.Plugin.BrowserBookmark
{
public abstract class ChromiumBookmarkLoader : IBookmarkLoader
{
public abstract List<Bookmark> GetBookmarks();
protected List<Bookmark> LoadBookmarks(string browserDataPath, string name)
{
var bookmarks = new List<Bookmark>();
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;
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)
{
if (!File.Exists(path))
return new();
var bookmarks = new List<Bookmark>();
using var jsonDocument = JsonDocument.Parse(File.ReadAllText(path));
if (!jsonDocument.RootElement.TryGetProperty("roots", out var rootElement))
return new();
foreach (var folder in rootElement.EnumerateObject())
{
EnumerateFolderBookmark(folder.Value, bookmarks, source);
}
return bookmarks;
}
private void EnumerateFolderBookmark(JsonElement folderElement, List<Bookmark> bookmarks, string source)
{
foreach (var subElement in folderElement.GetProperty("children").EnumerateArray())
{
switch (subElement.GetProperty("type").GetString())
{
case "folder":
EnumerateFolderBookmark(subElement, bookmarks, source);
break;
default:
bookmarks.Add(new Bookmark(
subElement.GetProperty("name").GetString(),
subElement.GetProperty("url").GetString(),
source));
break;
}
}
}
}
}

View file

@ -0,0 +1,47 @@
using System.Collections.Generic;
using System.Linq;
using Flow.Launcher.Infrastructure;
using Flow.Launcher.Plugin.BrowserBookmark.Models;
using Flow.Launcher.Plugin.SharedModels;
namespace Flow.Launcher.Plugin.BrowserBookmark.Commands
{
internal static class BookmarkLoader
{
internal static MatchResult MatchProgram(Bookmark bookmark, string queryString)
{
var match = StringMatcher.FuzzySearch(queryString, bookmark.Name);
if (match.IsSearchPrecisionScoreMet())
return match;
return StringMatcher.FuzzySearch(queryString, bookmark.Url);
}
internal static List<Bookmark> LoadAllBookmarks(Settings setting)
{
var chromeBookmarks = new ChromeBookmarkLoader();
var mozBookmarks = new FirefoxBookmarkLoader();
var edgeBookmarks = new EdgeBookmarkLoader();
var allBookmarks = new List<Bookmark>();
// Add Firefox bookmarks
allBookmarks.AddRange(mozBookmarks.GetBookmarks());
// Add Chrome bookmarks
allBookmarks.AddRange(chromeBookmarks.GetBookmarks());
// Add Edge (Chromium) bookmarks
allBookmarks.AddRange(edgeBookmarks.GetBookmarks());
foreach (var browser in setting.CustomChromiumBrowsers)
{
var loader = new CustomChromiumBookmarkLoader(browser);
allBookmarks.AddRange(loader.GetBookmarks());
}
return allBookmarks.Distinct().ToList();
}
}
}

View file

@ -1,40 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using Flow.Launcher.Infrastructure;
using Flow.Launcher.Plugin.SharedModels;
namespace Flow.Launcher.Plugin.BrowserBookmark.Commands
{
internal static class Bookmarks
{
internal static MatchResult MatchProgram(Bookmark bookmark, string queryString)
{
var match = StringMatcher.FuzzySearch(queryString, bookmark.Name);
if (match.IsSearchPrecisionScoreMet())
return match;
return StringMatcher.FuzzySearch(queryString, bookmark.Url);
}
internal static List<Bookmark> LoadAllBookmarks()
{
var allbookmarks = new List<Bookmark>();
var chromeBookmarks = new ChromeBookmarks();
var mozBookmarks = new FirefoxBookmarks();
var edgeBookmarks = new EdgeBookmarks();
//TODO: Let the user select which browser's bookmarks are displayed
// Add Firefox bookmarks
mozBookmarks.GetBookmarks().ForEach(x => allbookmarks.Add(x));
// Add Chrome bookmarks
chromeBookmarks.GetBookmarks().ForEach(x => allbookmarks.Add(x));
// Add Edge (Chromium) bookmarks
edgeBookmarks.GetBookmarks().ForEach(x => allbookmarks.Add(x));
return allbookmarks.Distinct().ToList();
}
}
}

View file

@ -0,0 +1,19 @@
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; }
public override List<Bookmark> GetBookmarks() => BrowserDataPath != null ? LoadBookmarks(BrowserDataPath, BrowserName) : LoadBookmarksFromFile(BookmarkFilePath, BrowserName);
}
}

View file

@ -0,0 +1,31 @@
using Flow.Launcher.Plugin.BrowserBookmark.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.Json;
using System.Text.RegularExpressions;
namespace Flow.Launcher.Plugin.BrowserBookmark
{
public class EdgeBookmarkLoader : ChromiumBookmarkLoader
{
private readonly List<Bookmark> _bookmarks = new();
private void LoadEdgeBookmarks()
{
var platformPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
LoadBookmarks(Path.Combine(platformPath, @"Microsoft\Edge\User Data"), "Microsoft Edge");
LoadBookmarks(Path.Combine(platformPath, @"Microsoft\Edge Dev\User Data"), "Microsoft Edge Dev");
LoadBookmarks(Path.Combine(platformPath, @"Microsoft\Edge SxS\User Data"), "Microsoft Edge Canary");
}
public override List<Bookmark> GetBookmarks()
{
_bookmarks.Clear();
LoadEdgeBookmarks();
return _bookmarks;
}
}
}

View file

@ -1,87 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
namespace Flow.Launcher.Plugin.BrowserBookmark
{
public class EdgeBookmarks
{
private List<Bookmark> bookmarks = new List<Bookmark>();
public List<Bookmark> GetBookmarks()
{
bookmarks.Clear();
LoadEdgeBookmarks();
return bookmarks;
}
private void ParseEdgeBookmarks(string path, string source)
{
if (!File.Exists(path)) return;
string all = File.ReadAllText(path);
Regex nameRegex = new Regex("\"name\": \"(?<name>.*?)\"");
MatchCollection nameCollection = nameRegex.Matches(all);
Regex typeRegex = new Regex("\"type\": \"(?<type>.*?)\"");
MatchCollection typeCollection = typeRegex.Matches(all);
Regex urlRegex = new Regex("\"url\": \"(?<url>.*?)\"");
MatchCollection urlCollection = urlRegex.Matches(all);
List<string> names = (from Match match in nameCollection select match.Groups["name"].Value).ToList();
List<string> types = (from Match match in typeCollection select match.Groups["type"].Value).ToList();
List<string> urls = (from Match match in urlCollection select match.Groups["url"].Value).ToList();
int urlIndex = 0;
for (int i = 0; i < names.Count; i++)
{
string name = DecodeUnicode(names[i]);
string type = types[i];
if (type == "url")
{
string url = urls[urlIndex];
urlIndex++;
if (url == null) continue;
if (url.StartsWith("javascript:", StringComparison.OrdinalIgnoreCase)) continue;
if (url.StartsWith("vbscript:", StringComparison.OrdinalIgnoreCase)) continue;
bookmarks.Add(new Bookmark()
{
Name = name,
Url = url,
Source = source
});
}
}
}
private void LoadEdgeBookmarks(string path, string name)
{
if (!Directory.Exists(path)) return;
var paths = Directory.GetDirectories(path);
foreach (var profile in paths)
{
if (File.Exists(Path.Combine(profile, "Bookmarks")))
ParseEdgeBookmarks(Path.Combine(profile, "Bookmarks"), name + (Path.GetFileName(profile) == "Default" ? "" : (" (" + Path.GetFileName(profile) + ")")));
}
}
private void LoadEdgeBookmarks()
{
string platformPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
LoadEdgeBookmarks(Path.Combine(platformPath, @"Microsoft\Edge\User Data"), "Microsoft Edge");
LoadEdgeBookmarks(Path.Combine(platformPath, @"Microsoft\Edge Dev\User Data"), "Microsoft Edge Dev");
LoadEdgeBookmarks(Path.Combine(platformPath, @"Microsoft\Edge SxS\User Data"), "Microsoft Edge Canary");
}
private string DecodeUnicode(string dataStr)
{
Regex reg = new Regex(@"(?i)\\[uU]([0-9a-f]{4})");
return reg.Replace(dataStr, m => ((char)Convert.ToInt32(m.Groups[1].Value, 16)).ToString());
}
}
}

View file

@ -1,3 +1,4 @@
using Flow.Launcher.Plugin.BrowserBookmark.Models;
using System;
using System.Collections.Generic;
using System.Data.SQLite;
@ -6,7 +7,7 @@ using System.Linq;
namespace Flow.Launcher.Plugin.BrowserBookmark
{
public class FirefoxBookmarks
public class FirefoxBookmarkLoader : IBookmarkLoader
{
private const string queryAllBookmarks = @"SELECT moz_places.url, moz_bookmarks.title
FROM moz_places
@ -27,10 +28,10 @@ namespace Flow.Launcher.Plugin.BrowserBookmark
if (string.IsNullOrEmpty(PlacesPath) || !File.Exists(PlacesPath))
return new List<Bookmark>();
var bookmarList = new List<Bookmark>();
var bookmarkList = new List<Bookmark>();
// create the connection string and init the connection
string dbPath = string.Format(dbPathFormat, PlacesPath);
string dbPath = string.Format(dbPathFormat, PlacesPath);
using (var dbConnection = new SQLiteConnection(dbPath))
{
// Open connection to the database file and execute the query
@ -38,14 +39,13 @@ namespace Flow.Launcher.Plugin.BrowserBookmark
var reader = new SQLiteCommand(queryAllBookmarks, dbConnection).ExecuteReader();
// return results in List<Bookmark> format
bookmarList = reader.Select(x => new Bookmark()
{
Name = (x["title"] is DBNull) ? string.Empty : x["title"].ToString(),
Url = x["url"].ToString()
}).ToList();
bookmarkList = reader.Select(
x => new Bookmark(x["title"] is DBNull ? string.Empty : x["title"].ToString(),
x["url"].ToString())
).ToList();
}
return bookmarList;
return bookmarkList;
}
/// <summary>
@ -63,7 +63,8 @@ namespace Flow.Launcher.Plugin.BrowserBookmark
// get firefox default profile directory from profiles.ini
string ini;
using (var sReader = new StreamReader(profileIni)) {
using (var sReader = new StreamReader(profileIni))
{
ini = sReader.ReadToEnd();
}
@ -95,7 +96,10 @@ namespace Flow.Launcher.Plugin.BrowserBookmark
Version=2
*/
var lines = ini.Split(new string[] { "\r\n" }, StringSplitOptions.None).ToList();
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;
@ -104,14 +108,14 @@ namespace Flow.Launcher.Plugin.BrowserBookmark
var defaultProfileFolderName = defaultProfileFolderNameRaw.Split('=').Last();
var indexOfDefaultProfileAtttributePath = lines.IndexOf("Path="+ defaultProfileFolderName);
var indexOfDefaultProfileAtttributePath = lines.IndexOf("Path=" + defaultProfileFolderName);
// Seen in the example above, the IsRelative attribute is always above the Path attribute
var relativeAttribute = lines[indexOfDefaultProfileAtttributePath - 1];
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";
? defaultProfileFolderName + @"\places.sqlite"
: Path.Combine(profileFolderPath, defaultProfileFolderName) + @"\places.sqlite";
}
}
}
@ -126,4 +130,4 @@ namespace Flow.Launcher.Plugin.BrowserBookmark
}
}
}
}
}

View file

@ -69,4 +69,8 @@
<PackageReference Include="UnidecodeSharp" Version="1.0.0" />
</ItemGroup>
<ItemGroup>
<Compile Remove="Bookmark.cs" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,10 @@
using Flow.Launcher.Plugin.BrowserBookmark.Models;
using System.Collections.Generic;
namespace Flow.Launcher.Plugin.BrowserBookmark
{
public interface IBookmarkLoader
{
public List<Bookmark> GetBookmarks();
}
}

View file

@ -14,4 +14,9 @@
<system:String x:Key="flowlauncher_plugin_browserbookmark_settings_choose">Choose</system:String>
<system:String x:Key="flowlauncher_plugin_browserbookmark_copyurl_title">Copy url</system:String>
<system:String x:Key="flowlauncher_plugin_browserbookmark_copyurl_subtitle">Copy the bookmark's url to clipboard</system:String>
<system:String x:Key="flowlauncher_plugin_browserbookmark_loadBrowserFrom">Load Browser From:</system:String>
<system:String x:Key="flowlauncher_plugin_browserbookmark_browserName">Browser Name</system:String>
<system:String x:Key="flowlauncher_plugin_browserbookmark_browserBookmarkDataDirectory">DataDirectoryPath</system:String>
<system:String x:Key="flowlauncher_plugin_browserbookmark_addBrowserBookmark">Add Custom Browser Bookmark</system:String>
<system:String x:Key="flowlauncher_plugin_browserbookmark_removeBrowserBookmark">Delete Custom Browser Bookmark</system:String>
</ResourceDictionary>

View file

@ -26,7 +26,7 @@ namespace Flow.Launcher.Plugin.BrowserBookmark
_settings = context.API.LoadSettingJsonStorage<Settings>();
cachedBookmarks = Bookmarks.LoadAllBookmarks();
cachedBookmarks = BookmarkLoader.LoadAllBookmarks(_settings);
}
public List<Result> Query(Query query)
@ -45,7 +45,7 @@ namespace Flow.Launcher.Plugin.BrowserBookmark
Title = c.Name,
SubTitle = c.Url,
IcoPath = @"Images\bookmark.png",
Score = Bookmarks.MatchProgram(c, param).Score,
Score = BookmarkLoader.MatchProgram(c, param).Score,
Action = _ =>
{
if (_settings.OpenInNewBrowserWindow)
@ -93,7 +93,7 @@ namespace Flow.Launcher.Plugin.BrowserBookmark
{
cachedBookmarks.Clear();
cachedBookmarks = Bookmarks.LoadAllBookmarks();
cachedBookmarks = BookmarkLoader.LoadAllBookmarks(_settings);
}
public string GetTranslatedPluginTitle()

View file

@ -0,0 +1,22 @@
using System.Collections.Generic;
namespace Flow.Launcher.Plugin.BrowserBookmark.Models
{
// Source may be important in the future
public record Bookmark(string Name, string Url, string Source = "")
{
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();
}
}

View file

@ -0,0 +1,26 @@
namespace Flow.Launcher.Plugin.BrowserBookmark.Models
{
public class CustomBrowser : BaseModel
{
private string _name;
private string _dataDirectoryPath;
public string Name
{
get => _name;
set
{
_name = value;
OnPropertyChanged(nameof(Name));
}
}
public string DataDirectoryPath
{
get => _dataDirectoryPath;
set
{
_dataDirectoryPath = value;
OnPropertyChanged(nameof(DataDirectoryPath));
}
}
}
}

View file

@ -1,9 +1,15 @@
namespace Flow.Launcher.Plugin.BrowserBookmark.Models
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text.Json.Serialization;
namespace Flow.Launcher.Plugin.BrowserBookmark.Models
{
public class Settings : BaseModel
{
public bool OpenInNewBrowserWindow { get; set; } = true;
public string BrowserPath { get; set; }
public ObservableCollection<CustomBrowser> CustomChromiumBrowsers { get; set; } = new();
}
}

View file

@ -0,0 +1,37 @@
<Window x:Class="Flow.Launcher.Plugin.BrowserBookmark.Views.CustomBrowserSettingWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Flow.Launcher.Plugin.BrowserBookmark.Models"
mc:Ignorable="d"
Title="CustomBrowserSetting" Height="450" Width="600"
KeyDown="WindowKeyDown"
>
<Window.DataContext>
<local:CustomBrowser/>
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="4*"/>
<ColumnDefinition Width="6*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="Browser Name" FontSize="15"
HorizontalAlignment="Left" VerticalAlignment="Center"/>
<TextBlock Grid.Row="1" Grid.Column="0" Text="Browser Data Directory Path" FontSize="15"
HorizontalAlignment="Left" VerticalAlignment="Center"/>
<TextBox Grid.Row="0" Grid.Column="1" Text="{Binding Name}"
HorizontalAlignment="Left" VerticalAlignment="Center" Width="100" Height="30"/>
<TextBox Grid.Row="1" Grid.Column="1" Text="{Binding DataDirectoryPath}"
HorizontalAlignment="Left" VerticalAlignment="Center" Width="200" Height="30"/>
<StackPanel HorizontalAlignment="Right" Grid.Row="2" Orientation="Horizontal" Grid.Column="1" Height="60">
<Button Content="Confirm" Margin="15" Click="ConfirmEditCustomBrowser"/>
<Button Content="Cancel" Margin="15"/>
</StackPanel>
</Grid>
</Window>

View file

@ -0,0 +1,51 @@
using Flow.Launcher.Plugin.BrowserBookmark.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace Flow.Launcher.Plugin.BrowserBookmark.Views
{
/// <summary>
/// Interaction logic for CustomBrowserSetting.xaml
/// </summary>
public partial class CustomBrowserSettingWindow : Window
{
private CustomBrowser currentCustomBrowser;
public CustomBrowserSettingWindow(CustomBrowser browser)
{
InitializeComponent();
currentCustomBrowser = browser;
DataContext = new CustomBrowser
{
Name = browser.Name, DataDirectoryPath = browser.DataDirectoryPath
};
}
private void ConfirmEditCustomBrowser(object sender, RoutedEventArgs e)
{
if (DataContext is CustomBrowser editedBrowser)
{
currentCustomBrowser.Name = editedBrowser.Name;
currentCustomBrowser.DataDirectoryPath = editedBrowser.DataDirectoryPath;
}
Close();
}
private void WindowKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
ConfirmEditCustomBrowser(sender, e);
}
}
}
}

View file

@ -5,21 +5,23 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
Background="White"
d:DesignHeight="300" d:DesignWidth="500">
<Grid>
d:DesignHeight="300" d:DesignWidth="500"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="90" />
<RowDefinition />
<RowDefinition Height="50" />
<RowDefinition Height="80"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<StackPanel>
<Grid Grid.Row="0" Margin="40 40 0 0">
<Grid Grid.Row="0" Margin="30 20 0 0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="160" />
<ColumnDefinition Width="140"/>
<ColumnDefinition Width="100"/>
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Content="{DynamicResource flowlauncher_plugin_browserbookmark_settings_openBookmarks}"
FontSize="15" Margin="0 5 0 0"/>
FontSize="15" Margin="10 5 0 0"/>
<RadioButton Grid.Column="1" Name="NewWindowBrowser" GroupName="OpenSearchBehaviour"
Content="{DynamicResource flowlauncher_plugin_browserbookmark_settings_newWindow}"
Click="OnNewBrowserWindowClick" />
@ -28,12 +30,42 @@
Click="OnNewTabClick" />
</Grid>
</StackPanel>
<StackPanel VerticalAlignment="Top" Grid.Row="1" Height="106" Margin="41,13,0,0">
<StackPanel Orientation="Horizontal" VerticalAlignment="Top" Grid.Row="1" Height="60" Margin="30,20,0,0">
<Label Content="{DynamicResource flowlauncher_plugin_browserbookmark_settings_setBrowserFromPath}"
Height="28" Margin="0,0,155,0" HorizontalAlignment="Left" Width="290"/>
<TextBox x:Name="browserPathBox" HorizontalAlignment="Left" Height="34" TextWrapping="NoWrap" VerticalAlignment="Top" Width="311" RenderTransformOrigin="0.502,-1.668" TextChanged="OnBrowserPathTextChanged" />
<Button x:Name="viewButton" Content="{DynamicResource flowlauncher_plugin_browserbookmark_settings_choose}"
HorizontalAlignment="Left" Margin="340,-35,-1,0" Width="100" Height="34" Click="OnChooseClick" FontSize="14" />
Height="28" Margin="10"/>
<TextBox x:Name="BrowserPathBox"
HorizontalAlignment="Left"
Height="30"
TextWrapping="NoWrap"
VerticalAlignment="Center"
Text="{Binding Settings.BrowserPath}"
Width="240"
Margin="10"/>
<Button x:Name="ViewButton" Content="{DynamicResource flowlauncher_plugin_browserbookmark_settings_choose}"
HorizontalAlignment="Left" Margin="10" Width="100" Height="30" Click="OnChooseClick" FontSize="14" />
</StackPanel>
<StackPanel Grid.Row="2" Orientation="Vertical" Margin="30,20,0,0">
<TextBlock Text="{DynamicResource flowlauncher_plugin_browserbookmark_loadBrowserFrom}" Margin="10"/>
<ListView Grid.Row="2" ItemsSource="{Binding Settings.CustomChromiumBrowsers}"
SelectedItem="{Binding SelectedCustomBrowser}"
Margin="10"
BorderBrush="DarkGray"
BorderThickness="1"
Style="{StaticResource {x:Static GridView.GridViewStyleKey}}"
Height="auto"
Name="CustomBrowsers"
MouseDoubleClick="MouseDoubleClickOnSelectedCustomBrowser">
<ListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="{Binding Name, Mode=OneWay}" Header="{DynamicResource flowlauncher_plugin_browserbookmark_browserName}"/>
<GridViewColumn DisplayMemberBinding="{Binding DataDirectoryPath, Mode=OneWay}" Header="{DynamicResource flowlauncher_plugin_browserbookmark_browserBookmarkDataDirectory}"/>
</GridView>
</ListView.View>
</ListView>
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal">
<Button Content="{DynamicResource flowlauncher_plugin_browserbookmark_addBrowserBookmark}" Margin="10" Click="NewCustomBrowser"/>
<Button Content="{DynamicResource flowlauncher_plugin_browserbookmark_removeBrowserBookmark}" Margin="10" Click="DeleteCustomBrowser"/>
</StackPanel>
</StackPanel>
</Grid>
</UserControl>

View file

@ -2,33 +2,34 @@ using Microsoft.Win32;
using System.Windows;
using System.Windows.Controls;
using Flow.Launcher.Plugin.BrowserBookmark.Models;
using System.Windows.Input;
namespace Flow.Launcher.Plugin.BrowserBookmark.Views
{
/// <summary>
/// Interaction logic for BrowserBookmark.xaml
/// </summary>
public partial class SettingsControl : UserControl
public partial class SettingsControl
{
private readonly Settings _settings;
public Settings Settings { get; }
public CustomBrowser SelectedCustomBrowser { get; set; }
public SettingsControl(Settings settings)
{
Settings = settings;
InitializeComponent();
_settings = settings;
browserPathBox.Text = _settings.BrowserPath;
NewWindowBrowser.IsChecked = _settings.OpenInNewBrowserWindow;
NewTabInBrowser.IsChecked = !_settings.OpenInNewBrowserWindow;
NewWindowBrowser.IsChecked = Settings.OpenInNewBrowserWindow;
NewTabInBrowser.IsChecked = !Settings.OpenInNewBrowserWindow;
}
private void OnNewBrowserWindowClick(object sender, RoutedEventArgs e)
{
_settings.OpenInNewBrowserWindow = true;
Settings.OpenInNewBrowserWindow = true;
}
private void OnNewTabClick(object sender, RoutedEventArgs e)
{
_settings.OpenInNewBrowserWindow = false;
Settings.OpenInNewBrowserWindow = false;
}
private void OnChooseClick(object sender, RoutedEventArgs e)
@ -39,14 +40,39 @@ namespace Flow.Launcher.Plugin.BrowserBookmark.Views
fileBrowserDialog.CheckPathExists = true;
if (fileBrowserDialog.ShowDialog() == true)
{
browserPathBox.Text = fileBrowserDialog.FileName;
_settings.BrowserPath = fileBrowserDialog.FileName;
Settings.BrowserPath = fileBrowserDialog.FileName;
}
}
private void OnBrowserPathTextChanged(object sender, TextChangedEventArgs e)
private void NewCustomBrowser(object sender, RoutedEventArgs e)
{
_settings.BrowserPath = browserPathBox.Text;
var newBrowser = new CustomBrowser();
var window = new CustomBrowserSettingWindow(newBrowser);
window.ShowDialog();
if (newBrowser is not
{
Name: null,
DataDirectoryPath: null
})
{
Settings.CustomChromiumBrowsers.Add(newBrowser);
}
}
private void DeleteCustomBrowser(object sender, RoutedEventArgs e)
{
if(CustomBrowsers.SelectedItem is CustomBrowser selectedCustomBrowser)
{
Settings.CustomChromiumBrowsers.Remove(selectedCustomBrowser);
}
}
private void MouseDoubleClickOnSelectedCustomBrowser(object sender, MouseButtonEventArgs e)
{
if (SelectedCustomBrowser is null)
return;
var window = new CustomBrowserSettingWindow(SelectedCustomBrowser);
window.ShowDialog();
}
}
}

View file

@ -4,7 +4,7 @@
"Name": "Browser Bookmarks",
"Description": "Search your browser bookmarks",
"Author": "qianlifeng, Ioannis G.",
"Version": "1.4.4",
"Version": "1.5.0",
"Language": "csharp",
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
"ExecuteFileName": "Flow.Launcher.Plugin.BrowserBookmark.dll",