Refactor TUI input handling (isolate shortcuts) and polish layout alignment
This commit is contained in:
@@ -400,9 +400,9 @@ func (m *Model) updateChannelList(channels []*ts3client.Channel) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *Model) handleKeyPress(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
|
func (m *Model) handleKeyPress(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
|
||||||
// Global keys (work regardless of focus)
|
// 1. Absolute Globals (Always active)
|
||||||
switch msg.String() {
|
switch msg.String() {
|
||||||
case "ctrl+c", "q":
|
case "ctrl+c":
|
||||||
if m.client != nil {
|
if m.client != nil {
|
||||||
m.client.Disconnect()
|
m.client.Disconnect()
|
||||||
}
|
}
|
||||||
@@ -419,6 +419,28 @@ func (m *Model) handleKeyPress(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
|
|||||||
// Cycle focus
|
// Cycle focus
|
||||||
m.focus = (m.focus + 1) % 3
|
m.focus = (m.focus + 1) % 3
|
||||||
return m, nil
|
return m, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Input Focus Priority
|
||||||
|
// If typing, ignore all other shortcuts except the absolute globals above
|
||||||
|
if m.focus == FocusInput {
|
||||||
|
return m.handleInputKeys(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Global Shortcuts (Only when NOT in Input)
|
||||||
|
switch msg.String() {
|
||||||
|
case "q":
|
||||||
|
// Quit (same as ctrl+c)
|
||||||
|
if m.client != nil {
|
||||||
|
m.client.Disconnect()
|
||||||
|
}
|
||||||
|
if m.audioPlayer != nil {
|
||||||
|
m.audioPlayer.Close()
|
||||||
|
}
|
||||||
|
if m.audioCapturer != nil {
|
||||||
|
m.audioCapturer.Close()
|
||||||
|
}
|
||||||
|
return m, tea.Quit
|
||||||
|
|
||||||
case "m", "M":
|
case "m", "M":
|
||||||
// Toggle mute
|
// Toggle mute
|
||||||
@@ -451,31 +473,25 @@ func (m *Model) handleKeyPress(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
|
|||||||
return m, nil
|
return m, nil
|
||||||
|
|
||||||
case "v", "V":
|
case "v", "V":
|
||||||
// Toggle voice (PTT) - V to start/stop transmitting
|
// Toggle voice (PTT)
|
||||||
if m.focus != FocusInput {
|
m.isPTT = !m.isPTT
|
||||||
m.isPTT = !m.isPTT
|
if m.isPTT {
|
||||||
if m.isPTT {
|
if m.audioCapturer != nil {
|
||||||
// Start capturing when PTT enabled
|
m.audioCapturer.Start()
|
||||||
if m.audioCapturer != nil {
|
|
||||||
m.audioCapturer.Start()
|
|
||||||
}
|
|
||||||
m.addLog("🎤 Transmitting...")
|
|
||||||
} else {
|
|
||||||
// Stop capturing when PTT disabled
|
|
||||||
if m.audioCapturer != nil {
|
|
||||||
m.audioCapturer.Stop()
|
|
||||||
}
|
|
||||||
m.addLog("🎤 Stopped transmitting")
|
|
||||||
}
|
}
|
||||||
return m, nil
|
m.addLog("🎤 Transmitting...")
|
||||||
|
} else {
|
||||||
|
if m.audioCapturer != nil {
|
||||||
|
m.audioCapturer.Stop()
|
||||||
|
}
|
||||||
|
m.addLog("🎤 Stopped transmitting")
|
||||||
}
|
}
|
||||||
|
return m, nil
|
||||||
|
|
||||||
case "l", "L":
|
case "l", "L":
|
||||||
// Toggle Log/Chat view
|
// Toggle Log/Chat view
|
||||||
if m.focus != FocusInput {
|
m.showLog = !m.showLog
|
||||||
m.showLog = !m.showLog
|
return m, nil
|
||||||
return m, nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Focus-specific keys
|
// Focus-specific keys
|
||||||
@@ -563,25 +579,31 @@ func (m *Model) View() string {
|
|||||||
// panels should be height - 5 (1 for header, 3 for input with border, 1 for help)
|
// panels should be height - 5 (1 for header, 3 for input with border, 1 for help)
|
||||||
panelHeight := m.height - 7
|
panelHeight := m.height - 7
|
||||||
|
|
||||||
|
// Calculate explicit widths to fit exactly (Width is content width)
|
||||||
|
// Box Width = Content + 2 (Border) + 2 (Padding) = Content + 4
|
||||||
|
// We want LeftBox + RightBox = m.width
|
||||||
|
leftBoxWidth := m.width / 4
|
||||||
|
rightBoxWidth := m.width - leftBoxWidth
|
||||||
|
|
||||||
channelPanelStyle := lipgloss.NewStyle().
|
channelPanelStyle := lipgloss.NewStyle().
|
||||||
Border(lipgloss.RoundedBorder()).
|
Border(lipgloss.RoundedBorder()).
|
||||||
BorderForeground(lipgloss.Color("63")).
|
BorderForeground(lipgloss.Color("63")).
|
||||||
Padding(0, 1).
|
Padding(0, 1).
|
||||||
Width(m.width/3 - 2).
|
Width(leftBoxWidth - 4).
|
||||||
Height(panelHeight)
|
Height(panelHeight)
|
||||||
|
|
||||||
chatPanelStyle := lipgloss.NewStyle().
|
chatPanelStyle := lipgloss.NewStyle().
|
||||||
Border(lipgloss.RoundedBorder()).
|
Border(lipgloss.RoundedBorder()).
|
||||||
BorderForeground(lipgloss.Color("63")).
|
BorderForeground(lipgloss.Color("63")).
|
||||||
Padding(0, 1).
|
Padding(0, 1).
|
||||||
Width(m.width*2/3 - 2).
|
Width(rightBoxWidth - 4).
|
||||||
Height(panelHeight)
|
Height(panelHeight)
|
||||||
|
|
||||||
inputStyle := lipgloss.NewStyle().
|
inputStyle := lipgloss.NewStyle().
|
||||||
Border(lipgloss.NormalBorder()).
|
Border(lipgloss.NormalBorder()).
|
||||||
BorderForeground(lipgloss.Color("63")).
|
BorderForeground(lipgloss.Color("63")).
|
||||||
Padding(0, 1).
|
Padding(0, 1).
|
||||||
Width(m.width - 4)
|
Width(m.width - 6)
|
||||||
|
|
||||||
// Header with status bar
|
// Header with status bar
|
||||||
header := m.renderStatusBar()
|
header := m.renderStatusBar()
|
||||||
@@ -618,7 +640,7 @@ func (m *Model) View() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Calculate available width for text
|
// Calculate available width for text
|
||||||
textWidth := (m.width * 2 / 3) - 6
|
textWidth := (rightBoxWidth - 4) - 2 // Content width - margin
|
||||||
if textWidth < 10 {
|
if textWidth < 10 {
|
||||||
textWidth = 10
|
textWidth = 10
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user