From 6bdd0c4ef97eb97177fedca65b7f86032d97d19f Mon Sep 17 00:00:00 2001 From: Alexander Heldt Date: Sun, 21 Dec 2025 17:35:28 +0100 Subject: [PATCH] wip-forward-control --- src/musicplayer/control.gleam | 20 +++++++++++-- src/musicplayer/musicplayer.gleam | 48 +++++++++++++++++++------------ src/musicplayer/ui/control.gleam | 2 ++ src/musicplayer/ui/layout.gleam | 11 ++++--- src/musicplayer/ui/plot.gleam | 1 + src/musicplayer/ui/ui.gleam | 6 ++++ 6 files changed, 60 insertions(+), 28 deletions(-) diff --git a/src/musicplayer/control.gleam b/src/musicplayer/control.gleam index 386ceeb..a9346b4 100644 --- a/src/musicplayer/control.gleam +++ b/src/musicplayer/control.gleam @@ -1,6 +1,13 @@ import musicplayer/input/key.{type Key} +pub type Mode { + Idle + Searching +} + pub type Control { + InputKey(Key) + TogglePlayPause Search @@ -11,16 +18,23 @@ pub type Control { Exit } -pub fn from_key(key: Key) -> Result(Control, Nil) { +pub fn from_key(key: Key, mode: Mode) -> Result(Control, Nil) { + case mode { + Idle -> idle_from_key(key) + Searching -> todo + } +} + +pub fn idle_from_key(key: Key) -> Result(Control, Nil) { case key { key.Return -> Ok(Return) key.Backspace -> Ok(Backspace) - key.Char(char) -> Ok(char_control(char)) + key.Char(char) -> Ok(idle_char_control(char)) _ -> Error(Nil) } } -fn char_control(char: String) -> Control { +fn idle_char_control(char: String) -> Control { case char { " " -> TogglePlayPause "/" -> Search diff --git a/src/musicplayer/musicplayer.gleam b/src/musicplayer/musicplayer.gleam index 525c0be..c1a33b4 100644 --- a/src/musicplayer/musicplayer.gleam +++ b/src/musicplayer/musicplayer.gleam @@ -1,9 +1,8 @@ import gleam/erlang/process.{type Name, type Pid, type Subject} import gleam/otp/actor -import gleam/result import gleam/string -import musicplayer/control.{type Control} +import musicplayer/control.{type Control, type Mode} import musicplayer/input/key.{type Key} import musicplayer/logging/logging import musicplayer/mpv/control as mpv_control @@ -11,11 +10,6 @@ import musicplayer/time/time import musicplayer/ui/control as ui_control import musicplayer/ui/layout -type Mode { - Idle - Searching -} - type Input { Input(capturing: Bool, content: String) } @@ -39,7 +33,7 @@ pub fn new( let input = Input(False, "") case - actor.new(State(Idle, input, ui, mpv)) + actor.new(State(control.Idle, input, ui, mpv)) |> actor.on_message(handle_message) |> actor.start { @@ -61,6 +55,12 @@ pub fn new( fn handle_message(state: State, control: Control) -> actor.Next(State, Control) { case control { + control.InputKey(key) -> { + let _ = control.from_key(key, state.mode) + // TODO get control and send it back to self + actor.continue(state) + } + control.Search -> { logging.log("musicplayer - initiating search") @@ -69,7 +69,7 @@ fn handle_message(state: State, control: Control) -> actor.Next(State, Control) actor.continue( State( ..state, - mode: Searching, + mode: control.Searching, input: Input(..state.input, capturing: True), ), ) @@ -79,8 +79,12 @@ fn handle_message(state: State, control: Control) -> actor.Next(State, Control) logging.log("musicplayer - recieved raw input: " <> content) let content = case state.mode { - Idle -> state.input.content - Searching -> { + control.Idle -> + case content { + "1" -> state.input.content + _ -> state.input.content + } + control.Searching -> { let updated = state.input.content <> content update_search(state.ui, "searching: " <> updated) updated @@ -90,11 +94,13 @@ fn handle_message(state: State, control: Control) -> actor.Next(State, Control) actor.continue(State(..state, input: Input(..state.input, content:))) } control.Backspace -> { - logging.log("musicplayer - recieved backspace") + logging.log( + "musicplayer - recieved backspace. mode:" <> string.inspect(state.mode), + ) let content = case state.mode { - Idle -> state.input.content - Searching -> { + control.Idle -> state.input.content + control.Searching -> { let updated = string.drop_end(state.input.content, 1) update_search(state.ui, "searching: " <> updated) updated @@ -113,12 +119,16 @@ fn handle_message(state: State, control: Control) -> actor.Next(State, Control) // Note: state.input.content is now the final input, use it // before it is reset case state.mode { - Idle -> Nil - Searching -> update_search(state.ui, "") + control.Idle -> Nil + control.Searching -> update_search(state.ui, "") } actor.continue( - State(..state, mode: Idle, input: Input(capturing: False, content: "")), + State( + ..state, + mode: control.Idle, + input: Input(capturing: False, content: ""), + ), ) } @@ -195,8 +205,8 @@ fn handle_key(musicplayer: Subject(Control), input_keys: Subject(Key)) -> Nil { process.new_selector() |> process.select(input_keys) |> process.selector_receive_forever - |> control.from_key - |> result.map(process.send(musicplayer, _)) + |> fn(key) { control.InputKey(key) } + |> process.send(musicplayer, _) handle_key(musicplayer, input_keys) } diff --git a/src/musicplayer/ui/control.gleam b/src/musicplayer/ui/control.gleam index bb9a501..3be454b 100644 --- a/src/musicplayer/ui/control.gleam +++ b/src/musicplayer/ui/control.gleam @@ -5,6 +5,8 @@ import musicplayer/ui/layout.{type Section} pub type Control { UpdateDimensions(columns: Int, rows: Int) UpdateState(section: Section, content: String) + SetView(view_idx: layout.ViewIdx) + // NodeEvent Exit(reply_to: Subject(Nil)) } diff --git a/src/musicplayer/ui/layout.gleam b/src/musicplayer/ui/layout.gleam index 34978eb..85ec87c 100644 --- a/src/musicplayer/ui/layout.gleam +++ b/src/musicplayer/ui/layout.gleam @@ -125,13 +125,11 @@ pub fn update_dimensions(layout: Layout, columns: Int, rows: Int) -> Layout { Layout(..layout, columns:, rows:) } -pub fn render(layout: Layout) -> Nil { - [layout.columns, layout.rows] - |> list.map(int.to_string) - |> string.join(" ") - |> string.append("layout - render: ", _) - |> logging.log +pub fn set_view(layout: Layout, view_idx: ViewIdx) -> Layout { + Layout(..layout, current_view: view_idx) +} +pub fn render(layout: Layout) -> Nil { let context = RenderContext( parent_width: layout.columns, @@ -149,6 +147,7 @@ pub fn render(layout: Layout) -> Nil { render_loop( view, context, + // TODO extract to function `view_index` Section(string.append("view_", string.inspect(layout.current_view))), buffer, ) diff --git a/src/musicplayer/ui/plot.gleam b/src/musicplayer/ui/plot.gleam index 91d1774..4868bf3 100644 --- a/src/musicplayer/ui/plot.gleam +++ b/src/musicplayer/ui/plot.gleam @@ -29,6 +29,7 @@ pub fn text(buffer: Buffer, text: String, x: Int, y: Int) -> Buffer { } pub fn box(buffer: Buffer, x: Int, y: Int, width: Int, height: Int) -> Buffer { + // TODO move box style to `layout.Style` let box_chars = #("┌", "┐", "└", "┘", "─", "│") let #(tl, tr, bl, br, hor, ver) = box_chars diff --git a/src/musicplayer/ui/ui.gleam b/src/musicplayer/ui/ui.gleam index 4d7cf2d..ddd5898 100644 --- a/src/musicplayer/ui/ui.gleam +++ b/src/musicplayer/ui/ui.gleam @@ -120,6 +120,12 @@ fn handle_message( process.send(reply_to, Nil) actor.stop() } + control.SetView(view_idx) -> { + let layout = layout.set_view(state.layout, view_idx) + + actor.send(state.redraw, layout) + actor.continue(State(..state, layout:)) + } } }