diff options
| author | Kyren223 <Kyren223@proton.me> | 2024-12-04 18:35:11 +0200 |
|---|---|---|
| committer | Kyren223 <Kyren223@proton.me> | 2024-12-04 18:35:11 +0200 |
| commit | 37cd043920aa92189d9ae19e7631968290e4d352 (patch) | |
| tree | 62282034ca56a52bbe36634d77932beaefa5d0ef /internal/client/ui | |
| parent | 567d569dd649cc0b82d6f8890e2bd77b052ebed6 (diff) | |
Started work on basic vim input box
Diffstat (limited to 'internal/client/ui')
| -rw-r--r-- | internal/client/ui/chat/chat.go | 130 | ||||
| -rw-r--r-- | internal/client/ui/core/chat/chat.go | 48 | ||||
| -rw-r--r-- | internal/client/ui/core/core.go | 20 | ||||
| -rw-r--r-- | internal/client/ui/core/network/network.go | 12 | ||||
| -rw-r--r-- | internal/client/ui/messagebox/messagebox.go | 131 | ||||
| -rw-r--r-- | internal/client/ui/viminput/linedecorations.go | 17 | ||||
| -rw-r--r-- | internal/client/ui/viminput/viminput.go | 89 |
7 files changed, 175 insertions, 272 deletions
diff --git a/internal/client/ui/chat/chat.go b/internal/client/ui/chat/chat.go deleted file mode 100644 index c69d0fd..0000000 --- a/internal/client/ui/chat/chat.go +++ /dev/null @@ -1,130 +0,0 @@ -package chat - -import ( - "fmt" - "log" - "strings" - - "github.com/charmbracelet/bubbles/cursor" - "github.com/charmbracelet/bubbles/textarea" - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" - - "github.com/kyren223/eko/internal/client/api" - "github.com/kyren223/eko/internal/client/ui/messagebox" - "github.com/kyren223/eko/internal/data" - "github.com/kyren223/eko/internal/packet" -) - -type Model struct { - messagebox messagebox.Model - textarea textarea.Model - err error -} - -func New() Model { - ta := textarea.New() - ta.Placeholder = "Send a message..." - ta.Focus() - - ta.Prompt = "┃ " - ta.CharLimit = 280 - - ta.SetWidth(30) - ta.SetHeight(3) - - // Remove cursor line styling - ta.FocusedStyle.CursorLine = lipgloss.NewStyle() - - ta.ShowLineNumbers = false - - ta.KeyMap.InsertNewline.SetEnabled(false) - - return Model{ - textarea: ta, - messagebox: messagebox.New(30, 20), - err: nil, - } -} - -func (m Model) Init() tea.Cmd { - return tea.Batch(textarea.Blink, api.GetMessages) -} - -func (m Model) View() string { - return fmt.Sprintf( - "%s\n%s", - m.messagebox.View(), - m.textarea.View(), - ) + "" -} - -func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) { - switch msg := msg.(type) { - case tea.WindowSizeMsg: - m.messagebox.Viewport.Width = msg.Width - m.messagebox.Viewport.Height = msg.Height - m.textarea.Height() - m.messagebox.Viewport.GotoBottom() - - m.textarea.SetWidth(msg.Width) - log.Println("resized to:", msg.Width, "x", msg.Height) - - var mbCmd, taCmd tea.Cmd - m.messagebox, mbCmd = m.messagebox.Update(msg) - m.textarea, taCmd = m.textarea.Update(msg) - return m, tea.Batch(mbCmd, taCmd) - - case tea.KeyMsg: - switch msg.Type { - - case tea.KeyEnter: - value := m.textarea.Value() - - content := strings.TrimSpace(value) - if content == "" { - return m, nil - } - m.textarea.Reset() - - return m, api.SendMessage(content) - - default: - var cmd tea.Cmd - m.textarea, cmd = m.textarea.Update(msg) - return m, cmd - } - - case packet.Payload: - switch msg := msg.(type) { - case *packet.Messages: - m.messagebox.SetMessages(msg.Messages) - - var cmd tea.Cmd - m.messagebox, cmd = m.messagebox.Update(msg) - return m, cmd - - default: - return m, nil - } - - case api.AppendMessage: - m.messagebox.AppendMessage(data.Message(msg)) - - var cmd tea.Cmd - m.messagebox, cmd = m.messagebox.Update(msg) - return m, cmd - - case api.UserProfileUpdate: - var cmd tea.Cmd - m.messagebox, cmd = m.messagebox.Update(msg) - return m, cmd - - case cursor.BlinkMsg: - var cmd tea.Cmd - m.textarea, cmd = m.textarea.Update(msg) - return m, cmd - - default: - return m, nil - } -} diff --git a/internal/client/ui/core/chat/chat.go b/internal/client/ui/core/chat/chat.go new file mode 100644 index 0000000..b3597a8 --- /dev/null +++ b/internal/client/ui/core/chat/chat.go @@ -0,0 +1,48 @@ +package chat + +import ( + "log" + + "github.com/charmbracelet/bubbles/textarea" + tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/lipgloss" + + "github.com/kyren223/eko/internal/client/ui/colors" + "github.com/kyren223/eko/internal/client/ui/viminput" +) + +type Model struct { + vi viminput.Model +} + +func New() Model { + vi := viminput.New(30, 3) + vi.Placeholder = "Send a message..." + vi.PlaceholderStyle = lipgloss.NewStyle().Foreground(colors.Gray) + vi.LineDecoration = func(lnum int, line string, cursorLnum int) string { + return "┃ " + } + // vi.ShowLineNumbers = false + + // vi.CharLimit = 280 + + // vi.Focus() + + log.Println("Placeholder:", vi.Placeholder) + + return Model{ + vi: vi, + } +} + +func (m Model) Init() tea.Cmd { + return tea.Batch(textarea.Blink, nil) +} + +func (m Model) View() string { + return m.vi.View() +} + +func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) { + return m, nil +} diff --git a/internal/client/ui/core/core.go b/internal/client/ui/core/core.go index 5031dc0..b4390e0 100644 --- a/internal/client/ui/core/core.go +++ b/internal/client/ui/core/core.go @@ -58,14 +58,18 @@ type Model struct { func New(privKey ed25519.PrivateKey, name string) Model { m := Model{ - name: name, - privKey: privKey, - networkList: networklist.New(), - loading: loadscreen.New(connectingToServer), - timer: newTimer(initialTimeout), - timeout: initialTimeout, - connected: false, - focus: FocusNetworkList, + name: name, + privKey: privKey, + id: 0, + loading: loadscreen.New(connectingToServer), + timer: newTimer(initialTimeout), + timeout: initialTimeout, + connected: false, + networkCreationPopup: nil, + frequencyCreationPopup: nil, + networkList: networklist.New(), + network: network.New(), + focus: FocusNetworkList, } m.move(0) // Update focus diff --git a/internal/client/ui/core/network/network.go b/internal/client/ui/core/network/network.go index 75ea318..3c24350 100644 --- a/internal/client/ui/core/network/network.go +++ b/internal/client/ui/core/network/network.go @@ -8,6 +8,7 @@ import ( "github.com/kyren223/eko/internal/client/gateway" "github.com/kyren223/eko/internal/client/ui" "github.com/kyren223/eko/internal/client/ui/colors" + "github.com/kyren223/eko/internal/client/ui/core/chat" "github.com/kyren223/eko/internal/client/ui/core/state" "github.com/kyren223/eko/internal/packet" ) @@ -31,12 +32,16 @@ type Model struct { networkIndex int index int focus bool + chat chat.Model } func New() Model { + chat := chat.New() + return Model{ focus: false, index: 0, + chat: chat, } } @@ -69,13 +74,14 @@ func (m Model) View() string { builder.WriteString("\n") } - result := builder.String() - + sidebar := builder.String() sep := sepStyle.Height(ui.Height) if m.focus { sep = sep.BorderForeground(colors.Focus) } - result = lipgloss.JoinHorizontal(lipgloss.Top, result, sep.String()) + sidebar = lipgloss.JoinHorizontal(lipgloss.Top, sidebar, sep.String()) + + result := lipgloss.JoinHorizontal(lipgloss.Top, sidebar, m.chat.View()) return result } diff --git a/internal/client/ui/messagebox/messagebox.go b/internal/client/ui/messagebox/messagebox.go deleted file mode 100644 index 0728cb1..0000000 --- a/internal/client/ui/messagebox/messagebox.go +++ /dev/null @@ -1,131 +0,0 @@ -package messagebox - -import ( - "slices" - "strings" - "time" - - "github.com/charmbracelet/bubbles/viewport" - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" - - "github.com/kyren223/eko/internal/client/api" - "github.com/kyren223/eko/internal/data" - "github.com/kyren223/eko/pkg/snowflake" -) - -var ( - senderStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("5")).Bold(true) - timestampStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#585c62")).Italic(true) -) - -type user struct { - name string - isFetching bool -} - -type Model struct { - Viewport viewport.Model - messages []data.Message - users map[snowflake.ID]user -} - -func New(width, height int) Model { - return Model{ - Viewport: viewport.New(width, height), - messages: nil, - users: make(map[snowflake.ID]user), - } -} - -func (m Model) Init() tea.Cmd { - return api.GetMessages -} - -func (m Model) View() string { - return m.Viewport.View() -} - -func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) { - var cmds []tea.Cmd - - for id, user := range m.users { - if !user.isFetching && user.name == "" { - cmds = append(cmds, api.GetUserById(id)) - user.isFetching = true - m.users[id] = user - } - } - - var cmd tea.Cmd - m.Viewport, cmd = m.Viewport.Update(msg) - cmds = append(cmds, cmd) - - switch msg := msg.(type) { - case api.UserProfileUpdate: - m.users[msg.ID] = user{msg.Name, false} - m.UpdateMessages() - } - - return m, tea.Batch(cmds...) -} - -func (m *Model) AppendMessage(message data.Message) { - m.messages = append(m.messages, message) - m.UpdateMessages() -} - -func (m *Model) SetMessages(messages []data.Message) { - m.messages = messages - m.UpdateMessages() -} - -func (m *Model) UpdateMessages() { - for _, message := range m.messages { - if _, exists := m.users[message.SenderID]; !exists { - m.users[message.SenderID] = user{name: "", isFetching: false} - } - } - - m.sortMessages() - m.updateContent() - m.Viewport.GotoBottom() -} - -func (m *Model) sortMessages() { - slices.SortFunc(m.messages, func(a, b data.Message) int { - if a.ID-b.ID < 0 { - return -1 - } else { - return 1 - } - }) -} - -func (m *Model) updateContent() { - if len(m.messages) == 0 { - return - } - - var builder strings.Builder - - for _, message := range m.messages { - sender := m.users[message.SenderID].name - builder.WriteString(senderStyle.Render(sender)) - builder.WriteByte(' ') - - timestamp := timestampFromID(message.ID) - builder.WriteString(timestampStyle.Render(timestamp)) - builder.WriteByte('\n') - - builder.WriteString(message.Content) - builder.WriteByte('\n') - } - - m.Viewport.SetContent(builder.String()[:builder.Len()-1]) -} - -func timestampFromID(id snowflake.ID) string { - localTime := time.UnixMilli(id.Time()) - return localTime.Format("02/01/2006 3:04 PM") -} diff --git a/internal/client/ui/viminput/linedecorations.go b/internal/client/ui/viminput/linedecorations.go new file mode 100644 index 0000000..82e51f1 --- /dev/null +++ b/internal/client/ui/viminput/linedecorations.go @@ -0,0 +1,17 @@ +package viminput + +import ( + "strconv" + + "github.com/charmbracelet/lipgloss" +) + +func LineNumberDecoration(style lipgloss.Style) LineDecoration { + return func(lnum int, line string, cursorLnum int) string { + return style.Render(strconv.FormatInt(int64(lnum), 10)) + } +} + +func EmptyLineDecoration(lnum int, line string, cursorLnum int) string { + return "" +} diff --git a/internal/client/ui/viminput/viminput.go b/internal/client/ui/viminput/viminput.go new file mode 100644 index 0000000..e2b65a8 --- /dev/null +++ b/internal/client/ui/viminput/viminput.go @@ -0,0 +1,89 @@ +package viminput + +import ( + tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/lipgloss" +) + +type ( + Keymap struct{} + LineDecoration = func(lnum int, line string, cursorLnum int) string +) + +type Line []byte + +type Model struct { + keymap Keymap + + PlaceholderStyle lipgloss.Style + PromptStyle lipgloss.Style + + Placeholder string + LineDecoration LineDecoration + + lines []Line + + width int + height int + focus bool +} + +func New(width, height int) Model { + return Model{ + keymap: Keymap{}, + PlaceholderStyle: lipgloss.NewStyle(), + PromptStyle: lipgloss.NewStyle(), + Placeholder: "", + LineDecoration: EmptyLineDecoration, + width: width, + height: height, + focus: false, + } +} + +func (m Model) Init() tea.Cmd { + return nil +} + +func (m Model) View() string { + placeholder := m.PlaceholderStyle.Render(m.Placeholder) + lineDecoration := m.LineDecoration(1, "", 1) + + result := lipgloss.JoinHorizontal(lipgloss.Top, lineDecoration, placeholder) + + result = lipgloss.NewStyle().Width(m.width).Height(m.height).Render(result) + + return result +} + +func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) { + if !m.focus { + return m, nil + } + + return m, nil +} + +func (m *Model) SetWidth(width int) { + m.width = width +} + +func (m Model) Width() int { + return m.width +} + +func (m *Model) SetHeight(height int) { + m.height = height +} + +func (m Model) Height() int { + return m.height +} + +func (m *Model) Focus() { + m.focus = true +} + +func (m *Model) Blur() { + m.focus = false +} |
