mirror of
https://codeberg.org/waydeer/layer-shika.git
synced 2025-12-12 23:25:55 +00:00
158 lines
4.7 KiB
Rust
158 lines
4.7 KiB
Rust
use std::path::PathBuf;
|
|
use std::thread;
|
|
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
|
|
|
|
use anyhow::Result;
|
|
use layer_shika::calloop::TimeoutAction;
|
|
use layer_shika::calloop::channel::Sender;
|
|
use layer_shika::prelude::*;
|
|
use layer_shika::slint_interpreter::Value;
|
|
|
|
enum UiMessage {
|
|
UpdateStatus(String),
|
|
IncrementCounter(i32),
|
|
BackgroundTaskComplete(String),
|
|
}
|
|
|
|
fn main() -> Result<()> {
|
|
env_logger::builder()
|
|
.filter_level(log::LevelFilter::Info)
|
|
.init();
|
|
|
|
log::info!("Starting channel example");
|
|
|
|
let ui_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("ui/demo.slint");
|
|
|
|
let mut shell = Shell::from_file(&ui_path)
|
|
.surface("Main")
|
|
.size(400, 200)
|
|
.layer(Layer::Top)
|
|
.namespace("channel-example")
|
|
.build()?;
|
|
|
|
let handle = shell.event_loop_handle();
|
|
|
|
let (_token, sender) = handle.add_channel(|message: UiMessage, app_state| {
|
|
for surface in app_state.all_outputs() {
|
|
let component = surface.component_instance();
|
|
|
|
match &message {
|
|
UiMessage::UpdateStatus(status) => {
|
|
if let Err(e) =
|
|
component.set_property("status", Value::String(status.clone().into()))
|
|
{
|
|
log::error!("Failed to set status: {e}");
|
|
}
|
|
log::info!("Status updated: {}", status);
|
|
}
|
|
UiMessage::IncrementCounter(delta) => {
|
|
if let Ok(Value::Number(current)) = component.get_property("counter") {
|
|
#[allow(clippy::cast_possible_truncation)]
|
|
let new_value = current as i32 + delta;
|
|
if let Err(e) =
|
|
component.set_property("counter", Value::Number(f64::from(new_value)))
|
|
{
|
|
log::error!("Failed to set counter: {e}");
|
|
}
|
|
log::debug!("Counter: {}", new_value);
|
|
}
|
|
}
|
|
UiMessage::BackgroundTaskComplete(result) => {
|
|
if let Err(e) = component
|
|
.set_property("status", Value::String(format!("Done: {result}").into()))
|
|
{
|
|
log::error!("Failed to set status: {e}");
|
|
}
|
|
log::info!("Background task complete: {}", result);
|
|
}
|
|
}
|
|
}
|
|
})?;
|
|
|
|
handle.add_timer(Duration::from_secs(1), |_instant, app_state| {
|
|
let time_str = current_time_string();
|
|
|
|
for surface in app_state.all_outputs() {
|
|
if let Err(e) = surface
|
|
.component_instance()
|
|
.set_property("time", Value::String(time_str.clone().into()))
|
|
{
|
|
log::error!("Failed to set time property: {e}");
|
|
}
|
|
}
|
|
|
|
TimeoutAction::ToInstant(Instant::now() + Duration::from_secs(1))
|
|
})?;
|
|
|
|
spawn_background_worker(sender.clone());
|
|
spawn_counter_worker(sender);
|
|
|
|
shell.run()?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn spawn_background_worker(sender: Sender<UiMessage>) {
|
|
thread::spawn(move || {
|
|
let tasks = vec![
|
|
("Loading configuration...", 500),
|
|
("Connecting to services...", 800),
|
|
("Fetching data...", 1200),
|
|
("Processing results...", 600),
|
|
];
|
|
|
|
for (status, delay_ms) in tasks {
|
|
if sender
|
|
.send(UiMessage::UpdateStatus(status.to_string()))
|
|
.is_err()
|
|
{
|
|
return;
|
|
}
|
|
thread::sleep(Duration::from_millis(delay_ms));
|
|
}
|
|
|
|
if sender
|
|
.send(UiMessage::BackgroundTaskComplete(
|
|
"All tasks finished".to_string(),
|
|
))
|
|
.is_err()
|
|
{
|
|
return;
|
|
}
|
|
|
|
loop {
|
|
thread::sleep(Duration::from_secs(5));
|
|
if sender
|
|
.send(UiMessage::UpdateStatus(
|
|
"Heartbeat from background".to_string(),
|
|
))
|
|
.is_err()
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
fn spawn_counter_worker(sender: Sender<UiMessage>) {
|
|
thread::spawn(move || {
|
|
loop {
|
|
thread::sleep(Duration::from_millis(50));
|
|
if sender.send(UiMessage::IncrementCounter(1)).is_err() {
|
|
break;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
fn current_time_string() -> String {
|
|
let now = SystemTime::now();
|
|
let duration = now.duration_since(UNIX_EPOCH).unwrap_or_default();
|
|
let secs = duration.as_secs();
|
|
|
|
let hours = (secs / 3600) % 24;
|
|
let minutes = (secs / 60) % 60;
|
|
let seconds = secs % 60;
|
|
|
|
format!("{hours:02}:{minutes:02}:{seconds:02}")
|
|
}
|