feat: unified navigation
fix: install script copying build binary chore: updated readme
This commit is contained in:
@@ -17,13 +17,6 @@ import (
|
||||
"playback/internal/ui/waveform"
|
||||
)
|
||||
|
||||
// FocusedView represents which view has focus
|
||||
type FocusedView int
|
||||
|
||||
const (
|
||||
FocusWaveform FocusedView = iota
|
||||
FocusTranscript
|
||||
)
|
||||
|
||||
// Model is the main application model
|
||||
type Model struct {
|
||||
@@ -44,7 +37,6 @@ type Model struct {
|
||||
transcript transcript.Model
|
||||
|
||||
// State
|
||||
focused FocusedView
|
||||
showHelp bool
|
||||
width int
|
||||
height int
|
||||
@@ -66,7 +58,6 @@ func New(audioPath, transcriptPath string) Model {
|
||||
header: header.New(),
|
||||
waveform: waveform.New(),
|
||||
transcript: transcript.New(),
|
||||
focused: FocusWaveform,
|
||||
}
|
||||
|
||||
return m
|
||||
@@ -144,7 +135,7 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
m.updateLayout()
|
||||
|
||||
case tea.KeyMsg:
|
||||
// Global keys
|
||||
// All shortcuts are now global
|
||||
switch {
|
||||
case key.Matches(msg, m.keys.Quit):
|
||||
m.quitting = true
|
||||
@@ -157,38 +148,25 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
case key.Matches(msg, m.keys.PlayPause):
|
||||
m.player.Toggle()
|
||||
|
||||
case key.Matches(msg, m.keys.FocusWaveform):
|
||||
m.focused = FocusWaveform
|
||||
m.waveform.SetFocused(true)
|
||||
m.transcript.SetFocused(false)
|
||||
|
||||
case key.Matches(msg, m.keys.FocusTranscript):
|
||||
m.focused = FocusTranscript
|
||||
m.waveform.SetFocused(false)
|
||||
m.transcript.SetFocused(true)
|
||||
|
||||
case key.Matches(msg, m.keys.EnterEdit):
|
||||
if m.focused == FocusTranscript {
|
||||
m.player.Pause()
|
||||
return m, m.launchEditor()
|
||||
}
|
||||
}
|
||||
m.player.Pause()
|
||||
return m, m.launchEditor()
|
||||
|
||||
// Context-specific keys
|
||||
if m.focused == FocusWaveform {
|
||||
switch {
|
||||
case key.Matches(msg, m.keys.SeekForward):
|
||||
m.player.SeekRelative(m.config.SeekStep)
|
||||
case key.Matches(msg, m.keys.SeekBackward):
|
||||
m.player.SeekRelative(-m.config.SeekStep)
|
||||
case key.Matches(msg, m.keys.SeekForwardBig):
|
||||
m.player.SeekRelative(m.config.BigSeekStep)
|
||||
case key.Matches(msg, m.keys.SeekBackwardBig):
|
||||
m.player.SeekRelative(-m.config.BigSeekStep)
|
||||
}
|
||||
}
|
||||
// Seeking shortcuts (previously waveform-only, now global)
|
||||
case key.Matches(msg, m.keys.SeekForward):
|
||||
m.player.SeekRelative(m.config.SeekStep)
|
||||
|
||||
if m.focused == FocusTranscript {
|
||||
case key.Matches(msg, m.keys.SeekBackward):
|
||||
m.player.SeekRelative(-m.config.SeekStep)
|
||||
|
||||
case key.Matches(msg, m.keys.SeekForwardBig):
|
||||
m.player.SeekRelative(m.config.BigSeekStep)
|
||||
|
||||
case key.Matches(msg, m.keys.SeekBackwardBig):
|
||||
m.player.SeekRelative(-m.config.BigSeekStep)
|
||||
|
||||
// Transcript navigation and other keys forward to transcript
|
||||
default:
|
||||
cmd := m.transcript.Update(msg)
|
||||
cmds = append(cmds, cmd)
|
||||
}
|
||||
@@ -262,9 +240,6 @@ func (m *Model) updateLayout() {
|
||||
m.header.SetWidth(m.width)
|
||||
m.waveform.SetSize(m.width, waveformHeight)
|
||||
m.transcript.SetSize(m.width, transcriptHeight)
|
||||
|
||||
m.waveform.SetFocused(m.focused == FocusWaveform)
|
||||
m.transcript.SetFocused(m.focused == FocusTranscript)
|
||||
}
|
||||
|
||||
func (m Model) launchEditor() tea.Cmd {
|
||||
@@ -272,7 +247,7 @@ func (m Model) launchEditor() tea.Cmd {
|
||||
if t == nil {
|
||||
return nil
|
||||
}
|
||||
lineNum := m.transcript.SelectedCueLineNumber()
|
||||
lineNum := m.transcript.ActiveCueLineNumber()
|
||||
c := exec.Command(m.config.Editor, fmt.Sprintf("+%d", lineNum), t.FilePath)
|
||||
return tea.ExecProcess(c, func(err error) tea.Msg {
|
||||
return VimExitedMsg{Path: t.FilePath, Err: err}
|
||||
@@ -330,13 +305,6 @@ func (m Model) renderStatus() string {
|
||||
modeStyle := ui.ModeStyle
|
||||
mode := modeStyle.Render(m.transcript.ModeString())
|
||||
|
||||
// Focus indicator
|
||||
focusStr := "Waveform"
|
||||
if m.focused == FocusTranscript {
|
||||
focusStr = "Transcript"
|
||||
}
|
||||
focus := ui.BaseStyle.Render(fmt.Sprintf("[%s]", focusStr))
|
||||
|
||||
// Status message
|
||||
statusMsg := ui.StatusBarStyle.Render(m.statusMsg)
|
||||
|
||||
@@ -347,10 +315,8 @@ func (m Model) renderStatus() string {
|
||||
lipgloss.Center,
|
||||
mode,
|
||||
" ",
|
||||
focus,
|
||||
" ",
|
||||
statusMsg,
|
||||
lipgloss.NewStyle().Width(m.width-lipgloss.Width(mode)-lipgloss.Width(focus)-lipgloss.Width(statusMsg)-lipgloss.Width(helpHint)-8).Render(""),
|
||||
lipgloss.NewStyle().Width(m.width-lipgloss.Width(mode)-lipgloss.Width(statusMsg)-lipgloss.Width(helpHint)-4).Render(""),
|
||||
helpHint,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -9,17 +9,11 @@ type KeyMap struct {
|
||||
Help key.Binding
|
||||
PlayPause key.Binding
|
||||
|
||||
// Focus
|
||||
FocusWaveform key.Binding
|
||||
FocusTranscript key.Binding
|
||||
|
||||
// Waveform navigation
|
||||
// Navigation (global)
|
||||
SeekForward key.Binding
|
||||
SeekBackward key.Binding
|
||||
SeekForwardBig key.Binding
|
||||
SeekBackwardBig key.Binding
|
||||
|
||||
// Transcript navigation
|
||||
ScrollUp key.Binding
|
||||
ScrollDown key.Binding
|
||||
PageUp key.Binding
|
||||
@@ -46,14 +40,6 @@ func DefaultKeyMap() KeyMap {
|
||||
key.WithKeys(" "),
|
||||
key.WithHelp("space", "play/pause"),
|
||||
),
|
||||
FocusWaveform: key.NewBinding(
|
||||
key.WithKeys("ctrl+k"),
|
||||
key.WithHelp("ctrl+k", "focus waveform"),
|
||||
),
|
||||
FocusTranscript: key.NewBinding(
|
||||
key.WithKeys("ctrl+j"),
|
||||
key.WithHelp("ctrl+j", "focus transcript"),
|
||||
),
|
||||
SeekForward: key.NewBinding(
|
||||
key.WithKeys("l", "right"),
|
||||
key.WithHelp("l/→", "seek forward"),
|
||||
@@ -72,27 +58,27 @@ func DefaultKeyMap() KeyMap {
|
||||
),
|
||||
ScrollUp: key.NewBinding(
|
||||
key.WithKeys("k", "up"),
|
||||
key.WithHelp("k/↑", "scroll up"),
|
||||
key.WithHelp("k/↑", "previous cue"),
|
||||
),
|
||||
ScrollDown: key.NewBinding(
|
||||
key.WithKeys("j", "down"),
|
||||
key.WithHelp("j/↓", "scroll down"),
|
||||
key.WithHelp("j/↓", "next cue"),
|
||||
),
|
||||
PageUp: key.NewBinding(
|
||||
key.WithKeys("ctrl+u"),
|
||||
key.WithHelp("ctrl+u", "page up"),
|
||||
key.WithHelp("ctrl+u", "jump 5 cues up"),
|
||||
),
|
||||
PageDown: key.NewBinding(
|
||||
key.WithKeys("ctrl+d"),
|
||||
key.WithHelp("ctrl+d", "page down"),
|
||||
key.WithHelp("ctrl+d", "jump 5 cues down"),
|
||||
),
|
||||
GoTop: key.NewBinding(
|
||||
key.WithKeys("g"),
|
||||
key.WithHelp("gg", "go to top"),
|
||||
key.WithHelp("g", "go to first cue"),
|
||||
),
|
||||
GoBottom: key.NewBinding(
|
||||
key.WithKeys("G"),
|
||||
key.WithHelp("G", "go to bottom"),
|
||||
key.WithHelp("G", "go to last cue"),
|
||||
),
|
||||
EnterEdit: key.NewBinding(
|
||||
key.WithKeys("i"),
|
||||
@@ -107,24 +93,21 @@ func (k KeyMap) HelpView() string {
|
||||
|
||||
Global:
|
||||
space Play/Pause
|
||||
ctrl+j Focus transcript
|
||||
ctrl+k Focus waveform
|
||||
q Quit
|
||||
? Toggle help
|
||||
|
||||
Waveform (when focused):
|
||||
Navigation (Global):
|
||||
h / ← Seek backward (5s)
|
||||
l / → Seek forward (5s)
|
||||
H Seek backward (30s)
|
||||
L Seek forward (30s)
|
||||
|
||||
Transcript (when focused):
|
||||
j / ↓ Next cue
|
||||
k / ↑ Previous cue
|
||||
ctrl+d Jump 5 cues down
|
||||
ctrl+u Jump 5 cues up
|
||||
g Go to first cue
|
||||
G Go to last cue
|
||||
enter Seek audio to cue
|
||||
|
||||
Editing:
|
||||
i Edit in $EDITOR at cue`
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user