3 KiB
3 KiB
Slint UI Migration — Phase 1.1
Current state
Desktop client uses egui (immediate-mode GUI). Functional but:
- Grey, utilitarian aesthetic
- Limited design system
- Text-heavy, no modern chat app feel
- Difficult to style consistently
Why Slint
| Criteria | egui | Slint | Iced |
|---|---|---|---|
| UI language | Rust code | Declarative DSL (.slint) |
Elm-style |
| Design quality | Utilitarian | Design-oriented | Good |
| Performance | Fast | Fast | Moderate |
| Chat app fit | ❌ feel | ✅ modern | ✅ modern |
| Learning curve | Low | Medium | Medium |
Recommendation: Slint — declarative DSL makes UI easier to iterate, built-in design system produces professional look out of the box.
Migration strategy
Stage 1 — Side-by-side (week 1)
- Embed Slint canvas alongside existing egui panels
- Rewrite sidebar (server list + channel list) in Slint first
- Keep chat area in egui
- Verify data flow works between both frameworks
Stage 2 — Chat panel (week 2)
- Rewrite channel chat (text messages + input bar) in Slint
- Rewrite voice panel in Slint
- Remove egui chat dependency
Stage 3 — Settings & polish (week 3)
- Rewrite settings window in Slint
- Add dark/light theme toggle
- Add accent color picker
- Apply consistent spacing/typography
Example Slint structure
// client/src/ui/main.slint
export component MainWindow inherits Window {
in-out property <[Channel]> channels;
in-out property <[Message]> messages;
in-out property <string> active-channel;
HorizontalLayout {
ServerSidebar {}
ChatPanel {}
VoicePanel {}
}
}
component ServerSidebar {
VerticalLayout {
Text { text: "VNOX"; }
ListView {
for ch in channels: ChannelRow {
text: ch.name;
icon: ch.kind == "voice" ? "~" : "#";
}
}
UserBar {}
}
}
Data binding
Use Slint's in-out property bindings to sync with Rust state:
// client/src/ui/app.rs
use slint::ComponentHandle;
let ui = MainWindow::new()?;
ui.set_channels(slint::ModelRc::from(models));
ui.on_send_message(|content| {
// forward to net layer
});
ui.run()?;
File structure after migration
client/src/ui/
├── app.rs # entry, wiring
├── main.slint # main layout
├── sidebar.slint # server sidebar + channel list
├── chat.slint # message list + input bar
├── voice.slint # voice panel
├── settings.slint # settings window
├── theme.slint # color/font definitions
└── state/ # UiState (stays in Rust)
Open questions
- Slint's rendering backend (gl/winit/software) — test on all target platforms
- Slint's text input / rich text support for chat messages (emoji, markdown?)
- Whether to remove egui entirely or keep for specific panels (e.g. overlay)
- Licensing: Slint is LGPL (compatible with GPL-3.0 for now, but check for future)