Skip to content

Commit cea6708

Browse files
authored
Theme switcher (#45)
1 parent 26e79f3 commit cea6708

10 files changed

Lines changed: 94 additions & 38 deletions

File tree

sed_manager_config/src/main.rs

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ mod utility;
2020
use backend::Backend;
2121
use core::error::Error;
2222
use frontend::Frontend;
23-
use license::{get_license_fingerprint, get_plain_license};
2423
use slint::ComponentHandle;
2524
use std::rc::Rc;
2625
use utility::PeekCell;
@@ -35,7 +34,7 @@ fn main() -> Result<(), Box<dyn Error>> {
3534
let backend = Rc::new(PeekCell::new(Backend::new()));
3635

3736
// Load settings.
38-
let settings = Rc::new(PeekCell::new(settings::load().unwrap_or(settings::Settings::default())));
37+
let settings = settings::load().unwrap_or(settings::Settings::default());
3938

4039
// Configure callbacks.
4140
let _ = slint::BackendSelector::new().backend_name("winit".into()).renderer_name("skia".into()).select();
@@ -46,31 +45,24 @@ fn main() -> Result<(), Box<dyn Error>> {
4645
configuration::set_callbacks(backend.clone(), frontend.clone());
4746
troubleshooting::set_callbacks(backend.clone(), frontend.clone());
4847
device_list::set_callbacks(backend.clone(), frontend.clone());
49-
settings::set_callbacks(settings.clone(), frontend.clone());
5048
app_window.on_quit(|| {
5149
let _ = slint::quit_event_loop();
5250
});
5351

5452
// Set parameters for the about page and the license.
5553
let ui_settings = app_window.global::<ui::SettingsState>();
56-
ui_settings.set_license_text(get_plain_license().into());
57-
ui_settings.set_license_changed(settings.peek(|settings| settings.accepted_license_fingerprint.is_some()));
54+
settings::set_ui(settings, &ui_settings);
5855

5956
// Refresh device list right after starting.
6057
let _ = app_window.show();
6158
app_window.global::<ui::DeviceListState>().invoke_list();
6259

63-
// Show license agreement if not already accepted.
64-
let accepted_license_fingerprint = settings.peek(|settings| settings.accepted_license_fingerprint.clone());
65-
if accepted_license_fingerprint != Some(get_license_fingerprint()) {
66-
app_window.invoke_show_license();
67-
}
68-
6960
// Display GUI.
7061
app_window.run()?;
7162

7263
// Save settings if changed.
73-
if let Err(error) = settings::save(&settings.peek(|settings| settings.clone())) {
64+
let settings = settings::get_ui(&ui_settings);
65+
if let Err(error) = settings::save(&settings) {
7466
eprint!("Cannot save settings: {error}");
7567
}
7668

sed_manager_config/src/settings.rs

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,31 +3,35 @@
33
//L Please refer to the full license distributed with this software.
44
//L-----------------------------------------------------------------------------
55

6-
use slint::ComponentHandle as _;
76
use std::fs;
87
use std::io::{Read, Write};
9-
use std::rc::Rc;
108

11-
use crate::frontend::Frontend;
12-
use crate::license::get_license_fingerprint;
9+
use crate::license::{get_license_fingerprint, get_plain_license};
1310
use crate::ui;
14-
use crate::utility::PeekCell;
1511

1612
#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
1713
pub struct Settings {
1814
#[serde(default = "make_none")]
1915
pub accepted_license_fingerprint: Option<String>,
16+
#[serde(default = "default_theme")]
17+
pub theme: ui::Theme,
2018
}
2119

22-
pub fn set_callbacks(settings: Rc<PeekCell<Settings>>, frontend: Frontend) {
23-
frontend.with(move |window| {
24-
let settings_state = window.global::<ui::SettingsState>();
25-
settings_state.on_accept_license(move || {
26-
settings.peek_mut(|settings| {
27-
settings.accepted_license_fingerprint = Some(get_license_fingerprint());
28-
});
29-
});
30-
});
20+
pub fn set_ui(settings: Settings, ui: &ui::SettingsState) {
21+
ui.set_license_text(get_plain_license().into());
22+
ui.set_accepted_license_fingerprint(settings.accepted_license_fingerprint.unwrap_or("".into()).into());
23+
ui.set_license_fingerprint(get_license_fingerprint().into());
24+
ui.set_theme(settings.theme);
25+
}
26+
27+
pub fn get_ui(ui: &ui::SettingsState) -> Settings {
28+
let accepted_license_fingerprint: String = ui.get_accepted_license_fingerprint().into();
29+
let theme = ui.get_theme();
30+
Settings {
31+
accepted_license_fingerprint: (!accepted_license_fingerprint.is_empty())
32+
.then_some(accepted_license_fingerprint),
33+
theme,
34+
}
3135
}
3236

3337
pub fn save(settings: &Settings) -> Result<(), std::io::Error> {
@@ -59,3 +63,7 @@ pub fn load() -> Result<Settings, std::io::Error> {
5963
fn make_none<T>() -> Option<T> {
6064
None
6165
}
66+
67+
fn default_theme() -> ui::Theme {
68+
ui::Theme::System
69+
}

sed_manager_config_ui/Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,7 @@ default-features = false
1515
features = ["std", "compat-1-2"]
1616

1717
[build-dependencies]
18-
slint-build = "1.12.0"
18+
slint-build = "1.12.0"
19+
20+
[dependencies.serde]
21+
version = "1.0.219"
Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 1 addition & 0 deletions
Loading

sed_manager_config_ui/ui/app_window.slint

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,10 @@ import {
1111
DeviceListState, TroubleshootingState, UserEditorState, RangeEditorState, SingleStepState,
1212
PermissionEditorState, MBREditorState, SettingsState, ChangePasswordState
1313
} from "state.slint";
14-
import { Button, Spinner, Palette } from "std-widgets.slint";
14+
import { Button, Palette } from "std-widgets.slint";
1515
import { DevicePage } from "pages/device_page.slint";
1616
import { UnavailableDevicesPage } from "pages/unavailable_devices_page.slint";
17+
import { Theme } from "data/theme.slint";
1718
import { Status } from "data/status.slint";
1819
import { StatusIndicator } from "widgets/progress.slint";
1920
import { PaletteExtra, Island } from "widgets/visual.slint";
@@ -60,6 +61,33 @@ component DriveTabView {
6061
}
6162
}
6263
}
64+
65+
Island {
66+
width: 42px;
67+
height: 32px;
68+
IconButton {
69+
width: 100%;
70+
height: 100%;
71+
icon: {
72+
if SettingsState.theme == Theme.dark {
73+
Icons.dark-mode
74+
} else if SettingsState.theme == Theme.light {
75+
Icons.light-mode
76+
} else {
77+
Icons.contrast
78+
}
79+
};
80+
clicked => {
81+
if SettingsState.theme == Theme.dark {
82+
SettingsState.theme = Theme.light
83+
} else if SettingsState.theme == Theme.light {
84+
SettingsState.theme = Theme.system
85+
} else {
86+
SettingsState.theme = Theme.dark
87+
}
88+
}
89+
}
90+
}
6391
}
6492

6593
AlternativeLayout {
@@ -139,14 +167,11 @@ component LoadingView {
139167
}
140168

141169
export component AppWindow inherits Window {
142-
title: "SED Manager";
170+
title: "SEDManager";
143171
icon: Icons.sed-manager;
144172
preferred-width: 960px;
145173
preferred-height: 600px;
146174
private property <bool> loaded: DeviceListState.extended-status.status == Status.success && DeviceListState.tab-names.length != 0;
147-
public function show-license() {
148-
license-popup.visible = true;
149-
}
150175
callback quit();
151176
VerticalLayout {
152177
if loaded: DriveTabView { }
@@ -157,11 +182,10 @@ export component AppWindow inherits Window {
157182
preferred-width: 100%;
158183
preferred-height: 100%;
159184
license-text: SettingsState.license-text;
160-
license-changed: SettingsState.license-changed;
161-
visible: false;
185+
license-changed: !SettingsState.accepted-license-fingerprint.is-empty;
186+
visible: SettingsState.accepted-license-fingerprint != SettingsState.license-fingerprint;
162187
accept => {
163-
self.visible = false;
164-
SettingsState.accept-license();
188+
SettingsState.accepted-license-fingerprint = SettingsState.license-fingerprint;
165189
}
166190
decline => {
167191
quit();
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//L-----------------------------------------------------------------------------
2+
//L Copyright (C) Péter Kardos
3+
//L Please refer to the full license distributed with this software.
4+
//L-----------------------------------------------------------------------------
5+
6+
@rust-attr(derive(serde::Serialize, serde::Deserialize))
7+
export enum Theme {
8+
system, // The first is always the default.
9+
dark,
10+
light,
11+
}

sed_manager_config_ui/ui/icons.slint

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ export global Icons {
4545
out property <image> file-open: @image-url("../images/action/file_open.svg");
4646
out property <image> close: @image-url("../images/action/close.svg");
4747
out property <image> cancel: @image-url("../images/action/cancel.svg");
48+
out property <image> dark-mode: @image-url("../images/action/dark_mode.svg");
49+
out property <image> light-mode: @image-url("../images/action/light_mode.svg");
50+
out property <image> contrast: @image-url("../images/action/contrast.svg");
4851
}
4952

5053
export global IconColors {

sed_manager_config_ui/ui/state.slint

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import { RangeAccess } from "data/range_access.slint";
1010
import { DeviceDescription } from "data/device_description.slint";
1111
import { UnavailableDevice } from "data/unavailable_device.slint";
1212
import { MBRControl } from "data/mbr_control.slint";
13+
import { Theme } from "data/theme.slint";
14+
import { Palette } from "std-widgets.slint";
1315

1416
export struct RangeList {
1517
names: [string],
@@ -125,6 +127,16 @@ export global DeviceListState {
125127

126128
export global SettingsState {
127129
in property <string> license-text;
128-
in property <bool> license-changed;
129-
callback accept-license();
130+
in property <string> accepted-license-fingerprint;
131+
in property <string> license-fingerprint;
132+
in property <Theme> theme;
133+
changed theme => {
134+
if theme == Theme.dark {
135+
Palette.color-scheme = ColorScheme.dark;
136+
} else if theme == Theme.light {
137+
Palette.color-scheme = ColorScheme.light;
138+
} else {
139+
Palette.color-scheme = ColorScheme.unknown;
140+
}
141+
}
130142
}

0 commit comments

Comments
 (0)