From 44e0ebdab40f3e59ddeee0b7f06284cd96d5bee0 Mon Sep 17 00:00:00 2001 From: James Date: Mon, 24 Jun 2019 00:18:59 +1000 Subject: [PATCH] Implement basic dark mode --- src/frontend/rest/services/dark_mode.rs | 27 +++++++++++++++++++++++++ src/frontend/rest/services/mod.rs | 2 ++ src/native/interop.cpp | 18 +++++++++++++++++ src/native/mod.rs | 16 +++++++++++++++ static/css/main.css | 5 +++++ static/js/main.js | 12 +++++++++-- 6 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 src/frontend/rest/services/dark_mode.rs diff --git a/src/frontend/rest/services/dark_mode.rs b/src/frontend/rest/services/dark_mode.rs new file mode 100644 index 0000000..bc6ef8a --- /dev/null +++ b/src/frontend/rest/services/dark_mode.rs @@ -0,0 +1,27 @@ +//! frontend/rest/services/dark_mode.rs +//! +//! This call returns if dark mode is enabled on the system currently. + +use frontend::rest::services::default_future; +use frontend::rest::services::Future; +use frontend::rest::services::Request; +use frontend::rest::services::Response; +use frontend::rest::services::WebService; + +use hyper::header::{ContentLength, ContentType}; + +use logging::LoggingErrors; + +use native::is_dark_mode_active; + +pub fn handle(_service: &WebService, _req: Request) -> Future { + let file = serde_json::to_string(&is_dark_mode_active()) + .log_expect("Failed to render JSON payload of installation status object"); + + default_future( + Response::new() + .with_header(ContentLength(file.len() as u64)) + .with_header(ContentType::json()) + .with_body(file), + ) +} diff --git a/src/frontend/rest/services/mod.rs b/src/frontend/rest/services/mod.rs index c7ce3b8..df9ea28 100644 --- a/src/frontend/rest/services/mod.rs +++ b/src/frontend/rest/services/mod.rs @@ -23,6 +23,7 @@ use futures::sink::Sink; mod attributes; mod config; mod default_path; +mod dark_mode; mod exit; mod install; mod installation_status; @@ -131,6 +132,7 @@ impl Service for WebService { match (method, path.as_str()) { (Method::Get, "/api/attrs") => attributes::handle(self, req), (Method::Get, "/api/config") => config::handle(self, req), + (Method::Get, "/api/dark-mode") => dark_mode::handle(self, req), (Method::Get, "/api/default-path") => default_path::handle(self, req), (Method::Get, "/api/exit") => exit::handle(self, req), (Method::Get, "/api/packages") => packages::handle(self, req), diff --git a/src/native/interop.cpp b/src/native/interop.cpp index 9373d02..6320002 100644 --- a/src/native/interop.cpp +++ b/src/native/interop.cpp @@ -9,6 +9,24 @@ #include "objidl.h" #include "shlguid.h" +// https://stackoverflow.com/questions/52101827/windows-10-getsyscolor-does-not-get-dark-ui-color-theme +extern "C" int isDarkThemeActive() { + DWORD type; + DWORD value; + DWORD count = 4; + LSTATUS st = RegGetValue( + HKEY_CURRENT_USER, + TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"), + TEXT("AppsUseLightTheme"), + RRF_RT_REG_DWORD, + &type, + &value, + &count ); + if ( st == ERROR_SUCCESS && type == REG_DWORD ) + return value == 0; + return false; +} + extern "C" int saveShortcut( const char *shortcutPath, const char *description, diff --git a/src/native/mod.rs b/src/native/mod.rs index 54c9950..1c2cc0d 100644 --- a/src/native/mod.rs +++ b/src/native/mod.rs @@ -39,6 +39,8 @@ mod natives { args: *const ::std::os::raw::c_char, workingDir: *const ::std::os::raw::c_char, ) -> ::std::os::raw::c_int; + + pub fn isDarkThemeActive() -> ::std::os::raw::c_uint; } // Needed here for Windows interop @@ -201,6 +203,14 @@ mod natives { processes } + + // Needed here for Windows interop + #[allow(unsafe_code)] + pub fn is_dark_mode_active() -> bool { + unsafe { + isDarkThemeActive() == 1 + } + } } #[cfg(not(windows))] @@ -307,6 +317,12 @@ mod natives { } processes // return running processes } + + /// Returns if dark mode is active on this system. + pub fn is_dark_mode_active() -> bool { + // No-op + false + } } pub use self::natives::*; diff --git a/static/css/main.css b/static/css/main.css index bd6337b..2ca61a7 100644 --- a/static/css/main.css +++ b/static/css/main.css @@ -86,3 +86,8 @@ pre { padding: 20px; background: #fff; } + +/* Dark mode */ +body.has-background-black-ter .subtitle, body.has-background-black-ter .column > div { + color: hsl(0, 0%, 96%); +} diff --git a/static/js/main.js b/static/js/main.js index 04fbdc9..6825c51 100644 --- a/static/js/main.js +++ b/static/js/main.js @@ -38,6 +38,13 @@ function disable_shortcuts(e) { } } +// Check to see if we need to enable dark mode +ajax("/api/dark-mode", function(enable) { + if (enable) { + document.body.classList.add("has-background-black-ter"); + } +}); + window.addEventListener("keydown", disable_shortcuts); document.getElementById("window-title").innerText = base_attributes.name + " Installer"; @@ -62,11 +69,12 @@ var app = new Vue({ }, methods: { "exit": function() { - ajax("/api/exit", function() {}, function(msg) { + /*ajax("/api/exit", function() {}, function(msg) { alert("LiftInstall encountered and error while exiting: " + msg + "\nPlease upload the log file (in the same directory as the installer) to " + "the respective maintainers for this application (where you got it from!)"); - }); + });*/ + window.close(); } } }).$mount("#app");