Preferences: Improve the appearances tab with live preview, color scheme and accent color settings
This commit is contained in:
Generated
+74
-1
@@ -10,11 +10,14 @@
|
||||
"@girs/adw-1": "^4.1.0",
|
||||
"@girs/gdesktopenums-3.0": "^4.1.0",
|
||||
"@girs/gdk-4.0": "^4.1.0",
|
||||
"@girs/gdkpixbuf-2.0": "^4.1.0",
|
||||
"@girs/geoclue-2.0": "^4.1.0",
|
||||
"@girs/gio-2.0": "^4.1.0",
|
||||
"@girs/glib-2.0": "^4.1.0",
|
||||
"@girs/gly-2": "^4.1.0",
|
||||
"@girs/glygtk4-2": "^4.1.0",
|
||||
"@girs/gobject-2.0": "^4.1.0",
|
||||
"@girs/graphene-1.0": "^4.1.0",
|
||||
"@girs/gsk-4.0": "^4.1.0",
|
||||
"@girs/gtk-4.0": "^4.1.0",
|
||||
"@girs/meta-18": "^4.1.0",
|
||||
"@girs/shell-18": "^4.1.0",
|
||||
@@ -444,6 +447,42 @@
|
||||
"@girs/gobject-2.0": "^4.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@girs/gly-2": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@girs/gly-2/-/gly-2-4.1.0.tgz",
|
||||
"integrity": "sha512-blF/PuZpQp5NhYYkIJOu9Xq+vEX3vxq2bzbjrNS3XodSh8gjX6wxX8Gxp9808YK7b2/6+MYVt3fVeZQ34ybHuw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@girs/gio-2.0": "^4.1.0",
|
||||
"@girs/gjs": "^4.1.0",
|
||||
"@girs/glib-2.0": "^4.1.0",
|
||||
"@girs/gmodule-2.0": "^4.1.0",
|
||||
"@girs/gobject-2.0": "^4.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@girs/glygtk4-2": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@girs/glygtk4-2/-/glygtk4-2-4.1.0.tgz",
|
||||
"integrity": "sha512-gD1kjxo1cnkq/rXKDVOY1gJfaxvgqtgl2jn5q56asN+9yk0Cp3jZyDPlPcqrC1Gdv8deD8j81P7nybo4jdJZwg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@girs/cairo-1.0": "^4.1.0",
|
||||
"@girs/freetype2-2.0": "^4.1.0",
|
||||
"@girs/gdk-4.0": "^4.1.0",
|
||||
"@girs/gdkpixbuf-2.0": "^4.1.0",
|
||||
"@girs/gio-2.0": "^4.1.0",
|
||||
"@girs/gjs": "^4.1.0",
|
||||
"@girs/glib-2.0": "^4.1.0",
|
||||
"@girs/gly-2": "^4.1.0",
|
||||
"@girs/gmodule-2.0": "^4.1.0",
|
||||
"@girs/gobject-2.0": "^4.1.0",
|
||||
"@girs/harfbuzz-0.0": "^4.1.0",
|
||||
"@girs/pango-1.0": "^4.1.0",
|
||||
"@girs/pangocairo-1.0": "^4.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@girs/gmodule-2.0": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@girs/gmodule-2.0/-/gmodule-2.0-4.1.0.tgz",
|
||||
@@ -2116,6 +2155,40 @@
|
||||
"@girs/gobject-2.0": "^4.1.0"
|
||||
}
|
||||
},
|
||||
"@girs/gly-2": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@girs/gly-2/-/gly-2-4.1.0.tgz",
|
||||
"integrity": "sha512-blF/PuZpQp5NhYYkIJOu9Xq+vEX3vxq2bzbjrNS3XodSh8gjX6wxX8Gxp9808YK7b2/6+MYVt3fVeZQ34ybHuw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@girs/gio-2.0": "^4.1.0",
|
||||
"@girs/gjs": "^4.1.0",
|
||||
"@girs/glib-2.0": "^4.1.0",
|
||||
"@girs/gmodule-2.0": "^4.1.0",
|
||||
"@girs/gobject-2.0": "^4.1.0"
|
||||
}
|
||||
},
|
||||
"@girs/glygtk4-2": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@girs/glygtk4-2/-/glygtk4-2-4.1.0.tgz",
|
||||
"integrity": "sha512-gD1kjxo1cnkq/rXKDVOY1gJfaxvgqtgl2jn5q56asN+9yk0Cp3jZyDPlPcqrC1Gdv8deD8j81P7nybo4jdJZwg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@girs/cairo-1.0": "^4.1.0",
|
||||
"@girs/freetype2-2.0": "^4.1.0",
|
||||
"@girs/gdk-4.0": "^4.1.0",
|
||||
"@girs/gdkpixbuf-2.0": "^4.1.0",
|
||||
"@girs/gio-2.0": "^4.1.0",
|
||||
"@girs/gjs": "^4.1.0",
|
||||
"@girs/glib-2.0": "^4.1.0",
|
||||
"@girs/gly-2": "^4.1.0",
|
||||
"@girs/gmodule-2.0": "^4.1.0",
|
||||
"@girs/gobject-2.0": "^4.1.0",
|
||||
"@girs/harfbuzz-0.0": "^4.1.0",
|
||||
"@girs/pango-1.0": "^4.1.0",
|
||||
"@girs/pangocairo-1.0": "^4.1.0"
|
||||
}
|
||||
},
|
||||
"@girs/gmodule-2.0": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@girs/gmodule-2.0/-/gmodule-2.0-4.1.0.tgz",
|
||||
|
||||
+4
-1
@@ -14,11 +14,14 @@
|
||||
"@girs/adw-1": "^4.1.0",
|
||||
"@girs/gdesktopenums-3.0": "^4.1.0",
|
||||
"@girs/gdk-4.0": "^4.1.0",
|
||||
"@girs/gdkpixbuf-2.0": "^4.1.0",
|
||||
"@girs/geoclue-2.0": "^4.1.0",
|
||||
"@girs/gio-2.0": "^4.1.0",
|
||||
"@girs/glib-2.0": "^4.1.0",
|
||||
"@girs/gly-2": "^4.1.0",
|
||||
"@girs/glygtk4-2": "^4.1.0",
|
||||
"@girs/gobject-2.0": "^4.1.0",
|
||||
"@girs/graphene-1.0": "^4.1.0",
|
||||
"@girs/gsk-4.0": "^4.1.0",
|
||||
"@girs/gtk-4.0": "^4.1.0",
|
||||
"@girs/meta-18": "^4.1.0",
|
||||
"@girs/shell-18": "^4.1.0",
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
SPDX-FileCopyrightText: Night Theme Switcher Contributors
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
-->
|
||||
<svg width="160" height="120" version="1.1" viewBox="0 0 160 120" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<filter id="filter12" x="-.0586" y="-.082" width="1.12" height="1.18" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-color="rgb(0,0,0)" flood-opacity=".2" in="SourceGraphic" result="flood"/>
|
||||
<feGaussianBlur in="SourceGraphic" result="blur" stdDeviation="3.000000"/>
|
||||
<feOffset dx="0.000000" dy="2.000000" in="blur" result="offset"/>
|
||||
<feComposite in="flood" in2="offset" operator="in" result="comp1"/>
|
||||
<feComposite in="SourceGraphic" in2="comp1" result="comp2"/>
|
||||
</filter>
|
||||
</defs>
|
||||
<rect x="10" y="10" width="140" height="100" rx="6" ry="6" fill="#222226" filter="url(#filter12)" stroke="#000006" stroke-opacity=".12" stroke-width="2" style="paint-order:markers stroke fill"/>
|
||||
<rect x="10" y="10" width="140" height="20" rx="6" ry="6" fill="#2e2e32"/>
|
||||
<rect x="10" y="20" width="140" height="10" fill="#2e2e32"/>
|
||||
<rect x="10" y="30" width="140" height="1" fill="#000006" fill-opacity=".12"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
SPDX-FileCopyrightText: Night Theme Switcher Contributors
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
-->
|
||||
<svg width="160" height="120" version="1.1" viewBox="0 0 160 120" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<filter id="filter12" x="-.0586" y="-.082" width="1.12" height="1.18" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-color="rgb(0,0,0)" flood-opacity=".2" in="SourceGraphic" result="flood"/>
|
||||
<feGaussianBlur in="SourceGraphic" result="blur" stdDeviation="3.000000"/>
|
||||
<feOffset dx="0.000000" dy="2.000000" in="blur" result="offset"/>
|
||||
<feComposite in="flood" in2="offset" operator="in" result="comp1"/>
|
||||
<feComposite in="SourceGraphic" in2="comp1" result="comp2"/>
|
||||
</filter>
|
||||
</defs>
|
||||
<rect x="10" y="10" width="140" height="100" rx="6" ry="6" fill="#fafafb" filter="url(#filter12)" stroke="#000006" stroke-opacity=".12" stroke-width="2" style="paint-order:markers stroke fill"/>
|
||||
<rect x="10" y="10" width="140" height="20" rx="6" ry="6" fill="#fff"/>
|
||||
<rect x="10" y="20" width="140" height="10" fill="#fff"/>
|
||||
<rect x="10" y="30" width="140" height="1" fill="#000006" fill-opacity=".12"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -4,6 +4,18 @@ SPDX-FileCopyrightText: Night Theme Switcher Contributors
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
-->
|
||||
<schemalist gettext-domain="nightthemeswitcher@romainvigier.fr">
|
||||
<enum id="org.gnome.shell.extensions.nightthemeswitcher.accent-color-enum">
|
||||
<value nick="unset" value="0"/>
|
||||
<value nick="blue" value="1"/>
|
||||
<value nick="green" value="2"/>
|
||||
<value nick="orange" value="3"/>
|
||||
<value nick="red" value="4"/>
|
||||
<value nick="pink" value="5"/>
|
||||
<value nick="purple" value="6"/>
|
||||
<value nick="slate" value="7"/>
|
||||
<value nick="teal" value="8"/>
|
||||
<value nick="yellow" value="9"/>
|
||||
</enum>
|
||||
<enum id="org.gnome.shell.extensions.nightthemeswitcher.color-scheme-enum">
|
||||
<value nick="default" value="0"/>
|
||||
<value nick="prefer-dark" value="1"/>
|
||||
@@ -59,4 +71,12 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
<default>"prefer-dark"</default>
|
||||
</key>
|
||||
</schema>
|
||||
<schema id="org.gnome.shell.extensions.nightthemeswitcher.accent-color" path="/org/gnome/shell/extensions/nightthemeswitcher/accent-color/">
|
||||
<key name="day" enum="org.gnome.shell.extensions.nightthemeswitcher.accent-color-enum">
|
||||
<default>"unset"</default>
|
||||
</key>
|
||||
<key name="night" enum="org.gnome.shell.extensions.nightthemeswitcher.accent-color-enum">
|
||||
<default>"unset"</default>
|
||||
</key>
|
||||
</schema>
|
||||
</schemalist>
|
||||
|
||||
@@ -5,6 +5,8 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
-->
|
||||
<gresources>
|
||||
<gresource prefix="/org/gnome/Shell/Extensions/nightthemeswitcher/preferences">
|
||||
<file compressed="true" preprocess="xml-stripblanks">assets/preview-window-dark.svg</file>
|
||||
<file compressed="true" preprocess="xml-stripblanks">assets/preview-window-light.svg</file>
|
||||
<file compressed="true" preprocess="xml-stripblanks" alias="icons/scalable/actions/nightthemeswitcher-code-symbolic.svg">icons/code-symbolic.svg</file>
|
||||
<file compressed="true" preprocess="xml-stripblanks" alias="icons/scalable/actions/nightthemeswitcher-translate-symbolic.svg">icons/translate-symbolic.svg</file>
|
||||
<file compressed="true" preprocess="xml-stripblanks" alias="icons/scalable/apps/nightthemeswitcher-symbolic.svg">icons/nightthemeswitcher-symbolic.svg</file>
|
||||
@@ -12,6 +14,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
<file compressed="true" preprocess="xml-stripblanks" alias="icons/scalable/categories/nightthemeswitcher-commands-symbolic.svg">icons/commands-symbolic.svg</file>
|
||||
<file compressed="true" preprocess="xml-stripblanks" alias="icons/scalable/categories/nightthemeswitcher-contribute-symbolic.svg">icons/contribute-symbolic.svg</file>
|
||||
<file compressed="true" preprocess="xml-stripblanks" alias="icons/scalable/categories/nightthemeswitcher-schedule-symbolic.svg">icons/schedule-symbolic.svg</file>
|
||||
<file compressed="true" preprocess="xml-stripblanks">ui/AppearanceChooser.ui</file>
|
||||
<file compressed="true" preprocess="xml-stripblanks">ui/AppearancePage.ui</file>
|
||||
<file compressed="true" preprocess="xml-stripblanks">ui/BackgroundButton.ui</file>
|
||||
<file compressed="true" preprocess="xml-stripblanks">ui/CommandsPage.ui</file>
|
||||
@@ -19,5 +22,6 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
<file compressed="true" preprocess="xml-stripblanks">ui/SchedulePage.ui</file>
|
||||
<file compressed="true" preprocess="xml-stripblanks">ui/ShortcutButton.ui</file>
|
||||
<file compressed="true" preprocess="xml-stripblanks">ui/TimeChooser.ui</file>
|
||||
<file compressed="true">style.css</file>
|
||||
</gresource>
|
||||
</gresources>
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: Night Theme Switcher Contributors
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
color-chooser button {
|
||||
min-width: 22px;
|
||||
min-height: 22px;
|
||||
margin: 3px;
|
||||
padding: 0;
|
||||
border-radius: 50%;
|
||||
background-color: var(--accent-color);
|
||||
outline: 3px solid transparent;
|
||||
outline-offset: 3px;
|
||||
}
|
||||
|
||||
color-chooser button:focus {
|
||||
outline-color: alpha(var(--accent-color), 0.5);
|
||||
}
|
||||
|
||||
color-chooser button:checked {
|
||||
outline-color: var(--accent-color);
|
||||
}
|
||||
|
||||
color-chooser button.blue {
|
||||
--accent-color: var(--accent-blue);
|
||||
}
|
||||
|
||||
color-chooser button.green {
|
||||
--accent-color: var(--accent-green);
|
||||
}
|
||||
|
||||
color-chooser button.orange {
|
||||
--accent-color: var(--accent-orange);
|
||||
}
|
||||
|
||||
color-chooser button.red {
|
||||
--accent-color: var(--accent-red);
|
||||
}
|
||||
|
||||
color-chooser button.pink {
|
||||
--accent-color: var(--accent-pink);
|
||||
}
|
||||
|
||||
color-chooser button.purple {
|
||||
--accent-color: var(--accent-purple);
|
||||
}
|
||||
|
||||
color-chooser button.slate {
|
||||
--accent-color: var(--accent-slate);
|
||||
}
|
||||
|
||||
color-chooser button.teal {
|
||||
--accent-color: var(--accent-teal);
|
||||
}
|
||||
|
||||
color-chooser button.yellow {
|
||||
--accent-color: var(--accent-yellow);
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
SPDX-FileCopyrightText: Night Theme Switcher Contributors
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
-->
|
||||
<interface domain="nightthemeswitcher@romainvigier.fr">
|
||||
<template class="AppearanceChooser" parent="GtkWidget">
|
||||
<property name="layout-manager">
|
||||
<object class="GtkBoxLayout">
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">24</property>
|
||||
</object>
|
||||
</property>
|
||||
<child>
|
||||
<object class="AppearancePreview">
|
||||
<binding name="accent-color">
|
||||
<lookup name="accent-color" type="AppearanceChooser"/>
|
||||
</binding>
|
||||
<binding name="background-uri">
|
||||
<lookup name="background-uri" type="AppearanceChooser"/>
|
||||
</binding>
|
||||
<binding name="color-scheme">
|
||||
<lookup name="color-scheme" type="AppearanceChooser"/>
|
||||
</binding>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup">
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Style</property>
|
||||
<child>
|
||||
<object class="AdwToggleGroup">
|
||||
<style>
|
||||
<class name="flat"/>
|
||||
<class name="round"/>
|
||||
</style>
|
||||
<property name="valign">center</property>
|
||||
<property name="active-name" bind-source="AppearanceChooser" bind-property="color-scheme" bind-flags="bidirectional"/>
|
||||
<child>
|
||||
<object class="AdwToggle">
|
||||
<property name="name">prefer-light</property>
|
||||
<property name="label" translatable="yes">Light</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwToggle">
|
||||
<property name="name">default</property>
|
||||
<property name="label" translatable="yes">Default</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwToggle">
|
||||
<property name="name">prefer-dark</property>
|
||||
<property name="label" translatable="yes">Dark</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Accent color</property>
|
||||
<child>
|
||||
<object class="ColorChooser">
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="margin-top">6</property>
|
||||
<property name="margin-bottom">6</property>
|
||||
<property name="active-color" bind-source="AppearanceChooser" bind-property="accent-color" bind-flags="bidirectional"/>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Background</property>
|
||||
<property name="activatable-widget">background_button</property>
|
||||
<child>
|
||||
<object class="BackgroundButton" id="background_button">
|
||||
<property name="valign">center</property>
|
||||
<property name="uri" bind-source="AppearanceChooser" bind-property="background-uri" bind-flags="bidirectional"/>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
||||
@@ -10,29 +10,44 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
<property name="icon-name">nightthemeswitcher-appearance-symbolic</property>
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup">
|
||||
<property name="description" translatable="yes">Background switching is handled by the Shell, these settings allow you to change the images it uses.</property>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Day background</property>
|
||||
<property name="activatable-widget">day_button</property>
|
||||
<object class="GtkBox">
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">24</property>
|
||||
<child>
|
||||
<object class="BackgroundButton" id="day_button">
|
||||
<property name="margin-top">12</property>
|
||||
<property name="margin-bottom">12</property>
|
||||
<property name="valign">center</property>
|
||||
<object class="AdwInlineViewSwitcher">
|
||||
<property name="stack">stack</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Night background</property>
|
||||
<property name="activatable-widget">night_button</property>
|
||||
<child>
|
||||
<object class="BackgroundButton" id="night_button">
|
||||
<property name="margin-top">12</property>
|
||||
<property name="margin-bottom">12</property>
|
||||
<property name="valign">center</property>
|
||||
<object class="AdwViewStack" id="stack">
|
||||
<property name="enable-transitions">True</property>
|
||||
<child>
|
||||
<object class="AdwViewStackPage">
|
||||
<property name="name">day</property>
|
||||
<property name="title" translatable="yes">Day</property>
|
||||
<property name="child">
|
||||
<object class="AppearanceChooser" id="day_appearance_chooser"/>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwViewStackPage">
|
||||
<property name="name">night</property>
|
||||
<property name="title" translatable="yes">Night</property>
|
||||
<property name="child">
|
||||
<object class="AppearanceChooser" id="night_appearance_chooser"/>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<style>
|
||||
<class name="dimmed"/>
|
||||
</style>
|
||||
<property name="label" translatable="yes">Settings are applied when the extension is enabled.</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
|
||||
@@ -5,18 +5,22 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
-->
|
||||
<interface domain="nightthemeswitcher@romainvigier.fr">
|
||||
<template class="BackgroundButton" parent="GtkButton">
|
||||
<property name="tooltip-text" translatable="yes">Change background</property>
|
||||
<signal name="clicked" handler="onClicked" swapped="no"/>
|
||||
<style>
|
||||
<class name="image-button"/>
|
||||
</style>
|
||||
<child>
|
||||
<object class="GtkPicture" id="thumbnail">
|
||||
<property name="can-shrink">False</property>
|
||||
<property name="width-request" bind-source="BackgroundButton" bind-property="thumb-width" bind-flags="sync-create"/>
|
||||
<property name="height-request" bind-source="BackgroundButton" bind-property="thumb-height" bind-flags="sync-create"/>
|
||||
<property name="tooltip-text" translatable="yes">Change background</property>
|
||||
<property name="child">
|
||||
<object class="AdwButtonContent">
|
||||
<property name="icon-name">document-open-symbolic</property>
|
||||
<property name="can-shrink">True</property>
|
||||
<binding name="label">
|
||||
<closure type="gchararray" function="_getBackgroundFileName">
|
||||
<lookup name="uri" type="BackgroundButton"/>
|
||||
</closure>
|
||||
</binding>
|
||||
</object>
|
||||
</child>
|
||||
</property>
|
||||
</template>
|
||||
<object class="GtkFileDialog" id="file_dialog">
|
||||
<property name="modal">True</property>
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
// SPDX-FileCopyrightText: Night Theme Switcher Contributors
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
/**
|
||||
* Accent colors.
|
||||
* @readonly
|
||||
* @enum {string}
|
||||
*/
|
||||
export const AccentColor = {
|
||||
BLUE: "blue",
|
||||
GREEN: "green",
|
||||
ORANGE: "orange",
|
||||
RED: "red",
|
||||
PINK: "pink",
|
||||
PURPLE: "purple",
|
||||
SLATE: "slate",
|
||||
TEAL: "teal",
|
||||
YELLOW: "yellow",
|
||||
};
|
||||
@@ -9,5 +9,5 @@
|
||||
export const ColorScheme = {
|
||||
DEFAULT: "default",
|
||||
PREFER_DARK: "prefer-dark",
|
||||
PREFER_LIGHT: "prefer-night",
|
||||
PREFER_LIGHT: "prefer-light",
|
||||
};
|
||||
|
||||
@@ -19,6 +19,7 @@ main = [
|
||||
'prefs.js',
|
||||
]
|
||||
enums = [
|
||||
'enums/AccentColor.js',
|
||||
'enums/ColorScheme.js',
|
||||
'enums/Time.js',
|
||||
]
|
||||
@@ -33,8 +34,11 @@ modules = [
|
||||
'modules/Timer.js',
|
||||
]
|
||||
preferences = [
|
||||
'preferences/AppearanceChooser.js',
|
||||
'preferences/AppearancePage.js',
|
||||
'preferences/AppearancePreview.js',
|
||||
'preferences/BackgroundButton.js',
|
||||
'preferences/ColorChooser.js',
|
||||
'preferences/CommandsPage.js',
|
||||
'preferences/ContributePage.js',
|
||||
'preferences/SchedulePage.js',
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
// SPDX-FileCopyrightText: Night Theme Switcher Contributors
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
import GObject from "gi://GObject";
|
||||
import Gtk from "gi://Gtk";
|
||||
|
||||
export class AppearanceChooser extends Gtk.Widget {
|
||||
static {
|
||||
GObject.registerClass(
|
||||
{
|
||||
GTypeName: "AppearanceChooser",
|
||||
Template: "resource:///org/gnome/Shell/Extensions/nightthemeswitcher/preferences/ui/AppearanceChooser.ui",
|
||||
Properties: {
|
||||
"accent-color": GObject.ParamSpec.string(
|
||||
"accent-color",
|
||||
"Accent color",
|
||||
"Accent color",
|
||||
GObject.ParamFlags.READWRITE,
|
||||
null,
|
||||
),
|
||||
"background-uri": GObject.ParamSpec.string(
|
||||
"background-uri",
|
||||
"Background URI",
|
||||
"URI to the background file",
|
||||
GObject.ParamFlags.READWRITE,
|
||||
null,
|
||||
),
|
||||
"color-scheme": GObject.ParamSpec.string(
|
||||
"color-scheme",
|
||||
"Color scheme",
|
||||
"Color scheme",
|
||||
GObject.ParamFlags.READWRITE,
|
||||
null,
|
||||
),
|
||||
},
|
||||
},
|
||||
this,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -11,17 +11,39 @@ export class AppearancePage extends Adw.PreferencesPage {
|
||||
{
|
||||
GTypeName: "AppearancePage",
|
||||
Template: "resource:///org/gnome/Shell/Extensions/nightthemeswitcher/preferences/ui/AppearancePage.ui",
|
||||
InternalChildren: ["day_button", "night_button"],
|
||||
InternalChildren: ["day_appearance_chooser", "night_appearance_chooser"],
|
||||
},
|
||||
this,
|
||||
);
|
||||
}
|
||||
|
||||
constructor({ ...params } = {}) {
|
||||
constructor({ accentColorSettings, colorSchemeSettings, ...params } = {}) {
|
||||
super(params);
|
||||
const settings = new Gio.Settings({ schema: "org.gnome.desktop.background" });
|
||||
const backgroundSettings = new Gio.Settings({ schema: "org.gnome.desktop.background" });
|
||||
const interfaceSettings = new Gio.Settings({ schema: "org.gnome.desktop.interface" });
|
||||
|
||||
settings.bind("picture-uri", this._day_button, "uri", Gio.SettingsBindFlags.DEFAULT);
|
||||
settings.bind("picture-uri-dark", this._night_button, "uri", Gio.SettingsBindFlags.DEFAULT);
|
||||
if (accentColorSettings.get_string("day") === "unset")
|
||||
accentColorSettings.set_string("day", interfaceSettings.get_string("accent-color"));
|
||||
if (accentColorSettings.get_string("night") === "unset")
|
||||
accentColorSettings.set_string("night", interfaceSettings.get_string("accent-color"));
|
||||
|
||||
accentColorSettings.bind("day", this._day_appearance_chooser, "accent-color", Gio.SettingsBindFlags.DEFAULT);
|
||||
accentColorSettings.bind("night", this._night_appearance_chooser, "accent-color", Gio.SettingsBindFlags.DEFAULT);
|
||||
|
||||
colorSchemeSettings.bind("day", this._day_appearance_chooser, "color-scheme", Gio.SettingsBindFlags.DEFAULT);
|
||||
colorSchemeSettings.bind("night", this._night_appearance_chooser, "color-scheme", Gio.SettingsBindFlags.DEFAULT);
|
||||
|
||||
backgroundSettings.bind(
|
||||
"picture-uri",
|
||||
this._day_appearance_chooser,
|
||||
"background-uri",
|
||||
Gio.SettingsBindFlags.DEFAULT,
|
||||
);
|
||||
backgroundSettings.bind(
|
||||
"picture-uri-dark",
|
||||
this._night_appearance_chooser,
|
||||
"background-uri",
|
||||
Gio.SettingsBindFlags.DEFAULT,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,333 @@
|
||||
// SPDX-FileCopyrightText: Night Theme Switcher Contributors
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
import Gdk from "gi://Gdk";
|
||||
import Gio from "gi://Gio";
|
||||
import Gly from "gi://Gly";
|
||||
import GlyGtk4 from "gi://GlyGtk4";
|
||||
import GObject from "gi://GObject";
|
||||
import Graphene from "gi://Graphene";
|
||||
import Gsk from "gi://Gsk";
|
||||
import Gtk from "gi://Gtk";
|
||||
import { AccentColor } from "../enums/AccentColor.js";
|
||||
import { ColorScheme } from "../enums/ColorScheme.js";
|
||||
|
||||
Gio._promisify(Gly.Loader.prototype, "load_async", "load_finish");
|
||||
|
||||
const PREVIEW_HEIGHT = 200;
|
||||
|
||||
const PANEL_HEIGHT = 15;
|
||||
|
||||
const WINDOW_WIDTH = 160;
|
||||
const WINDOW_HEIGHT = 120;
|
||||
|
||||
const BUTTON_WIDTH = 60;
|
||||
const BUTTON_HEIGHT = 20;
|
||||
|
||||
export class AppearancePreview extends Gtk.Widget {
|
||||
/** @type {?Gdk.Texture} */
|
||||
#backgroundTexture = null;
|
||||
/** @type {Gdk.Texture} */
|
||||
#windowDarkTexture;
|
||||
/** @type {Gdk.Texture} */
|
||||
#windowLightTexture;
|
||||
|
||||
/** @type {?AccentColor} */
|
||||
#accentColor = null;
|
||||
/** @type {?string} */
|
||||
#backgroundUri = null;
|
||||
/** @type {?ColorScheme} */
|
||||
#colorScheme = null;
|
||||
|
||||
static {
|
||||
GObject.registerClass(
|
||||
{
|
||||
GTypeName: "AppearancePreview",
|
||||
CssName: "appearance-preview",
|
||||
Properties: {
|
||||
"accent-color": GObject.ParamSpec.string(
|
||||
"accent-color",
|
||||
"Accent color",
|
||||
"Accent color",
|
||||
GObject.ParamFlags.READWRITE,
|
||||
null,
|
||||
),
|
||||
"background-uri": GObject.ParamSpec.string(
|
||||
"background-uri",
|
||||
"Background URI",
|
||||
"URI to the background file",
|
||||
GObject.ParamFlags.READWRITE,
|
||||
null,
|
||||
),
|
||||
"color-scheme": GObject.ParamSpec.string(
|
||||
"color-scheme",
|
||||
"Color scheme",
|
||||
"Color scheme",
|
||||
GObject.ParamFlags.READWRITE,
|
||||
null,
|
||||
),
|
||||
},
|
||||
},
|
||||
this,
|
||||
);
|
||||
}
|
||||
|
||||
constructor({ ...params } = {}) {
|
||||
super(params);
|
||||
|
||||
this.#windowDarkTexture = Gdk.Texture.new_from_resource(
|
||||
"/org/gnome/Shell/Extensions/nightthemeswitcher/preferences/assets/preview-window-dark.svg",
|
||||
);
|
||||
this.#windowLightTexture = Gdk.Texture.new_from_resource(
|
||||
"/org/gnome/Shell/Extensions/nightthemeswitcher/preferences/assets/preview-window-light.svg",
|
||||
);
|
||||
}
|
||||
|
||||
get accentColor() {
|
||||
return this.#accentColor;
|
||||
}
|
||||
|
||||
set accentColor(color) {
|
||||
if (!color || color === this.#accentColor || !Object.values(AccentColor).includes(color)) return;
|
||||
this.#accentColor = color;
|
||||
this.notify("accent-color");
|
||||
this.queue_draw();
|
||||
}
|
||||
|
||||
get backgroundUri() {
|
||||
return this.#backgroundUri;
|
||||
}
|
||||
|
||||
set backgroundUri(uri) {
|
||||
if (!uri || uri === this.#backgroundUri) return;
|
||||
this.#backgroundUri = uri;
|
||||
this.notify("background-uri");
|
||||
this.#updateBackgroundTexture();
|
||||
}
|
||||
|
||||
get colorScheme() {
|
||||
return this.#colorScheme;
|
||||
}
|
||||
|
||||
set colorScheme(scheme) {
|
||||
if (!scheme || scheme === this.#colorScheme || !Object.values(ColorScheme).includes(scheme)) return;
|
||||
this.#colorScheme = scheme;
|
||||
this.notify("color-scheme");
|
||||
this.queue_draw();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Gtk.Orientation} _orientation The orientation to measure.
|
||||
* @param {number} _for_size Size for the opposite of orientation.
|
||||
* @returns {[number, number, number, number]} Minimum size, natural size, minimum baseline, natural baseline.
|
||||
*/
|
||||
vfunc_measure(_orientation, _for_size) {
|
||||
return [PREVIEW_HEIGHT, PREVIEW_HEIGHT, -1, -1];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Gtk.Snapshot} snapshot The snapshot to populate.
|
||||
*/
|
||||
vfunc_snapshot(snapshot) {
|
||||
const previewWidth = this.get_width();
|
||||
const previewHeight = this.get_height();
|
||||
|
||||
snapshot.push_fill(buildGskRoundedRectanglePath(previewWidth, previewHeight, 12), Gsk.FillRule.WINDING);
|
||||
|
||||
this.#snapshotBackground(snapshot, previewWidth, previewHeight);
|
||||
this.#snapshotWindows(snapshot, previewWidth, previewHeight, this.colorScheme, this.accentColor);
|
||||
this.#snapshotPanel(snapshot, previewWidth, this.colorScheme);
|
||||
|
||||
snapshot.pop();
|
||||
}
|
||||
|
||||
async #updateBackgroundTexture() {
|
||||
try {
|
||||
const loader = new Gly.Loader({ file: Gio.File.new_for_uri(this.backgroundUri) });
|
||||
const image = await loader.load_async(null);
|
||||
this.#backgroundTexture = GlyGtk4.frame_get_texture(image.next_frame());
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
this.queue_draw();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Gtk.Snapshot} snapshot The snapshot to populate.
|
||||
* @param {number} width The width to populate.
|
||||
* @param {number} height The height to populate.
|
||||
*/
|
||||
#snapshotBackground(snapshot, width, height) {
|
||||
const ratio = width / height;
|
||||
if (!this.#backgroundTexture) {
|
||||
snapshot.append_color(
|
||||
new Gdk.RGBA({ red: 0.08, green: 0.235, blue: 0.533, alpha: 1 }),
|
||||
new Graphene.Rect({ origin: new Graphene.Point({ x: 0, y: 0 }), size: { width, height } }),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
let backgroundSnapshotWidth, backgroundSnapshotHeight;
|
||||
const backgroundRatio = this.#backgroundTexture.get_intrinsic_aspect_ratio();
|
||||
|
||||
if (backgroundRatio > ratio) {
|
||||
backgroundSnapshotWidth = height;
|
||||
backgroundSnapshotHeight = height / backgroundRatio;
|
||||
} else {
|
||||
backgroundSnapshotWidth = width * backgroundRatio;
|
||||
backgroundSnapshotHeight = width;
|
||||
}
|
||||
|
||||
const x = (width - backgroundSnapshotWidth) / 2;
|
||||
const y = (height - backgroundSnapshotHeight) / 2;
|
||||
|
||||
snapshot.save();
|
||||
snapshot.translate(new Graphene.Point({ x, y }));
|
||||
this.#backgroundTexture.snapshot(snapshot, backgroundSnapshotWidth, backgroundSnapshotHeight);
|
||||
snapshot.restore();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Gtk.Snapshot} snapshot The snapshot to populate.
|
||||
* @param {number} width The width to populate.
|
||||
* @param {number} height The height to populate.
|
||||
* @param {ColorScheme} colorScheme The color scheme to render.
|
||||
* @param {AccentColor} accentColor The accent color to render.
|
||||
*/
|
||||
#snapshotWindows(snapshot, width, height, colorScheme, accentColor) {
|
||||
const usableHeight = height - PANEL_HEIGHT;
|
||||
|
||||
const backgroundWindowX = Math.ceil(width / 2 - WINDOW_WIDTH + WINDOW_WIDTH / 2 - width / 16);
|
||||
const backgroundWindowY = Math.ceil(
|
||||
usableHeight / 2 - WINDOW_HEIGHT + WINDOW_HEIGHT / 2 - usableHeight / 16 + PANEL_HEIGHT,
|
||||
);
|
||||
const foregroundWindowX = Math.ceil(width / 2 - WINDOW_WIDTH / 2 + width / 16);
|
||||
const foregroundWindowY = Math.ceil(usableHeight / 2 - WINDOW_HEIGHT / 2 + usableHeight / 16 + PANEL_HEIGHT);
|
||||
|
||||
switch (colorScheme) {
|
||||
case ColorScheme.DEFAULT:
|
||||
this.#snapshotWindow(snapshot, backgroundWindowX, backgroundWindowY, ColorScheme.PREFER_DARK);
|
||||
this.#snapshotWindow(snapshot, foregroundWindowX, foregroundWindowY, ColorScheme.PREFER_LIGHT);
|
||||
break;
|
||||
case ColorScheme.PREFER_DARK:
|
||||
this.#snapshotWindow(snapshot, backgroundWindowX, backgroundWindowY, ColorScheme.PREFER_DARK);
|
||||
this.#snapshotWindow(snapshot, foregroundWindowX, foregroundWindowY, ColorScheme.PREFER_DARK);
|
||||
break;
|
||||
case ColorScheme.PREFER_LIGHT:
|
||||
this.#snapshotWindow(snapshot, backgroundWindowX, backgroundWindowY, ColorScheme.PREFER_LIGHT);
|
||||
this.#snapshotWindow(snapshot, foregroundWindowX, foregroundWindowY, ColorScheme.PREFER_LIGHT);
|
||||
break;
|
||||
}
|
||||
|
||||
const buttonX = foregroundWindowX + WINDOW_WIDTH - BUTTON_WIDTH - 20;
|
||||
const buttonY = foregroundWindowY + WINDOW_HEIGHT - BUTTON_HEIGHT - 20;
|
||||
|
||||
this.#snapshotButton(snapshot, buttonX, buttonY, accentColor);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Gtk.Snapshot} snapshot The snapshot to populate.
|
||||
* @param {number} x The X position at which to populate.
|
||||
* @param {number} y The Y position at which to populate.
|
||||
* @param {ColorScheme} colorScheme The color scheme to render.
|
||||
*/
|
||||
#snapshotWindow(snapshot, x, y, colorScheme) {
|
||||
const texture = colorScheme === ColorScheme.PREFER_DARK ? this.#windowDarkTexture : this.#windowLightTexture;
|
||||
snapshot.save();
|
||||
snapshot.translate(new Graphene.Point({ x, y }));
|
||||
texture.snapshot(snapshot, WINDOW_WIDTH, WINDOW_HEIGHT);
|
||||
snapshot.restore();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Gtk.Snapshot} snapshot The snapshot to populate.
|
||||
* @param {number} x The X position at which to populate.
|
||||
* @param {number} y The Y position at which to populate.
|
||||
* @param {AccentColor} accentColor The accent color to render.
|
||||
*/
|
||||
#snapshotButton(snapshot, x, y, accentColor) {
|
||||
let color;
|
||||
switch (accentColor) {
|
||||
case AccentColor.BLUE:
|
||||
color = new Gdk.RGBA({ red: 0.208, green: 0.518, blue: 0.894, alpha: 1 });
|
||||
break;
|
||||
case AccentColor.GREEN:
|
||||
color = new Gdk.RGBA({ red: 0.227, green: 0.58, blue: 0.29, alpha: 1 });
|
||||
break;
|
||||
case AccentColor.ORANGE:
|
||||
color = new Gdk.RGBA({ red: 0.929, green: 0.357, blue: 0, alpha: 1 });
|
||||
break;
|
||||
case AccentColor.PINK:
|
||||
color = new Gdk.RGBA({ red: 0.835, green: 0.38, blue: 0.6, alpha: 1 });
|
||||
break;
|
||||
case AccentColor.PURPLE:
|
||||
color = new Gdk.RGBA({ red: 0.569, green: 0.255, blue: 0.675, alpha: 1 });
|
||||
break;
|
||||
case AccentColor.RED:
|
||||
color = new Gdk.RGBA({ red: 0.902, green: 0.176, blue: 0.259, alpha: 1 });
|
||||
break;
|
||||
case AccentColor.SLATE:
|
||||
color = new Gdk.RGBA({ red: 0.435, green: 0.514, blue: 0.588, alpha: 1 });
|
||||
break;
|
||||
case AccentColor.TEAL:
|
||||
color = new Gdk.RGBA({ red: 0.129, green: 0.565, blue: 0.643, alpha: 1 });
|
||||
break;
|
||||
case AccentColor.YELLOW:
|
||||
color = new Gdk.RGBA({ red: 0.784, green: 0.533, blue: 0, alpha: 1 });
|
||||
break;
|
||||
}
|
||||
if (!color) return;
|
||||
snapshot.save();
|
||||
snapshot.translate(new Graphene.Point({ x, y }));
|
||||
snapshot.append_fill(buildGskRoundedRectanglePath(BUTTON_WIDTH, BUTTON_HEIGHT, 3), Gsk.FillRule.WINDING, color);
|
||||
snapshot.restore();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Gtk.Snapshot} snapshot The snapshot to populate.
|
||||
* @param {number} width The width to populate.
|
||||
* @param {ColorScheme} colorScheme The color scheme to render.
|
||||
*/
|
||||
#snapshotPanel(snapshot, width, colorScheme) {
|
||||
const backgroundColor =
|
||||
colorScheme === ColorScheme.PREFER_LIGHT
|
||||
? new Gdk.RGBA({ red: 0.98, green: 0.98, blue: 0.984, alpha: 1 })
|
||||
: new Gdk.RGBA({ red: 0, green: 0, blue: 0, alpha: 1 });
|
||||
|
||||
snapshot.append_color(
|
||||
backgroundColor,
|
||||
new Graphene.Rect({
|
||||
origin: new Graphene.Point({ x: 0, y: 0 }),
|
||||
size: new Graphene.Size({ width, height: PANEL_HEIGHT }),
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a rounded rectangle path until GJS supports `Gsk.RoundedRect`.
|
||||
* @param {number} width The width of the rectangle.
|
||||
* @param {number} height The height of the rectangle.
|
||||
* @param {number} radius The radius of the corners.
|
||||
* @returns {Gsk.Path} The path.
|
||||
*/
|
||||
function buildGskRoundedRectanglePath(width, height, radius) {
|
||||
const builder = new Gsk.PathBuilder();
|
||||
builder.add_circle(new Graphene.Point({ x: radius, y: radius }), radius);
|
||||
builder.add_circle(new Graphene.Point({ x: width - radius, y: radius }), radius);
|
||||
builder.add_circle(new Graphene.Point({ x: radius, y: height - radius }), radius);
|
||||
builder.add_circle(new Graphene.Point({ x: width - radius, y: height - radius }), radius);
|
||||
builder.add_rect(
|
||||
new Graphene.Rect({
|
||||
origin: new Graphene.Point({ x: radius, y: 0 }),
|
||||
size: new Graphene.Size({ width: width - 2 * radius, height }),
|
||||
}),
|
||||
);
|
||||
builder.add_rect(
|
||||
new Graphene.Rect({
|
||||
origin: new Graphene.Point({ x: 0, y: radius }),
|
||||
size: new Graphene.Size({ width, height: height - 2 * radius }),
|
||||
}),
|
||||
);
|
||||
return builder.to_path();
|
||||
}
|
||||
@@ -3,9 +3,9 @@
|
||||
|
||||
import Adw from "gi://Adw";
|
||||
import Gdk from "gi://Gdk";
|
||||
import GdkPixbuf from "gi://GdkPixbuf";
|
||||
import Gio from "gi://Gio";
|
||||
import GLib from "gi://GLib";
|
||||
import Gly from "gi://Gly";
|
||||
import GObject from "gi://GObject";
|
||||
import Gtk from "gi://Gtk";
|
||||
|
||||
@@ -14,34 +14,14 @@ import { gettext as _ } from "resource:///org/gnome/Shell/Extensions/js/extensio
|
||||
Gio._promisify(Gtk.FileDialog.prototype, "open", "open_finish");
|
||||
|
||||
export class BackgroundButton extends Gtk.Button {
|
||||
#uri;
|
||||
|
||||
static {
|
||||
GObject.registerClass(
|
||||
{
|
||||
GTypeName: "BackgroundButton",
|
||||
Template: "resource:///org/gnome/Shell/Extensions/nightthemeswitcher/preferences/ui/BackgroundButton.ui",
|
||||
InternalChildren: ["file_dialog", "thumbnail"],
|
||||
InternalChildren: ["file_dialog"],
|
||||
Properties: {
|
||||
uri: GObject.ParamSpec.string("uri", "URI", "URI to the background file", GObject.ParamFlags.READWRITE, null),
|
||||
thumbWidth: GObject.ParamSpec.int(
|
||||
"thumb-width",
|
||||
"Thumbnail width",
|
||||
"Width of the displayed thumbnail",
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0,
|
||||
600,
|
||||
180,
|
||||
),
|
||||
thumbHeight: GObject.ParamSpec.int(
|
||||
"thumb-height",
|
||||
"Thumbnail height",
|
||||
"Height of the displayed thumbnail",
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0,
|
||||
600,
|
||||
180,
|
||||
),
|
||||
},
|
||||
},
|
||||
this,
|
||||
@@ -50,33 +30,10 @@ export class BackgroundButton extends Gtk.Button {
|
||||
|
||||
constructor({ ...params } = {}) {
|
||||
super(params);
|
||||
this.#setupSize();
|
||||
this.#setupDropTarget();
|
||||
this.#setupFileDialog();
|
||||
}
|
||||
|
||||
get uri() {
|
||||
return this.#uri || null;
|
||||
}
|
||||
|
||||
set uri(uri) {
|
||||
if (uri === this.#uri) return;
|
||||
this.#uri = uri;
|
||||
this.notify("uri");
|
||||
GLib.idle_add(GLib.PRIORITY_DEFAULT_IDLE, () => {
|
||||
this.#updateThumbnail();
|
||||
return GLib.SOURCE_REMOVE;
|
||||
});
|
||||
}
|
||||
|
||||
#setupSize() {
|
||||
const display = Gdk.Display.get_default();
|
||||
const monitor = display.get_monitors().get_item(0);
|
||||
if (monitor.width_mm === 0 || monitor.height_mm === 0) return;
|
||||
if (monitor.width_mm > monitor.height_mm) this.thumbHeight *= monitor.height_mm / monitor.width_mm;
|
||||
else this.thumbWidth *= monitor.width_mm / monitor.height_mm;
|
||||
}
|
||||
|
||||
#setupDropTarget() {
|
||||
const dropTarget = Gtk.DropTarget.new(Gio.File.$gtype, Gdk.DragAction.COPY);
|
||||
dropTarget.connect("drop", (_target, file, _x, _y) => {
|
||||
@@ -108,9 +65,7 @@ export class BackgroundButton extends Gtk.Button {
|
||||
}
|
||||
|
||||
#getSupportedContentTypes() {
|
||||
return GdkPixbuf.Pixbuf.get_formats()
|
||||
.flatMap((format) => format.get_mime_types())
|
||||
.concat("application/xml");
|
||||
return Gly.Loader.get_mime_types().concat("application/xml");
|
||||
}
|
||||
|
||||
#isContentTypeSupported(contentType) {
|
||||
@@ -130,61 +85,13 @@ export class BackgroundButton extends Gtk.Button {
|
||||
|
||||
async #setURIFromFileDialog() {
|
||||
try {
|
||||
this._file_dialog.initial_folder = Gio.File.new_for_uri(this.uri).get_parent();
|
||||
const file = await this._file_dialog.open(this.get_root(), null);
|
||||
this.uri = file.get_uri();
|
||||
} catch {}
|
||||
}
|
||||
|
||||
#updateThumbnail() {
|
||||
this._thumbnail.paintable = null;
|
||||
|
||||
if (!this.uri) return;
|
||||
|
||||
const file = Gio.File.new_for_uri(this.uri);
|
||||
const contentType = Gio.content_type_guess(file.get_basename(), null)[0];
|
||||
|
||||
if (!this.#isContentTypeSupported(contentType)) return;
|
||||
|
||||
let path;
|
||||
if (Gio.content_type_equals(contentType, "application/xml")) {
|
||||
const decoder = new TextDecoder("utf-8");
|
||||
const contents = decoder.decode(file.load_contents(null)[1]);
|
||||
try {
|
||||
path = contents.match(/<file>(.+)<\/file>/m)[1];
|
||||
if (!this.#isContentTypeSupported(Gio.content_type_guess(path, null)[0])) throw new Error();
|
||||
} catch (e) {
|
||||
console.error(`No suitable background file found in ${file.get_path()}.\n${e}`);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
path = file.get_path();
|
||||
}
|
||||
|
||||
const pixbuf = GdkPixbuf.Pixbuf.new_from_file(path);
|
||||
const scale =
|
||||
pixbuf.width / pixbuf.height > this.thumbWidth / this.thumbHeight
|
||||
? this.thumbHeight / pixbuf.height
|
||||
: this.thumbWidth / pixbuf.width;
|
||||
const thumbPixbuf = GdkPixbuf.Pixbuf.new(
|
||||
pixbuf.colorspace,
|
||||
pixbuf.has_alpha,
|
||||
pixbuf.bits_per_sample,
|
||||
this.thumbWidth,
|
||||
this.thumbHeight,
|
||||
);
|
||||
pixbuf.scale(
|
||||
thumbPixbuf,
|
||||
0,
|
||||
0,
|
||||
this.thumbWidth,
|
||||
this.thumbHeight,
|
||||
-(pixbuf.width * scale - this.thumbWidth) / 2,
|
||||
-(pixbuf.height * scale - this.thumbHeight) / 2,
|
||||
scale,
|
||||
scale,
|
||||
GdkPixbuf.InterpType.TILES,
|
||||
);
|
||||
|
||||
this._thumbnail.paintable = Gdk.Texture.new_for_pixbuf(thumbPixbuf);
|
||||
_getBackgroundFileName(_widget, uri) {
|
||||
return uri ? GLib.filename_display_basename(uri) : "";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
// SPDX-FileCopyrightText: Night Theme Switcher Contributors
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
import GObject from "gi://GObject";
|
||||
import Gtk from "gi://Gtk";
|
||||
|
||||
import { gettext as _ } from "resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js";
|
||||
|
||||
import { AccentColor } from "../enums/AccentColor.js";
|
||||
|
||||
export class ColorChooser extends Gtk.Widget {
|
||||
/** @type {Gtk.ToggleButton[]} */
|
||||
#buttons = [];
|
||||
|
||||
/** @type {AccentColor} */
|
||||
#activeColor;
|
||||
|
||||
static {
|
||||
GObject.registerClass(
|
||||
{
|
||||
GTypeName: "ColorChooser",
|
||||
CssName: "color-chooser",
|
||||
Properties: {
|
||||
color: GObject.ParamSpec.string(
|
||||
"active-color",
|
||||
"Active color",
|
||||
"Active color",
|
||||
GObject.ParamFlags.READWRITE,
|
||||
null,
|
||||
),
|
||||
},
|
||||
},
|
||||
this,
|
||||
);
|
||||
}
|
||||
|
||||
constructor({ ...params } = {}) {
|
||||
super({ layoutManager: new Gtk.BoxLayout({ spacing: 6 }), ...params });
|
||||
|
||||
const colors = [
|
||||
{ accentColor: AccentColor.BLUE, name: _("Blue") },
|
||||
{ accentColor: AccentColor.TEAL, name: _("Teal") },
|
||||
{ accentColor: AccentColor.GREEN, name: _("Green") },
|
||||
{ accentColor: AccentColor.YELLOW, name: _("Yellow") },
|
||||
{ accentColor: AccentColor.ORANGE, name: _("Orange") },
|
||||
{ accentColor: AccentColor.RED, name: _("Red") },
|
||||
{ accentColor: AccentColor.PINK, name: _("Pink") },
|
||||
{ accentColor: AccentColor.PURPLE, name: _("Purple") },
|
||||
{ accentColor: AccentColor.SLATE, name: _("Slate") },
|
||||
];
|
||||
|
||||
let toggleGroup;
|
||||
for (const color of colors) {
|
||||
const button = new Gtk.ToggleButton({
|
||||
tooltipText: color.name,
|
||||
cssClasses: ["circular", color.accentColor],
|
||||
active: this.activeColor === color.accentColor,
|
||||
});
|
||||
|
||||
if (!toggleGroup) toggleGroup = button;
|
||||
else button.group = toggleGroup;
|
||||
|
||||
button.connect("toggled", () => {
|
||||
if (!button.active) return;
|
||||
this.activeColor = color.accentColor;
|
||||
});
|
||||
|
||||
this.#buttons.push(button);
|
||||
|
||||
button.set_parent(this);
|
||||
}
|
||||
}
|
||||
|
||||
get activeColor() {
|
||||
return this.#activeColor;
|
||||
}
|
||||
|
||||
set activeColor(color) {
|
||||
if (!color || color === this.#activeColor || !Object.values(AccentColor).includes(color)) return;
|
||||
this.#activeColor = color;
|
||||
this.notify("active-color");
|
||||
this.#updateButtons();
|
||||
}
|
||||
|
||||
#updateButtons() {
|
||||
this.#buttons.forEach((button) => {
|
||||
button.active = button.cssClasses.includes(this.activeColor);
|
||||
});
|
||||
}
|
||||
}
|
||||
+22
-3
@@ -21,17 +21,30 @@ export default class NightThemeSwitcherPreferences extends ExtensionPreferences
|
||||
const resource = Gio.Resource.load(GLib.build_filenamev([this.path, "resources", "preferences.gresource"]));
|
||||
Gio.resources_register(resource);
|
||||
|
||||
// Load stylesheet
|
||||
const provider = new Gtk.CssProvider();
|
||||
provider.load_from_resource("/org/gnome/Shell/Extensions/nightthemeswitcher/preferences/style.css");
|
||||
Gtk.StyleContext.add_provider_for_display(
|
||||
Gdk.Display.get_default(),
|
||||
provider,
|
||||
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION,
|
||||
);
|
||||
|
||||
// Load icons
|
||||
const iconTheme = Gtk.IconTheme.get_for_display(Gdk.Display.get_default());
|
||||
iconTheme.add_resource_path("/org/gnome/Shell/Extensions/nightthemeswitcher/preferences/icons");
|
||||
|
||||
// Set window properties
|
||||
window.search_enabled = true;
|
||||
window.set_size_request(420, 320);
|
||||
window.set_default_size(500, 630);
|
||||
|
||||
// Dynamically import all classes
|
||||
const { BackgroundButton } = await import("./preferences/BackgroundButton.js");
|
||||
const { AppearanceChooser } = await import("./preferences/AppearanceChooser.js");
|
||||
const { AppearancePage } = await import("./preferences/AppearancePage.js");
|
||||
const { AppearancePreview } = await import("./preferences/AppearancePreview.js");
|
||||
const { BackgroundButton } = await import("./preferences/BackgroundButton.js");
|
||||
const { ColorChooser } = await import("./preferences/ColorChooser.js");
|
||||
const { CommandsPage } = await import("./preferences/CommandsPage.js");
|
||||
const { ContributePage } = await import("./preferences/ContributePage.js");
|
||||
const { SchedulePage } = await import("./preferences/SchedulePage.js");
|
||||
@@ -39,8 +52,11 @@ export default class NightThemeSwitcherPreferences extends ExtensionPreferences
|
||||
const { TimeChooser } = await import("./preferences/TimeChooser.js");
|
||||
|
||||
// Make sure all GObjects are registered
|
||||
GObject.type_ensure(BackgroundButton);
|
||||
GObject.type_ensure(AppearanceChooser);
|
||||
GObject.type_ensure(AppearancePage);
|
||||
GObject.type_ensure(AppearancePreview);
|
||||
GObject.type_ensure(BackgroundButton);
|
||||
GObject.type_ensure(ColorChooser);
|
||||
GObject.type_ensure(CommandsPage);
|
||||
GObject.type_ensure(ContributePage);
|
||||
GObject.type_ensure(SchedulePage);
|
||||
@@ -50,7 +66,10 @@ export default class NightThemeSwitcherPreferences extends ExtensionPreferences
|
||||
// Add all pages
|
||||
[
|
||||
new SchedulePage({ settings: this.getSettings(`${this.metadata["settings-schema"]}.time`) }),
|
||||
new AppearancePage(),
|
||||
new AppearancePage({
|
||||
accentColorSettings: this.getSettings(`${this.metadata["settings-schema"]}.accent-color`),
|
||||
colorSchemeSettings: this.getSettings(`${this.metadata["settings-schema"]}.color-scheme`),
|
||||
}),
|
||||
new CommandsPage({ settings: this.getSettings(`${this.metadata["settings-schema"]}.commands`) }),
|
||||
new ContributePage(),
|
||||
].forEach((page) => window.add(page));
|
||||
|
||||
Reference in New Issue
Block a user