🔧 chore(control-center/tiles): better implementation for the network tile
This commit is contained in:
+33
-3
@@ -1,5 +1,6 @@
|
||||
import { Scope } from "ags";
|
||||
import { createScopedConnection, decoder, encoder } from "../modules/utils";
|
||||
import { showWorkspaceNumber } from "../window/bar/widgets/Workspaces";
|
||||
|
||||
import windows from "./modules/windows";
|
||||
import volume from "./modules/volume";
|
||||
@@ -9,6 +10,7 @@ import Gio from "gi://Gio?version=2.0";
|
||||
import GLib from "gi://GLib?version=2.0";
|
||||
|
||||
|
||||
/** cli implementation for colorshell */
|
||||
export namespace Cli {
|
||||
let rootScope: Scope;
|
||||
let initialized: boolean = false;
|
||||
@@ -27,6 +29,14 @@ export namespace Cli {
|
||||
type: "out"
|
||||
};
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "peek-workspace-num",
|
||||
help: "peek the workspace numbers in the workspace indicator. (optional: time in millis)",
|
||||
onCalled: () => {
|
||||
showWorkspaceNumber(true);
|
||||
return "Peeking workspace IDs...";
|
||||
}
|
||||
}
|
||||
],
|
||||
arguments: [
|
||||
@@ -214,13 +224,33 @@ export namespace Cli {
|
||||
);
|
||||
}
|
||||
|
||||
for(let i = 0; i < args.length; i++) {
|
||||
const arg = args[i];
|
||||
function handleCommandArguments(cmd: Module|Command, args: Array<string>, index: number, printFun: (out: Output) => void): void {
|
||||
const argNameRegEx = /^--/, argAliasRegEx = /^-/;
|
||||
let argName: string;
|
||||
|
||||
if(i === 0) {
|
||||
if(args[index].startsWith("--")) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
const firstFoundMod = modules.filter(mod => mod.prefix === args[0])[0];
|
||||
mod = firstFoundMod ?? modules[0];
|
||||
|
||||
if(!mod) {
|
||||
print({
|
||||
content: `No command module found with the name ${args[0]}!`,
|
||||
type: "err"
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
for(let i = 1; i < args.length; i++) {
|
||||
const arg = args[i];
|
||||
|
||||
if(/^-/.test(arg)) {
|
||||
handleCommandArguments(command ?? mod, args, i, print);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
function outputToString(out: Output): string {
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
import { CompositorHyprland } from "./hyprland";
|
||||
import GObject, { getter, gtype, register } from "ags/gobject";
|
||||
import GObject, { getter, gtype, property, register } from "ags/gobject";
|
||||
|
||||
import GLib from "gi://GLib?version=2.0";
|
||||
|
||||
|
||||
export default Compositors;
|
||||
|
||||
/** WIP modular implementation of a system that supports implementing
|
||||
* a variety of Wayland Compositors
|
||||
* @todo implement more general compositor info + a lot of stuff
|
||||
@@ -14,7 +17,6 @@ export namespace Compositors {
|
||||
export class Monitor extends GObject.Object {
|
||||
#width: number;
|
||||
#height: number;
|
||||
#scaling: number;
|
||||
|
||||
@getter(Number)
|
||||
get width() { return this.#width; }
|
||||
@@ -22,15 +24,15 @@ export namespace Compositors {
|
||||
@getter(Number)
|
||||
get height() { return this.#height; }
|
||||
|
||||
@getter(Number)
|
||||
get scaling() { return this.#scaling; }
|
||||
@property(Number)
|
||||
scaling: number;
|
||||
|
||||
constructor(width: number, height: number, scaling: number = 1) {
|
||||
super();
|
||||
|
||||
this.#width = width;
|
||||
this.#height = height;
|
||||
this.#scaling = scaling;
|
||||
this.scaling = scaling;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +51,6 @@ export namespace Compositors {
|
||||
super();
|
||||
|
||||
this.#monitor = monitor;
|
||||
this.notify("monitor");
|
||||
this.#id = id;
|
||||
}
|
||||
}
|
||||
@@ -110,10 +111,9 @@ export namespace Compositors {
|
||||
if(props.position !== undefined)
|
||||
this.#position = props.position;
|
||||
|
||||
if(props.initialClass !== undefined)
|
||||
this.#initialClass = props.initialClass;
|
||||
else
|
||||
this.#initialClass = props.class;
|
||||
this.#initialClass = props.initialClass !== undefined ?
|
||||
props.initialClass
|
||||
: props.class;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,85 +1,153 @@
|
||||
import { execAsync } from "ags/process";
|
||||
import { Tile } from "./Tile";
|
||||
import { execAsync } from "ags/process";
|
||||
import { PageNetwork } from "../pages/Network";
|
||||
import { tr } from "../../../../i18n/intl";
|
||||
import { TilesPages } from "../tiles";
|
||||
import { Gtk } from "ags/gtk4";
|
||||
import { createBinding, createComputed, With } from "ags";
|
||||
import { Accessor, createBinding, createComputed } from "ags";
|
||||
import { secureBaseBinding } from "../../../../modules/utils";
|
||||
|
||||
import AstalNetwork from "gi://AstalNetwork";
|
||||
import { Notifications } from "../../../../modules/notifications";
|
||||
|
||||
|
||||
export const TileNetwork = () => <Gtk.Box>
|
||||
<With value={createComputed([
|
||||
createBinding(AstalNetwork.get_default(), "primary"),
|
||||
const { WIFI, WIRED } = AstalNetwork.Primary,
|
||||
{ CONNECTED, CONNECTING } = AstalNetwork.Internet;
|
||||
|
||||
const wiredInternet = secureBaseBinding<AstalNetwork.Wired>(
|
||||
createBinding(AstalNetwork.get_default(), "wired"),
|
||||
createBinding(AstalNetwork.get_default(), "wifi")
|
||||
])}>
|
||||
"internet",
|
||||
AstalNetwork.Internet.DISCONNECTED
|
||||
) as Accessor<AstalNetwork.Internet>;
|
||||
|
||||
{([primary, wired, wifi]: [AstalNetwork.Primary, AstalNetwork.Wired, AstalNetwork.Wifi]) => {
|
||||
if(primary === AstalNetwork.Primary.WIFI) {
|
||||
return <Tile title={tr("control_center.tiles.network.wireless")}
|
||||
description={createComputed([
|
||||
createBinding(wifi, "ssid"), createBinding(wifi, "internet")
|
||||
], (ssid, internet) => ssid ? ssid : (() => {
|
||||
switch(internet) {
|
||||
case AstalNetwork.Internet.CONNECTED:
|
||||
return tr("connected");
|
||||
case AstalNetwork.Internet.DISCONNECTED:
|
||||
return tr("disconnected");
|
||||
case AstalNetwork.Internet.CONNECTING:
|
||||
return tr("connecting") + "...";
|
||||
}
|
||||
})()
|
||||
)} onEnabled={() => wifi.set_enabled(true)}
|
||||
onDisabled={() => wifi.set_enabled(false)}
|
||||
hasArrow onClicked={() => TilesPages?.toggle(PageNetwork)}
|
||||
icon={"network-wireless-signal-excellent-symbolic"}
|
||||
state={createBinding(wifi, "enabled")}
|
||||
/>
|
||||
const wifiInternet = secureBaseBinding<AstalNetwork.Wifi>(
|
||||
createBinding(AstalNetwork.get_default(), "wifi"),
|
||||
"internet",
|
||||
AstalNetwork.Internet.DISCONNECTED
|
||||
) as Accessor<AstalNetwork.Internet>;
|
||||
|
||||
} else if(primary === AstalNetwork.Primary.WIRED) {
|
||||
return <Tile title={tr("control_center.tiles.network.wired")}
|
||||
description={createBinding(wired, "internet").as((internet: AstalNetwork.Internet) => {
|
||||
switch(internet) {
|
||||
case AstalNetwork.Internet.CONNECTED:
|
||||
return tr("connected");
|
||||
case AstalNetwork.Internet.DISCONNECTED:
|
||||
return tr("disconnected");
|
||||
case AstalNetwork.Internet.CONNECTING:
|
||||
return tr("connecting") + "...";
|
||||
const wifiSSID = secureBaseBinding<AstalNetwork.Wifi>(
|
||||
createBinding(AstalNetwork.get_default(), "wifi"),
|
||||
"ssid",
|
||||
"Unknown"
|
||||
) as Accessor<string>;
|
||||
|
||||
const wifiIcon = secureBaseBinding<AstalNetwork.Wifi>(
|
||||
createBinding(AstalNetwork.get_default(), "wifi"),
|
||||
"iconName",
|
||||
"network-wireless-symbolic"
|
||||
);
|
||||
|
||||
const wiredIcon = secureBaseBinding<AstalNetwork.Wired>(
|
||||
createBinding(AstalNetwork.get_default(), "wired"),
|
||||
"iconName",
|
||||
"network-wired-symbolic"
|
||||
);
|
||||
|
||||
const primary = createBinding(AstalNetwork.get_default(), "primary");
|
||||
|
||||
export const TileNetwork = () =>
|
||||
<Tile hasArrow title={createComputed([
|
||||
primary,
|
||||
wifiInternet,
|
||||
wifiSSID
|
||||
], (primary, wiInternet, wiSSID) => {
|
||||
switch(primary) {
|
||||
case WIFI:
|
||||
if(wiInternet === CONNECTED)
|
||||
return wiSSID;
|
||||
|
||||
return tr("control_center.tiles.network.wireless");
|
||||
|
||||
case WIRED:
|
||||
return tr("control_center.tiles.network.wired");
|
||||
}
|
||||
|
||||
return tr("control_center.tiles.network.network");
|
||||
})}
|
||||
hasArrow onEnabled={() => execAsync("nmcli n on")}
|
||||
onDisabled={() => execAsync("nmcli n off")}
|
||||
onClicked={() => TilesPages?.toggle(PageNetwork)}
|
||||
icon={createBinding(wired, "internet").as((internet: AstalNetwork.Internet) => {
|
||||
switch(internet) {
|
||||
case AstalNetwork.Internet.CONNECTED:
|
||||
return "network-wired-symbolic";
|
||||
case AstalNetwork.Internet.DISCONNECTED:
|
||||
return "network-wired-disconnected-symbolic";
|
||||
icon={createComputed([
|
||||
primary,
|
||||
wifiIcon,
|
||||
wiredIcon
|
||||
], (primary, wifiIcon, wiredIcon) => {
|
||||
switch(primary) {
|
||||
case WIFI:
|
||||
return wifiIcon;
|
||||
|
||||
case WIRED:
|
||||
return wiredIcon;
|
||||
}
|
||||
|
||||
return "network-wired-no-route-symbolic";
|
||||
})}
|
||||
state={createBinding(wired, "internet").as((internet: AstalNetwork.Internet) =>
|
||||
internet === AstalNetwork.Internet.CONNECTING
|
||||
|| internet === AstalNetwork.Internet.CONNECTED
|
||||
)}
|
||||
/>
|
||||
state={createComputed([
|
||||
primary,
|
||||
secureBaseBinding<AstalNetwork.Wifi>(
|
||||
createBinding(AstalNetwork.get_default(), "wifi"),
|
||||
"enabled",
|
||||
false
|
||||
),
|
||||
wiredInternet.as(internet => internet === CONNECTED || internet === CONNECTING)
|
||||
], (primary, wifiEnabled, wiredEnabled) => {
|
||||
switch(primary) {
|
||||
case WIFI:
|
||||
return wifiEnabled;
|
||||
|
||||
case WIRED:
|
||||
return wiredEnabled;
|
||||
}
|
||||
|
||||
return <Tile
|
||||
title={tr("control_center.tiles.network.network")}
|
||||
description={tr("disconnected")}
|
||||
onEnabled={() => execAsync("nmcli n on")}
|
||||
onDisabled={() => execAsync("nmcli n off")}
|
||||
hasArrow onClicked={() => TilesPages?.toggle(PageNetwork)}
|
||||
icon={"network-wired-disconnected-symbolic"}
|
||||
state={createBinding(wired, "internet").as((internet: AstalNetwork.Internet) =>
|
||||
internet === AstalNetwork.Internet.CONNECTING || internet === AstalNetwork.Internet.CONNECTED)}
|
||||
/>
|
||||
return false;
|
||||
})}
|
||||
description={createComputed([
|
||||
primary,
|
||||
wifiInternet,
|
||||
wiredInternet
|
||||
], (primary, wifiInternet, wiredInternet) => {
|
||||
switch(primary) {
|
||||
case WIFI:
|
||||
return internetToTranslatedString(wifiInternet);
|
||||
|
||||
case WIRED:
|
||||
return internetToTranslatedString(wiredInternet);
|
||||
}
|
||||
|
||||
return tr("disconnected");
|
||||
})}
|
||||
onToggled={(self, state) => {
|
||||
switch(AstalNetwork.get_default().primary) {
|
||||
case WIFI:
|
||||
AstalNetwork.get_default().wifi.set_enabled(state);
|
||||
return;
|
||||
|
||||
case WIRED:
|
||||
(state ?
|
||||
execAsync("nmcli n off")
|
||||
: execAsync("nmcli n on")
|
||||
).catch(e => {
|
||||
Notifications.getDefault().sendNotification({
|
||||
appName: "network",
|
||||
summary: "Couldn't turn off network",
|
||||
body: `Turning off networking with nmcli failed: ${
|
||||
e?.message ?? "(no error message)"}`
|
||||
});
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// disable if no device available
|
||||
self.state = false;
|
||||
}}
|
||||
</With>
|
||||
</Gtk.Box>;
|
||||
/>;
|
||||
|
||||
|
||||
function internetToTranslatedString(internet: AstalNetwork.Internet): string {
|
||||
switch(internet) {
|
||||
case AstalNetwork.Internet.CONNECTED:
|
||||
return tr("connected");
|
||||
case AstalNetwork.Internet.CONNECTING:
|
||||
return tr("connecting") + "...";
|
||||
}
|
||||
|
||||
return tr("disconnected");
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ export class Tile extends Gtk.Box {
|
||||
public hasArrow: boolean = false;
|
||||
|
||||
declare $signals: Gtk.Box.SignalSignatures & {
|
||||
"toggled": (_state: boolean) => void;
|
||||
"toggled": (state: boolean) => void;
|
||||
"enabled": () => void;
|
||||
"disabled": () => void;
|
||||
"clicked": () => void;
|
||||
|
||||
@@ -16,34 +16,41 @@ export const FloatingNotifications = (mon: number) =>
|
||||
generalConfig.bindProperty("notifications.position_h", "string"),
|
||||
generalConfig.bindProperty("notifications.position_v", "string")
|
||||
]).as(([posH, posV]) => {
|
||||
let horizontal: Astal.WindowAnchor = Astal.WindowAnchor.RIGHT,
|
||||
vertical: Astal.WindowAnchor = Astal.WindowAnchor.TOP;
|
||||
const pos: Array<Astal.WindowAnchor> = [];
|
||||
|
||||
switch(posH) {
|
||||
case "left":
|
||||
horizontal = Astal.WindowAnchor.LEFT;
|
||||
pos.push(Astal.WindowAnchor.LEFT);
|
||||
break;
|
||||
case "center":
|
||||
horizontal = Astal.WindowAnchor.LEFT | Astal.WindowAnchor.RIGHT;
|
||||
pos.push(Astal.WindowAnchor.LEFT);
|
||||
pos.push(Astal.WindowAnchor.RIGHT);
|
||||
break;
|
||||
case "right":
|
||||
horizontal = Astal.WindowAnchor.RIGHT;
|
||||
pos.push(Astal.WindowAnchor.RIGHT);
|
||||
break;
|
||||
}
|
||||
|
||||
switch(posV) {
|
||||
case "top":
|
||||
vertical = Astal.WindowAnchor.TOP;
|
||||
pos.push(Astal.WindowAnchor.TOP);
|
||||
break;
|
||||
case "center":
|
||||
vertical = Astal.WindowAnchor.TOP | Astal.WindowAnchor.BOTTOM;
|
||||
pos.push(Astal.WindowAnchor.TOP);
|
||||
pos.push(Astal.WindowAnchor.BOTTOM);
|
||||
break;
|
||||
case "bottom":
|
||||
vertical = Astal.WindowAnchor.BOTTOM;
|
||||
pos.push(Astal.WindowAnchor.BOTTOM);
|
||||
break;
|
||||
}
|
||||
|
||||
return horizontal | vertical;
|
||||
let finalPos: Astal.WindowAnchor;
|
||||
|
||||
pos.forEach(pos => finalPos = (finalPos !== undefined ?
|
||||
finalPos | pos
|
||||
: pos));
|
||||
|
||||
return finalPos!;
|
||||
|
||||
})} exclusivity={Astal.Exclusivity.NORMAL}
|
||||
resizable={false} widthRequest={450}>
|
||||
|
||||
Reference in New Issue
Block a user