feat: adjust label of autoswith depending on time of day
This commit is contained in:
parent
bbf9eae401
commit
e29d89b42f
8 changed files with 162 additions and 23 deletions
27
Cargo.lock
generated
27
Cargo.lock
generated
|
|
@ -870,9 +870,9 @@ checksum = "77e53693616d3075149f4ead59bdeecd204ac6b8192d8969757601b74bddf00f"
|
|||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.35"
|
||||
version = "0.4.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8eaf5903dcbc0a39312feb77df2ff4c76387d591b9fc7b04a238dcf8bb62639a"
|
||||
checksum = "8a0d04d43504c61aa6c7531f1871dd0d418d91130162063b789da00fd7057a5e"
|
||||
dependencies = [
|
||||
"android-tzdata",
|
||||
"iana-time-zone",
|
||||
|
|
@ -1293,6 +1293,7 @@ dependencies = [
|
|||
"anyhow",
|
||||
"ashpd 0.7.0",
|
||||
"async-channel",
|
||||
"chrono",
|
||||
"clap",
|
||||
"color-eyre",
|
||||
"cosmic-bg-config",
|
||||
|
|
@ -1324,6 +1325,7 @@ dependencies = [
|
|||
"serde",
|
||||
"slotmap",
|
||||
"static_init",
|
||||
"sunrise",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
|
|
@ -5234,6 +5236,15 @@ version = "0.11.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01"
|
||||
|
||||
[[package]]
|
||||
name = "sunrise"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3217c5830416956b1f2dc731f526150a82c144ebe83d2f0e78853c8356a22ada"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "svg_fmt"
|
||||
version = "0.4.2"
|
||||
|
|
@ -5529,10 +5540,22 @@ dependencies = [
|
|||
"pin-project-lite",
|
||||
"signal-hook-registry",
|
||||
"socket2 0.5.6",
|
||||
"tokio-macros",
|
||||
"tracing",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-macros"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.55",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.5.11"
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ members = ["cosmic-settings", "page", "pages/*"]
|
|||
default-members = ["cosmic-settings"]
|
||||
resolver = "2"
|
||||
rust-version = "1.71.0"
|
||||
sunrise_sunset = "1.0.1"
|
||||
|
||||
|
||||
[workspace.dependencies.libcosmic]
|
||||
git = "https://github.com/pop-os/libcosmic"
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ license = "GPL-3.0"
|
|||
rust-version = "1.65.0"
|
||||
|
||||
[dependencies]
|
||||
tokio = { version = "1.35.1", features = ["macros"] }
|
||||
async-channel = "2.1.1"
|
||||
color-eyre = "0.6.2"
|
||||
cosmic-bg-config = { workspace = true }
|
||||
|
|
@ -20,16 +21,17 @@ dirs = "5.0.1"
|
|||
generator = "=0.7.5"
|
||||
i18n-embed-fl = "0.7.0"
|
||||
itertools = "0.12.0"
|
||||
libcosmic = {workspace = true}
|
||||
libcosmic = { workspace = true }
|
||||
once_cell = "1.19.0"
|
||||
regex = "1.10.3"
|
||||
rust-embed = "8.2.0"
|
||||
slotmap = "1.0.7"
|
||||
tokio = "1.35.1"
|
||||
downcast-rs = "1.2.0"
|
||||
cosmic-comp-config = { workspace = true }
|
||||
# TODO: migrate this dependency to the pages/desktop crate.
|
||||
cosmic-panel-config = { workspace = true }
|
||||
chrono = "0.4.37"
|
||||
sunrise = "1.0.1"
|
||||
tracing = "0.1.40"
|
||||
tracing-subscriber = "0.3.18"
|
||||
url = "2.5.0"
|
||||
|
|
@ -41,7 +43,7 @@ serde = { version = "1.0.196", features = ["derive"] }
|
|||
ashpd = { version = "0.7", default-features = false }
|
||||
ron = "0.8"
|
||||
static_init = "1.0.3"
|
||||
clap = {version = "4.4.18", features = ["derive"] }
|
||||
clap = { version = "4.4.18", features = ["derive"] }
|
||||
itoa = "1.0.10"
|
||||
futures = { package = "futures-lite", version = "2.2.0" }
|
||||
|
||||
|
|
|
|||
|
|
@ -225,6 +225,11 @@ impl cosmic::Application for SettingsApp {
|
|||
});
|
||||
|
||||
Subscription::batch(vec![
|
||||
crate::subscription::daytime().map(|daytime| {
|
||||
Message::PageMessage(pages::Message::Appearance(appearance::Message::Daytime(
|
||||
daytime,
|
||||
)))
|
||||
}),
|
||||
wayland_events,
|
||||
// Watch for changes to installed desktop entries
|
||||
desktop_files(0).map(|_| Message::DesktopInfo),
|
||||
|
|
|
|||
|
|
@ -76,8 +76,12 @@ pub struct Page {
|
|||
theme_builder_needs_update: bool,
|
||||
theme_builder_config: Option<Config>,
|
||||
|
||||
auto_switch_descs: [Cow<'static, str>; 4],
|
||||
|
||||
tk: CosmicTk,
|
||||
tk_config: Option<Config>,
|
||||
|
||||
day_time: bool,
|
||||
}
|
||||
|
||||
impl Default for Page {
|
||||
|
|
@ -192,6 +196,13 @@ impl
|
|||
theme_builder,
|
||||
tk_config,
|
||||
tk,
|
||||
day_time: true,
|
||||
auto_switch_descs: [
|
||||
fl!("auto-switch", "sunrise").into(),
|
||||
fl!("auto-switch", "sunset").into(),
|
||||
fl!("auto-switch", "next-sunrise").into(),
|
||||
fl!("auto-switch", "next-sunset").into(),
|
||||
],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -275,6 +286,7 @@ pub enum Message {
|
|||
StartImport,
|
||||
UseDefaultWindowHint(bool),
|
||||
WindowHintSize(spin_button::Message),
|
||||
Daytime(bool),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
|
|
@ -434,10 +446,6 @@ impl Page {
|
|||
let ret = match message {
|
||||
Message::DarkMode(enabled) => {
|
||||
if let Some(config) = self.theme_mode_config.as_ref() {
|
||||
// must disable auto switch if the user manually switches the theme
|
||||
if let Err(err) = self.theme_mode.set_auto_switch(config, false) {
|
||||
tracing::error!(?err, "Error setting auto switch");
|
||||
}
|
||||
if let Err(err) = self.theme_mode.set_is_dark(config, enabled) {
|
||||
tracing::error!(?err, "Error setting dark mode");
|
||||
}
|
||||
|
|
@ -821,6 +829,10 @@ impl Page {
|
|||
}
|
||||
Command::none()
|
||||
}
|
||||
Message::Daytime(day_time) => {
|
||||
self.day_time = day_time;
|
||||
Command::none()
|
||||
}
|
||||
};
|
||||
|
||||
if self.theme_builder_needs_update {
|
||||
|
|
@ -879,9 +891,9 @@ impl Page {
|
|||
fn reload_theme_mode(&mut self) {
|
||||
let icon_themes = std::mem::take(&mut self.icon_themes);
|
||||
let icon_theme_active = self.icon_theme_active.take();
|
||||
|
||||
let day_time = self.day_time;
|
||||
*self = Self::from((self.theme_mode_config.clone(), self.theme_mode));
|
||||
|
||||
self.day_time = day_time;
|
||||
self.icon_themes = icon_themes;
|
||||
self.icon_theme_active = icon_theme_active;
|
||||
}
|
||||
|
|
@ -1023,26 +1035,25 @@ pub fn mode_and_colors() -> Section<crate::pages::Message> {
|
|||
.descriptions(vec![
|
||||
// 0
|
||||
fl!("auto-switch").into(),
|
||||
fl!("auto-switch", "desc").into(),
|
||||
//2
|
||||
//1
|
||||
fl!("accent-color").into(),
|
||||
//3
|
||||
//2
|
||||
fl!("app-background").into(),
|
||||
//4
|
||||
//3
|
||||
fl!("container-background").into(),
|
||||
fl!("container-background", "desc").into(),
|
||||
fl!("container-background", "desc-detail").into(),
|
||||
fl!("container-background", "reset").into(),
|
||||
// 8
|
||||
// 7
|
||||
fl!("text-tint").into(),
|
||||
fl!("text-tint", "desc").into(),
|
||||
// 10
|
||||
// 9
|
||||
fl!("control-tint").into(),
|
||||
fl!("control-tint", "desc").into(),
|
||||
// 12
|
||||
// 11
|
||||
fl!("window-hint-accent-toggle").into(),
|
||||
fl!("window-hint-accent").into(),
|
||||
// 14
|
||||
// 13
|
||||
fl!("dark").into(),
|
||||
fl!("light").into(),
|
||||
])
|
||||
|
|
@ -1067,7 +1078,7 @@ pub fn mode_and_colors() -> Section<crate::pages::Message> {
|
|||
.padding([8, 0])
|
||||
.selected(page.theme_mode.is_dark)
|
||||
.on_press(Message::DarkMode(true)),
|
||||
text(&*descriptions[14])
|
||||
text(&*descriptions[13])
|
||||
]
|
||||
.spacing(8)
|
||||
.width(Length::FillPortion(1))
|
||||
|
|
@ -1082,7 +1093,7 @@ pub fn mode_and_colors() -> Section<crate::pages::Message> {
|
|||
.selected(!page.theme_mode.is_dark)
|
||||
.padding([8, 0])
|
||||
.on_press(Message::DarkMode(false)),
|
||||
text(&*descriptions[15])
|
||||
text(&*descriptions[14])
|
||||
]
|
||||
.spacing(8)
|
||||
.width(Length::FillPortion(1))
|
||||
|
|
@ -1097,7 +1108,18 @@ pub fn mode_and_colors() -> Section<crate::pages::Message> {
|
|||
)
|
||||
.add(
|
||||
settings::item::builder(&*descriptions[0])
|
||||
.description(&*descriptions[1])
|
||||
.description(
|
||||
if page.day_time && !page.theme_mode.is_dark {
|
||||
&page.auto_switch_descs[0]
|
||||
} else if !page.day_time && page.theme_mode.is_dark {
|
||||
&page.auto_switch_descs[1]
|
||||
} else if page.day_time && page.theme_mode.is_dark {
|
||||
&page.auto_switch_descs[2]
|
||||
} else {
|
||||
&page.auto_switch_descs[3]
|
||||
}
|
||||
.clone(),
|
||||
)
|
||||
.toggler(page.theme_mode.auto_switch, Message::Autoswitch),
|
||||
)
|
||||
.add(
|
||||
|
|
|
|||
80
cosmic-settings/src/subscription/daytime.rs
Normal file
80
cosmic-settings/src/subscription/daytime.rs
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
use std::any::TypeId;
|
||||
|
||||
use ashpd::desktop::location::{Location, LocationProxy};
|
||||
use chrono::Datelike;
|
||||
use cosmic::iced::{
|
||||
self,
|
||||
futures::{channel::mpsc::Sender, future, SinkExt, StreamExt},
|
||||
};
|
||||
use sunrise::sunrise_sunset;
|
||||
use tokio::select;
|
||||
|
||||
pub fn daytime() -> cosmic::iced::Subscription<bool> {
|
||||
struct Sunset;
|
||||
iced::subscription::channel(TypeId::of::<Sunset>(), 2, |tx| async {
|
||||
if let Err(err) = inner(tx).await {
|
||||
tracing::error!("Sunset subscription error: {:?}", err);
|
||||
}
|
||||
future::pending().await
|
||||
})
|
||||
}
|
||||
|
||||
enum Event {
|
||||
Daytime,
|
||||
LocationUpdated(Location),
|
||||
}
|
||||
|
||||
async fn inner(mut tx: Sender<bool>) -> anyhow::Result<()> {
|
||||
let location_proxy = LocationProxy::new().await?;
|
||||
let mut updates = location_proxy.receive_location_updated().await?;
|
||||
|
||||
let mut next = updates.next().await.map(Event::LocationUpdated);
|
||||
let mut loc = None;
|
||||
|
||||
while let Some(e) = next {
|
||||
match e {
|
||||
Event::LocationUpdated(l) => {
|
||||
loc = Some(l);
|
||||
}
|
||||
Event::Daytime => {}
|
||||
};
|
||||
let Some(loc) = loc.as_ref() else {
|
||||
break;
|
||||
};
|
||||
let (lat, long) = (loc.latitude(), loc.longitude());
|
||||
let now = chrono::Local::now();
|
||||
let date = now.date_naive();
|
||||
let (sunrise, sunset) = sunrise_sunset(lat, long, date.year(), date.month0(), date.day0());
|
||||
let now_in_seconds = now.timestamp();
|
||||
let daytime = now_in_seconds >= sunrise && now_in_seconds <= sunset;
|
||||
tx.send(daytime).await?;
|
||||
|
||||
let sleep = if daytime {
|
||||
sunset - now_in_seconds
|
||||
} else if now_in_seconds < sunset {
|
||||
sunrise - now_in_seconds
|
||||
} else {
|
||||
let tmrw = now + chrono::Duration::days(1);
|
||||
let tmrw_date = tmrw.date_naive();
|
||||
let (tmrw_sunrise, _) = sunrise_sunset(
|
||||
lat,
|
||||
long,
|
||||
tmrw_date.year(),
|
||||
tmrw_date.month0(),
|
||||
tmrw_date.day0(),
|
||||
);
|
||||
tmrw_sunrise - now_in_seconds
|
||||
};
|
||||
next = select! {
|
||||
() = tokio::time::sleep(tokio::time::Duration::from_secs(sleep as u64)) => {
|
||||
Some(Event::Daytime)
|
||||
},
|
||||
l = updates.next() => if let Some(l) = l {
|
||||
Some(Event::LocationUpdated(l))
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
Err(anyhow::anyhow!("Location updates ended unexpectedly."))
|
||||
}
|
||||
|
|
@ -1,2 +1,4 @@
|
|||
mod desktop_files;
|
||||
pub use desktop_files::*;
|
||||
mod daytime;
|
||||
pub use daytime::*;
|
||||
|
|
|
|||
|
|
@ -33,7 +33,10 @@ window-hint-accent = Active window hint color
|
|||
window-hint-accent-toggle = Use theme accent color as active window hint
|
||||
|
||||
auto-switch = Automatically switch from Light to Dark mode
|
||||
.desc = Switches to Light mode at sunrise
|
||||
.sunrise = Switches to Light mode at sunrise
|
||||
.sunset = Switches to Light mode at sunset
|
||||
.next-sunrise = Switches to Light mode at next sunrise
|
||||
.next-sunset = Switches to Light mode at next sunset
|
||||
|
||||
container-background = Container background
|
||||
.desc-detail = Container background color is used for navigation sidebar, side drawer, dialogs and similar widgets. By default, it is automatically derived from the Application or window background.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue