From 0c4c085dd0cb8f8df7efa14cc919371cc2354508 Mon Sep 17 00:00:00 2001 From: Alexander Heldt Date: Thu, 25 Dec 2025 19:49:08 +0100 Subject: [PATCH] Add ability to switch View --- src/musicplayer/control.gleam | 7 +++++++ src/musicplayer/musicplayer.gleam | 16 ++++++++++++++++ src/musicplayer/ui/control.gleam | 4 ++-- src/musicplayer/ui/layout.gleam | 13 +++++++++---- src/musicplayer/ui/ui.gleam | 28 ++++++++++++++++++++++++++-- 5 files changed, 60 insertions(+), 8 deletions(-) diff --git a/src/musicplayer/control.gleam b/src/musicplayer/control.gleam index 3246f00..6d1f7b8 100644 --- a/src/musicplayer/control.gleam +++ b/src/musicplayer/control.gleam @@ -1,4 +1,5 @@ import gleam/string +import musicplayer/ui/layout import musicplayer/input/key.{type Key} @@ -11,6 +12,8 @@ pub type Control { TogglePlayPause Search(input: String, capturing: Bool) + SetView(view_idx: layout.ViewIdx) + Exit } @@ -25,6 +28,10 @@ pub fn idle_from_key(key: Key) -> Result(Control, Nil) { case key { key.Char(char) -> { case char { + // Views are zero indexed + "1" -> Ok(SetView(0)) + "2" -> Ok(SetView(1)) + " " -> Ok(TogglePlayPause) "/" -> Ok(Search(input: "", capturing: True)) "q" -> Ok(Exit) diff --git a/src/musicplayer/musicplayer.gleam b/src/musicplayer/musicplayer.gleam index 31d006c..a3dc53d 100644 --- a/src/musicplayer/musicplayer.gleam +++ b/src/musicplayer/musicplayer.gleam @@ -51,6 +51,15 @@ fn handle_message(state: State, key: Key) -> actor.Next(State, Key) { Error(_) -> actor.continue(state) Ok(c) -> case c { + control.SetView(view_idx) -> { + logging.log( + "musicplayer - setting current view to: " + <> string.inspect(view_idx), + ) + + update_current_view(state.ui, view_idx) + actor.continue(state) + } control.Search(input, capturing) -> { case capturing { True -> { @@ -146,6 +155,13 @@ fn update_search(ui: Subject(ui_control.Control), content: String) -> Nil { process.send(ui, ui_control.UpdateState(layout.Search, content)) } +fn update_current_view( + ui: Subject(ui_control.Control), + view_idx: layout.ViewIdx, +) { + process.send(ui, ui_control.SetView(view_idx)) +} + /// `forward_key` listens to a subject onto which `input` will send messages with `Key`s /// that is then forwarded to the `musicplayer` agent to handle fn forward_key(musicplayer: Subject(Key), input_keys: Subject(Key)) -> Nil { diff --git a/src/musicplayer/ui/control.gleam b/src/musicplayer/ui/control.gleam index 1276950..a800761 100644 --- a/src/musicplayer/ui/control.gleam +++ b/src/musicplayer/ui/control.gleam @@ -1,11 +1,11 @@ import gleam/erlang/process.{type Subject} -import musicplayer/ui/layout.{type Section} +import musicplayer/ui/layout.{type Section, type ViewIdx} pub type Control { UpdateDimensions(columns: Int, rows: Int) UpdateState(section: Section, content: String) - SetView(view_idx: layout.ViewIdx) + SetView(view_idx: ViewIdx) Exit(reply_to: Subject(Nil)) } diff --git a/src/musicplayer/ui/layout.gleam b/src/musicplayer/ui/layout.gleam index 6d1b919..ff845f6 100644 --- a/src/musicplayer/ui/layout.gleam +++ b/src/musicplayer/ui/layout.gleam @@ -1,4 +1,5 @@ import gleam/dict +import gleam/int import gleam/list import gleam/pair import gleam/set @@ -83,7 +84,7 @@ fn view_loop(i: ViewIdx, view_nodes: List(#(Section, Node))) -> View { dict.from_list(view_nodes) |> dict.insert( - Section(string.append("view_", string.inspect(i))), + view_index_section(i), Row( content: "", style: Style(dimensions: Percent(width: 100, height: 100)), @@ -92,6 +93,11 @@ fn view_loop(i: ViewIdx, view_nodes: List(#(Section, Node))) -> View { ) } +/// Takes a ViewIndex and create a Section key from it +fn view_index_section(view_idx: ViewIdx) -> Section { + Section(string.append("view_", int.to_string(view_idx))) +} + pub fn update_section( layout: Layout, section: Section, @@ -123,7 +129,7 @@ pub fn update_dimensions(layout: Layout, columns: Int, rows: Int) -> Layout { Layout(..layout, columns:, rows:) } -pub fn set_view(layout: Layout, view_idx: ViewIdx) -> Layout { +pub fn update_current_view(layout: Layout, view_idx: ViewIdx) -> Layout { Layout(..layout, current_view: view_idx) } @@ -145,8 +151,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))), + view_index_section(layout.current_view), buffer, ) |> plot.flush_buffer(layout.columns, layout.rows) diff --git a/src/musicplayer/ui/ui.gleam b/src/musicplayer/ui/ui.gleam index ddd5898..a12fede 100644 --- a/src/musicplayer/ui/ui.gleam +++ b/src/musicplayer/ui/ui.gleam @@ -23,7 +23,31 @@ pub fn new() -> Result(Subject(Control), String) { #( layout.Header, layout.Row( - content: "Foo (1) | Bar (2) | Baz (3)", + content: "Foo <1> | Bar (2)", + style: layout.Style(dimensions: layout.Percent( + width: 100, + height: 50, + )), + children: [], + ), + ), + #( + layout.PlaybackTime, + layout.Row( + content: "00:00", + style: layout.Style(dimensions: layout.Percent( + width: 100, + height: 50, + )), + children: [], + ), + ), + ], + [ + #( + layout.Header, + layout.Row( + content: "Foo (1) | Bar <2>", style: layout.Style(dimensions: layout.Percent( width: 100, height: 33, @@ -121,7 +145,7 @@ fn handle_message( actor.stop() } control.SetView(view_idx) -> { - let layout = layout.set_view(state.layout, view_idx) + let layout = layout.update_current_view(state.layout, view_idx) actor.send(state.redraw, layout) actor.continue(State(..state, layout:))