diff --git a/dashboard/src/main.rs b/dashboard/src/main.rs index 88fc830..4207ecf 100644 --- a/dashboard/src/main.rs +++ b/dashboard/src/main.rs @@ -5,11 +5,19 @@ extern crate serde_derive; extern crate lazy_static; */ -use chrono::{Datelike, Duration, NaiveTime}; -use glib::Object; +use chrono::{Datelike, Duration, Local, NaiveTime}; +use geo_types::{Latitude, Longitude}; +use glib::{Object, Sender}; use gtk::{prelude::*, subclass::prelude::*, Orientation}; use ifc::IFC; -use std::{cell::RefCell, env, f64::consts::PI, ops::Deref, rc::Rc}; +use std::{ + cell::RefCell, + env, + f64::consts::PI, + ops::Deref, + rc::Rc, + sync::{Arc, RwLock}, +}; mod drawing; use drawing::{Color, PieChart, Wedge}; @@ -19,7 +27,7 @@ use geo_types::{Latitude, Longitude}; */ mod soluna_client; -use soluna_client::{LunarPhase, SunMoon}; +use soluna_client::{SolunaClient, SunMoon}; /* mod solstices; @@ -169,8 +177,37 @@ async fn page( } */ -#[derive(Default)] -pub struct DatePrivate {} +#[derive(Clone, Debug)] +pub enum Message { + Refresh(State), +} + +#[derive(Clone, Debug)] +pub struct State { + date: IFC, + transit: Option, +} + +#[derive(Clone)] +pub struct Core { + tx: Arc>>>, +} + +pub struct DatePrivate { + date: Rc>, + label: Rc>, +} + +impl Default for DatePrivate { + fn default() -> Self { + Self { + date: Rc::new(RefCell::new(IFC::from( + chrono::Local::now().date_naive().with_year(12023).unwrap(), + ))), + label: Rc::new(RefCell::new(gtk::Label::new(None))), + } + } +} #[glib::object_subclass] impl ObjectSubclass for DatePrivate { @@ -197,19 +234,27 @@ impl Date { s.set_margin_start(8); s.set_margin_end(8); - let dt = IFC::from(chrono::Local::now().date_naive().with_year(12023).unwrap()); - s.append(>k::Label::new(Some( - format!( - "{:?}, {:?} {}, {}", - dt.weekday(), - dt.month(), - dt.day(), - dt.year() - ) - .as_ref(), - ))); + s.append(&*s.imp().label.borrow()); + + s.redraw(); s } + + fn update_date(&self, date: IFC) { + *self.imp().date.borrow_mut() = date; + self.redraw(); + } + + fn redraw(&self) { + let date = self.imp().date.borrow().clone(); + self.imp().label.borrow_mut().set_text(&format!( + "{:?}, {:?} {}, {}", + date.weekday(), + date.month(), + date.day(), + date.year() + )); + } } pub struct TransitClockPrivate { @@ -240,13 +285,11 @@ glib::wrapper! { } impl TransitClock { - pub fn new(sun_moon_info: SunMoon) -> Self { + pub fn new() -> Self { let s: Self = Object::builder().build(); s.set_width_request(500); s.set_height_request(500); - *s.imp().info.borrow_mut() = Some(sun_moon_info); - s.set_draw_func({ let s = s.clone(); move |_, context, width, height| { @@ -291,6 +334,11 @@ impl TransitClock { s } + + pub fn update_transit(&self, transit_info: SunMoon) { + *self.imp().info.borrow_mut() = Some(transit_info); + self.queue_draw(); + } } pub fn main() { @@ -299,45 +347,83 @@ pub fn main() { .resource_base_path("/com/luminescent-dreams/dashboard") .build(); - app.connect_activate( - // let runtime = runtime.clone(); - |app| { - let window = gtk::ApplicationWindow::new(app); - window.present(); + let latitude = Latitude::from(41.78); + let longitude = Longitude::from(-71.41); - let layout = gtk::Box::builder() - .orientation(Orientation::Vertical) - .hexpand(true) - .vexpand(true) - .build(); - let date = Date::new(); - layout.append(&date); - - let button = gtk::Button::builder() - .label("Text") - .margin_bottom(8) - .margin_top(8) - .margin_start(8) - .margin_end(8) - .build(); - layout.append(&button); - - let day = TransitClock::new(SunMoon { - sunrise: NaiveTime::from_hms_opt(7, 0, 0).unwrap(), - sunset: NaiveTime::from_hms_opt(22, 0, 0).unwrap(), - moonrise: NaiveTime::from_hms_opt(15, 0, 0), - moonset: NaiveTime::from_hms_opt(5, 0, 0), - moon_phase: LunarPhase::WaningCrescent, - }); - layout.append(&day); - - window.set_child(Some(&layout)); - }, + let runtime = Arc::new( + tokio::runtime::Builder::new_multi_thread() + .enable_all() + .build() + .unwrap(), ); + let core = Core { + tx: Arc::new(RwLock::new(None)), + }; + + let app_handle = runtime.spawn({ + let core = core.clone(); + async move { + let soluna_client = SolunaClient::new(); + + let transit = soluna_client + .request(latitude, longitude, Local::now()) + .await; + + let state = State { + date: IFC::from(Local::now().date_naive().with_year(12023).unwrap()), + transit: Some(transit), + }; + loop { + if let Some(ref gtk_tx) = *core.tx.read().unwrap() { + let _ = gtk_tx.send(Message::Refresh(state.clone())); + } + std::thread::sleep(std::time::Duration::from_secs(300)); + } + } + }); + + app.connect_activate(move |app| { + let (gtk_tx, gtk_rx) = + gtk::glib::MainContext::channel::(gtk::glib::PRIORITY_DEFAULT); + + *core.tx.write().unwrap() = Some(gtk_tx); + + let window = gtk::ApplicationWindow::new(app); + window.present(); + + let layout = gtk::Box::builder() + .orientation(Orientation::Vertical) + .hexpand(true) + .vexpand(true) + .build(); + let date_label = Date::new(); + layout.append(&date_label); + + let transit_clock = TransitClock::new(); + layout.append(&transit_clock); + + window.set_child(Some(&layout)); + + gtk_rx.attach(None, move |msg| { + let Message::Refresh(state) = msg; + println!("new state: {:?}", state); + date_label.update_date(state.date); + if let Some(transit) = state.transit { + transit_clock.update_transit(transit); + } + + Continue(true) + }); + + std::thread::spawn(move || {}); + }); + let args: Vec = env::args().collect(); ApplicationExtManual::run_with_args(&app, &args); + let _ = runtime.block_on(async { app_handle.await }); + /* let now = Local::now(); let ifc = ifc::IFC::from(now.date_naive().with_year(12023).unwrap());