refactor(ui): adapt to tview input changes
This commit is contained in:
parent
7d66f3b20b
commit
be5aebdd14
7 changed files with 66 additions and 29 deletions
2
go.mod
2
go.mod
|
|
@ -10,7 +10,7 @@ require (
|
|||
github.com/andybalholm/brotli v1.2.2
|
||||
github.com/ayn2op/arikawa/v3 v3.0.0-20260708075022-9cc760fe507e
|
||||
github.com/ayn2op/ningen/v3 v3.0.1-0.20260708075321-0ba1ffc70bd6
|
||||
github.com/ayn2op/tview v0.0.0-20260807213801-ef1b0c0bb239
|
||||
github.com/ayn2op/tview v0.0.0-20260808011018-71a6ffd9ad39
|
||||
github.com/bogdanfinn/fhttp v0.6.8
|
||||
github.com/bogdanfinn/tls-client v1.15.1
|
||||
github.com/gdamore/tcell/v3 v3.4.1
|
||||
|
|
|
|||
4
go.sum
4
go.sum
|
|
@ -14,8 +14,8 @@ github.com/ayn2op/arikawa/v3 v3.0.0-20260708075022-9cc760fe507e h1:rsMifRXwxkbha
|
|||
github.com/ayn2op/arikawa/v3 v3.0.0-20260708075022-9cc760fe507e/go.mod h1:gqklpHK7WHYTzpd1ZY6Ho/p9GURBghzBCzRiBYpaUP8=
|
||||
github.com/ayn2op/ningen/v3 v3.0.1-0.20260708075321-0ba1ffc70bd6 h1:/khHm6G+GWwXpmwA8bJoaXoUhubqMEUG6spjZsnklIw=
|
||||
github.com/ayn2op/ningen/v3 v3.0.1-0.20260708075321-0ba1ffc70bd6/go.mod h1:vqLIvETLkjc2vIgQzVEBqpGNCrgNe7YJqS9TUAJsXRI=
|
||||
github.com/ayn2op/tview v0.0.0-20260807213801-ef1b0c0bb239 h1:xxtbWv2Rp8DvHu9MSd0ChChR0mRifSQVlzYb3QFIwR4=
|
||||
github.com/ayn2op/tview v0.0.0-20260807213801-ef1b0c0bb239/go.mod h1:bJZdl/FfspPLEW3nuX6ubt7YbmDoSj7f2IoWH37w1NE=
|
||||
github.com/ayn2op/tview v0.0.0-20260808011018-71a6ffd9ad39 h1:SOzvhkwbIQtlIkRUUFTBKdnECPuFjUBqptO8Pe7aP9Q=
|
||||
github.com/ayn2op/tview v0.0.0-20260808011018-71a6ffd9ad39/go.mod h1:bJZdl/FfspPLEW3nuX6ubt7YbmDoSj7f2IoWH37w1NE=
|
||||
github.com/bdandy/go-errors v1.2.2 h1:WdFv/oukjTJCLa79UfkGmwX7ZxONAihKu4V0mLIs11Q=
|
||||
github.com/bdandy/go-errors v1.2.2/go.mod h1:NkYHl4Fey9oRRdbB1CoC6e84tuqQHiqrOcZpqFEkBxM=
|
||||
github.com/bdandy/go-socks4 v1.2.3 h1:Q6Y2heY1GRjCtHbmlKfnwrKVU/k81LS8mRGLRlmDlic=
|
||||
|
|
|
|||
|
|
@ -86,8 +86,6 @@ func newComposer(cfg *config.Config, chat *Model) *composer {
|
|||
return c
|
||||
}
|
||||
|
||||
// forwardToTextArea passes a key event to the embedded TextArea then resizes for the new content.
|
||||
// SetChangedFunc isn't used: it fires inside replace's defer, before truncateLines/findCursor, so it would observe stale state.
|
||||
func (c *composer) forwardToTextArea(ev *tcell.EventKey) tview.Cmd {
|
||||
cmd := c.TextArea.Update(ev)
|
||||
c.resizeForContent()
|
||||
|
|
|
|||
|
|
@ -83,7 +83,6 @@ func newMessagesList(cfg *config.Config, chat *Model) *messagesList {
|
|||
ui.ConfigureBox(ml.Box, &cfg.Theme)
|
||||
ml.SetTitle("Messages")
|
||||
ml.SetBuilder(ml.buildItem)
|
||||
ml.SetChangedFunc(ml.onRowCursorChanged)
|
||||
ml.SetTrackEnd(true)
|
||||
ml.SetSelectedStyle(cfg.Theme.MessagesList.SelectedMessageStyle.Style)
|
||||
ml.SetKeybinds(list.Keybinds{
|
||||
|
|
@ -887,8 +886,6 @@ func (ml *messagesList) Update(msg tview.Msg) tview.Cmd {
|
|||
case keybind.Matches(msg, ml.cfg.Keybinds.MessagesList.DeleteConfirm.Keybind):
|
||||
return ml.confirmDelete()
|
||||
}
|
||||
return ml.Model.Update(msg)
|
||||
|
||||
case olderMessagesLoadedMsg:
|
||||
selectedChannel, ok := ml.chat.SelectedChannel()
|
||||
if !ok || selectedChannel.ID != msg.ChannelID {
|
||||
|
|
@ -918,7 +915,9 @@ func (ml *messagesList) Update(msg tview.Msg) tview.Cmd {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
return ml.Model.Update(msg)
|
||||
cmd := ml.Model.Update(msg)
|
||||
ml.onRowCursorChanged(ml.Model.Cursor())
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (ml *messagesList) selectUp() tview.Cmd {
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ type Model struct {
|
|||
fingerprint string
|
||||
|
||||
qrCode *qrcode.QRCode
|
||||
msg string
|
||||
status string
|
||||
}
|
||||
|
||||
func NewModel() *Model {
|
||||
|
|
@ -33,7 +33,7 @@ func NewModel() *Model {
|
|||
SetWrap(false).
|
||||
SetTextAlign(tview.AlignmentCenter)
|
||||
|
||||
m.msg = "Press Ctrl+N to open QR login"
|
||||
m.setStatus("Press Ctrl+N to open QR login")
|
||||
return m
|
||||
}
|
||||
|
||||
|
|
@ -46,18 +46,18 @@ func (m *Model) Label() string {
|
|||
func (m *Model) Update(msg tview.Msg) tview.Cmd {
|
||||
switch msg := msg.(type) {
|
||||
case tview.InitMsg:
|
||||
m.msg = "Connecting to Remote Auth Gateway..."
|
||||
m.setStatus("Connecting to Remote Auth Gateway...")
|
||||
return m.connect()
|
||||
case tview.KeyMsg:
|
||||
if msg.Key() == tcell.KeyEsc {
|
||||
m.msg = "Canceled"
|
||||
m.setStatus("Canceled")
|
||||
return m.close()
|
||||
}
|
||||
return m.TextView.Update(msg)
|
||||
|
||||
case connCreateMsg:
|
||||
m.conn = msg.conn
|
||||
m.msg = "Connected. Handshaking..."
|
||||
m.setStatus("Connected. Handshaking...")
|
||||
return m.listen()
|
||||
case connCloseMsg:
|
||||
m.conn = nil
|
||||
|
|
@ -76,7 +76,7 @@ func (m *Model) Update(msg tview.Msg) tview.Cmd {
|
|||
return tview.Batch(m.listen(), m.generateQRCode(msg.fingerprint))
|
||||
case qrCodeMsg:
|
||||
m.qrCode = msg.qrCode
|
||||
m.msg = "Scan this with the Discord mobile app to log in instantly."
|
||||
m.setStatus("Scan this with the Discord mobile app to log in instantly.")
|
||||
return m.listen()
|
||||
case pendingTicketMsg:
|
||||
return tview.Batch(m.listen(), m.decryptUserPayload(msg.encryptedUserPayload))
|
||||
|
|
@ -85,13 +85,13 @@ func (m *Model) Update(msg tview.Msg) tview.Cmd {
|
|||
if msg.discriminator != "0" {
|
||||
name += "#" + msg.discriminator
|
||||
}
|
||||
m.msg = "Check your phone! Logging in as " + name
|
||||
m.setStatus("Check your phone! Logging in as " + name)
|
||||
return m.listen()
|
||||
case pendingLoginMsg:
|
||||
m.msg = "Authenticating..."
|
||||
m.setStatus("Authenticating...")
|
||||
return tview.Batch(m.close(), m.exchangeTicket(msg.ticket))
|
||||
case cancelMsg:
|
||||
m.msg = "Login canceled on mobile"
|
||||
m.setStatus("Login canceled on mobile")
|
||||
return m.close()
|
||||
|
||||
case heartbeatTickMsg:
|
||||
|
|
@ -101,7 +101,7 @@ func (m *Model) Update(msg tview.Msg) tview.Cmd {
|
|||
return tview.Batch(m.heartbeat(), m.sendHeartbeat())
|
||||
|
||||
case errMsg:
|
||||
m.msg = msg.Error()
|
||||
m.setStatus(msg.Error())
|
||||
return m.close()
|
||||
}
|
||||
|
||||
|
|
@ -123,28 +123,46 @@ func halfBlock(top, bottom bool) rune {
|
|||
}
|
||||
}
|
||||
|
||||
func (m *Model) View(screen tcell.Screen) {
|
||||
var contents []string
|
||||
func (m *Model) SetRect(x, y, width, height int) {
|
||||
_, _, _, oldHeight := m.Rect()
|
||||
m.TextView.SetRect(x, y, width, height)
|
||||
if oldHeight != height {
|
||||
m.render()
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Model) setStatus(status string) {
|
||||
m.status = status
|
||||
m.render()
|
||||
}
|
||||
|
||||
func (m *Model) render() {
|
||||
var text strings.Builder
|
||||
if m.qrCode != nil {
|
||||
bitmap := m.qrCode.Bitmap()
|
||||
var b strings.Builder
|
||||
for y := 0; y < len(bitmap); y += 2 {
|
||||
for x := range bitmap[y] {
|
||||
top := bitmap[y][x]
|
||||
bottom := y+1 < len(bitmap) && bitmap[y+1][x]
|
||||
b.WriteRune(halfBlock(top, bottom))
|
||||
text.WriteRune(halfBlock(top, bottom))
|
||||
}
|
||||
b.WriteByte('\n')
|
||||
text.WriteByte('\n')
|
||||
}
|
||||
contents = append(contents, b.String())
|
||||
}
|
||||
if m.msg != "" {
|
||||
contents = append(contents, m.msg)
|
||||
if m.status != "" {
|
||||
if text.Len() > 0 {
|
||||
text.WriteByte('\n')
|
||||
}
|
||||
text.WriteString(m.status)
|
||||
}
|
||||
|
||||
builder := tview.NewLineBuilder()
|
||||
builder.Write(strings.Join(contents, "\n"), tcell.StyleDefault)
|
||||
builder.Write(text.String(), tcell.StyleDefault)
|
||||
m.SetLines(m.centerLines(builder.Finish()))
|
||||
m.TextView.SetRect(m.Rect())
|
||||
}
|
||||
|
||||
func (m *Model) View(screen tcell.Screen) {
|
||||
m.TextView.View(screen)
|
||||
}
|
||||
|
||||
|
|
|
|||
22
internal/ui/login/qr/model_test.go
Normal file
22
internal/ui/login/qr/model_test.go
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
package qr
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/skip2/go-qrcode"
|
||||
)
|
||||
|
||||
func TestSetRectRendersContent(t *testing.T) {
|
||||
m := NewModel()
|
||||
code, err := qrcode.New("test", qrcode.Low)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
m.qrCode = code
|
||||
m.SetRect(0, 0, 80, 24)
|
||||
text := m.Text()
|
||||
if !strings.Contains(text, m.status) || !strings.ContainsAny(text, "█▀▄") {
|
||||
t.Fatal("missing content")
|
||||
}
|
||||
}
|
||||
|
|
@ -155,7 +155,7 @@ func (m *Model) Update(msg tview.Msg) tview.Cmd {
|
|||
}
|
||||
return tview.Sequence(innerCmd, tview.Quit())
|
||||
}
|
||||
case tview.MouseMsg, tview.PasteMsg, tview.FormSubmitMsg, tview.FormCancelMsg, tview.ButtonExitMsg:
|
||||
case tview.MouseMsg, tview.PasteMsg, tview.FormSubmitMsg, tview.FormCancelMsg:
|
||||
if m.modalRequest != nil {
|
||||
return m.Layers.Update(msg)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue