diff --git a/README.md b/README.md index fe5712e..0a392c8 100644 --- a/README.md +++ b/README.md @@ -240,6 +240,33 @@ You can also get the image (if it was provided) by using: @define-color inverseSurface @{inverse_surface.strip}; @define-color inverseOnSurface @{inverse_on_surface}; @define-color inversePrimary @{inverse_primary.strip}; + +@define-color source_color @{source_color}; +@define-color color_accent_primary @{color_accent_primary}; +@define-color color_accent_primary_variant @{color_accent_primary_variant}; +@define-color color_accent_secondary @{color_accent_secondary}; +@define-color color_accent_secondary_variant @{color_accent_secondary_variant}; +@define-color color_accent_tertiary @{color_accent_tertiary}; +@define-color color_accent_tertiary_variant @{color_accent_tertiary_variant}; +@define-color text_color_primary @{text_color_primary}; +@define-color text_color_secondary @{text_color_secondary}; +@define-color text_color_tertiary @{text_color_tertiary}; +@define-color text_color_primary_inverse @{text_color_primary_inverse}; +@define-color text_color_secondary_inverse @{text_color_secondary_inverse}; +@define-color text_color_tertiary_inverse @{text_color_tertiary_inverse}; +@define-color color_background @{color_background}; +@define-color color_background_floating @{color_background_floating}; +@define-color color_surface @{color_surface}; +@define-color color_surface_variant @{color_surface_variant}; +@define-color color_surface_highlight @{color_surface_highlight}; +@define-color surface_header @{surface_header}; +@define-color under_surface @{under_surface}; +@define-color off_state @{off_state}; +@define-color accent_surface @{accent_surface}; +@define-color text_primary_on_accent @{text_primary_on_accent}; +@define-color text_secondary_on_accent @{text_secondary_on_accent}; +@define-color volume_background @{volume_background}; +@define-color scrim_android @{scrim_android}; ``` ## Configuration diff --git a/material-color-utilities-rs/src/scheme.rs b/material-color-utilities-rs/src/scheme.rs deleted file mode 100644 index 29895d9..0000000 --- a/material-color-utilities-rs/src/scheme.rs +++ /dev/null @@ -1,193 +0,0 @@ -use crate::palettes::core::CorePalette; -#[cfg(feature = "serde")] -use crate::util::color::format_argb_as_rgb; -#[cfg(feature = "serde")] -use serde::{ser::SerializeStruct, Serialize}; - -/// Represents a Material color scheme, a mapping of color roles to colors. -#[derive(Debug, Default, PartialEq, Eq, Clone, Copy)] -pub struct Scheme { - pub primary: [u8; 4], - pub on_primary: [u8; 4], - pub primary_container: [u8; 4], - pub on_primary_container: [u8; 4], - pub secondary: [u8; 4], - pub on_secondary: [u8; 4], - pub secondary_container: [u8; 4], - pub on_secondary_container: [u8; 4], - pub tertiary: [u8; 4], - pub on_tertiary: [u8; 4], - pub tertiary_container: [u8; 4], - pub on_tertiary_container: [u8; 4], - pub error: [u8; 4], - pub on_error: [u8; 4], - pub error_container: [u8; 4], - pub on_error_container: [u8; 4], - pub background: [u8; 4], - pub on_background: [u8; 4], - pub surface: [u8; 4], - pub on_surface: [u8; 4], - pub surface_variant: [u8; 4], - pub on_surface_variant: [u8; 4], - pub outline: [u8; 4], - pub outline_variant: [u8; 4], - pub shadow: [u8; 4], - pub scrim: [u8; 4], - pub inverse_surface: [u8; 4], - pub inverse_on_surface: [u8; 4], - pub inverse_primary: [u8; 4], -} - -#[cfg(feature = "serde")] -impl Serialize for Scheme { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let mut state = serializer.serialize_struct("Scheme", 29)?; - - // Macro to serialize an ARGB field to its RGB representation, and reduce - // the risk of a typo between a field name and it's name in the output. - macro_rules! ser { - ($key:ident) => { - state.serialize_field(stringify!($key), &format_argb_as_rgb(self.$key))?; - }; - } - - ser!(primary); - ser!(on_primary); - ser!(primary_container); - ser!(on_primary_container); - ser!(secondary); - ser!(on_secondary); - ser!(secondary_container); - ser!(on_secondary_container); - ser!(tertiary); - ser!(on_tertiary); - ser!(tertiary_container); - ser!(on_tertiary_container); - ser!(error); - ser!(on_error); - ser!(error_container); - ser!(on_error_container); - ser!(background); - ser!(on_background); - ser!(surface); - ser!(on_surface); - ser!(surface_variant); - ser!(on_surface_variant); - ser!(outline); - ser!(outline_variant); - ser!(shadow); - ser!(scrim); - ser!(inverse_surface); - ser!(inverse_on_surface); - ser!(inverse_primary); - - state.end() - } -} - -impl Scheme { - pub fn light_from_core_palette(core: &mut CorePalette) -> Scheme { - Scheme { - primary: core.a1.tone(40), - on_primary: core.a1.tone(100), - primary_container: core.a1.tone(90), - on_primary_container: core.a1.tone(10), - secondary: core.a2.tone(40), - on_secondary: core.a2.tone(100), - secondary_container: core.a2.tone(90), - on_secondary_container: core.a2.tone(10), - tertiary: core.a3.tone(40), - on_tertiary: core.a3.tone(100), - tertiary_container: core.a3.tone(90), - on_tertiary_container: core.a3.tone(10), - error: core.error.tone(40), - on_error: core.error.tone(100), - error_container: core.error.tone(90), - on_error_container: core.error.tone(10), - background: core.n1.tone(99), - on_background: core.n1.tone(10), - surface: core.n1.tone(99), - on_surface: core.n1.tone(10), - surface_variant: core.n2.tone(90), - on_surface_variant: core.n2.tone(30), - outline: core.n2.tone(50), - outline_variant: core.n2.tone(80), - shadow: core.n1.tone(0), - scrim: core.n1.tone(0), - inverse_surface: core.n1.tone(20), - inverse_on_surface: core.n1.tone(95), - inverse_primary: core.a1.tone(80), - } - } - - pub fn dark_from_core_palette(core: &mut CorePalette) -> Scheme { - Scheme { - primary: core.a1.tone(80), - on_primary: core.a1.tone(20), - primary_container: core.a1.tone(30), - on_primary_container: core.a1.tone(90), - secondary: core.a2.tone(80), - on_secondary: core.a2.tone(20), - secondary_container: core.a2.tone(30), - on_secondary_container: core.a2.tone(90), - tertiary: core.a3.tone(80), - on_tertiary: core.a3.tone(20), - tertiary_container: core.a3.tone(30), - on_tertiary_container: core.a3.tone(90), - error: core.error.tone(80), - on_error: core.error.tone(20), - error_container: core.error.tone(30), - on_error_container: core.error.tone(80), - background: core.n1.tone(10), - on_background: core.n1.tone(90), - surface: core.n1.tone(10), - on_surface: core.n1.tone(90), - surface_variant: core.n2.tone(30), - on_surface_variant: core.n2.tone(80), - outline: core.n2.tone(60), - outline_variant: core.n2.tone(30), - shadow: core.n1.tone(0), - scrim: core.n1.tone(0), - inverse_surface: core.n1.tone(90), - inverse_on_surface: core.n1.tone(20), - inverse_primary: core.a1.tone(40), - } - } - - pub fn pure_dark_from_core_palette(core: &mut CorePalette) -> Scheme { - Scheme { - primary: core.a1.tone(80), - on_primary: core.a1.tone(20), - primary_container: core.a1.tone(30), - on_primary_container: core.a1.tone(90), - secondary: core.a2.tone(80), - on_secondary: core.a2.tone(20), - secondary_container: core.a2.tone(30), - on_secondary_container: core.a2.tone(90), - tertiary: core.a3.tone(80), - on_tertiary: core.a3.tone(20), - tertiary_container: core.a3.tone(30), - on_tertiary_container: core.a3.tone(90), - error: core.error.tone(80), - on_error: core.error.tone(20), - error_container: core.error.tone(30), - on_error_container: core.error.tone(80), - background: core.n1.tone(0), - on_background: core.n1.tone(90), - surface: core.n1.tone(0), - on_surface: core.n1.tone(90), - surface_variant: core.n2.tone(5), - on_surface_variant: core.n2.tone(80), - outline: core.n2.tone(60), - outline_variant: core.n2.tone(30), - shadow: core.n1.tone(0), - scrim: core.n1.tone(0), - inverse_surface: core.n1.tone(90), - inverse_on_surface: core.n1.tone(20), - inverse_primary: core.a1.tone(40), - } - } -} diff --git a/src/main.rs b/src/main.rs index 47f60b0..ad0be39 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,7 +16,7 @@ use std::process::Command; use color_eyre::{eyre::Result, eyre::WrapErr, Report}; use material_color_utilities_rs::{ palettes::core::{ColorPalette, CorePalette}, - scheme::Scheme, + scheme::{scheme::Scheme, scheme_android::SchemeAndroid}, }; use clap::{Parser, ValueEnum}; @@ -27,6 +27,9 @@ pub struct Schemes { pub light: Scheme, pub dark: Scheme, pub amoled: Scheme, + pub light_android: SchemeAndroid, + pub dark_android: SchemeAndroid, + pub amoled_android: SchemeAndroid, } #[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)] @@ -36,67 +39,6 @@ pub enum SchemesEnum { Amoled, } -const COLORS: [&str; 30] = [ - "source_color", - "primary", - "on_primary", - "primary_container", - "on_primary_container", - "secondary", - "on_secondary", - "secondary_container", - "on_secondary_container", - "tertiary", - "on_tertiary", - "tertiary_container", - "on_tertiary_container", - "error", - "on_error", - "error_container", - "on_error_container", - "background", - "on_background", - "surface", - "on_surface", - "surface_variant", - "on_surface_variant", - "outline", - "outline_variant", - "shadow", - "scrim", - "inverse_surface", - "inverse_on_surface", - "inverse_primary", -]; - -const COLORS_ANDROID: [&str; 25] = [ - "color_accent_primary", - "color_accent_primary_variant", - "color_accent_secondary", - "color_accent_secondary_variant", - "color_accent_tertiary", - "color_accent_tertiary_variant", - "text_color_primary", - "text_color_secondary", - "text_color_tertiary", - "text_color_primary_inverse", - "text_color_secondary_inverse", - "text_color_tertiary_inverse", - "color_background", - "color_background_floating", - "color_surface", - "color_surface_variant", - "color_surface_highlight", - "surface_header", - "under_surface", - "off_state", - "accent_surface", - "text_primary_on_accent", - "text_secondary_on_accent", - "volume_background", - "scrim", -]; - fn main() -> Result<(), Report> { color_eyre::install()?; let args = Cli::parse(); @@ -115,12 +57,14 @@ fn main() -> Result<(), Report> { light: Scheme::light_from_core_palette(&mut palette), dark: Scheme::dark_from_core_palette(&mut palette), amoled: Scheme::pure_dark_from_core_palette(&mut palette), + light_android: SchemeAndroid::light_from_core_palette(&mut palette), + dark_android: SchemeAndroid::dark_from_core_palette(&mut palette), + amoled_android: SchemeAndroid::pure_dark_from_core_palette(&mut palette), }; if args.dry_run == Some(false) { Template::generate( - &COLORS, &schemes, &config, &args, @@ -140,7 +84,7 @@ fn main() -> Result<(), Report> { } if args.show_colors == Some(true) { - show_color(&schemes, &COLORS, &source_color); + show_color(&schemes, &source_color); } Ok(()) diff --git a/src/util/color.rs b/src/util/color.rs index 1ff361e..5af6823 100644 --- a/src/util/color.rs +++ b/src/util/color.rs @@ -1,4 +1,5 @@ -use material_color_utilities_rs::{scheme::Scheme, util::color::format_argb_as_rgb}; +use material_color_utilities_rs::scheme::scheme_android::SchemeAndroid; +use material_color_utilities_rs::{scheme::scheme::Scheme, util::color::format_argb_as_rgb}; use owo_colors::{OwoColorize, Style}; use prettytable::{format, Cell, Row, Table}; @@ -11,6 +12,67 @@ use colorsys::{ColorAlpha, Hsl, Rgb}; use std::str::FromStr; use color_eyre::{eyre::Result, Report}; +pub const COLORS: [&str; 30] = [ + "source_color", + "primary", + "on_primary", + "primary_container", + "on_primary_container", + "secondary", + "on_secondary", + "secondary_container", + "on_secondary_container", + "tertiary", + "on_tertiary", + "tertiary_container", + "on_tertiary_container", + "error", + "on_error", + "error_container", + "on_error_container", + "background", + "on_background", + "surface", + "on_surface", + "surface_variant", + "on_surface_variant", + "outline", + "outline_variant", + "shadow", + "scrim", + "inverse_surface", + "inverse_on_surface", + "inverse_primary", +]; + +pub const COLORS_ANDROID: [&str; 25] = [ + "color_accent_primary", + "color_accent_primary_variant", + "color_accent_secondary", + "color_accent_secondary_variant", + "color_accent_tertiary", + "color_accent_tertiary_variant", + "text_color_primary", + "text_color_secondary", + "text_color_tertiary", + "text_color_primary_inverse", + "text_color_secondary_inverse", + "text_color_tertiary_inverse", + "color_background", + "color_background_floating", + "color_surface", + "color_surface_variant", + "color_surface_highlight", + "surface_header", + "under_surface", + "off_state", + "accent_surface", + "text_primary_on_accent", + "text_secondary_on_accent", + "volume_background", + "scrim_android", // Should just be `scrim`, renamed so its not the same as `scrim` in `COLORS` +]; + // TODO Fix this monstrosity #[derive(Debug)] @@ -73,9 +135,45 @@ impl SchemeExt for Scheme { } } +pub trait SchemeAndroidExt { + fn get_value<'a>(&'a self, field: &str, source_color: &'a [u8; 4]) -> &[u8; 4]; +} +impl SchemeAndroidExt for SchemeAndroid { + fn get_value<'a>(&'a self, field: &str, source_color: &'a [u8; 4]) -> &[u8; 4] { + match field { + "source_color" => &source_color, + "color_accent_primary" => &self.color_accent_primary, + "color_accent_primary_variant" => &self.color_accent_primary_variant, + "color_accent_secondary" => &self.color_accent_secondary, + "color_accent_secondary_variant" => &self.color_accent_secondary_variant, + "color_accent_tertiary" => &self.color_accent_tertiary, + "color_accent_tertiary_variant" => &self.color_accent_tertiary_variant, + "text_color_primary" => &self.text_color_primary, + "text_color_secondary" => &self.text_color_secondary, + "text_color_tertiary" => &self.text_color_tertiary, + "text_color_primary_inverse" => &self.text_color_primary_inverse, + "text_color_secondary_inverse" => &self.text_color_secondary_inverse, + "text_color_tertiary_inverse" => &self.text_color_tertiary_inverse, + "color_background" => &self.color_background, + "color_background_floating" => &self.color_background_floating, + "color_surface" => &self.color_surface, + "color_surface_variant" => &self.color_surface_variant, + "color_surface_highlight" => &self.color_surface_highlight, + "surface_header" => &self.surface_header, + "under_surface" => &self.under_surface, + "off_state" => &self.off_state, + "accent_surface" => &self.accent_surface, + "text_primary_on_accent" => &self.text_primary_on_accent, + "text_secondary_on_accent" => &self.text_secondary_on_accent, + "volume_background" => &self.volume_background, + "scrim_android" => &self.scrim, + _ => panic!(), + } + } +} + pub fn show_color( schemes: &Schemes, - colors: &[&'static str; 30], source_color: &[u8; 4], ) { let mut table = Table::new(); @@ -107,9 +205,11 @@ pub fn show_color( Cell::new("AMOLED").style_spec("c"), Cell::new("AMOLED").style_spec("c"), ])); + + let mut table_android = table.clone(); // table.set_format(*format::consts::FORMAT_CLEAN); - for field in colors { + for field in COLORS { let formatstr = " "; let color_light: Color = Color::new(*Scheme::get_value(&schemes.light, field, source_color)); @@ -151,7 +251,51 @@ pub fn show_color( Cell::new(format!("{}", formatstr.style(generate_style(&color_amoled))).as_str()).style_spec("c"), ])); } + + for field in COLORS_ANDROID { + let formatstr = " "; + + let color_light: Color = Color::new(*SchemeAndroid::get_value(&schemes.light_android, field, source_color)); + let color_dark: Color = Color::new(*SchemeAndroid::get_value(&schemes.dark_android, field, source_color)); + let color_amoled: Color = Color::new(*SchemeAndroid::get_value(&schemes.amoled_android, field, source_color)); + + table_android.add_row(Row::new(vec![ + // Color names + Cell::new(field).style_spec(""), + // Light scheme + Cell::new( + format!( + "{}", + format_argb_as_rgb([color_light.alpha, color_light.red, color_light.green, color_light.blue]) + ) + .to_uppercase() + .as_str(), + ).style_spec("c"), + Cell::new(format!("{}", formatstr.style(generate_style(&color_light))).as_str()).style_spec("c"), + // Dark scheme + Cell::new( + format!( + "{}", + format_argb_as_rgb([color_dark.alpha, color_dark.red, color_dark.green, color_dark.blue]) + ) + .to_uppercase() + .as_str(), + ).style_spec("c"), + Cell::new(format!("{}", formatstr.style(generate_style(&color_dark))).as_str()).style_spec("c"), + // Amoled theme + Cell::new( + format!( + "{}", + format_argb_as_rgb([color_amoled.alpha, color_amoled.red, color_amoled.green, color_amoled.blue]) + ) + .to_uppercase() + .as_str(), + ).style_spec("c"), + Cell::new(format!("{}", formatstr.style(generate_style(&color_amoled))).as_str()).style_spec("c"), + ])); + } table.printstd(); + table_android.printstd(); } fn generate_style(color: &Color) -> Style { diff --git a/src/util/template.rs b/src/util/template.rs index 2790227..9d349af 100644 --- a/src/util/template.rs +++ b/src/util/template.rs @@ -15,11 +15,16 @@ use crate::util::arguments::Source; use crate::util::color::SchemeExt; use crate::Scheme; +use crate::SchemeAndroid; +use crate::util::color::SchemeAndroidExt; + use super::arguments::Cli; use super::config::ConfigFile; use material_color_utilities_rs::util::color::format_argb_as_rgb; use resolve_path::PathResolveExt; +use super::color::{COLORS, COLORS_ANDROID}; + use crate::{Schemes, SchemesEnum}; #[derive(Serialize, Deserialize, Debug)] @@ -60,7 +65,6 @@ use super::color::Color; impl Template { pub fn generate( - colors: &[&'static str; 30], schemes: &Schemes, config: &ConfigFile, args: &Cli, @@ -81,7 +85,7 @@ impl Template { Source::Color { .. } => None, }; - let regexvec: Patterns = generate_patterns(colors, &schemes, prefix, image, source_color)?; + let regexvec: Patterns = generate_patterns(&schemes, prefix, image, source_color)?; for (name, template) in &config.templates { @@ -196,14 +200,13 @@ fn replace_matches( } fn generate_patterns<'a>( - colors: &[&'static str; 30], schemes: &Schemes, prefix: &'a String, image: Option<&'a String>, source_color: &[u8; 4], ) -> Result, Report> { let mut regexvec: Vec = vec![]; - for field in colors { + for field in COLORS { let color_light: Color = Color::new(*Scheme::get_value(&schemes.light, field, source_color)); let color_dark: Color = Color::new(*Scheme::get_value(&schemes.dark, field, source_color)); @@ -287,6 +290,91 @@ fn generate_patterns<'a>( }, }); } + + for field in COLORS_ANDROID { + let color_light: Color = + Color::new(*SchemeAndroid::get_value(&schemes.light_android, field, source_color)); + let color_dark: Color = Color::new(*SchemeAndroid::get_value(&schemes.dark_android, field, source_color)); + let color_amoled: Color = + Color::new(*SchemeAndroid::get_value(&schemes.amoled_android, field, source_color)); + + regexvec.push(ColorPattern { + pattern: Regex::new( + &format!(r#"\{prefix}\{{{field}(\.hex|\.rgb|\.rgba|\.strip)?}}"#).to_string(), + )?, + replacements: ColorReplacements { + light: ColorReplacement { + hex: format_argb_as_rgb([ + color_light.alpha, + color_light.red, + color_light.green, + color_light.blue, + ]), + hex_stripped: format_argb_as_rgb([ + color_light.alpha, + color_light.red, + color_light.green, + color_light.blue, + ])[1..] + .to_string(), + rgb: format!( + "rgb({:?}, {:?}, {:?})", + color_light.red, color_light.green, color_light.blue + ), + rgba: format!( + "rgba({:?}, {:?}, {:?}, {:?})", + color_light.red, color_light.green, color_light.blue, color_light.alpha + ), + }, + dark: ColorReplacement { + hex: format_argb_as_rgb([ + color_dark.alpha, + color_dark.red, + color_dark.green, + color_dark.blue, + ]), + hex_stripped: format_argb_as_rgb([ + color_dark.alpha, + color_dark.red, + color_dark.green, + color_dark.blue, + ])[1..] + .to_string(), + rgb: format!( + "rgb({:?}, {:?}, {:?})", + color_dark.red, color_dark.green, color_dark.blue + ), + rgba: format!( + "rgba({:?}, {:?}, {:?}, {:?})", + color_dark.red, color_dark.green, color_dark.blue, color_dark.alpha + ), + }, + amoled: ColorReplacement { + hex: format_argb_as_rgb([ + color_amoled.alpha, + color_amoled.red, + color_amoled.green, + color_amoled.blue, + ]), + hex_stripped: format_argb_as_rgb([ + color_amoled.alpha, + color_amoled.red, + color_amoled.green, + color_amoled.blue, + ])[1..] + .to_string(), + rgb: format!( + "rgb({:?}, {:?}, {:?})", + color_amoled.red, color_amoled.green, color_amoled.blue + ), + rgba: format!( + "rgba({:?}, {:?}, {:?}, {:?})", + color_amoled.red, color_amoled.green, color_amoled.blue, color_amoled.alpha + ), + }, + }, + }); + } Ok(Patterns { colors: regexvec, image: ImagePattern {