summaryrefslogtreecommitdiff
path: root/internal
diff options
context:
space:
mode:
Diffstat (limited to 'internal')
-rw-r--r--internal/client/ui/core/core.go40
-rw-r--r--internal/client/ui/core/networkjoin/networkjoin.go163
2 files changed, 195 insertions, 8 deletions
diff --git a/internal/client/ui/core/core.go b/internal/client/ui/core/core.go
index 46eaca5..3048375 100644
--- a/internal/client/ui/core/core.go
+++ b/internal/client/ui/core/core.go
@@ -18,6 +18,7 @@ import (
"github.com/kyren223/eko/internal/client/ui/core/frequencycreation"
"github.com/kyren223/eko/internal/client/ui/core/frequencylist"
"github.com/kyren223/eko/internal/client/ui/core/networkcreation"
+ "github.com/kyren223/eko/internal/client/ui/core/networkjoin"
"github.com/kyren223/eko/internal/client/ui/core/networklist"
"github.com/kyren223/eko/internal/client/ui/core/state"
"github.com/kyren223/eko/internal/client/ui/loadscreen"
@@ -53,6 +54,7 @@ type Model struct {
connected bool
networkCreationPopup *networkcreation.Model
+ networkJoinPopup *networkjoin.Model
frequencyCreationPopup *frequencycreation.Model
networkList networklist.Model
frequencyList frequencylist.Model
@@ -70,6 +72,7 @@ func New(privKey ed25519.PrivateKey, name string) Model {
timeout: initialTimeout,
connected: false,
networkCreationPopup: nil,
+ networkJoinPopup: nil,
frequencyCreationPopup: nil,
networkList: networklist.New(),
frequencyList: frequencylist.New(),
@@ -106,6 +109,8 @@ func (m Model) View() string {
popup = m.networkCreationPopup.View()
} else if m.frequencyCreationPopup != nil {
popup = m.frequencyCreationPopup.View()
+ } else if m.networkJoinPopup != nil {
+ popup = m.networkJoinPopup.View()
}
if popup != "" {
x := (ui.Width - lipgloss.Width(popup)) / 2
@@ -238,12 +243,11 @@ func (m *Model) updateConnected(msg tea.Msg) tea.Cmd {
}
case tea.KeyMsg:
- key := msg.Type
- switch key {
- case tea.KeyCtrlN:
+ switch msg.String() {
+ case "n":
switch m.focus {
case FocusNetworkList:
- if m.networkCreationPopup == nil {
+ if m.networkCreationPopup == nil && m.networkJoinPopup == nil {
popup := networkcreation.New()
m.networkCreationPopup = &popup
}
@@ -256,14 +260,22 @@ func (m *Model) updateConnected(msg tea.Msg) tea.Cmd {
}
}
- case tea.KeyEscape:
+ case "i":
+ if m.focus == FocusNetworkList && m.networkJoinPopup == nil && m.networkCreationPopup == nil {
+ popup := networkjoin.New()
+ m.networkJoinPopup = &popup
+ }
+
+ case "esc":
if m.networkCreationPopup != nil {
m.networkCreationPopup = nil
} else if m.frequencyCreationPopup != nil {
m.frequencyCreationPopup = nil
+ } else if m.networkJoinPopup != nil {
+ m.networkJoinPopup = nil
}
- case tea.KeyEnter:
+ case "enter":
if m.networkCreationPopup != nil {
cmd := m.networkCreationPopup.Select()
if cmd != nil {
@@ -276,6 +288,12 @@ func (m *Model) updateConnected(msg tea.Msg) tea.Cmd {
m.frequencyCreationPopup = nil
}
return cmd
+ } else if m.networkJoinPopup != nil {
+ cmd := m.networkJoinPopup.Select()
+ if cmd != nil {
+ m.networkJoinPopup = nil
+ }
+ return cmd
}
default:
@@ -287,6 +305,10 @@ func (m *Model) updateConnected(msg tea.Msg) tea.Cmd {
popup, cmd := m.frequencyCreationPopup.Update(msg)
m.frequencyCreationPopup = &popup
return cmd
+ } else if m.networkJoinPopup != nil {
+ popup, cmd := m.networkJoinPopup.Update(msg)
+ m.networkJoinPopup = &popup
+ return cmd
}
if m.focus != FocusChat || !m.chat.Locked() {
@@ -303,8 +325,10 @@ func (m *Model) updateConnected(msg tea.Msg) tea.Cmd {
}
}
- inPopup := m.networkCreationPopup != nil || m.frequencyCreationPopup != nil
- if inPopup {
+ isPopup := m.networkCreationPopup != nil ||
+ m.frequencyCreationPopup != nil ||
+ m.networkJoinPopup != nil
+ if isPopup {
return nil
}
diff --git a/internal/client/ui/core/networkjoin/networkjoin.go b/internal/client/ui/core/networkjoin/networkjoin.go
new file mode 100644
index 0000000..1df0db3
--- /dev/null
+++ b/internal/client/ui/core/networkjoin/networkjoin.go
@@ -0,0 +1,163 @@
+package networkjoin
+
+import (
+ "errors"
+ "strings"
+
+ tea "github.com/charmbracelet/bubbletea"
+ "github.com/charmbracelet/lipgloss"
+ "github.com/kyren223/eko/internal/client/gateway"
+ "github.com/kyren223/eko/internal/client/ui/colors"
+ "github.com/kyren223/eko/internal/client/ui/field"
+ "github.com/kyren223/eko/internal/client/ui/layouts/flex"
+ "github.com/kyren223/eko/internal/packet"
+ "github.com/kyren223/eko/pkg/assert"
+)
+
+var (
+ width = 48
+
+ style = lipgloss.NewStyle().
+ Border(lipgloss.ThickBorder()).
+ Padding(1, 4).
+ Align(lipgloss.Center, lipgloss.Center)
+
+ headerStyle = lipgloss.NewStyle().Foreground(colors.Turquoise)
+
+ fieldBlurredStyle = lipgloss.NewStyle().
+ PaddingLeft(1).
+ Border(lipgloss.RoundedBorder()).
+ BorderForeground(colors.DarkCyan)
+ fieldFocusedStyle = fieldBlurredStyle.
+ BorderForeground(colors.Focus).
+ Border(lipgloss.ThickBorder())
+
+ blurredCreate = lipgloss.NewStyle().
+ Background(colors.Gray).Padding(0, 1).Render("Join Network")
+ focusedCreate = lipgloss.NewStyle().
+ Background(colors.Blue).Padding(0, 1).Render("Join Network")
+)
+
+const (
+ MaxIconLength = 2
+ MaxHexDigits = 6
+)
+
+const (
+ NameField = iota
+ CreateField
+ FieldCount
+)
+
+type Model struct {
+ name field.Model
+ create string
+
+ selected int
+ nameWidth int
+}
+
+func New() Model {
+ name := field.New(width)
+ name.Header = "Network ID"
+ name.HeaderStyle = headerStyle
+ name.FocusedStyle = fieldFocusedStyle
+ name.BlurredStyle = fieldBlurredStyle
+ name.ErrorStyle = lipgloss.NewStyle().Foreground(colors.Error)
+ name.Input.CharLimit = width
+ name.Focus()
+ name.Input.Validate = func(s string) error {
+ if strings.TrimSpace(s) == "" {
+ return errors.New("cannot be empty")
+ }
+
+ return nil
+ }
+
+ nameWidth := lipgloss.Width(name.View())
+
+ return Model{
+ name: name,
+ create: blurredCreate,
+ nameWidth: nameWidth,
+ }
+}
+
+func (m Model) Init() tea.Cmd {
+ return nil
+}
+
+func (m Model) View() string {
+ name := m.name.View()
+ create := lipgloss.NewStyle().
+ Width(m.nameWidth).Align(lipgloss.Center).
+ Render(m.create)
+
+ content := flex.NewVertical(name, create).WithGap(1).View()
+ return style.Render(content)
+}
+
+func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
+ switch msg := msg.(type) {
+ case tea.KeyMsg:
+ key := msg.Type
+ switch key {
+ case tea.KeyTab:
+ return m, m.cycle(1)
+ case tea.KeyShiftTab:
+ return m, m.cycle(-1)
+
+ default:
+ var cmd tea.Cmd
+ switch m.selected {
+ case NameField:
+ m.name, cmd = m.name.Update(msg)
+ }
+ return m, cmd
+ }
+ }
+
+ return m, nil
+}
+
+func (m *Model) cycle(step int) tea.Cmd {
+ m.selected += step
+ if m.selected < 0 {
+ m.selected = FieldCount - 1
+ } else {
+ m.selected %= FieldCount
+ }
+ return m.updateFocus()
+}
+
+func (m *Model) updateFocus() tea.Cmd {
+ m.name.Blur()
+ m.create = blurredCreate
+ switch m.selected {
+ case NameField:
+ return m.name.Focus()
+ case CreateField:
+ m.create = focusedCreate
+ return nil
+ default:
+ assert.Never("missing switch statement field in update focus", "selected", m.selected)
+ return nil
+ }
+}
+
+func (m *Model) Select() tea.Cmd {
+ if m.selected != CreateField {
+ return nil
+ }
+
+ m.name.Input.Err = m.name.Input.Validate(m.name.Input.Value())
+ if m.name.Input.Err != nil {
+ return nil
+ }
+
+ // TODO: change this to actual invite packet
+ request := packet.CreateNetwork{
+ Name: m.name.Input.Value(),
+ }
+ return gateway.Send(&request)
+}