Skip to content

Commit eb261f5

Browse files
authored
Merge pull request #3944 from Flow-Launcher/url_open_enhancement
Enhancement: Support Custom Browser Path & Open in window / tab & In private for URL Plugin
2 parents 01bbb54 + ec41ec2 commit eb261f5

File tree

7 files changed

+287
-27
lines changed

7 files changed

+287
-27
lines changed
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
using System;
2+
using System.Globalization;
3+
using System.Windows;
4+
using System.Windows.Data;
5+
6+
namespace Flow.Launcher.Plugin.Url.Converters;
7+
8+
[ValueConversion(typeof(bool), typeof(Visibility))]
9+
public class BoolToVisibilityConverter : IValueConverter
10+
{
11+
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
12+
{
13+
if (value is not bool)
14+
throw new ArgumentException("value should be boolean", nameof(value));
15+
16+
return (bool)value ? Visibility.Visible : Visibility.Collapsed;
17+
}
18+
19+
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
20+
{
21+
throw new InvalidOperationException();
22+
}
23+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
using System;
2+
using System.Globalization;
3+
using System.Windows.Data;
4+
5+
namespace Flow.Launcher.Plugin.Url.Converters;
6+
7+
[ValueConversion(typeof(bool), typeof(bool))]
8+
public class InverseBoolConverter : IValueConverter
9+
{
10+
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
11+
{
12+
if (value is not bool)
13+
throw new ArgumentException("value should be boolean", nameof(value));
14+
15+
return !(bool)value;
16+
}
17+
18+
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
19+
{
20+
if (value is not bool)
21+
throw new ArgumentException("value should be boolean", nameof(value));
22+
23+
return !(bool)value;
24+
}
25+
}
Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,22 @@
1-
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
2-
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
3-
xmlns:system="clr-namespace:System;assembly=mscorlib">
1+
<ResourceDictionary
2+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4+
xmlns:system="clr-namespace:System;assembly=mscorlib">
45

5-
<system:String x:Key="flowlauncher_plugin_url_open_search_in">Open search in:</system:String>
6-
<system:String x:Key="flowlauncher_plugin_new_window">New Window</system:String>
7-
<system:String x:Key="flowlauncher_plugin_new_tab">New Tab</system:String>
8-
96
<system:String x:Key="flowlauncher_plugin_url_open_url">Open url:{0}</system:String>
107
<system:String x:Key="flowlauncher_plugin_url_cannot_open_url">Can't open url:{0}</system:String>
118

129
<system:String x:Key="flowlauncher_plugin_url_plugin_name">URL</system:String>
1310
<system:String x:Key="flowlauncher_plugin_url_plugin_description">Open the typed URL from Flow Launcher</system:String>
1411

15-
<system:String x:Key="flowlauncher_plugin_url_plugin_set_tip">Please set your browser path:</system:String>
1612
<system:String x:Key="flowlauncher_plugin_url_plugin_choose">Choose</system:String>
1713
<system:String x:Key="flowlauncher_plugin_url_plugin_filter">Application(*.exe)|*.exe|All files|*.*</system:String>
14+
15+
<system:String x:Key="flowlauncher_plugin_url_use_custom_browser">Use custom instead of Flow's default web browser</system:String>
16+
<system:String x:Key="flowlauncher_plugin_url_browser_path">Browser path</system:String>
17+
18+
<system:String x:Key="flowlauncher_plugin_url_new_tab">New tab</system:String>
19+
<system:String x:Key="flowlauncher_plugin_url_new_window">New window</system:String>
20+
21+
<system:String x:Key="flowlauncher_plugin_url_private_mode">Private mode</system:String>
1822
</ResourceDictionary>

Plugins/Flow.Launcher.Plugin.Url/Main.cs

Lines changed: 38 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Text.RegularExpressions;
4+
using System.Windows.Controls;
5+
using Flow.Launcher.Plugin.SharedCommands;
46

57
namespace Flow.Launcher.Plugin.Url
68
{
7-
public class Main : IPlugin, IPluginI18n
9+
public class Main : IPlugin, IPluginI18n, ISettingProvider
810
{
911
//based on https://gist.github.com/dperini/729294
10-
private const string urlPattern = "^" +
12+
private const string UrlPattern = "^" +
1113
// protocol identifier
1214
"(?:(?:https?|ftp)://|)" +
1315
// user:pass authentication
@@ -39,33 +41,47 @@ public class Main : IPlugin, IPluginI18n
3941
// resource path
4042
"(?:/\\S*)?" +
4143
"$";
42-
Regex reg = new Regex(urlPattern, RegexOptions.Compiled | RegexOptions.IgnoreCase);
44+
private readonly Regex UrlRegex = new(UrlPattern, RegexOptions.Compiled | RegexOptions.IgnoreCase);
4345
internal static PluginInitContext Context { get; private set; }
44-
private Settings _settings;
45-
46+
internal static Settings Settings { get; private set; }
47+
4648
public List<Result> Query(Query query)
4749
{
4850
var raw = query.Search;
4951
if (IsURL(raw))
5052
{
51-
return new List<Result>
52-
{
53-
new Result
53+
return
54+
[
55+
new()
5456
{
5557
Title = raw,
5658
SubTitle = Localize.flowlauncher_plugin_url_open_url(raw),
5759
IcoPath = "Images/url.png",
5860
Score = 8,
5961
Action = _ =>
6062
{
61-
if (!raw.ToLower().StartsWith("http"))
63+
if (!raw.StartsWith("http", StringComparison.OrdinalIgnoreCase))
6264
{
6365
raw = "http://" + raw;
6466
}
6567
try
6668
{
67-
Context.API.OpenUrl(raw);
68-
69+
if (Settings.UseCustomBrowser)
70+
{
71+
if (Settings.OpenInNewBrowserWindow)
72+
{
73+
SearchWeb.OpenInBrowserWindow(raw, Settings.BrowserPath, Settings.OpenInPrivateMode, Settings.PrivateModeArgument);
74+
}
75+
else
76+
{
77+
SearchWeb.OpenInBrowserTab(raw, Settings.BrowserPath, Settings.OpenInPrivateMode, Settings.PrivateModeArgument);
78+
}
79+
}
80+
else
81+
{
82+
Context.API.OpenWebUrl(raw);
83+
}
84+
6985
return true;
7086
}
7187
catch(Exception)
@@ -75,16 +91,17 @@ public List<Result> Query(Query query)
7591
}
7692
}
7793
}
78-
};
94+
];
7995
}
80-
return new List<Result>(0);
96+
97+
return [];
8198
}
8299

83100
public bool IsURL(string raw)
84101
{
85102
raw = raw.ToLower();
86103

87-
if (reg.Match(raw).Value == raw) return true;
104+
if (UrlRegex.Match(raw).Value == raw) return true;
88105

89106
if (raw == "localhost" || raw.StartsWith("localhost:") ||
90107
raw == "http://localhost" || raw.StartsWith("http://localhost:") ||
@@ -100,8 +117,8 @@ public bool IsURL(string raw)
100117
public void Init(PluginInitContext context)
101118
{
102119
Context = context;
103-
104-
_settings = context.API.LoadSettingJsonStorage<Settings>();
120+
121+
Settings = context.API.LoadSettingJsonStorage<Settings>();
105122
}
106123

107124
public string GetTranslatedPluginTitle()
@@ -113,5 +130,10 @@ public string GetTranslatedPluginDescription()
113130
{
114131
return Localize.flowlauncher_plugin_url_plugin_description();
115132
}
133+
134+
public Control CreateSettingPanel()
135+
{
136+
return new SettingsControl();
137+
}
116138
}
117139
}
Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,51 @@
11
namespace Flow.Launcher.Plugin.Url
22
{
3-
public class Settings
3+
public class Settings : BaseModel
44
{
5-
public string BrowserPath { get; set; }
5+
private bool _useCustomBrowser = false;
6+
public bool UseCustomBrowser
7+
{
8+
get => _useCustomBrowser;
9+
set
10+
{
11+
if (_useCustomBrowser != value)
12+
{
13+
_useCustomBrowser = value;
14+
OnPropertyChanged();
15+
}
16+
}
17+
}
618

7-
public bool OpenInNewBrowserWindow { get; set; } = true;
19+
private string _browserPath = string.Empty;
20+
public string BrowserPath
21+
{
22+
get => _browserPath;
23+
set
24+
{
25+
if (_browserPath != value)
26+
{
27+
_browserPath = value;
28+
OnPropertyChanged();
29+
}
30+
}
31+
}
32+
33+
private bool _openInNewBrowserWindow = true;
34+
public bool OpenInNewBrowserWindow
35+
{
36+
get => _openInNewBrowserWindow;
37+
set
38+
{
39+
if (_openInNewBrowserWindow != value)
40+
{
41+
_openInNewBrowserWindow = value;
42+
OnPropertyChanged();
43+
}
44+
}
45+
}
46+
47+
public bool OpenInPrivateMode { get; set; } = false;
48+
49+
public string PrivateModeArgument { get; set; } = string.Empty;
850
}
951
}
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
<UserControl
2+
x:Class="Flow.Launcher.Plugin.Url.SettingsControl"
3+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
4+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
5+
xmlns:converters="clr-namespace:Flow.Launcher.Plugin.Url.Converters"
6+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
7+
xmlns:local="clr-namespace:Flow.Launcher.Plugin.Url"
8+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
9+
d:DesignHeight="450"
10+
d:DesignWidth="800"
11+
DataContext="{Binding RelativeSource={RelativeSource Self}}"
12+
mc:Ignorable="d">
13+
<UserControl.Resources>
14+
<converters:InverseBoolConverter x:Key="InverseBoolConverter" />
15+
<converters:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter" />
16+
</UserControl.Resources>
17+
18+
<Grid Margin="{StaticResource SettingPanelMargin}">
19+
<Grid.RowDefinitions>
20+
<RowDefinition Height="auto" />
21+
<RowDefinition Height="auto" />
22+
</Grid.RowDefinitions>
23+
24+
<CheckBox
25+
Grid.Row="0"
26+
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
27+
HorizontalAlignment="Left"
28+
VerticalAlignment="Center"
29+
Content="{DynamicResource flowlauncher_plugin_url_use_custom_browser}"
30+
IsChecked="{Binding Settings.UseCustomBrowser, Mode=TwoWay}" />
31+
32+
<Grid
33+
Grid.Row="1"
34+
HorizontalAlignment="Left"
35+
Visibility="{Binding Settings.UseCustomBrowser, Converter={StaticResource BoolToVisibilityConverter}, Mode=OneWay}">
36+
<Grid.RowDefinitions>
37+
<RowDefinition Height="auto" />
38+
<RowDefinition Height="auto" />
39+
<RowDefinition Height="auto" />
40+
</Grid.RowDefinitions>
41+
<Grid.ColumnDefinitions>
42+
<ColumnDefinition Width="Auto" />
43+
<ColumnDefinition Width="*" />
44+
</Grid.ColumnDefinitions>
45+
46+
<TextBlock
47+
Grid.Row="0"
48+
Grid.Column="0"
49+
Margin="{StaticResource SettingPanelItemRightTopBottomMargin}"
50+
VerticalAlignment="Center"
51+
FontSize="14"
52+
Text="{DynamicResource flowlauncher_plugin_url_browser_path}" />
53+
<Grid
54+
Grid.Row="0"
55+
Grid.Column="1"
56+
Margin="{StaticResource SettingPanelItemLeftTopBottomMargin}">
57+
<Grid.ColumnDefinitions>
58+
<ColumnDefinition Width="*" />
59+
<ColumnDefinition Width="Auto" />
60+
</Grid.ColumnDefinitions>
61+
62+
<TextBox
63+
Grid.Column="0"
64+
HorizontalAlignment="Stretch"
65+
VerticalAlignment="Center"
66+
IsReadOnly="True"
67+
Text="{Binding Settings.BrowserPath, Mode=OneWay}" />
68+
<Button
69+
Grid.Column="1"
70+
Margin="{StaticResource SettingPanelItemLeftMargin}"
71+
HorizontalAlignment="Left"
72+
VerticalAlignment="Center"
73+
Click="SelectBrowserPath"
74+
Content="{DynamicResource flowlauncher_plugin_url_plugin_choose}" />
75+
</Grid>
76+
77+
<StackPanel
78+
Grid.Row="1"
79+
Grid.Column="1"
80+
Margin="{StaticResource SettingPanelItemLeftTopBottomMargin}"
81+
Orientation="Horizontal">
82+
<RadioButton Content="{DynamicResource flowlauncher_plugin_url_new_tab}" IsChecked="{Binding Settings.OpenInNewBrowserWindow, Converter={StaticResource InverseBoolConverter}, Mode=TwoWay}" />
83+
<RadioButton Content="{DynamicResource flowlauncher_plugin_url_new_window}" IsChecked="{Binding Settings.OpenInNewBrowserWindow, Mode=TwoWay}" />
84+
</StackPanel>
85+
86+
<TextBlock
87+
Grid.Row="2"
88+
Grid.Column="0"
89+
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
90+
VerticalAlignment="Center"
91+
FontSize="14"
92+
Text="{DynamicResource flowlauncher_plugin_url_private_mode}" />
93+
<Grid
94+
Grid.Row="2"
95+
Grid.Column="1"
96+
Margin="{StaticResource SettingPanelItemLeftTopBottomMargin}">
97+
<Grid.ColumnDefinitions>
98+
<ColumnDefinition Width="*" />
99+
<ColumnDefinition Width="Auto" />
100+
</Grid.ColumnDefinitions>
101+
102+
<TextBox
103+
Grid.Column="0"
104+
HorizontalAlignment="Stretch"
105+
VerticalAlignment="Center"
106+
Text="{Binding Settings.PrivateModeArgument, Mode=TwoWay}" />
107+
<CheckBox
108+
Grid.Column="1"
109+
Margin="{StaticResource SettingPanelItemLeftMargin}"
110+
HorizontalAlignment="Left"
111+
VerticalAlignment="Center"
112+
Content=""
113+
IsChecked="{Binding Settings.OpenInPrivateMode, Mode=TwoWay}" />
114+
</Grid>
115+
</Grid>
116+
</Grid>
117+
</UserControl>

0 commit comments

Comments
 (0)