notifications: merge title widget, remove placeholder, restyle

parent 07222731
:root {
--notification-icon-size: 64px;
--notification-icon-size: 48px;
--notification-app-icon-size: calc(var(--notification-icon-size) / 3);
--notification-group-icon-size: 32px;
--border-radius: 12px;
--notification-group-icon-size: 24px;
--hover-tranistion: background 0.15s ease-in-out;
--group-collapse-tranistion: opacity 400ms ease-in-out;
......@@ -24,306 +22,16 @@ notificationwindow, blankwindow {
background: transparent;
}
.floating-notifications {
background: transparent;
.notification {
box-shadow: none;
}
}
.close-button {
background: unquote("alpha(var(--window-bg-color), 0.6)");
color: var(--window-fg-color);
text-shadow: none;
padding: 0;
border-radius: 100%;
margin-top: $margin;
margin-right: $margin;
box-shadow: none;
border: none;
min-width: 24px;
min-height: 24px;
&:hover {
box-shadow: none;
background: unquote("alpha(var(--window-bg-color), 0.4)");
transition: var(--hover-tranistion);
border: none;
}
}
.notification-row {
background: none;
outline: none;
&:focus {
background: none;
}
.notification-background {
padding: 5px 0;
.close-button {}
.notification {
border-radius: var(--window-radius);
border: 1px solid var(--border-color);
padding: 0;
transition: var(--hover-tranistion);
background: var(--dialog-bg-color);
box-shadow: 0 0 5px 0 var(--headerbar-shade-color);
&.low {
border-left: 4px solid var(--success-bg-color);
}
&.normal {
border-left: 4px solid var(--blue-3);
}
&.critical {
border-left: 4px solid var(--error-bg-color);
}
.notification-default-action {
padding: 10px;
margin: 0;
box-shadow: none;
background: transparent;
border: none;
color: var(--window-fg-color);
transition: var(--hover-tranistion);
border-radius: var(--window-radius);
&:hover {
-gtk-icon-filter: none;
background: unquote("alpha(var(--window-fg-color), 0.05)");
}
&:not(:only-child) {
border-bottom-left-radius: 0px;
border-bottom-right-radius: 0px;
}
.notification-content {
background: transparent;
border-radius: var(--border-radius);
$margin: 4px;
padding: 0;
.image {
-gtk-icon-filter: none;
-gtk-icon-size: var(--notification-icon-size);
border-radius: var(--window-radius);
margin: 0px 10px 0px 0px;
}
.app-icon {
-gtk-icon-filter: none;
-gtk-icon-size: var(--notification-app-icon-size);
-gtk-icon-shadow: 0 1px 4px black;
margin: 6px;
}
.text-box {
label {
filter: none;
}
.summary {
font-weight: bold;
background: transparent;
color: var(--window-fg-color);
text-shadow: none;
}
.time {
font-weight: bold;
background: transparent;
color: var(--window-fg-color);
text-shadow: none;
margin-right: 20px;
}
.body {
font-weight: normal;
background: transparent;
color: var(--window-fg-color);
text-shadow: none;
}
}
progressbar {
margin-top: $margin;
}
.body-image {
margin-top: $margin;
background-color: white;
-gtk-icon-filter: none;
}
.inline-reply {
margin-top: $margin;
.inline-reply-entry {
background: var(--view-bg-color);
color: var(--window-fg-color);
caret-color: var(--window-fg-color);
border: 1px solid var(--border-color);
border-radius: var(--border-radius);
}
.inline-reply-button {
margin-left: 4px;
background: var(--dialog-bg-color);
border: 1px solid var(--border-color);
border-radius: var(--border-radius);
color: var(--window-fg-color);
&:disabled {
background: initial;
color: unquote("alpha(var(--window-fg-color), 0.5)");
border-color: transparent;
}
&:hover {
background: unquote("alpha(var(--window-fg-color), 0.05)");
}
}
}
}
}
.notification-alt-actions {
background: none;
border-bottom-left-radius: var(--border-radius);
border-bottom-right-radius: var(--border-radius);
padding: $margin / 2;
}
.notification-action {
margin: $margin / 2;
padding: 0;
&>button {
border-radius: var(--window-radius);
color: var(--window-fg-color);
background: unquote("alpha(var(--window-bg-color), 0.4)");
border: 1px solid var(--border-color);
&:hover {
background: unquote("alpha(var(--window-bg-color), 0.2)");
border: 2px solid var(--accent-bg-color);
}
}
}
}
}
}
.notification-group {
transition: opacity 200ms ease-in-out;
&:focus {
background: none;
}
.notification-group-close-button .close-button {
background: unquote("alpha(var(--window-bg-color), 0.4)");
box-shadow: 0 0 5px 0 var(--headerbar-shade-color);
margin: $margin * 1.5 $margin * 2.5;
&:hover {
background: unquote("alpha(var(--window-bg-color), 0.8)");
}
}
%header {
margin: 0 $margin * 2;
color: var(--window-fg-color);
}
.notification-group-headers {
@extend %header;
.notification-group-icon {
color: var(--window-fg-color);
-gtk-icon-size: var(--notification-group-icon-size);
}
.notification-group-header {
color: var(--window-fg-color);
}
}
.notification-group-buttons {
@extend %header;
padding: 5px;
}
&.collapsed {
&.not-expanded {
opacity: 0.4;
}
.notification-row:not(:last-child) {
.notification {
background-color: var(--window-bg-color);
}
}
.notification-row:not(:last-child) {
.notification-action,
.notification-default-action {
opacity: 0;
}
.notification.low {
border-left: 3px solid unquote("alpha(var(--success-bg-color), 0.5)");
}
.notification.normal {
border-left: 3px solid unquote("alpha(var(--blue-3), 0.5)");
}
.notification.critical {
border-left: 3px solid unquote("alpha(var(--error-bg-color), 0.5)");
}
}
&:hover {
.notification-row:not(:only-child) {
.notification {
background-color: var(--dialog-bg-color);
}
}
}
}
}
.control-center {
padding: 15px;
background: var(--window-bg-color);
color: var(--window-fg-color);
border-radius: var(--window-radius);
box-shadow: 0 0 10px 0 var(--headerbar-shade-color);
}
.control-center-list-placeholder {
opacity: 0.5;
}
.control-center-list {
background: transparent;
margin: 0px 15px;
.notification {
.notification-default-action,
.notification-action {
transition: var(--group-collapse-tranistion), var(--hover-tranistion);
}
}
}
scrollbar {
opacity: 0;
}
/*** Widgets ***/
......@@ -331,8 +39,8 @@ notificationwindow, blankwindow {
padding: 0;
}
/* Title widget */
@import "widgets/title";
/* Notifications widget */
@import "widgets/notifications";
/* Label widget */
@import "widgets/label";
/* Mpris widget */
......
.widget-backlight {
padding: 0;
margin: 5px 15px;
margin: 5px 0px;
border-radius: var(--window-radius);
&.expanded {
......@@ -8,8 +8,8 @@
box-shadow: 0px 0px 10px var(--headerbar-shade-color);
border: 1px solid var(--border-color);
}
}
.widget-backlight .image-button {
background: transparent;
.image-button {
background: transparent;
}
}
.widget-inhibitors {
background: transparent;
padding: 0px;
margin: 10px 15px;
margin: 5px 0px;
&>label {
& > label {
font-size: 1.5rem;
margin-right: $margin;
}
&>button {
& > button {
background: var(--dialog-bg-color);
border-radius: 999px;
border: 1px solid var(--border-color);
......
.widget-label {
margin: 5px 15px;
margin: 5px 0px;
&>label {
& > label {
font-size: 1.1rem;
}
}
......@@ -4,7 +4,7 @@
.widget-mpris {
padding: 0;
margin: 5px 15px;
margin: 5px 0px;
border-radius: var(--window-radius);
box-shadow: 0px 0px 10px var(--headerbar-shade-color);
border: 1px solid var(--border-color);
......
/* Floating notifications window */
.floating-notifications {
background: transparent;
.notification {
box-shadow: none;
}
}
/* Close button (shared) */
.close-button {
background: unquote("alpha(var(--window-bg-color), 0.6)");
color: var(--window-fg-color);
text-shadow: none;
padding: 0;
border-radius: 100%;
margin-top: 5px;
margin-right: 5px;
box-shadow: none;
border: 1px solid var(--border-color);
min-width: 24px;
min-height: 24px;
&:hover {
box-shadow: none;
background: unquote("alpha(var(--window-bg-color), 0.4)");
transition: var(--hover-tranistion);
}
}
/* Single notification */
.notification-row {
background: none;
outline: none;
&:focus {
background: none;
}
}
.notification-background {
padding: 5px 0;
}
.notification {
border-radius: var(--window-radius);
border: 1px solid var(--border-color);
padding: 10px;
transition: var(--hover-tranistion);
background: var(--dialog-bg-color);
box-shadow: 0 0 5px 0 var(--headerbar-shade-color);
&.low {
border-left: 4px solid var(--success-bg-color);
}
&.normal {
border-left: 4px solid var(--blue-3);
}
&.critical {
border-left: 4px solid var(--error-bg-color);
}
.notification-default-action {
padding: 0;
margin: 0;
box-shadow: none;
background: transparent;
border: none;
color: var(--window-fg-color);
}
.notification-content {
background: transparent;
border-radius: var(--window-radius);
padding: 0;
.image {
-gtk-icon-filter: none;
-gtk-icon-size: var(--notification-icon-size);
border-radius: var(--window-radius);
margin: 0px 5px 0px 0px;
}
.app-icon {
-gtk-icon-filter: none;
-gtk-icon-size: var(--notification-app-icon-size);
-gtk-icon-shadow: 0 1px 4px black;
margin: 6px;
}
.text-box {
label {
filter: none;
}
.summary {
font-weight: bold;
background: transparent;
color: var(--window-fg-color);
text-shadow: none;
}
.time {
font-weight: bold;
color: var(--window-fg-color);
text-shadow: none;
}
.body {
font-weight: normal;
color: var(--window-fg-color);
}
}
.inline-reply {
.inline-reply-entry {
background: unquote("alpha(var(--window-bg-color), 0.4)");
color: var(--window-fg-color);
caret-color: var(--window-fg-color);
border: 1px solid var(--border-color);
border-radius: var(--window-radius);
}
.inline-reply-button {
margin-left: 5px;
background: unquote("alpha(var(--window-bg-color), 0.4)");
border: 1px solid var(--border-color);
border-radius: var(--window-radius);
color: var(--window-fg-color);
&:disabled {
background: initial;
color: unquote("alpha(var(--window-fg-color), 0.5)");
border-color: transparent;
}
&:hover {
background: unquote("alpha(var(--window-bg-color), 0.2)");
}
}
}
}
.notification-alt-actions .notification-action {
margin-top: 10px;
padding: 0;
background: transparent;
}
.notification-action > button {
border-radius: var(--window-radius);
color: var(--window-fg-color);
background: unquote("alpha(var(--window-bg-color), 0.4)");
border: 1px solid var(--border-color);
&:hover {
background: unquote("alpha(var(--window-bg-color), 0.2)");
border: 2px solid var(--accent-bg-color);
}
}
}
/* Notification group (control center only) */
.notification-group {
transition: opacity 200ms ease-in-out;
&:focus {
background: none;
}
.notification-group-close-button .close-button {
background: unquote("alpha(var(--window-bg-color), 0.4)");
box-shadow: 0 0 5px 0 var(--headerbar-shade-color);
margin-top: 10px;
margin-right: 7px;
&:hover {
background: unquote("alpha(var(--window-bg-color), 0.8)");
}
}
.notification-group-headers,
.notification-group-buttons {
margin: 0;
color: var(--window-fg-color);
}
.notification-group-headers {
.notification-group-icon {
-gtk-icon-size: var(--notification-group-icon-size);
}
.notification-group-header {
font-size: 1.5rem;
}
}
.notification-group-buttons {
padding: 0;
}
&.collapsed {
&.not-expanded {
opacity: 0.4;
}
.notification-row:not(:last-child) {
.notification {
background-color: var(--window-bg-color);
}
.notification-action,
.notification-default-action {
opacity: 0;
}
.notification.low {
border-left: 3px solid
unquote("alpha(var(--success-bg-color), 0.5)");
}
.notification.normal {
border-left: 3px solid
unquote("alpha(var(--blue-3), 0.5)");
}
.notification.critical {
border-left: 3px solid
unquote("alpha(var(--error-bg-color), 0.5)");
}
}
&:hover {
.notification-row:not(:only-child) {
.notification {
background-color: var(--dialog-bg-color);
}
}
}
}
}
/* Notification list in control center */
.control-center .control-center-list {
background: transparent;
margin: 0;
.notification {
&:hover {
background: unquote("alpha(var(--window-fg-color), 0.15)");
}
.notification-default-action,
.notification-action {
transition: var(--group-collapse-tranistion),
var(--hover-tranistion);
}
}
}
/* Notifications header */
.notifications-header {
background: transparent;
margin: 10px 0px;
& > label {
font-size: 1.3rem;
}
& > button {
background: var(--dialog-bg-color);
border-radius: 999px;
font-size: 0.9rem;
border: 1px solid var(--border-color);
&:hover {
background: unquote("alpha(var(--dialog-bg-color), 0.5)");
border: 1px solid var(--accent-bg-color);
}
}
}
.widget-quick-settings {
padding: 0;
margin: 5px 15px;
margin: 5px 0px;
}
.quick-settings-row {
......@@ -60,7 +60,7 @@
}
.quick-settings-submenu {
border-radius: var(--border-radius);
border-radius: var(--window-radius);
margin: 5px 0;
padding: 4px 0;
background: var(--dialog-bg-color);
......
.widget-title {
background: transparent;
padding: 0px;
margin: 10px 15px;
&>label {
font-size: 1.5rem;
margin-right: $margin;
}
&>button {
background: var(--dialog-bg-color);
border-radius: 999px;
border: 1px solid var(--border-color);
margin-left: $margin;
&:hover {
background: unquote("alpha(var(--dialog-bg-color), 0.5)");
border: 1px solid var(--accent-bg-color);
}
}
}
.widget-volume {
padding: 0;
margin: 5px 15px;
margin: 5px 0px;
border-radius: var(--window-radius);
&.expanded {
......@@ -9,27 +9,25 @@
border: 1px solid var(--border-color);
}
&>box {
& > box {
padding: 0 10px;
margin: 0 0 0 3px;
}
}
.widget-volume .image-button {
background: transparent;
.image-button {
background: transparent;
}
}
.widget-volume>box>button {}
.per-app-volume {
background: transparent;
padding: 0 10px;
margin: 0;
border-radius: var(--border-radius);
}
border-radius: var(--window-radius);
.per-app-volume row {
background: transparent;
row {
background: transparent;
}
}
.sink-selector {
......
......@@ -4,59 +4,54 @@ template $XimperShellNotificationCenterWidgetsNotifications: $XimperShellNotific
orientation: vertical;
overflow: hidden;
Stack stack {
hhomogeneous: true;
vhomogeneous: true;
transition-type: crossfade;
transition-duration: 200;
vexpand: true;
StackPage {
name: "notifications-list";
child: ScrolledWindow scrolled_window {
hscrollbar-policy: never;
has-frame: false;
Box header_box {
visible: false;
child: Viewport viewport {
vexpand: true;
styles ["notifications-header"]
child: ListBox list_box {
valign: fill;
styles [
"control-center-list",
]
};
};
};
Label title_label {
label: _("Notifications");
hexpand: true;
halign: start;
}
StackPage {
name: "notifications-placeholder";
Button clear_all_button {
can-focus: false;
valign: center;
clicked => $on_clear_all_clicked();
child: Box {
halign: center;
valign: center;
hexpand: true;
vexpand: true;
orientation: vertical;
spacing: 12;
styles ["control-center-clear-all"]
styles [
"control-center-list-placeholder",
]
Box {
orientation: horizontal;
spacing: 10;
Image {
pixel-size: 96;
icon-name: "preferences-system-notifications-symbolic";
use-fallback: true;
icon-name: "edit-clear-all-symbolic";
}
Label text_empty_label {
label: _("No Notifications");
Label {
label: _("Clear All");
}
};
}
}
}
ScrolledWindow scrolled_window {
hscrollbar-policy: never;
has-frame: false;
vexpand: true;
child: Viewport viewport {
vexpand: true;
child: ListBox list_box {
valign: fill;
styles [
"control-center-list",
]
};
};
}
}
using Gtk 4.0;
template $XimperShellNotificationCenterWidgetsTitle:
$XimperShellNotificationCenterWidgetsBaseWidget {
Label title_widget {
hexpand: true;
halign: start;
}
Button clear_all_button {
can-focus: false;
valign: center;
clicked => $on_clear_all_clicked();
styles ["control-center-clear-all"]
Box {
orientation: horizontal;
spacing: 10;
Image {
icon-name: "edit-clear-all-symbolic";
}
Label {
label: _("Clear All");
}
}
}
}
......@@ -16,7 +16,7 @@
<file preprocess="xml-stripblanks">ui/widgets/mpris_player.ui</file>
<file preprocess="xml-stripblanks">ui/widgets/notifications.ui</file>
<file preprocess="xml-stripblanks">ui/widgets/label.ui</file>
<file preprocess="xml-stripblanks">ui/widgets/title.ui</file>
<file preprocess="xml-stripblanks">ui/widgets/inhibitors.ui</file>
<file preprocess="xml-stripblanks">ui/widgets/volume.ui</file>
<file preprocess="xml-stripblanks">ui/widgets/backlight.ui</file>
......
......@@ -166,10 +166,6 @@ config file to be able to detect config errors
default: true ++
description: Hides the control center when clicking on notification action
*text-empty* ++
type: string ++
default: "No Notifications" ++
description: Text that appears when there are no notifications to show
*fit-to-screen* ++
type: bool ++
......@@ -323,12 +319,9 @@ config file to be able to detect config errors
*widgets* ++
type: array ++
Default values: ["inhibitors", "title", "notifications"] ++
Default values: ["notifications"] ++
Valid array values (see *widget-config* for more information): ++
*notifications*++
required: true ++
optional: false ++
*title*++
optional: true ++
*label*++
optional: true ++
......@@ -350,14 +343,13 @@ config file to be able to detect config errors
will be placed at the bottom. ++
multiple of same widget: ++
Append a # with any value to the end of the widget name. ++
Example: "title#TheMainTitle" ++
To address this widget specifically in the css file use the css class .TheMainTitle ++
Example: "label#MyLabel" ++
To address this widget specifically in the css file use the css class .MyLabel ++
example:
```
{
"widgets": [
"inhibitors",
"title",
"notifications"
]
}
......@@ -368,35 +360,24 @@ config file to be able to detect config errors
description: Configure specific widget properties. ++
multiple of same widget: ++
Append a # with any value to the end of the widget name. ++
Example: "title#TheMainTitle" ++
To address this widget specifically in the css file use the css class .TheMainTitle ++
Example: "label#MyLabel" ++
To address this widget specifically in the css file use the css class .MyLabel ++
Widgets to customize: ++
*notifications*++
type: object ++
css class: widget-notifications ++
properties: ++
vexpand: ++
type: bool ++
optional: true ++
default: true ++
description: Whether or not the notifications widget ++
should vertically expand or not ++
description: The Notifications Widget. ++
*title*++
type: object ++
css class: widget-title ++
properties: ++
text: ++
show-title: ++
type: string ++
optional: true ++
default: "Notifications" ++
description: The title of the widget ++
clear-all-button: ++
type: bool ++
optional: true ++
default: true ++
description: Whether to display a "Clear All" button ++
description: The notification visibility state. ++
default: "auto" ++
enum: auto, true, false ++
description: Title bar visibility. ++
auto: show when notifications exist. ++
true: always visible. ++
false: hidden, only clear button ++
shown when notifications exist. ++
description: The Notifications Widget. ++
*label*++
type: object ++
css class: widget-label ++
......@@ -550,9 +531,8 @@ config file to be able to detect config errors
```
{
"widget-config": {
"title": {
"text": "Notifications",
"clear-all-button": true
"notifications": {
"show-title": "auto"
},
"label": {
"max-lines": 5,
......
src/main.vala
src/notification/notification.vala
src/controlCenter/widgets/title/title.vala
src/controlCenter/widgets/inhibitors/inhibitors.vala
src/controlCenter/widgets/volume/volume.vala
src/controlCenter/widgets/backlight/backlight.vala
......@@ -15,6 +14,5 @@ src/controlCenter/widgets/quickSettings/tiles/wifiTile.vala
src/controlCenter/widgets/quickSettings/tiles/vpnTile.vala
src/controlCenter/widgets/quickSettings/tiles/bluetoothTile.vala
data/ui/widgets/notifications.blp
data/ui/widgets/title.blp
data/ui/widgets/inhibitors.blp
data/ui/widgets/backlight.blp
......@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: ximper-shell-notification-center 0.1.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-03-26 22:05+0300\n"
"POT-Creation-Date: 2026-03-27 20:18+0300\n"
"PO-Revision-Date: 2026-03-24 00:00+0300\n"
"Last-Translator: \n"
"Language-Team: Russian\n"
......@@ -59,10 +59,6 @@ msgstr[0] "%d д. назад"
msgstr[1] "%d д. назад"
msgstr[2] "%d д. назад"
#: src/controlCenter/widgets/title/title.vala:21
msgid "Notifications"
msgstr "Уведомления"
#: src/controlCenter/widgets/inhibitors/inhibitors.vala:21
msgid "Inhibitors"
msgstr "Блокировки"
......@@ -158,11 +154,11 @@ msgstr "Отключить"
msgid "Bluetooth Settings"
msgstr "Настройки Bluetooth"
#: data/ui/widgets/notifications.blp:57
msgid "No Notifications"
msgstr "Нет уведомлений"
#: data/ui/widgets/notifications.blp:13
msgid "Notifications"
msgstr "Уведомления"
#: data/ui/widgets/title.blp:27 data/ui/widgets/inhibitors.blp:25
#: data/ui/widgets/notifications.blp:34 data/ui/widgets/inhibitors.blp:25
msgid "Clear All"
msgstr "Очистить"
......@@ -170,5 +166,8 @@ msgstr "Очистить"
msgid "Brightness"
msgstr "Яркость"
#~ msgid "No Notifications"
#~ msgstr "Нет уведомлений"
#~ msgid "No active sink input"
#~ msgstr "Нет активного источника"
......@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: ximper-shell-notification-center\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-03-26 22:05+0300\n"
"POT-Creation-Date: 2026-03-27 20:18+0300\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
......@@ -56,10 +56,6 @@ msgid_plural "%d days ago"
msgstr[0] ""
msgstr[1] ""
#: src/controlCenter/widgets/title/title.vala:21
msgid "Notifications"
msgstr ""
#: src/controlCenter/widgets/inhibitors/inhibitors.vala:21
msgid "Inhibitors"
msgstr ""
......@@ -155,11 +151,11 @@ msgstr ""
msgid "Bluetooth Settings"
msgstr ""
#: data/ui/widgets/notifications.blp:57
msgid "No Notifications"
#: data/ui/widgets/notifications.blp:13
msgid "Notifications"
msgstr ""
#: data/ui/widgets/title.blp:27 data/ui/widgets/inhibitors.blp:25
#: data/ui/widgets/notifications.blp:34 data/ui/widgets/inhibitors.blp:25
msgid "Clear All"
msgstr ""
......
......@@ -32,7 +32,6 @@
"quick-settings",
"inhibitors",
"mpris",
"title",
"notifications"
],
"widget-config": {
......
......@@ -556,8 +556,6 @@ namespace XimperShellNotificationCenter {
/** Hides the control center when clicking on notification action */
public bool hide_on_action { get; set; default = true; }
/** Text that appears when there are no notifications to show */
public string text_empty { get; set; default = "No Notifications"; }
/** The controlcenters horizontal alignment. Supersedes `positionX` if not `NONE` */
public PositionX control_center_positionX { // vala-lint=naming-convention
......
......@@ -203,11 +203,6 @@
"description": "Hides the control center when clicking on notification action",
"default": true
},
"text-empty": {
"type": "string",
"description": "Text that appears when there are no notifications to show",
"default": "No Notifications"
},
"notification-action-filter": {
"type": "object",
"description": "Hides matching action(s) of matching notifications. If the notification doesn't include one of the properties, that property will be ignored. If all properties match the given notification, the matching actions will be hidden.",
......@@ -325,10 +320,6 @@
"$comment": "References the widget structure from \"widgets\" below",
"$ref": "#/widgets/notifications"
},
"^title(#[a-zA-Z0-9_-]{1,}){0,1}?$": {
"$comment": "References the widget structure from \"widgets\" below",
"$ref": "#/widgets/title"
},
"^label(#[a-zA-Z0-9_-]{1,}){0,1}?$": {
"$ref": "#/widgets/label"
},
......@@ -355,30 +346,14 @@
"$comment": "New widgets go here",
"notifications": {
"type": "object",
"description": "Control Center Title Widget",
"description": "Notifications widget with title and clear button",
"additionalProperties": false,
"properties": {
"vexpand": {
"type": "boolean",
"description": "Whether or not the notifications widget should vertically expand or not",
"default": true
}
}
},
"title": {
"type": "object",
"description": "Control Center Title Widget",
"additionalProperties": false,
"properties": {
"text": {
"show-title": {
"type": "string",
"description": "The title of the widget",
"default": "Notifications"
},
"clear-all-button": {
"type": "boolean",
"description": "Whether to display a \"Clear All\" button",
"default": true
"description": "Title bar visibility: auto (show when notifications exist), true (always visible), false (hidden, only clear button shown when notifications exist)",
"default": "auto",
"enum": ["auto", "true", "false"]
}
}
},
......
......@@ -14,7 +14,7 @@ namespace XimperShellNotificationCenter {
/** Unsorted list of copies of all notifications */
private List<unowned Widgets.BaseWidget> widgets;
private const string[] DEFAULT_WIDGETS = { "title", "dnd", "notifications" };
private const string[] DEFAULT_WIDGETS = { "notifications" };
private string ?monitor_name = null;
......
......@@ -16,9 +16,6 @@ namespace XimperShellNotificationCenter.Widgets {
is_notifications = true;
message ("Loading widget: widget-notifications");
return null;
case "title":
widget = new Title (suffix);
break;
case "label":
widget = new Label (suffix);
break;
......
......@@ -10,13 +10,13 @@ namespace XimperShellNotificationCenter.Widgets {
public uint n_notifications { get; private set; default = 0; }
public uint n_groups { get; private set; default = 0; }
const string STACK_NOTIFICATIONS_PAGE = "notifications-list";
const string STACK_PLACEHOLDER_PAGE = "notifications-placeholder";
[GtkChild]
unowned Gtk.Label text_empty_label;
unowned Gtk.Box header_box;
[GtkChild]
unowned Gtk.Stack stack;
unowned Gtk.Label title_label;
[GtkChild]
unowned Gtk.Button clear_all_button;
[GtkChild]
unowned Gtk.ScrolledWindow scrolled_window;
[GtkChild]
......@@ -31,16 +31,19 @@ namespace XimperShellNotificationCenter.Widgets {
}
private uint scroll_timer_id = 0;
private Gee.HashMap<uint32, unowned NotificationGroup> noti_groups_id =
new Gee.HashMap<uint32, unowned NotificationGroup> ();
/** NOTE: Only includes groups with ids with length of > 0 */
private Gee.HashMap<string, unowned NotificationGroup> noti_groups_name =
new Gee.HashMap<string, unowned NotificationGroup> ();
private Gee.HashMap<uint32, unowned NotificationGroup>
noti_groups_id =
new Gee.HashMap<uint32,
unowned NotificationGroup> ();
/** Only includes groups with ids with length > 0 */
private Gee.HashMap<string, unowned NotificationGroup>
noti_groups_name =
new Gee.HashMap<string,
unowned NotificationGroup> ();
private bool list_reverse = false;
// Default config values
bool vertical_expand = true;
string show_title = "auto";
public Notifications () {
base ("");
......@@ -49,14 +52,6 @@ namespace XimperShellNotificationCenter.Widgets {
notify["expanded-group"].connect (expanded_changed);
// TODO: Move this into notifications config!
string empty_text = ConfigModel.instance.text_empty;
text_empty_label.set_text (
empty_text == "No Notifications"
? _("No Notifications") : empty_text);
stack.set_visible_child_name (STACK_PLACEHOLDER_PAGE);
list_box.set_valign (Gtk.Align.START);
reload_config ();
......@@ -94,17 +89,47 @@ namespace XimperShellNotificationCenter.Widgets {
public void reload_config () {
Json.Object ?config = get_config (this);
if (config != null) {
// Get vexpand
bool found_vexpand;
bool ?vexpand = get_prop<bool> (config, "vexpand", out found_vexpand);
if (found_vexpand) {
this.vertical_expand = vexpand;
string ?st = get_prop<string> (
config, "show-title");
if (st != null) {
this.show_title = st;
}
}
set_vexpand (this.vertical_expand);
scrolled_window.set_propagate_natural_height (!this.vertical_expand);
stack.set_vhomogeneous (this.vertical_expand);
bool dynamic =
ConfigModel.instance
.control_center_dynamic_height;
set_vexpand (!dynamic);
scrolled_window.set_propagate_natural_height (
dynamic);
update_header_visibility ();
}
private void update_header_visibility () {
bool has_notis = !is_empty ();
scrolled_window.set_visible (has_notis);
switch (show_title) {
case "true":
header_box.set_visible (true);
title_label.set_visible (true);
clear_all_button.set_sensitive (has_notis);
break;
case "false":
header_box.set_visible (has_notis);
title_label.set_visible (false);
break;
default: // auto
header_box.set_visible (has_notis);
title_label.set_visible (true);
break;
}
}
[GtkCallback]
private void on_clear_all_clicked () {
noti_daemon
.request_dismiss_all_notifications (
ClosedReasons.DISMISSED);
}
public inline bool is_empty () {
......@@ -144,7 +169,7 @@ namespace XimperShellNotificationCenter.Widgets {
if (list_box_controller.length < 1) {
n_notifications = 0;
n_groups = 0;
stack.set_visible_child_name (STACK_PLACEHOLDER_PAGE);
update_header_visibility ();
}
}
......@@ -262,8 +287,6 @@ namespace XimperShellNotificationCenter.Widgets {
noti_groups_name.set (param.name_id, group);
}
stack.set_visible_child_name (STACK_NOTIFICATIONS_PAGE);
list_box_controller.append (group);
n_groups++;
}
......@@ -279,6 +302,7 @@ namespace XimperShellNotificationCenter.Widgets {
n_notifications++;
list_box.invalidate_sort ();
update_header_visibility ();
scroll_to_start ();
}
......
namespace XimperShellNotificationCenter.Widgets {
[GtkTemplate (ui = "/ru/ximperlinux/shell/NotificationCenter/ui/widgets/title.ui")]
public class Title : BaseWidget {
public override string widget_name {
get {
return "title";
}
}
[GtkChild]
unowned Gtk.Label title_widget;
[GtkChild]
unowned Gtk.Button clear_all_button;
// Default config values
string title;
bool has_clear_all_button = true;
public Title (string suffix) {
base (suffix);
title = _("Notifications");
Json.Object ?config = get_config (this);
if (config != null) {
// Get title
string ?title = get_prop<string> (config, "text");
if (title != null) {
this.title = title;
}
// Get has clear-all-button
bool found_clear_all;
bool ?has_clear_all_button = get_prop<bool> (
config, "clear-all-button", out found_clear_all);
if (found_clear_all) {
this.has_clear_all_button = has_clear_all_button;
}
}
title_widget.set_text (title);
clear_all_button.set_visible (
has_clear_all_button
&& notifications_widget != null);
if (notifications_widget != null) {
clear_all_button.set_sensitive (
!notifications_widget.is_empty ());
ximper_shell_notification_center_daemon
.subscribe_v2.connect ((count) => {
clear_all_button.set_sensitive (count > 0);
});
}
}
[GtkCallback]
private void on_clear_all_clicked () {
noti_daemon.request_dismiss_all_notifications (ClosedReasons.DISMISSED);
}
}
}
......@@ -30,8 +30,6 @@ widget_sources = [
'controlCenter/widgets/factory.vala',
# Widget: Notifications
'controlCenter/widgets/notifications/notifications.vala',
# Widget: Title
'controlCenter/widgets/title/title.vala',
# Widget: Label
'controlCenter/widgets/label/label.vala',
# Widget: MPRIS
......
......@@ -139,6 +139,23 @@ namespace XimperShellNotificationCenter {
break;
}
GtkLayerShell.set_margin (this,
GtkLayerShell.Edge.TOP,
ConfigModel.instance
.control_center_margin_top);
GtkLayerShell.set_margin (this,
GtkLayerShell.Edge.BOTTOM,
ConfigModel.instance
.control_center_margin_bottom);
GtkLayerShell.set_margin (this,
GtkLayerShell.Edge.LEFT,
ConfigModel.instance
.control_center_margin_left);
GtkLayerShell.set_margin (this,
GtkLayerShell.Edge.RIGHT,
ConfigModel.instance
.control_center_margin_right);
// Set the preferred monitor
string ?monitor_name = ConfigModel.instance.notification_window_preferred_output;
if (NotificationWindow.monitor_name != null) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment