mirror of
https://github.com/pcvolkmer/arsnova-client.git
synced 2025-04-19 19:16:51 +00:00
feat: add method to send feedback to service
This commit is contained in:
parent
a9b0e2f49a
commit
168717a78b
@ -64,6 +64,8 @@ async fn main() -> Result<(), ()> {
|
|||||||
|
|
||||||
let (tx, rx) = channel::<Feedback>(10);
|
let (tx, rx) = channel::<Feedback>(10);
|
||||||
|
|
||||||
|
let (fb_tx, fb_rx) = channel::<u8>(10);
|
||||||
|
|
||||||
let _ = tx
|
let _ = tx
|
||||||
.clone()
|
.clone()
|
||||||
.send(client.get_feedback(&cli.room).await.unwrap())
|
.send(client.get_feedback(&cli.room).await.unwrap())
|
||||||
@ -81,25 +83,43 @@ async fn main() -> Result<(), ()> {
|
|||||||
|
|
||||||
let l2 = create_ui(&mut terminal, &title, rx);
|
let l2 = create_ui(&mut terminal, &title, rx);
|
||||||
|
|
||||||
let l3 = tokio::spawn(async {
|
let l3 = tokio::spawn(async move {
|
||||||
loop {
|
loop {
|
||||||
if event::poll(std::time::Duration::from_millis(16))
|
if event::poll(std::time::Duration::from_millis(16))
|
||||||
.map_err(|_| ())
|
.map_err(|_| ())
|
||||||
.is_ok()
|
.is_ok()
|
||||||
{
|
{
|
||||||
if let event::Event::Key(key) = event::read().map_err(|_| ()).unwrap() {
|
if let event::Event::Key(key) = event::read().map_err(|_| ()).unwrap() {
|
||||||
if key.kind == KeyEventKind::Press && key.code == KeyCode::Esc {
|
if key.kind == KeyEventKind::Press {
|
||||||
break;
|
match key.code {
|
||||||
|
KeyCode::Esc => break,
|
||||||
|
KeyCode::Char('a') | KeyCode::Char('1') => {
|
||||||
|
let _ = fb_tx.send(0).await;
|
||||||
|
}
|
||||||
|
KeyCode::Char('b') | KeyCode::Char('2') => {
|
||||||
|
let _ = fb_tx.send(1).await;
|
||||||
|
}
|
||||||
|
KeyCode::Char('c') | KeyCode::Char('3') => {
|
||||||
|
let _ = fb_tx.send(2).await;
|
||||||
|
}
|
||||||
|
KeyCode::Char('d') | KeyCode::Char('4') => {
|
||||||
|
let _ = fb_tx.send(3).await;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let l4 = client.register_feedback_receiver(&cli.room, fb_rx);
|
||||||
|
|
||||||
select! {
|
select! {
|
||||||
_ = l1 => {},
|
_ = l1 => {},
|
||||||
_ = l2 => {},
|
_ = l2 => {},
|
||||||
_ = l3 => {},
|
_ = l3 => {},
|
||||||
|
_ = l4 => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
let _ = stdout().execute(LeaveAlternateScreen).map_err(|_| ());
|
let _ = stdout().execute(LeaveAlternateScreen).map_err(|_| ());
|
||||||
@ -113,7 +133,10 @@ async fn create_ui(
|
|||||||
title: &str,
|
title: &str,
|
||||||
mut rx: Receiver<Feedback>,
|
mut rx: Receiver<Feedback>,
|
||||||
) -> Result<(), ()> {
|
) -> Result<(), ()> {
|
||||||
fn feedback_paragraph(feedback: &Feedback, idx: usize, width: usize) -> Paragraph<'static> {
|
const ICONS: [&str; 4] = ["Super", "Gut", "Nicht so gut", "Schlecht"];
|
||||||
|
|
||||||
|
let feedback_paragraph =
|
||||||
|
|feedback: &Feedback, idx: usize, width: usize| -> Paragraph<'static> {
|
||||||
let value = match idx {
|
let value = match idx {
|
||||||
0 => feedback.very_good,
|
0 => feedback.very_good,
|
||||||
1 => feedback.good,
|
1 => feedback.good,
|
||||||
@ -122,11 +145,16 @@ async fn create_ui(
|
|||||||
_ => 0,
|
_ => 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let icons = ICONS
|
||||||
|
.iter()
|
||||||
|
.map(|icon| format!("{: <12}", icon))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let icon = match idx {
|
let icon = match idx {
|
||||||
0 => "Super ",
|
0 => &icons[0],
|
||||||
1 => "Gut ",
|
1 => &icons[1],
|
||||||
2 => "Nicht so gut",
|
2 => &icons[2],
|
||||||
3 => "Schlecht ",
|
3 => &icons[3],
|
||||||
_ => " ",
|
_ => " ",
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -145,7 +173,7 @@ async fn create_ui(
|
|||||||
])),
|
])),
|
||||||
_ => Paragraph::default(),
|
_ => Paragraph::default(),
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let feedback = match rx.recv().await {
|
let feedback = match rx.recv().await {
|
||||||
@ -156,9 +184,11 @@ async fn create_ui(
|
|||||||
let _ = terminal.draw(|frame| {
|
let _ = terminal.draw(|frame| {
|
||||||
let layout = Layout::default()
|
let layout = Layout::default()
|
||||||
.direction(Direction::Vertical)
|
.direction(Direction::Vertical)
|
||||||
.constraints(vec![
|
.constraints([
|
||||||
Constraint::Max(1),
|
Constraint::Max(1),
|
||||||
Constraint::Max(6),
|
Constraint::Max(6),
|
||||||
|
Constraint::Max(2),
|
||||||
|
Constraint::Max(1),
|
||||||
Constraint::Min(1),
|
Constraint::Min(1),
|
||||||
Constraint::Max(1),
|
Constraint::Max(1),
|
||||||
])
|
])
|
||||||
@ -185,12 +215,12 @@ async fn create_ui(
|
|||||||
Paragraph::new("Beenden mit <Esc>")
|
Paragraph::new("Beenden mit <Esc>")
|
||||||
.on_blue()
|
.on_blue()
|
||||||
.alignment(Alignment::Left),
|
.alignment(Alignment::Left),
|
||||||
layout[3],
|
layout[5],
|
||||||
);
|
);
|
||||||
|
|
||||||
let feedback_layout = Layout::default()
|
let feedback_layout = Layout::default()
|
||||||
.direction(Direction::Vertical)
|
.direction(Direction::Vertical)
|
||||||
.constraints(vec![
|
.constraints([
|
||||||
Constraint::Max(1),
|
Constraint::Max(1),
|
||||||
Constraint::Max(1),
|
Constraint::Max(1),
|
||||||
Constraint::Max(1),
|
Constraint::Max(1),
|
||||||
@ -205,6 +235,31 @@ async fn create_ui(
|
|||||||
feedback_layout[idx],
|
feedback_layout[idx],
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let button_layout = Layout::default()
|
||||||
|
.direction(Direction::Horizontal)
|
||||||
|
.constraints([
|
||||||
|
Constraint::Percentage(25),
|
||||||
|
Constraint::Percentage(25),
|
||||||
|
Constraint::Percentage(25),
|
||||||
|
Constraint::Percentage(25),
|
||||||
|
Constraint::Min(0),
|
||||||
|
])
|
||||||
|
.split(layout[3]);
|
||||||
|
|
||||||
|
ICONS.iter().enumerate().for_each(|(idx, label)| {
|
||||||
|
frame.render_widget(
|
||||||
|
Paragraph::new(Line::from(vec![
|
||||||
|
Span::raw(format!(" {} ", idx + 1))
|
||||||
|
.white()
|
||||||
|
.on_magenta()
|
||||||
|
.bold(),
|
||||||
|
Span::raw(format!("{: ^14}", label)).white().on_black(),
|
||||||
|
]))
|
||||||
|
.alignment(Alignment::Center),
|
||||||
|
button_layout[idx],
|
||||||
|
)
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 48 KiB |
@ -29,7 +29,7 @@ use reqwest::{IntoUrl, StatusCode};
|
|||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use tokio::join;
|
use tokio::join;
|
||||||
use tokio::sync::mpsc::Sender;
|
use tokio::sync::mpsc::{Receiver, Sender};
|
||||||
use tokio_tungstenite::connect_async;
|
use tokio_tungstenite::connect_async;
|
||||||
use tokio_tungstenite::tungstenite::Message;
|
use tokio_tungstenite::tungstenite::Message;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
@ -361,6 +361,66 @@ impl Client<LoggedIn> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Register feedback channel receiver and send incoming feedback to service
|
||||||
|
///
|
||||||
|
/// This method fails on connection or response errors and if
|
||||||
|
/// no room is available with given room ID.
|
||||||
|
pub async fn register_feedback_receiver(
|
||||||
|
&self,
|
||||||
|
short_id: &str,
|
||||||
|
mut receiver: Receiver<u8>,
|
||||||
|
) -> Result<(), ClientError> {
|
||||||
|
let room_info = self.get_room_info(short_id).await?;
|
||||||
|
|
||||||
|
let ws_url = self.api_url.replace("http", "ws");
|
||||||
|
let (socket, _) = connect_async(Url::parse(&format!("{}/ws/websocket", ws_url)).unwrap())
|
||||||
|
.await
|
||||||
|
.map_err(|_| ConnectionError)?;
|
||||||
|
|
||||||
|
let (mut write, _) = socket.split();
|
||||||
|
|
||||||
|
let user_id = self.get_user_id().unwrap_or_default();
|
||||||
|
|
||||||
|
if write
|
||||||
|
.send(Message::Text(
|
||||||
|
WsConnectMessage::new(self.token.as_ref().unwrap()).to_string(),
|
||||||
|
))
|
||||||
|
.await
|
||||||
|
.is_ok()
|
||||||
|
{
|
||||||
|
return match write
|
||||||
|
.send(Message::Text(
|
||||||
|
WsSubscribeMessage::new(&room_info.id).to_string(),
|
||||||
|
))
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(_) => loop {
|
||||||
|
if let Some(value) = receiver.recv().await {
|
||||||
|
let payload = json!({
|
||||||
|
"type": "CreateFeedback",
|
||||||
|
"payload": {
|
||||||
|
"roomId": room_info.id,
|
||||||
|
"userId": user_id,
|
||||||
|
"value": value
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.to_string();
|
||||||
|
|
||||||
|
let _ = write
|
||||||
|
.send(Message::Text(format!(
|
||||||
|
"SEND\ndestination:/queue/feedback.command\ncontent-type:application/json\ncontent-length:{}\n\n{}\0",
|
||||||
|
payload.chars().count(),
|
||||||
|
payload,
|
||||||
|
))).await;
|
||||||
|
};
|
||||||
|
},
|
||||||
|
Err(_) => Err(ConnectionError),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(ConnectionError)
|
||||||
|
}
|
||||||
|
|
||||||
/// Registers a handler to get notifications on feedback change.
|
/// Registers a handler to get notifications on feedback change.
|
||||||
///
|
///
|
||||||
/// This is done by using websocket connections to ARSnova.
|
/// This is done by using websocket connections to ARSnova.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user