mirror of
https://github.com/ErikReider/SwayNotificationCenter.git
synced 2024-11-22 09:43:52 +03:00
Customize and reorder widgets in Control Center (#150)
* Initial widget code with Title and DND widgets * Fixed linting issues * Added label widget * Added label to widgets JSON Schema * Added default widgets * Added info to swaync 5 man page * Updated README with widget info * Added ability for multiple configs per widget * Reworked how the widget CSS classes are applied * Fixed linting issues * Added CSS class names to man page
This commit is contained in:
parent
7716e5eeaf
commit
14a327603c
10
README.md
10
README.md
@ -21,6 +21,16 @@ A simple notification daemon with a GTK gui for notifications and the control ce
|
||||
- The same features as any other basic notification daemon
|
||||
- Basic configuration through a JSON config file
|
||||
- Hot-reload config through `swaync-client`
|
||||
- Customizable widgets
|
||||
|
||||
## Available Widgets
|
||||
|
||||
These widgets can be customized, added, removed and even reordered
|
||||
|
||||
- Title
|
||||
- Do Not Disturb
|
||||
- Notifications (Will always be visible)
|
||||
- Label
|
||||
|
||||
## Planned Features
|
||||
|
||||
|
@ -156,6 +156,102 @@ config file to be able to detect config errors
|
||||
}
|
||||
```
|
||||
|
||||
*widgets* ++
|
||||
type: array ++
|
||||
Default values: ["title", "dnd", "notifications"] ++
|
||||
Valid array values (see *widget-config* for more information): ++
|
||||
*notifications*++
|
||||
required: true ++
|
||||
optional: false ++
|
||||
*title*++
|
||||
optional: true ++
|
||||
*dnd*++
|
||||
optional: true ++
|
||||
*label*++
|
||||
optional: true ++
|
||||
description: Which order and which widgets to display. ++
|
||||
If the \"notifications\" widget isn't specified, it ++
|
||||
will be placed at the bottom. ++
|
||||
example:
|
||||
```
|
||||
{
|
||||
"widgets": [
|
||||
"title",
|
||||
"dnd",
|
||||
"notifications"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
*widget-config* ++
|
||||
type: object ++
|
||||
description: Configure specific widget properties. ++
|
||||
Widgets to customize: ++
|
||||
*title*++
|
||||
type: object ++
|
||||
css class: widget-title ++
|
||||
properties: ++
|
||||
text: ++
|
||||
type: string ++
|
||||
optional: true ++
|
||||
default: "Do Not Disturb" ++
|
||||
description: The title of the widget ++
|
||||
clear-all-button: ++
|
||||
type: bool ++
|
||||
optional: true ++
|
||||
default: true ++
|
||||
description: Wether to display a "Clear All" button ++
|
||||
button-text: ++
|
||||
type: string ++
|
||||
optional: true ++
|
||||
default: "Clear All" ++
|
||||
description: "Clear All" button text ++
|
||||
description: The notification visibility state. ++
|
||||
*dnd*++
|
||||
type: object ++
|
||||
css class: widget-dnd ++
|
||||
properties: ++
|
||||
text: ++
|
||||
type: string ++
|
||||
optional: true ++
|
||||
default: "Do Not Disturb" ++
|
||||
description: The title of the widget ++
|
||||
description: Control Center Do Not Disturb Widget. ++
|
||||
*label*++
|
||||
type: object ++
|
||||
css class: widget-label ++
|
||||
properties: ++
|
||||
text: ++
|
||||
type: string ++
|
||||
optional: true ++
|
||||
default: "Label Text" ++
|
||||
description: The text content of the widget ++
|
||||
clear-all-button: ++
|
||||
type: integer ++
|
||||
optional: true ++
|
||||
default: 5 ++
|
||||
description: The maximum lines ++
|
||||
description: A generic widget that allows the user to add custom text. ++
|
||||
example:
|
||||
```
|
||||
{
|
||||
"widget-config": {
|
||||
"title": {
|
||||
"text": "Notifications",
|
||||
"clear-all-button": true,
|
||||
"button-text": "Clear All"
|
||||
},
|
||||
"dnd": {
|
||||
"text": "Do Not Disturb"
|
||||
},
|
||||
"label": {
|
||||
"max-lines": 5,
|
||||
"text": "Label Text"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# IF BUILT WITH SCRIPTING
|
||||
|
||||
*script-fail-notify* ++
|
||||
|
@ -34,5 +34,24 @@
|
||||
"urgency": "Low",
|
||||
"app-name": "Spotify"
|
||||
}
|
||||
},
|
||||
"widgets": [
|
||||
"title",
|
||||
"dnd",
|
||||
"notifications"
|
||||
],
|
||||
"widget-config": {
|
||||
"title": {
|
||||
"text": "Notifications",
|
||||
"clear-all-button": true,
|
||||
"button-text": "Clear All"
|
||||
},
|
||||
"dnd": {
|
||||
"text": "Do Not Disturb"
|
||||
},
|
||||
"label": {
|
||||
"max-lines": 5,
|
||||
"text": "Label Text"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -503,6 +503,20 @@ namespace SwayNotificationCenter {
|
||||
}
|
||||
}
|
||||
|
||||
/** Widgets to show in ControlCenter */
|
||||
public GenericArray<string> widgets {
|
||||
get;
|
||||
set;
|
||||
default = new GenericArray<string> ();
|
||||
}
|
||||
|
||||
/** Widgets to show in ControlCenter */
|
||||
public HashTable<string, Json.Object> widget_config {
|
||||
get;
|
||||
set;
|
||||
default = new HashTable<string, Json.Object> (str_hash, str_equal);
|
||||
}
|
||||
|
||||
/* Methods */
|
||||
|
||||
/**
|
||||
@ -544,6 +558,34 @@ namespace SwayNotificationCenter {
|
||||
value = result;
|
||||
return status;
|
||||
#endif
|
||||
case "widgets":
|
||||
bool status;
|
||||
GenericArray<string> result =
|
||||
extract_array<string> (property_name,
|
||||
property_node,
|
||||
out status);
|
||||
value = result;
|
||||
return status;
|
||||
case "widget-config":
|
||||
HashTable<string, Json.Object> result
|
||||
= new HashTable<string, Json.Object> (str_hash, str_equal);
|
||||
if (property_node.get_value_type ().name () != "JsonObject") {
|
||||
value = result;
|
||||
return true;
|
||||
}
|
||||
Json.Object obj = property_node.get_object ();
|
||||
if (obj.get_size () == 0) {
|
||||
value = result;
|
||||
return true;
|
||||
}
|
||||
foreach (var key in obj.get_members ()) {
|
||||
Json.Node ? node = obj.get_member (key);
|
||||
if (node.get_node_type () != Json.NodeType.OBJECT) continue;
|
||||
Json.Object ? o = node.get_object ();
|
||||
if (o != null) result.set (key, o);
|
||||
}
|
||||
value = result;
|
||||
return true;
|
||||
default:
|
||||
// Handles all other properties
|
||||
return default_deserialize_property (
|
||||
@ -588,6 +630,16 @@ namespace SwayNotificationCenter {
|
||||
node.set_object (serialize_hashtable<Script> (table));
|
||||
break;
|
||||
#endif
|
||||
case "widgets":
|
||||
node = new Json.Node (Json.NodeType.ARRAY);
|
||||
var table = (GenericArray<string>) value.get_boxed ();
|
||||
node.set_array (serialize_array<string> (table));
|
||||
break;
|
||||
case "widget-config":
|
||||
node = new Json.Node (Json.NodeType.OBJECT);
|
||||
var table = (HashTable<string, Json.Object>) value.get_boxed ();
|
||||
node.set_object (serialize_hashtable<Json.Object> (table));
|
||||
break;
|
||||
default:
|
||||
node.set_value (value);
|
||||
break;
|
||||
@ -728,6 +780,18 @@ namespace SwayNotificationCenter {
|
||||
var node = Json.gobject_serialize (item as Object);
|
||||
json_object.set_member (key, node);
|
||||
break;
|
||||
case Type.BOXED:
|
||||
switch (typeof (T).name ()) {
|
||||
case "JsonObject":
|
||||
json_object.set_object_member (key,
|
||||
(Json.Object) item);
|
||||
break;
|
||||
case "JsonArray":
|
||||
json_object.set_array_member (key,
|
||||
(Json.Array) item);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return json_object;
|
||||
|
@ -1,4 +1,5 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"title": "SwayNotificationCenter JSON schema",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
@ -127,7 +128,7 @@
|
||||
},
|
||||
"scripts": {
|
||||
"type": "object",
|
||||
"description": "Which scripts to check and potentially run for every notification. If the notification doesn't include one of the properites, that property will be ignored. All properties (except for exec) use regex. If all properties match the given notification, the script will be run. Only the first matching script will be run.",
|
||||
"description": "Which scripts to check and potentially run for every notification. If the notification doesn't include one of the properties, that property will be ignored. All properties (except for exec) use regex. If all properties match the given notification, the script will be run. Only the first matching script will be run.",
|
||||
"minProperties": 1,
|
||||
"additionalProperties": false,
|
||||
"patternProperties": {
|
||||
@ -170,7 +171,7 @@
|
||||
},
|
||||
"notification-visibility": {
|
||||
"type": "object",
|
||||
"description": "Set the visibility of each incoming notification. If the notification doesn't include one of the properites, that property will be ignored. All properties (except for state) use regex. If all properties match the given notification, the notification will be follow the provided state. Only the first matching object will be used.",
|
||||
"description": "Set the visibility of each incoming notification. If the notification doesn't include one of the properties, that property will be ignored. All properties (except for state) use regex. If all properties match the given notification, the notification will be follow the provided state. Only the first matching object will be used.",
|
||||
"minProperties": 1,
|
||||
"additionalProperties": false,
|
||||
"patternProperties": {
|
||||
@ -212,6 +213,88 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"widgets": {
|
||||
"type": "array",
|
||||
"description": "Which order and which widgets to display. If the \"notifications\" widget isn't specified, it will be placed at the bottom.",
|
||||
"default": ["title", "dnd", "notifications"],
|
||||
"items": {
|
||||
"type": "string",
|
||||
// Sadly can't use regex and enums at the same time. Fix in the future?
|
||||
"pattern": "^[a-zA-Z0-9_-]{1,}(#[a-zA-Z0-9_-]{1,}){0,1}?$"
|
||||
}
|
||||
},
|
||||
"widget-config": {
|
||||
"type": "object",
|
||||
"description": "Configure specific widget properties.",
|
||||
"additionalProperties": false,
|
||||
"patternProperties": {
|
||||
// New widgets go here
|
||||
"^title(#[a-zA-Z0-9_-]{1,}){0,1}?$": {
|
||||
// References the widget structure from "widgets" below
|
||||
"$ref": "#/widgets/title"
|
||||
},
|
||||
"^dnd(#[a-zA-Z0-9_-]{1,}){0,1}?$": {
|
||||
"$ref": "#/widgets/dnd"
|
||||
},
|
||||
"^label(#[a-zA-Z0-9_-]{1,}){0,1}?$": {
|
||||
"$ref": "#/widgets/label"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"widgets": {
|
||||
// New widgets go here
|
||||
"title": {
|
||||
"type": "object",
|
||||
"description": "Control Center Title Widget",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"text": {
|
||||
"type": "string",
|
||||
"description": "The title of the widget",
|
||||
"default": "Notifications"
|
||||
},
|
||||
"clear-all-button": {
|
||||
"type": "boolean",
|
||||
"description": "Wether to display a \"Clear All\" button",
|
||||
"default": true
|
||||
},
|
||||
"button-text": {
|
||||
"type": "string",
|
||||
"description": "\"Clear All\" button text",
|
||||
"default": "Clear All"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dnd": {
|
||||
"type": "object",
|
||||
"description": "Control Center Do Not Disturb Widget",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"text": {
|
||||
"type": "string",
|
||||
"description": "The title of the widget",
|
||||
"default": "Do Not Disturb"
|
||||
}
|
||||
}
|
||||
},
|
||||
"label": {
|
||||
"type": "object",
|
||||
"description": "A generic widget that allows the user to add custom text",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"text": {
|
||||
"type": "string",
|
||||
"description": "The text content of the widget",
|
||||
"default": "Label Text"
|
||||
},
|
||||
"max-lines": {
|
||||
"type": "integer",
|
||||
"description": "The maximum lines",
|
||||
"default": 5
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -48,8 +48,7 @@
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="pack-type">end</property>
|
||||
<property name="position">2</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<style>
|
||||
|
@ -11,9 +11,6 @@ namespace SwayNotificationCenter {
|
||||
[GtkChild]
|
||||
unowned Gtk.Box box;
|
||||
|
||||
private Gtk.Switch dnd_button;
|
||||
private Gtk.Button clear_all_button;
|
||||
|
||||
private SwayncDaemon swaync_daemon;
|
||||
private NotiDaemon noti_daemon;
|
||||
|
||||
@ -23,6 +20,9 @@ namespace SwayNotificationCenter {
|
||||
private bool list_reverse = false;
|
||||
private Gtk.Align list_align = Gtk.Align.START;
|
||||
|
||||
private Array<Gtk.Widget> widgets = new Array<Gtk.Widget> ();
|
||||
private const string[] DEFAULT_WIDGETS = { "title", "dnd", "notifications" };
|
||||
|
||||
public ControlCenter (SwayncDaemon swaync_daemon, NotiDaemon noti_daemon) {
|
||||
this.swaync_daemon = swaync_daemon;
|
||||
this.noti_daemon = noti_daemon;
|
||||
@ -102,7 +102,11 @@ namespace SwayNotificationCenter {
|
||||
close_all_notifications ();
|
||||
break;
|
||||
case "D":
|
||||
set_switch_dnd_state (!dnd_button.get_state ());
|
||||
try {
|
||||
swaync_daemon.toggle_dnd ();
|
||||
} catch (Error e) {
|
||||
error ("Error: %s\n", e.message);
|
||||
}
|
||||
break;
|
||||
case "Down":
|
||||
if (list_position + 1 < children.length ()) {
|
||||
@ -136,23 +140,43 @@ namespace SwayNotificationCenter {
|
||||
return true;
|
||||
});
|
||||
|
||||
clear_all_button = new Gtk.Button.with_label ("Clear All");
|
||||
clear_all_button.get_style_context ().add_class (
|
||||
"control-center-clear-all");
|
||||
clear_all_button.clicked.connect (close_all_notifications);
|
||||
this.box.add (new TopAction ("Notifications",
|
||||
clear_all_button,
|
||||
true));
|
||||
add_widgets ();
|
||||
}
|
||||
|
||||
dnd_button = new Gtk.Switch () {
|
||||
state = noti_daemon.dnd,
|
||||
};
|
||||
dnd_button.get_style_context ().add_class ("control-center-dnd");
|
||||
dnd_button.state_set.connect ((widget, state) => {
|
||||
noti_daemon.dnd = state;
|
||||
return false;
|
||||
});
|
||||
this.box.add (new TopAction ("Do Not Disturb", dnd_button, false));
|
||||
/** Adds all custom widgets. Removes previous widgets */
|
||||
public void add_widgets () {
|
||||
// Remove all widgets
|
||||
while (widgets.length > 0) {
|
||||
uint i = widgets.length - 1;
|
||||
widgets.index (i).destroy ();
|
||||
widgets.remove_index (i);
|
||||
}
|
||||
|
||||
string[] w = ConfigModel.instance.widgets.data;
|
||||
if (w.length == 0) w = DEFAULT_WIDGETS;
|
||||
bool has_notification = false;
|
||||
foreach (string key in w) {
|
||||
// Reposition the scrolled_window
|
||||
if (key == "notifications") {
|
||||
has_notification = true;
|
||||
uint pos = box.get_children ().length ();
|
||||
box.reorder_child (scrolled_window, (int) (pos > 0 ? --pos : 0));
|
||||
continue;
|
||||
}
|
||||
// Add the widget if it is valid
|
||||
Gtk.Widget ? widget = Widgets.get_widget_from_key (key,
|
||||
swaync_daemon,
|
||||
noti_daemon);
|
||||
if (widget == null || !(widget is Widgets.BaseWidget)) continue;
|
||||
widgets.append_val (widget);
|
||||
box.pack_start (
|
||||
widgets.index (widgets.length - 1), false, true, 0);
|
||||
}
|
||||
if (!has_notification) {
|
||||
warning ("Notification widget not included in \"widgets\" config. Using default bottom position");
|
||||
uint pos = box.get_children ().length ();
|
||||
box.reorder_child (scrolled_window, (int) (pos > 0 ? --pos : 0));
|
||||
}
|
||||
}
|
||||
|
||||
private bool blank_window_press (Gdk.Event event) {
|
||||
@ -215,16 +239,12 @@ namespace SwayNotificationCenter {
|
||||
// Set cc widget position
|
||||
list_reverse = false;
|
||||
list_align = Gtk.Align.START;
|
||||
this.box.set_child_packing (
|
||||
scrolled_window, true, true, 0, Gtk.PackType.END);
|
||||
break;
|
||||
case PositionY.BOTTOM:
|
||||
align_y = Gtk.Align.END;
|
||||
// Set cc widget position
|
||||
list_reverse = true;
|
||||
list_align = Gtk.Align.END;
|
||||
this.box.set_child_packing (
|
||||
scrolled_window, true, true, 0, Gtk.PackType.START);
|
||||
break;
|
||||
}
|
||||
// Fit the ControlCenter to the monitor height
|
||||
@ -316,10 +336,6 @@ namespace SwayNotificationCenter {
|
||||
this.visible);
|
||||
}
|
||||
|
||||
public void set_switch_dnd_state (bool state) {
|
||||
if (this.dnd_button.state != state) this.dnd_button.state = state;
|
||||
}
|
||||
|
||||
public bool toggle_visibility () {
|
||||
var cc_visibility = !this.visible;
|
||||
if (this.visible != cc_visibility) {
|
||||
|
69
src/controlCenter/widgets/baseWidget.vala
Normal file
69
src/controlCenter/widgets/baseWidget.vala
Normal file
@ -0,0 +1,69 @@
|
||||
namespace SwayNotificationCenter.Widgets {
|
||||
public abstract class BaseWidget : Gtk.Box {
|
||||
public abstract string widget_name { get; }
|
||||
|
||||
public string key { get; private set; }
|
||||
public string suffix { get; private set; }
|
||||
|
||||
public unowned SwayncDaemon swaync_daemon;
|
||||
public unowned NotiDaemon noti_daemon;
|
||||
|
||||
protected BaseWidget (string suffix, SwayncDaemon swaync_daemon, NotiDaemon noti_daemon) {
|
||||
this.suffix = suffix;
|
||||
this.key = widget_name + (suffix.length > 0 ? "#%s".printf (suffix) : "");
|
||||
this.swaync_daemon = swaync_daemon;
|
||||
this.noti_daemon = noti_daemon;
|
||||
|
||||
get_style_context ().add_class ("widget-%s".printf (widget_name));
|
||||
if (suffix.length > 0) get_style_context ().add_class (suffix);
|
||||
}
|
||||
|
||||
protected Json.Object ? get_config (Gtk.Widget widget) {
|
||||
unowned HashTable<string, Json.Object> config
|
||||
= ConfigModel.instance.widget_config;
|
||||
string ? orig_key = null;
|
||||
Json.Object ? props = null;
|
||||
bool result = config.lookup_extended (key, out orig_key, out props);
|
||||
if (!result || orig_key == null || props == null) {
|
||||
critical ("%s: Config not found! Using default config...\n", key);
|
||||
return null;
|
||||
}
|
||||
return props;
|
||||
}
|
||||
|
||||
protected void get_prop<T> (Json.Object config, string value_key, ref T value) {
|
||||
if (!config.has_member (value_key)) {
|
||||
warning ("%s: Config doesn't have key: %s!\n", key, value_key);
|
||||
return;
|
||||
}
|
||||
var member = config.get_member (value_key);
|
||||
|
||||
Type base_type = Functions.get_base_type (member.get_value_type ());
|
||||
|
||||
Type generic_base_type = Functions.get_base_type (typeof (T));
|
||||
// Convert all INTs to INT64
|
||||
if (generic_base_type == Type.INT) generic_base_type = Type.INT64;
|
||||
|
||||
if (!base_type.is_a (generic_base_type)) {
|
||||
warning ("%s: Config type %s doesn't match: %s!\n",
|
||||
key,
|
||||
typeof (T).name (),
|
||||
member.get_value_type ().name ());
|
||||
return;
|
||||
}
|
||||
switch (typeof (T)) {
|
||||
case Type.STRING:
|
||||
value = member.get_string ();
|
||||
break;
|
||||
case Type.INT:
|
||||
case Type.INT64:
|
||||
value = member.get_int ();
|
||||
break;
|
||||
case Type.BOOLEAN:
|
||||
value = member.get_boolean ();
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
53
src/controlCenter/widgets/dnd/dnd.vala
Normal file
53
src/controlCenter/widgets/dnd/dnd.vala
Normal file
@ -0,0 +1,53 @@
|
||||
namespace SwayNotificationCenter.Widgets {
|
||||
public class Dnd : BaseWidget {
|
||||
public override string widget_name {
|
||||
get {
|
||||
return "dnd";
|
||||
}
|
||||
}
|
||||
|
||||
Gtk.Label title_widget;
|
||||
Gtk.Switch dnd_button;
|
||||
|
||||
// Default config values
|
||||
string title = "Do Not Disturb";
|
||||
|
||||
public Dnd (string suffix, SwayncDaemon swaync_daemon, NotiDaemon noti_daemon) {
|
||||
base (suffix, swaync_daemon, noti_daemon);
|
||||
|
||||
Json.Object ? config = get_config (this);
|
||||
if (config != null) {
|
||||
// Get title
|
||||
get_prop<string> (config, "text", ref title);
|
||||
}
|
||||
|
||||
// Title
|
||||
title_widget = new Gtk.Label (title);
|
||||
add (title_widget);
|
||||
|
||||
// Dnd button
|
||||
dnd_button = new Gtk.Switch () {
|
||||
state = noti_daemon.dnd,
|
||||
};
|
||||
dnd_button.state_set.connect (state_set);
|
||||
noti_daemon.on_dnd_toggle.connect ((dnd) => {
|
||||
dnd_button.state_set.disconnect (state_set);
|
||||
dnd_button.set_active (dnd);
|
||||
dnd_button.state_set.connect (state_set);
|
||||
});
|
||||
|
||||
dnd_button.set_can_focus (false);
|
||||
dnd_button.valign = Gtk.Align.CENTER;
|
||||
// Backwards compatible torwards older CSS stylesheets
|
||||
dnd_button.get_style_context ().add_class ("control-center-dnd");
|
||||
pack_end (dnd_button, false);
|
||||
|
||||
show_all ();
|
||||
}
|
||||
|
||||
private bool state_set (Gtk.Widget widget, bool state) {
|
||||
noti_daemon.dnd = state;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
27
src/controlCenter/widgets/factory.vala
Normal file
27
src/controlCenter/widgets/factory.vala
Normal file
@ -0,0 +1,27 @@
|
||||
namespace SwayNotificationCenter.Widgets {
|
||||
public static Gtk.Widget ? get_widget_from_key (owned string key,
|
||||
SwayncDaemon swaync_daemon,
|
||||
NotiDaemon noti_daemon) {
|
||||
string[] key_seperated = key.split ("#");
|
||||
string suffix = "";
|
||||
if (key_seperated.length > 0) key = key_seperated[0];
|
||||
if (key_seperated.length > 1) suffix = key_seperated[1];
|
||||
BaseWidget widget;
|
||||
switch (key) {
|
||||
case "title":
|
||||
widget = new Title (suffix, swaync_daemon, noti_daemon);
|
||||
break;
|
||||
case "dnd":
|
||||
widget = new Dnd (suffix, swaync_daemon, noti_daemon);
|
||||
break;
|
||||
case "label":
|
||||
widget = new Label (suffix, swaync_daemon, noti_daemon);
|
||||
break;
|
||||
default:
|
||||
warning ("Could not find widget: \"%s\"!", key);
|
||||
return null;
|
||||
}
|
||||
message ("Loading widget: %s", widget.key);
|
||||
return widget;
|
||||
}
|
||||
}
|
44
src/controlCenter/widgets/label/label.vala
Normal file
44
src/controlCenter/widgets/label/label.vala
Normal file
@ -0,0 +1,44 @@
|
||||
namespace SwayNotificationCenter.Widgets {
|
||||
public class Label : BaseWidget {
|
||||
public override string widget_name {
|
||||
get {
|
||||
return "label";
|
||||
}
|
||||
}
|
||||
|
||||
Gtk.Label label_widget;
|
||||
|
||||
// Default config values
|
||||
string text = "Label Text";
|
||||
int max_lines = 5;
|
||||
|
||||
public Label (string suffix, SwayncDaemon swaync_daemon, NotiDaemon noti_daemon) {
|
||||
base (suffix, swaync_daemon, noti_daemon);
|
||||
|
||||
Json.Object ? config = get_config (this);
|
||||
if (config != null) {
|
||||
// Get text
|
||||
get_prop<string> (config, "text", ref text);
|
||||
// Get max lines
|
||||
get_prop<int> (config, "max-lines", ref max_lines);
|
||||
}
|
||||
|
||||
label_widget = new Gtk.Label (null);
|
||||
label_widget.set_text (text);
|
||||
|
||||
label_widget.set_ellipsize (Pango.EllipsizeMode.END);
|
||||
label_widget.set_line_wrap (true);
|
||||
label_widget.set_lines (max_lines);
|
||||
// Without this and pack_start fill, the label would expand to
|
||||
// the monitors full width... GTK bug!...
|
||||
label_widget.set_max_width_chars (0);
|
||||
label_widget.set_line_wrap_mode (Pango.WrapMode.WORD_CHAR);
|
||||
label_widget.set_justify (Gtk.Justification.LEFT);
|
||||
label_widget.set_alignment (0, 0);
|
||||
|
||||
pack_start (label_widget, true, true, 0);
|
||||
|
||||
show_all ();
|
||||
}
|
||||
}
|
||||
}
|
51
src/controlCenter/widgets/title/title.vala
Normal file
51
src/controlCenter/widgets/title/title.vala
Normal file
@ -0,0 +1,51 @@
|
||||
namespace SwayNotificationCenter.Widgets {
|
||||
public class Title : BaseWidget {
|
||||
public override string widget_name {
|
||||
get {
|
||||
return "title";
|
||||
}
|
||||
}
|
||||
|
||||
Gtk.Label title_widget;
|
||||
Gtk.Button clear_all_button;
|
||||
|
||||
// Default config values
|
||||
string title = "Notifications";
|
||||
bool has_clear_all_button = true;
|
||||
string button_text = "Clear All";
|
||||
|
||||
public Title (string suffix, SwayncDaemon swaync_daemon, NotiDaemon noti_daemon) {
|
||||
base (suffix, swaync_daemon, noti_daemon);
|
||||
|
||||
Json.Object ? config = get_config (this);
|
||||
if (config != null) {
|
||||
// Get title
|
||||
get_prop<string> (config, "text", ref title);
|
||||
// Get has clear-all-button
|
||||
get_prop<bool> (config, "clear-all-button", ref has_clear_all_button);
|
||||
get_prop<string> (config, "button-text", ref button_text);
|
||||
}
|
||||
|
||||
title_widget = new Gtk.Label (title);
|
||||
add (title_widget);
|
||||
|
||||
if (has_clear_all_button) {
|
||||
clear_all_button = new Gtk.Button.with_label (button_text);
|
||||
clear_all_button.clicked.connect (() => {
|
||||
try {
|
||||
swaync_daemon.close_all_notifications ();
|
||||
} catch (Error e) {
|
||||
error ("Error: %s\n", e.message);
|
||||
}
|
||||
});
|
||||
clear_all_button.set_can_focus (false);
|
||||
clear_all_button.valign = Gtk.Align.CENTER;
|
||||
// Backwards compatible torwards older CSS stylesheets
|
||||
clear_all_button.get_style_context ().add_class ("control-center-clear-all");
|
||||
pack_end (clear_all_button, false);
|
||||
}
|
||||
|
||||
show_all ();
|
||||
}
|
||||
}
|
||||
}
|
@ -22,6 +22,16 @@ constants = configure_file(
|
||||
configuration : const_config_data
|
||||
)
|
||||
|
||||
widget_sources = [
|
||||
# Helpers
|
||||
'controlCenter/widgets/baseWidget.vala',
|
||||
'controlCenter/widgets/factory.vala',
|
||||
# Widgets
|
||||
'controlCenter/widgets/title/title.vala',
|
||||
'controlCenter/widgets/dnd/dnd.vala',
|
||||
'controlCenter/widgets/label/label.vala',
|
||||
]
|
||||
|
||||
app_sources = [
|
||||
'main.vala',
|
||||
'configModel/configModel.vala',
|
||||
@ -31,6 +41,7 @@ app_sources = [
|
||||
'notificationWindow/notificationWindow.vala',
|
||||
'notification/notification.vala',
|
||||
'controlCenter/controlCenter.vala',
|
||||
widget_sources,
|
||||
'controlCenter/topAction/topAction.vala',
|
||||
'blankWindow/blankWindow.vala',
|
||||
'functions.vala',
|
||||
|
@ -159,35 +159,6 @@
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
.control-center-clear-all {
|
||||
color: white;
|
||||
text-shadow: none;
|
||||
background: @noti-bg;
|
||||
border: 1px solid @noti-border-color;
|
||||
box-shadow: none;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.control-center-clear-all:hover {
|
||||
background: @noti-bg-hover;
|
||||
}
|
||||
|
||||
.control-center-dnd {
|
||||
border-radius: 12px;
|
||||
background: @noti-bg;
|
||||
border: 1px solid @noti-border-color;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.control-center-dnd:checked {
|
||||
background: @bg-selected;
|
||||
}
|
||||
|
||||
.control-center-dnd slider {
|
||||
background: @noti-bg-hover;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.control-center {
|
||||
background: @cc-bg;
|
||||
}
|
||||
@ -204,3 +175,51 @@
|
||||
.blank-window {
|
||||
background: alpha(black, 0.25);
|
||||
}
|
||||
|
||||
/*** Widgets ***/
|
||||
|
||||
/* Title widget */
|
||||
.widget-title {
|
||||
margin: 8px;
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
.widget-title > button {
|
||||
font-size: initial;
|
||||
color: white;
|
||||
text-shadow: none;
|
||||
background: @noti-bg;
|
||||
border: 1px solid @noti-border-color;
|
||||
box-shadow: none;
|
||||
border-radius: 12px;
|
||||
}
|
||||
.widget-title > button:hover {
|
||||
background: @noti-bg-hover;
|
||||
}
|
||||
|
||||
/* DND widget */
|
||||
.widget-dnd {
|
||||
margin: 8px;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
.widget-dnd > switch {
|
||||
font-size: initial;
|
||||
border-radius: 12px;
|
||||
background: @noti-bg;
|
||||
border: 1px solid @noti-border-color;
|
||||
box-shadow: none;
|
||||
}
|
||||
.widget-dnd > switch:checked {
|
||||
background: @bg-selected;
|
||||
}
|
||||
.widget-dnd > switch slider {
|
||||
background: @noti-bg-hover;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
/* Label widget */
|
||||
.widget-label {
|
||||
margin: 8px;
|
||||
}
|
||||
.widget-label > label {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
@ -28,7 +28,6 @@ namespace SwayNotificationCenter {
|
||||
});
|
||||
|
||||
noti_daemon.on_dnd_toggle.connect ((dnd) => {
|
||||
noti_daemon.control_center.set_switch_dnd_state (dnd);
|
||||
try {
|
||||
subscribe (noti_daemon.control_center.notification_count (),
|
||||
dnd,
|
||||
@ -152,6 +151,7 @@ namespace SwayNotificationCenter {
|
||||
/** Reloads the config file */
|
||||
public void reload_config () throws Error {
|
||||
ConfigModel.reload_config ();
|
||||
noti_daemon.control_center.add_widgets ();
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user