🎉 Initial implementation using fyne v1
This commit is contained in:
@@ -0,0 +1,206 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"fyne.io/fyne"
|
||||
"fyne.io/fyne/app"
|
||||
"fyne.io/fyne/canvas"
|
||||
"fyne.io/fyne/container"
|
||||
"fyne.io/fyne/theme"
|
||||
"fyne.io/fyne/widget"
|
||||
"github.com/sahilm/fuzzy"
|
||||
)
|
||||
|
||||
type Gitmoji struct {
|
||||
Emoji string
|
||||
Code string
|
||||
Description string
|
||||
Name string
|
||||
}
|
||||
|
||||
type GitmojiData struct {
|
||||
Gitmojis []Gitmoji
|
||||
}
|
||||
|
||||
type GitmojiEntry struct {
|
||||
Gitmoji
|
||||
Icon fyne.Resource
|
||||
}
|
||||
|
||||
type keyedEntry struct {
|
||||
widget.Entry
|
||||
onKeyTyped func(keyEvent *fyne.KeyEvent) bool
|
||||
}
|
||||
|
||||
func (e *keyedEntry) TypedKey(keyEvent *fyne.KeyEvent) {
|
||||
if e.onKeyTyped == nil || !e.onKeyTyped(keyEvent) {
|
||||
e.Entry.TypedKey(keyEvent)
|
||||
}
|
||||
}
|
||||
|
||||
func newKeyedEntry() *keyedEntry {
|
||||
e := &keyedEntry{}
|
||||
e.ExtendBaseWidget(e)
|
||||
return e
|
||||
}
|
||||
|
||||
func main() {
|
||||
gitmojiData, err := loadData()
|
||||
if err != nil {
|
||||
// TODO show dialog
|
||||
panic(err)
|
||||
}
|
||||
|
||||
a := app.New()
|
||||
a.Settings().SetTheme(theme.LightTheme())
|
||||
w := a.NewWindow("Gitmoji Picker")
|
||||
w.CenterOnScreen()
|
||||
|
||||
allEntries := make([]*GitmojiEntry, len(gitmojiData.Gitmojis))
|
||||
allTerms := make([]string, len(gitmojiData.Gitmojis))
|
||||
currentId := 0
|
||||
|
||||
for i, gitmoji := range gitmojiData.Gitmojis {
|
||||
res, err := fyne.LoadResourceFromPath("data/images/" + gitmoji.Name + ".png")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
allEntries[i] = &GitmojiEntry{
|
||||
Gitmoji: gitmoji,
|
||||
Icon: res,
|
||||
}
|
||||
allTerms[i] = gitmoji.Name + " " + gitmoji.Description
|
||||
}
|
||||
|
||||
buildFilteredList := func(filter string) []*GitmojiEntry {
|
||||
r := fuzzy.Find(filter, allTerms)
|
||||
result := make([]*GitmojiEntry, len(r))
|
||||
for i := range r {
|
||||
result[i] = allEntries[r[i].Index]
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
var m sync.Mutex
|
||||
currentEntries := allEntries
|
||||
|
||||
e := newKeyedEntry()
|
||||
|
||||
l := widget.NewList(
|
||||
func() int {
|
||||
return len(currentEntries)
|
||||
},
|
||||
func() fyne.CanvasObject {
|
||||
tn := canvas.NewText("Dummy", theme.TextColor())
|
||||
tn.TextStyle.Bold = true
|
||||
|
||||
td := canvas.NewText("Dummy", theme.TextColor())
|
||||
td.TextSize = theme.TextSize() * 8 / 10
|
||||
|
||||
return container.NewHBox(
|
||||
widget.NewIcon(allEntries[0].Icon),
|
||||
container.NewVBox(tn, td),
|
||||
)
|
||||
},
|
||||
func(id widget.ListItemID, object fyne.CanvasObject) {
|
||||
m.Lock()
|
||||
entry := currentEntries[id]
|
||||
m.Unlock()
|
||||
|
||||
hb := object.(*fyne.Container)
|
||||
hb.Objects[0].(*widget.Icon).SetResource(entry.Icon)
|
||||
vb := hb.Objects[1].(*fyne.Container)
|
||||
vb.Objects[0].(*canvas.Text).Text = entry.Name
|
||||
vb.Objects[1].(*canvas.Text).Text = entry.Description
|
||||
|
||||
vb.Objects[0].(*canvas.Text).Refresh()
|
||||
vb.Objects[1].(*canvas.Text).Refresh()
|
||||
},
|
||||
)
|
||||
|
||||
l.OnSelected = func(id widget.ListItemID) {
|
||||
currentId = id
|
||||
}
|
||||
|
||||
e.OnChanged = func(s string) {
|
||||
m.Lock()
|
||||
if s == "" {
|
||||
currentEntries = allEntries
|
||||
} else {
|
||||
currentEntries = buildFilteredList(s)
|
||||
}
|
||||
if len(currentEntries) > 0 {
|
||||
currentId = 0
|
||||
} else {
|
||||
currentId = -1
|
||||
}
|
||||
m.Unlock()
|
||||
|
||||
l.Select(currentId)
|
||||
l.Refresh()
|
||||
}
|
||||
|
||||
l.Select(currentId)
|
||||
|
||||
w.SetContent(container.NewBorder(e, nil, nil, nil, l))
|
||||
w.Resize(fyne.NewSize(300, 300))
|
||||
|
||||
e.Show()
|
||||
|
||||
e.onKeyTyped = func(event *fyne.KeyEvent) bool {
|
||||
switch event.Name {
|
||||
case fyne.KeyDown:
|
||||
m.Lock()
|
||||
if currentId < len(currentEntries)-1 {
|
||||
currentId++
|
||||
}
|
||||
m.Unlock()
|
||||
l.Select(currentId)
|
||||
return true
|
||||
case fyne.KeyUp:
|
||||
m.Lock()
|
||||
if currentId > 0 {
|
||||
currentId--
|
||||
}
|
||||
m.Unlock()
|
||||
l.Select(currentId)
|
||||
return true
|
||||
case fyne.KeyEscape:
|
||||
w.Close()
|
||||
return true
|
||||
case fyne.KeyReturn, fyne.KeyEnter:
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
|
||||
if currentId > -1 {
|
||||
w.Clipboard().SetContent(currentEntries[currentId].Emoji)
|
||||
w.Close()
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
w.Canvas().Focus(e)
|
||||
|
||||
w.ShowAndRun()
|
||||
}
|
||||
|
||||
func loadData() (*GitmojiData, error) {
|
||||
f, err := os.Open("data/gitmojis.json")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot load gitmoji file: %w", err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
var result GitmojiData
|
||||
if err := json.NewDecoder(f).Decode(&result); err != nil {
|
||||
return nil, fmt.Errorf("cannot load gitmoji file: %w", err)
|
||||
}
|
||||
|
||||
return &result, nil
|
||||
}
|
||||
Reference in New Issue
Block a user