fix device
This commit is contained in:
parent
3b7d669a5d
commit
f055fc7c0f
3 changed files with 108 additions and 24 deletions
|
|
@ -246,7 +246,7 @@ function handleApiMessage(e: MessageEvent) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("API recv", message.type);
|
console.log("API recv", message);
|
||||||
if (message.type !== "device_event") return;
|
if (message.type !== "device_event") return;
|
||||||
const socket = sockets.get(message.deviceId);
|
const socket = sockets.get(message.deviceId);
|
||||||
if (!socket) {
|
if (!socket) {
|
||||||
|
|
@ -274,6 +274,7 @@ function handleApiMessage(e: MessageEvent) {
|
||||||
|
|
||||||
if (event.type === "party_status") {
|
if (event.type === "party_status") {
|
||||||
const quizData = event.party?.data ?? null;
|
const quizData = event.party?.data ?? null;
|
||||||
|
console.log("API quizData", quizData);
|
||||||
if (!quizData) return;
|
if (!quizData) return;
|
||||||
if (quizData.status === "results") {
|
if (quizData.status === "results") {
|
||||||
writeProxyOutput(socket, "Results");
|
writeProxyOutput(socket, "Results");
|
||||||
|
|
|
||||||
|
|
@ -38,26 +38,26 @@ pub struct QuestionData {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct QuestionDataNet<'a> {
|
pub struct QuestionDataNet {
|
||||||
pub text: &'a str,
|
pub text: String,
|
||||||
pub q_type: QuestionType,
|
pub q_type: QuestionType,
|
||||||
pub points: i32,
|
pub points: i32,
|
||||||
pub index: usize,
|
pub index: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub enum ProxyOutput<'a> {
|
pub enum ProxyOutput {
|
||||||
ConnectPrompt(&'a str),
|
ConnectPrompt(String),
|
||||||
WaitingForParty(&'a str),
|
WaitingForParty(String),
|
||||||
Question(QuestionDataNet<'a>),
|
Question(QuestionDataNet),
|
||||||
Results,
|
Results,
|
||||||
Error(&'a str),
|
Error(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<QuestionDataNet<'a>> for QuestionData {
|
impl From<QuestionDataNet> for QuestionData {
|
||||||
fn from(value: QuestionDataNet<'a>) -> Self {
|
fn from(value: QuestionDataNet) -> Self {
|
||||||
QuestionData {
|
QuestionData {
|
||||||
text: OwnedStr::from_str(value.text).unwrap(),
|
text: OwnedStr::from_str(value.text.as_str()).unwrap(),
|
||||||
q_type: value.q_type,
|
q_type: value.q_type,
|
||||||
points: value.points,
|
points: value.points,
|
||||||
index: value.index,
|
index: value.index,
|
||||||
|
|
@ -135,7 +135,7 @@ impl DeviceState {
|
||||||
&mut self.wheel
|
&mut self.wheel
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn apply_proxy_output(&mut self, data: ProxyOutput<'_>) {
|
pub fn apply_proxy_output(&mut self, data: ProxyOutput) {
|
||||||
match data {
|
match data {
|
||||||
ProxyOutput::ConnectPrompt(device_id) => {
|
ProxyOutput::ConnectPrompt(device_id) => {
|
||||||
let mut owned_device_id = OwnedStr::new();
|
let mut owned_device_id = OwnedStr::new();
|
||||||
|
|
@ -161,11 +161,32 @@ impl DeviceState {
|
||||||
}
|
}
|
||||||
ProxyOutput::Question(data) => {
|
ProxyOutput::Question(data) => {
|
||||||
let data: QuestionData = data.into();
|
let data: QuestionData = data.into();
|
||||||
let mut future_wheel = WheelData::empty();
|
let same_question = self
|
||||||
if let QuestionType::Numeric { min, max } = data.q_type {
|
.question
|
||||||
future_wheel.max = max;
|
.as_ref()
|
||||||
future_wheel.min = min;
|
.is_some_and(|question| question.index == data.index);
|
||||||
future_wheel.value = (min + max) / 2;
|
let mut future_wheel = if same_question {
|
||||||
|
self.wheel
|
||||||
|
} else {
|
||||||
|
WheelData::empty()
|
||||||
|
};
|
||||||
|
match data.q_type {
|
||||||
|
QuestionType::Numeric { min, max } => {
|
||||||
|
future_wheel.max = max;
|
||||||
|
future_wheel.min = min;
|
||||||
|
if same_question {
|
||||||
|
future_wheel.value = future_wheel.value.clamp(min, max);
|
||||||
|
} else {
|
||||||
|
future_wheel.value = (min + max) / 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QuestionType::Choice => {
|
||||||
|
future_wheel = WheelData::empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !same_question {
|
||||||
|
self.last_index = data.index;
|
||||||
|
self.title_offset = 0;
|
||||||
}
|
}
|
||||||
self.question = Some(data);
|
self.question = Some(data);
|
||||||
self.view = ViewState::Question;
|
self.view = ViewState::Question;
|
||||||
|
|
@ -235,10 +256,7 @@ impl DeviceState {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Some((
|
return Some((display_name, OwnedStr::from_str("Awaiting party").unwrap()));
|
||||||
display_name,
|
|
||||||
OwnedStr::from_str("Awaiting party").unwrap(),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.view == ViewState::Results {
|
if self.view == ViewState::Results {
|
||||||
|
|
@ -255,7 +273,10 @@ impl DeviceState {
|
||||||
let question = self.question.as_ref()?;
|
let question = self.question.as_ref()?;
|
||||||
let title_line = if question.text.len() > 16 {
|
let title_line = if question.text.len() > 16 {
|
||||||
// overscroll, should show spaces after the end
|
// overscroll, should show spaces after the end
|
||||||
self.title_offset %= question.text.len() - 31;
|
let scroll_len = question.text.len().saturating_sub(15);
|
||||||
|
if scroll_len > 0 {
|
||||||
|
self.title_offset %= scroll_len;
|
||||||
|
}
|
||||||
let end = usize::min(self.title_offset + 16, question.text.len());
|
let end = usize::min(self.title_offset + 16, question.text.len());
|
||||||
OwnedStr::from_str(&question.text[self.title_offset..end]).unwrap()
|
OwnedStr::from_str(&question.text[self.title_offset..end]).unwrap()
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -306,8 +327,8 @@ pub enum WriteType<'a> {
|
||||||
DeviceId(&'a str),
|
DeviceId(&'a str),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_proxy_output<'a>(input: &'a str) -> Result<ProxyOutput<'a>, serde_json::Error> {
|
pub fn parse_proxy_output(input: &str) -> Result<ProxyOutput, serde_json::Error> {
|
||||||
serde_json::from_str::<ProxyOutput<'a>>(input)
|
serde_json::from_str::<ProxyOutput>(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn serialize_write(data: &WriteType<'_>) -> Result<String, serde_json::Error> {
|
pub fn serialize_write(data: &WriteType<'_>) -> Result<String, serde_json::Error> {
|
||||||
|
|
@ -453,6 +474,67 @@ mod tests {
|
||||||
assert!(state.question().is_none());
|
assert!(state.question().is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parses_numeric_question_with_escaped_quotes() {
|
||||||
|
let data = parse_proxy_output(
|
||||||
|
r#"{"Question":{"text":"How many players have \"Porter Robinson\" as a favourite artist?","points":10,"index":2,"q_type":{"Numeric":{"min":0,"max":2}}}}"#,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let mut state = DeviceState::new();
|
||||||
|
|
||||||
|
state.apply_proxy_output(data);
|
||||||
|
|
||||||
|
let question = state.question().unwrap();
|
||||||
|
assert_eq!(question.index, 2);
|
||||||
|
assert_eq!(
|
||||||
|
question.text.as_str(),
|
||||||
|
"How many players have \"Porter Robinson\" as a favourite artist?",
|
||||||
|
);
|
||||||
|
assert_eq!(state.wheel().value, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn preserves_numeric_wheel_for_same_question_updates() {
|
||||||
|
let mut state = DeviceState::new();
|
||||||
|
state.apply_proxy_output(
|
||||||
|
parse_proxy_output(
|
||||||
|
r#"{"Question":{"text":"Q","points":10,"index":2,"q_type":{"Numeric":{"min":0,"max":10}}}}"#,
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
|
state.wheel_mut().value = 7;
|
||||||
|
|
||||||
|
state.apply_proxy_output(
|
||||||
|
parse_proxy_output(
|
||||||
|
r#"{"Question":{"text":"Q updated","points":10,"index":2,"q_type":{"Numeric":{"min":0,"max":10}}}}"#,
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(state.wheel().value, 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn resets_numeric_wheel_for_new_questions() {
|
||||||
|
let mut state = DeviceState::new();
|
||||||
|
state.apply_proxy_output(
|
||||||
|
parse_proxy_output(
|
||||||
|
r#"{"Question":{"text":"Q","points":10,"index":2,"q_type":{"Numeric":{"min":0,"max":10}}}}"#,
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
|
state.wheel_mut().value = 7;
|
||||||
|
|
||||||
|
state.apply_proxy_output(
|
||||||
|
parse_proxy_output(
|
||||||
|
r#"{"Question":{"text":"Next","points":10,"index":3,"q_type":{"Numeric":{"min":0,"max":10}}}}"#,
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(state.wheel().value, 5);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parses_and_renders_waiting_for_party() {
|
fn parses_and_renders_waiting_for_party() {
|
||||||
let data = parse_proxy_output(r#"{"WaitingForParty":"User"}"#).unwrap();
|
let data = parse_proxy_output(r#"{"WaitingForParty":"User"}"#).unwrap();
|
||||||
|
|
|
||||||
|
|
@ -89,6 +89,7 @@ pub async fn tcp_read_loop(
|
||||||
};
|
};
|
||||||
if let Some(last) = str.lines().last() {
|
if let Some(last) = str.lines().last() {
|
||||||
let Ok(data) = device_state::parse_proxy_output(last) else {
|
let Ok(data) = device_state::parse_proxy_output(last) else {
|
||||||
|
println!("parse proxy output failed: {}", last);
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
let mut state = STATE.lock().await;
|
let mut state = STATE.lock().await;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue