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 @@
+
+
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 @@
+
+
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')