Cleanup UI-loading code

- Functions to separate concerns
- Comments
This commit is contained in:
Candifloss 2025-11-26 12:35:16 +05:30
parent db7ca71905
commit 92db45bb28

View File

@ -12,6 +12,7 @@ use i_slint_backend_winit::{
slint::include_modules!(); slint::include_modules!();
/// Derive temperature unit symbol for the configured units
fn unit_symbol(units: &str) -> char { fn unit_symbol(units: &str) -> char {
match units { match units {
"metric" => 'C', "metric" => 'C',
@ -21,58 +22,6 @@ fn unit_symbol(units: &str) -> char {
} }
} }
pub fn show_popup(resp: &WeatherResponse, cfg: &Config) -> Result<(), Box<dyn std::error::Error>> {
// Closure that adjusts winit WindowAttributes before Slint creates the window.
let window_attrs = |attrs: WindowAttributes| {
// Mark the X11 window as a DOCK so the WM treats it as a top bar/panel.
attrs.with_x11_window_type(vec![WindowType::Dock])
};
// Build a Slint backend that applies this attribute hook to all windows.
let backend = Backend::builder()
.with_window_attributes_hook(window_attrs) // Register the hook
.build()?; // Construct backend
// Activate this customized backend for all Slint window creation and events.
slint::platform::set_platform(Box::new(backend))?;
let ui = MainWindow::new()?;
let city = resp.name.clone().unwrap_or_else(|| "Unknown".into());
let country = resp
.sys
.as_ref()
.and_then(|s| s.country.clone())
.unwrap_or_default();
let (weather_main, weather_description, icon_code) = resp.weather.first().map_or_else(
|| ("N/A".into(), "N/A".into(), String::new()),
|w| (w.main.clone(), w.description.clone(), w.icon.clone()),
);
let temp = resp.main.as_ref().and_then(|m| m.temp).unwrap_or(0.0);
let temperature = format!("{temp:.1}");
let unit_symbol = unit_symbol(cfg.query_params.units.as_str());
ui.set_city(SharedString::from(city));
ui.set_country(SharedString::from(country));
ui.set_weather_main(SharedString::from(weather_main));
ui.set_weather_description(SharedString::from(weather_description));
ui.set_weather_icon(SharedString::from(icon_to_nerd_font(&icon_code)));
ui.set_temperature(SharedString::from(temperature));
ui.set_unit(SharedString::from(unit_symbol));
#[allow(clippy::cast_precision_loss)]
ui.window().set_size(LogicalSize::new(300.0, 124.0));
// Position the window (bar) at the top-left.
ui.window().set_position(LogicalPosition::new(0.0, 0.0));
ui.run()?;
Ok(())
}
/// Convert OWM icon codes (e.g. "01d", "09n") to Nerd Font weather glyphs. /// Convert OWM icon codes (e.g. "01d", "09n") to Nerd Font weather glyphs.
fn icon_to_nerd_font(code: &str) -> String { fn icon_to_nerd_font(code: &str) -> String {
match code { match code {
@ -90,3 +39,68 @@ fn icon_to_nerd_font(code: &str) -> String {
} }
.into() .into()
} }
/// Set Slint properties from weather data
fn set_ui_props(ui: &MainWindow, resp: &WeatherResponse, cfg: &Config) {
// Extract data
let city = resp.name.clone().unwrap_or_else(|| "Unknown".into());
let country = resp
.sys
.as_ref()
.and_then(|s| s.country.clone())
.unwrap_or_default();
let (weather_main, weather_description, icon_code) = resp.weather.first().map_or_else(
|| ("N/A".into(), "N/A".into(), String::new()),
|w| (w.main.clone(), w.description.clone(), w.icon.clone()),
);
let temp = resp.main.as_ref().and_then(|m| m.temp).unwrap_or(0.0);
let temperature = format!("{temp:.1}");
let unit = unit_symbol(cfg.query_params.units.as_str());
// Set UI elements
ui.set_city(SharedString::from(city));
ui.set_country(SharedString::from(country));
ui.set_weather_main(SharedString::from(weather_main));
ui.set_weather_description(SharedString::from(weather_description));
ui.set_weather_icon(SharedString::from(icon_to_nerd_font(&icon_code)));
ui.set_temperature(SharedString::from(temperature));
ui.set_unit(SharedString::from(unit));
// Window size (width, height): pixels
#[allow(clippy::cast_precision_loss)]
ui.window().set_size(LogicalSize::new(300.0, 124.0));
// Window position (x,y): pixels
ui.window().set_position(LogicalPosition::new(1610.0, 32.0));
}
/// Create and show the Window UI
pub fn show_popup(resp: &WeatherResponse, cfg: &Config) -> Result<(), Box<dyn std::error::Error>> {
// Closure that adjusts winit WindowAttributes before Slint creates the window.
let window_attrs = |attrs: WindowAttributes| {
// Mark the X11 window as a DOCK so the WM doesn't treat it as a normal window
attrs.with_x11_window_type(vec![WindowType::Dock])
};
// Build a Slint backend that applies this attribute hook to all windows.
let backend = Backend::builder()
.with_window_attributes_hook(window_attrs) // Register the hook
.build()?; // Construct backend
// Activate this customized backend for all Slint window creation and events.
slint::platform::set_platform(Box::new(backend))?;
// Create window
let ui = MainWindow::new()?;
// Send the weather data to the UI as properties
set_ui_props(&ui, resp, cfg);
// Run the UI
ui.run()?;
Ok(())
}