Skip to content

Commit

Permalink
Merge pull request #2 from Brady-Simon/theme-animation
Browse files Browse the repository at this point in the history
feat: Theme animation
  • Loading branch information
decipher3114 authored Sep 27, 2024
2 parents b800d45 + 00627fd commit cecfed9
Show file tree
Hide file tree
Showing 8 changed files with 109 additions and 26 deletions.
22 changes: 22 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ arboard = { version = "3.4", features = ["wayland-data-control", "wl-clipboard-r
chrono = "0.4"
display-info = { version = "0.5"}
iced = { version = "0.13", features = ["advanced", "canvas", "multi-window", "image", "tokio", "svg"] }
iced_anim = { version = "0.1.1", features = ["derive", "serde"] }
interprocess = { version = "2.2", features = ["tokio"] }
rdev = { git = "https://github.com/rustdesk-org/rdev", branch = "master"}
rfd = { version = "0.14", features = ["gtk3", "tokio"], default-features = false }
Expand Down
13 changes: 11 additions & 2 deletions src/entities/config.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
use iced_anim::{Spring, SpringEvent};
use serde::{Deserialize, Serialize};

use crate::entities::theme::Theme;

#[derive(Debug, Clone, Serialize, Deserialize)]
#[derive(Debug, Clone)]
pub struct Config {
pub theme: Spring<Theme>,
pub directory: String,
}

/// The configuration that gets serialized to disk.
/// This is distinct to avoid serializing animated values.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StoredConfig {
#[serde(default)]
pub theme: Theme,
#[serde(default = "Config::default_path")]
Expand All @@ -20,6 +29,6 @@ pub struct ConfigureWindow {
pub enum ConfigEvent {
UpdateFolderPath,
OpenFolder,
ToggleTheme,
UpdateTheme(SpringEvent<Theme>),
RequestExit,
}
4 changes: 4 additions & 0 deletions src/entities/theme.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
use iced::Color;
use iced_anim::Animate;
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub enum Theme {
#[default]
Light,
Dark,
#[serde(skip)]
Custom(Palette),
}

#[derive(Debug, Clone, Copy, PartialEq, Animate)]
pub struct Palette {
pub background: Color,
pub surface: Color,
Expand Down
9 changes: 6 additions & 3 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use std::collections::BTreeMap;
use assets::{APPNAME, FONT_BOLD, FONT_MEDIUM, ICON, MEDIUM};
use entities::{
app::{App, AppEvent},
config::{Config, ConfigureWindow},
config::{Config, ConfigEvent, ConfigureWindow},
crop::CropWindow,
theme::Theme,
window::WindowType,
Expand All @@ -28,6 +28,7 @@ use iced::{
},
Size, Subscription, Task,
};
use iced_anim::Animation;
use interprocess::local_socket::{traits::Stream, GenericNamespaced, ToNsName};
use style::Element;
use utils::{
Expand Down Expand Up @@ -189,11 +190,13 @@ impl App {
None => horizontal_space().into(),
};

content
Animation::new(&self.config.theme, content)
.on_update(move |event| AppEvent::Config(id, ConfigEvent::UpdateTheme(event)))
.into()
}

pub fn theme(&self, _id: Id) -> Theme {
self.config.theme.clone()
self.config.theme.value().clone()
}

pub fn style(&self, theme: &Theme) -> Appearance {
Expand Down
26 changes: 26 additions & 0 deletions src/style/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,15 @@ impl Theme {
match self {
Theme::Light => LIGHT,
Theme::Dark => DARK,
Theme::Custom(palette) => *palette,
}
}

/// Toggles the theme between light and dark, defaulting to `Light` if using a custom palette.
pub fn toggle(&self) -> Self {
match self {
Theme::Light => Theme::Dark,
_ => Theme::Light,
}
}
}
Expand All @@ -49,6 +58,7 @@ impl Display for Theme {
match self {
Self::Light => write!(f, "Light"),
Self::Dark => write!(f, "Dark"),
Self::Custom(_) => write!(f, "Custom"),
}
}
}
Expand All @@ -61,3 +71,19 @@ impl DefaultStyle for Theme {
}
}
}

impl iced_anim::Animate for Theme {
fn components() -> usize {
Palette::components()
}

fn distance_to(&self, end: &Self) -> Vec<f32> {
self.palette().distance_to(&end.palette())
}

fn update(&mut self, components: &mut impl Iterator<Item = f32>) {
let mut palette = self.palette();
palette.update(components);
*self = Theme::Custom(palette);
}
}
42 changes: 27 additions & 15 deletions src/utils/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,17 @@ use std::{
process::Command,
};

use iced_anim::Spring;
use rfd::FileDialog;

use crate::entities::{
config::{Config, ConfigureWindow},
theme::Theme,
};
use crate::entities::config::{Config, ConfigureWindow, StoredConfig};

use super::shorten_path;

impl Default for Config {
fn default() -> Self {
Self {
theme: Theme::default(),
theme: Spring::default(),
directory: Config::default_path(),
}
}
Expand All @@ -31,12 +29,12 @@ impl Config {
let mut file_content = String::new();
let _ = file.read_to_string(&mut file_content).unwrap();
let bool = file_content.is_empty();
let config = match toml::from_str::<Config>(&file_content) {
Ok(config) => config,
let config: Config = match toml::from_str::<StoredConfig>(&file_content) {
Ok(config) => config.into(),
Err(_) => {
let config = Self::default();
Self::update_config(&config);
config
config.into()
}
};
(config, bool)
Expand Down Expand Up @@ -76,7 +74,8 @@ impl Config {
match Self::get_config_file() {
Ok(mut file) => {
file.set_len(0).unwrap();
let contents = toml::to_string(self).unwrap();
let config = StoredConfig::from(self);
let contents = toml::to_string(&config).unwrap();
file.write_all(contents.as_bytes()).unwrap();
}
Err(_) => println!("Config can't be updated"),
Expand Down Expand Up @@ -106,19 +105,32 @@ impl Config {
}
}

// From impls to convert betwen different config types
impl From<StoredConfig> for Config {
fn from(config: StoredConfig) -> Self {
Self {
theme: Spring::new(config.theme),
directory: config.directory,
}
}
}

impl From<&Config> for StoredConfig {
fn from(config: &Config) -> Self {
Self {
theme: config.theme.target().clone(),
directory: config.directory.clone(),
}
}
}

impl ConfigureWindow {
pub fn new(config: &Config) -> Self {
Self {
config: config.clone(),
path: shorten_path(config.directory.clone()),
}
}
pub fn toggle_theme(&mut self) {
self.config.theme = match self.config.theme {
Theme::Light => Theme::Dark,
Theme::Dark => Theme::Light,
}
}

pub fn update_directory(&mut self) {
if let Some(path) = FileDialog::new()
Expand Down
18 changes: 12 additions & 6 deletions src/windows/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ impl ConfigureWindow {
self.open_directory();
Task::none()
}
ConfigEvent::ToggleTheme => {
self.toggle_theme();
ConfigEvent::UpdateTheme(event) => {
self.config.theme.update(event);
Task::done(AppEvent::UpdateConfig(id))
}
ConfigEvent::RequestExit => Task::done(AppEvent::ExitApp),
Expand Down Expand Up @@ -83,10 +83,16 @@ impl ConfigureWindow {
row![
text("App Theme").align_x(Left).size(22).font(BOLD),
horizontal_space().width(Fill),
button(text(self.config.theme.to_string()).size(20).center())
.height(40)
.width(160)
.on_press(ConfigEvent::ToggleTheme)
button(
text(self.config.theme.target().to_string())
.size(20)
.center()
)
.height(40)
.width(160)
.on_press(ConfigEvent::UpdateTheme(
self.config.theme.target().toggle().into()
))
]
.align_y(Alignment::Center)
.width(Fill)
Expand Down

0 comments on commit cecfed9

Please sign in to comment.