(WIP) Code orginazation/refactoring and beging nework refactoring...

This commit is contained in:
Jas Singh
2024-06-29 03:36:57 -07:00
parent 78496ae98a
commit 5ddf5c240d
18 changed files with 1109 additions and 984 deletions

View File

@@ -0,0 +1,58 @@
const audio = await Service.import("audio");
const renderInputDevices = (inputDevices) => {
if (!inputDevices.length) {
return [
Widget.Box({
class_name: `menu-unfound-button input`,
child: Widget.Box({
children: [
Widget.Label({
class_name: "menu-button-name input",
label: "No input devices found...",
}),
],
}),
}),
];
}
return inputDevices.map((device) => {
return Widget.Button({
on_primary_click: () => (audio.microphone = device),
class_name: `menu-button audio input ${device}`,
child: Widget.Box({
children: [
Widget.Box({
hpack: "start",
children: [
Widget.Label({
class_name: audio.microphone
.bind("description")
.as((v) =>
device.description === v
? "menu-button-icon active input"
: "menu-button-icon input",
),
label: "",
}),
Widget.Label({
truncate: "end",
wrap: true,
class_name: audio.microphone
.bind("description")
.as((v) =>
device.description === v
? "menu-button-name active input"
: "menu-button-name input",
),
label: device.description,
}),
],
}),
],
}),
});
});
};
export { renderInputDevices };

View File

@@ -0,0 +1,58 @@
const audio = await Service.import("audio");
const renderPlaybacks = (playbackDevices) => {
return playbackDevices.map((device) => {
if (device.description === "Dummy Output") {
return Widget.Box({
class_name: "menu-unfound-button playback",
child: Widget.Box({
children: [
Widget.Label({
class_name: "menu-button-name playback",
label: "No playback devices found...",
}),
],
}),
});
}
return Widget.Button({
class_name: `menu-button audio playback ${device}`,
on_primary_click: () => (audio.speaker = device),
child: Widget.Box({
children: [
Widget.Box({
hpack: "start",
children: [
Widget.Label({
truncate: "end",
wrap: true,
class_name: audio.speaker
.bind("description")
.as((v) =>
device.description === v
? "menu-button-icon active playback"
: "menu-button-icon playback",
),
label: "",
}),
Widget.Label({
class_name: audio.speaker
.bind("description")
.as((v) =>
device.description === v
? "menu-button-name active playback"
: "menu-button-name playback",
),
truncate: "end",
wrap: true,
label: device.description,
}),
],
}),
],
}),
});
});
};
export { renderPlaybacks };

View File

@@ -0,0 +1,66 @@
const audio = await Service.import("audio");
import { getIcon } from './utils.js';
const renderActiveInput = () => {
return [
Widget.Box({
class_name: "menu-slider-container input",
children: [
Widget.Button({
vexpand: false,
vpack: "end",
setup: (self) => {
self.hook(audio, () => {
const mic = audio.microphone;
const className = `menu-active-button input ${mic.is_muted ? "muted" : ""}`;
return (self.class_name = className);
});
},
on_primary_click: () =>
(audio.microphone.is_muted = !audio.microphone.is_muted),
child: Widget.Icon({
class_name: "menu-active-icon input",
setup: (self) => {
self.hook(audio, () => {
self.icon = getIcon(
audio.microphone.volume,
audio.microphone.is_muted,
)["mic"];
});
},
}),
}),
Widget.Box({
vertical: true,
children: [
Widget.Label({
class_name: "menu-active input",
hpack: "start",
truncate: "end",
wrap: true,
label: audio.bind("microphone").as((v) => v.description || ""),
}),
Widget.Slider({
value: audio.microphone.bind("volume").as((v) => v),
class_name: "menu-active-slider menu-slider inputs",
draw_value: false,
hexpand: true,
min: 0,
max: 1,
onChange: ({ value }) => (audio.microphone.volume = value),
}),
],
}),
Widget.Label({
class_name: "menu-active-percentage input",
vpack: "end",
label: audio.microphone
.bind("volume")
.as((v) => `${Math.floor(v * 100)}%`),
}),
],
}),
];
};
export { renderActiveInput };

View File

@@ -0,0 +1,67 @@
const audio = await Service.import("audio");
import { getIcon } from "./utils.js";
const renderActivePlayback = () => {
return [
Widget.Box({
class_name: "menu-slider-container playback",
children: [
Widget.Button({
vexpand: false,
vpack: "end",
setup: (self) => {
self.hook(audio, () => {
const spkr = audio.speaker;
const className = `menu-active-button playback ${spkr.is_muted ? "muted" : ""}`;
return (self.class_name = className);
});
},
on_primary_click: () =>
(audio.speaker.is_muted = !audio.speaker.is_muted),
child: Widget.Icon({
class_name: "menu-active-icon playback",
setup: (self) => {
self.hook(audio, () => {
self.icon = getIcon(
audio.speaker.volume,
audio.speaker.is_muted,
)["spkr"];
});
},
}),
}),
Widget.Box({
vertical: true,
children: [
Widget.Label({
class_name: "menu-active playback",
hpack: "start",
truncate: "end",
expand: true,
wrap: true,
label: audio.bind("speaker").as((v) => v.description || ""),
}),
Widget.Slider({
value: audio["speaker"].bind("volume"),
class_name: "menu-active-slider menu-slider playback",
draw_value: false,
hexpand: true,
min: 0,
max: 1,
onChange: ({ value }) => (audio.speaker.volume = value),
}),
],
}),
Widget.Label({
vpack: "end",
class_name: "menu-active-percentage playback",
label: audio.speaker
.bind("volume")
.as((v) => `${Math.floor(v * 100)}%`),
}),
],
}),
];
};
export { renderActivePlayback };

View File

@@ -1,294 +1,11 @@
const audio = await Service.import("audio"); const audio = await Service.import("audio");
import DropdownMenu from "../DropdownMenu.js"; import DropdownMenu from "../DropdownMenu.js";
import { renderInputDevices } from "./InputDevices.js";
import { renderPlaybacks } from "./PlaybackDevices.js";
import { renderActiveInput } from "./SelectedInput.js";
import { renderActivePlayback } from "./SelectedPlayback.js";
export default () => { export default () => {
const renderPlaybacks = (playbackDevices) => {
return playbackDevices.map((device) => {
if (device.description === "Dummy Output") {
return Widget.Box({
class_name: "menu-unfound-button playback",
child: Widget.Box({
children: [
Widget.Label({
class_name: "menu-button-name playback",
label: "No playback devices found...",
}),
],
}),
});
}
return Widget.Button({
class_name: `menu-button audio playback ${device}`,
on_primary_click: () => (audio.speaker = device),
child: Widget.Box({
children: [
Widget.Box({
hpack: "start",
children: [
Widget.Label({
truncate: "end",
wrap: true,
class_name: audio.speaker
.bind("description")
.as((v) =>
device.description === v
? "menu-button-icon active playback"
: "menu-button-icon playback",
),
label: "",
}),
Widget.Label({
class_name: audio.speaker
.bind("description")
.as((v) =>
device.description === v
? "menu-button-name active playback"
: "menu-button-name playback",
),
truncate: "end",
wrap: true,
label: device.description,
}),
],
}),
Widget.Box({
hpack: "end",
expand: true,
children: [
Widget.Label({
class_name: "menu-button-isactive audio playback",
label: audio.speaker
.bind("description")
.as((v) => (device.description === v ? " " : "")),
}),
],
}),
],
}),
});
});
};
const getIcon = (audioVol, isMuted) => {
const speakerIcons = {
101: "audio-volume-overamplified-symbolic",
66: "audio-volume-high-symbolic",
34: "audio-volume-medium-symbolic",
1: "audio-volume-low-symbolic",
0: "audio-volume-muted-symbolic",
};
const inputIcons = {
66: "microphone-sensitivity-high-symbolic",
34: "microphone-sensitivity-medium-symbolic",
1: "microphone-sensitivity-low-symbolic",
0: "microphone-disabled-symbolic",
};
const icon = isMuted
? 0
: [101, 66, 34, 1, 0].find((threshold) => threshold <= audioVol * 100);
return {
spkr: speakerIcons[icon],
mic: inputIcons[icon],
};
};
const renderInputDevices = (inputDevices) => {
if (!inputDevices.length) {
return [
Widget.Box({
class_name: `menu-unfound-button input`,
child: Widget.Box({
children: [
Widget.Label({
class_name: "menu-button-name input",
label: "No input devices found...",
}),
],
}),
}),
];
}
return inputDevices.map((device) => {
return Widget.Button({
on_primary_click: () => (audio.microphone = device),
class_name: `menu-button audio input ${device}`,
child: Widget.Box({
children: [
Widget.Box({
hpack: "start",
children: [
Widget.Label({
class_name: audio.microphone
.bind("description")
.as((v) =>
device.description === v
? "menu-button-icon active input"
: "menu-button-icon input",
),
label: "",
}),
Widget.Label({
truncate: "end",
wrap: true,
class_name: audio.microphone
.bind("description")
.as((v) =>
device.description === v
? "menu-button-name active input"
: "menu-button-name input",
),
label: device.description,
}),
],
}),
Widget.Box({
hpack: "end",
expand: true,
children: [
Widget.Label({
class_name: "menu-button-isactive audio input",
truncate: "end",
wrap: true,
label: audio.microphone
.bind("description")
.as((v) => (device.description === v ? " " : "")),
}),
],
}),
],
}),
});
});
};
const renderActivePlayback = () => {
return [
Widget.Box({
class_name: "menu-slider-container playback",
children: [
Widget.Button({
vexpand: false,
vpack: "end",
setup: (self) => {
self.hook(audio, () => {
const spkr = audio.speaker;
const className = `menu-active-button playback ${spkr.is_muted ? "muted" : ""}`;
return (self.class_name = className);
});
},
on_primary_click: () =>
(audio.speaker.is_muted = !audio.speaker.is_muted),
child: Widget.Icon({
class_name: "menu-active-icon playback",
setup: (self) => {
self.hook(audio, () => {
self.icon = getIcon(
audio.speaker.volume,
audio.speaker.is_muted,
)["spkr"];
});
},
}),
}),
Widget.Box({
vertical: true,
children: [
Widget.Label({
class_name: "menu-active playback",
hpack: "start",
truncate: "end",
expand: true,
wrap: true,
label: audio.bind("speaker").as((v) => v.description || ""),
}),
Widget.Slider({
value: audio["speaker"].bind("volume"),
class_name: "menu-active-slider menu-slider playback",
draw_value: false,
hexpand: true,
min: 0,
max: 1,
onChange: ({ value }) => (audio.speaker.volume = value),
}),
],
}),
Widget.Label({
vpack: "end",
class_name: "menu-active-percentage playback",
label: audio.speaker
.bind("volume")
.as((v) => `${Math.floor(v * 100)}%`),
}),
],
}),
];
};
const renderActiveInput = () => {
return [
Widget.Box({
class_name: "menu-slider-container input",
children: [
Widget.Button({
vexpand: false,
vpack: "end",
setup: (self) => {
self.hook(audio, () => {
const mic = audio.microphone;
const className = `menu-active-button input ${mic.is_muted ? "muted" : ""}`;
return (self.class_name = className);
});
},
on_primary_click: () =>
(audio.microphone.is_muted = !audio.microphone.is_muted),
child: Widget.Icon({
class_name: "menu-active-icon input",
setup: (self) => {
self.hook(audio, () => {
self.icon = getIcon(
audio.microphone.volume,
audio.microphone.is_muted,
)["mic"];
});
},
}),
}),
Widget.Box({
vertical: true,
children: [
Widget.Label({
class_name: "menu-active input",
hpack: "start",
truncate: "end",
wrap: true,
label: audio.bind("microphone").as((v) => v.description || ""),
}),
Widget.Slider({
value: audio.microphone.bind("volume").as((v) => v),
class_name: "menu-active-slider menu-slider inputs",
draw_value: false,
hexpand: true,
min: 0,
max: 1,
onChange: ({ value }) => (audio.microphone.volume = value),
}),
],
}),
Widget.Label({
class_name: "menu-active-percentage input",
vpack: "end",
label: audio.microphone
.bind("volume")
.as((v) => `${Math.floor(v * 100)}%`),
}),
],
}),
];
};
return DropdownMenu({ return DropdownMenu({
name: "audiomenu", name: "audiomenu",
transition: "crossfade", transition: "crossfade",

View File

@@ -0,0 +1,27 @@
const getIcon = (audioVol, isMuted) => {
const speakerIcons = {
101: "audio-volume-overamplified-symbolic",
66: "audio-volume-high-symbolic",
34: "audio-volume-medium-symbolic",
1: "audio-volume-low-symbolic",
0: "audio-volume-muted-symbolic",
};
const inputIcons = {
66: "microphone-sensitivity-high-symbolic",
34: "microphone-sensitivity-medium-symbolic",
1: "microphone-sensitivity-low-symbolic",
0: "microphone-disabled-symbolic",
};
const icon = isMuted
? 0
: [101, 66, 34, 1, 0].find((threshold) => threshold <= audioVol * 100);
return {
spkr: speakerIcons[icon],
mic: inputIcons[icon],
};
};
export { getIcon };

View File

@@ -0,0 +1,67 @@
const network = await Service.import("network");
const Ethernet = () => {
return Widget.Box({
class_name: "menu-section-container ethernet",
vertical: true,
children: [
Widget.Box({
class_name: "menu-label-container",
hpack: "fill",
child: Widget.Label({
class_name: "menu-label",
hexpand: true,
hpack: "center",
label: "Ethernet",
}),
}),
Widget.Box({
class_name: "menu-items-section",
vertical: true,
children: [
Widget.Box({
class_name: "menu-content",
vertical: true,
child: network.bind("wired").as((wired) => {
return Widget.Box({
class_name: "network-element-item",
child: Widget.Box({
hpack: "start",
children: [
Widget.Icon({
class_name: "network-ethernet-icon",
tooltip_text: wired.internet,
icon: `${wired["icon_name"]}`,
}),
Widget.Box({
class_name: "connection-container",
vertical: true,
children: [
Widget.Label({
class_name: "active-connection",
hpack: "start",
truncate: "end",
wrap: true,
label: `Ethernet Connection ${typeof wired.speed === "number" ? `(${wired.speed / 1000} Gbps)` : ""}`,
}),
Widget.Label({
hpack: "start",
class_name: "connection-status dim",
label:
wired.internet.charAt(0).toUpperCase() +
wired.internet.slice(1),
}),
],
}),
],
}),
});
}),
}),
],
}),
],
});
};
export { Ethernet };

View File

@@ -0,0 +1,39 @@
const renderWapStaging = (self, stagedDevice) => {
self.hook(stagedDevice, ({ value }) => {
return (self.child = Widget.Button({
class_name: "network-element-item",
child: Widget.Box({
hpack: "start",
children: [
Widget.Icon({
class_name: "network-ethernet-icon",
icon: `${stagedDevice["iconName"]}`,
}),
Widget.Box({
class_name: "connection-container",
vertical: true,
children: [
Widget.Label({
class_name: "active-connection",
hpack: "start",
truncate: "end",
wrap: true,
label: stagedDevice.ssid,
}),
Widget.Revealer({
revealChild: stagedDevice.active,
child: Widget.Label({
hpack: "start",
class_name: "connection-status dim",
label: "Connected",
}),
}),
],
}),
],
}),
}));
});
};
export { renderWapStaging };

View File

@@ -0,0 +1,61 @@
const renderWAPs = (self, network) => {
self.hook(network, () => {
const WAPs = network.wifi.access_points;
console.log("WAPs");
console.log(JSON.stringify(WAPs, null, 2));
const filteredWAPs = WAPs.filter((ap) => ap.ssid !== "Unknown").sort(
(a, b) => {
return b.strength - a.strength;
},
);
if (filteredWAPs.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.Button({
class_name: "network-element-item",
child: Widget.Box({
hpack: "start",
children: [
Widget.Icon({
class_name: "network-ethernet-icon",
icon: `${ap["iconName"]}`,
}),
Widget.Box({
class_name: "connection-container",
vertical: true,
children: [
Widget.Label({
class_name: "active-connection",
hpack: "start",
truncate: "end",
wrap: true,
label: ap.ssid,
}),
Widget.Revealer({
revealChild: ap.active,
child: Widget.Label({
hpack: "start",
class_name: "connection-status dim",
label: "Connected",
}),
}),
],
}),
],
}),
});
}));
});
};
export { renderWAPs };

View File

@@ -0,0 +1,45 @@
const network = await Service.import("network");
import { renderWAPs } from "./WirelessAPs.js";
import { renderWapStaging } from "./APStaging.js";
const Staging = Variable("none");
const Wifi = () => {
return Widget.Box({
class_name: "menu-section-container wifi",
vertical: true,
children: [
Widget.Box({
class_name: "menu-label-container",
hpack: "fill",
child: Widget.Label({
class_name: "menu-label",
hexpand: true,
hpack: "center",
label: "Wi-Fi",
}),
}),
Widget.Box({
class_name: "menu-items-section",
vertical: true,
children: [
Widget.Box({
class_name: "wap-staging",
setup: (self) => {
renderWapStaging(self, Staging);
},
}),
Widget.Box({
class_name: "available-waps",
vertical: true,
setup: (self) => {
renderWAPs(self, network);
},
}),
],
}),
],
});
};
export { Wifi };

View File

@@ -0,0 +1,483 @@
const network = await Service.import("network");
import DropdownMenu from "../DropdownMenu.js";
export default () => {
const pendingAuth = Variable("");
return DropdownMenu({
name: "networkmenu",
transition: "crossfade",
child: Widget.Box({
class_name: "menu-items",
child: Widget.Box({
vertical: true,
hexpand: true,
class_name: "menu-items-container network",
children: [
Widget.Box({
class_name: "menu-label-container network",
child: Widget.Label({
class_name: "menu-label network",
hpack: "start",
label: "Connected Network",
}),
}),
Widget.Box({
class_name: "menu-item-box network",
vertical: true,
children: Utils.merge(
[
network.bind("wired"),
network.bind("wifi"),
network.bind("primary"),
pendingAuth.bind("value"),
],
(wired, wifi, primary) => {
let sortedNetworks = [];
if (wifi.access_points.length > 0) {
sortedNetworks = wifi.access_points
.filter((ap) => ap.ssid !== "Unknown")
.sort((a, b) => {
return b.strength - a.strength;
});
}
const localIfConnected = () => {
if (primary === "wired") {
return [
Widget.Box({
class_name: `network-element-item-ethernet ${sortedNetworks.length > 0 ? "multi" : ""}`,
child: Widget.Box({
hpack: "start",
vertical: true,
children: [
Widget.Box({
children: [
Widget.Box({
class_name: "network-element-items-container",
children: [
Widget.Button({
class_name: "menu-button-icon network",
child: Widget.Icon({
tooltip_text: wired.internet,
icon: `${wired["icon_name"]}`,
}),
}),
Widget.Label({
class_name: "menu-button-name network",
truncate: "end",
wrap: true,
label: `Ethernet (${wired.speed / 1000} Gbps)`,
}),
],
}),
],
}),
Widget.Box({
class_name:
"menu-button-name-container status dim",
children: [
Widget.Label({
class_name:
"menu-button-name status network dim",
label:
wired.internet.charAt(0).toUpperCase() +
wired.internet.slice(1),
}),
],
}),
],
}),
}),
];
}
return [];
};
const wifiIfConnected = () => {
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;
};
if (wifi.ssid !== "") {
return [
Widget.Box({
class_name: `network-element-item-ethernet`,
children: [
Widget.Box({
hpack: "start",
vertical: true,
children: [
Widget.Box({
children: [
Widget.Box({
class_name:
"network-element-items-container",
children: [
Widget.Button({
class_name: "menu-button-icon network",
child: Widget.Icon({
tooltip_text: wifi.state,
icon: `${wifi["icon_name"]}`,
}),
}),
Widget.Label({
class_name: "menu-button-name network",
truncate: "end",
wrap: true,
label: wifi.ssid,
}),
],
}),
],
}),
Widget.Box({
class_name:
"menu-button-name-container status dim",
children: [
Widget.Label({
class_name:
"menu-button-name status network dim",
label:
wifi.internet.charAt(0).toUpperCase() +
wifi.internet.slice(1),
}),
],
}),
],
}),
Widget.Box({
hexpand: true,
hpack: "end",
children: [
Widget.Button({
class_name:
"menu-icon-button network disconnect",
on_primary_click: () => {
Utils.execAsync(
"nmcli connection show --active",
).then((res) => {
const connectionId = getIdBySsid(
wifi.ssid,
res,
);
Utils.execAsync(
`nmcli connection down ${connectionId} "${wifi.ssid}"`,
).catch((err) =>
console.error(
`Error while disconnecting from wifi "${wifi.ssid}": ${err}`,
),
);
});
},
child: Widget.Label(""),
}),
Widget.Box({
hexpand: true,
child: Widget.Button({
class_name: "menu-icon-button network forget",
on_primary_click: () => {
Utils.execAsync(
"nmcli connection show --active",
).then((res) => {
const connectionId = getIdBySsid(
wifi.ssid,
res,
);
Utils.execAsync(
`nmcli connection delete ${connectionId} "${wifi.ssid}"`,
).catch((err) =>
console.error(
`Error while forgetting "${wifi.ssid}": ${err}`,
),
);
});
},
child: Widget.Label("󰆴"),
}),
}),
],
}),
],
}),
];
}
return [];
};
return [...localIfConnected(), ...wifiIfConnected()];
},
),
}),
Widget.Box({
children: [
Widget.Box({
hpack: "start",
class_name: "menu-label-container network",
child: Widget.Label({
class_name: "menu-label network",
hpack: "start",
label: "Available Networks",
}),
}),
Widget.Box({
hexpand: true,
hpack: "end",
child: Widget.Button({
class_name: "menu-icon-button refresh network",
on_primary_click: () => {
network.wifi.scan();
},
child: Widget.Icon("view-refresh-symbolic"),
}),
}),
],
}),
Widget.Box({
class_name: "menu-item-box network",
vertical: true,
children: [
Widget.Box({
vertical: true,
setup: (self) => {
self.hook(pendingAuth, () => {
const accPoint = network.wifi.access_points.find(
(ap) => ap.bssid === pendingAuth.value,
);
if (
pendingAuth.value !== "" &&
accPoint !== undefined &&
network.wifi.ssid !== pendingAuth.value
) {
return (self.child = Widget.Box({
vertical: true,
children: [
Widget.Button({
class_name: "network-element-item",
child: Widget.Box({
children: [
Widget.Box({
hpack: "start",
vertical: true,
children: [
Widget.Box({
class_name:
"network-element-items-container",
children: [
Widget.Button({
class_name:
"menu-button-icon network",
child: Widget.Icon({
tooltip_text:
accPoint.ssid ===
network.wifi.ssid
? network.wifi.state
: null,
icon: `${accPoint["iconName"]}`,
}),
}),
Widget.Label({
class_name:
"menu-button-name network",
truncate: "end",
wrap: true,
label: accPoint.ssid,
}),
],
}),
],
}),
],
}),
}),
Widget.Revealer({
transition: "slide_down",
reveal_child: pendingAuth
.bind("value")
.as((v) => (v === accPoint.bssid ? true : false)),
class_name: "network-password-input-container",
child: Widget.Box({
hexpand: true,
children: [
Widget.Box({
child: Widget.Entry({
hpack: "start",
class_name: "network-password-input",
placeholder_text: "enter password",
visibility: false,
onAccept: (selfInp) => {
Utils.execAsync(
`nmcli dev wifi connect ${accPoint.bssid} password ${selfInp.text}`,
)
.catch((err) => {
pendingAuth.value = "";
console.error(
`Failed to connect to wifi: ${accPoint.ssid}... ${err}`,
);
})
.then(() => (pendingAuth.value = ""));
selfInp.text = "";
},
}),
}),
Widget.Box({
class_name:
"network-password-input-close-container",
hexpand: true,
child: Widget.Button({
class_name: "network-password-input-close",
on_primary_click: () =>
(pendingAuth.value = ""),
child: Widget.Label("󰅜 "),
}),
}),
],
}),
}),
],
}));
} else {
self.children = [];
}
});
},
}),
Widget.Box({
vertical: true,
setup: (self) => {
self.hook(network, () => {
let sortedNetworks = [];
self.hook(pendingAuth, () => {
if (network.wifi.access_points.length > 0) {
sortedNetworks = network.wifi.access_points
.filter((ap) => {
return (
ap.ssid !== "Unknown" &&
ap.bssid !== pendingAuth.value &&
!ap.active &&
network.wifi.ssid !== ap.ssid
);
})
.sort((a, b) => {
return b.strength - a.strength;
});
}
if (sortedNetworks.length <= 0) {
return (self.children = [
Widget.Label({
class_name: "not-found-label dim",
expand: true,
hpack: "center",
vpack: "center",
label: "No Wifi Networks Found",
}),
]);
}
return (self.children = sortedNetworks.map((accPoint) => {
return Widget.Box({
vertical: true,
children: [
Widget.Button({
on_primary_click: () => {
Utils.execAsync(
`nmcli device wifi connect ${accPoint.bssid}`,
).catch((err) => {
if (
err
.toLowerCase()
.includes(
"secrets were required, but not provided",
)
) {
pendingAuth.value = accPoint.bssid;
}
});
},
class_name: "network-element-item",
child: Widget.Box({
children: [
Widget.Box({
hpack: "start",
vertical: true,
children: [
Widget.Box({
class_name:
"network-element-items-container",
children: [
Widget.Button({
class_name:
"menu-button-icon network",
child: Widget.Icon({
tooltip_text:
accPoint.ssid ===
network.wifi.ssid
? network.wifi.state
: null,
icon: `${accPoint["iconName"]}`,
}),
}),
Widget.Label({
class_name:
"menu-button-name network",
truncate: "end",
wrap: true,
label: accPoint.ssid,
}),
],
}),
],
}),
],
}),
}),
Widget.Revealer({
transition: "slide_down",
reveal_child: pendingAuth
.bind("value")
.as((v) =>
v === accPoint.bssid ? true : false,
),
class_name: "network-password-input-container",
child: Widget.Box({
hexpand: true,
children: [
Widget.Entry({
hexpand: true,
class_name: "network-password-input",
placeholder_text: "enter password",
visibility: false,
onAccept: (selfInp) => {
selfInp.text = "";
},
}),
],
}),
}),
],
});
}));
});
});
},
}),
],
}),
],
}),
}),
});
};

View File

@@ -1,9 +1,9 @@
const network = await Service.import("network"); const network = await Service.import("network");
import DropdownMenu from "../DropdownMenu.js"; import DropdownMenu from "../DropdownMenu.js";
import { Ethernet } from "./Ethernet.js";
import { Wifi } from "./Wifi/index.js";
export default () => { export default () => {
const pendingAuth = Variable("");
return DropdownMenu({ return DropdownMenu({
name: "networkmenu", name: "networkmenu",
transition: "crossfade", transition: "crossfade",
@@ -13,487 +13,7 @@ export default () => {
vertical: true, vertical: true,
hexpand: true, hexpand: true,
class_name: "menu-items-container network", class_name: "menu-items-container network",
children: [ children: [Ethernet(), Wifi()],
Widget.Box({
class_name: "menu-dropdown-label-container",
hpack: "start",
children: [
Widget.Label({
class_name: "menu-dropdown-label network",
label: "Networks",
}),
],
}),
Widget.Box({
class_name: "menu-label-container network",
child: Widget.Label({
class_name: "menu-label network",
hpack: "start",
label: "Connected Network",
}),
}),
Widget.Box({
class_name: "menu-item-box network",
vertical: true,
setup: (self) => {
self.hook(network, () => {
self.hook(pendingAuth, () => {
let sortedNetworks = [];
if (network.wifi.access_points.length > 0) {
sortedNetworks = network.wifi.access_points
.filter((ap) => ap.ssid !== "Unknown")
.sort((a, b) => {
return b.strength - a.strength;
});
}
const localIfConnected = () => {
if (network.primary === "wired") {
return [
Widget.Box({
class_name: `network-element-item-ethernet ${sortedNetworks.length > 0 ? "multi" : ""}`,
child: Widget.Box({
hpack: "start",
vertical: true,
children: [
Widget.Box({
children: [
Widget.Box({
class_name:
"network-element-items-container",
children: [
Widget.Button({
class_name: "menu-button-icon network",
child: Widget.Icon({
tooltip_text: network.wired.internet,
icon: `${network.wired["icon_name"]}`,
}),
}),
Widget.Label({
class_name: "menu-button-name network",
truncate: "end",
wrap: true,
label: `Ethernet (${network.wired.speed / 1000} Gbps)`,
}),
],
}),
],
}),
Widget.Box({
class_name:
"menu-button-name-container status dim",
children: [
Widget.Label({
class_name:
"menu-button-name status network dim",
label:
network.wired.internet
.charAt(0)
.toUpperCase() +
network.wired.internet.slice(1),
}),
],
}),
],
}),
}),
];
}
return [];
};
const wifiIfConnected = () => {
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;
};
if (network.wifi.ssid !== "") {
return [
Widget.Box({
class_name: `network-element-item-ethernet`,
children: [
Widget.Box({
hpack: "start",
vertical: true,
children: [
Widget.Box({
children: [
Widget.Box({
class_name:
"network-element-items-container",
children: [
Widget.Button({
class_name:
"menu-button-icon network",
child: Widget.Icon({
tooltip_text: network.wifi.state,
icon: `${network.wifi["icon_name"]}`,
}),
}),
Widget.Label({
class_name:
"menu-button-name network",
truncate: "end",
wrap: true,
label: network.wifi.ssid,
}),
],
}),
],
}),
Widget.Box({
class_name:
"menu-button-name-container status dim",
children: [
Widget.Label({
class_name:
"menu-button-name status network dim",
label:
network.wifi.internet
.charAt(0)
.toUpperCase() +
network.wifi.internet.slice(1),
}),
],
}),
],
}),
Widget.Box({
hexpand: true,
hpack: "end",
children: [
Widget.Button({
class_name:
"menu-icon-button network disconnect",
on_primary_click: () => {
Utils.execAsync(
"nmcli connection show --active",
).then((res) => {
const connectionId = getIdBySsid(
network.wifi.ssid,
res,
);
Utils.execAsync(
`nmcli connection down ${connectionId} "${network.wifi.ssid}"`,
).catch((err) =>
console.error(
`Error while disconnecting from wifi "${network.wifi.ssid}": ${err}`,
),
);
});
},
child: Widget.Label(""),
}),
Widget.Box({
hexpand: true,
child: Widget.Button({
class_name:
"menu-icon-button network forget",
on_primary_click: () => {
Utils.execAsync(
"nmcli connection show --active",
).then((res) => {
const connectionId = getIdBySsid(
network.wifi.ssid,
res,
);
Utils.execAsync(
`nmcli connection delete ${connectionId} "${network.wifi.ssid}"`,
).catch((err) =>
console.error(
`Error while forgetting "${network.wifi.ssid}": ${err}`,
),
);
});
},
child: Widget.Label("󰆴"),
}),
}),
],
}),
],
}),
];
}
return [];
};
return (self.children = [
...localIfConnected(),
...wifiIfConnected(),
]);
});
});
},
}),
Widget.Box({
children: [
Widget.Box({
hpack: "start",
class_name: "menu-label-container network",
child: Widget.Label({
class_name: "menu-label network",
hpack: "start",
label: "Available Networks",
}),
}),
Widget.Box({
hexpand: true,
hpack: "end",
child: Widget.Button({
class_name: "menu-icon-button refresh network",
on_primary_click: () => {
network.wifi.scan();
},
child: Widget.Icon("view-refresh-symbolic"),
}),
}),
],
}),
Widget.Box({
class_name: "menu-item-box network",
vertical: true,
children: [
Widget.Box({
vertical: true,
setup: (self) => {
self.hook(pendingAuth, () => {
const accPoint = network.wifi.access_points.find(
(ap) => ap.bssid === pendingAuth.value,
);
if (
pendingAuth.value !== "" &&
accPoint !== undefined &&
network.wifi.ssid !== pendingAuth.value
) {
return (self.child = Widget.Box({
vertical: true,
children: [
Widget.Button({
class_name: "network-element-item",
child: Widget.Box({
children: [
Widget.Box({
hpack: "start",
vertical: true,
children: [
Widget.Box({
class_name:
"network-element-items-container",
children: [
Widget.Button({
class_name:
"menu-button-icon network",
child: Widget.Icon({
tooltip_text:
accPoint.ssid ===
network.wifi.ssid
? network.wifi.state
: null,
icon: `${accPoint["iconName"]}`,
}),
}),
Widget.Label({
class_name:
"menu-button-name network",
truncate: "end",
wrap: true,
label: accPoint.ssid,
}),
],
}),
],
}),
],
}),
}),
Widget.Revealer({
transition: "slide_down",
reveal_child: pendingAuth
.bind("value")
.as((v) => (v === accPoint.bssid ? true : false)),
class_name: "network-password-input-container",
child: Widget.Box({
hexpand: true,
children: [
Widget.Box({
child: Widget.Entry({
hpack: "start",
class_name: "network-password-input",
placeholder_text: "enter password",
visibility: false,
onAccept: (selfInp) => {
Utils.execAsync(
`nmcli dev wifi connect ${accPoint.bssid} password ${selfInp.text}`,
)
.catch((err) => {
pendingAuth.value = "";
console.error(
`Failed to connect to wifi: ${accPoint.ssid}... ${err}`,
);
})
.then(() => (pendingAuth.value = ""));
selfInp.text = "";
},
}),
}),
Widget.Box({
class_name:
"network-password-input-close-container",
hexpand: true,
child: Widget.Button({
class_name: "network-password-input-close",
on_primary_click: () =>
(pendingAuth.value = ""),
child: Widget.Label("󰅜 "),
}),
}),
],
}),
}),
],
}));
} else {
self.children = [];
}
});
},
}),
Widget.Box({
vertical: true,
setup: (self) => {
self.hook(network, () => {
let sortedNetworks = [];
self.hook(pendingAuth, () => {
if (network.wifi.access_points.length > 0) {
sortedNetworks = network.wifi.access_points
.filter((ap) => {
return (
ap.ssid !== "Unknown" &&
ap.bssid !== pendingAuth.value &&
!ap.active &&
network.wifi.ssid !== ap.ssid
);
})
.sort((a, b) => {
return b.strength - a.strength;
});
}
if (sortedNetworks.length <= 0) {
return self.children = [
Widget.Label({
class_name: "not-found-label dim",
expand: true,
hpack: "center",
vpack: "center",
label: "No Wifi Networks Found"
})
]
}
return (self.children = sortedNetworks.map((accPoint) => {
return Widget.Box({
vertical: true,
children: [
Widget.Button({
on_primary_click: () => {
Utils.execAsync(
`nmcli device wifi connect ${accPoint.bssid}`,
).catch((err) => {
if (
err
.toLowerCase()
.includes(
"secrets were required, but not provided",
)
) {
pendingAuth.value = accPoint.bssid;
}
});
},
class_name: "network-element-item",
child: Widget.Box({
children: [
Widget.Box({
hpack: "start",
vertical: true,
children: [
Widget.Box({
class_name:
"network-element-items-container",
children: [
Widget.Button({
class_name:
"menu-button-icon network",
child: Widget.Icon({
tooltip_text:
accPoint.ssid ===
network.wifi.ssid
? network.wifi.state
: null,
icon: `${accPoint["iconName"]}`,
}),
}),
Widget.Label({
class_name:
"menu-button-name network",
truncate: "end",
wrap: true,
label: accPoint.ssid,
}),
],
}),
],
}),
],
}),
}),
Widget.Revealer({
transition: "slide_down",
reveal_child: pendingAuth
.bind("value")
.as((v) =>
v === accPoint.bssid ? true : false,
),
class_name: "network-password-input-container",
child: Widget.Box({
hexpand: true,
children: [
Widget.Entry({
hexpand: true,
class_name: "network-password-input",
placeholder_text: "enter password",
visibility: false,
onAccept: (selfInp) => {
selfInp.text = "";
},
}),
],
}),
}),
],
});
}));
});
});
},
}),
],
}),
],
}), }),
}), }),
}); });

View File

@@ -196,6 +196,9 @@ export default () => {
return (self.children = sortedNotifications.map((notif) => { return (self.children = sortedNotifications.map((notif) => {
return Widget.Box({ return Widget.Box({
class_name: "notification-card-content-container",
children: [
Widget.Box({
class_name: "notification-card menu", class_name: "notification-card menu",
vpack: "center", vpack: "center",
hexpand: true, hexpand: true,
@@ -212,7 +215,8 @@ export default () => {
hexpand: true, hexpand: true,
children: [ children: [
Widget.Box({ Widget.Box({
class_name: "notification-card-header menu", class_name:
"notification-card-header menu",
hexpand: true, hexpand: true,
vpack: "start", vpack: "start",
children: [ children: [
@@ -231,7 +235,8 @@ export default () => {
], ],
}), }),
Widget.Box({ Widget.Box({
class_name: "notification-card-header menu", class_name:
"notification-card-header menu",
hexpand: true, hexpand: true,
hpack: "end", hpack: "end",
children: [NotificationIcon(notif)], children: [NotificationIcon(notif)],
@@ -262,6 +267,8 @@ export default () => {
...actionsContainer(notif), ...actionsContainer(notif),
], ],
}), }),
],
}),
Widget.Button({ Widget.Button({
class_name: "close-notification-button menu", class_name: "close-notification-button menu",
on_primary_click: () => { on_primary_click: () => {

View File

@@ -103,6 +103,8 @@ tooltip label {
} }
.menu-section-container { .menu-section-container {
margin: 1.35em 0em;
.menu-label { .menu-label {
color: $text; color: $text;
font-size: 1.1em; font-size: 1.1em;
@@ -118,16 +120,18 @@ tooltip label {
min-height: 2em; min-height: 2em;
} }
margin: 1.35em 0em; &:first-child {
&.volume {
margin-bottom: 0em; margin-bottom: 0em;
} }
&.input { &:last-child {
margin-top: 0em; margin-top: 0em;
} }
&:nth-child(2) {
margin-top: 1.35em;
}
.menu-items-section { .menu-items-section {
background: $base; background: $base;
border-radius: 0.4em; border-radius: 0.4em;
@@ -135,13 +139,6 @@ tooltip label {
border-top-right-radius: 0em; border-top-right-radius: 0em;
padding: 0.9em; padding: 0.9em;
margin: 0em 1.35em; margin: 0em 1.35em;
&.selected {
margin-bottom: 0em;
}
&.input {
margin-top: 0em;
}
} }
} }
@@ -232,6 +229,10 @@ tooltip label {
font-weight: bold; font-weight: bold;
color: $overlay0; color: $overlay0;
margin-right: .5rem; margin-right: .5rem;
&.active {
color: $maroon;
}
} }
.menu-item-box { .menu-item-box {

View File

@@ -1,91 +1,38 @@
@import "../colors"; @import "../colors";
.menu-dropdown-label.network { .menu-items-container.network {
.menu-items-section {
padding-bottom: 1.5em;
}
.menu-label {
color: $mauve; color: $mauve;
} }
.network-element-item-ethernet.multi { .network-ethernet-icon {
margin-bottom: 0.5rem; font-size: 1.3em;
}
.menu-button-name.status.network {
margin-left: 2.5rem;
}
.menu-label.network {
color: $mauve; color: $mauve;
} }
.network-element-items-container * { .connection-container {
font-size: 0.95em; margin-left: 1em;
} }
.connection-status {
font-size: 0.9em;
}
.menu-section-container.wifi {
.menu-items-section {
min-height: 5em;
}
}
.network-element-item {
.network-element-item {
&:not(:last-child) { &:not(:last-child) {
margin-bottom: 0.4em; margin-bottom: 0.5em;
} }
&:hover { &:hover {
color: $mauve; color: $mauve;
} }
}
.menu-button-icon.network {
color: $overlay2;
}
.network-password-input {
border-radius: 0.4rem;
background: $crust;
padding: 0.4rem;
margin-left: 2.5rem;
margin-bottom: 0.5rem;
font-size: 0.85em;
}
.menu-icon-button.refresh.network {
margin-bottom: 1rem;
&:hover {
color: $mauve;
}
}
.network-password-input-close {
margin-left: 0.75rem;
margin-bottom: 0.6rem;
&:hover {
color: $sky;
}
label {
font-size: 1.45em;
}
}
.menu-icon-button.network.disconnect {
margin-bottom: 1.4rem;
margin-right: 0.5rem;
&:hover {
color: $mauve;
}
label {
font-size: 1.2rem;
}
}
.menu-icon-button.network.forget {
margin-bottom: 1.4rem;
margin-right: 0.5rem;
&:hover {
color: $mauve;
}
label {
font-size: 1.35em;
} }
} }

View File

@@ -32,6 +32,15 @@
margin: 0em; margin: 0em;
} }
.notification-card-content-container {
&:first-child {
margin-top: 0.5em;
}
&:not(:last-child) {
margin-bottom: 1em;
}
}
.menu-label-container.notifications { .menu-label-container.notifications {
margin: 0em; margin: 0em;
padding: 0em; padding: 0em;

111
style.css
View File

@@ -523,12 +523,15 @@ tooltip label {
margin: 0em 1.35em; margin: 0em 1.35em;
min-height: 2em; min-height: 2em;
} }
.menu-section-container.volume { .menu-section-container:first-child {
margin-bottom: 0em; margin-bottom: 0em;
} }
.menu-section-container.input { .menu-section-container:last-child {
margin-top: 0em; margin-top: 0em;
} }
.menu-section-container:nth-child(2) {
margin-top: 1.35em;
}
.menu-section-container .menu-items-section { .menu-section-container .menu-items-section {
background: #1e1e2e; background: #1e1e2e;
border-radius: 0.4em; border-radius: 0.4em;
@@ -537,12 +540,6 @@ tooltip label {
padding: 0.9em; padding: 0.9em;
margin: 0em 1.35em; margin: 0em 1.35em;
} }
.menu-section-container .menu-items-section.selected {
margin-bottom: 0em;
}
.menu-section-container .menu-items-section.input {
margin-top: 0em;
}
.menu-active { .menu-active {
font-size: 0.9em; font-size: 0.9em;
@@ -628,6 +625,9 @@ tooltip label {
color: #6c7086; color: #6c7086;
margin-right: 0.5rem; margin-right: 0.5rem;
} }
.menu-button-icon.active {
color: #eba0ac;
}
.menu-item-box { .menu-item-box {
margin-bottom: 0.5rem; margin-bottom: 0.5rem;
@@ -826,86 +826,32 @@ window#powermenu .powermenu.box {
color: #eba0ac; color: #eba0ac;
} }
.menu-dropdown-label.network { .menu-items-container.network .menu-items-section {
padding-bottom: 1.5em;
}
.menu-items-container.network .menu-label {
color: #cba6f7; color: #cba6f7;
} }
.menu-items-container.network .network-ethernet-icon {
.network-element-item-ethernet.multi { font-size: 1.3em;
margin-bottom: 0.5rem;
}
.menu-button-name.status.network {
margin-left: 2.5rem;
}
.menu-label.network {
color: #cba6f7; color: #cba6f7;
} }
.menu-items-container.network .connection-container {
.network-element-items-container * { margin-left: 1em;
font-size: 0.95em;
} }
.menu-items-container.network .connection-status {
.network-element-item:not(:last-child) { font-size: 0.9em;
margin-bottom: 0.4em;
} }
.network-element-item:hover { .menu-items-container.network .menu-section-container.wifi .menu-items-section {
min-height: 5em;
}
.menu-items-container.network .network-element-item:not(:last-child) {
margin-bottom: 0.5em;
}
.menu-items-container.network .network-element-item:hover {
color: #cba6f7; color: #cba6f7;
} }
.menu-button-icon.network {
color: #9399b2;
}
.network-password-input {
border-radius: 0.4rem;
background: #11111b;
padding: 0.4rem;
margin-left: 2.5rem;
margin-bottom: 0.5rem;
font-size: 0.85em;
}
.menu-icon-button.refresh.network {
margin-bottom: 1rem;
}
.menu-icon-button.refresh.network:hover {
color: #cba6f7;
}
.network-password-input-close {
margin-left: 0.75rem;
margin-bottom: 0.6rem;
}
.network-password-input-close:hover {
color: #89dceb;
}
.network-password-input-close label {
font-size: 1.45em;
}
.menu-icon-button.network.disconnect {
margin-bottom: 1.4rem;
margin-right: 0.5rem;
}
.menu-icon-button.network.disconnect:hover {
color: #cba6f7;
}
.menu-icon-button.network.disconnect label {
font-size: 1.2rem;
}
.menu-icon-button.network.forget {
margin-bottom: 1.4rem;
margin-right: 0.5rem;
}
.menu-icon-button.network.forget:hover {
color: #cba6f7;
}
.menu-icon-button.network.forget label {
font-size: 1.35em;
}
.menu-dropdown-label.bluetooth { .menu-dropdown-label.bluetooth {
color: #89dceb; color: #89dceb;
} }
@@ -1093,6 +1039,13 @@ image {
margin: 0em; margin: 0em;
} }
.notification-card-content-container:first-child {
margin-top: 0.5em;
}
.notification-card-content-container:not(:last-child) {
margin-bottom: 1em;
}
.menu-label-container.notifications { .menu-label-container.notifications {
margin: 0em; margin: 0em;
padding: 0em; padding: 0em;

File diff suppressed because one or more lines are too long