diff --git a/src/hooks/mod.rs b/src/hooks/mod.rs index 89e3355..efc31dc 100644 --- a/src/hooks/mod.rs +++ b/src/hooks/mod.rs @@ -1,6 +1,6 @@ use dioxus::{ CapturedError, - fullstack::{Loader, Loading, WebSocketOptions, use_websocket}, + fullstack::{Loader, Loading, WebSocketOptions}, prelude::*, }; use serde::{Serialize, de::DeserializeOwned}; @@ -13,6 +13,29 @@ use crate::{ }, }; +fn use_on_document_become_visible(mut callback: impl FnMut() + 'static) { + let callback = use_callback(move |_| callback()); + use_effect(move || { + spawn(async move { + let mut eval = document::eval( + r#" + document.addEventListener("visibilitychange", () => { + if (!document.hidden) { + dioxus.send(0); + } + }); + "#, + ); + loop { + eval.recv::() + .await + .expect("The JS code returned a value not parsable to `u8`."); + callback.call(()); + } + }); + }); +} + #[allow(clippy::result_large_err)] fn sort_loader_result( result: Result>, Loading>, @@ -34,17 +57,37 @@ where E: Into + 'static, { let mut refresh_tick = use_signal(|| 0u64); + let mut websocket_reset_tick = use_signal(|| 0u64); let loader = use_loader(move || { let _ = refresh_tick(); // Read => dependency. future() }); - let mut socket = use_websocket(|| subscribe_to_updates(WebSocketOptions::default())); - use_future(move || async move { - while socket.recv().await.is_ok() { - refresh_tick += 1; - } + use_effect(move || { + let initial_websocket_reset_tick = websocket_reset_tick(); + spawn(async move { + let Ok(socket) = + subscribe_to_updates(WebSocketOptions::new().with_automatic_reconnect()).await + else { + return; + }; + while socket.recv().await.is_ok() { + if websocket_reset_tick() != initial_websocket_reset_tick { + // A new WebSocket has been created (a new task spawned), cleaning this one up. + break; + } + refresh_tick += 1; + } + }); + }); + + /* So that when the device goes to sleep or suspends the app, the WebSocket gets recreated on + waking up. It is important to do this only on becoming visible (document.hidden == false), + because becoming hidden is the part when network may not work and thus cause errors. */ + use_on_document_become_visible(move || { + websocket_reset_tick += 1; + refresh_tick += 1; }); loader