Skip to content

Commit

Permalink
MainWindow: add light/dark headerbar colors (#45)
Browse files Browse the repository at this point in the history
* MainWindow: add light/dark headerbar colors

* MainWindow: fix loading title

* Metainfo: update release notes
  • Loading branch information
cassidyjames authored Aug 28, 2024
1 parent cd66fe6 commit 6b71a7a
Show file tree
Hide file tree
Showing 8 changed files with 248 additions and 53 deletions.
1 change: 1 addition & 0 deletions data/gresource.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
<gresource prefix="/com/cassidyjames/butler/">
<file preprocess="xml-stripblanks" compressed="true">metainfo.xml.in</file>
<file alias="Devel/style.css">style.css</file>
<file alias="Devel/style-dark.css">style-dark.css</file>
</gresource>
</gresources>
5 changes: 5 additions & 0 deletions data/gschema.xml.in
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@
<summary>Current URL</summary>
<description>The last-viewed URL for restoring state</description>
</key>
<key name="headerbar-colors" type="(ss)">
<default>("#03a9f5", "#03a9f5")</default>
<summary>Headerbar Colors</summary>
<description>Colors for the header bar to better integrate into custom servers, stored as a (light, dark) pair to be used according to the system color scheme preference</description>
</key>
<key name="server" type="s">
<default>"https://demo.home-assistant.io/"</default>
<summary>Home Assistant server URL</summary>
Expand Down
5 changes: 5 additions & 0 deletions data/metainfo.xml.in
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@
<releases>
<release version="1.2.0" date="2024-08-27">
<description>
<p>The Rise of Settings</p>
<ul>
<li>New “Settings” dialog where you can set your server URL, and more…</li>
<li>New “Header Bar Color” setting where you can customize the background color of the top bar, including different colors for light and dark styles</li>
</ul>
<p>Under the hood</p>
<ul>
<li>Separate development and release profiles to make development easier</li>
Expand Down
2 changes: 2 additions & 0 deletions data/style-dark.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
@define-color headerbar_bg_color @headerbar_bg_dark;
@define-color headerbar_fg_color @headerbar_fg_dark;
12 changes: 7 additions & 5 deletions data/style.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
@define-color headerbar_bg_color #03a9f5;
@define-color headerbar_fg_color #fff;
@define-color headerbar_border_color #fff;
@define-color headerbar_backdrop_color mix(@headerbar_bg_color, @window_bg_color, 0.1);
@define-color ha_color #03a9f5;
@define-color accent_color @ha_color;

@define-color headerbar_bg_color @headerbar_bg_light;
@define-color headerbar_fg_color @headerbar_fg_light;

@define-color accent_color @headerbar_bg_color;
@define-color headerbar_border_color @headerbar_fg_color;
@define-color headerbar_backdrop_color mix(@headerbar_bg_color, @window_bg_color, 0.1);
203 changes: 155 additions & 48 deletions src/MainWindow.vala
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,22 @@ public class Butler.MainWindow : Adw.ApplicationWindow {

private const GLib.ActionEntry[] ACTION_ENTRIES = {
{ "toggle_fullscreen", toggle_fullscreen },
{ "set_server", on_set_server_activate },
{ "settings", on_settings_activate },
{ "log_out", on_log_out_activate },
{ "about", on_about_activate },
};

private Butler.WebView web_view;

private const string CSS = """
@define-color headerbar_bg_light %s;
@define-color headerbar_fg_light %s;
@define-color headerbar_bg_dark %s;
@define-color headerbar_fg_dark %s;
""";
private Gtk.CssProvider css_provider;

public MainWindow (Adw.Application app) {
Object (
application: app,
Expand All @@ -35,7 +44,7 @@ public class Butler.MainWindow : Adw.ApplicationWindow {
construct {
maximized = App.settings.get_boolean ("window-maximized");
fullscreened = App.settings.get_boolean ("window-fullscreened");
this.add_css_class (PROFILE);
add_css_class (PROFILE);

about_dialog = new Adw.AboutDialog.from_appdata (
"/com/cassidyjames/butler/metainfo.xml.in", VERSION
Expand All @@ -51,8 +60,7 @@ public class Butler.MainWindow : Adw.ApplicationWindow {
};
about_dialog.application_icon = APP_ID;
about_dialog.application_name = APP_NAME;
about_dialog.copyright = "© 2020–%i %s".printf (
new DateTime.now_local ().get_year (),
about_dialog.copyright = "© 2020–2024 %s".printf (
about_dialog.developer_name
);
about_dialog.add_link (_("About Home Assistant"), "https://www.home-assistant.io/");
Expand All @@ -73,7 +81,7 @@ public class Butler.MainWindow : Adw.ApplicationWindow {
var app_menu = new Menu ();
// TODO: How do I add shortcuts to the menu?
app_menu.append (_("_Fullscreen"), "win.toggle_fullscreen");
app_menu.append (_("Change _Server"), "win.set_server");
app_menu.append (_("_Server Settings"), "win.settings");
app_menu.append (_("_About %s").printf (APP_NAME), "win.about");

var menu = new Menu ();
Expand All @@ -96,8 +104,8 @@ public class Butler.MainWindow : Adw.ApplicationWindow {
};

demo_banner = new Adw.Banner (_("Browsing Home Assistant Demo")) {
action_name = "win.set_server",
button_label = _("Set _Server…")
action_name = "win.settings",
button_label = _("Change _Server…")
};

fullscreen_toast = new Adw.Toast (_("Press <b>Ctrl F</b> or <b>F11</b> to toggle fullscreen")) {
Expand All @@ -116,7 +124,7 @@ public class Butler.MainWindow : Adw.ApplicationWindow {
}

var status_page = new Adw.StatusPage () {
title = title,
title = APP_NAME,
description = _("Loading the dashboard…"),
icon_name = APP_ID
};
Expand All @@ -130,18 +138,20 @@ public class Butler.MainWindow : Adw.ApplicationWindow {
stack.add_named (status_page, "loading");
stack.add_named (web_view, "web");

string headerbar_color_light, headerbar_color_dark;
App.settings.get ("headerbar-colors", "(ss)", out headerbar_color_light, out headerbar_color_dark);
update_headerbar_colors (headerbar_color_light, headerbar_color_dark);

toast_overlay = new Adw.ToastOverlay () {
child = stack
};

var grid = new Gtk.Grid () {
orientation = Gtk.Orientation.VERTICAL
};
grid.attach (header_revealer, 0, 0);
grid.attach (toast_overlay, 0, 1);
grid.attach (demo_banner, 0, 2);
var box = new Gtk.Box (Gtk.Orientation.VERTICAL, 0);
box.append (header_revealer);
box.append (toast_overlay);
box.append (demo_banner);

set_content (grid);
set_content (box);

int window_width, window_height;
App.settings.get ("window-size", "(ii)", out window_width, out window_height);
Expand Down Expand Up @@ -177,6 +187,30 @@ public class Butler.MainWindow : Adw.ApplicationWindow {
App.settings.bind ("zoom", web_view, "zoom-level", SettingsBindFlags.DEFAULT);
}

private void update_headerbar_colors (string light, string dark) {
var light_rgba = Gdk.RGBA ();
light_rgba.parse (light);

var dark_rgba = Gdk.RGBA ();
dark_rgba.parse (dark);

css_provider = new Gtk.CssProvider ();

var css = CSS.printf (
light_rgba.to_string (),
contrasting_foreground_color (light_rgba).to_string (),
dark_rgba.to_string (),
contrasting_foreground_color (dark_rgba).to_string ()
);

css_provider.load_from_string (css);
Gtk.StyleContext.add_provider_for_display (
Gdk.Display.get_default (),
css_provider,
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION + 1
);
}

private void save_window_state () {
if (fullscreened) {
App.settings.set_boolean ("window-fullscreened", true);
Expand Down Expand Up @@ -270,54 +304,127 @@ public class Butler.MainWindow : Adw.ApplicationWindow {
}
}

private void on_set_server_activate () {
private void on_settings_activate () {
string current_server = App.settings.get_string ("server");
string default_server = App.settings.get_default_value ("server").get_string ();

var server_entry = new Gtk.Entry.with_buffer (new Gtk.EntryBuffer ((uint8[]) current_server)) {
string current_color_light, current_color_dark;
App.settings.get ("headerbar-colors", "(ss)", out current_color_light, out current_color_dark);

var current_rgba_light = Gdk.RGBA ();
current_rgba_light.parse (current_color_light);

var current_rgba_dark = Gdk.RGBA ();
current_rgba_dark.parse (current_color_dark);

var server_entry = new Adw.EntryRow () {
activates_default = true,
hexpand = true,
placeholder_text = default_server
text = current_server,
title = _("Server URL"),
};

var server_dialog = new Adw.AlertDialog (
_("Set Server URL"),
_("Enter the full URL including any custom port")
) {
body_use_markup = true,
default_response = "save",
extra_child = server_entry,
var server_group = new Adw.PreferencesGroup () {
title = _("Server Settings"),
description = _("Enter the full URL including any custom port"),
};
server_dialog.add_response ("close", _("_Cancel"));
server_group.add (server_entry);

server_dialog.add_response ("demo", _("_Reset to Demo"));
server_dialog.set_response_appearance ("demo", Adw.ResponseAppearance.DESTRUCTIVE);
var color_light_button = new Gtk.ColorDialogButton (new Gtk.ColorDialog ()) {
rgba = current_rgba_light,
valign = Gtk.Align.CENTER,
};

server_dialog.add_response ("save", _("_Set Server"));
server_dialog.set_response_appearance ("save", Adw.ResponseAppearance.SUGGESTED);
var color_light_row = new Adw.ActionRow () {
title = _("Light"),
subtitle = _("Used with default system style preference"),
activatable_widget = color_light_button,
};
color_light_row.add_suffix (color_light_button);

var color_dark_button = new Gtk.ColorDialogButton (new Gtk.ColorDialog ()) {
rgba = current_rgba_dark,
valign = Gtk.Align.CENTER,
};

server_dialog.present (this);
var color_dark_row = new Adw.ActionRow () {
title = _("Dark"),
subtitle = _("Used with dark system style preference"),
activatable_widget = color_dark_button,
};
color_dark_row.add_suffix (color_dark_button);

server_dialog.response.connect ((response_id) => {
if (response_id == "save") {
string new_server = server_entry.buffer.text;
var colors_group = new Adw.PreferencesGroup () {
title = _("Header Bar Color"),
description = _("Better match your dashboard"),
};
colors_group.add (color_light_row);
colors_group.add (color_dark_row);

if (new_server == "") {
new_server = default_server;
}
var settings_box = new Gtk.Box (Gtk.Orientation.VERTICAL, 24);
settings_box.append (server_group);
settings_box.append (colors_group);

if (!new_server.contains ("://")) {
new_server = "http://" + new_server;
}
var settings_dialog = new Adw.AlertDialog (null, null) {
body_use_markup = true,
default_response = "save",
extra_child = settings_box,
};
settings_dialog.add_response ("close", _("_Cancel"));

settings_dialog.add_response ("reset", _("_Reset to Default"));
settings_dialog.set_response_appearance ("reset", Adw.ResponseAppearance.DESTRUCTIVE);

settings_dialog.add_response ("save", _("_Save"));
settings_dialog.set_response_appearance ("save", Adw.ResponseAppearance.SUGGESTED);

settings_dialog.present (this);

settings_dialog.response.connect ((response_id) => {
switch (response_id) {
case "save":
string new_server = server_entry.text;
string new_color_light = color_light_button.get_rgba ().to_string ();
string new_color_dark = color_dark_button.get_rgba ().to_string ();

if (new_server == "") {
new_server = default_server;
}

if (!new_server.contains ("://")) {
new_server = "http://" + new_server;
}

if (new_server != current_server) {
// FIXME: There's currently no validation of this
App.settings.set_string ("server", new_server);
log_out ();
}

if (
new_color_light != current_color_light ||
new_color_dark != current_color_dark
) {
App.settings.set (
"headerbar-colors", "(ss)", new_color_light, new_color_dark
);
update_headerbar_colors (new_color_light, new_color_dark);
}
break;

case "reset":
App.settings.reset ("headerbar-colors");
App.settings.reset ("server");

string color_light, color_dark;
App.settings.get ("headerbar-colors", "(ss)", out color_light, out color_dark);
update_headerbar_colors (color_light, color_dark);

if (new_server != current_server) {
// FIXME: There's currently no validation of this
App.settings.set_string ("server", new_server);
log_out ();
}
} else if (response_id == "demo") {
App.settings.reset ("server");
log_out ();
break;

case "close":
default:
break;
}
});
}
Expand Down
Loading

0 comments on commit 6b71a7a

Please sign in to comment.