Open bviefhues opened 2 years ago
Yep, I would love to have pretty much all of these. We've struggled a lot to get the hs.chooser UI working even as well as it does now, so I think if I was going to try again to make it even more dynamic, I would want to rewrite the whole thing and probably use SwiftUI. I can't make any promises about when we'll be able to do that though!
There is a long way to go in terms of the behaviours and keyboard navigation, but I have a very barebones SwiftUI Playground up and running that looks kinda like a Chooser:
import SwiftUI
import PlaygroundSupport
struct ChooserResult: Hashable {
var icon: String?
var text: String
var subText: String?
}
struct ContentView: View {
@State private var showQuery = true
@State private var showDetail = true
@State private var queryString: String = ""
@State private var results:[ChooserResult] = []
var body: some View {
let queryBinding = Binding<String>(get: { self.queryString }, set: {
self.queryString = $0
self.results.append(ChooserResult(icon: "app.gift", text: "lol", subText: "asdf"))
self.results.append(ChooserResult(icon: "scribble", text: "otherlol"))
})
VStack {
if (showQuery) {
HStack {
Image(systemName: "magnifyingglass")
.resizable()
.aspectRatio(contentMode: .fit)
.foregroundColor(.gray)
.frame(maxWidth: 30, maxHeight: 30)
.padding([.leading])
TextField("Type query...", text: queryBinding)
.font(.largeTitle)
.padding([.trailing, .top, .bottom])
// .border(.red)
}
}
if (results.count > 0) {
HStack {
List {
ForEach(results, id: \.self) { result in
HStack {
Image(systemName: result.icon ?? "arrow.forward.circle")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(maxWidth: 40, maxHeight: 40)
VStack {
if (result.subText != nil) {
Text(result.text)
.font(.title)
.padding([.leading, .trailing, .top])
Text(result.subText!)
.foregroundColor(.gray)
.padding([.leading, .trailing, .bottom])
} else {
Text(result.text)
.font(.title)
.padding()
}
}
Spacer()
Text("%1")
.font(.title)
.foregroundColor(.gray)
}
.padding([.leading, .trailing])
}
}
.listStyle(.plain)
// .border(.green)
if (showDetail) {
VStack {
Text("Detail here")
.padding()
// .border(.yellow)
Spacer()
// .border(.gray)
}
}
}
}
}
}
}
PlaygroundPage.current.setLiveView(ContentView())
I have a question about existing chooser implementation, which I couldn't find much info on. Can we customize the hotkeys to pick specific items beyond cmd+number? Because I would prefer to just hit a number key, but ideally I would be able to explicitly specify the hotkey for any given choice.
You could use a separate hs.eventtap to watch for keypresses, but not sure how you'd know if the user is typing a number versus pressing a number to trigger a chooser line item.
I would like to add a request to chooser enhancements. Ability to use emoji/favicon in place of image, so that it does not look like the image attached.
You could use hs.canvas
to create a new image that contains the emoji, and use that in hs.chooser
?
You could use
hs.canvas
to create a new image that contains the emoji, and use that inhs.chooser
?
I've tried looking into the docs, but cannot understand how to do it. Is it possible for you to share a working code?
Interestingly, ChatGPT 4o gives me this, which actually works!
-- Create a canvas and draw an emoji on it
local function createEmojiImage(emoji, size)
local canvas = hs.canvas.new({x = 0, y = 0, w = size, h = size})
-- Draw the emoji in the center of the canvas
canvas[1] = {
type = "text",
text = emoji,
textSize = size * 0.8,
textAlignment = "center",
frame = {x = "0%", y = "0%", w = "100%", h = "100%"},
}
-- Convert the canvas to an image
local image = canvas:imageFromCanvas()
canvas:delete()
return image
end
-- Example usage in hs.chooser
local function showEmojiChooser()
local chooser = hs.chooser.new(function(choice)
if choice then
hs.alert.show("You chose: " .. choice.text)
end
end)
local emojiList = {"😀", "😂", "😎", "❤️", "👍"}
local choices = {}
for i, emoji in ipairs(emojiList) do
local emojiImage = createEmojiImage(emoji, 64) -- create a 64x64 image
table.insert(choices, {
text = emoji,
image = emojiImage,
})
end
chooser:choices(choices)
chooser:show()
end
-- Call the function to show the chooser
showEmojiChooser()
@latenitefilms Thank you. That helped.
Just want to mention here, that keeping textSize = size
does not properly align the image. So the image needs to be shifted frame = {x = "0%", y = "-15%", w = "100%", h = "100%"}
.
While such an issue is not found (or maybe not noticeable) if textSize = size * 0.8
, but then the image is smaller.
Thanks for sharing the tips. So we are able to set icons via emoji in that way? Awesome.
I wanted to be able to set different background colors for choices but marking them out with different icons will be effective too.
You could customise the colour behind the emoji.
Would be great if sometime
hs.chooser
could get these configuration enhancements:return
, for triggering different behavour, e.g. via an additional argument tocompletionFn