diff --git a/data/applications.gresource.xml b/data/applications.gresource.xml index 067e48d6..ce573071 100644 --- a/data/applications.gresource.xml +++ b/data/applications.gresource.xml @@ -2,5 +2,9 @@ background.svg + startup-32.svg + startup-32.svg + startup-48.svg + startup-48.svg diff --git a/data/startup-32.svg b/data/startup-32.svg new file mode 100644 index 00000000..036380f7 --- /dev/null +++ b/data/startup-32.svg @@ -0,0 +1,184 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/data/startup-48.svg b/data/startup-48.svg new file mode 100644 index 00000000..6c0afdb1 --- /dev/null +++ b/data/startup-48.svg @@ -0,0 +1,228 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/po/POTFILES b/po/POTFILES index ce3b6cc1..b99b6599 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -1,5 +1,5 @@ src/Plug.vala -src/Permissions/PermissionsPlug.vala +src/Sidebar.vala src/Permissions/Widgets/AppSettingsView.vala src/Permissions/Widgets/SidebarRow.vala src/Startup/Utils.vala diff --git a/src/Defaults/DefaultPlug.vala b/src/Defaults/DefaultPlug.vala index 47a8027c..88043058 100644 --- a/src/Defaults/DefaultPlug.vala +++ b/src/Defaults/DefaultPlug.vala @@ -6,7 +6,14 @@ * Chris Triantafillis */ -public class Defaults.Plug : Gtk.Box { +public class Defaults.Plug : Switchboard.SettingsPage { + public Plug () { + Object ( + title: _("Defaults"), + icon: new ThemedIcon ("preferences-system") + ); + } + construct { var browser_setting = new SettingsChild ( _("Web Browser"), @@ -65,19 +72,8 @@ public class Defaults.Plug : Gtk.Box { flowbox.append (videos_setting); flowbox.append (files_setting); - var clamp = new Adw.Clamp () { - child = flowbox, - margin_end = 12, - margin_bottom = 12, - margin_start = 12 - }; - - var scrolled_window = new Gtk.ScrolledWindow () { - child = clamp - }; - - append (scrolled_window); - + child = flowbox; + show_end_title_buttons = true; } private class SettingsChild : Gtk.FlowBoxChild { diff --git a/src/Permissions/Backend/App.vala b/src/Permissions/Backend/App.vala index a21efd09..b17b42be 100644 --- a/src/Permissions/Backend/App.vala +++ b/src/Permissions/Backend/App.vala @@ -29,12 +29,26 @@ public class Permissions.Backend.App : GLib.Object { public Icon icon { get; private set; } public GenericArray settings; + public static GLib.HashTable permission_names { get; private set; } + private const string GROUP = "Context"; public App (Flatpak.InstalledRef installed_ref) { Object (installed_ref: installed_ref); } + static construct { + permission_names = new GLib.HashTable (str_hash, str_equal); + permission_names["filesystems=home"] = _("Home Folder"); + permission_names["filesystems=host"] = _("System Folders"); + permission_names["devices=all"] = _("Devices"); + permission_names["shared=network"] = _("Network"); + permission_names["features=bluetooth"] = _("Bluetooth"); + permission_names["sockets=cups"] = _("Printing"); + permission_names["sockets=ssh-auth"] = _("Secure Shell Agent"); + permission_names["devices=dri"] = _("GPU Acceleration"); + } + construct { id = installed_ref.get_name (); @@ -99,7 +113,7 @@ public class Permissions.Backend.App : GLib.Object { current_permissions.add (permission); } - Plug.permission_names.foreach ((key) => { + permission_names.foreach ((key) => { bool standard = false; bool enabled = false; diff --git a/src/Permissions/PermissionsPlug.vala b/src/Permissions/PermissionsPlug.vala deleted file mode 100644 index c7eafad3..00000000 --- a/src/Permissions/PermissionsPlug.vala +++ /dev/null @@ -1,148 +0,0 @@ -/* -* Copyright 2020 elementary, Inc. (https://elementary.io) -* -* This program is free software; you can redistribute it and/or -* modify it under the terms of the GNU General Public -* License as published by the Free Software Foundation; either -* version 3 of the License, or (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* General Public License for more details. -* -* You should have received a copy of the GNU General Public -* License along with this program; if not, write to the -* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -* Boston, MA 02110-1301 USA -* -* Authored by: Marius Meisenzahl -*/ - -public class Permissions.Plug : Gtk.Box { - public static GLib.HashTable permission_names { get; private set; } - - private Gtk.SearchEntry search_entry; - private Gtk.ListBox app_list; - private Widgets.AppSettingsView app_settings_view; - - static construct { - permission_names = new GLib.HashTable (str_hash, str_equal); - permission_names["filesystems=home"] = _("Home Folder"); - permission_names["filesystems=host"] = _("System Folders"); - permission_names["devices=all"] = _("Devices"); - permission_names["shared=network"] = _("Network"); - permission_names["features=bluetooth"] = _("Bluetooth"); - permission_names["sockets=cups"] = _("Printing"); - permission_names["sockets=ssh-auth"] = _("Secure Shell Agent"); - permission_names["devices=dri"] = _("GPU Acceleration"); - } - - construct { - var placeholder = new Granite.Placeholder (_("No Flatpak apps installed")) { - icon = new ThemedIcon ("dialog-information"), - description = _("Apps whose permissions can be adjusted will automatically appear here when installed") - }; - placeholder.add_css_class (Granite.STYLE_CLASS_BACKGROUND); - - search_entry = new Gtk.SearchEntry () { - placeholder_text = _("Search Applications") - }; - - var alert_view = new Granite.Placeholder ("") { - icon = new ThemedIcon ("edit-find-symbolic"), - description = _("Try changing search terms.") - }; - - app_list = new Gtk.ListBox () { - vexpand = true, - selection_mode = Gtk.SelectionMode.SINGLE - }; - app_list.add_css_class (Granite.STYLE_CLASS_RICH_LIST); - app_list.set_placeholder (alert_view); - app_list.set_filter_func ((Gtk.ListBoxFilterFunc) filter_func); - app_list.set_sort_func ((Gtk.ListBoxSortFunc) sort_func); - app_list.update_property (Gtk.AccessibleProperty.LABEL, _("Applications"), -1); - - - var scrolled_window = new Gtk.ScrolledWindow () { - child = app_list - }; - - var frame = new Gtk.Frame (null) { - child = scrolled_window - }; - - var sidebar = new Gtk.Box (VERTICAL, 12) { - margin_bottom = 12, - margin_start = 12 - }; - sidebar.append (search_entry); - sidebar.append (frame); - - var app_manager = Permissions.Backend.AppManager.get_default (); - - app_manager.apps.foreach ((id, app) => { - var app_entry = new Permissions.SidebarRow (app); - app_list.append (app_entry); - }); - - app_settings_view = new Widgets.AppSettingsView (); - - var first_child = app_list.get_first_child (); - if (first_child != null && first_child is Gtk.ListBoxRow) { - var row = (Gtk.ListBoxRow) first_child; - - app_list.select_row (row); - show_row (row); - } - - var grid = new Gtk.Grid (); - grid.attach (sidebar, 0, 0, 1, 1); - grid.attach (app_settings_view, 1, 0, 2, 1); - - var placeholder_stack = new Gtk.Stack (); - placeholder_stack.add_child (placeholder); - placeholder_stack.add_child (grid); - - append (placeholder_stack); - - if (app_manager.apps.length > 0) { - placeholder_stack.set_visible_child (grid); - } else { - placeholder_stack.set_visible_child (placeholder); - } - - map.connect (() => search_entry.grab_focus ()); - search_entry.search_changed.connect (() => { - app_list.invalidate_filter (); - alert_view.title = _("No Results for ā€œ%sā€").printf (search_entry.text); - }); - - app_list.row_selected.connect (show_row); - } - - [CCode (instance_pos = -1)] - private bool filter_func (SidebarRow row) { - var should_show = search_entry.text.down ().strip () in row.app.name.down (); - - if (!should_show && app_list.get_selected_row () == row) { - app_list.select_row (null); - } - - return should_show; - } - - [CCode (instance_pos = -1)] - private int sort_func (SidebarRow row1, SidebarRow row2) { - return row1.app.name.collate (row2.app.name); - } - - private void show_row (Gtk.ListBoxRow? row) { - if (row == null || !(row is Permissions.SidebarRow)) { - app_settings_view.selected_app = null; - } else { - app_settings_view.selected_app = ((Permissions.SidebarRow)row).app; - } - } -} diff --git a/src/Permissions/Widgets/AppSettingsView.vala b/src/Permissions/Widgets/AppSettingsView.vala index d5583c30..76e7f6d9 100644 --- a/src/Permissions/Widgets/AppSettingsView.vala +++ b/src/Permissions/Widgets/AppSettingsView.vala @@ -74,6 +74,7 @@ public class Permissions.Widgets.AppSettingsView : Switchboard.SettingsPage { box.append (reset_button); child = box; + show_end_title_buttons = true; update_view (); @@ -147,7 +148,7 @@ public class Permissions.Widgets.AppSettingsView : Switchboard.SettingsPage { } var override_row = new PermissionSettingsWidget ( - Plug.permission_names[settings.context], + Backend.App.permission_names[settings.context], description, icon_name ); diff --git a/src/Permissions/Widgets/SidebarRow.vala b/src/Permissions/Widgets/SidebarRow.vala index 5aa183d2..81c3e8b1 100644 --- a/src/Permissions/Widgets/SidebarRow.vala +++ b/src/Permissions/Widgets/SidebarRow.vala @@ -74,7 +74,7 @@ public class Permissions.SidebarRow : Gtk.ListBoxRow { for (var i = 0; i < app.settings.length; i++) { var settings = app.settings.get (i); if (settings.enabled) { - current_permissions.add (Plug.permission_names[settings.context]); + current_permissions.add (Backend.App.permission_names[settings.context]); } } diff --git a/src/Plug.vala b/src/Plug.vala index e5c1db39..fa814005 100644 --- a/src/Plug.vala +++ b/src/Plug.vala @@ -20,15 +20,15 @@ * Marius Meisenzahl */ -public class ApplicationsPlug : Switchboard.Plug { - private const string DEFAULTS = "defaults"; - private const string STARTUP = "startup"; - private const string PERMISSIONS = "permissions"; +public class Applications.Plug : Switchboard.Plug { + public const string DEFAULTS = "preferences-system"; + public const string STARTUP = "preferences-desktop-startup"; + public const string PERMISSIONS = "permissions"; - private Gtk.Grid grid; + private Gtk.Paned paned; private Gtk.Stack stack; - public ApplicationsPlug () { + public Plug () { GLib.Intl.bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); GLib.Intl.bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); @@ -49,40 +49,26 @@ public class ApplicationsPlug : Switchboard.Plug { } public override Gtk.Widget get_widget () { - if (grid == null) { - stack = new Gtk.Stack () { - hexpand = true, - vexpand = true + if (paned == null) { + var app_settings_view = new Permissions.Widgets.AppSettingsView (); + + stack = new Gtk.Stack (); + stack.add_named (new Defaults.Plug (), DEFAULTS); + stack.add_named (new Startup.Plug (), STARTUP); + stack.add_named (app_settings_view, PERMISSIONS); + + var sidebar = new Sidebar (stack); + + paned = new Gtk.Paned (HORIZONTAL) { + start_child = sidebar, + end_child = stack, + shrink_start_child = false, + shrink_end_child = false, + resize_start_child = false }; - stack.add_titled (new Defaults.Plug (), DEFAULTS, _("Defaults")); - stack.add_titled (new Startup.Plug (), STARTUP, _("Startup")); - stack.add_titled (new Permissions.Plug (), PERMISSIONS, _("Permissions")); - - var stack_switcher = new Gtk.StackSwitcher () { - halign = Gtk.Align.CENTER, - stack = stack - }; - - var size_group = new Gtk.SizeGroup (Gtk.SizeGroupMode.HORIZONTAL); - var widget = stack_switcher.get_first_child (); - while (widget != null) { - size_group.add_widget (widget); - widget = widget.get_next_sibling (); - } - - var headerbar = new Adw.HeaderBar () { - title_widget = stack_switcher - }; - headerbar.add_css_class (Granite.STYLE_CLASS_FLAT); - - grid = new Gtk.Grid () { - row_spacing = 24 - }; - grid.attach (headerbar, 0, 0); - grid.attach (stack, 0, 1); } - return grid; + return paned; } public override void shown () { @@ -124,9 +110,8 @@ public class ApplicationsPlug : Switchboard.Plug { search_results.set ("%s ā†’ %s ā†’ %s".printf (display_name, _("Default"), _("File Browser")), DEFAULTS); return search_results; } - } public Switchboard.Plug get_plug (Module module) { - return new ApplicationsPlug (); + return new Applications.Plug (); } diff --git a/src/Sidebar.vala b/src/Sidebar.vala new file mode 100644 index 00000000..0682da45 --- /dev/null +++ b/src/Sidebar.vala @@ -0,0 +1,176 @@ +/* + * SPDX-License-Identifier: GPL-3.0-or-later + * SPDX-FileCopyrightText: 2024 elementary, Inc. (https://elementary.io) + */ + +public class Applications.Sidebar : Gtk.Box { + public Gtk.Stack stack { get; construct; } + + private Gtk.SearchEntry search_entry; + + class construct { + set_css_name ("settingssidebar"); + } + + public Sidebar (Gtk.Stack stack) { + Object (stack: stack); + } + + construct { + var defaults_row = new SimpleSidebarRow ( + _("Defaults"), Plug.DEFAULTS + ); + + var startup_row = new SimpleSidebarRow ( + _("Startup"), Plug.STARTUP + ); + + search_entry = new Gtk.SearchEntry () { + placeholder_text = _("Search Apps"), + margin_top = 6, + margin_bottom = 6, + margin_start = 6, + margin_end = 6, + hexpand = true + }; + + var search_revealer = new Gtk.Revealer () { + child = search_entry + }; + + var search_toggle = new Gtk.ToggleButton () { + icon_name = "edit-find-symbolic", + tooltip_text = _("Search Apps") + }; + + var headerbar = new Adw.HeaderBar () { + show_end_title_buttons = false, + show_title = false + }; + headerbar.pack_end (search_toggle); + + var listbox = new Gtk.ListBox () { + vexpand = true, + selection_mode = BROWSE + }; + listbox.set_filter_func (filter_function); + listbox.set_header_func (header_func); + listbox.set_sort_func (sort_func); + listbox.append (defaults_row); + listbox.append (startup_row); + + var scrolled_window = new Gtk.ScrolledWindow () { + child = listbox, + hscrollbar_policy = NEVER + }; + + var toolbarview = new Adw.ToolbarView () { + content = scrolled_window, + top_bar_style = FLAT, + }; + toolbarview.add_top_bar (headerbar); + toolbarview.add_top_bar (search_revealer); + + append (toolbarview); + add_css_class (Granite.STYLE_CLASS_SIDEBAR); + + Permissions.Backend.AppManager.get_default ().apps.foreach ((id, app) => { + var app_entry = new Permissions.SidebarRow (app); + listbox.append (app_entry); + }); + + listbox.row_selected.connect ((row) => { + if (row == null) { + return; + } + + if (row is Permissions.SidebarRow) { + stack.visible_child_name = Plug.PERMISSIONS; + ((Permissions.Widgets.AppSettingsView) stack.visible_child).selected_app = ((Permissions.SidebarRow)row).app; + } else if (row is SimpleSidebarRow) { + stack.visible_child_name = ((SimpleSidebarRow) row).icon_name; + } + }); + + search_entry.search_changed.connect (() => { + listbox.invalidate_filter (); + }); + + search_toggle.bind_property ("active", search_revealer, "reveal-child"); + + search_revealer.notify["child-revealed"].connect (() => { + if (search_revealer.child_revealed) { + search_entry.grab_focus (); + } else { + search_entry.text = ""; + } + }); + } + + private bool filter_function (Gtk.ListBoxRow row) { + if (search_entry.text != "") { + if (row is SimpleSidebarRow) { + return false; + } + + var search_term = search_entry.text.down (); + var row_name = ((Permissions.SidebarRow) row).app.name.down (); + + return search_term in row_name; + } + + return true; + } + + private void header_func (Gtk.ListBoxRow row, Gtk.ListBoxRow? before) { + if (row is SimpleSidebarRow && !(before is SimpleSidebarRow)) { + row.set_header (new Granite.HeaderLabel (_("System"))); + return; + } + + if (row is Permissions.SidebarRow && before is SimpleSidebarRow) { + row.set_header (new Granite.HeaderLabel (_("Apps"))); + return; + } + + row.set_header (null); + } + + private int sort_func (Gtk.ListBoxRow row1, Gtk.ListBoxRow row2) { + if (row1 is Permissions.SidebarRow && row2 is Permissions.SidebarRow) { + return ((Permissions.SidebarRow) row1).app.name.collate (((Permissions.SidebarRow) row2).app.name); + } + + return 0; + } + + private class SimpleSidebarRow : Gtk.ListBoxRow { + public string label { get; construct; } + public string icon_name { get; construct; } + + public SimpleSidebarRow (string label, string icon_name) { + Object ( + label: label, + icon_name: icon_name + ); + } + + construct { + var image = new Gtk.Image.from_icon_name (icon_name) { + icon_size = LARGE + }; + + var title_label = new Gtk.Label (label) { + ellipsize = END, + xalign = 0 + }; + title_label.add_css_class (Granite.STYLE_CLASS_H3_LABEL); + + var box = new Gtk.Box (HORIZONTAL, 6); + box.append (image); + box.append (title_label); + + child = box; + } + } +} diff --git a/src/Startup/Startup.vala b/src/Startup/Startup.vala index f930e281..55973111 100644 --- a/src/Startup/Startup.vala +++ b/src/Startup/Startup.vala @@ -6,17 +6,23 @@ * Julien Spautz */ -public class Startup.Plug : Gtk.Box { +public class Startup.Plug : Switchboard.SettingsPage { private Controller controller; private Gtk.ListBox list; private Widgets.AppChooser app_chooser; + public Plug () { + Object ( + title: _("Startup"), + icon: new ThemedIcon ("preferences-desktop-startup") + ); + } + construct { Backend.KeyFileFactory.init (); var empty_alert = new Granite.Placeholder (_("Launch Apps on Startup")) { - description = _("Add apps to the Startup list by clicking the icon in the toolbar below."), - icon = new ThemedIcon ("system-restart") + description = _("Add apps to the Startup list by clicking the icon in the toolbar below.") }; list = new Gtk.ListBox () { @@ -57,14 +63,8 @@ public class Startup.Plug : Gtk.Box { child = box }; - var clamp = new Adw.Clamp () { - child = frame, - margin_end = 12, - margin_bottom = 12, - margin_start = 12 - }; - - append (clamp); + child = frame; + show_end_title_buttons = true; app_chooser = new Widgets.AppChooser () { modal = true diff --git a/src/meson.build b/src/meson.build index 5a7cedef..1dca946b 100644 --- a/src/meson.build +++ b/src/meson.build @@ -1,5 +1,6 @@ plug_files = files( 'Plug.vala', + 'Sidebar.vala', 'Startup/Utils.vala', 'Startup/Startup.vala', 'Startup/Controller.vala', @@ -19,8 +20,7 @@ plug_files = files( 'Permissions/Backend/PermissionStore.vala', 'Permissions/Widgets/AppSettingsView.vala', 'Permissions/Widgets/PermissionSettingsWidget.vala', - 'Permissions/Widgets/SidebarRow.vala', - 'Permissions/PermissionsPlug.vala' + 'Permissions/Widgets/SidebarRow.vala' ) switchboard_dep = dependency('switchboard-3')