1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
//! Example demonstrating the create_service API for background tasks.
//!
//! This example shows:
//! - Creating a bidirectional service that handles commands
//! - Creating a read-only service for periodic updates
//! - Using `.writer()` to get Send-able signal handles for background threads
//! - Automatic cleanup when components unmount
use std::time::Duration;
use guido::prelude::*;
/// Commands that can be sent to the workspace service
#[derive(Clone)]
enum WorkspaceCmd {
Switch(i32),
}
#[tokio::main]
async fn main() {
App::new().run(|app| {
// Clock signal - updated by a read-only service
let time = create_signal(get_current_time());
let time_w = time.writer(); // WriteSignal is Send — can be captured by service
// Clock service - read-only (ignore the receiver)
create_task(move |ctx| async move {
log::info!("Clock service started");
while ctx.is_running() {
time_w.set(get_current_time());
tokio::time::sleep(Duration::from_secs(1)).await;
}
log::info!("Clock service stopped");
});
// Workspace signals
let active = create_signal(1i32);
let active_w = active.writer(); // WriteSignal is Send
let workspaces: Vec<i32> = vec![1, 2, 3, 4, 5];
// Workspace service - bidirectional
let service = create_service(move |mut rx, ctx| async move {
log::info!("Workspace service started");
while ctx.is_running() {
// Handle commands from UI
while let Ok(cmd) = rx.try_recv() {
match cmd {
WorkspaceCmd::Switch(id) => {
log::info!("Switching to workspace {}", id);
active_w.set(id);
}
}
}
tokio::time::sleep(Duration::from_millis(16)).await;
}
log::info!("Workspace service stopped");
});
app.add_surface(
SurfaceConfig::new()
.height(40)
.anchor(Anchor::TOP | Anchor::LEFT | Anchor::RIGHT)
.background_color(Color::rgb(0.1, 0.1, 0.15)),
move || {
let svc = service;
container()
.layout(
Flex::row()
.spacing(16.0)
.main_alignment(MainAlignment::SpaceBetween),
)
.padding(4.0)
// Workspace buttons
.child(container().layout(Flex::row().spacing(4.0)).children(
workspaces.clone().into_iter().map(move |id| {
container()
.width(32.0)
.height(32.0)
.background(move || {
if active.get() == id {
Color::rgb(0.3, 0.5, 0.8)
} else {
Color::rgb(0.2, 0.2, 0.3)
}
})
.corners(4.0)
.when_hovered(|s| s.lighter(0.1))
.when_pressed(|s| s.ripple())
.on_click(move || svc.send(WorkspaceCmd::Switch(id)))
.child(
container()
.layout(
Flex::row()
.main_alignment(MainAlignment::Center)
.cross_alignment(CrossAlignment::Center),
)
.child(text(format!("{}", id)).color(Color::WHITE)),
)
}),
))
// Clock display
.child(
container()
.padding(8.0)
.background(Color::rgb(0.2, 0.2, 0.3))
.corners(4.0)
.child(text(move || time.get()).color(Color::WHITE)),
)
},
);
});
}
fn get_current_time() -> String {
use std::time::{SystemTime, UNIX_EPOCH};
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs();
// Simple time formatting (HH:MM:SS)
let hours = (now % 86400) / 3600;
let minutes = (now % 3600) / 60;
let seconds = now % 60;
format!("{:02}:{:02}:{:02}", hours, minutes, seconds)
}