Convert all remaining files to typescript.
This commit is contained in:
@@ -1,41 +0,0 @@
|
|||||||
import Service from "resource:///com/github/Aylur/ags/service.js";
|
|
||||||
import App from "resource:///com/github/Aylur/ags/app.js";
|
|
||||||
import { monitorFile } from "resource:///com/github/Aylur/ags/utils.js";
|
|
||||||
import Gio from "gi://Gio";
|
|
||||||
|
|
||||||
class DirectoryMonitorService extends Service {
|
|
||||||
static {
|
|
||||||
Service.register(this, {}, {});
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
this.recursiveDirectoryMonitor(`${App.configDir}/scss`);
|
|
||||||
}
|
|
||||||
|
|
||||||
recursiveDirectoryMonitor(directoryPath) {
|
|
||||||
monitorFile(directoryPath, (_, eventType) => {
|
|
||||||
if (eventType === Gio.FileMonitorEvent.CHANGES_DONE_HINT) {
|
|
||||||
this.emit("changed");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const directory = Gio.File.new_for_path(directoryPath);
|
|
||||||
const enumerator = directory.enumerate_children(
|
|
||||||
"standard::*",
|
|
||||||
Gio.FileQueryInfoFlags.NONE,
|
|
||||||
null,
|
|
||||||
);
|
|
||||||
|
|
||||||
let fileInfo;
|
|
||||||
while ((fileInfo = enumerator.next_file(null)) !== null) {
|
|
||||||
const childPath = directoryPath + "/" + fileInfo.get_name();
|
|
||||||
if (fileInfo.get_file_type() === Gio.FileType.DIRECTORY) {
|
|
||||||
this.recursiveDirectoryMonitor(childPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const service = new DirectoryMonitorService();
|
|
||||||
export default service;
|
|
||||||
42
directoryMonitorService.ts
Normal file
42
directoryMonitorService.ts
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
import Service from "resource:///com/github/Aylur/ags/service.js";
|
||||||
|
import App from "resource:///com/github/Aylur/ags/app.js";
|
||||||
|
import { monitorFile } from "resource:///com/github/Aylur/ags/utils.js";
|
||||||
|
import Gio from "gi://Gio";
|
||||||
|
import { FileInfo } from "types/@girs/gio-2.0/gio-2.0.cjs";
|
||||||
|
|
||||||
|
class DirectoryMonitorService extends Service {
|
||||||
|
static {
|
||||||
|
Service.register(this, {}, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.recursiveDirectoryMonitor(`${App.configDir}/scss`);
|
||||||
|
}
|
||||||
|
|
||||||
|
recursiveDirectoryMonitor(directoryPath: string) {
|
||||||
|
monitorFile(directoryPath, (_, eventType) => {
|
||||||
|
if (eventType === Gio.FileMonitorEvent.CHANGES_DONE_HINT) {
|
||||||
|
this.emit("changed");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const directory = Gio.File.new_for_path(directoryPath);
|
||||||
|
const enumerator = directory.enumerate_children(
|
||||||
|
"standard::*",
|
||||||
|
Gio.FileQueryInfoFlags.NONE,
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
|
||||||
|
let fileInfo: FileInfo;
|
||||||
|
while ((fileInfo = enumerator.next_file(null) as FileInfo) !== null) {
|
||||||
|
const childPath = directoryPath + "/" + fileInfo.get_name();
|
||||||
|
if (fileInfo.get_file_type() === Gio.FileType.DIRECTORY) {
|
||||||
|
this.recursiveDirectoryMonitor(childPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const service = new DirectoryMonitorService();
|
||||||
|
export default service;
|
||||||
25
lib/types/gpustat.d.ts
vendored
Normal file
25
lib/types/gpustat.d.ts
vendored
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
export type GPU_Stat_Process = {
|
||||||
|
username: string;
|
||||||
|
command: string;
|
||||||
|
full_command: string[];
|
||||||
|
gpu_memory_usage: number;
|
||||||
|
cpu_percent: number;
|
||||||
|
cpu_memory_usage: number;
|
||||||
|
pid: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type GPU_Stat = {
|
||||||
|
index: number;
|
||||||
|
uuid: string;
|
||||||
|
name: string;
|
||||||
|
"temperature.gpu": number;
|
||||||
|
"fan.speed": number;
|
||||||
|
"utilization.gpu": number;
|
||||||
|
"utilization.enc": number;
|
||||||
|
"utilization.dec": number;
|
||||||
|
"power.draw": number;
|
||||||
|
"enforced.power.limit": number;
|
||||||
|
"memory.used": number;
|
||||||
|
"memory.total": number;
|
||||||
|
processes: Process[];
|
||||||
|
};
|
||||||
10
lib/types/network.d.ts
vendored
Normal file
10
lib/types/network.d.ts
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
export type AccessPoint = {
|
||||||
|
bssid: string | null;
|
||||||
|
address: string | null;
|
||||||
|
lastSeen: number;
|
||||||
|
ssid: string | null;
|
||||||
|
active: boolean;
|
||||||
|
strength: number;
|
||||||
|
frequency: number;
|
||||||
|
iconName: string | undefined;
|
||||||
|
}
|
||||||
2
lib/types/options.d.ts
vendored
2
lib/types/options.d.ts
vendored
@@ -1 +1,3 @@
|
|||||||
export type Unit = "imperial" | "metric";
|
export type Unit = "imperial" | "metric";
|
||||||
|
export type PowerOptions = "sleep" | "reboot" | "logout" | "shutdown";
|
||||||
|
export type NotificationAnchor = "top" | "top right" | "top left" | "bottom" | "bottom right" | "bottom left";
|
||||||
|
|||||||
1
lib/types/power.d.ts
vendored
Normal file
1
lib/types/power.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export type Action = "sleep" | "reboot" | "logout" | "shutdown";
|
||||||
3
lib/types/widget.d.ts
vendored
Normal file
3
lib/types/widget.d.ts
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export type Exclusivity = 'normal' | 'ignore' | 'exclusive';
|
||||||
|
export type Anchor = "left" | "right" | "top" | "down";
|
||||||
|
export type Transition = "none" | "crossfade" | "slide_right" | "slide_left" | "slide_up" | "slide_down";
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
const hyprland = await Service.import("hyprland");
|
const hyprland = await Service.import("hyprland");
|
||||||
import { globalMousePos } from "globals";
|
import { globalMousePos } from "globals";
|
||||||
|
import { Exclusivity } from "lib/types/widget";
|
||||||
|
|
||||||
export const Padding = (name) =>
|
export const Padding = (name: string) =>
|
||||||
Widget.EventBox({
|
Widget.EventBox({
|
||||||
hexpand: true,
|
hexpand: true,
|
||||||
vexpand: true,
|
vexpand: true,
|
||||||
@@ -10,7 +11,7 @@ export const Padding = (name) =>
|
|||||||
setup: (w) => w.on("button-press-event", () => App.toggleWindow(name)),
|
setup: (w) => w.on("button-press-event", () => App.toggleWindow(name)),
|
||||||
});
|
});
|
||||||
|
|
||||||
const moveBoxToCursor = (self, fixed) => {
|
const moveBoxToCursor = (self: any, fixed: boolean) => {
|
||||||
if (fixed) {
|
if (fixed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -77,7 +78,7 @@ export default ({
|
|||||||
child,
|
child,
|
||||||
layout = "center",
|
layout = "center",
|
||||||
transition,
|
transition,
|
||||||
exclusivity = "ignore",
|
exclusivity = "ignore" as Exclusivity,
|
||||||
fixed = false,
|
fixed = false,
|
||||||
...props
|
...props
|
||||||
}) =>
|
}) =>
|
||||||
@@ -1,165 +0,0 @@
|
|||||||
export const Padding = (name, opts = {}) =>
|
|
||||||
Widget.EventBox({
|
|
||||||
class_name: opts?.className || "",
|
|
||||||
hexpand: true,
|
|
||||||
vexpand: typeof opts?.vexpand === "boolean" ? opts.vexpand : true,
|
|
||||||
can_focus: false,
|
|
||||||
child: Widget.Box(),
|
|
||||||
setup: (w) => w.on("button-press-event", () => App.toggleWindow(name)),
|
|
||||||
});
|
|
||||||
|
|
||||||
const PopupRevealer = (name, child, transition = "slide_down") =>
|
|
||||||
Widget.Box(
|
|
||||||
{ css: "padding: 1px;" },
|
|
||||||
Widget.Revealer({
|
|
||||||
transition,
|
|
||||||
child: Widget.Box({
|
|
||||||
class_name: `window-content ${name}-window`,
|
|
||||||
child,
|
|
||||||
}),
|
|
||||||
transitionDuration: 200,
|
|
||||||
setup: (self) =>
|
|
||||||
self.hook(App, (_, wname, visible) => {
|
|
||||||
if (wname === name) self.reveal_child = visible;
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
const Layout = (name, child, transition) => ({
|
|
||||||
center: () =>
|
|
||||||
Widget.CenterBox(
|
|
||||||
{},
|
|
||||||
Padding(name),
|
|
||||||
Widget.CenterBox(
|
|
||||||
{ vertical: true },
|
|
||||||
Padding(name),
|
|
||||||
PopupRevealer(name, child, transition),
|
|
||||||
Padding(name),
|
|
||||||
),
|
|
||||||
Padding(name),
|
|
||||||
),
|
|
||||||
top: () =>
|
|
||||||
Widget.CenterBox(
|
|
||||||
{},
|
|
||||||
Padding(name),
|
|
||||||
Widget.Box(
|
|
||||||
{ vertical: true },
|
|
||||||
PopupRevealer(name, child, transition),
|
|
||||||
Padding(name),
|
|
||||||
),
|
|
||||||
Padding(name),
|
|
||||||
),
|
|
||||||
"top-right": () =>
|
|
||||||
Widget.Box(
|
|
||||||
{},
|
|
||||||
Padding(name),
|
|
||||||
Widget.Box(
|
|
||||||
{
|
|
||||||
hexpand: false,
|
|
||||||
vertical: true,
|
|
||||||
},
|
|
||||||
Padding(name, {
|
|
||||||
vexpand: false,
|
|
||||||
className: "event-top-padding",
|
|
||||||
}),
|
|
||||||
PopupRevealer(name, child, transition),
|
|
||||||
Padding(name),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
"top-center": () =>
|
|
||||||
Widget.Box(
|
|
||||||
{},
|
|
||||||
Padding(name),
|
|
||||||
Widget.Box(
|
|
||||||
{
|
|
||||||
hexpand: false,
|
|
||||||
vertical: true,
|
|
||||||
},
|
|
||||||
Padding(name, {
|
|
||||||
vexpand: false,
|
|
||||||
className: "event-top-padding",
|
|
||||||
}),
|
|
||||||
PopupRevealer(name, child, transition),
|
|
||||||
Padding(name),
|
|
||||||
),
|
|
||||||
Padding(name),
|
|
||||||
),
|
|
||||||
"top-left": () =>
|
|
||||||
Widget.Box(
|
|
||||||
{},
|
|
||||||
Widget.Box(
|
|
||||||
{
|
|
||||||
hexpand: false,
|
|
||||||
vertical: true,
|
|
||||||
},
|
|
||||||
Padding(name, {
|
|
||||||
vexpand: false,
|
|
||||||
className: "event-top-padding",
|
|
||||||
}),
|
|
||||||
PopupRevealer(name, child, transition),
|
|
||||||
Padding(name),
|
|
||||||
),
|
|
||||||
Padding(name),
|
|
||||||
),
|
|
||||||
"bottom-left": () =>
|
|
||||||
Widget.Box(
|
|
||||||
{},
|
|
||||||
Widget.Box(
|
|
||||||
{
|
|
||||||
hexpand: false,
|
|
||||||
vertical: true,
|
|
||||||
},
|
|
||||||
Padding(name),
|
|
||||||
PopupRevealer(name, child, transition),
|
|
||||||
),
|
|
||||||
Padding(name),
|
|
||||||
),
|
|
||||||
"bottom-center": () =>
|
|
||||||
Widget.Box(
|
|
||||||
{},
|
|
||||||
Padding(name),
|
|
||||||
Widget.Box(
|
|
||||||
{
|
|
||||||
hexpand: false,
|
|
||||||
vertical: true,
|
|
||||||
},
|
|
||||||
Padding(name),
|
|
||||||
PopupRevealer(name, child, transition),
|
|
||||||
),
|
|
||||||
Padding(name),
|
|
||||||
),
|
|
||||||
"bottom-right": () =>
|
|
||||||
Widget.Box(
|
|
||||||
{},
|
|
||||||
Padding(name),
|
|
||||||
Widget.Box(
|
|
||||||
{
|
|
||||||
hexpand: false,
|
|
||||||
vertical: true,
|
|
||||||
},
|
|
||||||
Padding(name),
|
|
||||||
PopupRevealer(name, child, transition),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
});
|
|
||||||
|
|
||||||
export default ({
|
|
||||||
name,
|
|
||||||
child,
|
|
||||||
layout = "center",
|
|
||||||
transition,
|
|
||||||
exclusivity = "ignore",
|
|
||||||
...props
|
|
||||||
}) =>
|
|
||||||
Widget.Window({
|
|
||||||
name,
|
|
||||||
class_names: [name, "popup-window"],
|
|
||||||
setup: (w) => w.keybind("Escape", () => App.closeWindow(name)),
|
|
||||||
visible: false,
|
|
||||||
keymode: "on-demand",
|
|
||||||
exclusivity,
|
|
||||||
layer: "top",
|
|
||||||
anchor: ["top", "bottom", "right", "left"],
|
|
||||||
child: Layout(name, child, transition)[layout](),
|
|
||||||
...props,
|
|
||||||
});
|
|
||||||
172
modules/menus/PopupWindow.ts
Normal file
172
modules/menus/PopupWindow.ts
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
import { Exclusivity, Transition } from "lib/types/widget";
|
||||||
|
|
||||||
|
type Opts = {
|
||||||
|
className: string
|
||||||
|
vexpand: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Padding = (name: string, opts: Opts) =>
|
||||||
|
Widget.EventBox({
|
||||||
|
class_name: opts?.className || "",
|
||||||
|
hexpand: true,
|
||||||
|
vexpand: typeof opts?.vexpand === "boolean" ? opts.vexpand : true,
|
||||||
|
can_focus: false,
|
||||||
|
child: Widget.Box(),
|
||||||
|
setup: (w) => w.on("button-press-event", () => App.toggleWindow(name)),
|
||||||
|
});
|
||||||
|
|
||||||
|
const PopupRevealer = (name: string, child: any, transition = "slide_down" as Transition) =>
|
||||||
|
Widget.Box(
|
||||||
|
{ css: "padding: 1px;" },
|
||||||
|
Widget.Revealer({
|
||||||
|
transition,
|
||||||
|
child: Widget.Box({
|
||||||
|
class_name: `window-content ${name}-window`,
|
||||||
|
child,
|
||||||
|
}),
|
||||||
|
transitionDuration: 200,
|
||||||
|
setup: (self) =>
|
||||||
|
self.hook(App, (_, wname, visible) => {
|
||||||
|
if (wname === name) self.reveal_child = visible;
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
const Layout = (name: string, child: any, transition: Transition) => ({
|
||||||
|
center: () =>
|
||||||
|
Widget.CenterBox(
|
||||||
|
{},
|
||||||
|
Padding(name, {} as Opts),
|
||||||
|
Widget.CenterBox(
|
||||||
|
{ vertical: true },
|
||||||
|
Padding(name, {} as Opts),
|
||||||
|
PopupRevealer(name, child, transition),
|
||||||
|
Padding(name, {} as Opts),
|
||||||
|
),
|
||||||
|
Padding(name, {} as Opts),
|
||||||
|
),
|
||||||
|
top: () =>
|
||||||
|
Widget.CenterBox(
|
||||||
|
{},
|
||||||
|
Padding(name, {} as Opts),
|
||||||
|
Widget.Box(
|
||||||
|
{ vertical: true },
|
||||||
|
PopupRevealer(name, child, transition),
|
||||||
|
Padding(name, {} as Opts),
|
||||||
|
),
|
||||||
|
Padding(name, {} as Opts),
|
||||||
|
),
|
||||||
|
"top-right": () =>
|
||||||
|
Widget.Box(
|
||||||
|
{},
|
||||||
|
Padding(name, {} as Opts),
|
||||||
|
Widget.Box(
|
||||||
|
{
|
||||||
|
hexpand: false,
|
||||||
|
vertical: true,
|
||||||
|
},
|
||||||
|
Padding(name, {
|
||||||
|
vexpand: false,
|
||||||
|
className: "event-top-padding",
|
||||||
|
}),
|
||||||
|
PopupRevealer(name, child, transition),
|
||||||
|
Padding(name, {} as Opts),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
"top-center": () =>
|
||||||
|
Widget.Box(
|
||||||
|
{},
|
||||||
|
Padding(name, {} as Opts),
|
||||||
|
Widget.Box(
|
||||||
|
{
|
||||||
|
hexpand: false,
|
||||||
|
vertical: true,
|
||||||
|
},
|
||||||
|
Padding(name, {
|
||||||
|
vexpand: false,
|
||||||
|
className: "event-top-padding",
|
||||||
|
}),
|
||||||
|
PopupRevealer(name, child, transition),
|
||||||
|
Padding(name, {} as Opts),
|
||||||
|
),
|
||||||
|
Padding(name, {} as Opts),
|
||||||
|
),
|
||||||
|
"top-left": () =>
|
||||||
|
Widget.Box(
|
||||||
|
{},
|
||||||
|
Widget.Box(
|
||||||
|
{
|
||||||
|
hexpand: false,
|
||||||
|
vertical: true,
|
||||||
|
},
|
||||||
|
Padding(name, {
|
||||||
|
vexpand: false,
|
||||||
|
className: "event-top-padding",
|
||||||
|
}),
|
||||||
|
PopupRevealer(name, child, transition),
|
||||||
|
Padding(name, {} as Opts),
|
||||||
|
),
|
||||||
|
Padding(name, {} as Opts),
|
||||||
|
),
|
||||||
|
"bottom-left": () =>
|
||||||
|
Widget.Box(
|
||||||
|
{},
|
||||||
|
Widget.Box(
|
||||||
|
{
|
||||||
|
hexpand: false,
|
||||||
|
vertical: true,
|
||||||
|
},
|
||||||
|
Padding(name, {} as Opts),
|
||||||
|
PopupRevealer(name, child, transition),
|
||||||
|
),
|
||||||
|
Padding(name, {} as Opts),
|
||||||
|
),
|
||||||
|
"bottom-center": () =>
|
||||||
|
Widget.Box(
|
||||||
|
{},
|
||||||
|
Padding(name, {} as Opts),
|
||||||
|
Widget.Box(
|
||||||
|
{
|
||||||
|
hexpand: false,
|
||||||
|
vertical: true,
|
||||||
|
},
|
||||||
|
Padding(name, {} as Opts),
|
||||||
|
PopupRevealer(name, child, transition),
|
||||||
|
),
|
||||||
|
Padding(name, {} as Opts),
|
||||||
|
),
|
||||||
|
"bottom-right": () =>
|
||||||
|
Widget.Box(
|
||||||
|
{},
|
||||||
|
Padding(name, {} as Opts),
|
||||||
|
Widget.Box(
|
||||||
|
{
|
||||||
|
hexpand: false,
|
||||||
|
vertical: true,
|
||||||
|
},
|
||||||
|
Padding(name, {} as Opts),
|
||||||
|
PopupRevealer(name, child, transition),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
|
export default ({
|
||||||
|
name,
|
||||||
|
child,
|
||||||
|
layout = "center",
|
||||||
|
transition,
|
||||||
|
exclusivity = "ignore" as Exclusivity,
|
||||||
|
...props
|
||||||
|
}) =>
|
||||||
|
Widget.Window({
|
||||||
|
name,
|
||||||
|
class_names: [name, "popup-window"],
|
||||||
|
setup: (w) => w.keybind("Escape", () => App.closeWindow(name)),
|
||||||
|
visible: false,
|
||||||
|
keymode: "on-demand",
|
||||||
|
exclusivity,
|
||||||
|
layer: "top",
|
||||||
|
anchor: ["top", "bottom", "right", "left"],
|
||||||
|
child: Layout(name, child, transition)[layout](),
|
||||||
|
...props,
|
||||||
|
});
|
||||||
@@ -1,133 +0,0 @@
|
|||||||
import GLib from "gi://GLib";
|
|
||||||
import options from "options";
|
|
||||||
|
|
||||||
const { left, right } = options.menus.dashboard.directories;
|
|
||||||
|
|
||||||
const Directories = () => {
|
|
||||||
return Widget.Box({
|
|
||||||
class_name: "dashboard-card directories-container",
|
|
||||||
vpack: "fill",
|
|
||||||
hpack: "fill",
|
|
||||||
expand: true,
|
|
||||||
children: [
|
|
||||||
Widget.Box({
|
|
||||||
vertical: true,
|
|
||||||
expand: true,
|
|
||||||
class_name: "section right",
|
|
||||||
children: [
|
|
||||||
Widget.Button({
|
|
||||||
hpack: "start",
|
|
||||||
expand: true,
|
|
||||||
class_name: "directory-link left top",
|
|
||||||
on_primary_click: left.directory1.command
|
|
||||||
.bind("value")
|
|
||||||
.as((cmd) => {
|
|
||||||
return () => {
|
|
||||||
App.closeWindow("dashboardmenu");
|
|
||||||
Utils.execAsync(cmd);
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
child: Widget.Label({
|
|
||||||
hpack: "start",
|
|
||||||
label: left.directory1.label.bind("value"),
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
Widget.Button({
|
|
||||||
expand: true,
|
|
||||||
hpack: "start",
|
|
||||||
class_name: "directory-link left middle",
|
|
||||||
on_primary_click: left.directory2.command
|
|
||||||
.bind("value")
|
|
||||||
.as((cmd) => {
|
|
||||||
return () => {
|
|
||||||
App.closeWindow("dashboardmenu");
|
|
||||||
Utils.execAsync(cmd);
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
child: Widget.Label({
|
|
||||||
hpack: "start",
|
|
||||||
label: left.directory2.label.bind("value"),
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
Widget.Button({
|
|
||||||
expand: true,
|
|
||||||
hpack: "start",
|
|
||||||
class_name: "directory-link left bottom",
|
|
||||||
on_primary_click: left.directory3.command
|
|
||||||
.bind("value")
|
|
||||||
.as((cmd) => {
|
|
||||||
return () => {
|
|
||||||
App.closeWindow("dashboardmenu");
|
|
||||||
Utils.execAsync(cmd);
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
child: Widget.Label({
|
|
||||||
hpack: "start",
|
|
||||||
label: left.directory3.label.bind("value"),
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
Widget.Box({
|
|
||||||
vertical: true,
|
|
||||||
expand: true,
|
|
||||||
class_name: "section left",
|
|
||||||
children: [
|
|
||||||
Widget.Button({
|
|
||||||
hpack: "start",
|
|
||||||
expand: true,
|
|
||||||
class_name: "directory-link right top",
|
|
||||||
on_primary_click: right.directory1.command
|
|
||||||
.bind("value")
|
|
||||||
.as((cmd) => {
|
|
||||||
return () => {
|
|
||||||
App.closeWindow("dashboardmenu");
|
|
||||||
Utils.execAsync(cmd);
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
child: Widget.Label({
|
|
||||||
hpack: "start",
|
|
||||||
label: right.directory1.label.bind("value"),
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
Widget.Button({
|
|
||||||
expand: true,
|
|
||||||
hpack: "start",
|
|
||||||
class_name: "directory-link right middle",
|
|
||||||
on_primary_click: right.directory2.command
|
|
||||||
.bind("value")
|
|
||||||
.as((cmd) => {
|
|
||||||
return () => {
|
|
||||||
App.closeWindow("dashboardmenu");
|
|
||||||
Utils.execAsync(cmd);
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
child: Widget.Label({
|
|
||||||
hpack: "start",
|
|
||||||
label: right.directory2.label.bind("value"),
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
Widget.Button({
|
|
||||||
expand: true,
|
|
||||||
hpack: "start",
|
|
||||||
class_name: "directory-link right bottom",
|
|
||||||
on_primary_click: right.directory3.command
|
|
||||||
.bind("value")
|
|
||||||
.as((cmd) => {
|
|
||||||
return () => {
|
|
||||||
App.closeWindow("dashboardmenu");
|
|
||||||
Utils.execAsync(cmd);
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
child: Widget.Label({
|
|
||||||
hpack: "start",
|
|
||||||
label: right.directory3.label.bind("value"),
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export { Directories };
|
|
||||||
132
modules/menus/dashboard/directories/index.ts
Normal file
132
modules/menus/dashboard/directories/index.ts
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
import options from "options";
|
||||||
|
|
||||||
|
const { left, right } = options.menus.dashboard.directories;
|
||||||
|
|
||||||
|
const Directories = () => {
|
||||||
|
return Widget.Box({
|
||||||
|
class_name: "dashboard-card directories-container",
|
||||||
|
vpack: "fill",
|
||||||
|
hpack: "fill",
|
||||||
|
expand: true,
|
||||||
|
children: [
|
||||||
|
Widget.Box({
|
||||||
|
vertical: true,
|
||||||
|
expand: true,
|
||||||
|
class_name: "section right",
|
||||||
|
children: [
|
||||||
|
Widget.Button({
|
||||||
|
hpack: "start",
|
||||||
|
expand: true,
|
||||||
|
class_name: "directory-link left top",
|
||||||
|
on_primary_click: left.directory1.command
|
||||||
|
.bind("value")
|
||||||
|
.as((cmd) => {
|
||||||
|
return () => {
|
||||||
|
App.closeWindow("dashboardmenu");
|
||||||
|
Utils.execAsync(cmd);
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
child: Widget.Label({
|
||||||
|
hpack: "start",
|
||||||
|
label: left.directory1.label.bind("value"),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
Widget.Button({
|
||||||
|
expand: true,
|
||||||
|
hpack: "start",
|
||||||
|
class_name: "directory-link left middle",
|
||||||
|
on_primary_click: left.directory2.command
|
||||||
|
.bind("value")
|
||||||
|
.as((cmd) => {
|
||||||
|
return () => {
|
||||||
|
App.closeWindow("dashboardmenu");
|
||||||
|
Utils.execAsync(cmd);
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
child: Widget.Label({
|
||||||
|
hpack: "start",
|
||||||
|
label: left.directory2.label.bind("value"),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
Widget.Button({
|
||||||
|
expand: true,
|
||||||
|
hpack: "start",
|
||||||
|
class_name: "directory-link left bottom",
|
||||||
|
on_primary_click: left.directory3.command
|
||||||
|
.bind("value")
|
||||||
|
.as((cmd) => {
|
||||||
|
return () => {
|
||||||
|
App.closeWindow("dashboardmenu");
|
||||||
|
Utils.execAsync(cmd);
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
child: Widget.Label({
|
||||||
|
hpack: "start",
|
||||||
|
label: left.directory3.label.bind("value"),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
Widget.Box({
|
||||||
|
vertical: true,
|
||||||
|
expand: true,
|
||||||
|
class_name: "section left",
|
||||||
|
children: [
|
||||||
|
Widget.Button({
|
||||||
|
hpack: "start",
|
||||||
|
expand: true,
|
||||||
|
class_name: "directory-link right top",
|
||||||
|
on_primary_click: right.directory1.command
|
||||||
|
.bind("value")
|
||||||
|
.as((cmd) => {
|
||||||
|
return () => {
|
||||||
|
App.closeWindow("dashboardmenu");
|
||||||
|
Utils.execAsync(cmd);
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
child: Widget.Label({
|
||||||
|
hpack: "start",
|
||||||
|
label: right.directory1.label.bind("value"),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
Widget.Button({
|
||||||
|
expand: true,
|
||||||
|
hpack: "start",
|
||||||
|
class_name: "directory-link right middle",
|
||||||
|
on_primary_click: right.directory2.command
|
||||||
|
.bind("value")
|
||||||
|
.as((cmd) => {
|
||||||
|
return () => {
|
||||||
|
App.closeWindow("dashboardmenu");
|
||||||
|
Utils.execAsync(cmd);
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
child: Widget.Label({
|
||||||
|
hpack: "start",
|
||||||
|
label: right.directory2.label.bind("value"),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
Widget.Button({
|
||||||
|
expand: true,
|
||||||
|
hpack: "start",
|
||||||
|
class_name: "directory-link right bottom",
|
||||||
|
on_primary_click: right.directory3.command
|
||||||
|
.bind("value")
|
||||||
|
.as((cmd) => {
|
||||||
|
return () => {
|
||||||
|
App.closeWindow("dashboardmenu");
|
||||||
|
Utils.execAsync(cmd);
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
child: Widget.Label({
|
||||||
|
hpack: "start",
|
||||||
|
label: right.directory3.label.bind("value"),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export { Directories };
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
import icons from "../../../icons/index.js";
|
|
||||||
import powermenu from "../../power/helpers/actions.js";
|
|
||||||
|
|
||||||
import options from "options";
|
|
||||||
const { image, name } = options.menus.dashboard.powermenu.avatar;
|
|
||||||
|
|
||||||
const Profile = () => {
|
|
||||||
const handleClick = (action) => {
|
|
||||||
App.closeWindow("dashboardmenu");
|
|
||||||
return powermenu.action(action);
|
|
||||||
};
|
|
||||||
|
|
||||||
return Widget.Box({
|
|
||||||
class_name: "profiles-container",
|
|
||||||
hpack: "fill",
|
|
||||||
hexpand: true,
|
|
||||||
children: [
|
|
||||||
Widget.Box({
|
|
||||||
class_name: "profile-picture-container dashboard-card",
|
|
||||||
hexpand: true,
|
|
||||||
vertical: true,
|
|
||||||
children: [
|
|
||||||
Widget.Icon({
|
|
||||||
hpack: "center",
|
|
||||||
class_name: "profile-picture",
|
|
||||||
icon: image.bind("value"),
|
|
||||||
}),
|
|
||||||
Widget.Label({
|
|
||||||
hpack: "center",
|
|
||||||
class_name: "profile-name",
|
|
||||||
label: name.bind("value").as((v) => {
|
|
||||||
if (v === "system") {
|
|
||||||
return Utils.exec("bash -c whoami");
|
|
||||||
}
|
|
||||||
return v;
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
Widget.Box({
|
|
||||||
class_name: "power-menu-container dashboard-card",
|
|
||||||
vertical: true,
|
|
||||||
vexpand: true,
|
|
||||||
children: [
|
|
||||||
Widget.Button({
|
|
||||||
class_name: "dashboard-button shutdown",
|
|
||||||
on_clicked: () => handleClick("shutdown"),
|
|
||||||
tooltip_text: "Shut Down",
|
|
||||||
vexpand: true,
|
|
||||||
child: Widget.Icon(icons.powermenu.shutdown),
|
|
||||||
}),
|
|
||||||
Widget.Button({
|
|
||||||
class_name: "dashboard-button restart",
|
|
||||||
on_clicked: () => handleClick("reboot"),
|
|
||||||
tooltip_text: "Restart",
|
|
||||||
vexpand: true,
|
|
||||||
child: Widget.Icon(icons.powermenu.reboot),
|
|
||||||
}),
|
|
||||||
Widget.Button({
|
|
||||||
class_name: "dashboard-button lock",
|
|
||||||
on_clicked: () => handleClick("logout"),
|
|
||||||
tooltip_text: "Log Out",
|
|
||||||
vexpand: true,
|
|
||||||
child: Widget.Icon(icons.powermenu.logout),
|
|
||||||
}),
|
|
||||||
Widget.Button({
|
|
||||||
class_name: "dashboard-button sleep",
|
|
||||||
on_clicked: () => handleClick("sleep"),
|
|
||||||
tooltip_text: "Sleep",
|
|
||||||
vexpand: true,
|
|
||||||
child: Widget.Icon(icons.powermenu.sleep),
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export { Profile };
|
|
||||||
80
modules/menus/dashboard/profile/index.ts
Normal file
80
modules/menus/dashboard/profile/index.ts
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
import icons from "../../../icons/index.js";
|
||||||
|
import powermenu from "../../power/helpers/actions.js";
|
||||||
|
import { PowerOptions } from "lib/types/options.js";
|
||||||
|
|
||||||
|
import options from "options";
|
||||||
|
const { image, name } = options.menus.dashboard.powermenu.avatar;
|
||||||
|
|
||||||
|
const Profile = () => {
|
||||||
|
const handleClick = (action: PowerOptions) => {
|
||||||
|
App.closeWindow("dashboardmenu");
|
||||||
|
return powermenu.action(action);
|
||||||
|
};
|
||||||
|
|
||||||
|
return Widget.Box({
|
||||||
|
class_name: "profiles-container",
|
||||||
|
hpack: "fill",
|
||||||
|
hexpand: true,
|
||||||
|
children: [
|
||||||
|
Widget.Box({
|
||||||
|
class_name: "profile-picture-container dashboard-card",
|
||||||
|
hexpand: true,
|
||||||
|
vertical: true,
|
||||||
|
children: [
|
||||||
|
Widget.Icon({
|
||||||
|
hpack: "center",
|
||||||
|
class_name: "profile-picture",
|
||||||
|
icon: image.bind("value"),
|
||||||
|
}),
|
||||||
|
Widget.Label({
|
||||||
|
hpack: "center",
|
||||||
|
class_name: "profile-name",
|
||||||
|
label: name.bind("value").as((v) => {
|
||||||
|
if (v === "system") {
|
||||||
|
return Utils.exec("bash -c whoami");
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
Widget.Box({
|
||||||
|
class_name: "power-menu-container dashboard-card",
|
||||||
|
vertical: true,
|
||||||
|
vexpand: true,
|
||||||
|
children: [
|
||||||
|
Widget.Button({
|
||||||
|
class_name: "dashboard-button shutdown",
|
||||||
|
on_clicked: () => handleClick("shutdown"),
|
||||||
|
tooltip_text: "Shut Down",
|
||||||
|
vexpand: true,
|
||||||
|
child: Widget.Icon(icons.powermenu.shutdown),
|
||||||
|
}),
|
||||||
|
Widget.Button({
|
||||||
|
class_name: "dashboard-button restart",
|
||||||
|
on_clicked: () => handleClick("reboot"),
|
||||||
|
tooltip_text: "Restart",
|
||||||
|
vexpand: true,
|
||||||
|
child: Widget.Icon(icons.powermenu.reboot),
|
||||||
|
}),
|
||||||
|
Widget.Button({
|
||||||
|
class_name: "dashboard-button lock",
|
||||||
|
on_clicked: () => handleClick("logout"),
|
||||||
|
tooltip_text: "Log Out",
|
||||||
|
vexpand: true,
|
||||||
|
child: Widget.Icon(icons.powermenu.logout),
|
||||||
|
}),
|
||||||
|
Widget.Button({
|
||||||
|
class_name: "dashboard-button sleep",
|
||||||
|
on_clicked: () => handleClick("sleep"),
|
||||||
|
tooltip_text: "Sleep",
|
||||||
|
vexpand: true,
|
||||||
|
child: Widget.Icon(icons.powermenu.sleep),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export { Profile };
|
||||||
@@ -16,16 +16,12 @@ const Shortcuts = () => {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
const handleClick = (action, resolver, tOut = 250) => {
|
const handleClick = (action: any, tOut: number = 250) => {
|
||||||
App.closeWindow("dashboardmenu");
|
App.closeWindow("dashboardmenu");
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
Utils.execAsync(action)
|
Utils.execAsync(action)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
if (typeof resolver === "function") {
|
|
||||||
return resolver(res);
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
})
|
})
|
||||||
.catch((err) => err);
|
.catch((err) => err);
|
||||||
@@ -1,11 +1,12 @@
|
|||||||
import options from "options";
|
import options from "options";
|
||||||
|
import { GPU_Stat } from "lib/types/gpustat";
|
||||||
|
|
||||||
const { terminal } = options;
|
const { terminal } = options;
|
||||||
|
|
||||||
const Stats = () => {
|
const Stats = () => {
|
||||||
const divide = ([total, free]) => free / total;
|
const divide = ([total, free]) => free / total;
|
||||||
|
|
||||||
const formatSizeInGB = (sizeInKB) =>
|
const formatSizeInGB = (sizeInKB: number) =>
|
||||||
Number((sizeInKB / 1024 ** 2).toFixed(2));
|
Number((sizeInKB / 1024 ** 2).toFixed(2));
|
||||||
|
|
||||||
const cpu = Variable(0, {
|
const cpu = Variable(0, {
|
||||||
@@ -73,8 +74,10 @@ const Stats = () => {
|
|||||||
|
|
||||||
const totalGpu = 100;
|
const totalGpu = 100;
|
||||||
const usedGpu =
|
const usedGpu =
|
||||||
data.gpus.reduce((acc, gpu) => acc + gpu["utilization.gpu"], 0) /
|
data.gpus.reduce((acc: number, gpu: GPU_Stat) => {
|
||||||
data.gpus.length;
|
|
||||||
|
return acc + gpu["utilization.gpu"]
|
||||||
|
}, 0) / data.gpus.length;
|
||||||
|
|
||||||
return divide([totalGpu, usedGpu]);
|
return divide([totalGpu, usedGpu]);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
import brightness from "../../../../services/Brightness.js";
|
|
||||||
import icons from "../../../icons/index.js";
|
|
||||||
|
|
||||||
const Brightness = () => {
|
|
||||||
return Widget.Box({
|
|
||||||
class_name: "menu-section-container brightness",
|
|
||||||
vertical: true,
|
|
||||||
children: [
|
|
||||||
Widget.Box({
|
|
||||||
class_name: "menu-label-container",
|
|
||||||
hpack: "fill",
|
|
||||||
child: Widget.Label({
|
|
||||||
class_name: "menu-label",
|
|
||||||
hexpand: true,
|
|
||||||
hpack: "start",
|
|
||||||
label: "Brightness",
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
Widget.Box({
|
|
||||||
class_name: "menu-items-section",
|
|
||||||
vpack: "fill",
|
|
||||||
vexpand: true,
|
|
||||||
vertical: true,
|
|
||||||
child: Widget.Box({
|
|
||||||
class_name: "brightness-container",
|
|
||||||
children: [
|
|
||||||
Widget.Icon({
|
|
||||||
vexpand: true,
|
|
||||||
vpack: "center",
|
|
||||||
class_name: "brightness-slider-icon",
|
|
||||||
icon: icons.brightness.screen,
|
|
||||||
}),
|
|
||||||
Widget.Slider({
|
|
||||||
vpack: "center",
|
|
||||||
vexpand: true,
|
|
||||||
value: brightness.bind("screen_value"),
|
|
||||||
class_name: "menu-active-slider menu-slider brightness",
|
|
||||||
draw_value: false,
|
|
||||||
hexpand: true,
|
|
||||||
min: 0,
|
|
||||||
max: 1,
|
|
||||||
onChange: ({ value }) => (brightness.screen_value = value),
|
|
||||||
}),
|
|
||||||
Widget.Label({
|
|
||||||
vpack: "center",
|
|
||||||
vexpand: true,
|
|
||||||
class_name: "brightness-slider-label",
|
|
||||||
label: brightness
|
|
||||||
.bind("screen_value")
|
|
||||||
.as((b) => `${Math.floor(b * 100)}%`),
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export { Brightness };
|
|
||||||
59
modules/menus/energy/brightness/index.ts
Normal file
59
modules/menus/energy/brightness/index.ts
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
import brightness from "../../../../services/Brightness.js";
|
||||||
|
import icons from "../../../icons/index.js";
|
||||||
|
|
||||||
|
const Brightness = () => {
|
||||||
|
return Widget.Box({
|
||||||
|
class_name: "menu-section-container brightness",
|
||||||
|
vertical: true,
|
||||||
|
children: [
|
||||||
|
Widget.Box({
|
||||||
|
class_name: "menu-label-container",
|
||||||
|
hpack: "fill",
|
||||||
|
child: Widget.Label({
|
||||||
|
class_name: "menu-label",
|
||||||
|
hexpand: true,
|
||||||
|
hpack: "start",
|
||||||
|
label: "Brightness",
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
Widget.Box({
|
||||||
|
class_name: "menu-items-section",
|
||||||
|
vpack: "fill",
|
||||||
|
vexpand: true,
|
||||||
|
vertical: true,
|
||||||
|
child: Widget.Box({
|
||||||
|
class_name: "brightness-container",
|
||||||
|
children: [
|
||||||
|
Widget.Icon({
|
||||||
|
vexpand: true,
|
||||||
|
vpack: "center",
|
||||||
|
class_name: "brightness-slider-icon",
|
||||||
|
icon: icons.brightness.screen,
|
||||||
|
}),
|
||||||
|
Widget.Slider({
|
||||||
|
vpack: "center",
|
||||||
|
vexpand: true,
|
||||||
|
value: brightness.bind("screen_value"),
|
||||||
|
class_name: "menu-active-slider menu-slider brightness",
|
||||||
|
draw_value: false,
|
||||||
|
hexpand: true,
|
||||||
|
min: 0,
|
||||||
|
max: 1,
|
||||||
|
onChange: ({ value }) => (brightness.screen_value = value),
|
||||||
|
}),
|
||||||
|
Widget.Label({
|
||||||
|
vpack: "center",
|
||||||
|
vexpand: true,
|
||||||
|
class_name: "brightness-slider-label",
|
||||||
|
label: brightness
|
||||||
|
.bind("screen_value")
|
||||||
|
.as((b) => `${Math.floor(b * 100)}%`),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export { Brightness };
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
import DropdownMenu from "../DropdownMenu.js";
|
|
||||||
import { EnergyProfiles } from "./profiles/index.js";
|
|
||||||
import { Brightness } from "./brightness/index.js";
|
|
||||||
|
|
||||||
export default () => {
|
|
||||||
return DropdownMenu({
|
|
||||||
name: "energymenu",
|
|
||||||
transition: "crossfade",
|
|
||||||
child: Widget.Box({
|
|
||||||
class_name: "menu-items energy",
|
|
||||||
hpack: "fill",
|
|
||||||
hexpand: true,
|
|
||||||
child: Widget.Box({
|
|
||||||
vertical: true,
|
|
||||||
hpack: "fill",
|
|
||||||
hexpand: true,
|
|
||||||
class_name: "menu-items-container energy",
|
|
||||||
children: [
|
|
||||||
Brightness(),
|
|
||||||
EnergyProfiles(),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
};
|
|
||||||
25
modules/menus/energy/index.ts
Normal file
25
modules/menus/energy/index.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import DropdownMenu from "../DropdownMenu.js";
|
||||||
|
import { EnergyProfiles } from "./profiles/index.js";
|
||||||
|
import { Brightness } from "./brightness/index.js";
|
||||||
|
|
||||||
|
export default () => {
|
||||||
|
return DropdownMenu({
|
||||||
|
name: "energymenu",
|
||||||
|
transition: "crossfade",
|
||||||
|
child: Widget.Box({
|
||||||
|
class_name: "menu-items energy",
|
||||||
|
hpack: "fill",
|
||||||
|
hexpand: true,
|
||||||
|
child: Widget.Box({
|
||||||
|
vertical: true,
|
||||||
|
hpack: "fill",
|
||||||
|
hexpand: true,
|
||||||
|
class_name: "menu-items-container energy",
|
||||||
|
children: [
|
||||||
|
Brightness(),
|
||||||
|
EnergyProfiles(),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
const powerProfiles = await Service.import("powerprofiles");
|
|
||||||
import icons from "../../../icons/index.js";
|
|
||||||
|
|
||||||
const EnergyProfiles = () => {
|
|
||||||
return Widget.Box({
|
|
||||||
class_name: "menu-section-container energy",
|
|
||||||
vertical: true,
|
|
||||||
children: [
|
|
||||||
Widget.Box({
|
|
||||||
class_name: "menu-label-container",
|
|
||||||
hpack: "fill",
|
|
||||||
child: Widget.Label({
|
|
||||||
class_name: "menu-label",
|
|
||||||
hexpand: true,
|
|
||||||
hpack: "start",
|
|
||||||
label: "Power Profile",
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
Widget.Box({
|
|
||||||
class_name: "menu-items-section",
|
|
||||||
vpack: "fill",
|
|
||||||
vexpand: true,
|
|
||||||
vertical: true,
|
|
||||||
children: powerProfiles.bind("profiles").as((profiles) => {
|
|
||||||
return profiles.map((prof) => {
|
|
||||||
const ProfileLabels = {
|
|
||||||
"power-saver": "Power Saver",
|
|
||||||
balanced: "Balanced",
|
|
||||||
performance: "Performance",
|
|
||||||
};
|
|
||||||
return Widget.Button({
|
|
||||||
on_primary_click: () => {
|
|
||||||
powerProfiles.active_profile = prof.Profile;
|
|
||||||
},
|
|
||||||
class_name: powerProfiles.bind("active_profile").as((active) => {
|
|
||||||
return `power-profile-item ${active === prof.Profile ? "active" : ""}`;
|
|
||||||
}),
|
|
||||||
child: Widget.Box({
|
|
||||||
children: [
|
|
||||||
Widget.Icon({
|
|
||||||
class_name: "power-profile-icon",
|
|
||||||
icon: icons.powerprofile[prof.Profile],
|
|
||||||
}),
|
|
||||||
Widget.Label({
|
|
||||||
class_name: "power-profile-label",
|
|
||||||
label: ProfileLabels[prof.Profile],
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export { EnergyProfiles };
|
|
||||||
58
modules/menus/energy/profiles/index.ts
Normal file
58
modules/menus/energy/profiles/index.ts
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
const powerProfiles = await Service.import("powerprofiles");
|
||||||
|
import icons from "../../../icons/index.js";
|
||||||
|
|
||||||
|
const EnergyProfiles = () => {
|
||||||
|
return Widget.Box({
|
||||||
|
class_name: "menu-section-container energy",
|
||||||
|
vertical: true,
|
||||||
|
children: [
|
||||||
|
Widget.Box({
|
||||||
|
class_name: "menu-label-container",
|
||||||
|
hpack: "fill",
|
||||||
|
child: Widget.Label({
|
||||||
|
class_name: "menu-label",
|
||||||
|
hexpand: true,
|
||||||
|
hpack: "start",
|
||||||
|
label: "Power Profile",
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
Widget.Box({
|
||||||
|
class_name: "menu-items-section",
|
||||||
|
vpack: "fill",
|
||||||
|
vexpand: true,
|
||||||
|
vertical: true,
|
||||||
|
children: powerProfiles.bind("profiles").as((profiles) => {
|
||||||
|
return profiles.map((prof) => {
|
||||||
|
const ProfileLabels = {
|
||||||
|
"power-saver": "Power Saver",
|
||||||
|
balanced: "Balanced",
|
||||||
|
performance: "Performance",
|
||||||
|
};
|
||||||
|
return Widget.Button({
|
||||||
|
on_primary_click: () => {
|
||||||
|
powerProfiles.active_profile = prof.Profile;
|
||||||
|
},
|
||||||
|
class_name: powerProfiles.bind("active_profile").as((active) => {
|
||||||
|
return `power-profile-item ${active === prof.Profile ? "active" : ""}`;
|
||||||
|
}),
|
||||||
|
child: Widget.Box({
|
||||||
|
children: [
|
||||||
|
Widget.Icon({
|
||||||
|
class_name: "power-profile-icon",
|
||||||
|
icon: icons.powerprofile[prof.Profile],
|
||||||
|
}),
|
||||||
|
Widget.Label({
|
||||||
|
class_name: "power-profile-label",
|
||||||
|
label: ProfileLabels[prof.Profile],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export { EnergyProfiles };
|
||||||
@@ -10,14 +10,14 @@ import EnergyMenu from "./energy/index.js";
|
|||||||
import DashboardMenu from "./dashboard/index.js";
|
import DashboardMenu from "./dashboard/index.js";
|
||||||
|
|
||||||
export default [
|
export default [
|
||||||
PowerMenu(),
|
PowerMenu(),
|
||||||
Verification(),
|
Verification(),
|
||||||
AudioMenu(),
|
AudioMenu(),
|
||||||
NetworkMenu(),
|
NetworkMenu(),
|
||||||
BluetoothMenu(),
|
BluetoothMenu(),
|
||||||
MediaMenu(),
|
MediaMenu(),
|
||||||
NotificationsMenu(),
|
NotificationsMenu(),
|
||||||
CalendarMenu(),
|
CalendarMenu(),
|
||||||
EnergyMenu(),
|
EnergyMenu(),
|
||||||
DashboardMenu(),
|
DashboardMenu(),
|
||||||
];
|
];
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
const media = await Service.import("mpris");
|
|
||||||
|
|
||||||
const Bar = (getPlayerInfo) => {
|
|
||||||
return Widget.Box({
|
|
||||||
class_name: "media-indicator-current-progress-bar",
|
|
||||||
hexpand: true,
|
|
||||||
children: [
|
|
||||||
Widget.Box({
|
|
||||||
hexpand: true,
|
|
||||||
child: Widget.Slider({
|
|
||||||
hexpand: true,
|
|
||||||
tooltip_text: "--",
|
|
||||||
class_name: "menu-slider media progress",
|
|
||||||
draw_value: false,
|
|
||||||
on_change: ({ value }) => {
|
|
||||||
const foundPlayer = getPlayerInfo(media);
|
|
||||||
if (foundPlayer === undefined) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
return (foundPlayer.position = value * foundPlayer.length);
|
|
||||||
},
|
|
||||||
setup: (self) => {
|
|
||||||
const update = () => {
|
|
||||||
const foundPlayer = getPlayerInfo(media);
|
|
||||||
if (foundPlayer !== undefined) {
|
|
||||||
const value = foundPlayer.position / foundPlayer.length;
|
|
||||||
self.value = value > 0 ? value : 0;
|
|
||||||
} else {
|
|
||||||
self.value = 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
self.hook(media, update);
|
|
||||||
self.poll(1000, update);
|
|
||||||
|
|
||||||
function updateTooltip() {
|
|
||||||
const foundPlayer = getPlayerInfo(media);
|
|
||||||
if (foundPlayer === undefined) {
|
|
||||||
return self.tooltip_text = '00:00'
|
|
||||||
}
|
|
||||||
const curHour = Math.floor(foundPlayer.position / 3600);
|
|
||||||
const curMin = Math.floor((foundPlayer.position % 3600) / 60);
|
|
||||||
const curSec = Math.floor(foundPlayer.position % 60);
|
|
||||||
|
|
||||||
if (
|
|
||||||
typeof foundPlayer.position === "number" &&
|
|
||||||
foundPlayer.position >= 0
|
|
||||||
) {
|
|
||||||
// WARN: These nested ternaries are absolutely disgusting lol
|
|
||||||
self.tooltip_text = `${
|
|
||||||
curHour > 0
|
|
||||||
? (curHour < 10 ? "0" + curHour : curHour) + ":"
|
|
||||||
: ""
|
|
||||||
}${curMin < 10 ? "0" + curMin : curMin}:${curSec < 10 ? "0" + curSec : curSec}`;
|
|
||||||
} else {
|
|
||||||
self.tooltip_text = `00:00`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.poll(1000, updateTooltip);
|
|
||||||
self.hook(media, updateTooltip);
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export { Bar };
|
|
||||||
66
modules/menus/media/components/bar.ts
Normal file
66
modules/menus/media/components/bar.ts
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
const media = await Service.import("mpris");
|
||||||
|
|
||||||
|
const Bar = (getPlayerInfo: Function) => {
|
||||||
|
return Widget.Box({
|
||||||
|
class_name: "media-indicator-current-progress-bar",
|
||||||
|
hexpand: true,
|
||||||
|
children: [
|
||||||
|
Widget.Box({
|
||||||
|
hexpand: true,
|
||||||
|
child: Widget.Slider({
|
||||||
|
hexpand: true,
|
||||||
|
tooltip_text: "--",
|
||||||
|
class_name: "menu-slider media progress",
|
||||||
|
draw_value: false,
|
||||||
|
on_change: ({ value }) => {
|
||||||
|
const foundPlayer = getPlayerInfo(media);
|
||||||
|
if (foundPlayer === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return (foundPlayer.position = value * foundPlayer.length);
|
||||||
|
},
|
||||||
|
setup: (self) => {
|
||||||
|
const update = () => {
|
||||||
|
const foundPlayer = getPlayerInfo(media);
|
||||||
|
if (foundPlayer !== undefined) {
|
||||||
|
const value = foundPlayer.position / foundPlayer.length;
|
||||||
|
self.value = value > 0 ? value : 0;
|
||||||
|
} else {
|
||||||
|
self.value = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
self.hook(media, update);
|
||||||
|
self.poll(1000, update);
|
||||||
|
|
||||||
|
function updateTooltip() {
|
||||||
|
const foundPlayer = getPlayerInfo(media);
|
||||||
|
if (foundPlayer === undefined) {
|
||||||
|
return self.tooltip_text = '00:00'
|
||||||
|
}
|
||||||
|
const curHour = Math.floor(foundPlayer.position / 3600);
|
||||||
|
const curMin = Math.floor((foundPlayer.position % 3600) / 60);
|
||||||
|
const curSec = Math.floor(foundPlayer.position % 60);
|
||||||
|
|
||||||
|
if (
|
||||||
|
typeof foundPlayer.position === "number" &&
|
||||||
|
foundPlayer.position >= 0
|
||||||
|
) {
|
||||||
|
// WARN: These nested ternaries are absolutely disgusting lol
|
||||||
|
self.tooltip_text = `${curHour > 0
|
||||||
|
? (curHour < 10 ? "0" + curHour : curHour) + ":"
|
||||||
|
: ""
|
||||||
|
}${curMin < 10 ? "0" + curMin : curMin}:${curSec < 10 ? "0" + curSec : curSec}`;
|
||||||
|
} else {
|
||||||
|
self.tooltip_text = `00:00`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.poll(1000, updateTooltip);
|
||||||
|
self.hook(media, updateTooltip);
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export { Bar };
|
||||||
187
modules/menus/media/components/controls.js
vendored
187
modules/menus/media/components/controls.js
vendored
@@ -1,187 +0,0 @@
|
|||||||
import icons from "../../../icons/index.js";
|
|
||||||
const media = await Service.import("mpris");
|
|
||||||
|
|
||||||
const Controls = (getPlayerInfo) => {
|
|
||||||
const isLoopActive = (player) => {
|
|
||||||
return player["loop-status"] !== null &&
|
|
||||||
["track", "playlist"].includes(player["loop-status"].toLowerCase())
|
|
||||||
? "active"
|
|
||||||
: "";
|
|
||||||
};
|
|
||||||
|
|
||||||
const isShuffleActive = (player) => {
|
|
||||||
return player["shuffle-status"] !== null && player["shuffle-status"]
|
|
||||||
? "active"
|
|
||||||
: "";
|
|
||||||
};
|
|
||||||
|
|
||||||
return Widget.Box({
|
|
||||||
class_name: "media-indicator-current-player-controls",
|
|
||||||
vertical: true,
|
|
||||||
children: [
|
|
||||||
Widget.Box({
|
|
||||||
class_name: "media-indicator-current-controls",
|
|
||||||
hpack: "center",
|
|
||||||
children: [
|
|
||||||
Widget.Box({
|
|
||||||
class_name: "media-indicator-control shuffle",
|
|
||||||
children: [
|
|
||||||
Widget.Button({
|
|
||||||
hpack: "center",
|
|
||||||
hasTooltip: true,
|
|
||||||
setup: (self) => {
|
|
||||||
self.hook(media, () => {
|
|
||||||
const foundPlayer = getPlayerInfo();
|
|
||||||
if (foundPlayer === undefined) {
|
|
||||||
self.tooltip_text = "Unavailable";
|
|
||||||
self.class_name =
|
|
||||||
"media-indicator-control-button shuffle disabled";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.tooltip_text =
|
|
||||||
foundPlayer.shuffle_status !== null
|
|
||||||
? foundPlayer.shuffle_status
|
|
||||||
? "Shuffling"
|
|
||||||
: "Not Shuffling"
|
|
||||||
: null;
|
|
||||||
self.on_primary_click = () => foundPlayer.shuffle();
|
|
||||||
self.class_name = `media-indicator-control-button shuffle ${isShuffleActive(foundPlayer)} ${foundPlayer.shuffle_status !== null ? "enabled" : "disabled"}`;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
child: Widget.Icon(icons.mpris.shuffle["enabled"]),
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
Widget.Box({
|
|
||||||
children: [
|
|
||||||
Widget.Button({
|
|
||||||
hpack: "center",
|
|
||||||
child: Widget.Icon(icons.mpris.prev),
|
|
||||||
setup: (self) => {
|
|
||||||
self.hook(media, () => {
|
|
||||||
const foundPlayer = getPlayerInfo();
|
|
||||||
if (foundPlayer === undefined) {
|
|
||||||
self.class_name =
|
|
||||||
"media-indicator-control-button prev disabled";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.on_primary_click = () => foundPlayer.previous();
|
|
||||||
self.class_name = `media-indicator-control-button prev ${foundPlayer.can_go_prev !== null && foundPlayer.can_go_prev ? "enabled" : "disabled"}`;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
Widget.Box({
|
|
||||||
children: [
|
|
||||||
Widget.Button({
|
|
||||||
hpack: "center",
|
|
||||||
setup: (self) => {
|
|
||||||
self.hook(media, () => {
|
|
||||||
const foundPlayer = getPlayerInfo();
|
|
||||||
if (foundPlayer === undefined) {
|
|
||||||
self.class_name =
|
|
||||||
"media-indicator-control-button play disabled";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.on_primary_click = () => foundPlayer.playPause();
|
|
||||||
self.class_name = `media-indicator-control-button play ${foundPlayer.can_play !== null ? "enabled" : "disabled"}`;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
child: Widget.Icon({
|
|
||||||
icon: Utils.watch(
|
|
||||||
icons.mpris.paused,
|
|
||||||
media,
|
|
||||||
"changed",
|
|
||||||
() => {
|
|
||||||
const foundPlayer = getPlayerInfo();
|
|
||||||
if (foundPlayer === undefined) {
|
|
||||||
return icons.mpris["paused"];
|
|
||||||
}
|
|
||||||
return icons.mpris[
|
|
||||||
foundPlayer.play_back_status.toLowerCase()
|
|
||||||
];
|
|
||||||
},
|
|
||||||
),
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
Widget.Box({
|
|
||||||
class_name: `media-indicator-control next`,
|
|
||||||
children: [
|
|
||||||
Widget.Button({
|
|
||||||
hpack: "center",
|
|
||||||
child: Widget.Icon(icons.mpris.next),
|
|
||||||
setup: (self) => {
|
|
||||||
self.hook(media, () => {
|
|
||||||
const foundPlayer = getPlayerInfo();
|
|
||||||
if (foundPlayer === undefined) {
|
|
||||||
self.class_name =
|
|
||||||
"media-indicator-control-button next disabled";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.on_primary_click = () => foundPlayer.next();
|
|
||||||
self.class_name = `media-indicator-control-button next ${foundPlayer.can_go_next !== null && foundPlayer.can_go_next ? "enabled" : "disabled"}`;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
Widget.Box({
|
|
||||||
class_name: "media-indicator-control loop",
|
|
||||||
children: [
|
|
||||||
Widget.Button({
|
|
||||||
hpack: "center",
|
|
||||||
setup: (self) => {
|
|
||||||
self.hook(media, () => {
|
|
||||||
const foundPlayer = getPlayerInfo();
|
|
||||||
if (foundPlayer === undefined) {
|
|
||||||
self.tooltip_text = "Unavailable";
|
|
||||||
self.class_name =
|
|
||||||
"media-indicator-control-button shuffle disabled";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.tooltip_text =
|
|
||||||
foundPlayer.loop_status !== null
|
|
||||||
? foundPlayer.loop_status
|
|
||||||
? "Shuffling"
|
|
||||||
: "Not Shuffling"
|
|
||||||
: null;
|
|
||||||
self.on_primary_click = () => foundPlayer.loop();
|
|
||||||
self.class_name = `media-indicator-control-button loop ${isLoopActive(foundPlayer)} ${foundPlayer.loop_status !== null ? "enabled" : "disabled"}`;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
child: Widget.Icon({
|
|
||||||
setup: (self) => {
|
|
||||||
self.hook(media, () => {
|
|
||||||
const foundPlayer = getPlayerInfo();
|
|
||||||
if (foundPlayer === undefined) {
|
|
||||||
self.icon = icons.mpris.loop["none"];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.icon =
|
|
||||||
foundPlayer.loop_status === null
|
|
||||||
? icons.mpris.loop["none"]
|
|
||||||
: icons.mpris.loop[
|
|
||||||
foundPlayer.loop_status?.toLowerCase()
|
|
||||||
];
|
|
||||||
});
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export { Controls };
|
|
||||||
188
modules/menus/media/components/controls.ts
Normal file
188
modules/menus/media/components/controls.ts
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
import { MprisPlayer } from "types/service/mpris.js";
|
||||||
|
import icons from "../../../icons/index.js";
|
||||||
|
const media = await Service.import("mpris");
|
||||||
|
|
||||||
|
const Controls = (getPlayerInfo: Function) => {
|
||||||
|
const isLoopActive = (player: MprisPlayer) => {
|
||||||
|
return player["loop-status"] !== null &&
|
||||||
|
["track", "playlist"].includes(player["loop-status"].toLowerCase())
|
||||||
|
? "active"
|
||||||
|
: "";
|
||||||
|
};
|
||||||
|
|
||||||
|
const isShuffleActive = (player: MprisPlayer) => {
|
||||||
|
return player["shuffle-status"] !== null && player["shuffle-status"]
|
||||||
|
? "active"
|
||||||
|
: "";
|
||||||
|
};
|
||||||
|
|
||||||
|
return Widget.Box({
|
||||||
|
class_name: "media-indicator-current-player-controls",
|
||||||
|
vertical: true,
|
||||||
|
children: [
|
||||||
|
Widget.Box({
|
||||||
|
class_name: "media-indicator-current-controls",
|
||||||
|
hpack: "center",
|
||||||
|
children: [
|
||||||
|
Widget.Box({
|
||||||
|
class_name: "media-indicator-control shuffle",
|
||||||
|
children: [
|
||||||
|
Widget.Button({
|
||||||
|
hpack: "center",
|
||||||
|
hasTooltip: true,
|
||||||
|
setup: (self) => {
|
||||||
|
self.hook(media, () => {
|
||||||
|
const foundPlayer = getPlayerInfo();
|
||||||
|
if (foundPlayer === undefined) {
|
||||||
|
self.tooltip_text = "Unavailable";
|
||||||
|
self.class_name =
|
||||||
|
"media-indicator-control-button shuffle disabled";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.tooltip_text =
|
||||||
|
foundPlayer.shuffle_status !== null
|
||||||
|
? foundPlayer.shuffle_status
|
||||||
|
? "Shuffling"
|
||||||
|
: "Not Shuffling"
|
||||||
|
: null;
|
||||||
|
self.on_primary_click = () => foundPlayer.shuffle();
|
||||||
|
self.class_name = `media-indicator-control-button shuffle ${isShuffleActive(foundPlayer)} ${foundPlayer.shuffle_status !== null ? "enabled" : "disabled"}`;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: Widget.Icon(icons.mpris.shuffle["enabled"]),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
Widget.Box({
|
||||||
|
children: [
|
||||||
|
Widget.Button({
|
||||||
|
hpack: "center",
|
||||||
|
child: Widget.Icon(icons.mpris.prev),
|
||||||
|
setup: (self) => {
|
||||||
|
self.hook(media, () => {
|
||||||
|
const foundPlayer = getPlayerInfo();
|
||||||
|
if (foundPlayer === undefined) {
|
||||||
|
self.class_name =
|
||||||
|
"media-indicator-control-button prev disabled";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.on_primary_click = () => foundPlayer.previous();
|
||||||
|
self.class_name = `media-indicator-control-button prev ${foundPlayer.can_go_prev !== null && foundPlayer.can_go_prev ? "enabled" : "disabled"}`;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
Widget.Box({
|
||||||
|
children: [
|
||||||
|
Widget.Button({
|
||||||
|
hpack: "center",
|
||||||
|
setup: (self) => {
|
||||||
|
self.hook(media, () => {
|
||||||
|
const foundPlayer = getPlayerInfo();
|
||||||
|
if (foundPlayer === undefined) {
|
||||||
|
self.class_name =
|
||||||
|
"media-indicator-control-button play disabled";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.on_primary_click = () => foundPlayer.playPause();
|
||||||
|
self.class_name = `media-indicator-control-button play ${foundPlayer.can_play !== null ? "enabled" : "disabled"}`;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: Widget.Icon({
|
||||||
|
icon: Utils.watch(
|
||||||
|
icons.mpris.paused,
|
||||||
|
media,
|
||||||
|
"changed",
|
||||||
|
() => {
|
||||||
|
const foundPlayer = getPlayerInfo();
|
||||||
|
if (foundPlayer === undefined) {
|
||||||
|
return icons.mpris["paused"];
|
||||||
|
}
|
||||||
|
return icons.mpris[
|
||||||
|
foundPlayer.play_back_status.toLowerCase()
|
||||||
|
];
|
||||||
|
},
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
Widget.Box({
|
||||||
|
class_name: `media-indicator-control next`,
|
||||||
|
children: [
|
||||||
|
Widget.Button({
|
||||||
|
hpack: "center",
|
||||||
|
child: Widget.Icon(icons.mpris.next),
|
||||||
|
setup: (self) => {
|
||||||
|
self.hook(media, () => {
|
||||||
|
const foundPlayer = getPlayerInfo();
|
||||||
|
if (foundPlayer === undefined) {
|
||||||
|
self.class_name =
|
||||||
|
"media-indicator-control-button next disabled";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.on_primary_click = () => foundPlayer.next();
|
||||||
|
self.class_name = `media-indicator-control-button next ${foundPlayer.can_go_next !== null && foundPlayer.can_go_next ? "enabled" : "disabled"}`;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
Widget.Box({
|
||||||
|
class_name: "media-indicator-control loop",
|
||||||
|
children: [
|
||||||
|
Widget.Button({
|
||||||
|
hpack: "center",
|
||||||
|
setup: (self) => {
|
||||||
|
self.hook(media, () => {
|
||||||
|
const foundPlayer = getPlayerInfo();
|
||||||
|
if (foundPlayer === undefined) {
|
||||||
|
self.tooltip_text = "Unavailable";
|
||||||
|
self.class_name =
|
||||||
|
"media-indicator-control-button shuffle disabled";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.tooltip_text =
|
||||||
|
foundPlayer.loop_status !== null
|
||||||
|
? foundPlayer.loop_status
|
||||||
|
? "Shuffling"
|
||||||
|
: "Not Shuffling"
|
||||||
|
: null;
|
||||||
|
self.on_primary_click = () => foundPlayer.loop();
|
||||||
|
self.class_name = `media-indicator-control-button loop ${isLoopActive(foundPlayer)} ${foundPlayer.loop_status !== null ? "enabled" : "disabled"}`;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: Widget.Icon({
|
||||||
|
setup: (self) => {
|
||||||
|
self.hook(media, () => {
|
||||||
|
const foundPlayer = getPlayerInfo();
|
||||||
|
if (foundPlayer === undefined) {
|
||||||
|
self.icon = icons.mpris.loop["none"];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.icon =
|
||||||
|
foundPlayer.loop_status === null
|
||||||
|
? icons.mpris.loop["none"]
|
||||||
|
: icons.mpris.loop[
|
||||||
|
foundPlayer.loop_status?.toLowerCase()
|
||||||
|
];
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export { Controls };
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
const media = await Service.import("mpris");
|
|
||||||
|
|
||||||
const MediaInfo = (getPlayerInfo) => {
|
|
||||||
return Widget.Box({
|
|
||||||
class_name: "media-indicator-current-media-info",
|
|
||||||
hpack: "center",
|
|
||||||
hexpand: true,
|
|
||||||
vertical: true,
|
|
||||||
children: [
|
|
||||||
Widget.Box({
|
|
||||||
class_name: "media-indicator-current-song-name",
|
|
||||||
hpack: "center",
|
|
||||||
children: [
|
|
||||||
Widget.Label({
|
|
||||||
truncate: "end",
|
|
||||||
max_width_chars: 31,
|
|
||||||
wrap: true,
|
|
||||||
class_name: "media-indicator-current-song-name-label",
|
|
||||||
setup: (self) => {
|
|
||||||
self.hook(media, () => {
|
|
||||||
const curPlayer = getPlayerInfo();
|
|
||||||
return (self.label =
|
|
||||||
curPlayer !== undefined && curPlayer["track-title"].length
|
|
||||||
? curPlayer["track-title"]
|
|
||||||
: "No Media Currently Playing");
|
|
||||||
});
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
Widget.Box({
|
|
||||||
class_name: "media-indicator-current-song-author",
|
|
||||||
hpack: "center",
|
|
||||||
children: [
|
|
||||||
Widget.Label({
|
|
||||||
truncate: "end",
|
|
||||||
wrap: true,
|
|
||||||
max_width_chars: 35,
|
|
||||||
class_name: "media-indicator-current-song-author-label",
|
|
||||||
setup: (self) => {
|
|
||||||
self.hook(media, () => {
|
|
||||||
const curPlayer = getPlayerInfo();
|
|
||||||
|
|
||||||
const makeArtistList = (trackArtists) => {
|
|
||||||
if (trackArtists.length === 1 && !trackArtists[0].length) {
|
|
||||||
return "-----";
|
|
||||||
}
|
|
||||||
|
|
||||||
return trackArtists.join(", ");
|
|
||||||
};
|
|
||||||
return (self.label =
|
|
||||||
curPlayer !== undefined && curPlayer["track-artists"].length
|
|
||||||
? makeArtistList(curPlayer["track-artists"])
|
|
||||||
: "-----");
|
|
||||||
});
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
Widget.Box({
|
|
||||||
class_name: "media-indicator-current-song-album",
|
|
||||||
hpack: "center",
|
|
||||||
children: [
|
|
||||||
Widget.Label({
|
|
||||||
truncate: "end",
|
|
||||||
wrap: true,
|
|
||||||
max_width_chars: 40,
|
|
||||||
class_name: "media-indicator-current-song-album-label",
|
|
||||||
setup: (self) => {
|
|
||||||
self.hook(media, () => {
|
|
||||||
const curPlayer = getPlayerInfo();
|
|
||||||
return (self.label =
|
|
||||||
curPlayer !== undefined && curPlayer["track-album"].length
|
|
||||||
? curPlayer["track-album"]
|
|
||||||
: "---");
|
|
||||||
});
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export { MediaInfo };
|
|
||||||
85
modules/menus/media/components/mediainfo.ts
Normal file
85
modules/menus/media/components/mediainfo.ts
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
const media = await Service.import("mpris");
|
||||||
|
|
||||||
|
const MediaInfo = (getPlayerInfo: Function) => {
|
||||||
|
return Widget.Box({
|
||||||
|
class_name: "media-indicator-current-media-info",
|
||||||
|
hpack: "center",
|
||||||
|
hexpand: true,
|
||||||
|
vertical: true,
|
||||||
|
children: [
|
||||||
|
Widget.Box({
|
||||||
|
class_name: "media-indicator-current-song-name",
|
||||||
|
hpack: "center",
|
||||||
|
children: [
|
||||||
|
Widget.Label({
|
||||||
|
truncate: "end",
|
||||||
|
max_width_chars: 31,
|
||||||
|
wrap: true,
|
||||||
|
class_name: "media-indicator-current-song-name-label",
|
||||||
|
setup: (self) => {
|
||||||
|
self.hook(media, () => {
|
||||||
|
const curPlayer = getPlayerInfo();
|
||||||
|
return (self.label =
|
||||||
|
curPlayer !== undefined && curPlayer["track-title"].length
|
||||||
|
? curPlayer["track-title"]
|
||||||
|
: "No Media Currently Playing");
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
Widget.Box({
|
||||||
|
class_name: "media-indicator-current-song-author",
|
||||||
|
hpack: "center",
|
||||||
|
children: [
|
||||||
|
Widget.Label({
|
||||||
|
truncate: "end",
|
||||||
|
wrap: true,
|
||||||
|
max_width_chars: 35,
|
||||||
|
class_name: "media-indicator-current-song-author-label",
|
||||||
|
setup: (self) => {
|
||||||
|
self.hook(media, () => {
|
||||||
|
const curPlayer = getPlayerInfo();
|
||||||
|
|
||||||
|
const makeArtistList = (trackArtists: string[]) => {
|
||||||
|
if (trackArtists.length === 1 && !trackArtists[0].length) {
|
||||||
|
return "-----";
|
||||||
|
}
|
||||||
|
|
||||||
|
return trackArtists.join(", ");
|
||||||
|
};
|
||||||
|
return (self.label =
|
||||||
|
curPlayer !== undefined && curPlayer["track-artists"].length
|
||||||
|
? makeArtistList(curPlayer["track-artists"])
|
||||||
|
: "-----");
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
Widget.Box({
|
||||||
|
class_name: "media-indicator-current-song-album",
|
||||||
|
hpack: "center",
|
||||||
|
children: [
|
||||||
|
Widget.Label({
|
||||||
|
truncate: "end",
|
||||||
|
wrap: true,
|
||||||
|
max_width_chars: 40,
|
||||||
|
class_name: "media-indicator-current-song-album-label",
|
||||||
|
setup: (self) => {
|
||||||
|
self.hook(media, () => {
|
||||||
|
const curPlayer = getPlayerInfo();
|
||||||
|
return (self.label =
|
||||||
|
curPlayer !== undefined && curPlayer["track-album"].length
|
||||||
|
? curPlayer["track-album"]
|
||||||
|
: "---");
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export { MediaInfo };
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
const media = await Service.import("mpris");
|
|
||||||
import { MediaInfo } from "./components/mediainfo.js";
|
|
||||||
import { Controls } from "./components/controls.js";
|
|
||||||
import { Bar } from "./components/bar.js";
|
|
||||||
|
|
||||||
const Media = () => {
|
|
||||||
const curPlayer = Variable("");
|
|
||||||
|
|
||||||
media.connect("changed", () => {
|
|
||||||
const statusOrder = {
|
|
||||||
Playing: 1,
|
|
||||||
Paused: 2,
|
|
||||||
Stopped: 3,
|
|
||||||
};
|
|
||||||
|
|
||||||
const isPlaying = media.players.find(
|
|
||||||
(p) => p["play-back-status"] === "Playing",
|
|
||||||
);
|
|
||||||
|
|
||||||
if (isPlaying) {
|
|
||||||
curPlayer.value = media.players.sort(
|
|
||||||
(a, b) =>
|
|
||||||
statusOrder[a["play-back-status"]] -
|
|
||||||
statusOrder[b["play-back-status"]],
|
|
||||||
)[0].name;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const getPlayerInfo = () => {
|
|
||||||
return media.players.find((p) => p.name === curPlayer.value);
|
|
||||||
};
|
|
||||||
|
|
||||||
return Widget.Box({
|
|
||||||
class_name: "menu-section-container",
|
|
||||||
children: [
|
|
||||||
Widget.Box({
|
|
||||||
class_name: "menu-items-section",
|
|
||||||
vertical: false,
|
|
||||||
child: Widget.Box({
|
|
||||||
class_name: "menu-content",
|
|
||||||
children: [
|
|
||||||
Widget.Box({
|
|
||||||
class_name: "media-content",
|
|
||||||
child: Widget.Box({
|
|
||||||
class_name: "media-indicator-right-section",
|
|
||||||
hpack: "fill",
|
|
||||||
hexpand: true,
|
|
||||||
vertical: true,
|
|
||||||
children: [
|
|
||||||
MediaInfo(getPlayerInfo),
|
|
||||||
Controls(getPlayerInfo),
|
|
||||||
Bar(getPlayerInfo),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
setup: (self) => {
|
|
||||||
self.hook(media, () => {
|
|
||||||
const curPlayer = getPlayerInfo();
|
|
||||||
if (curPlayer !== undefined) {
|
|
||||||
self.css = `background-image: linear-gradient(
|
|
||||||
rgba(30, 30, 46, 0.85),
|
|
||||||
rgba(30, 30, 46, 0.9),
|
|
||||||
#1e1e2e 40em), url("${curPlayer.track_cover_url}");
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export { Media };
|
|
||||||
76
modules/menus/media/media.ts
Normal file
76
modules/menus/media/media.ts
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
const media = await Service.import("mpris");
|
||||||
|
import { MediaInfo } from "./components/mediainfo.js";
|
||||||
|
import { Controls } from "./components/controls.js";
|
||||||
|
import { Bar } from "./components/bar.js";
|
||||||
|
import { MprisPlayer } from "types/service/mpris.js";
|
||||||
|
|
||||||
|
const Media = () => {
|
||||||
|
const curPlayer = Variable("");
|
||||||
|
|
||||||
|
media.connect("changed", () => {
|
||||||
|
const statusOrder = {
|
||||||
|
Playing: 1,
|
||||||
|
Paused: 2,
|
||||||
|
Stopped: 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
const isPlaying = media.players.find(
|
||||||
|
(p) => p["play-back-status"] === "Playing",
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isPlaying) {
|
||||||
|
curPlayer.value = media.players.sort(
|
||||||
|
(a, b) =>
|
||||||
|
statusOrder[a["play-back-status"]] -
|
||||||
|
statusOrder[b["play-back-status"]],
|
||||||
|
)[0].name;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const getPlayerInfo = (): MprisPlayer => {
|
||||||
|
return media.players.find((p) => p.name === curPlayer.value) || media.players[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
return Widget.Box({
|
||||||
|
class_name: "menu-section-container",
|
||||||
|
children: [
|
||||||
|
Widget.Box({
|
||||||
|
class_name: "menu-items-section",
|
||||||
|
vertical: false,
|
||||||
|
child: Widget.Box({
|
||||||
|
class_name: "menu-content",
|
||||||
|
children: [
|
||||||
|
Widget.Box({
|
||||||
|
class_name: "media-content",
|
||||||
|
child: Widget.Box({
|
||||||
|
class_name: "media-indicator-right-section",
|
||||||
|
hpack: "fill",
|
||||||
|
hexpand: true,
|
||||||
|
vertical: true,
|
||||||
|
children: [
|
||||||
|
MediaInfo(getPlayerInfo),
|
||||||
|
Controls(getPlayerInfo),
|
||||||
|
Bar(getPlayerInfo),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
setup: (self) => {
|
||||||
|
self.hook(media, () => {
|
||||||
|
const curPlayer = getPlayerInfo();
|
||||||
|
if (curPlayer !== undefined) {
|
||||||
|
self.css = `background-image: linear-gradient(
|
||||||
|
rgba(30, 30, 46, 0.85),
|
||||||
|
rgba(30, 30, 46, 0.9),
|
||||||
|
#1e1e2e 40em), url("${curPlayer.track_cover_url}");
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export { Media };
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
const getWifiIcon = (iconName) => {
|
|
||||||
const deviceIconMap = [
|
|
||||||
["network-wireless-acquiring", ""],
|
|
||||||
["network-wireless-connected", ""],
|
|
||||||
["network-wireless-encrypted", ""],
|
|
||||||
["network-wireless-hotspot", ""],
|
|
||||||
["network-wireless-no-route", ""],
|
|
||||||
["network-wireless-offline", ""],
|
|
||||||
["network-wireless-signal-excellent", ""],
|
|
||||||
["network-wireless-signal-good", ""],
|
|
||||||
["network-wireless-signal-ok", ""],
|
|
||||||
["network-wireless-signal-weak", ""],
|
|
||||||
["network-wireless-signal-none", ""],
|
|
||||||
];
|
|
||||||
|
|
||||||
const foundMatch = deviceIconMap.find((icon) =>
|
|
||||||
RegExp(icon[0]).test(iconName.toLowerCase()),
|
|
||||||
);
|
|
||||||
|
|
||||||
return foundMatch ? foundMatch[1] : "";
|
|
||||||
};
|
|
||||||
|
|
||||||
export { getWifiIcon };
|
|
||||||
23
modules/menus/network/utils.ts
Normal file
23
modules/menus/network/utils.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
const getWifiIcon = (iconName: string) => {
|
||||||
|
const deviceIconMap = [
|
||||||
|
["network-wireless-acquiring", ""],
|
||||||
|
["network-wireless-connected", ""],
|
||||||
|
["network-wireless-encrypted", ""],
|
||||||
|
["network-wireless-hotspot", ""],
|
||||||
|
["network-wireless-no-route", ""],
|
||||||
|
["network-wireless-offline", ""],
|
||||||
|
["network-wireless-signal-excellent", ""],
|
||||||
|
["network-wireless-signal-good", ""],
|
||||||
|
["network-wireless-signal-ok", ""],
|
||||||
|
["network-wireless-signal-weak", ""],
|
||||||
|
["network-wireless-signal-none", ""],
|
||||||
|
];
|
||||||
|
|
||||||
|
const foundMatch = deviceIconMap.find((icon) =>
|
||||||
|
RegExp(icon[0]).test(iconName.toLowerCase()),
|
||||||
|
);
|
||||||
|
|
||||||
|
return foundMatch ? foundMatch[1] : "";
|
||||||
|
};
|
||||||
|
|
||||||
|
export { getWifiIcon };
|
||||||
@@ -1,97 +0,0 @@
|
|||||||
const renderWapStaging = (self, network, staging, connecting) => {
|
|
||||||
Utils.merge([network.bind("wifi"), staging.bind("value")], () => {
|
|
||||||
if (!Object.keys(staging.value).length) {
|
|
||||||
return (self.child = Widget.Box());
|
|
||||||
}
|
|
||||||
|
|
||||||
return (self.child = Widget.Box({
|
|
||||||
class_name: "network-element-item staging",
|
|
||||||
vertical: true,
|
|
||||||
children: [
|
|
||||||
Widget.Box({
|
|
||||||
hpack: "fill",
|
|
||||||
hexpand: true,
|
|
||||||
children: [
|
|
||||||
Widget.Icon({
|
|
||||||
class_name: `network-icon wifi`,
|
|
||||||
icon: `${staging.value.iconName}`,
|
|
||||||
}),
|
|
||||||
Widget.Box({
|
|
||||||
class_name: "connection-container",
|
|
||||||
hexpand: true,
|
|
||||||
vertical: true,
|
|
||||||
children: [
|
|
||||||
Widget.Label({
|
|
||||||
class_name: "active-connection",
|
|
||||||
hpack: "start",
|
|
||||||
truncate: "end",
|
|
||||||
wrap: true,
|
|
||||||
label: staging.value.ssid,
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
Widget.Revealer({
|
|
||||||
hpack: "end",
|
|
||||||
reveal_child: connecting
|
|
||||||
.bind("value")
|
|
||||||
.as((c) => staging.value.bssid === c),
|
|
||||||
child: Widget.Spinner({
|
|
||||||
class_name: "spinner wap",
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
Widget.Box({
|
|
||||||
class_name: "network-password-input-container",
|
|
||||||
hpack: "fill",
|
|
||||||
hexpand: true,
|
|
||||||
children: [
|
|
||||||
Widget.Entry({
|
|
||||||
hpack: "start",
|
|
||||||
hexpand: true,
|
|
||||||
visibility: false,
|
|
||||||
class_name: "network-password-input",
|
|
||||||
placeholder_text: "enter password",
|
|
||||||
onAccept: (selfInp) => {
|
|
||||||
connecting.value = staging.value.bssid;
|
|
||||||
Utils.execAsync(
|
|
||||||
`nmcli dev wifi connect ${staging.value.bssid} password ${selfInp.text}`,
|
|
||||||
)
|
|
||||||
.catch((err) => {
|
|
||||||
connecting.value = "";
|
|
||||||
console.error(
|
|
||||||
`Failed to connect to wifi: ${staging.value.ssid}... ${err}`,
|
|
||||||
);
|
|
||||||
Utils.notify({
|
|
||||||
summary: "Network",
|
|
||||||
body: err,
|
|
||||||
timeout: 5000,
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
connecting.value = "";
|
|
||||||
staging.value = {};
|
|
||||||
});
|
|
||||||
selfInp.text = "";
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
Widget.Button({
|
|
||||||
hpack: "end",
|
|
||||||
class_name: "close-network-password-input-button",
|
|
||||||
on_primary_click: () => {
|
|
||||||
connecting.value = "";
|
|
||||||
staging.value = {};
|
|
||||||
},
|
|
||||||
child: Widget.Icon({
|
|
||||||
class_name: "close-network-password-input-icon",
|
|
||||||
icon: "window-close-symbolic",
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export { renderWapStaging };
|
|
||||||
100
modules/menus/network/wifi/APStaging.ts
Normal file
100
modules/menus/network/wifi/APStaging.ts
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
import { Network } from "types/service/network";
|
||||||
|
import { Variable } from "types/variable";
|
||||||
|
import { AccessPoint } from "lib/types/network";
|
||||||
|
const renderWapStaging = (self: any, network: Network, staging: Variable<AccessPoint>, connecting: Variable<string>) => {
|
||||||
|
Utils.merge([network.bind("wifi"), staging.bind("value")], () => {
|
||||||
|
if (!Object.keys(staging.value).length) {
|
||||||
|
return (self.child = Widget.Box());
|
||||||
|
}
|
||||||
|
|
||||||
|
return (self.child = Widget.Box({
|
||||||
|
class_name: "network-element-item staging",
|
||||||
|
vertical: true,
|
||||||
|
children: [
|
||||||
|
Widget.Box({
|
||||||
|
hpack: "fill",
|
||||||
|
hexpand: true,
|
||||||
|
children: [
|
||||||
|
Widget.Icon({
|
||||||
|
class_name: `network-icon wifi`,
|
||||||
|
icon: `${staging.value.iconName}`,
|
||||||
|
}),
|
||||||
|
Widget.Box({
|
||||||
|
class_name: "connection-container",
|
||||||
|
hexpand: true,
|
||||||
|
vertical: true,
|
||||||
|
children: [
|
||||||
|
Widget.Label({
|
||||||
|
class_name: "active-connection",
|
||||||
|
hpack: "start",
|
||||||
|
truncate: "end",
|
||||||
|
wrap: true,
|
||||||
|
label: staging.value.ssid,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
Widget.Revealer({
|
||||||
|
hpack: "end",
|
||||||
|
reveal_child: connecting
|
||||||
|
.bind("value")
|
||||||
|
.as((c) => staging.value.bssid === c),
|
||||||
|
child: Widget.Spinner({
|
||||||
|
class_name: "spinner wap",
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
Widget.Box({
|
||||||
|
class_name: "network-password-input-container",
|
||||||
|
hpack: "fill",
|
||||||
|
hexpand: true,
|
||||||
|
children: [
|
||||||
|
Widget.Entry({
|
||||||
|
hpack: "start",
|
||||||
|
hexpand: true,
|
||||||
|
visibility: false,
|
||||||
|
class_name: "network-password-input",
|
||||||
|
placeholder_text: "enter password",
|
||||||
|
onAccept: (selfInp) => {
|
||||||
|
connecting.value = staging.value.bssid || "";
|
||||||
|
Utils.execAsync(
|
||||||
|
`nmcli dev wifi connect ${staging.value.bssid} password ${selfInp.text}`,
|
||||||
|
)
|
||||||
|
.catch((err) => {
|
||||||
|
connecting.value = "";
|
||||||
|
console.error(
|
||||||
|
`Failed to connect to wifi: ${staging.value.ssid}... ${err}`,
|
||||||
|
);
|
||||||
|
Utils.notify({
|
||||||
|
summary: "Network",
|
||||||
|
body: err,
|
||||||
|
timeout: 5000,
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
connecting.value = "";
|
||||||
|
staging.value = {} as AccessPoint;
|
||||||
|
});
|
||||||
|
selfInp.text = "";
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
Widget.Button({
|
||||||
|
hpack: "end",
|
||||||
|
class_name: "close-network-password-input-button",
|
||||||
|
on_primary_click: () => {
|
||||||
|
connecting.value = "";
|
||||||
|
staging.value = {} as AccessPoint;
|
||||||
|
},
|
||||||
|
child: Widget.Icon({
|
||||||
|
class_name: "close-network-password-input-icon",
|
||||||
|
icon: "window-close-symbolic",
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export { renderWapStaging };
|
||||||
@@ -1,211 +0,0 @@
|
|||||||
import { getWifiIcon } from "../utils.js";
|
|
||||||
const renderWAPs = (self, network, staging, connecting) => {
|
|
||||||
const getIdBySsid = (ssid, nmcliOutput) => {
|
|
||||||
const lines = nmcliOutput.trim().split("\n");
|
|
||||||
for (const line of lines) {
|
|
||||||
const columns = line.trim().split(/\s{2,}/);
|
|
||||||
if (columns[0].includes(ssid)) {
|
|
||||||
return columns[1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
|
|
||||||
const WifiStatusMap = {
|
|
||||||
unknown: "Status Unknown",
|
|
||||||
unmanaged: "Unmanaged",
|
|
||||||
unavailable: "Unavailable",
|
|
||||||
disconnected: "Disconnected",
|
|
||||||
prepare: "Preparing Connecting",
|
|
||||||
config: "Connecting",
|
|
||||||
need_auth: "Needs Authentication",
|
|
||||||
ip_config: "Requesting IP",
|
|
||||||
ip_check: "Checking Access",
|
|
||||||
secondaries: "Waiting on Secondaries",
|
|
||||||
activated: "Connected",
|
|
||||||
deactivating: "Disconnecting",
|
|
||||||
failed: "Connection Failed",
|
|
||||||
};
|
|
||||||
self.hook(network, () => {
|
|
||||||
Utils.merge([staging.bind("value"), connecting.bind("value")], () => {
|
|
||||||
// Sometimes the network service will yield a "this._device is undefined" when
|
|
||||||
// trying to access the "access_points" property. So we must validate that
|
|
||||||
// it's not 'undefined'
|
|
||||||
let WAPs =
|
|
||||||
network.wifi._device !== undefined ? network.wifi["access-points"] : [];
|
|
||||||
|
|
||||||
const dedupeWAPs = () => {
|
|
||||||
const dedupMap = {};
|
|
||||||
WAPs.forEach((item) => {
|
|
||||||
if (!Object.hasOwnProperty.call(dedupMap, item.ssid)) {
|
|
||||||
dedupMap[item.ssid] = item;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return Object.keys(dedupMap).map((itm) => dedupMap[itm]);
|
|
||||||
};
|
|
||||||
|
|
||||||
WAPs = dedupeWAPs();
|
|
||||||
|
|
||||||
const isInStaging = (wap) => {
|
|
||||||
if (Object.keys(staging.value).length === 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return wap.bssid === staging.value.bssid;
|
|
||||||
};
|
|
||||||
|
|
||||||
const isDisconnecting = (wap) => {
|
|
||||||
if (wap.ssid === network.wifi.ssid) {
|
|
||||||
return network.wifi.state.toLowerCase() === "deactivating";
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
const filteredWAPs = WAPs.filter((ap) => {
|
|
||||||
return ap.ssid !== "Unknown" && !isInStaging(ap);
|
|
||||||
}).sort((a, b) => {
|
|
||||||
if (network.wifi.ssid === a.ssid) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (network.wifi.ssid === b.ssid) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return b.strength - a.strength;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (filteredWAPs.length <= 0 && Object.keys(staging.value).length === 0) {
|
|
||||||
return (self.child = Widget.Label({
|
|
||||||
class_name: "waps-not-found dim",
|
|
||||||
expand: true,
|
|
||||||
hpack: "center",
|
|
||||||
vpack: "center",
|
|
||||||
label: "No Wi-Fi Networks Found",
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
return (self.children = filteredWAPs.map((ap) => {
|
|
||||||
return Widget.Box({
|
|
||||||
children: [
|
|
||||||
Widget.Button({
|
|
||||||
on_primary_click: () => {
|
|
||||||
if (ap.bssid === connecting.value || ap.active) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
connecting.value = ap.bssid;
|
|
||||||
Utils.execAsync(`nmcli device wifi connect ${ap.bssid}`)
|
|
||||||
.then(() => {
|
|
||||||
connecting.value = "";
|
|
||||||
staging.value = {};
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
if (
|
|
||||||
err
|
|
||||||
.toLowerCase()
|
|
||||||
.includes("secrets were required, but not provided")
|
|
||||||
) {
|
|
||||||
staging.value = ap;
|
|
||||||
} else {
|
|
||||||
Utils.notify({
|
|
||||||
summary: "Network",
|
|
||||||
body: err,
|
|
||||||
timeout: 5000,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
connecting.value = "";
|
|
||||||
});
|
|
||||||
},
|
|
||||||
class_name: "network-element-item",
|
|
||||||
child: Widget.Box({
|
|
||||||
hexpand: true,
|
|
||||||
children: [
|
|
||||||
Widget.Box({
|
|
||||||
hpack: "start",
|
|
||||||
hexpand: true,
|
|
||||||
children: [
|
|
||||||
Widget.Label({
|
|
||||||
vpack: "start",
|
|
||||||
class_name: `network-icon wifi ${ap.ssid === network.wifi.ssid ? "active" : ""}`,
|
|
||||||
label: getWifiIcon(`${ap["iconName"]}`),
|
|
||||||
}),
|
|
||||||
Widget.Box({
|
|
||||||
class_name: "connection-container",
|
|
||||||
vpack: "center",
|
|
||||||
vertical: true,
|
|
||||||
children: [
|
|
||||||
Widget.Label({
|
|
||||||
vpack: "center",
|
|
||||||
class_name: "active-connection",
|
|
||||||
hpack: "start",
|
|
||||||
truncate: "end",
|
|
||||||
wrap: true,
|
|
||||||
label: ap.ssid,
|
|
||||||
}),
|
|
||||||
Widget.Revealer({
|
|
||||||
revealChild: ap.ssid === network.wifi.ssid,
|
|
||||||
child: Widget.Label({
|
|
||||||
hpack: "start",
|
|
||||||
class_name: "connection-status dim",
|
|
||||||
label:
|
|
||||||
WifiStatusMap[network.wifi.state.toLowerCase()],
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
Widget.Revealer({
|
|
||||||
hpack: "end",
|
|
||||||
vpack: "start",
|
|
||||||
reveal_child:
|
|
||||||
ap.bssid === connecting.value || isDisconnecting(ap),
|
|
||||||
child: Widget.Spinner({
|
|
||||||
vpack: "start",
|
|
||||||
class_name: "spinner wap",
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
Widget.Revealer({
|
|
||||||
vpack: "start",
|
|
||||||
reveal_child: ap.bssid !== connecting.value && ap.active,
|
|
||||||
child: Widget.Button({
|
|
||||||
tooltip_text: "Delete/Forget Network",
|
|
||||||
class_name: "menu-icon-button network disconnect",
|
|
||||||
on_primary_click: () => {
|
|
||||||
connecting.value = ap.bssid;
|
|
||||||
Utils.execAsync("nmcli connection show --active").then(() => {
|
|
||||||
Utils.execAsync("nmcli connection show --active").then(
|
|
||||||
(res) => {
|
|
||||||
const connectionId = getIdBySsid(ap.ssid, res);
|
|
||||||
|
|
||||||
Utils.execAsync(
|
|
||||||
`nmcli connection delete ${connectionId} "${ap.ssid}"`,
|
|
||||||
)
|
|
||||||
.then(() => (connecting.value = ""))
|
|
||||||
.catch((err) => {
|
|
||||||
connecting.value = "";
|
|
||||||
console.error(
|
|
||||||
`Error while forgetting "${ap.ssid}": ${err}`,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
child: Widget.Label({
|
|
||||||
label: "",
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export { renderWAPs };
|
|
||||||
216
modules/menus/network/wifi/WirelessAPs.ts
Normal file
216
modules/menus/network/wifi/WirelessAPs.ts
Normal file
@@ -0,0 +1,216 @@
|
|||||||
|
import { Network } from "types/service/network.js";
|
||||||
|
import { AccessPoint } from "lib/types/network.js";
|
||||||
|
import { Variable } from "types/variable.js";
|
||||||
|
import { getWifiIcon } from "../utils.js";
|
||||||
|
const renderWAPs = (self: any, network: Network, staging: Variable<AccessPoint>, connecting: Variable<string>) => {
|
||||||
|
const getIdBySsid = (ssid: string, nmcliOutput: string) => {
|
||||||
|
const lines = nmcliOutput.trim().split("\n");
|
||||||
|
for (const line of lines) {
|
||||||
|
const columns = line.trim().split(/\s{2,}/);
|
||||||
|
if (columns[0].includes(ssid)) {
|
||||||
|
return columns[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const WifiStatusMap = {
|
||||||
|
unknown: "Status Unknown",
|
||||||
|
unmanaged: "Unmanaged",
|
||||||
|
unavailable: "Unavailable",
|
||||||
|
disconnected: "Disconnected",
|
||||||
|
prepare: "Preparing Connecting",
|
||||||
|
config: "Connecting",
|
||||||
|
need_auth: "Needs Authentication",
|
||||||
|
ip_config: "Requesting IP",
|
||||||
|
ip_check: "Checking Access",
|
||||||
|
secondaries: "Waiting on Secondaries",
|
||||||
|
activated: "Connected",
|
||||||
|
deactivating: "Disconnecting",
|
||||||
|
failed: "Connection Failed",
|
||||||
|
};
|
||||||
|
self.hook(network, () => {
|
||||||
|
Utils.merge([staging.bind("value"), connecting.bind("value")], () => {
|
||||||
|
// Sometimes the network service will yield a "this._device is undefined" when
|
||||||
|
// trying to access the "access_points" property. So we must validate that
|
||||||
|
// it's not 'undefined'
|
||||||
|
//
|
||||||
|
// Also this is an AGS bug that needs to be fixed
|
||||||
|
let WAPs =
|
||||||
|
network.wifi._device !== undefined ? network.wifi["access-points"] : [];
|
||||||
|
|
||||||
|
const dedupeWAPs = () => {
|
||||||
|
const dedupMap = {};
|
||||||
|
WAPs.forEach((item: AccessPoint) => {
|
||||||
|
if (item.ssid !== null && !Object.hasOwnProperty.call(dedupMap, item.ssid)) {
|
||||||
|
dedupMap[item.ssid] = item;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return Object.keys(dedupMap).map((itm) => dedupMap[itm]);
|
||||||
|
};
|
||||||
|
|
||||||
|
WAPs = dedupeWAPs();
|
||||||
|
|
||||||
|
const isInStaging = (wap: AccessPoint) => {
|
||||||
|
if (Object.keys(staging.value).length === 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return wap.bssid === staging.value.bssid;
|
||||||
|
};
|
||||||
|
|
||||||
|
const isDisconnecting = (wap: AccessPoint) => {
|
||||||
|
if (wap.ssid === network.wifi.ssid) {
|
||||||
|
return network.wifi.state.toLowerCase() === "deactivating";
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const filteredWAPs = WAPs.filter((ap: AccessPoint) => {
|
||||||
|
return ap.ssid !== "Unknown" && !isInStaging(ap);
|
||||||
|
}).sort((a: AccessPoint, b: AccessPoint) => {
|
||||||
|
if (network.wifi.ssid === a.ssid) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (network.wifi.ssid === b.ssid) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return b.strength - a.strength;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (filteredWAPs.length <= 0 && Object.keys(staging.value).length === 0) {
|
||||||
|
return (self.child = Widget.Label({
|
||||||
|
class_name: "waps-not-found dim",
|
||||||
|
expand: true,
|
||||||
|
hpack: "center",
|
||||||
|
vpack: "center",
|
||||||
|
label: "No Wi-Fi Networks Found",
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
return (self.children = filteredWAPs.map((ap: AccessPoint) => {
|
||||||
|
return Widget.Box({
|
||||||
|
children: [
|
||||||
|
Widget.Button({
|
||||||
|
on_primary_click: () => {
|
||||||
|
if (ap.bssid === connecting.value || ap.active) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
connecting.value = ap.bssid || "";
|
||||||
|
Utils.execAsync(`nmcli device wifi connect ${ap.bssid}`)
|
||||||
|
.then(() => {
|
||||||
|
connecting.value = "";
|
||||||
|
staging.value = {} as AccessPoint;
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
if (
|
||||||
|
err
|
||||||
|
.toLowerCase()
|
||||||
|
.includes("secrets were required, but not provided")
|
||||||
|
) {
|
||||||
|
staging.value = ap;
|
||||||
|
} else {
|
||||||
|
Utils.notify({
|
||||||
|
summary: "Network",
|
||||||
|
body: err,
|
||||||
|
timeout: 5000,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
connecting.value = "";
|
||||||
|
});
|
||||||
|
},
|
||||||
|
class_name: "network-element-item",
|
||||||
|
child: Widget.Box({
|
||||||
|
hexpand: true,
|
||||||
|
children: [
|
||||||
|
Widget.Box({
|
||||||
|
hpack: "start",
|
||||||
|
hexpand: true,
|
||||||
|
children: [
|
||||||
|
Widget.Label({
|
||||||
|
vpack: "start",
|
||||||
|
class_name: `network-icon wifi ${ap.ssid === network.wifi.ssid ? "active" : ""}`,
|
||||||
|
label: getWifiIcon(`${ap["iconName"]}`),
|
||||||
|
}),
|
||||||
|
Widget.Box({
|
||||||
|
class_name: "connection-container",
|
||||||
|
vpack: "center",
|
||||||
|
vertical: true,
|
||||||
|
children: [
|
||||||
|
Widget.Label({
|
||||||
|
vpack: "center",
|
||||||
|
class_name: "active-connection",
|
||||||
|
hpack: "start",
|
||||||
|
truncate: "end",
|
||||||
|
wrap: true,
|
||||||
|
label: ap.ssid,
|
||||||
|
}),
|
||||||
|
Widget.Revealer({
|
||||||
|
revealChild: ap.ssid === network.wifi.ssid,
|
||||||
|
child: Widget.Label({
|
||||||
|
hpack: "start",
|
||||||
|
class_name: "connection-status dim",
|
||||||
|
label:
|
||||||
|
WifiStatusMap[network.wifi.state.toLowerCase()],
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
Widget.Revealer({
|
||||||
|
hpack: "end",
|
||||||
|
vpack: "start",
|
||||||
|
reveal_child:
|
||||||
|
ap.bssid === connecting.value || isDisconnecting(ap),
|
||||||
|
child: Widget.Spinner({
|
||||||
|
vpack: "start",
|
||||||
|
class_name: "spinner wap",
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
Widget.Revealer({
|
||||||
|
vpack: "start",
|
||||||
|
reveal_child: ap.bssid !== connecting.value && ap.active,
|
||||||
|
child: Widget.Button({
|
||||||
|
tooltip_text: "Delete/Forget Network",
|
||||||
|
class_name: "menu-icon-button network disconnect",
|
||||||
|
on_primary_click: () => {
|
||||||
|
connecting.value = ap.bssid || "";
|
||||||
|
Utils.execAsync("nmcli connection show --active").then(() => {
|
||||||
|
Utils.execAsync("nmcli connection show --active").then(
|
||||||
|
(res) => {
|
||||||
|
const connectionId = getIdBySsid(ap.ssid || "", res);
|
||||||
|
|
||||||
|
Utils.execAsync(
|
||||||
|
`nmcli connection delete ${connectionId} "${ap.ssid}"`,
|
||||||
|
)
|
||||||
|
.then(() => (connecting.value = ""))
|
||||||
|
.catch((err) => {
|
||||||
|
connecting.value = "";
|
||||||
|
console.error(
|
||||||
|
`Error while forgetting "${ap.ssid}": ${err}`,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: Widget.Label({
|
||||||
|
label: "",
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export { renderWAPs };
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
const network = await Service.import("network");
|
|
||||||
import { renderWAPs } from "./WirelessAPs.js";
|
|
||||||
import { renderWapStaging } from "./APStaging.js";
|
|
||||||
|
|
||||||
const Staging = Variable({});
|
|
||||||
const Connecting = Variable("");
|
|
||||||
|
|
||||||
const searchInProgress = Variable(false);
|
|
||||||
|
|
||||||
const startRotation = () => {
|
|
||||||
searchInProgress.value = true;
|
|
||||||
setTimeout(() => {
|
|
||||||
searchInProgress.value = false;
|
|
||||||
}, 5 * 1000);
|
|
||||||
};
|
|
||||||
|
|
||||||
const Wifi = () => {
|
|
||||||
return Widget.Box({
|
|
||||||
class_name: "menu-section-container wifi",
|
|
||||||
vertical: true,
|
|
||||||
children: [
|
|
||||||
Widget.Box({
|
|
||||||
class_name: "menu-label-container",
|
|
||||||
hpack: "fill",
|
|
||||||
children: [
|
|
||||||
Widget.Label({
|
|
||||||
class_name: "menu-label",
|
|
||||||
hexpand: true,
|
|
||||||
hpack: "start",
|
|
||||||
label: "Wi-Fi",
|
|
||||||
}),
|
|
||||||
Widget.Button({
|
|
||||||
vpack: "center",
|
|
||||||
hpack: "end",
|
|
||||||
class_name: "menu-icon-button search network",
|
|
||||||
on_primary_click: () => {
|
|
||||||
startRotation();
|
|
||||||
network.wifi.scan();
|
|
||||||
},
|
|
||||||
child: Widget.Icon({
|
|
||||||
class_name: searchInProgress
|
|
||||||
.bind("value")
|
|
||||||
.as((v) => (v ? "spinning" : "")),
|
|
||||||
icon: "view-refresh-symbolic",
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
Widget.Box({
|
|
||||||
class_name: "menu-items-section",
|
|
||||||
vertical: true,
|
|
||||||
children: [
|
|
||||||
Widget.Box({
|
|
||||||
class_name: "wap-staging",
|
|
||||||
setup: (self) => {
|
|
||||||
renderWapStaging(self, network, Staging, Connecting);
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
Widget.Box({
|
|
||||||
class_name: "available-waps",
|
|
||||||
vertical: true,
|
|
||||||
setup: (self) => {
|
|
||||||
renderWAPs(self, network, Staging, Connecting);
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export { Wifi };
|
|
||||||
73
modules/menus/network/wifi/index.ts
Normal file
73
modules/menus/network/wifi/index.ts
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
const network = await Service.import("network");
|
||||||
|
import { renderWAPs } from "./WirelessAPs.js";
|
||||||
|
import { renderWapStaging } from "./APStaging.js";
|
||||||
|
import { AccessPoint } from "lib/types/network.js";
|
||||||
|
|
||||||
|
const Staging = Variable({} as AccessPoint);
|
||||||
|
const Connecting = Variable("");
|
||||||
|
|
||||||
|
const searchInProgress = Variable(false);
|
||||||
|
|
||||||
|
const startRotation = () => {
|
||||||
|
searchInProgress.value = true;
|
||||||
|
setTimeout(() => {
|
||||||
|
searchInProgress.value = false;
|
||||||
|
}, 5 * 1000);
|
||||||
|
};
|
||||||
|
|
||||||
|
const Wifi = () => {
|
||||||
|
return Widget.Box({
|
||||||
|
class_name: "menu-section-container wifi",
|
||||||
|
vertical: true,
|
||||||
|
children: [
|
||||||
|
Widget.Box({
|
||||||
|
class_name: "menu-label-container",
|
||||||
|
hpack: "fill",
|
||||||
|
children: [
|
||||||
|
Widget.Label({
|
||||||
|
class_name: "menu-label",
|
||||||
|
hexpand: true,
|
||||||
|
hpack: "start",
|
||||||
|
label: "Wi-Fi",
|
||||||
|
}),
|
||||||
|
Widget.Button({
|
||||||
|
vpack: "center",
|
||||||
|
hpack: "end",
|
||||||
|
class_name: "menu-icon-button search network",
|
||||||
|
on_primary_click: () => {
|
||||||
|
startRotation();
|
||||||
|
network.wifi.scan();
|
||||||
|
},
|
||||||
|
child: Widget.Icon({
|
||||||
|
class_name: searchInProgress
|
||||||
|
.bind("value")
|
||||||
|
.as((v) => (v ? "spinning" : "")),
|
||||||
|
icon: "view-refresh-symbolic",
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
Widget.Box({
|
||||||
|
class_name: "menu-items-section",
|
||||||
|
vertical: true,
|
||||||
|
children: [
|
||||||
|
Widget.Box({
|
||||||
|
class_name: "wap-staging",
|
||||||
|
setup: (self) => {
|
||||||
|
renderWapStaging(self, network, Staging, Connecting);
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
Widget.Box({
|
||||||
|
class_name: "available-waps",
|
||||||
|
vertical: true,
|
||||||
|
setup: (self) => {
|
||||||
|
renderWAPs(self, network, Staging, Connecting);
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export { Wifi };
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
const Controls = (notifs) => {
|
|
||||||
return Widget.Box({
|
|
||||||
class_name: "notification-menu-controls",
|
|
||||||
expand: false,
|
|
||||||
vertical: false,
|
|
||||||
children: [
|
|
||||||
Widget.Box({
|
|
||||||
class_name: "menu-label-container notifications",
|
|
||||||
hpack: "start",
|
|
||||||
vpack: "center",
|
|
||||||
expand: true,
|
|
||||||
children: [
|
|
||||||
Widget.Label({
|
|
||||||
class_name: "menu-label notifications",
|
|
||||||
label: "Notifications",
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
Widget.Box({
|
|
||||||
hpack: "end",
|
|
||||||
vpack: "center",
|
|
||||||
expand: false,
|
|
||||||
children: [
|
|
||||||
Widget.Switch({
|
|
||||||
class_name: "menu-switch notifications",
|
|
||||||
active: notifs.bind("dnd").as((dnd) => !dnd),
|
|
||||||
on_activate: ({ active }) => {
|
|
||||||
notifs.dnd = !active;
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
Widget.Box({
|
|
||||||
children: [
|
|
||||||
Widget.Separator({
|
|
||||||
hpack: "center",
|
|
||||||
vexpand: true,
|
|
||||||
vertical: true,
|
|
||||||
class_name: "menu-separator notification-controls",
|
|
||||||
}),
|
|
||||||
Widget.Button({
|
|
||||||
class_name: "clear-notifications-button",
|
|
||||||
tooltip_text: "Clear Notifications",
|
|
||||||
on_primary_click: () => notifs.clear(),
|
|
||||||
child: Widget.Label({
|
|
||||||
class_name: "clear-notifications-label",
|
|
||||||
label: "",
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export { Controls };
|
|
||||||
56
modules/menus/notifications/controls/index.ts
Normal file
56
modules/menus/notifications/controls/index.ts
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
const Controls = (notifs) => {
|
||||||
|
return Widget.Box({
|
||||||
|
class_name: "notification-menu-controls",
|
||||||
|
expand: false,
|
||||||
|
vertical: false,
|
||||||
|
children: [
|
||||||
|
Widget.Box({
|
||||||
|
class_name: "menu-label-container notifications",
|
||||||
|
hpack: "start",
|
||||||
|
vpack: "center",
|
||||||
|
expand: true,
|
||||||
|
children: [
|
||||||
|
Widget.Label({
|
||||||
|
class_name: "menu-label notifications",
|
||||||
|
label: "Notifications",
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
Widget.Box({
|
||||||
|
hpack: "end",
|
||||||
|
vpack: "center",
|
||||||
|
expand: false,
|
||||||
|
children: [
|
||||||
|
Widget.Switch({
|
||||||
|
class_name: "menu-switch notifications",
|
||||||
|
active: notifs.bind("dnd").as((dnd: boolean) => !dnd),
|
||||||
|
on_activate: ({ active }) => {
|
||||||
|
notifs.dnd = !active;
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
Widget.Box({
|
||||||
|
children: [
|
||||||
|
Widget.Separator({
|
||||||
|
hpack: "center",
|
||||||
|
vexpand: true,
|
||||||
|
vertical: true,
|
||||||
|
class_name: "menu-separator notification-controls",
|
||||||
|
}),
|
||||||
|
Widget.Button({
|
||||||
|
class_name: "clear-notifications-button",
|
||||||
|
tooltip_text: "Clear Notifications",
|
||||||
|
on_primary_click: () => notifs.clear(),
|
||||||
|
child: Widget.Label({
|
||||||
|
class_name: "clear-notifications-label",
|
||||||
|
label: "",
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export { Controls };
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
const Actions = (notif, notifs) => {
|
|
||||||
if (notif.actions !== undefined && notif.actions.length > 0) {
|
|
||||||
return Widget.Box({
|
|
||||||
class_name: "notification-card-actions menu",
|
|
||||||
hexpand: true,
|
|
||||||
vpack: "end",
|
|
||||||
children: notif.actions.map((action) => {
|
|
||||||
return Widget.Button({
|
|
||||||
hexpand: true,
|
|
||||||
class_name: "notification-action-buttons menu",
|
|
||||||
on_primary_click: () => {
|
|
||||||
if (action.id.includes("scriptAction:-")) {
|
|
||||||
App.closeWindow("notificationsmenu");
|
|
||||||
Utils.execAsync(
|
|
||||||
`${action.id.replace("scriptAction:-", "")}`,
|
|
||||||
).catch((err) => console.error(err));
|
|
||||||
notifs.CloseNotification(notif.id);
|
|
||||||
} else {
|
|
||||||
App.closeWindow("notificationsmenu");
|
|
||||||
notif.invoke(action.id);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
child: Widget.Box({
|
|
||||||
hpack: "center",
|
|
||||||
hexpand: true,
|
|
||||||
children: [
|
|
||||||
Widget.Label({
|
|
||||||
class_name: "notification-action-buttons-label menu",
|
|
||||||
hexpand: true,
|
|
||||||
max_width_chars: 15,
|
|
||||||
truncate: "end",
|
|
||||||
wrap: true,
|
|
||||||
label: action.label,
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return Widget.Box({
|
|
||||||
class_name: "spacer",
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export { Actions };
|
|
||||||
48
modules/menus/notifications/notification/actions/index.ts
Normal file
48
modules/menus/notifications/notification/actions/index.ts
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
import { Notification, Notifications } from "types/service/notifications";
|
||||||
|
const Actions = (notif: Notification, notifs: Notifications) => {
|
||||||
|
if (notif.actions !== undefined && notif.actions.length > 0) {
|
||||||
|
return Widget.Box({
|
||||||
|
class_name: "notification-card-actions menu",
|
||||||
|
hexpand: true,
|
||||||
|
vpack: "end",
|
||||||
|
children: notif.actions.map((action) => {
|
||||||
|
return Widget.Button({
|
||||||
|
hexpand: true,
|
||||||
|
class_name: "notification-action-buttons menu",
|
||||||
|
on_primary_click: () => {
|
||||||
|
if (action.id.includes("scriptAction:-")) {
|
||||||
|
App.closeWindow("notificationsmenu");
|
||||||
|
Utils.execAsync(
|
||||||
|
`${action.id.replace("scriptAction:-", "")}`,
|
||||||
|
).catch((err) => console.error(err));
|
||||||
|
notifs.CloseNotification(notif.id);
|
||||||
|
} else {
|
||||||
|
App.closeWindow("notificationsmenu");
|
||||||
|
notif.invoke(action.id);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: Widget.Box({
|
||||||
|
hpack: "center",
|
||||||
|
hexpand: true,
|
||||||
|
children: [
|
||||||
|
Widget.Label({
|
||||||
|
class_name: "notification-action-buttons-label menu",
|
||||||
|
hexpand: true,
|
||||||
|
max_width_chars: 15,
|
||||||
|
truncate: "end",
|
||||||
|
wrap: true,
|
||||||
|
label: action.label,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return Widget.Box({
|
||||||
|
class_name: "spacer",
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export { Actions };
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
import { notifHasImg } from "../../utils.js";
|
|
||||||
|
|
||||||
export const Body = (notif) => {
|
|
||||||
return Widget.Box({
|
|
||||||
vpack: "start",
|
|
||||||
hexpand: true,
|
|
||||||
class_name: "notification-card-body menu",
|
|
||||||
children: [
|
|
||||||
Widget.Label({
|
|
||||||
hexpand: true,
|
|
||||||
use_markup: true,
|
|
||||||
xalign: 0,
|
|
||||||
justification: "left",
|
|
||||||
truncate: "end",
|
|
||||||
lines: 2,
|
|
||||||
max_width_chars: !notifHasImg(notif) ? 35 : 28,
|
|
||||||
wrap: true,
|
|
||||||
class_name: "notification-card-body-label menu",
|
|
||||||
label: notif["body"],
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
};
|
|
||||||
24
modules/menus/notifications/notification/body/index.ts
Normal file
24
modules/menus/notifications/notification/body/index.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import { notifHasImg } from "../../utils.js";
|
||||||
|
import { Notification } from "types/service/notifications";
|
||||||
|
|
||||||
|
export const Body = (notif: Notification) => {
|
||||||
|
return Widget.Box({
|
||||||
|
vpack: "start",
|
||||||
|
hexpand: true,
|
||||||
|
class_name: "notification-card-body menu",
|
||||||
|
children: [
|
||||||
|
Widget.Label({
|
||||||
|
hexpand: true,
|
||||||
|
use_markup: true,
|
||||||
|
xalign: 0,
|
||||||
|
justification: "left",
|
||||||
|
truncate: "end",
|
||||||
|
lines: 2,
|
||||||
|
max_width_chars: !notifHasImg(notif) ? 35 : 28,
|
||||||
|
wrap: true,
|
||||||
|
class_name: "notification-card-body-label menu",
|
||||||
|
label: notif["body"],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
export const CloseButton = (notif, notifs) => {
|
|
||||||
return Widget.Button({
|
|
||||||
class_name: "close-notification-button menu",
|
|
||||||
on_primary_click: () => {
|
|
||||||
notifs.CloseNotification(notif.id);
|
|
||||||
},
|
|
||||||
child: Widget.Label({
|
|
||||||
label: "",
|
|
||||||
hpack: "center",
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
};
|
|
||||||
13
modules/menus/notifications/notification/close/index.ts
Normal file
13
modules/menus/notifications/notification/close/index.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import { Notification, Notifications } from "types/service/notifications";
|
||||||
|
export const CloseButton = (notif: Notification, notifs: Notifications) => {
|
||||||
|
return Widget.Button({
|
||||||
|
class_name: "close-notification-button menu",
|
||||||
|
on_primary_click: () => {
|
||||||
|
notifs.CloseNotification(notif.id);
|
||||||
|
},
|
||||||
|
child: Widget.Label({
|
||||||
|
label: "",
|
||||||
|
hpack: "center",
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
import GLib from "gi://GLib";
|
|
||||||
import { NotificationIcon } from "./icon.js";
|
|
||||||
import { notifHasImg } from "../../utils.js";
|
|
||||||
|
|
||||||
const time = (time, format = "%I:%M %p") =>
|
|
||||||
GLib.DateTime.new_from_unix_local(time).format(format);
|
|
||||||
|
|
||||||
export const Header = (notif) => {
|
|
||||||
return Widget.Box({
|
|
||||||
vertical: false,
|
|
||||||
hexpand: true,
|
|
||||||
children: [
|
|
||||||
Widget.Box({
|
|
||||||
class_name: "notification-card-header menu",
|
|
||||||
hpack: "start",
|
|
||||||
children: [NotificationIcon(notif)],
|
|
||||||
}),
|
|
||||||
Widget.Box({
|
|
||||||
class_name: "notification-card-header menu",
|
|
||||||
hexpand: true,
|
|
||||||
vpack: "start",
|
|
||||||
children: [
|
|
||||||
Widget.Label({
|
|
||||||
class_name: "notification-card-header-label menu",
|
|
||||||
hpack: "start",
|
|
||||||
hexpand: true,
|
|
||||||
vexpand: true,
|
|
||||||
max_width_chars: !notifHasImg(notif) ? 34 : 22,
|
|
||||||
truncate: "end",
|
|
||||||
wrap: true,
|
|
||||||
label: notif["summary"],
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
Widget.Box({
|
|
||||||
class_name: "notification-card-header menu",
|
|
||||||
hpack: "end",
|
|
||||||
vpack: "start",
|
|
||||||
hexpand: true,
|
|
||||||
child: Widget.Label({
|
|
||||||
vexpand: true,
|
|
||||||
class_name: "notification-time",
|
|
||||||
label: time(notif.time),
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
};
|
|
||||||
49
modules/menus/notifications/notification/header/index.ts
Normal file
49
modules/menus/notifications/notification/header/index.ts
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
import GLib from "gi://GLib";
|
||||||
|
import { Notification } from "types/service/notifications";
|
||||||
|
import { NotificationIcon } from "./icon.js";
|
||||||
|
import { notifHasImg } from "../../utils.js";
|
||||||
|
|
||||||
|
const time = (time: number, format = "%I:%M %p") =>
|
||||||
|
GLib.DateTime.new_from_unix_local(time).format(format);
|
||||||
|
|
||||||
|
export const Header = (notif: Notification) => {
|
||||||
|
return Widget.Box({
|
||||||
|
vertical: false,
|
||||||
|
hexpand: true,
|
||||||
|
children: [
|
||||||
|
Widget.Box({
|
||||||
|
class_name: "notification-card-header menu",
|
||||||
|
hpack: "start",
|
||||||
|
children: [NotificationIcon(notif)],
|
||||||
|
}),
|
||||||
|
Widget.Box({
|
||||||
|
class_name: "notification-card-header menu",
|
||||||
|
hexpand: true,
|
||||||
|
vpack: "start",
|
||||||
|
children: [
|
||||||
|
Widget.Label({
|
||||||
|
class_name: "notification-card-header-label menu",
|
||||||
|
hpack: "start",
|
||||||
|
hexpand: true,
|
||||||
|
vexpand: true,
|
||||||
|
max_width_chars: !notifHasImg(notif) ? 34 : 22,
|
||||||
|
truncate: "end",
|
||||||
|
wrap: true,
|
||||||
|
label: notif["summary"],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
Widget.Box({
|
||||||
|
class_name: "notification-card-header menu",
|
||||||
|
hpack: "end",
|
||||||
|
vpack: "start",
|
||||||
|
hexpand: true,
|
||||||
|
child: Widget.Label({
|
||||||
|
vexpand: true,
|
||||||
|
class_name: "notification-time",
|
||||||
|
label: time(notif.time),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
import { notifHasImg } from "../../utils.js";
|
|
||||||
|
|
||||||
const Image = (notif) => {
|
|
||||||
if (notifHasImg(notif)) {
|
|
||||||
return Widget.Box({
|
|
||||||
class_name: "notification-card-image-container menu",
|
|
||||||
hpack: "center",
|
|
||||||
vpack: "center",
|
|
||||||
vexpand: false,
|
|
||||||
child: Widget.Box({
|
|
||||||
hpack: "center",
|
|
||||||
vexpand: false,
|
|
||||||
class_name: "notification-card-image menu",
|
|
||||||
css: `background-image: url("${notif.image}")`,
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return Widget.Box();
|
|
||||||
};
|
|
||||||
|
|
||||||
export { Image };
|
|
||||||
23
modules/menus/notifications/notification/image/index.ts
Normal file
23
modules/menus/notifications/notification/image/index.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import { Notification } from "types/service/notifications";
|
||||||
|
import { notifHasImg } from "../../utils.js";
|
||||||
|
|
||||||
|
const Image = (notif: Notification) => {
|
||||||
|
if (notifHasImg(notif)) {
|
||||||
|
return Widget.Box({
|
||||||
|
class_name: "notification-card-image-container menu",
|
||||||
|
hpack: "center",
|
||||||
|
vpack: "center",
|
||||||
|
vexpand: false,
|
||||||
|
child: Widget.Box({
|
||||||
|
hpack: "center",
|
||||||
|
vexpand: false,
|
||||||
|
class_name: "notification-card-image menu",
|
||||||
|
css: `background-image: url("${notif.image}")`,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return Widget.Box();
|
||||||
|
};
|
||||||
|
|
||||||
|
export { Image };
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
import { notifHasImg } from "../utils.js";
|
|
||||||
import { Header } from "./header/index.js";
|
|
||||||
import { Actions } from "./actions/index.js";
|
|
||||||
import { Image } from "./image/index.js";
|
|
||||||
import { Placeholder } from "./placeholder/index.js";
|
|
||||||
import { Body } from "./body/index.js";
|
|
||||||
import { CloseButton } from "./close/index.js";
|
|
||||||
|
|
||||||
const NotificationCard = (notifs) => {
|
|
||||||
return Widget.Box({
|
|
||||||
class_name: "menu-content-container notifications",
|
|
||||||
hpack: "center",
|
|
||||||
vexpand: true,
|
|
||||||
spacing: 0,
|
|
||||||
vertical: true,
|
|
||||||
setup: (self) => {
|
|
||||||
self.hook(notifs, () => {
|
|
||||||
const sortedNotifications = notifs.notifications.sort(
|
|
||||||
(a, b) => b.time - a.time,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (notifs.notifications.length <= 0) {
|
|
||||||
return (self.children = [Placeholder(notifs)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (self.children = sortedNotifications.map((notif) => {
|
|
||||||
return Widget.Box({
|
|
||||||
class_name: "notification-card-content-container",
|
|
||||||
children: [
|
|
||||||
Widget.Box({
|
|
||||||
class_name: "notification-card menu",
|
|
||||||
vpack: "start",
|
|
||||||
hexpand: true,
|
|
||||||
vexpand: false,
|
|
||||||
children: [
|
|
||||||
Image(notif),
|
|
||||||
Widget.Box({
|
|
||||||
vpack: "center",
|
|
||||||
vertical: true,
|
|
||||||
hexpand: true,
|
|
||||||
class_name: `notification-card-content ${!notifHasImg(notif) ? "noimg" : " menu"}`,
|
|
||||||
children: [
|
|
||||||
Header(notif),
|
|
||||||
Body(notif),
|
|
||||||
Actions(notif, notifs),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
CloseButton(notif, notifs),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export { NotificationCard };
|
|
||||||
60
modules/menus/notifications/notification/index.ts
Normal file
60
modules/menus/notifications/notification/index.ts
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
import { Notifications, Notification } from "types/service/notifications";
|
||||||
|
import { notifHasImg } from "../utils.js";
|
||||||
|
import { Header } from "./header/index.js";
|
||||||
|
import { Actions } from "./actions/index.js";
|
||||||
|
import { Image } from "./image/index.js";
|
||||||
|
import { Placeholder } from "./placeholder/index.js";
|
||||||
|
import { Body } from "./body/index.js";
|
||||||
|
import { CloseButton } from "./close/index.js";
|
||||||
|
|
||||||
|
const NotificationCard = (notifs: Notifications) => {
|
||||||
|
return Widget.Box({
|
||||||
|
class_name: "menu-content-container notifications",
|
||||||
|
hpack: "center",
|
||||||
|
vexpand: true,
|
||||||
|
spacing: 0,
|
||||||
|
vertical: true,
|
||||||
|
setup: (self) => {
|
||||||
|
self.hook(notifs, () => {
|
||||||
|
const sortedNotifications = notifs.notifications.sort(
|
||||||
|
(a, b) => b.time - a.time,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (notifs.notifications.length <= 0) {
|
||||||
|
return (self.children = [Placeholder(notifs)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (self.children = sortedNotifications.map((notif: Notification) => {
|
||||||
|
return Widget.Box({
|
||||||
|
class_name: "notification-card-content-container",
|
||||||
|
children: [
|
||||||
|
Widget.Box({
|
||||||
|
class_name: "notification-card menu",
|
||||||
|
vpack: "start",
|
||||||
|
hexpand: true,
|
||||||
|
vexpand: false,
|
||||||
|
children: [
|
||||||
|
Image(notif),
|
||||||
|
Widget.Box({
|
||||||
|
vpack: "center",
|
||||||
|
vertical: true,
|
||||||
|
hexpand: true,
|
||||||
|
class_name: `notification-card-content ${!notifHasImg(notif) ? "noimg" : " menu"}`,
|
||||||
|
children: [
|
||||||
|
Header(notif),
|
||||||
|
Body(notif),
|
||||||
|
Actions(notif, notifs),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
CloseButton(notif, notifs),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export { NotificationCard };
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
const Placeholder = (notifs) => {
|
|
||||||
return Widget.Box({
|
|
||||||
class_name: "notification-label-container",
|
|
||||||
vpack: "fill",
|
|
||||||
hpack: "center",
|
|
||||||
expand: true,
|
|
||||||
child: Widget.Box({
|
|
||||||
vpack: "center",
|
|
||||||
vertical: true,
|
|
||||||
expand: true,
|
|
||||||
children: [
|
|
||||||
Widget.Label({
|
|
||||||
vpack: "center",
|
|
||||||
class_name: "placeholder-label dim bell",
|
|
||||||
label: notifs.bind("dnd").as((dnd) => (dnd ? "" : "")),
|
|
||||||
}),
|
|
||||||
Widget.Label({
|
|
||||||
vpack: "start",
|
|
||||||
class_name: "placehold-label dim message",
|
|
||||||
label: "You're all caught up :)",
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export { Placeholder };
|
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import { Notifications } from "types/service/notifications";
|
||||||
|
|
||||||
|
const Placeholder = (notifs: Notifications) => {
|
||||||
|
return Widget.Box({
|
||||||
|
class_name: "notification-label-container",
|
||||||
|
vpack: "fill",
|
||||||
|
hpack: "center",
|
||||||
|
expand: true,
|
||||||
|
child: Widget.Box({
|
||||||
|
vpack: "center",
|
||||||
|
vertical: true,
|
||||||
|
expand: true,
|
||||||
|
children: [
|
||||||
|
Widget.Label({
|
||||||
|
vpack: "center",
|
||||||
|
class_name: "placeholder-label dim bell",
|
||||||
|
label: notifs.bind("dnd").as((dnd) => (dnd ? "" : "")),
|
||||||
|
}),
|
||||||
|
Widget.Label({
|
||||||
|
vpack: "start",
|
||||||
|
class_name: "placehold-label dim message",
|
||||||
|
label: "You're all caught up :)",
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export { Placeholder };
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
const notifHasImg = (notif) => {
|
|
||||||
return notif.image !== undefined && notif.image.length;
|
|
||||||
};
|
|
||||||
|
|
||||||
export { notifHasImg };
|
|
||||||
7
modules/menus/notifications/utils.ts
Normal file
7
modules/menus/notifications/utils.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import { Notification } from "types/service/notifications";
|
||||||
|
|
||||||
|
const notifHasImg = (notif: Notification) => {
|
||||||
|
return notif.image !== undefined && notif.image.length;
|
||||||
|
};
|
||||||
|
|
||||||
|
export { notifHasImg };
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
import options from "options";
|
|
||||||
const { sleep, reboot, logout, shutdown } = options.menus.dashboard.powermenu;
|
|
||||||
|
|
||||||
class PowerMenu extends Service {
|
|
||||||
static {
|
|
||||||
Service.register(
|
|
||||||
this,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
title: ["string"],
|
|
||||||
cmd: ["string"],
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#title = "";
|
|
||||||
#cmd = "";
|
|
||||||
|
|
||||||
get title() {
|
|
||||||
return this.#title;
|
|
||||||
}
|
|
||||||
|
|
||||||
action(action) {
|
|
||||||
[this.#cmd, this.#title] = {
|
|
||||||
sleep: [sleep.value, "Sleep"],
|
|
||||||
reboot: [reboot.value, "Reboot"],
|
|
||||||
logout: [logout.value, "Log Out"],
|
|
||||||
shutdown: [shutdown.value, "Shutdown"],
|
|
||||||
}[action];
|
|
||||||
|
|
||||||
this.notify("cmd");
|
|
||||||
this.notify("title");
|
|
||||||
this.emit("changed");
|
|
||||||
App.closeWindow("powermenu");
|
|
||||||
App.openWindow("verification");
|
|
||||||
}
|
|
||||||
|
|
||||||
shutdown = () => {
|
|
||||||
this.action("shutdown");
|
|
||||||
};
|
|
||||||
|
|
||||||
exec = () => {
|
|
||||||
App.closeWindow("verification");
|
|
||||||
Utils.exec(this.#cmd);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const powermenu = new PowerMenu();
|
|
||||||
Object.assign(globalThis, { powermenu });
|
|
||||||
export default powermenu;
|
|
||||||
51
modules/menus/power/helpers/actions.ts
Normal file
51
modules/menus/power/helpers/actions.ts
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
import { Action } from "lib/types/power";
|
||||||
|
import options from "options";
|
||||||
|
const { sleep, reboot, logout, shutdown } = options.menus.dashboard.powermenu;
|
||||||
|
|
||||||
|
class PowerMenu extends Service {
|
||||||
|
static {
|
||||||
|
Service.register(
|
||||||
|
this,
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
title: ["string"],
|
||||||
|
cmd: ["string"],
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#title = "";
|
||||||
|
#cmd = "";
|
||||||
|
|
||||||
|
get title() {
|
||||||
|
return this.#title;
|
||||||
|
}
|
||||||
|
|
||||||
|
action(action: Action) {
|
||||||
|
[this.#cmd, this.#title] = {
|
||||||
|
sleep: [sleep.value, "Sleep"],
|
||||||
|
reboot: [reboot.value, "Reboot"],
|
||||||
|
logout: [logout.value, "Log Out"],
|
||||||
|
shutdown: [shutdown.value, "Shutdown"],
|
||||||
|
}[action];
|
||||||
|
|
||||||
|
this.notify("cmd");
|
||||||
|
this.notify("title");
|
||||||
|
this.emit("changed");
|
||||||
|
App.closeWindow("powermenu");
|
||||||
|
App.openWindow("verification");
|
||||||
|
}
|
||||||
|
|
||||||
|
shutdown = () => {
|
||||||
|
this.action("shutdown");
|
||||||
|
};
|
||||||
|
|
||||||
|
exec = () => {
|
||||||
|
App.closeWindow("verification");
|
||||||
|
Utils.exec(this.#cmd);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const powermenu = new PowerMenu();
|
||||||
|
Object.assign(globalThis, { powermenu });
|
||||||
|
export default powermenu;
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
import PopupWindow from "../PopupWindow.js";
|
|
||||||
import powermenu from "./helpers/actions.js";
|
|
||||||
import icons from "../../icons/index.js";
|
|
||||||
|
|
||||||
const SysButton = (action, label) =>
|
|
||||||
Widget.Button({
|
|
||||||
class_name: `widget-button powermenu-button-${action}`,
|
|
||||||
on_clicked: () => powermenu.action(action),
|
|
||||||
child: Widget.Box({
|
|
||||||
vertical: true,
|
|
||||||
class_name: "system-button widget-box",
|
|
||||||
children: [
|
|
||||||
Widget.Icon({
|
|
||||||
class_name: `system-button_icon ${action}`,
|
|
||||||
icon: icons.powermenu[action],
|
|
||||||
}),
|
|
||||||
Widget.Label({
|
|
||||||
class_name: `system-button_label ${action}`,
|
|
||||||
label,
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
export default () =>
|
|
||||||
PopupWindow({
|
|
||||||
name: "powermenu",
|
|
||||||
transition: "crossfade",
|
|
||||||
child: Widget.Box({
|
|
||||||
class_name: "powermenu horizontal",
|
|
||||||
children: [
|
|
||||||
SysButton("shutdown", "SHUTDOWN"),
|
|
||||||
SysButton("logout", "LOG OUT"),
|
|
||||||
SysButton("reboot", "REBOOT"),
|
|
||||||
SysButton("sleep", "SLEEP"),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
38
modules/menus/power/index.ts
Normal file
38
modules/menus/power/index.ts
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import { Action } from "lib/types/power.js";
|
||||||
|
import PopupWindow from "../PopupWindow.js";
|
||||||
|
import powermenu from "./helpers/actions.js";
|
||||||
|
import icons from "../../icons/index.js";
|
||||||
|
|
||||||
|
const SysButton = (action: Action, label: string) =>
|
||||||
|
Widget.Button({
|
||||||
|
class_name: `widget-button powermenu-button-${action}`,
|
||||||
|
on_clicked: () => powermenu.action(action),
|
||||||
|
child: Widget.Box({
|
||||||
|
vertical: true,
|
||||||
|
class_name: "system-button widget-box",
|
||||||
|
children: [
|
||||||
|
Widget.Icon({
|
||||||
|
class_name: `system-button_icon ${action}`,
|
||||||
|
icon: icons.powermenu[action],
|
||||||
|
}),
|
||||||
|
Widget.Label({
|
||||||
|
class_name: `system-button_label ${action}`,
|
||||||
|
label,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
export default () =>
|
||||||
|
PopupWindow({
|
||||||
|
name: "powermenu",
|
||||||
|
transition: "crossfade",
|
||||||
|
child: Widget.Box({
|
||||||
|
class_name: "powermenu horizontal",
|
||||||
|
children: [
|
||||||
|
SysButton("shutdown", "SHUTDOWN"),
|
||||||
|
SysButton("logout", "LOG OUT"),
|
||||||
|
SysButton("reboot", "REBOOT"),
|
||||||
|
SysButton("sleep", "SLEEP"),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
});
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
const Action = (notif, notifs) => {
|
|
||||||
if (notif.actions !== undefined && notif.actions.length > 0) {
|
|
||||||
return Widget.Box({
|
|
||||||
class_name: "notification-card-actions",
|
|
||||||
hexpand: true,
|
|
||||||
vpack: "end",
|
|
||||||
children: notif.actions.map((action) => {
|
|
||||||
return Widget.Button({
|
|
||||||
hexpand: true,
|
|
||||||
class_name: "notification-action-buttons",
|
|
||||||
on_primary_click: () => {
|
|
||||||
if (action.id.includes("scriptAction:-")) {
|
|
||||||
Utils.execAsync(
|
|
||||||
`${action.id.replace("scriptAction:-", "")}`,
|
|
||||||
).catch((err) => console.error(err));
|
|
||||||
notifs.CloseNotification(notif.id);
|
|
||||||
} else {
|
|
||||||
notif.invoke(action.id);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
child: Widget.Box({
|
|
||||||
hpack: "center",
|
|
||||||
hexpand: true,
|
|
||||||
children: [
|
|
||||||
Widget.Label({
|
|
||||||
class_name: "notification-action-buttons-label",
|
|
||||||
hexpand: true,
|
|
||||||
label: action.label,
|
|
||||||
max_width_chars: 15,
|
|
||||||
truncate: "end",
|
|
||||||
wrap: true,
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return Widget.Box();
|
|
||||||
};
|
|
||||||
|
|
||||||
export { Action };
|
|
||||||
45
modules/notifications/actions/index.ts
Normal file
45
modules/notifications/actions/index.ts
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
import { Notification, Notifications } from "types/service/notifications";
|
||||||
|
|
||||||
|
const Action = (notif: Notification, notifs: Notifications) => {
|
||||||
|
if (notif.actions !== undefined && notif.actions.length > 0) {
|
||||||
|
return Widget.Box({
|
||||||
|
class_name: "notification-card-actions",
|
||||||
|
hexpand: true,
|
||||||
|
vpack: "end",
|
||||||
|
children: notif.actions.map((action) => {
|
||||||
|
return Widget.Button({
|
||||||
|
hexpand: true,
|
||||||
|
class_name: "notification-action-buttons",
|
||||||
|
on_primary_click: () => {
|
||||||
|
if (action.id.includes("scriptAction:-")) {
|
||||||
|
Utils.execAsync(
|
||||||
|
`${action.id.replace("scriptAction:-", "")}`,
|
||||||
|
).catch((err) => console.error(err));
|
||||||
|
notifs.CloseNotification(notif.id);
|
||||||
|
} else {
|
||||||
|
notif.invoke(action.id);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: Widget.Box({
|
||||||
|
hpack: "center",
|
||||||
|
hexpand: true,
|
||||||
|
children: [
|
||||||
|
Widget.Label({
|
||||||
|
class_name: "notification-action-buttons-label",
|
||||||
|
hexpand: true,
|
||||||
|
label: action.label,
|
||||||
|
max_width_chars: 15,
|
||||||
|
truncate: "end",
|
||||||
|
wrap: true,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return Widget.Box();
|
||||||
|
};
|
||||||
|
|
||||||
|
export { Action };
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
import { notifHasImg } from "../../menus/notifications/utils.js";
|
|
||||||
|
|
||||||
export const Body = (notif) => {
|
|
||||||
return Widget.Box({
|
|
||||||
vpack: "start",
|
|
||||||
hexpand: true,
|
|
||||||
class_name: "notification-card-body",
|
|
||||||
children: [
|
|
||||||
Widget.Label({
|
|
||||||
hexpand: true,
|
|
||||||
use_markup: true,
|
|
||||||
xalign: 0,
|
|
||||||
justification: "left",
|
|
||||||
truncate: "end",
|
|
||||||
lines: 2,
|
|
||||||
max_width_chars: !notifHasImg(notif) ? 35 : 28,
|
|
||||||
wrap: true,
|
|
||||||
class_name: "notification-card-body-label",
|
|
||||||
label: notif["body"],
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
};
|
|
||||||
24
modules/notifications/body/index.ts
Normal file
24
modules/notifications/body/index.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import { Notification } from "types/service/notifications";
|
||||||
|
import { notifHasImg } from "../../menus/notifications/utils.js";
|
||||||
|
|
||||||
|
export const Body = (notif: Notification) => {
|
||||||
|
return Widget.Box({
|
||||||
|
vpack: "start",
|
||||||
|
hexpand: true,
|
||||||
|
class_name: "notification-card-body",
|
||||||
|
children: [
|
||||||
|
Widget.Label({
|
||||||
|
hexpand: true,
|
||||||
|
use_markup: true,
|
||||||
|
xalign: 0,
|
||||||
|
justification: "left",
|
||||||
|
truncate: "end",
|
||||||
|
lines: 2,
|
||||||
|
max_width_chars: !notifHasImg(notif) ? 35 : 28,
|
||||||
|
wrap: true,
|
||||||
|
class_name: "notification-card-body-label",
|
||||||
|
label: notif["body"],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
export const CloseButton = (notif, notifs) => {
|
|
||||||
return Widget.Button({
|
|
||||||
class_name: "close-notification-button",
|
|
||||||
on_primary_click: () => {
|
|
||||||
notifs.CloseNotification(notif.id);
|
|
||||||
},
|
|
||||||
child: Widget.Label({
|
|
||||||
label: "",
|
|
||||||
hpack: "center",
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
};
|
|
||||||
14
modules/notifications/close/index.ts
Normal file
14
modules/notifications/close/index.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import { Notification, Notifications } from "types/service/notifications";
|
||||||
|
|
||||||
|
export const CloseButton = (notif: Notification, notifs: Notifications) => {
|
||||||
|
return Widget.Button({
|
||||||
|
class_name: "close-notification-button",
|
||||||
|
on_primary_click: () => {
|
||||||
|
notifs.CloseNotification(notif.id);
|
||||||
|
},
|
||||||
|
child: Widget.Label({
|
||||||
|
label: "",
|
||||||
|
hpack: "center",
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
import GLib from "gi://GLib";
|
|
||||||
import { notifHasImg } from "../../menus/notifications/utils.js";
|
|
||||||
import { NotificationIcon } from "./icon.js";
|
|
||||||
|
|
||||||
const time = (time, format = "%I:%M %p") =>
|
|
||||||
GLib.DateTime.new_from_unix_local(time).format(format);
|
|
||||||
|
|
||||||
export const Header = (notif) => {
|
|
||||||
return Widget.Box({
|
|
||||||
vertical: false,
|
|
||||||
hexpand: true,
|
|
||||||
children: [
|
|
||||||
Widget.Box({
|
|
||||||
class_name: "notification-card-header",
|
|
||||||
hpack: "start",
|
|
||||||
children: [NotificationIcon(notif)],
|
|
||||||
}),
|
|
||||||
Widget.Box({
|
|
||||||
class_name: "notification-card-header",
|
|
||||||
hexpand: true,
|
|
||||||
hpack: "start",
|
|
||||||
vpack: "start",
|
|
||||||
children: [
|
|
||||||
Widget.Label({
|
|
||||||
class_name: "notification-card-header-label",
|
|
||||||
hpack: "start",
|
|
||||||
hexpand: true,
|
|
||||||
vexpand: true,
|
|
||||||
max_width_chars: !notifHasImg(notif) ? 30 : 19,
|
|
||||||
truncate: "end",
|
|
||||||
wrap: true,
|
|
||||||
label: notif["summary"],
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
Widget.Box({
|
|
||||||
class_name: "notification-card-header menu",
|
|
||||||
hpack: "end",
|
|
||||||
vpack: "start",
|
|
||||||
hexpand: true,
|
|
||||||
child: Widget.Label({
|
|
||||||
vexpand: true,
|
|
||||||
class_name: "notification-time",
|
|
||||||
label: time(notif.time),
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
};
|
|
||||||
50
modules/notifications/header/index.ts
Normal file
50
modules/notifications/header/index.ts
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
import GLib from "gi://GLib";
|
||||||
|
import { notifHasImg } from "../../menus/notifications/utils.js";
|
||||||
|
import { NotificationIcon } from "./icon.js";
|
||||||
|
import { Notification } from "types/service/notifications";
|
||||||
|
|
||||||
|
const time = (time: number, format = "%I:%M %p") =>
|
||||||
|
GLib.DateTime.new_from_unix_local(time).format(format);
|
||||||
|
|
||||||
|
export const Header = (notif: Notification) => {
|
||||||
|
return Widget.Box({
|
||||||
|
vertical: false,
|
||||||
|
hexpand: true,
|
||||||
|
children: [
|
||||||
|
Widget.Box({
|
||||||
|
class_name: "notification-card-header",
|
||||||
|
hpack: "start",
|
||||||
|
children: [NotificationIcon(notif)],
|
||||||
|
}),
|
||||||
|
Widget.Box({
|
||||||
|
class_name: "notification-card-header",
|
||||||
|
hexpand: true,
|
||||||
|
hpack: "start",
|
||||||
|
vpack: "start",
|
||||||
|
children: [
|
||||||
|
Widget.Label({
|
||||||
|
class_name: "notification-card-header-label",
|
||||||
|
hpack: "start",
|
||||||
|
hexpand: true,
|
||||||
|
vexpand: true,
|
||||||
|
max_width_chars: !notifHasImg(notif) ? 30 : 19,
|
||||||
|
truncate: "end",
|
||||||
|
wrap: true,
|
||||||
|
label: notif["summary"],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
Widget.Box({
|
||||||
|
class_name: "notification-card-header menu",
|
||||||
|
hpack: "end",
|
||||||
|
vpack: "start",
|
||||||
|
hexpand: true,
|
||||||
|
child: Widget.Label({
|
||||||
|
vexpand: true,
|
||||||
|
class_name: "notification-time",
|
||||||
|
label: time(notif.time),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
import { notifHasImg } from "../../menus/notifications/utils.js";
|
|
||||||
|
|
||||||
const Image = (notif) => {
|
|
||||||
if (notifHasImg(notif)) {
|
|
||||||
return Widget.Box({
|
|
||||||
class_name: "notification-card-image-container",
|
|
||||||
hpack: "center",
|
|
||||||
vpack: "center",
|
|
||||||
vexpand: false,
|
|
||||||
child: Widget.Box({
|
|
||||||
hpack: "center",
|
|
||||||
vexpand: false,
|
|
||||||
class_name: "notification-card-image",
|
|
||||||
css: `background-image: url("${notif.image}")`,
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return Widget.Box();
|
|
||||||
};
|
|
||||||
|
|
||||||
export { Image };
|
|
||||||
23
modules/notifications/image/index.ts
Normal file
23
modules/notifications/image/index.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import { Notification } from "types/service/notifications";
|
||||||
|
import { notifHasImg } from "../../menus/notifications/utils.js";
|
||||||
|
|
||||||
|
const Image = (notif: Notification) => {
|
||||||
|
if (notifHasImg(notif)) {
|
||||||
|
return Widget.Box({
|
||||||
|
class_name: "notification-card-image-container",
|
||||||
|
hpack: "center",
|
||||||
|
vpack: "center",
|
||||||
|
vexpand: false,
|
||||||
|
child: Widget.Box({
|
||||||
|
hpack: "center",
|
||||||
|
vexpand: false,
|
||||||
|
class_name: "notification-card-image",
|
||||||
|
css: `background-image: url("${notif.image}")`,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return Widget.Box();
|
||||||
|
};
|
||||||
|
|
||||||
|
export { Image };
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
const notifs = await Service.import("notifications");
|
|
||||||
import options from "options";
|
|
||||||
import { notifHasImg } from "../menus/notifications/utils.js";
|
|
||||||
import { Image } from "./image/index.js";
|
|
||||||
import { Action } from "./actions/index.js";
|
|
||||||
import { Header } from "./header/index.js";
|
|
||||||
import { Body } from "./body/index.js";
|
|
||||||
import { CloseButton } from "./close/index.js";
|
|
||||||
|
|
||||||
const { position } = options.notifications;
|
|
||||||
|
|
||||||
export default () => {
|
|
||||||
notifs.popupTimeout = 7000;
|
|
||||||
const getPosition = (pos) => {
|
|
||||||
return pos.split(" ");
|
|
||||||
}
|
|
||||||
|
|
||||||
return Widget.Window({
|
|
||||||
name: "notifications-window",
|
|
||||||
class_name: "notifications-window",
|
|
||||||
monitor: 2,
|
|
||||||
layer: "top",
|
|
||||||
anchor: position.bind("value").as(v => getPosition(v)),
|
|
||||||
exclusivity: "ignore",
|
|
||||||
child: Widget.Box({
|
|
||||||
class_name: "notification-card-container",
|
|
||||||
vertical: true,
|
|
||||||
hexpand: true,
|
|
||||||
setup: (self) => {
|
|
||||||
self.hook(notifs, () => {
|
|
||||||
return (self.children = notifs.popups.map((notif) => {
|
|
||||||
return Widget.Box({
|
|
||||||
class_name: "notification-card",
|
|
||||||
vpack: "start",
|
|
||||||
hexpand: true,
|
|
||||||
children: [
|
|
||||||
Image(notif),
|
|
||||||
Widget.Box({
|
|
||||||
vpack: "start",
|
|
||||||
vertical: true,
|
|
||||||
hexpand: true,
|
|
||||||
class_name: `notification-card-content ${!notifHasImg(notif) ? "noimg" : ""}`,
|
|
||||||
children: [Header(notif), Body(notif), Action(notif, notifs)],
|
|
||||||
}),
|
|
||||||
CloseButton(notif, notifs),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
};
|
|
||||||
63
modules/notifications/index.ts
Normal file
63
modules/notifications/index.ts
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
const notifs = await Service.import("notifications");
|
||||||
|
import options from "options";
|
||||||
|
import { notifHasImg } from "../menus/notifications/utils.js";
|
||||||
|
import { Image } from "./image/index.js";
|
||||||
|
import { Action } from "./actions/index.js";
|
||||||
|
import { Header } from "./header/index.js";
|
||||||
|
import { Body } from "./body/index.js";
|
||||||
|
import { CloseButton } from "./close/index.js";
|
||||||
|
import { NotificationAnchor } from "lib/types/options";
|
||||||
|
|
||||||
|
const { position } = options.notifications;
|
||||||
|
|
||||||
|
export default () => {
|
||||||
|
notifs.popupTimeout = 7000;
|
||||||
|
const getPosition = (pos: NotificationAnchor): ("top" | "bottom" | "left" | "right")[] => {
|
||||||
|
const positionMap: { [key: string]: ("top" | "bottom" | "left" | "right")[] } = {
|
||||||
|
"top": ["top"],
|
||||||
|
"top right": ["top", "right"],
|
||||||
|
"top left": ["top", "left"],
|
||||||
|
"bottom": ["bottom"],
|
||||||
|
"bottom right": ["bottom", "right"],
|
||||||
|
"bottom left": ["bottom", "left"]
|
||||||
|
};
|
||||||
|
|
||||||
|
return positionMap[pos] || ["top"];
|
||||||
|
}
|
||||||
|
|
||||||
|
return Widget.Window({
|
||||||
|
name: "notifications-window",
|
||||||
|
class_name: "notifications-window",
|
||||||
|
monitor: 2,
|
||||||
|
layer: "top",
|
||||||
|
anchor: position.bind("value").as(v => getPosition(v)),
|
||||||
|
exclusivity: "ignore",
|
||||||
|
child: Widget.Box({
|
||||||
|
class_name: "notification-card-container",
|
||||||
|
vertical: true,
|
||||||
|
hexpand: true,
|
||||||
|
setup: (self) => {
|
||||||
|
self.hook(notifs, () => {
|
||||||
|
return (self.children = notifs.popups.map((notif) => {
|
||||||
|
return Widget.Box({
|
||||||
|
class_name: "notification-card",
|
||||||
|
vpack: "start",
|
||||||
|
hexpand: true,
|
||||||
|
children: [
|
||||||
|
Image(notif),
|
||||||
|
Widget.Box({
|
||||||
|
vpack: "start",
|
||||||
|
vertical: true,
|
||||||
|
hexpand: true,
|
||||||
|
class_name: `notification-card-content ${!notifHasImg(notif) ? "noimg" : ""}`,
|
||||||
|
children: [Header(notif), Body(notif), Action(notif, notifs)],
|
||||||
|
}),
|
||||||
|
CloseButton(notif, notifs),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -72,7 +72,7 @@ class BrightnessService extends Service {
|
|||||||
|
|
||||||
// overwriting the connect method, let's you
|
// overwriting the connect method, let's you
|
||||||
// change the default event that widgets connect to
|
// change the default event that widgets connect to
|
||||||
connect(event = 'screen-changed', callback) {
|
connect(event: string = 'screen-changed', callback: any) {
|
||||||
return super.connect(event, callback);
|
return super.connect(event, callback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user