[AGS] Bar progress
This commit is contained in:
		| @@ -1,23 +1,36 @@ | ||||
| import { createQuickActionsMenu } from "./QuickActions"; | ||||
| import { GLib } from "astal"; | ||||
| import { Astal, Gdk, Gtk } from "astal/gtk3"; | ||||
| import Hyprland from "./modules/Hyprland"; | ||||
| import Calendar from "./modules/Calendar"; | ||||
| import QuickView from "./modules/QuickView"; | ||||
|  | ||||
| const Bar = (gdkmonitor: Gdk.Monitor) => { | ||||
|     const { TOP, LEFT, RIGHT } = Astal.WindowAnchor; | ||||
|  | ||||
|     return ( | ||||
|         <window gdkmonitor={gdkmonitor} | ||||
|             cssClasses={["Bar"]}> | ||||
|             cssClasses={["Bar"]} | ||||
|             exclusivity={Astal.Exclusivity.EXCLUSIVE} | ||||
|             anchor={TOP | LEFT | RIGHT}> | ||||
|             <box orientation={Gtk.Orientation.HORIZONTAL} spacing={10}> | ||||
|                 <box> | ||||
|                 <box hexpand halign={Gtk.Align.START}> | ||||
|                     <Calendar.Time /> | ||||
|                     <Hyprland.Workspace /> | ||||
|                 </box> | ||||
|                 <label>{windowTitle}</label> | ||||
|                 <box> | ||||
|                     <tray /> | ||||
|                     <button icon="quickaction" menu={quickActionMenu} /> | ||||
|                 <Hyprland.ActiveWindow /> | ||||
|                 <box hexpand halign={Gtk.Align.END}> | ||||
|                     <Hyprland.SysTray /> | ||||
|                     <QuickView.QuickView /> | ||||
|                 </box> | ||||
|             </box> | ||||
|         </window> | ||||
|     ); | ||||
| } | ||||
|  | ||||
| export default Bar; | ||||
| const cliHandler = ( args: string[] ): string => { | ||||
|     return 'Not implemented'; | ||||
| } | ||||
|  | ||||
| export default { | ||||
|     Bar, | ||||
|     cliHandler | ||||
| }; | ||||
|   | ||||
| @@ -0,0 +1,17 @@ | ||||
| import { GLib, Variable } from "astal" | ||||
|  | ||||
| const Time = ({ format = "%a, %e.%m %H:%M:%S" }) => { | ||||
|     const time = Variable<string>("").poll(1000, () => | ||||
|         GLib.DateTime.new_now_local().format(format)!) | ||||
|  | ||||
|     return <label | ||||
|         className="Time" | ||||
|         onDestroy={() => time.drop()} | ||||
|         label={time()} | ||||
|     /> | ||||
| } | ||||
|  | ||||
|  | ||||
| export default { | ||||
|     Time | ||||
| } | ||||
|   | ||||
| @@ -19,7 +19,7 @@ const SysTray = () => { | ||||
| } | ||||
|  | ||||
|  | ||||
| const HyprlandWorkspace = () => { | ||||
| const Workspace = () => { | ||||
|     const hypr = AstalHyprland.get_default() | ||||
|  | ||||
|     return <box className={"HyprlandWorkspaces"}> | ||||
| @@ -39,7 +39,7 @@ const HyprlandWorkspace = () => { | ||||
| } | ||||
|  | ||||
|  | ||||
| const HyprlandActiveWindow = () => { | ||||
| const ActiveWindow = () => { | ||||
|     const hypr = AstalHyprland.get_default(); | ||||
|     const focused = bind( hypr, "focusedClient" ); | ||||
|  | ||||
| @@ -51,7 +51,7 @@ const HyprlandActiveWindow = () => { | ||||
| } | ||||
|  | ||||
| export default { | ||||
|     HyprlandWorkspace,  | ||||
|     HyprlandActiveWindow, | ||||
|     Workspace,  | ||||
|     ActiveWindow, | ||||
|     SysTray | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,106 @@ | ||||
| import { bind } from "astal"; | ||||
| import AstalBattery from "gi://AstalBattery?version=0.1"; | ||||
| import AstalBluetooth from "gi://AstalBluetooth?version=0.1"; | ||||
| import AstalNetwork from "gi://AstalNetwork?version=0.1" | ||||
| import AstalWp from "gi://AstalWp?version=0.1"; | ||||
| import Brightness from "../../util/brightness"; | ||||
| import { Gtk } from "astal/gtk3"; | ||||
|  | ||||
| const QuickView = () => { | ||||
|     return <box> | ||||
|         <Audio></Audio> | ||||
|         <label label="QuickView"></label> | ||||
|     </box> | ||||
| } | ||||
|  | ||||
|  | ||||
| const NetworkWidget = () => { | ||||
|     const network = AstalNetwork.get_default(); | ||||
|     const status = bind( network, "state" ); | ||||
|     const wifiStrength = bind( network.wifi, 'strength' ); | ||||
|     const states = { | ||||
|         "off": "" | ||||
|     } | ||||
|  | ||||
|     return <label label={""}></label> | ||||
|  | ||||
| } | ||||
|  | ||||
| const BluetoothWidget = () => { | ||||
|     const bluetooth = AstalBluetooth.get_default(); | ||||
|     const enabled = bind( bluetooth, "isPowered" ); | ||||
|     const connected = bind( bluetooth, "isConnected" ); | ||||
| } | ||||
|  | ||||
|  | ||||
| const BatteryWidget = () => { | ||||
|     const battery = AstalBattery.get_default(); | ||||
|     if ( battery.get_is_present() ) { | ||||
|         const states = { | ||||
|             "100": "", | ||||
|             "90": "", | ||||
|             "80": "", | ||||
|             "70": "", | ||||
|             "60": "", | ||||
|             "50": "", | ||||
|             "40": "", | ||||
|             "30": "", | ||||
|             "20": "", | ||||
|             "10": "", | ||||
|             "critical": "", | ||||
|             "charging":"", | ||||
|             "plugged": " ", | ||||
|         } | ||||
|     } | ||||
|     // Else, no battery available -> Don't show the widget | ||||
| } | ||||
|  | ||||
|  | ||||
| const BrightnessWidget = () => { | ||||
|     // TODO: Finish (detect if there is a controllable screen) | ||||
|     const brightness = Brightness.get_default(); | ||||
|     const screen_brightness = bind( brightness, "screen" ); | ||||
|  | ||||
|     return <label label={"🌣" + screen_brightness}></label> | ||||
| } | ||||
|  | ||||
|  | ||||
| const Audio = () => { | ||||
|     const wireplumber = AstalWp.get_default(); | ||||
|     if ( wireplumber ) { | ||||
|         // With the states, split up the icons according to number of elements available | ||||
|         const speakerMuted = " "; | ||||
|         const speakersStates = [ | ||||
|             "", | ||||
|             "", | ||||
|             "" | ||||
|         ] | ||||
|         const micStates = { | ||||
|             "on": " ", | ||||
|             "muted": " ", | ||||
|         } | ||||
|         const volume_speakers = bind( wireplumber.defaultSpeaker, 'volume' ); | ||||
|         const muted_speakers = bind( wireplumber.defaultSpeaker, 'mute' ); | ||||
|         const muted_mic = bind( wireplumber.defaultMicrophone, 'mute' ); | ||||
|  | ||||
|         return <box orientation={Gtk.Orientation.HORIZONTAL}> | ||||
|             <label label={micStates[ muted_mic ? 'muted' : 'on' ]}></label> | ||||
|             <label label={(muted_speakers ? speakerMuted : volume_speakers.as( v => { | ||||
|                 if ( v === 0 ) return speakerMuted; | ||||
|                 else if ( v <= 30 ) return speakersStates[ 0 ]; | ||||
|                 else if ( v <= 70 ) return speakersStates[ 1 ]; | ||||
|                 else return speakersStates[ 2 ]; | ||||
|             } ) )}></label> | ||||
|             <label label={volume_speakers.as( v => { return "" + v } ) }></label> | ||||
|             <label label={wireplumber.default_speaker.get_name()}></label> | ||||
|         </box> | ||||
|     } else { | ||||
|         print( '[ WirePlumber ] Could not connect, Audio support in bar will be missing' ); | ||||
|     } | ||||
|     return null; | ||||
| } | ||||
|  | ||||
|  | ||||
| export default { | ||||
|     QuickView | ||||
| } | ||||
|   | ||||
							
								
								
									
										71
									
								
								config/astal/components/bar/util/brightness.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								config/astal/components/bar/util/brightness.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,71 @@ | ||||
| import GObject, { register, property } from "astal/gobject" | ||||
| import { monitorFile, readFileAsync } from "astal/file" | ||||
| import { exec, execAsync } from "astal/process" | ||||
|  | ||||
| const get = (args: string) => Number(exec(`brightnessctl ${args}`)) | ||||
| const screen = exec(`bash -c "ls -w1 /sys/class/backlight | head -1"`) | ||||
| const kbd = exec(`bash -c "ls -w1 /sys/class/leds | head -1"`) | ||||
|  | ||||
| @register({ GTypeName: "Brightness" }) | ||||
| export default class Brightness extends GObject.Object { | ||||
|     static instance: Brightness | ||||
|     static get_default() { | ||||
|         if (!this.instance) | ||||
|             this.instance = new Brightness() | ||||
|  | ||||
|         return this.instance | ||||
|     } | ||||
|  | ||||
|     #kbdMax = get(`--device ${kbd} max`) | ||||
|     #kbd = get(`--device ${kbd} get`) | ||||
|     #screenMax = get("max") | ||||
|     #screen = get("get") / (get("max") || 1) | ||||
|  | ||||
|     @property(Number) | ||||
|     get kbd() { return this.#kbd } | ||||
|  | ||||
|     set kbd(value) { | ||||
|         if (value < 0 || value > this.#kbdMax) | ||||
|             return | ||||
|  | ||||
|         execAsync(`brightnessctl -d ${kbd} s ${value} -q`).then(() => { | ||||
|             this.#kbd = value | ||||
|             this.notify("kbd") | ||||
|         }) | ||||
|     } | ||||
|  | ||||
|     @property(Number) | ||||
|     get screen() { return this.#screen } | ||||
|  | ||||
|     set screen(percent) { | ||||
|         if (percent < 0) | ||||
|             percent = 0 | ||||
|  | ||||
|         if (percent > 1) | ||||
|             percent = 1 | ||||
|  | ||||
|         execAsync(`brightnessctl set ${Math.floor(percent * 100)}% -q`).then(() => { | ||||
|             this.#screen = percent | ||||
|             this.notify("screen") | ||||
|         }) | ||||
|     } | ||||
|  | ||||
|     constructor() { | ||||
|         super() | ||||
|  | ||||
|         const screenPath = `/sys/class/backlight/${screen}/brightness` | ||||
|         const kbdPath = `/sys/class/leds/${kbd}/brightness` | ||||
|  | ||||
|         monitorFile(screenPath, async f => { | ||||
|             const v = await readFileAsync(f) | ||||
|             this.#screen = Number(v) / this.#screenMax | ||||
|             this.notify("screen") | ||||
|         }) | ||||
|  | ||||
|         monitorFile(kbdPath, async f => { | ||||
|             const v = await readFileAsync(f) | ||||
|             this.#kbd = Number(v) / this.#kbdMax | ||||
|             this.notify("kbd") | ||||
|         }) | ||||
|     } | ||||
| } | ||||
| @@ -1,68 +0,0 @@ | ||||
| import AstalHyprland from "gi://AstalHyprland"; | ||||
|  | ||||
| const getAvailableWorkspaces = (): number[] => { | ||||
|     const workspaces: number[] = []; | ||||
|     AstalHyprland.get_default().get_workspaces().forEach( val => { | ||||
|         workspaces.push( val.get_id() ); | ||||
|     } ) | ||||
|     return workspaces; | ||||
| } | ||||
|  | ||||
| const getCurrentWorkspaceID = (): number => { | ||||
|     return AstalHyprland.get_default().get_focused_workspace().get_id(); | ||||
| } | ||||
|  | ||||
| const getCurrentWindowTitle = (): string => { | ||||
|     return AstalHyprland.get_default().get_focused_client().get_title(); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Get the workspace ID of a window by its address | ||||
|  * @param address - The address of the window | ||||
|  * @returns The workspace ID | ||||
|  */ | ||||
| const getWorkspaceIDOfWindowByAddress = ( address: string ): number => { | ||||
|     AstalHyprland.get_default().get_clients().forEach( client => { | ||||
|         if ( client.get_address() === address ) { | ||||
|             return client.get_workspace().get_id(); | ||||
|         } | ||||
|     } ); | ||||
|  | ||||
|     return -1; | ||||
| } | ||||
|  | ||||
|  | ||||
| interface HyprlandSubscriptions { | ||||
|     [key: string]: ( data: string ) => void; | ||||
| } | ||||
| const hooks: HyprlandSubscriptions = {}; | ||||
|  | ||||
| /** | ||||
|  * Add an event listener for Hyprland events. | ||||
|  * @param event - A hyprland IPC event. See https://wiki.hyprland.org/IPC/. Useful events include: urgent, windowtitlev2, workspace, createworkspacev2, destroyworkspacev2, activewindowv2 | ||||
|  * @param cb - The callback function | ||||
|  */ | ||||
| const subscribeToUpdates = ( event: string, cb: ( data: string ) => void ): void => { | ||||
|     hooks[ event ] = cb; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Listen to events. Must be called at some point if events are to be listened for | ||||
|  */ | ||||
| const listen = () => { | ||||
|     AstalHyprland.get_default().connect( "event", ( name: string, data: string ) => { | ||||
|         if ( hooks[ name ] ) { | ||||
|             hooks[ name ]( data ); | ||||
|         } | ||||
|     } ); | ||||
| } | ||||
|  | ||||
|  | ||||
| export default { | ||||
|     getAvailableWorkspaces, | ||||
|     getCurrentWorkspaceID, | ||||
|     getCurrentWindowTitle, | ||||
|     getWorkspaceIDOfWindowByAddress, | ||||
|     subscribeToUpdates, | ||||
|     listen | ||||
| } | ||||
| @@ -195,12 +195,29 @@ const startNotificationHandler = (id: number, gdkmonitor: Gdk.Monitor) => { | ||||
|     </window> | ||||
| } | ||||
|  | ||||
| const cliHandler = ( args: string[] ): string => { | ||||
|     if ( args[ 1 ] == 'show' ) { | ||||
|         openNotificationMenu( 0 ); | ||||
|         return 'Showing all open notifications'; | ||||
|     } else if ( args[ 1 ] == 'hide' ) { | ||||
|         closeNotificationMenu( 0 ); | ||||
|         return 'Hid all notifications'; | ||||
|     } else if ( args[ 1 ] == 'clear' ) { | ||||
|         clearAllNotifications( 0 ); | ||||
|         return 'Cleared all notifications'; | ||||
|     } else if ( args[ 1 ] == 'clear-newest' ) { | ||||
|         clearNewestNotifications( 0 ); | ||||
|         return 'Cleared newest notification'; | ||||
|     } else if ( args[ 1 ] == 'toggle' ) { | ||||
|         toggleNotificationMenu( 0 ); | ||||
|         return 'Toggled notifications'; | ||||
|     } else { | ||||
|         return 'Unknown command!'; | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| export default { | ||||
|     startNotificationHandler, | ||||
|     openNotificationMenu, | ||||
|     closeNotificationMenu, | ||||
|     clearAllNotifications, | ||||
|     clearNewestNotifications, | ||||
|     toggleNotificationMenu | ||||
|     cliHandler | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user