summaryrefslogtreecommitdiff
path: root/internal/client
diff options
context:
space:
mode:
Diffstat (limited to 'internal/client')
-rw-r--r--internal/client/ui/core/chat/chat.go4
-rw-r--r--internal/client/ui/core/core.go92
-rw-r--r--internal/client/ui/core/helppopup.go245
-rw-r--r--internal/client/ui/core/memberlist/memberlist.go2
4 files changed, 300 insertions, 43 deletions
diff --git a/internal/client/ui/core/chat/chat.go b/internal/client/ui/core/chat/chat.go
index c650c04..0675230 100644
--- a/internal/client/ui/core/chat/chat.go
+++ b/internal/client/ui/core/chat/chat.go
@@ -1102,3 +1102,7 @@ func (m *Model) renderFrequencyName() string {
return frequencyNameStyle.Render(frequency.Name) + "\n"
}
+
+func (m *Model) Mode() int {
+ return m.vi.Mode()
+}
diff --git a/internal/client/ui/core/core.go b/internal/client/ui/core/core.go
index c099473..43695e7 100644
--- a/internal/client/ui/core/core.go
+++ b/internal/client/ui/core/core.go
@@ -26,6 +26,7 @@ import (
"github.com/kyren223/eko/internal/client/ui/core/state"
"github.com/kyren223/eko/internal/client/ui/core/usersettings"
"github.com/kyren223/eko/internal/client/ui/loadscreen"
+ "github.com/kyren223/eko/internal/client/ui/viminput"
"github.com/kyren223/eko/internal/data"
"github.com/kyren223/eko/internal/packet"
"github.com/kyren223/eko/pkg/assert"
@@ -63,6 +64,7 @@ type Model struct {
timeout time.Duration
connected bool
+ helpPopup *HelpPopup
userSettingsPopup *usersettings.Model
networkCreationPopup *networkcreation.Model
networkUpdatePopup *networkupdate.Model
@@ -84,6 +86,7 @@ func New(privKey ed25519.PrivateKey, name string) Model {
timer: newTimer(initialTimeout),
timeout: initialTimeout,
connected: false,
+ helpPopup: nil,
userSettingsPopup: nil,
networkCreationPopup: nil,
networkUpdatePopup: nil,
@@ -123,7 +126,9 @@ func (m Model) View() string {
)
var popup string
- if m.userSettingsPopup != nil {
+ if m.helpPopup != nil {
+ popup = m.helpPopup.View()
+ } else if m.userSettingsPopup != nil {
popup = m.userSettingsPopup.View()
} else if m.networkCreationPopup != nil {
popup = m.networkCreationPopup.View()
@@ -299,11 +304,7 @@ func (m *Model) updateConnected(msg tea.Msg) tea.Cmd {
if !m.HasPopup() {
popup := networkcreation.New()
m.networkCreationPopup = &popup
- } else {
- cmd := m.updatePopups(msg)
- if cmd != nil {
- return cmd
- }
+ return nil
}
case FocusLeftSidebar:
if !m.HasPopup() {
@@ -317,17 +318,7 @@ func (m *Model) updateConnected(msg tea.Msg) tea.Cmd {
}
popup := frequencycreation.New(*networkId)
m.frequencyCreationPopup = &popup
- } else {
- cmd := m.updatePopups(msg)
- if cmd != nil {
- return cmd
- }
- }
-
- default:
- cmd := m.updatePopups(msg)
- if cmd != nil {
- return cmd
+ return nil
}
}
@@ -335,8 +326,7 @@ func (m *Model) updateConnected(msg tea.Msg) tea.Cmd {
if m.focus == FocusNetworkList && !m.HasPopup() {
popup := networkjoin.New()
m.networkJoinPopup = &popup
- } else {
- m.updatePopups(msg)
+ return nil
}
case "i":
@@ -347,8 +337,7 @@ func (m *Model) updateConnected(msg tea.Msg) tea.Cmd {
if networkId != nil {
_ = clipboard.WriteAll(networkId.String())
}
- } else {
- m.updatePopups(msg)
+ return nil
}
case "e":
@@ -377,27 +366,41 @@ func (m *Model) updateConnected(msg tea.Msg) tea.Cmd {
index := m.frequencyList.Index()
popup := frequencyupdate.New(*networkId, index)
m.frequencyUpdatePopup = &popup
- } else {
- cmd := m.updatePopups(msg)
- if cmd != nil {
- return cmd
- }
+ return nil
}
- // user/profile/options/settings
- case "u", "p", "o", "s":
- if !m.HasPopup() && m.focus == FocusNetworkList {
+ // user
+ case "u":
+ isChatLocked := m.focus == FocusChat && m.chat.Locked()
+ if !m.HasPopup() && !isChatLocked {
popup := usersettings.New()
m.userSettingsPopup = &popup
- } else if m.HasPopup() {
- cmd := m.updatePopups(msg)
- if cmd != nil {
- return cmd
+ return nil
+ }
+
+ case "?":
+ normalMode := m.chat.Mode() == viminput.NormalMode
+ if !m.HasPopup() && (m.focus != FocusChat || !m.chat.Locked() || normalMode) {
+ switch m.focus {
+ case FocusNetworkList:
+ m.helpPopup = NewHelpPopup(HelpNetworkList)
+ case FocusLeftSidebar:
+ m.helpPopup = NewHelpPopup(HelpFrequencyList)
+ case FocusChat:
+ if m.chat.Locked() {
+ m.helpPopup = NewHelpPopup(HelpVim)
+ } else {
+ m.helpPopup = NewHelpPopup(HelpChat)
+ }
+ case FocusRightSidebar:
+ m.helpPopup = NewHelpPopup(HelpMemberList)
}
+ return nil
}
case "esc":
if m.HasPopup() {
+ m.helpPopup = nil
m.userSettingsPopup = nil
m.networkCreationPopup = nil
m.networkUpdatePopup = nil
@@ -407,7 +410,9 @@ func (m *Model) updateConnected(msg tea.Msg) tea.Cmd {
}
case "enter":
- if m.userSettingsPopup != nil {
+ if m.helpPopup != nil {
+ m.helpPopup = nil
+ } else if m.userSettingsPopup != nil {
cmd := m.userSettingsPopup.Select()
if cmd != nil {
m.userSettingsPopup = nil
@@ -446,12 +451,9 @@ func (m *Model) updateConnected(msg tea.Msg) tea.Cmd {
}
default:
- cmd := m.updatePopups(msg)
- if cmd != nil {
- return cmd
- }
+ isChatLocked := m.focus == FocusChat && m.chat.Locked()
+ if !m.HasPopup() && !isChatLocked {
- if m.focus != FocusChat || !m.chat.Locked() {
left := msg.String() == "H"
right := msg.String() == "L"
direction := 0
@@ -466,7 +468,8 @@ func (m *Model) updateConnected(msg tea.Msg) tea.Cmd {
}
if m.HasPopup() {
- return nil
+ cmd := m.updatePopups(msg)
+ return cmd
}
var cmds []tea.Cmd
@@ -531,7 +534,11 @@ func (m *Model) move(direction int) {
}
func (m *Model) updatePopups(msg tea.Msg) tea.Cmd {
- if m.userSettingsPopup != nil {
+ if m.helpPopup != nil {
+ popup, cmd := m.helpPopup.Update(msg)
+ m.helpPopup = &popup
+ return cmd
+ } else if m.userSettingsPopup != nil {
popup, cmd := m.userSettingsPopup.Update(msg)
m.userSettingsPopup = &popup
return cmd
@@ -560,7 +567,8 @@ func (m *Model) updatePopups(msg tea.Msg) tea.Cmd {
}
func (m *Model) HasPopup() bool {
- return m.userSettingsPopup != nil ||
+ return m.helpPopup != nil ||
+ m.userSettingsPopup != nil ||
m.networkCreationPopup != nil ||
m.networkUpdatePopup != nil ||
m.frequencyCreationPopup != nil ||
diff --git a/internal/client/ui/core/helppopup.go b/internal/client/ui/core/helppopup.go
new file mode 100644
index 0000000..db81a38
--- /dev/null
+++ b/internal/client/ui/core/helppopup.go
@@ -0,0 +1,245 @@
+package core
+
+import (
+ "strings"
+
+ tea "github.com/charmbracelet/bubbletea"
+ "github.com/charmbracelet/lipgloss"
+ "github.com/kyren223/eko/internal/client/ui"
+ "github.com/kyren223/eko/internal/client/ui/colors"
+)
+
+var (
+ style = lipgloss.NewStyle().
+ MaxWidth(ui.MinWidth).
+ Border(lipgloss.ThickBorder()).
+ Padding(1, 2).
+ Align(lipgloss.Center, lipgloss.Center)
+
+ titleStyle = lipgloss.NewStyle().
+ Foreground(colors.Focus).
+ Border(lipgloss.ThickBorder(), false, false, true).
+ Padding(0, 4, 1).MarginBottom(1).
+ Align(lipgloss.Center, lipgloss.Center)
+
+ keyStyle = lipgloss.NewStyle().
+ Padding(0, 1).
+ Background(colors.DarkPurple).Foreground(colors.White)
+
+ descriptionStyle = lipgloss.NewStyle()
+
+ toggleHint = lipgloss.NewStyle().Foreground(colors.Gold).
+ Render("-- Press space to toggle between global/local keybindings --")
+)
+
+const (
+ HelpNetworkList = iota
+ HelpFrequencyList
+ HelpChat
+ HelpMemberList
+ HelpGlobal
+ HelpVim
+ HelpMax
+)
+
+type Keymap struct {
+ key string
+ description string
+}
+
+type HelpPopup struct {
+ help int
+ global bool
+}
+
+func NewHelpPopup(help int) *HelpPopup {
+ return &HelpPopup{
+ help: help,
+ global: false,
+ }
+}
+
+func (m HelpPopup) Init() tea.Cmd {
+ return nil
+}
+
+func (m HelpPopup) View() string {
+ if m.global {
+ m.help = HelpGlobal
+ }
+
+ title := titleStyle.Render(m.Title()+" Keybindings Cheatsheet") + "\n"
+
+ keymapLists := [][]Keymap{}
+ switch m.help {
+ case HelpNetworkList:
+ keymapLists = m.HelpNetworkList()
+ case HelpFrequencyList:
+ keymapLists = m.HelpFrequencyList()
+ case HelpChat:
+ keymapLists = m.HelpChat()
+ case HelpMemberList:
+ keymapLists = m.HelpMemberList()
+ case HelpGlobal:
+ keymapLists = m.HelpGlobal()
+ case HelpVim:
+ keymapLists = m.HelpVim()
+ }
+
+ helps := []string{}
+
+ for i, keymaps := range keymapLists {
+ var builder strings.Builder
+
+ for _, keymap := range keymaps {
+ builder.WriteString(keyStyle.Render(keymap.key))
+ builder.WriteString(" ")
+ builder.WriteString(descriptionStyle.Render(keymap.description))
+ builder.WriteString("\n\n")
+ }
+
+ // help := lipgloss.NewStyle().Align(lipgloss.Left).Render()
+ helps = append(helps, builder.String())
+
+ if i != len(keymapLists)-1 {
+ helps = append(helps, " ") // separator
+ }
+ }
+
+ content := lipgloss.JoinHorizontal(lipgloss.Top, helps...) + "\n"
+
+ return style.Render(title + content + toggleHint)
+}
+
+func (m HelpPopup) Update(msg tea.Msg) (HelpPopup, tea.Cmd) {
+ switch msg := msg.(type) {
+ case tea.KeyMsg:
+ if msg.Type == tea.KeySpace {
+ m.global = !m.global
+ }
+ }
+
+ return m, nil
+}
+
+func (m HelpPopup) Title() string {
+ switch m.help {
+ case HelpNetworkList:
+ return "Network"
+ case HelpFrequencyList:
+ return "Frequency"
+ case HelpChat:
+ return "Chat"
+ case HelpMemberList:
+ return "Member"
+ case HelpGlobal:
+ return "Global"
+ case HelpVim:
+ return "VIM"
+ }
+ return "Unknown"
+}
+
+func (m HelpPopup) HelpGlobal() [][]Keymap {
+ return [][]Keymap{{
+ {"ctrl+c", "Exit eko"},
+ {"H", "Move focus to the right"},
+ {"L", "Move focus to the left"},
+ {"u", "Edit your user profile"},
+ {"?", "Show a help popup"},
+ }, {
+ {"esc", "Close popup"},
+ {"tab", "cycle to the next option"},
+ {"shift+tab", "cycle to the previous option"},
+ {"enter", "confirm the selected option"},
+ }}
+}
+
+func (m HelpPopup) HelpNetworkList() [][]Keymap {
+ return [][]Keymap{{
+ {"k", "Move up a network"},
+ {"j", "Move down a network"},
+ {"K", "Move the selected network up"},
+ {"J", "Move the selected network down"},
+ {"Q", "Leave the selected network"},
+ }, {
+ {"n", "Create a new network"},
+ {"e", "Edit the selected network"},
+ {"a", "Join a new network from an invite code"},
+ {"i", "Copy the selected network's invite code"},
+ {"D", "Delete the selected network"},
+ }}
+}
+
+func (m HelpPopup) HelpFrequencyList() [][]Keymap {
+ return [][]Keymap{{
+ {"k", "Move up a frequency"},
+ {"j", "Move down a frequency"},
+ {"ctrl+u", "Move half a page up"},
+ {"ctrl+d", "Move half a page down"},
+ {"g", "Move to the first frequency"},
+ {"G", "Move to the last frequency"},
+ }, {
+ {"n", "Create a new frequency"},
+ {"e", "Edit the selected frequency"},
+ {"x", "Delete the selected frequency"},
+ {"K", "Move the selected frequency up"},
+ {"J", "Move the selected frequency down"},
+ {"i", "Copy the network's invite code"},
+ }}
+}
+
+func (m HelpPopup) HelpChat() [][]Keymap {
+ return [][]Keymap{{
+ {"k", "Move up a message"},
+ {"j", "Move down a message"},
+ {"ctrl+u", "Move half a page up"},
+ {"ctrl+d", "Move half a page down"},
+ {"G", "Snap to the bottom message"},
+ {"i", "Start typing a message"},
+ {"enter", "Snap to bottom and type"},
+ {"ctrl+q", "Exit typing mode"},
+ }, {
+ {"x", "Delete selected message"},
+ {"e", "Edit selected message"},
+
+ {"K", "Kick message sender"},
+ {"M", "Mute message sender"},
+ {"U", "Unmute message sender"},
+ {"B", "Ban message sender"}, // TODO: implement
+ {"P", "Promote sender to admin"},
+ {"D", "Demote sender from admin"},
+ }}
+}
+
+func (m HelpPopup) HelpMemberList() [][]Keymap {
+ return [][]Keymap{{
+ {"k", "Move up by one"},
+ {"j", "Move down by one"},
+ {"ctrl+u", "Move half a page up"},
+ {"ctrl+d", "Move half a page down"},
+ {"g", "Move to the top"},
+ {"G", "Move to the bottom"},
+
+ {"p", "View member profile"},
+ {"T", "Trust/untrust member"},
+ }, {
+ {"K", "Kick selected member"},
+ {"M", "Mute selected member"},
+ {"U", "Unmute selected member"},
+ {"B", "Ban selected member"}, // TODO: implement
+ {"b", "Switch to banlist view"}, // TODO: implement
+ {"P", "Promote member to admin"},
+ {"D", "Demote member from admin"},
+ {"ctrl+t", "Transfer ownership"}, // TODO: implement
+ }}
+}
+
+func (m HelpPopup) HelpVim() [][]Keymap {
+ return [][]Keymap{{
+ {"esc", "Go into normal mode from insert mode"},
+ {"q", "Exit typing from normal mode"},
+ {"ctrl+q", "Exit typing from insert mode"},
+ {"Other", "The rest of the vim keys work as usual"},
+ }, {}}
+}
diff --git a/internal/client/ui/core/memberlist/memberlist.go b/internal/client/ui/core/memberlist/memberlist.go
index 2d589fa..f42a4ac 100644
--- a/internal/client/ui/core/memberlist/memberlist.go
+++ b/internal/client/ui/core/memberlist/memberlist.go
@@ -191,7 +191,7 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
})
// Admin
- case "x", "K":
+ case "K":
networkId := state.NetworkId(m.networkIndex)
network := state.State.Networks[*networkId]
member := m.Members()[m.index]