Skip to content

Commit

Permalink
Add silent query execution option
Browse files Browse the repository at this point in the history
In this commit, an option for silent query execution has been added to Wox.UI.Flutter. This allows for queries to be executed directly when the count of query results is 1, providing benefits in specific use-cases. Error handling has also been introduced for image loading within the WoxImageView component. This prevents potential crashes when images fail to load, ensuring a more resilient UI experience.
  • Loading branch information
qianlifeng committed May 27, 2024
1 parent 14a47a9 commit dc06d16
Show file tree
Hide file tree
Showing 10 changed files with 112 additions and 11 deletions.
10 changes: 9 additions & 1 deletion Wox.UI.Flutter/wox/lib/components/wox_image_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,15 @@ class WoxImageView extends StatelessWidget {
@override
Widget build(BuildContext context) {
if (woxImage.imageType == WoxImageTypeEnum.WOX_IMAGE_TYPE_URL.code) {
return Image.network(woxImage.imageData, width: width, height: height, fit: BoxFit.contain);
return Image.network(
woxImage.imageData,
width: width,
height: height,
fit: BoxFit.contain,
errorBuilder: (context, error, stackTrace) {
return SizedBox(width: width, height: height);
},
);
} else if (woxImage.imageType == WoxImageTypeEnum.WOX_IMAGE_TYPE_SVG.code) {
return SvgPicture.string(woxImage.imageData, width: width, height: height);
} else if (woxImage.imageType == WoxImageTypeEnum.WOX_IMAGE_TYPE_EMOJI.code) {
Expand Down
18 changes: 14 additions & 4 deletions Wox.UI.Flutter/wox/lib/entity/wox_query.dart
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,8 @@ class Position {
late int x;
late int y;

Position({required this.type, required this.x, required this.y});

Position.fromJson(Map<String, dynamic> json) {
type = json['Type'];
x = json['X'];
Expand All @@ -189,13 +191,21 @@ class ShowAppParams {
late List<QueryHistory> queryHistories;
late WoxLastQueryMode lastQueryMode;

ShowAppParams({required this.selectAll, required this.position, required this.queryHistories, required this.lastQueryMode});

ShowAppParams.fromJson(Map<String, dynamic> json) {
selectAll = json['SelectAll'];
position = Position.fromJson(json['Position']);
if (json['Position'] != null) {
position = Position.fromJson(json['Position']);
}
queryHistories = <QueryHistory>[];
json['QueryHistories'].forEach((v) {
queryHistories.add(QueryHistory.fromJson(v));
});
if (json['QueryHistories'] != null) {
json['QueryHistories'].forEach((v) {
queryHistories.add(QueryHistory.fromJson(v));
});
} else {
queryHistories = <QueryHistory>[];
}
lastQueryMode = json['LastQueryMode'];
}
}
Expand Down
6 changes: 5 additions & 1 deletion Wox.UI.Flutter/wox/lib/entity/wox_setting.dart
Original file line number Diff line number Diff line change
Expand Up @@ -86,17 +86,21 @@ class QueryHotkey {

late String query; // Support plugin.QueryVariable

QueryHotkey({required this.hotkey, required this.query});
late bool isSilentExecution;

QueryHotkey({required this.hotkey, required this.query, required this.isSilentExecution});

QueryHotkey.fromJson(Map<String, dynamic> json) {
hotkey = json['Hotkey'];
query = json['Query'];
isSilentExecution = json['IsSilentExecution'] ?? false;
}

Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['Hotkey'] = hotkey;
data['Query'] = query;
data['IsSilentExecution'] = isSilentExecution;
return data;
}
}
Expand Down
2 changes: 2 additions & 0 deletions Wox.UI.Flutter/wox/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -109,13 +109,15 @@ class _WoxAppState extends State<WoxApp> with WindowListener {
var launcherController = Get.find<WoxLauncherController>();
launcherController.isInSettingView.stream.listen((isShowSetting) async {
if (isShowSetting) {
await windowManager.setAlwaysOnTop(false);
await WoxThemeUtil.instance.loadTheme();
await WoxSettingUtil.instance.loadSetting();
launcherController.positionBeforeOpenSetting = await windowManager.getPosition();
windowManager.setSize(const Size(1200, 800));
windowManager.center();
Get.find<WoxSettingController>().activePaneIndex.value = 0;
} else {
await windowManager.setAlwaysOnTop(true);
launcherController.resizeHeight();
await windowManager.setPosition(launcherController.positionBeforeOpenSetting);
await windowManager.focus();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -658,6 +658,23 @@ class WoxLauncherController extends GetxController implements WoxLauncherInterfa
settingController.switchToPluginSettingTab();
});
}

// if user open setting window from silent query, the windows may not visible yet
var isVisible = await windowManager.isVisible();
if (!isVisible) {
await showApp(
traceId,
ShowAppParams(
queryHistories: latestQueryHistories,
lastQueryMode: lastQueryMode,
selectAll: true,
position: Position(
type: WoxPositionTypeEnum.POSITION_TYPE_LAST_LOCATION.code,
x: 0,
y: 0,
),
));
}
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,15 @@ class WoxSettingGeneralView extends GetView<WoxSettingController> {
"Validators": [
{"Type": "not_empty"}
],
},
{
"Key": "IsSilentExecution",
"Label": "Silent",
"Tooltip": "When selected, if the count of query result is 1, Wox will execute the query directly without showing the result list.\n\n"
"This is useful when you have a query that always return one result and you want to execute it directly.\n"
"Note: This option is only available when the query result count is 1. Otherwise it will be ignored and notify a warning.",
"Width": 60,
"Type": "checkbox"
}
],
"SortColumnKey": "Query"
Expand Down
32 changes: 32 additions & 0 deletions Wox/plugin/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,38 @@ func (m *Manager) Query(ctx context.Context, query Query) (results chan []QueryR
return
}

func (m *Manager) QuerySilent(ctx context.Context, query Query) bool {
var startTimestamp = util.GetSystemTimestamp()
var results []QueryResultUI
resultChan, doneChan := m.Query(ctx, query)
for {
select {
case r := <-resultChan:
results = append(results, r...)
case <-doneChan:
logger.Info(ctx, fmt.Sprintf("silent query done, total results: %d, cost %d ms", len(results), util.GetSystemTimestamp()-startTimestamp))

// execute default action if only one result
if len(results) == 1 {
result := results[0]
for _, action := range result.Actions {
if action.IsDefault {
m.ExecuteAction(ctx, result.Id, action.Id)
return true
}
}
} else {
m.GetUI().Notify(ctx, "Silent query failed", fmt.Sprintf("There shouldbe only one result, but got %d", len(results)))
}

return false
case <-time.After(time.Minute):
logger.Error(ctx, "silent query timeout")
return false
}
}
}

func (m *Manager) QueryFallback(ctx context.Context, query Query) (results []QueryResultUI) {
if !query.IsGlobalQuery() {
return
Expand Down
1 change: 1 addition & 0 deletions Wox/plugin/system/selection.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ func (i *SelectionPlugin) queryForFile(ctx context.Context, filePath string) (re
woxImage := plugin.NewWoxImageAbsolutePath(trimmedText)
results = append(results, plugin.QueryResult{
Title: "Preview",
Score: 1000,
Icon: plugin.NewWoxImageSvg(`<svg t="1713248218693" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1465" width="200" height="200"><path d="M929.5 185.3c-0.2-25.1-9.9-48.5-27.5-66.1-3.7-3.7-7.6-7-11.8-10-14-10.1-30.4-16.1-47.8-17.5H841.8c-2.2-0.2-4.3-0.2-6.5-0.2H188.7c-2.2 0-4.3 0.1-6.5 0.2H181.6c-17.4 1.3-33.8 7.4-47.8 17.5-4.2 3-8.1 6.3-11.8 10-17.7 17.7-27.5 41.4-27.5 66.7v652.3c0 52 42.3 94.3 94.4 94.3h164.6c19.3 0 35-15.7 35-35s-15.7-35-35-35H188.9c-13.5 0-24.4-10.9-24.4-24.3V185.9c0-6.4 2.6-12.7 7.3-17.4 4.5-4.5 10.6-7 17.1-7h646.2c6.5 0 12.6 2.5 17.1 7 4.7 4.7 7.3 11 7.3 17.4v652.3c0 13.4-10.9 24.3-24.4 24.3H670.5c-19.3 0-35 15.7-35 35s15.7 35 35 35h164.6c52.1 0 94.4-42.3 94.4-94.3V185.9v-0.6z" fill="#1296db" p-id="1466"></path><path d="M512 380.9c-72.3 0-131.1 58.8-131.1 131.1S439.7 643.1 512 643.1 643.1 584.3 643.1 512 584.3 380.9 512 380.9z m0 218.5c-48.3 0-87.4-39.1-87.4-87.4 0-48.3 39.1-87.4 87.4-87.4s87.4 39.1 87.4 87.4-39.1 87.4-87.4 87.4z" fill="#1296db" p-id="1467"></path><path d="M795 449.6c-10.8-17.9-30-45.3-60.4-73.9-29-27.3-61.1-49.2-95.3-64.9-40.8-18.7-83.6-28.2-127.3-28.2s-86.6 9.6-127.3 28.4c-34.2 15.8-66.3 37.8-95.3 65.3-30.3 28.7-49.6 56-60.4 73.9-10.5 17.3-23 42.1-23 61.9s12.5 44.6 23 61.9c10.8 17.9 30.1 45.2 60.4 73.9 29 27.5 61.1 49.4 95.3 65.3 40.8 18.8 83.6 28.4 127.3 28.4s86.5-9.5 127.3-28.2c34.2-15.7 66.3-37.6 95.3-64.9 30.4-28.7 49.6-56 60.4-73.9 10.5-17.4 22.9-42.3 22.9-62.4 0.1-20.3-12.4-45.3-22.9-62.6z m-90.4 167c-39.3 37-104.6 81.2-192.6 81.2-87.8 0-153.2-44.4-192.6-81.7-49.6-46.9-69.7-92.8-69.7-104.1 0-11.2 20-57.1 69.7-104.1 39.4-37.3 104.8-81.7 192.6-81.7 88 0 153.3 44.2 192.6 81.2 49.6 46.8 69.7 93.1 69.7 104.6s-20.1 57.8-69.7 104.6z" fill="#1296db" p-id="1468"></path></svg>`),
Actions: []plugin.QueryResultAction{
{
Expand Down
5 changes: 3 additions & 2 deletions Wox/setting/wox_setting.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,9 @@ func (q *QueryShortcut) PlaceholderCount() int {
}

type QueryHotkey struct {
Hotkey string
Query string // Support plugin.QueryVariable
Hotkey string
Query string // Support plugin.QueryVariable
IsSilentExecution bool // If true, the query will be executed without showing the query in the input box
}

func GetDefaultWoxSetting(ctx context.Context) WoxSetting {
Expand Down
23 changes: 20 additions & 3 deletions Wox/ui/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,14 +228,31 @@ func (m *Manager) RegisterSelectionHotkey(ctx context.Context, combineKey string

func (m *Manager) RegisterQueryHotkey(ctx context.Context, queryHotkey setting.QueryHotkey) error {
hk := &hotkey.Hotkey{}

err := hk.Register(ctx, queryHotkey.Hotkey, func() {
newCtx := util.NewTraceContext()
query := plugin.GetPluginManager().ReplaceQueryVariable(newCtx, queryHotkey.Query)
m.ui.ChangeQuery(newCtx, share.PlainQuery{
plainQuery := share.PlainQuery{
QueryType: plugin.QueryTypeInput,
QueryText: query,
})
m.ui.ShowApp(newCtx, share.ShowContext{SelectAll: false})
}

if queryHotkey.IsSilentExecution {
q, _, err := plugin.GetPluginManager().NewQuery(ctx, plainQuery)
if err != nil {
logger.Error(ctx, fmt.Sprintf("failed to create silent query: %s", err.Error()))
return
}
success := plugin.GetPluginManager().QuerySilent(ctx, q)
if !success {
logger.Error(ctx, fmt.Sprintf("failed to execute silent query: %s", query))
} else {
logger.Info(ctx, fmt.Sprintf("silent query executed: %s", query))
}
} else {
m.ui.ChangeQuery(newCtx, plainQuery)
m.ui.ShowApp(newCtx, share.ShowContext{SelectAll: false})
}
})
if err != nil {
return err
Expand Down

0 comments on commit dc06d16

Please sign in to comment.