mirror of
https://github.com/fiatjaf/nak.git
synced 2025-12-10 09:28:51 +00:00
view: refactor edit into its own self-contained file and struct.
This commit is contained in:
181
view/event.go
Normal file
181
view/event.go
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"slices"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"fiatjaf.com/nostr"
|
||||||
|
"github.com/therecipe/qt/core"
|
||||||
|
"github.com/therecipe/qt/widgets"
|
||||||
|
)
|
||||||
|
|
||||||
|
var event struct {
|
||||||
|
kindSpin *widgets.QSpinBox
|
||||||
|
kindNameLabel *widgets.QLabel
|
||||||
|
tagRows [][]*widgets.QLineEdit
|
||||||
|
contentEdit *widgets.QTextEdit
|
||||||
|
createdAtEdit *widgets.QDateTimeEdit
|
||||||
|
outputEdit *widgets.QTextEdit
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateEvent() {
|
||||||
|
kind := nostr.Kind(event.kindSpin.Value())
|
||||||
|
kindName := kind.Name()
|
||||||
|
if kindName != "unknown" {
|
||||||
|
event.kindNameLabel.SetText(kindName)
|
||||||
|
} else {
|
||||||
|
event.kindNameLabel.SetText("")
|
||||||
|
}
|
||||||
|
tags := make(nostr.Tags, 0, len(event.tagRows))
|
||||||
|
for y, tagItems := range event.tagRows {
|
||||||
|
if y == len(event.tagRows)-1 && strings.TrimSpace(tagItems[0].Text()) == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
tag := make(nostr.Tag, 0, len(tagItems))
|
||||||
|
for x, edit := range tagItems {
|
||||||
|
text := strings.TrimSpace(edit.Text())
|
||||||
|
if x == len(tagItems)-1 && text == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
text = decodeTagValue(text)
|
||||||
|
tag = append(tag, text)
|
||||||
|
}
|
||||||
|
if len(tag) > 0 {
|
||||||
|
tags = append(tags, tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final := nostr.Event{
|
||||||
|
Kind: kind,
|
||||||
|
Content: event.contentEdit.ToPlainText(),
|
||||||
|
CreatedAt: nostr.Timestamp(event.createdAtEdit.DateTime().ToMSecsSinceEpoch() / 1000),
|
||||||
|
Tags: tags,
|
||||||
|
}
|
||||||
|
|
||||||
|
if currentKeyer != nil {
|
||||||
|
currentKeyer.SignEvent(context.Background(), &final)
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonBytes, _ := json.MarshalIndent(event, "", " ")
|
||||||
|
event.outputEdit.SetPlainText(string(jsonBytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupEventTab() *widgets.QWidget {
|
||||||
|
tab := widgets.NewQWidget(nil, 0)
|
||||||
|
|
||||||
|
// set up event tab
|
||||||
|
layout := widgets.NewQVBoxLayout()
|
||||||
|
tab.SetLayout(layout)
|
||||||
|
|
||||||
|
// kind input
|
||||||
|
kindHBox := widgets.NewQHBoxLayout()
|
||||||
|
layout.AddLayout(kindHBox, 0)
|
||||||
|
kindLabel := widgets.NewQLabel2("kind:", nil, 0)
|
||||||
|
kindHBox.AddWidget(kindLabel, 0, 0)
|
||||||
|
event.kindSpin = widgets.NewQSpinBox(nil)
|
||||||
|
event.kindSpin.SetValue(1)
|
||||||
|
event.kindSpin.SetMinimum(0)
|
||||||
|
event.kindSpin.SetMaximum(1<<16 - 1)
|
||||||
|
kindHBox.AddWidget(event.kindSpin, 0, 0)
|
||||||
|
event.kindSpin.ConnectValueChanged(func(int) {
|
||||||
|
updateEvent()
|
||||||
|
})
|
||||||
|
event.kindNameLabel = widgets.NewQLabel2("", nil, 0)
|
||||||
|
kindHBox.AddWidget(event.kindNameLabel, 0, 0)
|
||||||
|
|
||||||
|
// content input
|
||||||
|
contentLabel := widgets.NewQLabel2("content:", nil, 0)
|
||||||
|
layout.AddWidget(contentLabel, 0, 0)
|
||||||
|
event.contentEdit = widgets.NewQTextEdit(nil)
|
||||||
|
layout.AddWidget(event.contentEdit, 0, 0)
|
||||||
|
event.contentEdit.ConnectTextChanged(updateEvent)
|
||||||
|
|
||||||
|
// created_at input
|
||||||
|
createdAtLabel := widgets.NewQLabel2("created at:", nil, 0)
|
||||||
|
layout.AddWidget(createdAtLabel, 0, 0)
|
||||||
|
event.createdAtEdit = widgets.NewQDateTimeEdit(nil)
|
||||||
|
event.createdAtEdit.SetDateTime(core.QDateTime_CurrentDateTime())
|
||||||
|
layout.AddWidget(event.createdAtEdit, 0, 0)
|
||||||
|
event.createdAtEdit.ConnectDateTimeChanged(func(*core.QDateTime) {
|
||||||
|
updateEvent()
|
||||||
|
})
|
||||||
|
|
||||||
|
// tags input
|
||||||
|
tagsLabel := widgets.NewQLabel2("tags:", nil, 0)
|
||||||
|
layout.AddWidget(tagsLabel, 0, 0)
|
||||||
|
tagsLayout := widgets.NewQVBoxLayout()
|
||||||
|
tagRowHBoxes := make([]widgets.QLayout_ITF, 0, 2)
|
||||||
|
event.tagRows = make([][]*widgets.QLineEdit, 0, 2)
|
||||||
|
layout.AddLayout(tagsLayout, 0)
|
||||||
|
|
||||||
|
var addTagRow func()
|
||||||
|
addTagRow = func() {
|
||||||
|
hbox := widgets.NewQHBoxLayout()
|
||||||
|
tagRowHBoxes = append(tagRowHBoxes, hbox)
|
||||||
|
tagsLayout.AddLayout(hbox, 0)
|
||||||
|
tagItems := []*widgets.QLineEdit{}
|
||||||
|
y := len(event.tagRows)
|
||||||
|
event.tagRows = append(event.tagRows, tagItems)
|
||||||
|
|
||||||
|
var addItem func()
|
||||||
|
addItem = func() {
|
||||||
|
edit := widgets.NewQLineEdit(nil)
|
||||||
|
hbox.AddWidget(edit, 0, 0)
|
||||||
|
x := len(tagItems)
|
||||||
|
tagItems = append(tagItems, edit)
|
||||||
|
event.tagRows[y] = tagItems
|
||||||
|
edit.ConnectTextChanged(func(text string) {
|
||||||
|
if strings.TrimSpace(text) != "" {
|
||||||
|
// when an item input has been filled check if we have to show more
|
||||||
|
if y == len(event.tagRows)-1 {
|
||||||
|
addTagRow()
|
||||||
|
}
|
||||||
|
if x == len(tagItems)-1 {
|
||||||
|
addItem()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// do this when an item input has been emptied: check if we need to remove an item from this row
|
||||||
|
nItems := len(tagItems)
|
||||||
|
if nItems >= 2 && strings.TrimSpace(tagItems[nItems-1].Text()) == "" && strings.TrimSpace(tagItems[nItems-2].Text()) == "" {
|
||||||
|
// remove last item if the last 2 are empty
|
||||||
|
hbox.Layout().RemoveWidget(tagItems[nItems-1])
|
||||||
|
tagItems[nItems-1].DeleteLater()
|
||||||
|
tagItems = tagItems[0 : nItems-1]
|
||||||
|
event.tagRows[y] = tagItems
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if we need to remove rows
|
||||||
|
nRows := len(event.tagRows)
|
||||||
|
itemIsFilled := func(edit *widgets.QLineEdit) bool { return strings.TrimSpace(edit.Text()) != "" }
|
||||||
|
if nRows >= 2 && !slices.ContainsFunc(event.tagRows[nRows-1], itemIsFilled) && !slices.ContainsFunc(event.tagRows[nRows-2], itemIsFilled) {
|
||||||
|
// remove the last row if the last 2 are empty
|
||||||
|
tagsLayout.RemoveItem(tagRowHBoxes[nRows-1])
|
||||||
|
for _, tagItem := range event.tagRows[nRows-1] {
|
||||||
|
tagItem.DeleteLater()
|
||||||
|
}
|
||||||
|
tagRowHBoxes[nRows-1].QLayout_PTR().DeleteLater()
|
||||||
|
event.tagRows = event.tagRows[0 : nRows-1]
|
||||||
|
tagRowHBoxes = tagRowHBoxes[0 : nRows-1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateEvent()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
addItem()
|
||||||
|
}
|
||||||
|
|
||||||
|
// first
|
||||||
|
addTagRow()
|
||||||
|
|
||||||
|
// output JSON
|
||||||
|
outputLabel := widgets.NewQLabel2("event:", nil, 0)
|
||||||
|
layout.AddWidget(outputLabel, 0, 0)
|
||||||
|
event.outputEdit = widgets.NewQTextEdit(nil)
|
||||||
|
event.outputEdit.SetReadOnly(true)
|
||||||
|
layout.AddWidget(event.outputEdit, 0, 0)
|
||||||
|
|
||||||
|
return tab
|
||||||
|
}
|
||||||
172
view/main.go
172
view/main.go
@@ -1,21 +1,16 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"os"
|
"os"
|
||||||
"slices"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"fiatjaf.com/nostr"
|
"fiatjaf.com/nostr"
|
||||||
"github.com/therecipe/qt/core"
|
|
||||||
"github.com/therecipe/qt/widgets"
|
"github.com/therecipe/qt/widgets"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
currentSec nostr.SecretKey
|
currentSec nostr.SecretKey
|
||||||
currentKeyer nostr.Keyer
|
currentKeyer nostr.Keyer
|
||||||
tagRows [][]*widgets.QLineEdit
|
statusLabel *widgets.QLabel
|
||||||
updateEvent func()
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@@ -41,22 +36,25 @@ func main() {
|
|||||||
if text == "" {
|
if text == "" {
|
||||||
currentSec = nostr.SecretKey{}
|
currentSec = nostr.SecretKey{}
|
||||||
currentKeyer = nil
|
currentKeyer = nil
|
||||||
|
statusLabel.SetText("")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
sk, bunker, err := handleSecretKeyOrBunker(text)
|
sk, bunker, err := handleSecretKeyOrBunker(text)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// TODO: have a field somewhere at the bottom of the screen, below the tabs view, to display errors and other messages
|
statusLabel.SetText(err.Error())
|
||||||
currentSec = nostr.SecretKey{}
|
currentSec = nostr.SecretKey{}
|
||||||
currentKeyer = nil
|
currentKeyer = nil
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
currentSec = sk
|
currentSec = sk
|
||||||
currentKeyer = bunker
|
currentKeyer = bunker
|
||||||
|
statusLabel.SetText("")
|
||||||
|
updateEvent()
|
||||||
})
|
})
|
||||||
|
|
||||||
tabWidget := widgets.NewQTabWidget(nil)
|
tabWidget := widgets.NewQTabWidget(nil)
|
||||||
|
|
||||||
eventTab := widgets.NewQWidget(nil, 0)
|
eventTab := setupEventTab()
|
||||||
reqTab := widgets.NewQWidget(nil, 0)
|
reqTab := widgets.NewQWidget(nil, 0)
|
||||||
|
|
||||||
tabWidget.AddTab(eventTab, "event")
|
tabWidget.AddTab(eventTab, "event")
|
||||||
@@ -64,162 +62,8 @@ func main() {
|
|||||||
|
|
||||||
mainLayout.AddWidget(tabWidget, 0, 0)
|
mainLayout.AddWidget(tabWidget, 0, 0)
|
||||||
|
|
||||||
// set up event tab
|
statusLabel = widgets.NewQLabel2("", nil, 0)
|
||||||
layout := widgets.NewQVBoxLayout()
|
mainLayout.AddWidget(statusLabel, 0, 0)
|
||||||
eventTab.SetLayout(layout)
|
|
||||||
|
|
||||||
// kind input
|
|
||||||
kindHBox := widgets.NewQHBoxLayout()
|
|
||||||
layout.AddLayout(kindHBox, 0)
|
|
||||||
kindLabel := widgets.NewQLabel2("kind:", nil, 0)
|
|
||||||
kindHBox.AddWidget(kindLabel, 0, 0)
|
|
||||||
kindSpin := widgets.NewQSpinBox(nil)
|
|
||||||
// TODO: set default value to 1
|
|
||||||
kindSpin.SetMinimum(0)
|
|
||||||
kindSpin.SetMaximum(1<<16 - 1)
|
|
||||||
kindHBox.AddWidget(kindSpin, 0, 0)
|
|
||||||
kindSpin.ConnectValueChanged(func(int) {
|
|
||||||
updateEvent()
|
|
||||||
})
|
|
||||||
kindNameLabel := widgets.NewQLabel2("", nil, 0)
|
|
||||||
kindHBox.AddWidget(kindNameLabel, 0, 0)
|
|
||||||
|
|
||||||
// content input
|
|
||||||
contentLabel := widgets.NewQLabel2("content:", nil, 0)
|
|
||||||
layout.AddWidget(contentLabel, 0, 0)
|
|
||||||
contentEdit := widgets.NewQTextEdit(nil)
|
|
||||||
layout.AddWidget(contentEdit, 0, 0)
|
|
||||||
contentEdit.ConnectTextChanged(updateEvent)
|
|
||||||
|
|
||||||
// created_at input
|
|
||||||
createdAtLabel := widgets.NewQLabel2("created at:", nil, 0)
|
|
||||||
layout.AddWidget(createdAtLabel, 0, 0)
|
|
||||||
createdAtEdit := widgets.NewQDateTimeEdit(nil)
|
|
||||||
createdAtEdit.SetDateTime(core.QDateTime_CurrentDateTime())
|
|
||||||
layout.AddWidget(createdAtEdit, 0, 0)
|
|
||||||
createdAtEdit.ConnectDateTimeChanged(func(*core.QDateTime) {
|
|
||||||
updateEvent()
|
|
||||||
})
|
|
||||||
|
|
||||||
// tags input
|
|
||||||
tagsLabel := widgets.NewQLabel2("tags:", nil, 0)
|
|
||||||
layout.AddWidget(tagsLabel, 0, 0)
|
|
||||||
tagsLayout := widgets.NewQVBoxLayout()
|
|
||||||
tagRowHBoxes := make([]widgets.QLayout_ITF, 0, 2)
|
|
||||||
layout.AddLayout(tagsLayout, 0)
|
|
||||||
|
|
||||||
var addTagRow func()
|
|
||||||
addTagRow = func() {
|
|
||||||
hbox := widgets.NewQHBoxLayout()
|
|
||||||
tagRowHBoxes = append(tagRowHBoxes, hbox)
|
|
||||||
tagsLayout.AddLayout(hbox, 0)
|
|
||||||
tagItems := []*widgets.QLineEdit{}
|
|
||||||
y := len(tagRows)
|
|
||||||
tagRows = append(tagRows, tagItems)
|
|
||||||
|
|
||||||
var addItem func()
|
|
||||||
addItem = func() {
|
|
||||||
edit := widgets.NewQLineEdit(nil)
|
|
||||||
hbox.AddWidget(edit, 0, 0)
|
|
||||||
x := len(tagItems)
|
|
||||||
tagItems = append(tagItems, edit)
|
|
||||||
tagRows[y] = tagItems
|
|
||||||
edit.ConnectTextChanged(func(text string) {
|
|
||||||
if strings.TrimSpace(text) != "" {
|
|
||||||
// when an item input has been filled check if we have to show more
|
|
||||||
if y == len(tagRows)-1 {
|
|
||||||
addTagRow()
|
|
||||||
}
|
|
||||||
if x == len(tagItems)-1 {
|
|
||||||
addItem()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// do this when an item input has been emptied: check if we need to remove an item from this row
|
|
||||||
nItems := len(tagItems)
|
|
||||||
if nItems >= 2 && strings.TrimSpace(tagItems[nItems-1].Text()) == "" && strings.TrimSpace(tagItems[nItems-2].Text()) == "" {
|
|
||||||
// remove last item if the last 2 are empty
|
|
||||||
hbox.Layout().RemoveWidget(tagItems[nItems-1])
|
|
||||||
tagItems[nItems-1].DeleteLater()
|
|
||||||
tagItems = tagItems[0 : nItems-1]
|
|
||||||
tagRows[y] = tagItems
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if we need to remove rows
|
|
||||||
nRows := len(tagRows)
|
|
||||||
itemIsFilled := func(edit *widgets.QLineEdit) bool { return strings.TrimSpace(edit.Text()) != "" }
|
|
||||||
if nRows >= 2 && !slices.ContainsFunc(tagRows[nRows-1], itemIsFilled) && !slices.ContainsFunc(tagRows[nRows-2], itemIsFilled) {
|
|
||||||
// remove the last row if the last 2 are empty
|
|
||||||
tagsLayout.RemoveItem(tagRowHBoxes[nRows-1])
|
|
||||||
for _, tagItem := range tagRows[nRows-1] {
|
|
||||||
tagItem.DeleteLater()
|
|
||||||
}
|
|
||||||
tagRowHBoxes[nRows-1].QLayout_PTR().DeleteLater()
|
|
||||||
tagRows = tagRows[0 : nRows-1]
|
|
||||||
tagRowHBoxes = tagRowHBoxes[0 : nRows-1]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
updateEvent()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
addItem()
|
|
||||||
}
|
|
||||||
|
|
||||||
// first
|
|
||||||
addTagRow()
|
|
||||||
|
|
||||||
// output JSON
|
|
||||||
outputLabel := widgets.NewQLabel2("event:", nil, 0)
|
|
||||||
layout.AddWidget(outputLabel, 0, 0)
|
|
||||||
outputEdit := widgets.NewQTextEdit(nil)
|
|
||||||
outputEdit.SetReadOnly(true)
|
|
||||||
layout.AddWidget(outputEdit, 0, 0)
|
|
||||||
|
|
||||||
// function to update the display
|
|
||||||
updateEvent = func() {
|
|
||||||
kind := nostr.Kind(kindSpin.Value())
|
|
||||||
kindName := kind.Name()
|
|
||||||
if kindName != "unknown" {
|
|
||||||
kindNameLabel.SetText(kindName)
|
|
||||||
} else {
|
|
||||||
kindNameLabel.SetText("")
|
|
||||||
}
|
|
||||||
tags := make(nostr.Tags, 0, len(tagRows))
|
|
||||||
for y, tagItems := range tagRows {
|
|
||||||
if y == len(tagRows)-1 && strings.TrimSpace(tagItems[0].Text()) == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
tag := make(nostr.Tag, 0, len(tagItems))
|
|
||||||
for x, edit := range tagItems {
|
|
||||||
text := strings.TrimSpace(edit.Text())
|
|
||||||
if x == len(tagItems)-1 && text == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
text = decodeTagValue(text)
|
|
||||||
tag = append(tag, text)
|
|
||||||
}
|
|
||||||
if len(tag) > 0 {
|
|
||||||
tags = append(tags, tag)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
event := nostr.Event{
|
|
||||||
Kind: kind,
|
|
||||||
Content: contentEdit.ToPlainText(),
|
|
||||||
CreatedAt: nostr.Timestamp(createdAtEdit.DateTime().ToMSecsSinceEpoch() / 1000),
|
|
||||||
Tags: tags,
|
|
||||||
}
|
|
||||||
|
|
||||||
if currentKeyer != nil {
|
|
||||||
// TODO:
|
|
||||||
// call debounced function that calls:
|
|
||||||
// currentKeyer.SignEvent(event)
|
|
||||||
// then the json.Marshal / outputEdit.SetPlainText
|
|
||||||
}
|
|
||||||
|
|
||||||
jsonBytes, _ := json.MarshalIndent(event, "", " ")
|
|
||||||
outputEdit.SetPlainText(string(jsonBytes))
|
|
||||||
}
|
|
||||||
|
|
||||||
// initial render
|
// initial render
|
||||||
updateEvent()
|
updateEvent()
|
||||||
|
|||||||
1
view/req.go
Normal file
1
view/req.go
Normal file
@@ -0,0 +1 @@
|
|||||||
|
package main
|
||||||
Reference in New Issue
Block a user