Implement missing UI functions
This commit is contained in:
parent
c3654ade89
commit
326dc82594
|
|
@ -163,10 +163,10 @@ struct UiItem {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct QueueView {
|
struct QueueView {
|
||||||
// FIXME: implement skip on server, remove current
|
|
||||||
current_position: usize,
|
current_position: usize,
|
||||||
list: Vec<UiItem>,
|
list: Vec<UiItem>,
|
||||||
list_state: ListState,
|
list_state: ListState,
|
||||||
|
tx: Sender<MessageFromUi>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ListView for QueueView {
|
impl ListView for QueueView {
|
||||||
|
|
@ -184,14 +184,27 @@ impl ListView for QueueView {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl QueueView {
|
impl QueueView {
|
||||||
fn skip(&self, tx: &Sender<MessageFromUi>) {
|
fn play_next(&self) {
|
||||||
if self.current_position < self.get_size() - 1 {
|
if self.current_position < self.get_size() - 1 {
|
||||||
tx.send(MessageFromUi::Next);
|
self.tx.send(MessageFromUi::NextTrack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn play_selected(&self, tx: &Sender<MessageFromUi>) {
|
fn play_prev(&self) {
|
||||||
|
if self.current_position > 0 {
|
||||||
|
self.tx.send(MessageFromUi::PrevTrack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn play_selected(&self) {
|
||||||
if let Some(pos) = self.selected() {
|
if let Some(pos) = self.selected() {
|
||||||
tx.send(MessageFromUi::SetCurrentTrack(pos));
|
self.tx.send(MessageFromUi::SetCurrentTrack(pos));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn insert_track(&mut self) {
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
fn remove_track(&mut self) {
|
||||||
|
if let Some(pos) = self.selected() {
|
||||||
|
self.tx.send(MessageFromUi::RemoveTrack(pos));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn update_position(&mut self, pos: usize) {
|
fn update_position(&mut self, pos: usize) {
|
||||||
|
|
@ -221,6 +234,7 @@ struct LibraryView {
|
||||||
list_state: ListState,
|
list_state: ListState,
|
||||||
parent: Option<String>,
|
parent: Option<String>,
|
||||||
positions: HashMap<String, usize>,
|
positions: HashMap<String, usize>,
|
||||||
|
tx: Sender<MessageFromUi>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ListView for LibraryView {
|
impl ListView for LibraryView {
|
||||||
|
|
@ -250,21 +264,32 @@ impl LibraryView {
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
fn ascend(&mut self, tx: &Sender<MessageFromUi>) {
|
fn ascend(&mut self) {
|
||||||
if let Some(parent) = self.parent.as_ref() {
|
if let Some(parent) = self.parent.as_ref() {
|
||||||
tx.send(MessageFromUi::GetLibraryNode(parent.clone()));
|
self.tx.send(MessageFromUi::GetLibraryNode(parent.clone()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn dive(&mut self, tx: &Sender<MessageFromUi>) {
|
fn dive(&mut self) {
|
||||||
if let Some(item) = self.get_selected() {
|
if let Some(item) = self.get_selected() {
|
||||||
if let UiItemKind::Node = item.kind {
|
if let UiItemKind::Node = item.kind {
|
||||||
tx.send(MessageFromUi::GetLibraryNode(item.uuid.clone()));
|
self.tx
|
||||||
|
.send(MessageFromUi::GetLibraryNode(item.uuid.clone()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn queue_replace_with_item(&mut self, tx: &Sender<MessageFromUi>) {
|
fn queue_append(&mut self) {
|
||||||
if let Some(item) = self.get_selected() {
|
if let Some(item) = self.get_selected() {
|
||||||
tx.send(MessageFromUi::ReplaceQueue(item.uuid.clone()));
|
self.tx.send(MessageFromUi::AppendTrack(item.uuid.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn queue_queue(&mut self) {
|
||||||
|
if let Some(item) = self.get_selected() {
|
||||||
|
self.tx.send(MessageFromUi::QueueTrack(item.uuid.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn queue_replace(&mut self) {
|
||||||
|
if let Some(item) = self.get_selected() {
|
||||||
|
self.tx.send(MessageFromUi::ReplaceQueue(item.uuid.clone()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn prev_selected(&self) -> usize {
|
fn prev_selected(&self) -> usize {
|
||||||
|
|
@ -341,7 +366,7 @@ struct App {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
fn new() -> App {
|
fn new(tx: Sender<MessageFromUi>) -> App {
|
||||||
let mut library = LibraryView {
|
let mut library = LibraryView {
|
||||||
title: "Library".to_string(),
|
title: "Library".to_string(),
|
||||||
uuid: "node:/".to_string(),
|
uuid: "node:/".to_string(),
|
||||||
|
|
@ -349,11 +374,13 @@ impl App {
|
||||||
list_state: ListState::default(),
|
list_state: ListState::default(),
|
||||||
positions: HashMap::new(),
|
positions: HashMap::new(),
|
||||||
parent: None,
|
parent: None,
|
||||||
|
tx: tx.clone(),
|
||||||
};
|
};
|
||||||
let queue = QueueView {
|
let queue = QueueView {
|
||||||
current_position: 0,
|
current_position: 0,
|
||||||
list: Vec::new(),
|
list: Vec::new(),
|
||||||
list_state: ListState::default(),
|
list_state: ListState::default(),
|
||||||
|
tx,
|
||||||
};
|
};
|
||||||
let now_playing = NowPlayingView {
|
let now_playing = NowPlayingView {
|
||||||
completion: None,
|
completion: None,
|
||||||
|
|
@ -388,10 +415,18 @@ enum MessageToUi {
|
||||||
// FIXME: Rename this
|
// FIXME: Rename this
|
||||||
enum MessageFromUi {
|
enum MessageFromUi {
|
||||||
GetLibraryNode(String),
|
GetLibraryNode(String),
|
||||||
Next,
|
AppendTrack(String),
|
||||||
|
QueueTrack(String),
|
||||||
|
InsertTrack(String, usize),
|
||||||
|
RemoveTrack(usize),
|
||||||
ReplaceQueue(String),
|
ReplaceQueue(String),
|
||||||
|
NextTrack,
|
||||||
|
PrevTrack,
|
||||||
|
RestartTrack,
|
||||||
SetCurrentTrack(usize),
|
SetCurrentTrack(usize),
|
||||||
TogglePlay,
|
TogglePlay,
|
||||||
|
ChangeVolume(f32),
|
||||||
|
ToggleMute,
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn poll(
|
async fn poll(
|
||||||
|
|
@ -407,19 +442,42 @@ async fn poll(
|
||||||
tx.send(MessageToUi::ReplaceLibraryNode(node.clone()));
|
tx.send(MessageToUi::ReplaceLibraryNode(node.clone()));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
MessageFromUi::AppendTrack(uuid) => {
|
||||||
|
rpc_client.append_track(&uuid).await?
|
||||||
|
}
|
||||||
|
MessageFromUi::QueueTrack(uuid) => {
|
||||||
|
rpc_client.queue_track(&uuid).await?
|
||||||
|
}
|
||||||
|
MessageFromUi::InsertTrack(uuid, pos) => {
|
||||||
|
rpc_client.insert_track(&uuid, pos).await?
|
||||||
|
}
|
||||||
|
MessageFromUi::RemoveTrack(pos) => {
|
||||||
|
rpc_client.remove_track(pos).await?
|
||||||
|
}
|
||||||
MessageFromUi::ReplaceQueue(uuid) => {
|
MessageFromUi::ReplaceQueue(uuid) => {
|
||||||
rpc_client.replace_queue(&uuid).await?
|
rpc_client.replace_queue(&uuid).await?
|
||||||
}
|
}
|
||||||
MessageFromUi::TogglePlay => {
|
MessageFromUi::NextTrack => {
|
||||||
rpc_client.toggle_play().await?
|
rpc_client.next_track().await?
|
||||||
|
}
|
||||||
|
MessageFromUi::PrevTrack => {
|
||||||
|
rpc_client.prev_track().await?
|
||||||
|
}
|
||||||
|
MessageFromUi::RestartTrack => {
|
||||||
|
rpc_client.restart_track().await?
|
||||||
}
|
}
|
||||||
MessageFromUi::SetCurrentTrack(pos) => {
|
MessageFromUi::SetCurrentTrack(pos) => {
|
||||||
rpc_client.set_current_track(pos).await?
|
rpc_client.set_current_track(pos).await?
|
||||||
}
|
}
|
||||||
MessageFromUi::Next => {
|
MessageFromUi::TogglePlay => {
|
||||||
// FIXME:
|
rpc_client.toggle_play().await?
|
||||||
|
}
|
||||||
|
MessageFromUi::ChangeVolume(delta) => {
|
||||||
|
rpc_client.change_volume(delta).await?
|
||||||
|
}
|
||||||
|
MessageFromUi::ToggleMute => {
|
||||||
|
rpc_client.toggle_mute().await?
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(resp) = rpc_client.update_stream.next() => {
|
Some(resp) = rpc_client.update_stream.next() => {
|
||||||
|
|
@ -482,7 +540,7 @@ fn run_ui(tx: Sender<MessageFromUi>, rx: Receiver<MessageToUi>) {
|
||||||
let mut terminal = Terminal::new(backend).unwrap();
|
let mut terminal = Terminal::new(backend).unwrap();
|
||||||
|
|
||||||
// create app and run it
|
// create app and run it
|
||||||
let mut app = App::new();
|
let mut app = App::new(tx.clone());
|
||||||
let tick_rate = Duration::from_millis(100);
|
let tick_rate = Duration::from_millis(100);
|
||||||
let mut last_tick = Instant::now();
|
let mut last_tick = Instant::now();
|
||||||
|
|
||||||
|
|
@ -540,8 +598,23 @@ fn run_ui(tx: Sender<MessageFromUi>, rx: Receiver<MessageToUi>) {
|
||||||
(_, KeyModifiers::NONE, KeyCode::Char(' ')) => {
|
(_, KeyModifiers::NONE, KeyCode::Char(' ')) => {
|
||||||
tx.send(MessageFromUi::TogglePlay);
|
tx.send(MessageFromUi::TogglePlay);
|
||||||
}
|
}
|
||||||
|
(_, KeyModifiers::NONE, KeyCode::Char('p')) => {
|
||||||
|
tx.send(MessageFromUi::RestartTrack);
|
||||||
|
}
|
||||||
|
(_, KeyModifiers::SHIFT, KeyCode::Char('j')) => {
|
||||||
|
tx.send(MessageFromUi::ChangeVolume(-0.1));
|
||||||
|
}
|
||||||
|
(_, KeyModifiers::SHIFT, KeyCode::Char('k')) => {
|
||||||
|
tx.send(MessageFromUi::ChangeVolume(0.1));
|
||||||
|
}
|
||||||
|
(_, KeyModifiers::NONE, KeyCode::Char('m')) => {
|
||||||
|
tx.send(MessageFromUi::ToggleMute);
|
||||||
|
}
|
||||||
(_, KeyModifiers::CONTROL, KeyCode::Char('n')) => {
|
(_, KeyModifiers::CONTROL, KeyCode::Char('n')) => {
|
||||||
app.queue.skip(&tx);
|
app.queue.play_next();
|
||||||
|
}
|
||||||
|
(_, KeyModifiers::CONTROL, KeyCode::Char('p')) => {
|
||||||
|
app.queue.play_prev();
|
||||||
}
|
}
|
||||||
(UiFocus::Library, KeyModifiers::NONE, KeyCode::Char('g')) => {
|
(UiFocus::Library, KeyModifiers::NONE, KeyCode::Char('g')) => {
|
||||||
app.library.first();
|
app.library.first();
|
||||||
|
|
@ -562,13 +635,19 @@ fn run_ui(tx: Sender<MessageFromUi>, rx: Receiver<MessageToUi>) {
|
||||||
app.library.up();
|
app.library.up();
|
||||||
}
|
}
|
||||||
(UiFocus::Library, KeyModifiers::NONE, KeyCode::Char('h')) => {
|
(UiFocus::Library, KeyModifiers::NONE, KeyCode::Char('h')) => {
|
||||||
app.library.ascend(&tx);
|
app.library.ascend();
|
||||||
}
|
}
|
||||||
(UiFocus::Library, KeyModifiers::NONE, KeyCode::Char('l')) => {
|
(UiFocus::Library, KeyModifiers::NONE, KeyCode::Char('l')) => {
|
||||||
app.library.dive(&tx);
|
app.library.dive();
|
||||||
|
}
|
||||||
|
(UiFocus::Library, KeyModifiers::NONE, KeyCode::Char('n')) => {
|
||||||
|
app.library.queue_queue();
|
||||||
|
}
|
||||||
|
(UiFocus::Library, KeyModifiers::NONE, KeyCode::Char('a')) => {
|
||||||
|
app.library.queue_append();
|
||||||
}
|
}
|
||||||
(UiFocus::Library, KeyModifiers::NONE, KeyCode::Enter) => {
|
(UiFocus::Library, KeyModifiers::NONE, KeyCode::Enter) => {
|
||||||
app.library.queue_replace_with_item(&tx);
|
app.library.queue_replace();
|
||||||
}
|
}
|
||||||
(UiFocus::Queue, KeyModifiers::NONE, KeyCode::Char('g')) => {
|
(UiFocus::Queue, KeyModifiers::NONE, KeyCode::Char('g')) => {
|
||||||
app.queue.first();
|
app.queue.first();
|
||||||
|
|
@ -589,7 +668,10 @@ fn run_ui(tx: Sender<MessageFromUi>, rx: Receiver<MessageToUi>) {
|
||||||
app.queue.up();
|
app.queue.up();
|
||||||
}
|
}
|
||||||
(UiFocus::Queue, KeyModifiers::NONE, KeyCode::Enter) => {
|
(UiFocus::Queue, KeyModifiers::NONE, KeyCode::Enter) => {
|
||||||
app.queue.play_selected(&tx);
|
app.queue.play_selected();
|
||||||
|
}
|
||||||
|
(UiFocus::Queue, KeyModifiers::NONE, KeyCode::Char('d')) => {
|
||||||
|
app.queue.remove_track();
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
use crabidy_core::proto::crabidy::{
|
use crabidy_core::proto::crabidy::{
|
||||||
crabidy_service_client::CrabidyServiceClient, get_update_stream_response::Update,
|
crabidy_service_client::CrabidyServiceClient, get_update_stream_response::Update,
|
||||||
GetLibraryNodeRequest, GetLibraryNodeResponse, GetUpdateStreamRequest, GetUpdateStreamResponse,
|
AppendRequest, ChangeVolumeRequest, GetLibraryNodeRequest, GetLibraryNodeResponse,
|
||||||
LibraryNode, ReplaceRequest, SetCurrentRequest, SetCurrentResponse, TogglePlayRequest,
|
GetUpdateStreamRequest, GetUpdateStreamResponse, InitRequest, InitResponse, InsertRequest,
|
||||||
TogglePlayResponse, InitRequest, InitResponse,
|
LibraryNode, NextRequest, PrevRequest, QueueRequest, RemoveRequest, ReplaceRequest,
|
||||||
|
RestartTrackRequest, SetCurrentRequest, SetCurrentResponse, ToggleMuteRequest,
|
||||||
|
TogglePlayRequest, TogglePlayResponse,
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
|
|
@ -87,40 +89,77 @@ impl RpcClient {
|
||||||
if self.library_node_cache.contains_key(uuid) {
|
if self.library_node_cache.contains_key(uuid) {
|
||||||
return Ok(self.library_node_cache.get(uuid));
|
return Ok(self.library_node_cache.get(uuid));
|
||||||
}
|
}
|
||||||
|
|
||||||
let get_library_node_request = Request::new(GetLibraryNodeRequest {
|
let get_library_node_request = Request::new(GetLibraryNodeRequest {
|
||||||
uuid: uuid.to_string(),
|
uuid: uuid.to_string(),
|
||||||
});
|
});
|
||||||
|
|
||||||
let response = self
|
let response = self
|
||||||
.client
|
.client
|
||||||
.get_library_node(get_library_node_request)
|
.get_library_node(get_library_node_request)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
if let Some(library_node) = response.into_inner().node {
|
if let Some(library_node) = response.into_inner().node {
|
||||||
self.library_node_cache
|
self.library_node_cache
|
||||||
.insert(uuid.to_string(), library_node);
|
.insert(uuid.to_string(), library_node);
|
||||||
return Ok(self.library_node_cache.get(uuid));
|
return Ok(self.library_node_cache.get(uuid));
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(Box::new(RpcClientError::NotFound))
|
Err(Box::new(RpcClientError::NotFound))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn append_track(&mut self, uuid: &str) -> Result<(), Box<dyn Error>> {
|
||||||
|
let append_request = Request::new(AppendRequest {
|
||||||
|
uuid: vec![uuid.to_string()],
|
||||||
|
});
|
||||||
|
self.client.append(append_request).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn queue_track(&mut self, uuid: &str) -> Result<(), Box<dyn Error>> {
|
||||||
|
let queue_request = Request::new(QueueRequest {
|
||||||
|
uuid: vec![uuid.to_string()],
|
||||||
|
});
|
||||||
|
self.client.queue(queue_request).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn insert_track(&mut self, uuid: &str, pos: usize) -> Result<(), Box<dyn Error>> {
|
||||||
|
let insert_request = Request::new(InsertRequest {
|
||||||
|
uuid: vec![uuid.to_string()],
|
||||||
|
position: pos as u32,
|
||||||
|
});
|
||||||
|
self.client.insert(insert_request).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn remove_track(&mut self, pos: usize) -> Result<(), Box<dyn Error>> {
|
||||||
|
let remove_request = Request::new(RemoveRequest {
|
||||||
|
positions: vec![pos as u32],
|
||||||
|
});
|
||||||
|
self.client.remove(remove_request).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn replace_queue(&mut self, uuid: &str) -> Result<(), Box<dyn Error>> {
|
pub async fn replace_queue(&mut self, uuid: &str) -> Result<(), Box<dyn Error>> {
|
||||||
let replace_request = Request::new(ReplaceRequest {
|
let replace_request = Request::new(ReplaceRequest {
|
||||||
uuid: vec![uuid.to_string()],
|
uuid: vec![uuid.to_string()],
|
||||||
});
|
});
|
||||||
|
self.client.replace(replace_request).await?;
|
||||||
let response = self.client.replace(replace_request).await?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn toggle_play(&mut self) -> Result<(), Box<dyn Error>> {
|
pub async fn next_track(&mut self) -> Result<(), Box<dyn Error>> {
|
||||||
let toggle_play_request = Request::new(TogglePlayRequest {});
|
let next_request = Request::new(NextRequest {});
|
||||||
|
self.client.next(next_request).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
let response = self.client.toggle_play(toggle_play_request).await?;
|
pub async fn prev_track(&mut self) -> Result<(), Box<dyn Error>> {
|
||||||
|
let prev_request = Request::new(PrevRequest {});
|
||||||
|
self.client.prev(prev_request).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn restart_track(&mut self) -> Result<(), Box<dyn Error>> {
|
||||||
|
let restart_track_request = Request::new(RestartTrackRequest {});
|
||||||
|
self.client.restart_track(restart_track_request).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -128,9 +167,25 @@ impl RpcClient {
|
||||||
let set_current_request = Request::new(SetCurrentRequest {
|
let set_current_request = Request::new(SetCurrentRequest {
|
||||||
position: pos as u32,
|
position: pos as u32,
|
||||||
});
|
});
|
||||||
|
self.client.set_current(set_current_request).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
let response = self.client.set_current(set_current_request).await?;
|
pub async fn toggle_play(&mut self) -> Result<(), Box<dyn Error>> {
|
||||||
|
let toggle_play_request = Request::new(TogglePlayRequest {});
|
||||||
|
self.client.toggle_play(toggle_play_request).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn change_volume(&mut self, delta: f32) -> Result<(), Box<dyn Error>> {
|
||||||
|
let change_volume_request = Request::new(ChangeVolumeRequest { delta });
|
||||||
|
self.client.change_volume(change_volume_request).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn toggle_mute(&mut self) -> Result<(), Box<dyn Error>> {
|
||||||
|
let toggle_mute_request = Request::new(ToggleMuteRequest {});
|
||||||
|
self.client.toggle_mute(toggle_mute_request).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue