From 92c6fe67e6c5140a71ac331d9ef4b02034bf44f2 Mon Sep 17 00:00:00 2001
From: Kubat <mael.martin31@gmail.com>
Date: Sat, 4 Feb 2023 09:24:37 +0100
Subject: [PATCH] AMADEUS: Add tabs to handle the different views

---
 src/rust/Cargo.lock                           |  2 +
 src/rust/amadeus/Cargo.toml                   |  2 +
 src/rust/amadeus/src/amadeus/mod.rs           | 16 ++--
 src/rust/amadeus/src/amadeus/side_panel.rs    |  2 +
 src/rust/amadeus/src/amadeus/tabs/mod.rs      |  3 +
 src/rust/amadeus/src/amadeus/tabs/playlist.rs | 29 ++++++
 .../{window_content.rs => tabs/queue.rs}      | 10 +-
 src/rust/amadeus/src/amadeus/tabs/search.rs   | 27 ++++++
 src/rust/amadeus/src/amadeus/window.rs        | 91 +++++++++++++++++++
 9 files changed, 169 insertions(+), 13 deletions(-)
 create mode 100644 src/rust/amadeus/src/amadeus/tabs/mod.rs
 create mode 100644 src/rust/amadeus/src/amadeus/tabs/playlist.rs
 rename src/rust/amadeus/src/amadeus/{window_content.rs => tabs/queue.rs} (66%)
 create mode 100644 src/rust/amadeus/src/amadeus/tabs/search.rs
 create mode 100644 src/rust/amadeus/src/amadeus/window.rs

diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock
index 4ac8b0ed..192af230 100644
--- a/src/rust/Cargo.lock
+++ b/src/rust/Cargo.lock
@@ -54,8 +54,10 @@ dependencies = [
  "clap",
  "commons",
  "getset",
+ "hashbrown 0.13.2",
  "iced",
  "serde",
+ "smallstring",
 ]
 
 [[package]]
diff --git a/src/rust/amadeus/Cargo.toml b/src/rust/amadeus/Cargo.toml
index 794c4105..18ef4a4a 100644
--- a/src/rust/amadeus/Cargo.toml
+++ b/src/rust/amadeus/Cargo.toml
@@ -6,10 +6,12 @@ authors.workspace = true
 license.workspace = true
 
 [dependencies]
+hashbrown.workspace = true
 serde.workspace = true
 clap.workspace = true
 iced.workspace = true
 
+smallstring = { path = "../smallstring" }
 commons = { path = "../commons" }
 amalib = { path = "../amalib" }
 getset = { path = "../getset" }
diff --git a/src/rust/amadeus/src/amadeus/mod.rs b/src/rust/amadeus/src/amadeus/mod.rs
index a9b3ed4b..4ae3d60c 100644
--- a/src/rust/amadeus/src/amadeus/mod.rs
+++ b/src/rust/amadeus/src/amadeus/mod.rs
@@ -3,7 +3,8 @@ mod client;
 mod constants;
 mod queue_control;
 mod side_panel;
-mod window_content;
+mod tabs;
+mod window;
 
 use crate::AmadeusConfig;
 use iced::{
@@ -20,7 +21,7 @@ pub struct Amadeus {
     client: client::Client,
     queue_control: queue_control::QueueControl,
     side_panel: side_panel::SidePanel,
-    window_content: window_content::WindowContent,
+    window: window::Window,
 }
 
 #[derive(Debug, Clone)]
@@ -53,7 +54,7 @@ pub enum Message {
 
     /// Got a message for the different tabs inside the window / the main
     /// content returned a message.
-    WindowContent(window_content::Message),
+    Window(window::Message),
 }
 
 impl Application for Amadeus {
@@ -71,7 +72,7 @@ impl Application for Amadeus {
                 client: client::Client::new(),
                 queue_control: queue_control::QueueControl::new(),
                 side_panel: side_panel::SidePanel::new(),
-                window_content: window_content::WindowContent::new(),
+                window: window::Window::new(),
             },
             Command::none(),
         )
@@ -136,10 +137,7 @@ impl Application for Amadeus {
             Message::SidePanel(message) => self.side_panel.update(message).map(Message::SidePanel),
 
             // Dispatch to main window content.
-            Message::WindowContent(message) => self
-                .window_content
-                .update(message)
-                .map(Message::WindowContent),
+            Message::Window(message) => self.window.update(message).map(Message::Window),
 
             // On notifications we update only the queue controler for now, in
             // the future we may update something else.
@@ -169,7 +167,7 @@ impl Application for Amadeus {
             row![
                 column![self.side_panel.view().map(Message::SidePanel)].padding(10),
                 vertical_rule(2),
-                column![self.window_content.view().map(Message::WindowContent)].padding(10),
+                column![self.window.view().map(Message::Window)].padding(10),
             ]
         ]
         .into()
diff --git a/src/rust/amadeus/src/amadeus/side_panel.rs b/src/rust/amadeus/src/amadeus/side_panel.rs
index 4b58190a..d9e45d81 100644
--- a/src/rust/amadeus/src/amadeus/side_panel.rs
+++ b/src/rust/amadeus/src/amadeus/side_panel.rs
@@ -1,4 +1,5 @@
 use super::constants::*;
+use commons::log;
 use iced::{widget::text, Command, Element};
 
 #[derive(Debug, Clone, Copy)]
@@ -16,6 +17,7 @@ impl SidePanel {
     }
 
     pub fn update(&mut self, message: Message) -> Command<Message> {
+        log::info!("got message {message:?}");
         Command::none()
     }
 
diff --git a/src/rust/amadeus/src/amadeus/tabs/mod.rs b/src/rust/amadeus/src/amadeus/tabs/mod.rs
new file mode 100644
index 00000000..6546102b
--- /dev/null
+++ b/src/rust/amadeus/src/amadeus/tabs/mod.rs
@@ -0,0 +1,3 @@
+pub mod playlist;
+pub mod queue;
+pub mod search;
diff --git a/src/rust/amadeus/src/amadeus/tabs/playlist.rs b/src/rust/amadeus/src/amadeus/tabs/playlist.rs
new file mode 100644
index 00000000..423c6948
--- /dev/null
+++ b/src/rust/amadeus/src/amadeus/tabs/playlist.rs
@@ -0,0 +1,29 @@
+use crate::amadeus::constants::*;
+use commons::log;
+use iced::{widget::text, Command, Element};
+use smallstring::SmallString;
+
+#[derive(Debug, Clone, Copy)]
+pub enum Message {}
+
+#[derive(Debug, Clone)]
+pub struct Playlist {
+    name: SmallString,
+}
+
+impl Playlist {
+    pub fn new(name: SmallString) -> Self {
+        Self { name }
+    }
+
+    pub fn update(&mut self, message: Message) -> Command<Message> {
+        log::info!("got message {message:?} for playlist {}", self.name);
+        Command::none()
+    }
+
+    pub fn view(&self) -> Element<Message> {
+        text(format!("playlist {}...", self.name))
+            .size(TEXT_SIZE)
+            .into()
+    }
+}
diff --git a/src/rust/amadeus/src/amadeus/window_content.rs b/src/rust/amadeus/src/amadeus/tabs/queue.rs
similarity index 66%
rename from src/rust/amadeus/src/amadeus/window_content.rs
rename to src/rust/amadeus/src/amadeus/tabs/queue.rs
index c8c29dee..0a5612ff 100644
--- a/src/rust/amadeus/src/amadeus/window_content.rs
+++ b/src/rust/amadeus/src/amadeus/tabs/queue.rs
@@ -1,4 +1,5 @@
-use super::constants::*;
+use crate::amadeus::constants::*;
+use commons::log;
 use iced::{widget::text, Command, Element};
 
 #[derive(Debug, Clone, Copy)]
@@ -8,18 +9,19 @@ pub enum Message {}
 struct State {}
 
 #[derive(Debug, Clone)]
-pub struct WindowContent {}
+pub struct Queue {}
 
-impl WindowContent {
+impl Queue {
     pub fn new() -> Self {
         Self {}
     }
 
     pub fn update(&mut self, message: Message) -> Command<Message> {
+        log::info!("got message {message:?}");
         Command::none()
     }
 
     pub fn view(&self) -> Element<Message> {
-        text("window content...").size(TEXT_SIZE).into()
+        text("queue...").size(TEXT_SIZE).into()
     }
 }
diff --git a/src/rust/amadeus/src/amadeus/tabs/search.rs b/src/rust/amadeus/src/amadeus/tabs/search.rs
new file mode 100644
index 00000000..4951e02a
--- /dev/null
+++ b/src/rust/amadeus/src/amadeus/tabs/search.rs
@@ -0,0 +1,27 @@
+use crate::amadeus::constants::*;
+use commons::log;
+use iced::{widget::text, Command, Element};
+
+#[derive(Debug, Clone, Copy)]
+pub enum Message {}
+
+#[derive(Debug, Clone)]
+struct State {}
+
+#[derive(Debug, Clone)]
+pub struct Search {}
+
+impl Search {
+    pub fn new() -> Self {
+        Self {}
+    }
+
+    pub fn update(&mut self, message: Message) -> Command<Message> {
+        log::info!("got message {message:?}");
+        Command::none()
+    }
+
+    pub fn view(&self) -> Element<Message> {
+        text("search...").size(TEXT_SIZE).into()
+    }
+}
diff --git a/src/rust/amadeus/src/amadeus/window.rs b/src/rust/amadeus/src/amadeus/window.rs
new file mode 100644
index 00000000..faab60a1
--- /dev/null
+++ b/src/rust/amadeus/src/amadeus/window.rs
@@ -0,0 +1,91 @@
+use crate::amadeus::{constants::*, tabs};
+use commons::log;
+use hashbrown::HashMap;
+use iced::{widget::text, Command, Element};
+use smallstring::SmallString;
+
+#[derive(Debug, Default, Clone, PartialEq, Eq)]
+pub enum View {
+    #[default]
+    Queue,
+    Search,
+    Playlist(SmallString),
+}
+
+#[derive(Debug, Clone)]
+pub enum Message {
+    Playlist(SmallString, tabs::playlist::Message),
+    Search(tabs::search::Message),
+    Queue(tabs::queue::Message),
+
+    ChangeView(View),
+
+    LoadPlaylistAndRetry(SmallString, tabs::playlist::Message),
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+struct State(View);
+
+#[derive(Debug, Clone)]
+pub struct Window {
+    state: State,
+
+    tab_search: tabs::search::Search,
+    tab_queue: tabs::queue::Queue,
+
+    tabs_playlists: HashMap<SmallString, tabs::playlist::Playlist>,
+}
+
+impl Window {
+    pub fn new() -> Self {
+        Self {
+            state: State(Default::default()),
+            tab_search: tabs::search::Search::new(),
+            tab_queue: tabs::queue::Queue::new(),
+            tabs_playlists: Default::default(),
+        }
+    }
+
+    pub fn update(&mut self, message: Message) -> Command<Message> {
+        match message {
+            Message::Playlist(name, message) => match self.tabs_playlists.get_mut(&name) {
+                Some(tab_playlist) => tab_playlist
+                    .update(message)
+                    .map(move |message| Message::Playlist(name.clone(), message)),
+                None => Command::perform(async { () }, move |()| {
+                    Message::LoadPlaylistAndRetry(name, message)
+                }),
+            },
+
+            Message::Search(message) => self.tab_search.update(message).map(Message::Search),
+            Message::Queue(message) => self.tab_queue.update(message).map(Message::Queue),
+
+            Message::ChangeView(view) => {
+                log::info!("change window view to {view:?}");
+                log::error!("handle playlist loading and queue refresh...");
+                self.state = State(view);
+                Command::none()
+            }
+
+            message => {
+                log::info!("ignored message {message:?}");
+                Command::none()
+            }
+        }
+    }
+
+    pub fn view(&self) -> Element<Message> {
+        match self.state.0 {
+            View::Queue => self.tab_queue.view().map(Message::Queue),
+            View::Search => self.tab_search.view().map(Message::Search),
+            View::Playlist(ref name) => match self.tabs_playlists.get(name) {
+                Some(tab_playlist) => tab_playlist
+                    .view()
+                    .map(move |message| Message::Playlist(name.clone(), message)),
+                None => text(format!("playlist {name} is not loaded..."))
+                    .size(TITLE_SIZE)
+                    .into(),
+            },
+        }
+    }
+}
-- 
GitLab