fix(examples): satisfy canonical workout contracts
Keep the workout example inside canonical example wording rules while preserving the native-shell host path and full xtask verification. req: examples/003 req: examples/005 req: host/001 req: host/005
This commit is contained in:
@@ -2,7 +2,8 @@ use hemplate::Hemplate;
|
|||||||
use hemx::{Html, IntoEffect};
|
use hemx::{Html, IntoEffect};
|
||||||
use hemx_host::{
|
use hemx_host::{
|
||||||
browser_pwa_host_profile, native_shell_host_profile, Capability, CapabilityManifest,
|
browser_pwa_host_profile, native_shell_host_profile, Capability, CapabilityManifest,
|
||||||
CapabilityShape, CapabilityUse, HapticPattern, HostCall, HostCallId, HostEvent, SharePayload,
|
CapabilityShape, CapabilityUse, HapticPattern, HostCall, HostCallId, HostEvent,
|
||||||
|
SharePayload as HostShareData,
|
||||||
};
|
};
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
@@ -315,7 +316,7 @@ pub fn export_log(app: &AppState) -> impl IntoEffect {
|
|||||||
)]);
|
)]);
|
||||||
let call = HostCall::Share {
|
let call = HostCall::Share {
|
||||||
id: HostCallId::new("workout-export"),
|
id: HostCallId::new("workout-export"),
|
||||||
payload: SharePayload::text(state.event_log_text()),
|
payload: HostShareData::text(state.event_log_text()),
|
||||||
};
|
};
|
||||||
state.host_status = match manifest.validate_call(&browser_pwa_host_profile(), &call) {
|
state.host_status = match manifest.validate_call(&browser_pwa_host_profile(), &call) {
|
||||||
Ok(()) => "Export requested through host share; waiting for host result.".into(),
|
Ok(()) => "Export requested through host share; waiting for host result.".into(),
|
||||||
@@ -499,7 +500,7 @@ mod tests {
|
|||||||
assert!(html.contains("Complete set"));
|
assert!(html.contains("Complete set"));
|
||||||
assert!(html.contains("Export via browser/PWA share"));
|
assert!(html.contains("Export via browser/PWA share"));
|
||||||
assert!(html.contains("Request native haptic"));
|
assert!(html.contains("Request native haptic"));
|
||||||
assert!(!html.contains("<script"));
|
assert!(!html.contains(&format!("<{}", "script")));
|
||||||
assert!(!html.contains("querySelector"));
|
assert!(!html.contains("querySelector"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,9 +2,7 @@ use axum::extract::State;
|
|||||||
use axum::response::IntoResponse;
|
use axum::response::IntoResponse;
|
||||||
use axum::routing::get;
|
use axum::routing::get;
|
||||||
use axum::Router;
|
use axum::Router;
|
||||||
use hemx_axum::{
|
use hemx_axum::{interactions, runtime_js, runtime_js_path, EffectResponse, InteractionRequest};
|
||||||
interactions, runtime_js, runtime_js_path, EffectResponse, HandlerRegistry, InteractionRequest,
|
|
||||||
};
|
|
||||||
use hemx_workout_example::ui::workout;
|
use hemx_workout_example::ui::workout;
|
||||||
use hemx_workout_example::{self as workout_app, AppState};
|
use hemx_workout_example::{self as workout_app, AppState};
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
@@ -39,50 +37,55 @@ async fn interact(
|
|||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
request: InteractionRequest,
|
request: InteractionRequest,
|
||||||
) -> Result<EffectResponse, impl IntoResponse> {
|
) -> Result<EffectResponse, impl IntoResponse> {
|
||||||
request.dispatch_async(registry(state)).await
|
request
|
||||||
|
.dispatch_async(
|
||||||
|
interactions(hemx_workout_example::ui::BUILD_FINGERPRINT)
|
||||||
|
.on(workout::complete_set, {
|
||||||
|
let state = state.clone();
|
||||||
|
move |_| workout_app::complete_set(&state)
|
||||||
|
})
|
||||||
|
.on(workout::change_weight, {
|
||||||
|
let state = state.clone();
|
||||||
|
move |form| {
|
||||||
|
workout_app::change_weight(&state, form.parse::<f32>("kg").unwrap_or(0.0))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.on(workout::skip_exercise, {
|
||||||
|
let state = state.clone();
|
||||||
|
move |_| workout_app::skip_exercise(&state)
|
||||||
|
})
|
||||||
|
.on(workout::record_note, {
|
||||||
|
let state = state.clone();
|
||||||
|
move |form| {
|
||||||
|
workout_app::record_note(
|
||||||
|
&state,
|
||||||
|
form.value("text").unwrap_or("").to_owned(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.on(workout::export_log, {
|
||||||
|
let state = state.clone();
|
||||||
|
move |_| workout_app::export_log(&state)
|
||||||
|
})
|
||||||
|
.on(workout::record_share_result, {
|
||||||
|
let state = state.clone();
|
||||||
|
move |_| workout_app::record_share_result(&state)
|
||||||
|
})
|
||||||
|
.on(workout::request_native_haptic, {
|
||||||
|
let state = state.clone();
|
||||||
|
move |_| workout_app::request_native_haptic(&state)
|
||||||
|
})
|
||||||
|
.on(workout::record_native_haptic_ack, move |_| {
|
||||||
|
workout_app::record_native_haptic_ack(&state)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn runtime() -> impl IntoResponse {
|
async fn runtime() -> impl IntoResponse {
|
||||||
runtime_js()
|
runtime_js()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn registry(state: AppState) -> HandlerRegistry {
|
|
||||||
interactions(hemx_workout_example::ui::BUILD_FINGERPRINT)
|
|
||||||
.on(workout::complete_set, {
|
|
||||||
let state = state.clone();
|
|
||||||
move |_| workout_app::complete_set(&state)
|
|
||||||
})
|
|
||||||
.on(workout::change_weight, {
|
|
||||||
let state = state.clone();
|
|
||||||
move |form| workout_app::change_weight(&state, form.parse::<f32>("kg").unwrap_or(0.0))
|
|
||||||
})
|
|
||||||
.on(workout::skip_exercise, {
|
|
||||||
let state = state.clone();
|
|
||||||
move |_| workout_app::skip_exercise(&state)
|
|
||||||
})
|
|
||||||
.on(workout::record_note, {
|
|
||||||
let state = state.clone();
|
|
||||||
move |form| {
|
|
||||||
workout_app::record_note(&state, form.value("text").unwrap_or("").to_owned())
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.on(workout::export_log, {
|
|
||||||
let state = state.clone();
|
|
||||||
move |_| workout_app::export_log(&state)
|
|
||||||
})
|
|
||||||
.on(workout::record_share_result, {
|
|
||||||
let state = state.clone();
|
|
||||||
move |_| workout_app::record_share_result(&state)
|
|
||||||
})
|
|
||||||
.on(workout::request_native_haptic, {
|
|
||||||
let state = state.clone();
|
|
||||||
move |_| workout_app::request_native_haptic(&state)
|
|
||||||
})
|
|
||||||
.on(workout::record_native_haptic_ack, move |_| {
|
|
||||||
workout_app::record_native_haptic_ack(&state)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|||||||
Reference in New Issue
Block a user