diff --git a/Wox.UI.Flutter/wox/lib/entity/wox_plugin.dart b/Wox.UI.Flutter/wox/lib/entity/wox_plugin.dart index 37fde6ae9..402fc6d7f 100644 --- a/Wox.UI.Flutter/wox/lib/entity/wox_plugin.dart +++ b/Wox.UI.Flutter/wox/lib/entity/wox_plugin.dart @@ -20,6 +20,7 @@ class PluginDetail { late bool isDisable; late List settingDefinitions; late PluginSetting setting; + late List features; PluginDetail.empty() { id = ''; @@ -40,6 +41,7 @@ class PluginDetail { isDisable = false; settingDefinitions = []; setting = PluginSetting.empty(); + features = []; } PluginDetail.fromJson(Map json) { @@ -97,6 +99,15 @@ class PluginDetail { } else { setting = PluginSetting.empty(); } + + if (json['Features'] != null) { + features = []; + json['Features'].forEach((v) { + features.add(MetadataFeature.fromJson(v)); + }); + } else { + features = []; + } } } @@ -165,3 +176,18 @@ class PluginQueryCommand { description = json['Description']; } } + +class MetadataFeature { + late String name; + late Map params; + + MetadataFeature.fromJson(Map json) { + name = json['Name']; + + if (json['Params'] != null) { + params = json['Params'].cast(); + } else { + params = {}; + } + } +} diff --git a/Wox.UI.Flutter/wox/lib/modules/setting/views/wox_setting_plugin_view.dart b/Wox.UI.Flutter/wox/lib/modules/setting/views/wox_setting_plugin_view.dart index 23b7a3973..6013bed78 100644 --- a/Wox.UI.Flutter/wox/lib/modules/setting/views/wox_setting_plugin_view.dart +++ b/Wox.UI.Flutter/wox/lib/modules/setting/views/wox_setting_plugin_view.dart @@ -3,6 +3,7 @@ import 'package:fluent_ui/fluent_ui.dart'; import 'package:flutter/material.dart' as material; import 'package:flutter/services.dart'; import 'package:flutter_image_slideshow/flutter_image_slideshow.dart'; +import 'package:flutter_svg/flutter_svg.dart'; import 'package:get/get.dart'; import 'package:wox/components/plugin/wox_setting_plugin_head_view.dart'; import 'package:wox/components/plugin/wox_setting_plugin_label_view.dart'; @@ -10,6 +11,7 @@ import 'package:wox/components/plugin/wox_setting_plugin_newline_view.dart'; import 'package:wox/components/plugin/wox_setting_plugin_select_view.dart'; import 'package:wox/components/plugin/wox_setting_plugin_table_view.dart'; import 'package:wox/components/wox_image_view.dart'; +import 'package:wox/components/wox_tooltip_view.dart'; import 'package:wox/entity/setting/wox_plugin_setting_label.dart'; import 'package:wox/entity/setting/wox_plugin_setting_table.dart'; import 'package:wox/entity/wox_plugin.dart'; @@ -306,6 +308,13 @@ class WoxSettingPluginView extends GetView { ), content: pluginTabSetting(), ), + dt.TabData( + index: 2, + title: const material.Tab( + child: Text('Privacy'), + ), + content: pluginTabPrivacy(), + ), ], onTabControllerUpdated: (tabController) { controller.activePluginTabController = tabController; @@ -435,6 +444,92 @@ class WoxSettingPluginView extends GetView { }); } + Widget pluginTabPrivacy() { + var plugin = controller.activePluginDetail.value; + var noDataAccess = const Padding( + padding: EdgeInsets.all(16), + child: Text('This plugin requires no data access'), + ); + + if (plugin.features.isEmpty) { + return noDataAccess; + } + + //check if "queryEnv" feature is exist and list it's params + var queryEnv = plugin.features.where((element) => element.name == "queryEnv").toList(); + if (queryEnv.isEmpty) { + return noDataAccess; + } + + List params = []; + queryEnv.first.params.forEach((key, value) { + if (value == "true") { + params.add(key); + } + }); + if (params.isEmpty) { + return noDataAccess; + } + + return Padding( + padding: const EdgeInsets.all(16.0), + child: Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text('This plugin requires access to the following data:'), + const SizedBox(height: 20), + ...params.map((e) { + if (e == "requireActiveWindowName") { + return privacyItem( + material.Icons.window, + 'Active window name', + 'E.g. you are using google chrome to view webpages, you activate Wox and this plugin will get the active window name as "Google Chrome"', + ); + } + if (e == "requireActiveBrowserUrl") { + return privacyItem( + material.Icons.web_sharp, + 'Active browser URL', + 'E.g. you are using google chrome to view webpages, you activate Wox and this plugin will get the url of active tab you are viewing', + ); + } + return Text(e); + }), + ], + ), + ), + ); + } + + Widget privacyItem(IconData icon, String title, String description) { + return Column( + children: [ + Row( + children: [ + Icon(icon), + SizedBox(width: 10), + Text(title), + ], + ), + const SizedBox(height: 10), + Row( + children: [ + const SizedBox(width: 30), + Flexible( + child: Text( + description, + style: TextStyle( + color: Colors.grey[100], + ), + ), + ), + ], + ) + ], + ); + } + @override Widget build(BuildContext context) { return Padding( diff --git a/Wox/plugin/manager.go b/Wox/plugin/manager.go index 9f64e3b82..2425ecd7f 100644 --- a/Wox/plugin/manager.go +++ b/Wox/plugin/manager.go @@ -39,6 +39,8 @@ type Manager struct { ui share.UI resultCache *util.HashMap[string, *QueryResultCache] debounceQueryTimer *util.HashMap[string, *debounceTimer] + + activeBrowserUrl string //active browser url before wox is activated } func GetPluginManager() *Manager { @@ -73,6 +75,10 @@ func (m *Manager) Stop(ctx context.Context) { } } +func (m *Manager) SetActiveBrowserUrl(url string) { + m.activeBrowserUrl = url +} + func (m *Manager) loadPlugins(ctx context.Context) error { logger.Info(ctx, "start loading plugins") @@ -368,6 +374,25 @@ func (m *Manager) canOperateQuery(ctx context.Context, pluginInstance *Instance, func (m *Manager) queryForPlugin(ctx context.Context, pluginInstance *Instance, query Query) []QueryResult { logger.Info(ctx, fmt.Sprintf("<%s> start query: %s", pluginInstance.Metadata.Name, query.RawQuery)) start := util.GetSystemTimestamp() + + // set query env base on plugin's feature + currentEnv := query.Env + newEnv := QueryEnv{} + if pluginInstance.Metadata.IsSupportFeature(MetadataFeatureQueryEnv) { + queryEnvParams, err := pluginInstance.Metadata.GetFeatureParamsForQueryEnv() + if err != nil { + logger.Error(ctx, fmt.Sprintf("<%s> invalid query env config: %s", pluginInstance.Metadata.Name, err)) + } else { + if queryEnvParams.RequireActiveWindowName { + newEnv.ActiveWindowTitle = currentEnv.ActiveWindowTitle + } + if queryEnvParams.RequireActiveBrowserUrl { + newEnv.ActiveBrowserUrl = currentEnv.ActiveBrowserUrl + } + } + } + query.Env = newEnv + results := pluginInstance.Plugin.Query(ctx, query) logger.Debug(ctx, fmt.Sprintf("<%s> finish query, result count: %d, cost: %dms", pluginInstance.Metadata.Name, len(results), util.GetSystemTimestamp()-start)) @@ -695,6 +720,7 @@ func (m *Manager) NewQuery(ctx context.Context, plainQuery share.PlainQuery) (Qu } query, instance := newQueryInputWithPlugins(newQuery, GetPluginManager().GetPluginInstances()) query.Env.ActiveWindowTitle = m.GetUI().GetActiveWindowName() + query.Env.ActiveBrowserUrl = m.getActiveBrowserUrl(ctx) return query, instance, nil } @@ -706,12 +732,23 @@ func (m *Manager) NewQuery(ctx context.Context, plainQuery share.PlainQuery) (Qu Selection: plainQuery.QuerySelection, } query.Env.ActiveWindowTitle = window.GetActiveWindowName() + query.Env.ActiveBrowserUrl = m.getActiveBrowserUrl(ctx) return query, nil, nil } return Query{}, nil, errors.New("invalid query type") } +func (m *Manager) getActiveBrowserUrl(ctx context.Context) string { + activeWindowName := m.GetUI().GetActiveWindowName() + isGoogleChrome := strings.ToLower(activeWindowName) == "google chrome" + if !isGoogleChrome { + return "" + } + + return m.activeBrowserUrl +} + func (m *Manager) expandQueryShortcut(ctx context.Context, query string, queryShorts []setting.QueryShortcut) (newQuery string) { newQuery = query diff --git a/Wox/plugin/metadata.go b/Wox/plugin/metadata.go index d5ce89718..fd4f64468 100644 --- a/Wox/plugin/metadata.go +++ b/Wox/plugin/metadata.go @@ -22,6 +22,9 @@ const ( // enable this feature to let Wox don't auto score results // by default, Wox will auto score results by the frequency of their actioned times MetadataFeatureIgnoreAutoScore MetadataFeatureName = "ignoreAutoScore" + + // enable this feature to get query env in plugin + MetadataFeatureQueryEnv MetadataFeatureName = "queryEnv" ) // Metadata parsed from plugin.json, see `Plugin.json.md` for more detail @@ -83,6 +86,33 @@ func (m *Metadata) GetFeatureParamsForDebounce() (MetadataFeatureParamsDebounce, return MetadataFeatureParamsDebounce{}, errors.New("plugin does not support debounce feature") } +func (m *Metadata) GetFeatureParamsForQueryEnv() (MetadataFeatureParamsQueryEnv, error) { + for _, feature := range m.Features { + if strings.ToLower(feature.Name) == strings.ToLower(MetadataFeatureQueryEnv) { + params := MetadataFeatureParamsQueryEnv{ + RequireActiveWindowName: false, + RequireActiveBrowserUrl: false, + } + + if v, ok := feature.Params["requireActiveWindowName"]; ok { + if v == "true" { + params.RequireActiveWindowName = true + } + } + + if v, ok := feature.Params["requireActiveBrowserUrl"]; ok { + if v == "true" { + params.RequireActiveBrowserUrl = true + } + } + + return params, nil + } + } + + return MetadataFeatureParamsQueryEnv{}, errors.New("plugin does not support queryEnv feature") +} + type MetadataFeature struct { Name MetadataFeatureName Params map[string]string @@ -105,3 +135,8 @@ type MetadataWithDirectory struct { type MetadataFeatureParamsDebounce struct { intervalMs int } + +type MetadataFeatureParamsQueryEnv struct { + RequireActiveWindowName bool + RequireActiveBrowserUrl bool +} diff --git a/Wox/plugin/query.go b/Wox/plugin/query.go index b0d840013..4e291a2d4 100644 --- a/Wox/plugin/query.go +++ b/Wox/plugin/query.go @@ -71,6 +71,10 @@ func (q *Query) String() string { type QueryEnv struct { ActiveWindowTitle string // active window title when user query + + // active browser url when user query + // Only available when active window is browser and https://github.com/Wox-launcher/Wox.Chrome.Extension is installed + ActiveBrowserUrl string } // Query result return from plugin diff --git a/Wox/plugin/system/browser.go b/Wox/plugin/system/browser.go index 5bdb6c3db..fa99e8a8d 100644 --- a/Wox/plugin/system/browser.go +++ b/Wox/plugin/system/browser.go @@ -72,6 +72,14 @@ func (c *BrowserPlugin) GetMetadata() plugin.Metadata { "Macos", "Linux", }, + Features: []plugin.MetadataFeature{ + { + Name: "queryEnv", + Params: map[string]string{ + "requireActiveWindowName": "true", + }, + }, + }, SettingDefinitions: []definition.PluginSettingDefinitionItem{ { Type: definition.PluginSettingDefinitionTypeTextBox, @@ -251,7 +259,7 @@ func (c *BrowserPlugin) onUpdateTabs(ctx context.Context, data string) { }) if exist { c.activeTab = activeTab - //c.api.Log(ctx, plugin.LogLevelDebug, fmt.Sprintf("active tab: %s", activeTab.Title)) + plugin.GetPluginManager().SetActiveBrowserUrl(activeTab.Url) } // filter invalid tabs diff --git a/Wox/ui/dto/plugin_dto.go b/Wox/ui/dto/plugin_dto.go index aafd2985a..05ec07bd6 100644 --- a/Wox/ui/dto/plugin_dto.go +++ b/Wox/ui/dto/plugin_dto.go @@ -23,6 +23,7 @@ type PluginDto struct { SupportedOS []string SettingDefinitions definition.PluginSettingDefinitions // only available when plugin is installed Setting setting.PluginSetting // only available when plugin is installed + Features []plugin.MetadataFeature // only available when plugin is installed IsSystem bool IsDev bool IsInstalled bool diff --git a/Wox/ui/http.go b/Wox/ui/http.go index ba880df5b..c1000ab1f 100644 --- a/Wox/ui/http.go +++ b/Wox/ui/http.go @@ -241,6 +241,7 @@ func convertPluginDto(ctx context.Context, pluginDto dto.PluginDto, pluginInstan pluginDto.Setting = *pluginInstance.Setting //only return user pre-defined settings pluginDto.Setting.Settings = definitionSettings + pluginDto.Features = pluginInstance.Metadata.Features } return pluginDto