Skip to content

Commit

Permalink
ui progress
Browse files Browse the repository at this point in the history
  • Loading branch information
jacob-pro committed Dec 31, 2023
1 parent 51066e9 commit dd7074f
Show file tree
Hide file tree
Showing 5 changed files with 162 additions and 41 deletions.
2 changes: 1 addition & 1 deletion app/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ fn run(args: Args) -> anyhow::Result<()> {
} else {
let (tx, rx) = mpsc::channel();
let config = Arc::new(RwLock::new(config));
let controller = BrightnessController::start(config);
let controller = BrightnessController::start(config, None);
let _event_watcher = EventWatcher::start(&controller, None);
ctrlc::set_handler(move || tx.send(()).unwrap()).expect("Error setting Ctrl-C handler");
rx.recv().expect("Could not receive from channel.");
Expand Down
3 changes: 3 additions & 0 deletions app/src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ pub enum UserEvent {
Exit,
// Hide the window if it is open
CloseWindow,
// Repaint now
RepaintNow,

RequestRepaint {
when: Instant,
/// What the frame number was when the repaint was _requested_.
Expand Down
52 changes: 22 additions & 30 deletions app/src/controller.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ use std::time::{Duration, SystemTime, UNIX_EPOCH};

pub enum Message {
Shutdown,
Enable,
Disable,
Refresh,
}

Expand All @@ -22,12 +20,15 @@ pub struct BrightnessController {
}

impl BrightnessController {
pub fn start(config: Arc<RwLock<SsbConfig>>) -> BrightnessController {
pub fn start<F: Fn() + Send + 'static>(
config: Arc<RwLock<SsbConfig>>,
on_update: Option<F>,
) -> BrightnessController {
let (sender, receiver) = mpsc::channel();
let last_result = Arc::new(RwLock::new(None));
let cloned = last_result.clone();
let join_handle = thread::spawn(move || {
run(config, receiver, cloned);
run(config, receiver, cloned, on_update);
});
BrightnessController {
sender,
Expand All @@ -45,22 +46,25 @@ impl Drop for BrightnessController {
}
}

fn run(
fn run<F: Fn()>(
config: Arc<RwLock<SsbConfig>>,
receiver: mpsc::Receiver<Message>,
last_result: Arc<RwLock<Option<ApplyResults>>>,
on_update: Option<F>,
) {
log::info!("Starting BrightnessController");
let mut enabled = true;

loop {
// Apply brightness using latest config
let config = config.read().unwrap().clone();
let result = apply(config, enabled);
let result = apply(config);
let timeout = calculate_timeout(&result);

// Update last result
*last_result.write().unwrap() = result;
if let Some(on_update) = &on_update {
on_update();
}

// Sleep until receiving message or timeout
let rx_result = match timeout {
Expand All @@ -85,14 +89,6 @@ fn run(
log::info!("Stopping BrightnessController");
break;
}
Ok(Message::Enable) => {
log::info!("Enabling BrightnessController");
enabled = true;
}
Ok(Message::Disable) => {
log::info!("Disabling BrightnessController");
enabled = false;
}
Ok(Message::Refresh) => {
log::info!("Refreshing due to signal");
}
Expand All @@ -119,21 +115,17 @@ fn calculate_timeout(results: &Option<ApplyResults>) -> Option<SystemTime> {
}

// Calculate and apply the brightness
fn apply(config: SsbConfig, enabled: bool) -> Option<ApplyResults> {
if enabled {
if let Some(location) = config.location {
return Some(apply_brightness(
config.brightness_day,
config.brightness_night,
config.transition_mins,
location,
config.overrides,
));
} else {
log::debug!("Skipping apply because no location is configured");
}
fn apply(config: SsbConfig) -> Option<ApplyResults> {
if let Some(location) = config.location {
Some(apply_brightness(
config.brightness_day,
config.brightness_night,
config.transition_mins,
location,
config.overrides,
))
} else {
log::debug!("Skipping apply because controller is disabled");
log::debug!("Skipping apply because no location is configured");
None
}
None
}
132 changes: 123 additions & 9 deletions app/src/gui/app.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
use crate::apply::ApplyResults;
use crate::common::UserEvent;
use crate::config::SsbConfig;
use crate::config::{Location, SsbConfig};
use crate::controller::Message;
use chrono::{Local, TimeZone};
use egui::{Align, Color32, Layout, ScrollArea};
use egui_winit::winit::event_loop::EventLoopProxy;
use enum_iterator::Sequence;
use std::sync::mpsc::Sender;
use std::sync::{Arc, RwLock};
use validator::Validate;

const SPACING: f32 = 10.0;

Expand All @@ -16,18 +17,19 @@ pub struct SsbEguiApp {
selected_page: Page,
overlay: Option<OverlayWindow>,
results: Arc<RwLock<Option<ApplyResults>>>,
brightness_settings_page: BrightnessSettings,
brightness_settings_page: BrightnessSettingsState,
location_settings_page: LocationSettingsState,
config: Arc<RwLock<SsbConfig>>,
controller: Sender<Message>,
}

struct BrightnessSettings {
struct BrightnessSettingsState {
brightness_day: u32,
brightness_night: u32,
transition_mins: u32,
}

impl BrightnessSettings {
impl BrightnessSettingsState {
fn from_config(config: &SsbConfig) -> Self {
Self {
brightness_day: config.brightness_day,
Expand All @@ -40,6 +42,46 @@ impl BrightnessSettings {
config.brightness_night = self.brightness_night;
config.brightness_day = self.brightness_day;
config.transition_mins = self.transition_mins;
assert!(config.validate().is_ok())
}
}

struct LocationSettingsState {
latitude: String,
longitude: String,
}

impl LocationSettingsState {
fn from_config(config: &SsbConfig) -> Self {
Self {
latitude: format!(
"{:.5}",
config.location.as_ref().map(|l| l.latitude).unwrap_or(0.0)
),
longitude: format!(
"{:.5}",
config.location.as_ref().map(|l| l.longitude).unwrap_or(0.0)
),
}
}

fn copy_to_config(&self, config: &mut SsbConfig) {
config.location = Some(Location {
latitude: self.latitude.parse().unwrap(),
longitude: self.longitude.parse().unwrap(),
})
}

fn is_latitude_valid(&self) -> bool {
self.latitude
.parse::<f64>()
.is_ok_and(|l| l >= -90.0 && l <= 90.0)
}

fn is_longitude_valid(&self) -> bool {
self.longitude
.parse::<f64>()
.is_ok_and(|l| l >= -180.0 && l <= 180.0)
}
}

Expand Down Expand Up @@ -80,7 +122,8 @@ impl SsbEguiApp {
selected_page: Page::Status,
overlay: None,
results,
brightness_settings_page: BrightnessSettings::from_config(&config_read),
brightness_settings_page: BrightnessSettingsState::from_config(&config_read),
location_settings_page: LocationSettingsState::from_config(&config_read),
config: config.clone(),
controller,
}
Expand Down Expand Up @@ -145,7 +188,7 @@ impl SsbEguiApp {
match self.selected_page {
Page::Status => self.render_status(ui),
Page::BrightnessSettings => self.render_brightness_settings(ui),
Page::LocationSettings => {}
Page::LocationSettings => self.render_location_settings(ui),
Page::Monitors => {}
}
});
Expand Down Expand Up @@ -213,20 +256,37 @@ impl SsbEguiApp {
}
});

ui.add_space(SPACING);
ui.separator();
ui.add_space(SPACING);

egui::Grid::new("monitors_grid")
.striped(true)
.num_columns(1)
.num_columns(5)
.show(ui, |ui| {
ui.label("Name");
ui.label("Brightness")
ui.label("Monitor");
ui.label("Day")
.on_hover_text("Configured day time brightness");
ui.label("Night")
.on_hover_text("Configured night time brightness");
ui.label("Now")
.on_hover_text("The computed brightness percentage for this monitor");
ui.label("Next update")
.on_hover_text("Time that the brightness will be changed");
ui.end_row();

for monitor in &results.monitors {
ui.label(&monitor.name);
ui.label(format!("{}%", monitor.brightness.brightness_day));
ui.label(format!("{}%", monitor.brightness.brightness_night));
ui.label(format!("{}%", monitor.brightness.brightness));

let changes_at = Local
.timestamp_opt(monitor.brightness.expiry_time, 0)
.unwrap();
ui.label(changes_at.format("%H:%M %P").to_string())
.on_hover_text(changes_at.format("%b %d").to_string());

ui.end_row();
}
});
Expand Down Expand Up @@ -272,4 +332,58 @@ impl SsbEguiApp {
};
});
}

fn render_location_settings(&mut self, ui: &mut egui::Ui) {
let latitude_valid = self.location_settings_page.is_latitude_valid();
let longitude_valid = self.location_settings_page.is_longitude_valid();

egui::Grid::new("location_settings")
.num_columns(2)
.show(ui, |ui| {
ui.label("Latitude")
.on_hover_text("Latitude (N), between -90° to 90°");
ui.vertical(|ui| {
if !latitude_valid {
set_red_widget_border(ui);
}
ui.text_edit_singleline(&mut self.location_settings_page.latitude);
});
ui.end_row();

ui.label("Longitude")
.on_hover_text("Longitude (E), between -180° to 180°");
ui.vertical(|ui| {
if !longitude_valid {
set_red_widget_border(ui);
}
ui.text_edit_singleline(&mut self.location_settings_page.longitude);
});
ui.end_row();
});

ui.add_space(SPACING);

let save_enabled = latitude_valid && longitude_valid;
if ui
.add_enabled(save_enabled, egui::Button::new("Save"))
.clicked()
{
let mut config = self.config.write().unwrap();
self.location_settings_page.copy_to_config(&mut config);
self.controller.send(Message::Refresh).unwrap();
if let Err(e) = config.save() {
self.overlay = Some(OverlayWindow::ErrorMessage(format!(
"Unable to save config: {}",
e
)));
log::error!("Unable to save config: {:#}", e)
}
}
}
}

fn set_red_widget_border(ui: &mut egui::Ui) {
ui.style_mut().visuals.widgets.inactive.bg_stroke.color = Color32::RED;
ui.style_mut().visuals.widgets.inactive.bg_stroke.width = 1.0;
ui.style_mut().visuals.widgets.hovered.bg_stroke.color = Color32::RED;
}
14 changes: 13 additions & 1 deletion app/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,17 @@ fn run() -> anyhow::Result<()> {
SsbConfig::default()
}
}));
let controller = BrightnessController::start(config.clone());

let mut event_loop = EventLoopBuilder::<UserEvent>::with_user_event().build();

let proxy = event_loop.create_proxy();
let controller = BrightnessController::start(
config.clone(),
Some(move || {
proxy.clone().send_event(UserEvent::RepaintNow).unwrap();
}),
);

let _event_watcher = EventWatcher::start(&controller, Some(&event_loop));
let _tray = tray::create(&event_loop)?;

Expand Down Expand Up @@ -85,6 +92,11 @@ fn run() -> anyhow::Result<()> {
Ok(framework.close_window())
}

Event::UserEvent(UserEvent::RepaintNow) => {
log::info!("Received RepaintNow action");
Ok(NextPaint::RepaintNext)
}

Event::UserEvent(UserEvent::OpenWindow) => {
log::info!("Received OpenWindow action");
if let Some(window) = framework.window() {
Expand Down

0 comments on commit dd7074f

Please sign in to comment.