diff --git a/package.json b/package.json index c8339ebea..681723b6e 100644 --- a/package.json +++ b/package.json @@ -113,4 +113,4 @@ "yargs": "^17.7.2" }, "browserslist": "cover 100%,not android < 5" -} +} \ No newline at end of file diff --git a/res/android/values/themes.xml b/res/android/values/themes.xml index 82bcebedc..bd2204411 100644 --- a/res/android/values/themes.xml +++ b/res/android/values/themes.xml @@ -4,6 +4,6 @@ @color/ic_splash_background @drawable/ic_launcher_foreground 200 - @style/Theme.AppCompat.NoActionBar + @style/Theme.AppCompat.DayNight.NoActionBar diff --git a/src/lib/settings.js b/src/lib/settings.js index 090bf94ab..391654494 100644 --- a/src/lib/settings.js +++ b/src/lib/settings.js @@ -1,10 +1,12 @@ import fsOperation from "fileSystem"; import ThemeBuilder from "theme/builder"; import themes from "theme/list"; +import { getSystemEditorTheme } from "theme/preInstalled"; import Url from "utils/Url"; import helpers from "utils/helpers"; import constants from "./constants"; import lang from "./lang"; +import { isDeviceDarkTheme } from "./systemConfiguration"; /** * @typedef {object} fileBrowserSettings @@ -182,8 +184,10 @@ class Settings { this.settingsFile = Url.join(DATA_STORAGE, "settings.json"); if (!IS_FREE_VERSION) { - this.#defaultSettings.appTheme = "ocean"; - this.#defaultSettings.editorTheme = "ace/theme/dracula"; + this.#defaultSettings.appTheme = "system"; + this.#defaultSettings.editorTheme = getSystemEditorTheme( + isDeviceDarkTheme(), + ); } this.#initialized = true; diff --git a/src/lib/systemConfiguration.js b/src/lib/systemConfiguration.js index 59dc59bd6..24a3180b7 100644 --- a/src/lib/systemConfiguration.js +++ b/src/lib/systemConfiguration.js @@ -52,3 +52,7 @@ export function getSystemConfiguration() { cordova.exec(resolve, reject, "System", "get-configuration", []); }); } + +export function isDeviceDarkTheme() { + return window.matchMedia("(prefers-color-scheme: dark)").matches; +} diff --git a/src/palettes/changeTheme/index.js b/src/palettes/changeTheme/index.js index 8e4ff873f..be76c6fa7 100644 --- a/src/palettes/changeTheme/index.js +++ b/src/palettes/changeTheme/index.js @@ -1,7 +1,9 @@ import "./style.scss"; import palette from "components/palette"; import appSettings from "lib/settings"; +import { isDeviceDarkTheme } from "lib/systemConfiguration"; import themes from "theme/list"; +import { updateSystemTheme } from "theme/preInstalled"; export default function changeTheme(type = "editor") { palette( @@ -56,11 +58,45 @@ function generateHints(type) { }); } +let previousDark = isDeviceDarkTheme(); +const updateTimeMs = 2000; + +let intervalId = setInterval(async () => { + if (appSettings.value.appTheme.toLowerCase() === "system") { + const isDark = isDeviceDarkTheme(); + if (isDark !== previousDark) { + previousDark = isDark; + updateSystemTheme(isDark); + } + } +}, updateTimeMs); + function onselect(value) { if (!value) return; const selection = JSON.parse(value); + if (selection.theme === "system") { + // Start interval if not already started + if (!intervalId) { + intervalId = setInterval(async () => { + if (appSettings.value.appTheme.toLowerCase() === "system") { + const isDark = isDeviceDarkTheme(); + if (isDark !== previousDark) { + previousDark = isDark; + updateSystemTheme(isDark); + } + } + }, updateTimeMs); + } + } else { + // Cancel interval if it's running + if (intervalId) { + clearInterval(intervalId); + intervalId = null; + } + } + if (selection.type === "editor") { editorManager.editor.setTheme(selection.theme); appSettings.update( diff --git a/src/theme/list.js b/src/theme/list.js index dfeea53ef..0c8b308f8 100644 --- a/src/theme/list.js +++ b/src/theme/list.js @@ -1,10 +1,11 @@ import fsOperation from "fileSystem"; +import { isDeviceDarkTheme } from "lib/systemConfiguration"; import Url from "utils/Url"; import color from "utils/color"; import fonts from "../lib/fonts"; import settings from "../lib/settings"; import ThemeBuilder from "./builder"; -import themes from "./preInstalled"; +import themes, { updateSystemTheme } from "./preInstalled"; /** @type {Map} */ const appThemes = new Map(); @@ -12,6 +13,9 @@ let themeApplied = false; function init() { themes.forEach((theme) => add(theme)); + (async () => { + updateSystemTheme(isDeviceDarkTheme()); + })(); } /** @@ -68,7 +72,7 @@ function add(theme) { * @param {string} id The name of the theme to apply * @param {boolean} init Whether or not this is the first time the theme is being applied */ -async function apply(id, init) { +export async function apply(id, init) { if (!DOES_SUPPORT_THEME) { id = "default"; } @@ -91,7 +95,9 @@ async function apply(id, init) { if (init && theme.preferredEditorTheme) { update.editorTheme = theme.preferredEditorTheme; - editorManager.editor.setTheme(theme.preferredEditorTheme); + if (editorManager != null && editorManager.editor != null) { + editorManager.editor.setTheme(theme.preferredEditorTheme); + } } if (init && theme.preferredFont) { @@ -129,7 +135,7 @@ async function apply(id, init) { * Update a theme * @param {ThemeBuilder} theme */ -function update(theme) { +export function update(theme) { if (!(theme instanceof ThemeBuilder)) return; const oldTheme = get(theme.id); if (!oldTheme) { diff --git a/src/theme/preInstalled.js b/src/theme/preInstalled.js index a3acefe5a..f66704819 100644 --- a/src/theme/preInstalled.js +++ b/src/theme/preInstalled.js @@ -1,4 +1,9 @@ +import restoreTheme from "lib/restoreTheme"; +import appSettings from "lib/settings"; +import { isDeviceDarkTheme } from "lib/systemConfiguration"; +import color from "utils/color"; import { createBuiltInTheme } from "./builder"; +import { apply, update } from "./list"; const WHITE = "rgb(255, 255, 255)"; const BLACK = "rgb(0, 0, 0)"; @@ -164,10 +169,68 @@ light.linkTextColor = "rgb(104, 103, 149)"; light.borderColor = "rgb(153, 153, 153)"; light.popupIconColor = "rgb(51, 62, 89)"; +const system = createBuiltInTheme("System"); + +export function getSystemEditorTheme(darkTheme) { + if (darkTheme) { + return "ace/theme/clouds_midnight"; + } else { + return "ace/theme/crimson_editor"; + } +} + +export function updateSystemTheme(darkTheme) { + if (darkTheme) { + system.primaryColor = "rgb(49, 49, 49)"; + system.primaryTextColor = WHITE; + system.darkenedPrimaryColor = "rgb(29, 29, 29)"; + system.secondaryColor = "rgb(37, 37, 37)"; + system.secondaryTextColor = WHITE; + system.activeColor = "rgb(51, 153, 255)"; + system.linkTextColor = "rgb(181, 180, 233)"; + system.borderColor = "rgba(230, 230, 230, 0.2)"; + system.popupIconColor = WHITE; + + system.popupBackgroundColor = "rgb(49, 49, 49)"; + system.popupTextColor = WHITE; + system.popupActiveColor = "rgb(255, 215, 0)"; + system.type = "dark"; + } else { + system.type = "light"; + system.darkenedPrimaryColor = "rgb(153, 153, 153)"; + system.primaryColor = WHITE; + system.primaryTextColor = "rgb(51, 62, 89)"; + system.secondaryColor = WHITE; + system.secondaryTextColor = "rgb(51, 62, 89)"; + system.activeColor = "rgb(51, 153, 255)"; + system.linkTextColor = BLACK; + system.borderColor = "rgb(153, 153, 153)"; + system.popupIconColor = "rgb(51, 62, 89)"; + + system.popupBackgroundColor = WHITE; + system.popupTextColor = BLACK; + system.popupActiveColor = "rgb(255, 215, 0)"; + } + + system.preferredEditorTheme = getSystemEditorTheme(darkTheme); + + if ( + appSettings !== undefined && + appSettings.value !== undefined && + appSettings.value.appTheme !== undefined && + appSettings.value.appTheme.toLowerCase() === "system" + ) { + apply(system.id, true); + } +} + +updateSystemTheme(isDeviceDarkTheme()); + const custom = createBuiltInTheme("Custom"); custom.autoDarkened = true; export default [ + system, createBuiltInTheme("default", "dark", "free"), dark, oled, diff --git a/www/index.html b/www/index.html index e4c0e5ec3..ae9aa7f4d 100644 --- a/www/index.html +++ b/www/index.html @@ -165,17 +165,17 @@ Acode - - - - - + + + + +