diff --git a/.github/workflows/flatpak.yml b/.github/workflows/flatpak.yml index 373c784..49a831e 100644 --- a/.github/workflows/flatpak.yml +++ b/.github/workflows/flatpak.yml @@ -23,3 +23,16 @@ jobs: bundle: com.cassidyjames.butler.Devel.flatpak manifest-path: com.cassidyjames.butler.Devel.json cache-key: "flatpak-builder-${{ github.sha }}" + flatpak-release: + name: Flatpak (Release) + runs-on: ubuntu-latest + container: + image: ghcr.io/flathub-infra/flatpak-github-actions:gnome-46 + options: --privileged + steps: + - uses: actions/checkout@v4 + - uses: flathub-infra/flatpak-github-actions/flatpak-builder@master + with: + bundle: com.cassidyjames.butler.flatpak + manifest-path: com.cassidyjames.butler.json + cache-key: "flatpak-builder-${{ github.sha }}" diff --git a/com.cassidyjames.butler.Devel.json b/com.cassidyjames.butler.Devel.json index 1aefb83..92347b0 100644 --- a/com.cassidyjames.butler.Devel.json +++ b/com.cassidyjames.butler.Devel.json @@ -1,7 +1,7 @@ { "app-id": "com.cassidyjames.butler.Devel", "runtime": "org.gnome.Platform", - "runtime-version": "46", + "runtime-version": "47", "sdk": "org.gnome.Sdk", "command": "com.cassidyjames.butler.Devel", "finish-args": [ diff --git a/com.cassidyjames.butler.json b/com.cassidyjames.butler.json index fec1243..395d7b3 100644 --- a/com.cassidyjames.butler.json +++ b/com.cassidyjames.butler.json @@ -1,7 +1,7 @@ { "app-id": "com.cassidyjames.butler", "runtime": "org.gnome.Platform", - "runtime-version": "46", + "runtime-version": "47", "sdk": "org.gnome.Sdk", "command": "com.cassidyjames.butler", "finish-args": [ diff --git a/data/gresource.xml b/data/gresource.xml index ca7363b..2c558eb 100644 --- a/data/gresource.xml +++ b/data/gresource.xml @@ -6,5 +6,7 @@ style-dark.css style.css style-dark.css + icons/step-back-symbolic.svg + icons/step-back-symbolic.svg diff --git a/data/gschema.xml.in b/data/gschema.xml.in index 5d93032..aa5e84c 100644 --- a/data/gschema.xml.in +++ b/data/gschema.xml.in @@ -7,7 +7,7 @@ The last-viewed URL for restoring state - ("#03a9f5", "#03a9f5") + ("#03a9f5", "#101e24") Headerbar Colors 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 diff --git a/data/icons/step-back-symbolic.svg b/data/icons/step-back-symbolic.svg new file mode 100644 index 0000000..b56f807 --- /dev/null +++ b/data/icons/step-back-symbolic.svg @@ -0,0 +1,2 @@ + + diff --git a/data/metainfo.xml.in b/data/metainfo.xml.in index d2cea0f..6ca4207 100644 --- a/data/metainfo.xml.in +++ b/data/metainfo.xml.in @@ -53,16 +53,35 @@ - https://raw.githubusercontent.com/cassidyjames/butler/518b5c81e35d366fa6ea62d4835d8e9a61e039e1/data/screenshots/light.png + https://raw.githubusercontent.com/cassidyjames/butler/3c3c6f7182049db184e6f7533326d5240ea3bdfc/data/screenshots/light.png Home Assistant dashboard with many rooms and devices - https://raw.githubusercontent.com/cassidyjames/butler/518b5c81e35d366fa6ea62d4835d8e9a61e039e1/data/screenshots/dark.png + https://raw.githubusercontent.com/cassidyjames/butler/3c3c6f7182049db184e6f7533326d5240ea3bdfc/data/screenshots/light-settings.png + Available settings, including server URL and custom header colors + + + https://raw.githubusercontent.com/cassidyjames/butler/3c3c6f7182049db184e6f7533326d5240ea3bdfc/data/screenshots/dark.png Home Assistant dashboard in dark style + + https://raw.githubusercontent.com/cassidyjames/butler/3c3c6f7182049db184e6f7533326d5240ea3bdfc/data/screenshots/dark-settings.png + Available settings in dark style + + + +

GNOME 47 “Denver”

+
    +
  • Updated with the latest GNOME 47 platform and design
  • +
  • Matched the default dark header color to the Home Assistant dark theme
  • +
  • Reworked adaptive “Settings” dialog with individually-resettable options
  • +
  • Improved reliability of saving server URLs
  • +
+
+

The Rise of Settings

diff --git a/data/screenshots/dark-settings.png b/data/screenshots/dark-settings.png new file mode 100644 index 0000000..8c6f7fd Binary files /dev/null and b/data/screenshots/dark-settings.png differ diff --git a/data/screenshots/dark.png b/data/screenshots/dark.png index c92e067..0567035 100644 Binary files a/data/screenshots/dark.png and b/data/screenshots/dark.png differ diff --git a/data/screenshots/light-settings.png b/data/screenshots/light-settings.png new file mode 100644 index 0000000..2dae990 Binary files /dev/null and b/data/screenshots/light-settings.png differ diff --git a/data/screenshots/light.png b/data/screenshots/light.png index c2f3c14..747b457 100644 Binary files a/data/screenshots/light.png and b/data/screenshots/light.png differ diff --git a/meson.build b/meson.build index 0803b65..235f949 100644 --- a/meson.build +++ b/meson.build @@ -1,8 +1,8 @@ project( 'com.cassidyjames.butler', 'vala', 'c', - version: '1.2.0', - meson_version: '>=1.1', + version: '1.3.0', + meson_version: '>=1.5.1', ) app_id = meson.project_name() diff --git a/src/MainWindow.vala b/src/MainWindow.vala index b10f990..c29c5a5 100644 --- a/src/MainWindow.vala +++ b/src/MainWindow.vala @@ -4,13 +4,6 @@ */ public class Butler.MainWindow : Adw.ApplicationWindow { - public Adw.AboutDialog about_dialog; - public Adw.Banner demo_banner; - public Adw.Toast fullscreen_toast; - public Adw.ToastOverlay toast_overlay; - public Gtk.Revealer header_revealer; - public Gtk.Revealer home_revealer; - private const GLib.ActionEntry[] ACTION_ENTRIES = { { "toggle_fullscreen", toggle_fullscreen }, { "settings", on_settings_activate }, @@ -18,7 +11,15 @@ public class Butler.MainWindow : Adw.ApplicationWindow { { "about", on_about_activate }, }; + private Adw.Banner demo_banner; + private Adw.Toast fullscreen_toast; + private Adw.ToastOverlay toast_overlay; + private Gtk.Revealer header_revealer; + private Gtk.Revealer home_revealer; + private Adw.AboutDialog about_dialog; private Butler.WebView web_view; + private Gtk.ColorDialogButton color_light_button; + private Gtk.ColorDialogButton color_dark_button; private const string CSS = """ @define-color headerbar_bg_light %s; @@ -81,7 +82,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 (_("_Server Settings"), "win.settings"); + app_menu.append (_("_Settings"), "win.settings"); app_menu.append (_("_About %s").printf (APP_NAME), "win.about"); var menu = new Menu (); @@ -171,10 +172,6 @@ public class Butler.MainWindow : Adw.ApplicationWindow { web_view.load_changed.connect ((load_event) => { if (load_event == WebKit.LoadEvent.FINISHED) { - // NOTE: As of WebKitGTK in the GNOME 46 SDK, this seems - // glitchier… not sure how to fix it. A GLib.Timeout doesn't - // seem to help, as it just looks glitchy after the stack child - // changes to the WebView. stack.visible_child_name = "web"; } }); @@ -242,6 +239,8 @@ public class Butler.MainWindow : Adw.ApplicationWindow { } else if (current_url.has_prefix (server)) { demo_banner.revealed = false; } else { + // Somehow you got away from the server without opening a link + // in the browser… demo_banner.revealed = false; home_revealer.set_reveal_child (true); } @@ -282,8 +281,6 @@ public class Butler.MainWindow : Adw.ApplicationWindow { } private void log_out () { - // Home Assistant doesn't use cookies for login; clear ALL to include - // local storage and cache web_view.network_session.get_website_data_manager ().clear.begin ( WebKit.WebsiteDataTypes.ALL, 0, null, () => { debug ("Cleared data; going home."); @@ -317,19 +314,28 @@ public class Butler.MainWindow : Adw.ApplicationWindow { var current_rgba_dark = Gdk.RGBA (); current_rgba_dark.parse (current_color_dark); + var server_reset_button = new Gtk.Button.from_icon_name ("step-back-symbolic") { + tooltip_text = _("Reset to Demo"), + valign = Gtk.Align.CENTER, + }; + server_reset_button.add_css_class ("flat"); + var server_entry = new Adw.EntryRow () { activates_default = true, + input_purpose = Gtk.InputPurpose.URL, + show_apply_button = true, text = current_server, title = _("Server URL"), }; + server_entry.add_suffix (server_reset_button); var server_group = new Adw.PreferencesGroup () { - title = _("Server Settings"), + title = _("Server"), description = _("Enter the full URL including any custom port"), }; server_group.add (server_entry); - var color_light_button = new Gtk.ColorDialogButton (new Gtk.ColorDialog ()) { + color_light_button = new Gtk.ColorDialogButton (new Gtk.ColorDialog ()) { rgba = current_rgba_light, valign = Gtk.Align.CENTER, }; @@ -341,7 +347,7 @@ public class Butler.MainWindow : Adw.ApplicationWindow { }; color_light_row.add_suffix (color_light_button); - var color_dark_button = new Gtk.ColorDialogButton (new Gtk.ColorDialog ()) { + color_dark_button = new Gtk.ColorDialogButton (new Gtk.ColorDialog ()) { rgba = current_rgba_dark, valign = Gtk.Align.CENTER, }; @@ -353,80 +359,84 @@ public class Butler.MainWindow : Adw.ApplicationWindow { }; color_dark_row.add_suffix (color_dark_button); - var colors_group = new Adw.PreferencesGroup () { - title = _("Header Bar Color"), + var color_reset_button = new Gtk.Button.from_icon_name ("step-back-symbolic") { + tooltip_text = _("Reset to Default"), + valign = Gtk.Align.CENTER, + }; + color_reset_button.add_css_class ("flat"); + + var color_group = new Adw.PreferencesGroup () { + title = _("Header Colors"), description = _("Better match your dashboard"), }; - colors_group.add (color_light_row); - colors_group.add (color_dark_row); + color_group.add (color_light_row); + color_group.add (color_dark_row); + color_group.set_header_suffix (color_reset_button); - var settings_box = new Gtk.Box (Gtk.Orientation.VERTICAL, 24); - settings_box.append (server_group); - settings_box.append (colors_group); + var settings_page = new Adw.PreferencesPage (); + settings_page.add (server_group); + settings_page.add (color_group); - var settings_dialog = new Adw.AlertDialog (null, null) { - body_use_markup = true, - default_response = "save", - extra_child = settings_box, + var settings_dialog = new Adw.PreferencesDialog () { + content_width = 480, + title = _("Settings"), }; - settings_dialog.add_response ("close", _("_Cancel")); + settings_dialog.add (settings_page); - settings_dialog.add_response ("reset", _("_Reset to Default")); - settings_dialog.set_response_appearance ("reset", Adw.ResponseAppearance.DESTRUCTIVE); + settings_dialog.present (this); - settings_dialog.add_response ("save", _("_Save")); - settings_dialog.set_response_appearance ("save", Adw.ResponseAppearance.SUGGESTED); + server_entry.apply.connect (() => { + string new_server = server_entry.text.strip (); - settings_dialog.present (this); + if (new_server == "") { + new_server = default_server; + } - 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); - - log_out (); - break; - - case "close": - default: - break; + 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 (); } }); + + server_reset_button.clicked.connect (() => { + server_entry.text = default_server; + server_entry.apply (); + }); + + color_reset_button.clicked.connect (() => { + string light, dark; + + App.settings.reset ("headerbar-colors"); + App.settings.get ("headerbar-colors", "(ss)", out light, out dark); + + var light_rgba = Gdk.RGBA (); + light_rgba.parse (light); + + var dark_rgba = Gdk.RGBA (); + dark_rgba.parse (dark); + + color_light_button.rgba = light_rgba; + color_dark_button.rgba = dark_rgba; + }); + + color_light_button.notify["rgba"].connect (on_color_button_change); + color_dark_button.notify["rgba"].connect (on_color_button_change); + } + + private void on_color_button_change () { + string light = color_light_button.get_rgba ().to_string (); + string dark = color_dark_button.get_rgba ().to_string (); + + App.settings.set ( + "headerbar-colors", "(ss)", light, dark + ); + + update_headerbar_colors (light, dark); } private void on_log_out_activate () { @@ -434,10 +444,11 @@ public class Butler.MainWindow : Adw.ApplicationWindow { var log_out_dialog = new Adw.AlertDialog ( _("Log out of Home Assistant?"), - _("You will need to re-enter your username and password for %s to log back in.").printf (server) + _("You will need to re-enter any username and password required to log back in to %s.").printf (server) ) { body_use_markup = true, - default_response = "log_out" + default_response = "log_out", + prefer_wide_layout = true, }; log_out_dialog.add_response ("close", _("_Stay Logged In")); log_out_dialog.add_response ("log_out", _("_Log Out")); diff --git a/src/meson.build b/src/meson.build index 9836eae..3429297 100644 --- a/src/meson.build +++ b/src/meson.build @@ -8,10 +8,10 @@ executable( config_file, include_directories: config_include, dependencies: [ - dependency('glib-2.0'), - dependency('gtk4'), - dependency('libadwaita-1', version: '>=1.5'), - dependency('webkitgtk-6.0'), + dependency('glib-2.0', version: '>=2.82.0'), + dependency('gtk4', version: '>=4.16.1'), + dependency('libadwaita-1', version: '>=1.6.0'), + dependency('webkitgtk-6.0', version: '>=2.46.0'), meson.get_compiler('c').find_library('m'), # GLib.Math meson.get_compiler('vala').find_library('posix'), ],