refactor(ui): replace tview modal usage
This commit is contained in:
parent
c1af115e27
commit
391f3b974c
6 changed files with 93 additions and 54 deletions
10
go.mod
10
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-20260708025551-16f85f97975e
|
||||
github.com/ayn2op/tview v0.0.0-20260709081114-77dc5f1dd56c
|
||||
github.com/deckarep/gosx-notifier v0.0.0-20180201035817-e127226297fb
|
||||
github.com/gdamore/tcell/v3 v3.4.1-0.20260703160154-d85b1fbd48b8
|
||||
github.com/gen2brain/beeep v0.11.2
|
||||
|
|
@ -55,10 +55,10 @@ require (
|
|||
go4.org v0.0.0-20260112195520-a5071408f32f // indirect
|
||||
golang.design/x/x11 v0.2.0 // indirect
|
||||
golang.org/x/exp/shiny v0.0.0-20260611194520-c48552f49976 // indirect
|
||||
golang.org/x/image v0.43.0 // indirect
|
||||
golang.org/x/image v0.44.0 // indirect
|
||||
golang.org/x/mobile v0.0.0-20260611195102-4dd8f1dbf5d2 // indirect
|
||||
golang.org/x/sys v0.46.0 // indirect
|
||||
golang.org/x/term v0.44.0 // indirect
|
||||
golang.org/x/text v0.39.0 // indirect
|
||||
golang.org/x/sys v0.47.0 // indirect
|
||||
golang.org/x/term v0.45.0 // indirect
|
||||
golang.org/x/text v0.40.0 // indirect
|
||||
golang.org/x/time v0.15.0 // indirect
|
||||
)
|
||||
|
|
|
|||
20
go.sum
20
go.sum
|
|
@ -16,8 +16,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-20260708025551-16f85f97975e h1:WVf0fqBMetR5F5VoA1lMvRpSX25YUyekaNwaWXieW7c=
|
||||
github.com/ayn2op/tview v0.0.0-20260708025551-16f85f97975e/go.mod h1:kBq8YDymQUJsGxUfhatCnwc1XU0z1tXjSLNpGpzcMp8=
|
||||
github.com/ayn2op/tview v0.0.0-20260709081114-77dc5f1dd56c h1:hX1fxRak+RQnwWjeTVv7xuuOxqBxrT5ITM+reIq5eKs=
|
||||
github.com/ayn2op/tview v0.0.0-20260709081114-77dc5f1dd56c/go.mod h1:kBq8YDymQUJsGxUfhatCnwc1XU0z1tXjSLNpGpzcMp8=
|
||||
github.com/clipperhouse/displaywidth v0.11.0 h1:lBc6kY44VFw+TDx4I8opi/EtL9m20WSEFgwIwO+UVM8=
|
||||
github.com/clipperhouse/displaywidth v0.11.0/go.mod h1:bkrFNkf81G8HyVqmKGxsPufD3JhNl3dSqnGhOoSD/o0=
|
||||
github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk=
|
||||
|
|
@ -123,8 +123,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
|
|||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/exp/shiny v0.0.0-20260611194520-c48552f49976 h1:xAKfctaZuXDxw/I98uYRl7TXMBy4a1BgPgl7NavbrdY=
|
||||
golang.org/x/exp/shiny v0.0.0-20260611194520-c48552f49976/go.mod h1:UXxgIHNj0uSRIk9ua62CRJcUpfHN9V+cRZRXHEo4GhE=
|
||||
golang.org/x/image v0.43.0 h1:FLxcP4ec2350nTfOC8ysKtqYSIFbk/QGjw1ZHNP4tsY=
|
||||
golang.org/x/image v0.43.0/go.mod h1:rrpelvGFt+kLPAjPM4HeWPgrl0FtafueU//e5N0qk/Q=
|
||||
golang.org/x/image v0.44.0 h1:+tDekMZED9+LrtB3G5xzRggpVh9CARjZqROla3R3R+I=
|
||||
golang.org/x/image v0.44.0/go.mod h1:V8K3KE9KKKE+pLpQDOeN18w9oacNSvy1tDOirTu4xtY=
|
||||
golang.org/x/mobile v0.0.0-20260611195102-4dd8f1dbf5d2 h1:zoM1gIKhVkcQNm43kad8OHLgPNoJ12xIqmxHtKr8Mug=
|
||||
golang.org/x/mobile v0.0.0-20260611195102-4dd8f1dbf5d2/go.mod h1:QGMqsqLn6orFQ/ksqYMf+Fa33Soa1vPoHEd0Pj7N+lQ=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
|
|
@ -143,20 +143,20 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw=
|
||||
golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs=
|
||||
golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc=
|
||||
golang.org/x/term v0.44.0/go.mod h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y=
|
||||
golang.org/x/term v0.45.0 h1:NwWyBmoJCbfTHpxrWoZ9C6/VxOf7ic219I8xZZFdrf0=
|
||||
golang.org/x/term v0.45.0/go.mod h1:9aqxs0blBcrm/n0L9QW0aRVD+ktan8ssZromtqJC43w=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.39.0 h1:UbZz4pLOvn600D6Oh6GGEI6VAmndrEBLv8/6BEXzyus=
|
||||
golang.org/x/text v0.39.0/go.mod h1:3UwRclnC2g0TU9x8PZiyfOajCd1zaUNHF9cvqcQZ+ZM=
|
||||
golang.org/x/text v0.40.0 h1:Ub2Z6/xjgF1WrYQz2nuITOEegKFtiIy+rieRJ5lHZKs=
|
||||
golang.org/x/text v0.40.0/go.mod h1:hpnzDAfGV753zIKo+wk3u1bVKCGPbrnF7+7LBF/UHVY=
|
||||
golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
|
||||
golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
|
|
|
|||
|
|
@ -1278,7 +1278,7 @@ func (ml *messagesList) confirmDelete() {
|
|||
}
|
||||
}
|
||||
|
||||
ml.chat.showConfirmModal(
|
||||
ml.chat.showConfirmDialog(
|
||||
"Are you sure you want to delete this message?",
|
||||
[]string{"Yes", "No"},
|
||||
onChoice,
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import (
|
|||
"github.com/ayn2op/ningen/v3/states/read"
|
||||
"github.com/ayn2op/tview"
|
||||
"github.com/ayn2op/tview/flex"
|
||||
"github.com/ayn2op/tview/frame"
|
||||
"github.com/ayn2op/tview/keybind"
|
||||
"github.com/ayn2op/tview/layers"
|
||||
"github.com/gdamore/tcell/v3"
|
||||
|
|
@ -29,9 +30,9 @@ import (
|
|||
const typingDuration = 10 * time.Second
|
||||
|
||||
const (
|
||||
flexLayerName = "flex"
|
||||
mentionsListLayerName = "mentionsList"
|
||||
confirmModalLayerName = "confirmModal"
|
||||
flexLayerName = "flex"
|
||||
mentionsListLayerName = "mentionsList"
|
||||
confirmDialogLayerName = "confirmDialog"
|
||||
|
||||
channelsPickerLayerName = "channelsPicker"
|
||||
attachmentsPickerLayerName = "attachmentsPicker"
|
||||
|
|
@ -53,8 +54,8 @@ type Model struct {
|
|||
selectedChannel *discord.Channel
|
||||
selectedChannelMu sync.RWMutex
|
||||
|
||||
confirmModalDone func(label string)
|
||||
confirmModalPreviousFocus tview.Model
|
||||
confirmDialogDone func(label string)
|
||||
confirmDialogPreviousFocus tview.Model
|
||||
|
||||
state *ningen.State
|
||||
events chan gateway.Event
|
||||
|
|
@ -318,21 +319,36 @@ func (m *Model) Update(msg tview.Msg) tview.Cmd {
|
|||
return focusCmd
|
||||
case QuitMsg:
|
||||
return m.closeState()
|
||||
case tview.ModalDoneMsg:
|
||||
if m.HasLayer(confirmModalLayerName) {
|
||||
m.RemoveLayer(confirmModalLayerName)
|
||||
case tview.FormSubmitMsg:
|
||||
if m.HasLayer(confirmDialogLayerName) {
|
||||
m.RemoveLayer(confirmDialogLayerName)
|
||||
var focusCmd tview.Cmd
|
||||
if m.confirmModalPreviousFocus != nil {
|
||||
focusCmd = tview.SetFocus(m.confirmModalPreviousFocus)
|
||||
if m.confirmDialogPreviousFocus != nil {
|
||||
focusCmd = tview.SetFocus(m.confirmDialogPreviousFocus)
|
||||
}
|
||||
onDone := m.confirmModalDone
|
||||
m.confirmModalDone = nil
|
||||
m.confirmModalPreviousFocus = nil
|
||||
onDone := m.confirmDialogDone
|
||||
m.confirmDialogDone = nil
|
||||
m.confirmDialogPreviousFocus = nil
|
||||
if onDone != nil {
|
||||
onDone(msg.ButtonLabel)
|
||||
}
|
||||
return focusCmd
|
||||
}
|
||||
case tview.FormCancelMsg:
|
||||
if m.HasLayer(confirmDialogLayerName) {
|
||||
m.RemoveLayer(confirmDialogLayerName)
|
||||
var focusCmd tview.Cmd
|
||||
if m.confirmDialogPreviousFocus != nil {
|
||||
focusCmd = tview.SetFocus(m.confirmDialogPreviousFocus)
|
||||
}
|
||||
onDone := m.confirmDialogDone
|
||||
m.confirmDialogDone = nil
|
||||
m.confirmDialogPreviousFocus = nil
|
||||
if onDone != nil {
|
||||
onDone("")
|
||||
}
|
||||
return focusCmd
|
||||
}
|
||||
case tview.KeyMsg:
|
||||
switch {
|
||||
case keybind.Matches(msg, m.cfg.Keybinds.FocusGuildsTree.Keybind):
|
||||
|
|
@ -366,22 +382,27 @@ func (m *Model) Update(msg tview.Msg) tview.Cmd {
|
|||
return m.Layers.Update(msg)
|
||||
}
|
||||
|
||||
func (m *Model) showConfirmModal(prompt string, buttons []string, onDone func(label string)) {
|
||||
m.confirmModalPreviousFocus = m.app.Focused()
|
||||
m.confirmModalDone = onDone
|
||||
func (m *Model) showConfirmDialog(prompt string, buttons []string, onDone func(label string)) {
|
||||
m.confirmDialogPreviousFocus = m.app.Focused()
|
||||
m.confirmDialogDone = onDone
|
||||
|
||||
modal := tview.NewModal().
|
||||
SetText(prompt).
|
||||
AddButtons(buttons)
|
||||
form := tview.NewForm().SetButtonsAlignment(tview.AlignmentCenter)
|
||||
for _, button := range buttons {
|
||||
form.AddButton(button)
|
||||
}
|
||||
dialog := frame.NewModel(form).SetBorders(0, 0, 1, 0, 0, 0)
|
||||
for _, line := range tview.WordWrap(prompt, 80) {
|
||||
dialog.AddText(line, true, tview.AlignmentCenter, tview.Styles.PrimaryTextColor)
|
||||
}
|
||||
m.
|
||||
AddLayer(
|
||||
ui.Centered(modal, 0, 0),
|
||||
layers.WithName(confirmModalLayerName),
|
||||
ui.Centered(dialog, 0, 0),
|
||||
layers.WithName(confirmDialogLayerName),
|
||||
layers.WithResize(true),
|
||||
layers.WithVisible(true),
|
||||
layers.WithOverlay(),
|
||||
).
|
||||
SendToFront(confirmModalLayerName)
|
||||
SendToFront(confirmDialogLayerName)
|
||||
}
|
||||
|
||||
func (m *Model) clearTypers() {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package login
|
|||
import (
|
||||
"log/slog"
|
||||
|
||||
"github.com/ayn2op/tview/frame"
|
||||
"github.com/ayn2op/tview/layers"
|
||||
"github.com/ayn2op/tview/tabs"
|
||||
"github.com/gdamore/tcell/v3"
|
||||
|
|
@ -23,8 +24,8 @@ type Model struct {
|
|||
*layers.Layers
|
||||
tabs *tabs.Model
|
||||
|
||||
cfg *config.Config
|
||||
errorModalText string
|
||||
cfg *config.Config
|
||||
errorDialogText string
|
||||
}
|
||||
|
||||
func NewModel(cfg *config.Config) *Model {
|
||||
|
|
@ -48,15 +49,22 @@ func (m *Model) Update(msg tview.Msg) tview.Cmd {
|
|||
return nil
|
||||
}
|
||||
return m.showErrorDialog(msg.err)
|
||||
case tview.ModalDoneMsg:
|
||||
case tview.FormSubmitMsg:
|
||||
if !m.HasLayer(errorLayerName) {
|
||||
return nil
|
||||
}
|
||||
if msg.ButtonIndex == 0 {
|
||||
return setClipboard(m.errorModalText)
|
||||
return setClipboard(m.errorDialogText)
|
||||
}
|
||||
m.RemoveLayer(errorLayerName)
|
||||
m.errorModalText = ""
|
||||
m.errorDialogText = ""
|
||||
return nil
|
||||
case tview.FormCancelMsg:
|
||||
if !m.HasLayer(errorLayerName) {
|
||||
return nil
|
||||
}
|
||||
m.RemoveLayer(errorLayerName)
|
||||
m.errorDialogText = ""
|
||||
return nil
|
||||
}
|
||||
return m.Layers.Update(msg)
|
||||
|
|
@ -66,34 +74,43 @@ func (m *Model) showErrorDialog(err error) tview.Cmd {
|
|||
slog.Error("failed to login", "err", err)
|
||||
|
||||
message := err.Error()
|
||||
m.errorModalText = message
|
||||
modal := tview.NewModal().
|
||||
SetText(message).
|
||||
AddButtons([]string{"Copy", "Close"})
|
||||
m.errorDialogText = message
|
||||
form := tview.NewForm().
|
||||
SetButtonsAlignment(tview.AlignmentCenter).
|
||||
AddButton("Copy").
|
||||
AddButton("Close")
|
||||
dialog := frame.NewModel(form).SetBorders(0, 0, 1, 0, 0, 0)
|
||||
for _, line := range tview.WordWrap(message, 80) {
|
||||
dialog.AddText(line, true, tview.AlignmentCenter, tview.Styles.PrimaryTextColor)
|
||||
}
|
||||
{
|
||||
bg := m.cfg.Theme.Dialog.Style.GetBackground()
|
||||
buttonStyle := m.cfg.Theme.Dialog.Style.Style
|
||||
if bg != tcell.ColorDefault {
|
||||
modal.SetBackgroundColor(bg)
|
||||
form.SetBackgroundColor(bg)
|
||||
dialog.SetBackgroundColor(bg)
|
||||
buttonStyle = buttonStyle.Background(bg)
|
||||
}
|
||||
fg := m.cfg.Theme.Dialog.Style.GetForeground()
|
||||
if fg != tcell.ColorDefault {
|
||||
modal.SetTextColor(fg)
|
||||
dialog.Clear()
|
||||
for _, line := range tview.WordWrap(message, 80) {
|
||||
dialog.AddText(line, true, tview.AlignmentCenter, fg)
|
||||
}
|
||||
buttonStyle = buttonStyle.Foreground(fg)
|
||||
}
|
||||
// Keep button styles aligned with dialog content and still show focus.
|
||||
modal.SetButtonStyle(buttonStyle)
|
||||
modal.SetButtonActivatedStyle(buttonStyle.Reverse(true))
|
||||
form.SetButtonStyle(buttonStyle)
|
||||
form.SetButtonActivatedStyle(buttonStyle.Reverse(true))
|
||||
}
|
||||
m.
|
||||
AddLayer(
|
||||
ui.Centered(modal, 0, 0),
|
||||
ui.Centered(dialog, 0, 0),
|
||||
layers.WithName(errorLayerName),
|
||||
layers.WithResize(true),
|
||||
layers.WithVisible(true),
|
||||
layers.WithOverlay(),
|
||||
).
|
||||
SendToFront(errorLayerName)
|
||||
return tview.SetFocus(modal)
|
||||
return tview.SetFocus(dialog)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import (
|
|||
"github.com/ayn2op/discordo/internal/config"
|
||||
"github.com/ayn2op/ningen/v3"
|
||||
"github.com/ayn2op/tview"
|
||||
"github.com/ayn2op/tview/grid"
|
||||
)
|
||||
|
||||
// ConfigureBox configures the provided box according to the provided theme.
|
||||
|
|
@ -55,7 +56,7 @@ func ConfigureBox(box *tview.Box, cfg *config.Theme) *tview.Box {
|
|||
|
||||
// Centered creates a new grid with provided primitive aligned in the center.
|
||||
func Centered(m tview.Model, width, height int) tview.Model {
|
||||
return tview.NewGrid().
|
||||
return grid.NewModel().
|
||||
SetColumns(0, width, 0).
|
||||
SetRows(0, height, 0).
|
||||
AddItem(m, 1, 1, 1, 1, 0, 0, true)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue