Added ags
TODO copy ags config
This commit is contained in:
138
roles/ags/files/widget/notifications/Notification.ts
Normal file
138
roles/ags/files/widget/notifications/Notification.ts
Normal file
@@ -0,0 +1,138 @@
|
||||
import { type Notification } from "types/service/notifications"
|
||||
import GLib from "gi://GLib"
|
||||
import icons from "lib/icons"
|
||||
|
||||
const time = (time: number, format = "%H:%M") => GLib.DateTime
|
||||
.new_from_unix_local(time)
|
||||
.format(format)
|
||||
|
||||
const NotificationIcon = ({ app_entry, app_icon, image }: Notification) => {
|
||||
if (image) {
|
||||
return Widget.Box({
|
||||
vpack: "start",
|
||||
hexpand: false,
|
||||
class_name: "icon img",
|
||||
css: `
|
||||
background-image: url("${image}");
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
min-width: 78px;
|
||||
min-height: 78px;
|
||||
`,
|
||||
})
|
||||
}
|
||||
|
||||
let icon = icons.fallback.notification
|
||||
if (Utils.lookUpIcon(app_icon))
|
||||
icon = app_icon
|
||||
|
||||
if (Utils.lookUpIcon(app_entry || ""))
|
||||
icon = app_entry || ""
|
||||
|
||||
return Widget.Box({
|
||||
vpack: "start",
|
||||
hexpand: false,
|
||||
class_name: "icon",
|
||||
css: `
|
||||
min-width: 78px;
|
||||
min-height: 78px;
|
||||
`,
|
||||
child: Widget.Icon({
|
||||
icon,
|
||||
size: 58,
|
||||
hpack: "center", hexpand: true,
|
||||
vpack: "center", vexpand: true,
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
export default (notification: Notification) => {
|
||||
const content = Widget.Box({
|
||||
class_name: "content",
|
||||
children: [
|
||||
NotificationIcon(notification),
|
||||
Widget.Box({
|
||||
hexpand: true,
|
||||
vertical: true,
|
||||
children: [
|
||||
Widget.Box({
|
||||
children: [
|
||||
Widget.Label({
|
||||
class_name: "title",
|
||||
xalign: 0,
|
||||
justification: "left",
|
||||
hexpand: true,
|
||||
max_width_chars: 24,
|
||||
truncate: "end",
|
||||
wrap: true,
|
||||
label: notification.summary.trim(),
|
||||
use_markup: true,
|
||||
}),
|
||||
Widget.Label({
|
||||
class_name: "time",
|
||||
vpack: "start",
|
||||
label: time(notification.time),
|
||||
}),
|
||||
Widget.Button({
|
||||
class_name: "close-button",
|
||||
vpack: "start",
|
||||
child: Widget.Icon("window-close-symbolic"),
|
||||
on_clicked: notification.close,
|
||||
}),
|
||||
],
|
||||
}),
|
||||
Widget.Label({
|
||||
class_name: "description",
|
||||
hexpand: true,
|
||||
use_markup: true,
|
||||
xalign: 0,
|
||||
justification: "left",
|
||||
label: notification.body.trim(),
|
||||
max_width_chars: 24,
|
||||
wrap: true,
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
})
|
||||
|
||||
const actionsbox = notification.actions.length > 0 ? Widget.Revealer({
|
||||
transition: "slide_down",
|
||||
child: Widget.EventBox({
|
||||
child: Widget.Box({
|
||||
class_name: "actions horizontal",
|
||||
children: notification.actions.map(action => Widget.Button({
|
||||
class_name: "action-button",
|
||||
on_clicked: () => notification.invoke(action.id),
|
||||
hexpand: true,
|
||||
child: Widget.Label(action.label),
|
||||
})),
|
||||
}),
|
||||
}),
|
||||
}) : null
|
||||
|
||||
const eventbox = Widget.EventBox({
|
||||
vexpand: false,
|
||||
on_primary_click: notification.dismiss,
|
||||
on_hover() {
|
||||
if (actionsbox)
|
||||
actionsbox.reveal_child = true
|
||||
},
|
||||
on_hover_lost() {
|
||||
if (actionsbox)
|
||||
actionsbox.reveal_child = true
|
||||
|
||||
notification.dismiss()
|
||||
},
|
||||
child: Widget.Box({
|
||||
vertical: true,
|
||||
children: actionsbox ? [content, actionsbox] : [content],
|
||||
}),
|
||||
})
|
||||
|
||||
return Widget.Box({
|
||||
class_name: `notification ${notification.urgency}`,
|
||||
child: eventbox,
|
||||
})
|
||||
}
|
||||
90
roles/ags/files/widget/notifications/NotificationPopups.ts
Normal file
90
roles/ags/files/widget/notifications/NotificationPopups.ts
Normal file
@@ -0,0 +1,90 @@
|
||||
import Notification from "./Notification"
|
||||
import options from "options"
|
||||
|
||||
const notifications = await Service.import("notifications")
|
||||
const { transition } = options
|
||||
const { position } = options.notifications
|
||||
const { timeout, idle } = Utils
|
||||
|
||||
function Animated(id: number) {
|
||||
const n = notifications.getNotification(id)!
|
||||
const widget = Notification(n)
|
||||
|
||||
const inner = Widget.Revealer({
|
||||
transition: "slide_left",
|
||||
transition_duration: transition.value,
|
||||
child: widget,
|
||||
})
|
||||
|
||||
const outer = Widget.Revealer({
|
||||
transition: "slide_down",
|
||||
transition_duration: transition.value,
|
||||
child: inner,
|
||||
})
|
||||
|
||||
const box = Widget.Box({
|
||||
hpack: "end",
|
||||
child: outer,
|
||||
})
|
||||
|
||||
idle(() => {
|
||||
outer.reveal_child = true
|
||||
timeout(transition.value, () => {
|
||||
inner.reveal_child = true
|
||||
})
|
||||
})
|
||||
|
||||
return Object.assign(box, {
|
||||
dismiss() {
|
||||
inner.reveal_child = false
|
||||
timeout(transition.value, () => {
|
||||
outer.reveal_child = false
|
||||
timeout(transition.value, () => {
|
||||
box.destroy()
|
||||
})
|
||||
})
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
function PopupList() {
|
||||
const map: Map<number, ReturnType<typeof Animated>> = new Map
|
||||
const box = Widget.Box({
|
||||
hpack: "end",
|
||||
vertical: true,
|
||||
css: options.notifications.width.bind().as(w => `min-width: ${w}px;`),
|
||||
})
|
||||
|
||||
function remove(_: unknown, id: number) {
|
||||
map.get(id)?.dismiss()
|
||||
map.delete(id)
|
||||
}
|
||||
|
||||
return box
|
||||
.hook(notifications, (_, id: number) => {
|
||||
if (id !== undefined) {
|
||||
if (map.has(id))
|
||||
remove(null, id)
|
||||
|
||||
if (notifications.dnd)
|
||||
return
|
||||
|
||||
const w = Animated(id)
|
||||
map.set(id, w)
|
||||
box.children = [w, ...box.children]
|
||||
}
|
||||
}, "notified")
|
||||
.hook(notifications, remove, "dismissed")
|
||||
.hook(notifications, remove, "closed")
|
||||
}
|
||||
|
||||
export default (monitor: number) => Widget.Window({
|
||||
monitor,
|
||||
name: `notifications${monitor}`,
|
||||
anchor: position.bind(),
|
||||
class_name: "notifications",
|
||||
child: Widget.Box({
|
||||
css: "padding: 2px;",
|
||||
child: PopupList(),
|
||||
}),
|
||||
})
|
||||
79
roles/ags/files/widget/notifications/notifications.scss
Normal file
79
roles/ags/files/widget/notifications/notifications.scss
Normal file
@@ -0,0 +1,79 @@
|
||||
@mixin notification() {
|
||||
&.critical {
|
||||
box-shadow: inset 0 0 .5em 0 $error-bg;
|
||||
}
|
||||
|
||||
&:hover button.close-button {
|
||||
@include button-hover;
|
||||
background-color: transparentize($error-bg, .5);
|
||||
}
|
||||
|
||||
.content {
|
||||
.title {
|
||||
margin-right: $spacing;
|
||||
color: $fg;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
.time {
|
||||
color: transparentize($fg, .2);
|
||||
}
|
||||
|
||||
.description {
|
||||
font-size: .9em;
|
||||
color: transparentize($fg, .2);
|
||||
}
|
||||
|
||||
.icon {
|
||||
border-radius: $radius*0.8;
|
||||
margin-right: $spacing;
|
||||
|
||||
&.img {
|
||||
border: $border;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
box.actions {
|
||||
@include spacing(0.5);
|
||||
margin-top: $spacing;
|
||||
|
||||
button {
|
||||
@include button;
|
||||
border-radius: $radius*0.8;
|
||||
font-size: 1.2em;
|
||||
padding: $padding * 0.7;
|
||||
}
|
||||
}
|
||||
|
||||
button.close-button {
|
||||
@include button($flat: true);
|
||||
margin-left: $spacing / 2;
|
||||
border-radius: $radius*0.8;
|
||||
min-width: 1.2em;
|
||||
min-height: 1.2em;
|
||||
|
||||
&:hover {
|
||||
background-color: transparentize($error-bg, .2);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-image: none;
|
||||
background-color: $error-bg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
window.notifications {
|
||||
@include unset;
|
||||
|
||||
.notification {
|
||||
@include notification;
|
||||
@include floating-widget;
|
||||
border-radius: $radius;
|
||||
|
||||
.description {
|
||||
min-width: 350px;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user