Forcing The Dark Color Scheme
GNOME applications will respect the system setting for the light or dark theme. It is possible, however, to present the choice of forcing the dark theme to the user in your application’s UI.
Add the “Dark Mode” item to the application’s menu
- Open the UI definition file for the
Text::Viewer::Window
widget - Add a menu item for the
app.dark
action, calledDark Mode
xml
<menu id="primary_menu">
<section>
<item>
<attribute name="label" translatable="yes">Save _as...</attribute>
<attribute name="action">win.save-as</attribute>
</item>
<item>
<attribute name="label" translatable="yes">_Dark mode</attribute>
<attribute name="action">app.dark-mode</attribute>
</item>
Add the dark mode action to the application
- Open the
Text::View::App
source - Find the
Text::View::App
class constructor - Create the
dark-mode
stateful action and connect to itsactivate
andchange-state
signals - Add the action to the application
crystal
def initialize
super(application_id: "com.example.TextViewer", flags: Gio::ApplicationFlags::DefaultFlags)
#...
dark_mode_action = Gio::SimpleAction.new_stateful("dark-mode", nil, GLib::Variant.new(false))
dark_mode_action.activate_signal.connect do
end
dark_mode_action.change_state_signal.connect do |new_state|
end
#...
self.add_action dark_mode_action
end
- Add the
activate_signal
callback; this callback toggles the state of thedark-mode
action betweentrue
andfalse
crystal
dark_mode_action = Gio::SimpleAction.new_stateful("dark-mode", nil, GLib::Variant.new(false))
dark_mode_action.activate_signal.connect do
state = dark_mode_action.state
old_state = state.nil? ? false : state.as_bool
new_state = !old_state
dark_mode_action.change_state(GLib::Variant.new(new_state))
end
dark_mode_action.change_state_signal.connect do |new_state|
end
- Add the
change_state_signal
callback; this callback is responsible for switching the application’s color scheme using theAdw::StyleManager
API
crystal
dark_mode_action = Gio::SimpleAction.new_stateful("dark-mode", nil, GLib::Variant.new(false))
dark_mode_action.activate_signal.connect do
state = dark_mode_action.state
old_state = state.nil? ? false : state.as_bool
new_state = !old_state
dark_mode_action.change_state(GLib::Variant.new(new_state))
end
dark_mode_action.change_state_signal.connect do |new_state|
dark_mode = new_state.nil? ? false : new_state.as_bool
style_manager = Adw::StyleManager.default
style_manager.color_scheme = dark_mode ? Adw::ColorScheme::ForceDark : Adw::ColorScheme::Default
dark_mode_action.state = new_state
end
Store the dark mode state as a setting
If you want to preserve the chosen color scheme across sessions you can store it inside GSettings, which you added in Saving The Application State.
Add a new key to the settings schema
- Open the
com.example.TextViewer.gschema.xml
file - Add a
dark-mode
boolean key
xml
<?xml version="1.0" encoding="UTF-8"?>
<schemalist gettext-domain="text-viewer">
<schema id="com.example.TextViewer" path="/com/example/TextViewer/">
<key name="window-width" type="i">
<default>600</default>
</key>
<key name="window-height" type="i">
<default>400</default>
</key>
<key name="window-maximized" type="b">
<default>false</default>
</key>
<key name="dark-mode" type="b">
<default>false</default>
</key>
</schema>
</schemalist>
WARNING
You'll need to re-install and compile the schema.
Add GSettings to the application
Add a Gio::Settings
instance to your Text::Viewer::App
class
crystal
class App < Adw::Application
@settings : Gio::Settings
def initialize
super(application_id: "com.example.TextViewer", flags: Gio::ApplicationFlags::DefaultFlags)
@settings = Gio::Settings.new("com.example.TextViewer")
Set the initial state for the color scheme
- Retrieve the value of the
dark-mode
GSettings key - Set the color scheme using the key’s value
- Initialize the state of the
dark-mode
action with the key’s value
crystal
class App < Adw::Application
@settings : Gio::Settings
def initialize
super(application_id: "com.example.TextViewer", flags: Gio::ApplicationFlags::DefaultFlags)
@settings = Gio::Settings.new("com.example.TextViewer")
#...
dark_mode = @settings.boolean("dark-mode");
style_manager = Adw::StyleManager.default
style_manager.color_scheme = dark_mode ? Adw::ColorScheme::ForceDark : Adw::ColorScheme::Default
dark_mode_action = Gio::SimpleAction.new_stateful("dark-mode", nil, GLib::Variant.new(dark_mode))
#...
Save the color scheme when it changes
Update the dark-mode
GSettings key using the state of the dark-mode
action whenever it changes.
crystal
dark_mode_action.change_state_signal.connect do |new_state|
dark_mode = new_state.nil? ? false : new_state.as_bool
style_manager = Adw::StyleManager.default
style_manager.color_scheme = dark_mode ? Adw::ColorScheme::ForceDark : Adw::ColorScheme::Default
dark_mode_action.state = new_state
@settings.set_boolean("dark-mode", dark_mode)
end
In this lesson you have learned how to force the dark color scheme for your application, and storing it as an application preference.