use config::{AppConfig, MusicServer, MusicService, Source};
use db::ReadDb;
use dioxus::prelude::*;
use server::source::{ActiveSource, AuthOutcome};
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum ConnStatus {
Connecting,
Online,
Offline,
}
pub fn use_connection_status() -> Memo<ConnStatus> {
let active_source = use_context::<Signal<ActiveSource>>();
let config = use_context::<Signal<AppConfig>>();
let mut status = use_signal(|| ConnStatus::Connecting);
use_effect(move || {
let src = active_source.read().clone();
if matches!(config.peek().active_source, Source::Local) {
status.set(ConnStatus::Online);
return;
}
status.set(ConnStatus::Connecting);
spawn(async move {
status.set(match src.validate().await {
AuthOutcome::Valid => ConnStatus::Online,
AuthOutcome::Expired | AuthOutcome::Unreachable => ConnStatus::Offline,
});
});
});
use_memo(move || *status.read())
}
pub async fn apply_source_switch(
mut config: Signal<AppConfig>,
db: ReadDb,
source: Source,
) -> bool {
match source {
Source::Local => {
config.write().clear_active_server();
tracing::info!(target: "kopuz::source", source = "local", "source switched");
true
}
Source::Server(id) => {
let Some(saved) = config.peek().find_saved_server(&id).cloned() else {
return false;
};
let is_anon = saved.service == MusicService::YtMusic && saved.yt_anonymous;
let stored = db.load_server(&saved.id).await.ok().flatten();
let stored_token = stored.as_ref().and_then(|s| s.access_token.clone());
let stored_user = stored.as_ref().and_then(|s| s.user_id.clone());
let has_creds = stored_token.as_deref().is_some_and(|t| !t.is_empty());
let active = MusicServer {
name: saved.name,
url: saved.url,
service: saved.service,
access_token: if is_anon {
Some(String::new())
} else {
stored_token
},
user_id: stored_user,
id: Some(saved.id.clone()),
yt_browser: saved.yt_browser,
yt_anonymous: is_anon,
};
{
let mut cfg = config.write();
cfg.set_active_server_snapshot(active);
}
tracing::info!(target: "kopuz::source", server = %id, "source switched");
has_creds || is_anon
}
}
}
pub fn use_switch_source() -> impl Fn(Source) + Clone {
let config = use_context::<Signal<AppConfig>>();
let db = use_context::<ReadDb>();
move |source: Source| {
let db = db.clone();
spawn(async move {
apply_source_switch(config, db, source).await;
});
}
}