Skip to content

Commit

Permalink
Merge pull request #3 from ahoneybun/add-theme+settings
Browse files Browse the repository at this point in the history
Add theme+settings
  • Loading branch information
ahoneybun authored May 18, 2024
2 parents 61c045a + dbb4408 commit 005fc55
Show file tree
Hide file tree
Showing 6 changed files with 200 additions and 46 deletions.
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ once_cell = "1.19.0"
rust-embed = "8.3.0"
log = "0.4"
open = "5.0.2"
serde = { version = "1.0.202", features = ["serde_derive"] }
paste = "1.0"

[dependencies.libcosmic]
git = "https://github.com/pop-os/libcosmic.git"
Expand Down
12 changes: 12 additions & 0 deletions i18n/en/cosmic_backups.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,19 @@ welcome = Backup and backup often! ✨
# Context Pages

## About
about = About
git-description = Git commit {$hash} on {$date}
## Settings
settings = Settings
### Appearance
appearance = Appearance
theme = Theme
match-desktop = Match desktop
dark = Dark
light = Light
# Menu

## File
Expand All @@ -20,4 +31,5 @@ cut = Cut
## View
view = View
menu-settings = Settings...
menu-about = About COSMIC Backups...
162 changes: 118 additions & 44 deletions src/app.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,25 @@
// SPDX-License-Identifier: GPL-3.0-only

use std::{
collections::{HashMap},
env,
process,
};
use crate::app::config::AppTheme;
use crate::fl;
use cosmic::app::{Command, Core};
use cosmic::{
cosmic_theme, ApplicationExt,
iced::{Alignment, Length},
};
use cosmic::iced::alignment::{Horizontal, Vertical};
use cosmic::iced::window;
use cosmic::iced_core::keyboard::Key;
use cosmic::widget::menu::{
action::{MenuAction},
action::MenuAction,
key_bind::{KeyBind, Modifier},
};
use cosmic::widget::segmented_button::Entity;
use cosmic::{
cosmic_config, cosmic_theme,
iced::{Alignment, Length},
ApplicationExt,
};
use cosmic::{widget, Application, Element};
use std::{collections::HashMap, env, process};

pub mod config;
pub mod menu;

/// This is the struct that represents your application.
Expand All @@ -30,6 +29,9 @@ pub struct App {
/// This is the core of your application, it is used to communicate with the Cosmic runtime.
/// It is used to send messages to your application, and to access the resources of the Cosmic runtime.
core: Core,
config_handler: Option<cosmic_config::Config>,
config: config::CosmicBackupsConfig,
app_themes: Vec<String>,
context_page: ContextPage,
key_binds: HashMap<KeyBind, Action>,
}
Expand All @@ -42,27 +44,38 @@ pub enum Message {
// Cut(Option<Entity>),
ToggleContextPage(ContextPage),
LaunchUrl(String),
AppTheme(usize),
SystemThemeModeChange(cosmic_theme::ThemeMode),
WindowClose,
WindowNew,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ContextPage {
About,
Settings,
}

impl ContextPage {
fn title(&self) -> String {
match self {
Self::About => String::new(),
Self::About => fl!("about"),
Self::Settings => fl!("settings"),
}
}
}

#[derive(Clone, Debug)]
pub struct Flags {
pub config_handler: Option<cosmic_config::Config>,
pub config: config::CosmicBackupsConfig,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Action {
About,
// Cut,
Settings,
WindowClose,
WindowNew,
}
Expand All @@ -73,16 +86,17 @@ impl MenuAction for Action {
match self {
Action::About => Message::ToggleContextPage(ContextPage::About),
// Action::Cut => Message::Cut(entity_opt),
Action::Settings => Message::ToggleContextPage(ContextPage::Settings),
Action::WindowClose => Message::WindowClose,
Action::WindowNew => Message::WindowNew,
}
}
}

impl App {
// fn update_config(&mut self) -> Command<CosmicMessage<Message>> {
// cosmic::app::command::set_theme(self.config.app_theme.theme())
// }
fn update_config(&mut self) -> Command<Message> {
cosmic::app::command::set_theme(self.config.app_theme.theme())
}

fn about(&self) -> Element<Message> {
let cosmic_theme::Spacing { space_xxs, .. } = cosmic::theme::active().cosmic().spacing;
Expand All @@ -91,38 +105,57 @@ impl App {
let short_hash: String = hash.chars().take(7).collect();
let date = env!("VERGEN_GIT_COMMIT_DATE");
widget::column::with_children(vec![
widget::svg(widget::svg::Handle::from_memory(
&include_bytes!(
"../res/icons/hicolor/128x128/apps/com.example.CosmicAppTemplate.svg"
)[..],
))
widget::svg(widget::svg::Handle::from_memory(
&include_bytes!(
"../res/icons/hicolor/128x128/apps/com.example.CosmicAppTemplate.svg"
)[..],
))
.into(),
widget::text::title3(fl!("cosmic-backups")).into(),
widget::button::link(repository)
.on_press(Message::LaunchUrl(repository.to_string()))
.padding(0)
.into(),
widget::text::title3(fl!("cosmic-backups")).into(),
widget::button::link(repository)
.on_press(Message::LaunchUrl(repository.to_string()))
.padding(0)
.into(),
widget::button::link(fl!(
"git-description",
hash = short_hash.as_str(),
date = date
))
.on_press(Message::LaunchUrl(format!("{}/commits/{}", repository, hash)))
.padding(0)
.into(),
])
widget::button::link(fl!(
"git-description",
hash = short_hash.as_str(),
date = date
))
.on_press(Message::LaunchUrl(format!(
"{}/commits/{}",
repository, hash
)))
.padding(0)
.into(),
])
.align_items(Alignment::Center)
.spacing(space_xxs)
.into()
}

}

fn settings(&self) -> Element<Message> {
let app_theme_selected = match self.config.app_theme {
AppTheme::Dark => 1,
AppTheme::Light => 2,
AppTheme::System => 0,
};
widget::settings::view_column(vec![widget::settings::view_section(fl!("appearance"))
.add(
widget::settings::item::builder(fl!("theme")).control(widget::dropdown(
&self.app_themes,
Some(app_theme_selected),
Message::AppTheme,
)),
)
.into()])
.into()
}
}

impl Application for App {
type Executor = cosmic::executor::Default;

type Flags = ();
type Flags = Flags;

type Message = Message;

Expand All @@ -141,10 +174,13 @@ impl Application for App {
vec![menu::menu_bar(&self.key_binds)]
}

fn init(core: Core, _input: Self::Flags) -> (Self, Command<Self::Message>) {
fn init(core: Core, flags: Self::Flags) -> (Self, Command<Self::Message>) {
let app = App {
core,
context_page: ContextPage::About,
context_page: ContextPage::Settings,
config_handler: flags.config_handler,
config: flags.config,
app_themes: vec![fl!("match-desktop"), fl!("dark"), fl!("light")],
key_binds: key_binds(),
};

Expand All @@ -158,6 +194,7 @@ impl Application for App {

Some(match self.context_page {
ContextPage::About => self.about(),
ContextPage::Settings => self.settings(),
})
}

Expand All @@ -169,11 +206,37 @@ impl Application for App {
.align_y(Vertical::Center)
.into()
}

/// Handle application events here.
fn update(&mut self, message: Self::Message) -> Command<Self::Message> {

match message {
// Helper for updating config values efficiently
macro_rules! config_set {
($name: ident, $value: expr) => {
match &self.config_handler {
Some(config_handler) => {
match paste::paste! { self.config.[<set_ $name>](config_handler, $value) } {
Ok(_) => {}
Err(err) => {
log::warn!(
"failed to save config {:?}: {}",
stringify!($name),
err
);
}
}
}
None => {
self.config.$name = $value;
log::warn!(
"failed to save config {:?}: no config handler",
stringify!($name)
);
}
}
};
}

match message {
Message::ToggleContextPage(context_page) => {
//TODO: ensure context menus are closed
if self.context_page == context_page {
Expand Down Expand Up @@ -204,11 +267,22 @@ impl Application for App {
log::warn!("failed to open {:?}: {}", url, err);
}
},
Message::AppTheme(index) => {
let app_theme = match index {
1 => AppTheme::Dark,
2 => AppTheme::Light,
_ => AppTheme::System,
};
config_set!(app_theme, app_theme);
return self.update_config();
}
Message::SystemThemeModeChange(_) => {
return self.update_config();
}
}

Command::none()

}
Command::none()
}
}

pub fn key_binds() -> HashMap<KeyBind, Action> {
Expand Down
52 changes: 52 additions & 0 deletions src/app/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
use crate::app::App;
use cosmic::{
cosmic_config::{self, cosmic_config_derive::CosmicConfigEntry, Config, CosmicConfigEntry},
theme, Application,
};
use serde::{Deserialize, Serialize};

pub const CONFIG_VERSION: u64 = 1;

#[derive(Clone, Default, Debug, Eq, PartialEq, Deserialize, Serialize, CosmicConfigEntry)]
pub struct CosmicBackupsConfig {
pub app_theme: AppTheme,
}

impl CosmicBackupsConfig {
pub fn config_handler() -> Option<Config> {
Config::new(App::APP_ID, CONFIG_VERSION).ok()
}

pub fn config() -> CosmicBackupsConfig {
match Self::config_handler() {
Some(config_handler) => {
let config = CosmicBackupsConfig::get_entry(&config_handler).unwrap_or_else(
|(errs, config)| {
log::info!("errors loading config: {:?}", errs);
config
},
);
config
}
None => CosmicBackupsConfig::default(),
}
}
}

#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
pub enum AppTheme {
Dark,
Light,
#[default]
System,
}

impl AppTheme {
pub fn theme(&self) -> theme::Theme {
match self {
Self::Dark => theme::Theme::dark(),
Self::Light => theme::Theme::light(),
Self::System => theme::system_preference(),
}
}
}
2 changes: 2 additions & 0 deletions src/app/menu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ pub fn menu_bar<'a>(key_binds: &HashMap<KeyBind, Action>) -> Element<'a, Message
items(
key_binds,
vec![
Item::Button(fl!("menu-settings"), Action::Settings),
Item::Divider,
Item::Button(fl!("menu-about"), Action::About),
],
),
Expand Down
Loading

0 comments on commit 005fc55

Please sign in to comment.