[Astal] Add mode indicator
This commit is contained in:
		| @@ -1,19 +1,30 @@ | |||||||
| import { App, Astal, Gdk, Gtk } from "astal/gtk4"; | import { | ||||||
| import Hyprland from "./modules/Hyprland"; |     App, Astal, Gdk, Gtk | ||||||
| import Calendar from "./modules/Calendar"; | } from 'astal/gtk4'; | ||||||
| import QuickView from "./modules/QuickView"; | import Calendar from './modules/Calendar'; | ||||||
| import SystemInfo from "./modules/SystemInfo"; | import { | ||||||
| import { CenterBox } from "astal/gtk4/widget"; |     CenterBox | ||||||
|  | } from 'astal/gtk4/widget'; | ||||||
|  | import Hyprland from './modules/Hyprland'; | ||||||
|  | import QuickView from './modules/QuickView'; | ||||||
|  | import SystemInfo from './modules/SystemInfo'; | ||||||
|  |  | ||||||
| const Bar = ( { gdkmonitor, name }: { gdkmonitor: Gdk.Monitor, name: string } ) => { | const Bar = ( { | ||||||
|     const { TOP, LEFT, RIGHT } = Astal.WindowAnchor; |     gdkmonitor, name | ||||||
|  | }: { | ||||||
|  |     'gdkmonitor': Gdk.Monitor, | ||||||
|  |     'name': string | ||||||
|  | } ) => { | ||||||
|  |     const { | ||||||
|  |         TOP, LEFT, RIGHT | ||||||
|  |     } = Astal.WindowAnchor; | ||||||
|  |  | ||||||
|     return ( |     return ( | ||||||
|         <window |         <window | ||||||
|             gdkmonitor={gdkmonitor} |             gdkmonitor={gdkmonitor} | ||||||
|             cssClasses={["Bar"]} |             cssClasses={[ 'Bar' ]} | ||||||
|             name={name} |             name={name} | ||||||
|             namespace={"bar"} |             namespace={'bar'} | ||||||
|             exclusivity={Astal.Exclusivity.EXCLUSIVE} |             exclusivity={Astal.Exclusivity.EXCLUSIVE} | ||||||
|             anchor={TOP | LEFT | RIGHT} |             anchor={TOP | LEFT | RIGHT} | ||||||
|             visible |             visible | ||||||
| @@ -26,6 +37,7 @@ const Bar = ( { gdkmonitor, name }: { gdkmonitor: Gdk.Monitor, name: string } ) | |||||||
|                             hexpand |                             hexpand | ||||||
|                             halign={Gtk.Align.START} |                             halign={Gtk.Align.START} | ||||||
|                         > |                         > | ||||||
|  |                             <Hyprland.ModeStatus /> | ||||||
|                             <Calendar.Time /> |                             <Calendar.Time /> | ||||||
|                             <SystemInfo.SystemInfo /> |                             <SystemInfo.SystemInfo /> | ||||||
|                             <Hyprland.Workspace /> |                             <Hyprland.Workspace /> | ||||||
| @@ -36,7 +48,7 @@ const Bar = ( { gdkmonitor, name }: { gdkmonitor: Gdk.Monitor, name: string } ) | |||||||
|                         <box |                         <box | ||||||
|                             hexpand |                             hexpand | ||||||
|                             halign={Gtk.Align.END} |                             halign={Gtk.Align.END} | ||||||
|                             cssClasses={["BarRight"]} |                             cssClasses={[ 'BarRight' ]} | ||||||
|                         > |                         > | ||||||
|                             <Hyprland.SysTray /> |                             <Hyprland.SysTray /> | ||||||
|                             <QuickView.QuickView /> |                             <QuickView.QuickView /> | ||||||
| @@ -48,21 +60,24 @@ const Bar = ( { gdkmonitor, name }: { gdkmonitor: Gdk.Monitor, name: string } ) | |||||||
|     ); |     ); | ||||||
| }; | }; | ||||||
|  |  | ||||||
| const cliHandler = (args: string[]): string => { | const cliHandler = ( args: string[] ): string => { | ||||||
|     return "Not implemented"; |     console.debug( args ); | ||||||
|  |  | ||||||
|  |     return 'Not implemented'; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| const BarLauncher = ( monitor: Gdk.Monitor ) => { | const BarLauncher = ( monitor: Gdk.Monitor ) => { | ||||||
|     const windowName = `bar-${monitor.get_connector()}` |     const windowName = `bar-${ monitor.get_connector() }`; | ||||||
|  |  | ||||||
|     const createBar = () => { |     const createBar = () => { | ||||||
|         return <Bar gdkmonitor={monitor} name={windowName}></Bar> |         return <Bar gdkmonitor={monitor} name={windowName}></Bar>; | ||||||
|     } |     }; | ||||||
|  |  | ||||||
|     // Actually start the bar |     // Actually start the bar | ||||||
|     createBar(); |     createBar(); | ||||||
|  |  | ||||||
|     return windowName; |     return windowName; | ||||||
| } | }; | ||||||
|  |  | ||||||
| export default { | export default { | ||||||
|     BarLauncher, |     BarLauncher, | ||||||
|   | |||||||
| @@ -12,6 +12,14 @@ window.Bar { | |||||||
|   /*     margin: 8px; */ |   /*     margin: 8px; */ | ||||||
|   /* } */ |   /* } */ | ||||||
|   .mode-status { |   .mode-status { | ||||||
|  |     color: white; | ||||||
|  |     background-color: #00002dff; | ||||||
|  |     padding-left: 10px; | ||||||
|  |     padding-right: 10px; | ||||||
|  |     margin-left: 5px; | ||||||
|  |     border-radius: 20px; | ||||||
|  |     font-family: $monospace-font; | ||||||
|  |  | ||||||
|     &.windowing-mode { |     &.windowing-mode { | ||||||
|       background-color: darkslategray; |       background-color: darkslategray; | ||||||
|       color: white; |       color: white; | ||||||
| @@ -85,6 +93,7 @@ window.Bar { | |||||||
|   .time { |   .time { | ||||||
|     min-width: 11rem; |     min-width: 11rem; | ||||||
|     padding: 3px; |     padding: 3px; | ||||||
|  |  | ||||||
|     & button { |     & button { | ||||||
|       box-shadow: none; |       box-shadow: none; | ||||||
|       padding: 0; |       padding: 0; | ||||||
|   | |||||||
| @@ -1,50 +1,59 @@ | |||||||
| import AstalTray from "gi://AstalTray"; | import { | ||||||
| import { bind, GObject } from "astal"; |     GObject, bind, | ||||||
| import AstalHyprland from "gi://AstalHyprland"; |     exec, | ||||||
| import { Gtk } from "astal/gtk4"; |     readFile | ||||||
| import Pango from "gi://Pango?version=1.0"; | } from 'astal'; | ||||||
|  | import AstalHyprland from 'gi://AstalHyprland'; | ||||||
|  | import AstalTray from 'gi://AstalTray'; | ||||||
|  | import { | ||||||
|  |     Gtk | ||||||
|  | } from 'astal/gtk4'; | ||||||
|  | import Pango from 'gi://Pango?version=1.0'; | ||||||
|  |  | ||||||
| const hypr = AstalHyprland.get_default(); | const hypr = AstalHyprland.get_default(); | ||||||
| const SYNC = GObject.BindingFlags.SYNC_CREATE; | const SYNC = GObject.BindingFlags.SYNC_CREATE; | ||||||
|  |  | ||||||
| const SysTray = () => { | const SysTray = () => { | ||||||
|     const trayBox = new Gtk.Box({ cssClasses: ["bar-button"] }); |     const trayBox = new Gtk.Box( { | ||||||
|  |         'cssClasses': [ 'bar-button' ] | ||||||
|  |     } ); | ||||||
|     const tray = AstalTray.get_default(); |     const tray = AstalTray.get_default(); | ||||||
|  |  | ||||||
|     const trayItems = new Map<string, Gtk.MenuButton>(); |     const trayItems = new Map<string, Gtk.MenuButton>(); | ||||||
|     const trayAddedHandler = tray.connect("item-added", (_, id) => { |     const trayAddedHandler = tray.connect( 'item-added', ( _, id ) => { | ||||||
|         const item = tray.get_item(id); |         const item = tray.get_item( id ); | ||||||
|         const popover = Gtk.PopoverMenu.new_from_model(item.menu_model); |         const popover = Gtk.PopoverMenu.new_from_model( item.menu_model ); | ||||||
|         const icon = new Gtk.Image(); |         const icon = new Gtk.Image(); | ||||||
|         const button = new Gtk.MenuButton({ |         const button = new Gtk.MenuButton( { | ||||||
|             popover, |             popover, | ||||||
|             child: icon, |             'child': icon, | ||||||
|             cssClasses: ["tray-item"], |             'cssClasses': [ 'tray-item' ], | ||||||
|         }); |         } ); | ||||||
|  |  | ||||||
|         item.bind_property("gicon", icon, "gicon", SYNC); |         item.bind_property( | ||||||
|         popover.insert_action_group("dbusmenu", item.action_group); |             'gicon', icon, 'gicon', SYNC | ||||||
|         item.connect("notify::action-group", () => { |         ); | ||||||
|             popover.insert_action_group("dbusmenu", item.action_group); |         popover.insert_action_group( 'dbusmenu', item.action_group ); | ||||||
|         }); |         item.connect( 'notify::action-group', () => { | ||||||
|  |             popover.insert_action_group( 'dbusmenu', item.action_group ); | ||||||
|  |         } ); | ||||||
|  |  | ||||||
|         trayItems.set(id, button); |         trayItems.set( id, button ); | ||||||
|         trayBox.append(button); |         trayBox.append( button ); | ||||||
|     }); |     } ); | ||||||
|  |     const trayRemovedHandler = tray.connect( 'item-removed', ( _, id ) => { | ||||||
|  |         const button = trayItems.get( id ); | ||||||
|  |  | ||||||
|     const trayRemovedHandler = tray.connect("item-removed", (_, id) => { |         if ( button ) { | ||||||
|         const button = trayItems.get(id); |             trayBox.remove( button ); | ||||||
|         if (button) { |  | ||||||
|             trayBox.remove(button); |  | ||||||
|             button.run_dispose(); |             button.run_dispose(); | ||||||
|             trayItems.delete(id); |             trayItems.delete( id ); | ||||||
|         } |         } | ||||||
|     }); |     } ); | ||||||
|  |  | ||||||
|     trayBox.connect("destroy", () => { |     trayBox.connect( 'destroy', () => { | ||||||
|         tray.disconnect(trayAddedHandler); |         tray.disconnect( trayAddedHandler ); | ||||||
|         tray.disconnect(trayRemovedHandler); |         tray.disconnect( trayRemovedHandler ); | ||||||
|     }); |     } ); | ||||||
|  |  | ||||||
|     return trayBox; |     return trayBox; | ||||||
| }; | }; | ||||||
| @@ -52,25 +61,21 @@ const SysTray = () => { | |||||||
| const Workspace = () => { | const Workspace = () => { | ||||||
|     return ( |     return ( | ||||||
|         <box> |         <box> | ||||||
|             {bind(hypr, "workspaces").as(wss => |             {bind( hypr, 'workspaces' ).as( wss => wss | ||||||
|                 wss |                 .filter( ws => !( ws.id >= -99 && ws.id <= -2 ) ) // filter out special workspaces | ||||||
|                     .filter(ws => !(ws.id >= -99 && ws.id <= -2)) // filter out special workspaces |                 .sort( ( a, b ) => a.id - b.id ) | ||||||
|                     .sort((a, b) => a.id - b.id) |                 .map( ws => ( | ||||||
|                     .map(ws => ( |  | ||||||
|                     <button |                     <button | ||||||
|                             cssClasses={bind(hypr, "focusedWorkspace").as(fw => |                         cssClasses={bind( hypr, 'focusedWorkspace' ).as( fw => ws === fw | ||||||
|                                 ws === fw |  | ||||||
|                             ? [ |                             ? [ | ||||||
|                                         "focused-workspace-button", |                                 'focused-workspace-button', | ||||||
|                                         "workspace-button", |                                 'workspace-button', | ||||||
|                             ] |                             ] | ||||||
|                                     : ["workspace-button"], |                             : [ 'workspace-button' ], )} | ||||||
|                             )} |  | ||||||
|                         onButtonPressed={() => ws.focus()} |                         onButtonPressed={() => ws.focus()} | ||||||
|                             child={<label label={String(ws.id)}></label>} |                         child={<label label={String( ws.id )}></label>} | ||||||
|                     ></button> |                     ></button> | ||||||
|                     )), |                 ) ), )} | ||||||
|             )} |  | ||||||
|         </box> |         </box> | ||||||
|     ); |     ); | ||||||
| }; | }; | ||||||
| @@ -80,15 +85,15 @@ const Workspace = () => { | |||||||
|  * displaying all available clients |  * displaying all available clients | ||||||
|  */ |  */ | ||||||
| const ActiveWindow = () => { | const ActiveWindow = () => { | ||||||
|     const focused = bind(hypr, "focusedClient"); |     const focused = bind( hypr, 'focusedClient' ); | ||||||
|  |  | ||||||
|     const WindowPopover = (): Gtk.Popover => { |     const WindowPopover = (): Gtk.Popover => { | ||||||
|         // Set up boxes + Popover |         // Set up boxes + Popover | ||||||
|         const popover = new Gtk.Popover(); |         const popover = new Gtk.Popover(); | ||||||
|  |  | ||||||
|         const popoverBox = WindowPopoverBox(); |         const popoverBox = WindowPopoverBox(); | ||||||
|  |  | ||||||
|         popover.set_child(popoverBox); |         popover.set_child( popoverBox ); | ||||||
|  |  | ||||||
|         return popover; |         return popover; | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
| @@ -98,65 +103,88 @@ const ActiveWindow = () => { | |||||||
|     // Return fully assembled HyprlandFocusedClient box |     // Return fully assembled HyprlandFocusedClient box | ||||||
|     // ─────────────────────────────────────────────────────────────────── |     // ─────────────────────────────────────────────────────────────────── | ||||||
|     return ( |     return ( | ||||||
|         <box visible={focused.as(Boolean)}> |         <box visible={focused.as( Boolean )}> | ||||||
|             <button |             <button | ||||||
|                 onClicked={() => windowPopover.popup()} |                 onClicked={() => windowPopover.popup()} | ||||||
|                 cssClasses={["bar-button"]} |                 cssClasses={[ 'bar-button' ]} | ||||||
|                 child={ |                 child={ | ||||||
|                     focused.as( |                     focused.as( client => client && ( | ||||||
|                         client => |  | ||||||
|                             client && ( |  | ||||||
|                         <label |                         <label | ||||||
|                             maxWidthChars={70} |                             maxWidthChars={70} | ||||||
|                             ellipsize={Pango.EllipsizeMode.END} |                             ellipsize={Pango.EllipsizeMode.END} | ||||||
|                                     label={bind(client, "title").as(String)} /> |                             label={bind( client, 'title' ).as( String )} /> | ||||||
|                             ), |                     ), ) | ||||||
|                     ) |  | ||||||
|                 }></button> |                 }></button> | ||||||
|             {windowPopover} |             {windowPopover} | ||||||
|         </box > |         </box > | ||||||
|     ); |     ); | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | type submaps = 'device' | 'launch' | 'workspace' | 'windowing' | 'screenshotting' | 'notifications' | ''; | ||||||
|  |  | ||||||
| const ModeStatus = () => { | const ModeStatus = () => { | ||||||
|     const label = new Gtk.Label(); |     let isUsingHyprmode = false; | ||||||
|     const map = { |  | ||||||
|         "device": "D", |     try { | ||||||
|         "launch": "L", |         const path = exec( 'bash -c "cd ~ && pwd"' ) + '/.config/hyprmode'; | ||||||
|         "workspace": "W", |  | ||||||
|         "windowing": "M", |         isUsingHyprmode = readFile( path ).trim() === 'y'; | ||||||
|         "screenshotting": "S", |     } catch ( e ) { | ||||||
|         "notifications": "N", |         printerr( 'Failed to read hyprmode config', e ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     const label = new Gtk.Label(); | ||||||
|  |  | ||||||
|  |     if ( !isUsingHyprmode ) return label; | ||||||
|  |  | ||||||
|  |     print( '==> Using hyprmode config' ); | ||||||
|  |  | ||||||
|  |     const map = { | ||||||
|  |         'device': 'D', | ||||||
|  |         'launch': 'L', | ||||||
|  |         'workspace': 'W', | ||||||
|  |         'windowing': 'M', | ||||||
|  |         'screenshotting': 'S', | ||||||
|  |         'notifications': 'N', | ||||||
|  |         '': 'N' | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     label.label = 'N'; | ||||||
|  |     label.cssClasses = [ 'mode-status' ]; | ||||||
|  |  | ||||||
|     // TODO: Possibly add popover to it that lists binds |     // TODO: Possibly add popover to it that lists binds | ||||||
|     hypr.connect("submap", (name: string) => { |     hypr.connect( 'submap', ( _, name: submaps ) => { | ||||||
|         label.label = map[name]; |         label.label = map[name]; | ||||||
|         label.cssClasses = ["mode-status", name + '-mode'] |         label.cssClasses = [ | ||||||
|     }) |             'mode-status', | ||||||
|     return  |             name + '-mode' | ||||||
| } |         ]; | ||||||
|  |     } ); | ||||||
|  |  | ||||||
|  |     return label; | ||||||
|  | }; | ||||||
|  |  | ||||||
| const WindowPopoverBox = () => { | const WindowPopoverBox = () => { | ||||||
|     return <box vertical> |     return <box vertical> | ||||||
|         <label label={"Available Windows"} cssClasses={['title-2']}></label> |         <label label={'Available Windows'} cssClasses={[ 'title-2' ]}></label> | ||||||
|         <Gtk.Separator marginTop={5} marginBottom={5}></Gtk.Separator> |         <Gtk.Separator marginTop={5} marginBottom={5}></Gtk.Separator> | ||||||
|         <box vertical> |         <box vertical> | ||||||
|             {bind(hypr, 'clients').as(clients => { |             {bind( hypr, 'clients' ).as( clients => { | ||||||
|                 return clients.map(client => { |                 return clients.map( client => { | ||||||
|                     return <button child={ |                     return <button child={ | ||||||
|                         <box> |                         <box> | ||||||
|                             <label label={bind(client, 'workspace').as(w => `(WS ${w.name})`)}></label> |                             <label label={bind( client, 'workspace' ).as( w => `(WS ${ w.name })` )}></label> | ||||||
|                             <label label={bind(client, 'initialClass').as(c => `[${c}]`)}></label> |                             <label label={bind( client, 'initialClass' ).as( c => `[${ c }]` )}></label> | ||||||
|                             <label label={bind(client, 'title')}></label> |                             <label label={bind( client, 'title' )}></label> | ||||||
|                         </box> |                         </box> | ||||||
|                     } |                     } | ||||||
|                     onClicked={() => client.focus()} |                     onClicked={() => client.focus()} | ||||||
|                     ></button> |                     ></button>; | ||||||
|                 }) |                 } ); | ||||||
|             })} |             } )} | ||||||
|         </box> |         </box> | ||||||
|     </box> |     </box>; | ||||||
| } | }; | ||||||
|  |  | ||||||
| export default { | export default { | ||||||
|     Workspace, |     Workspace, | ||||||
|   | |||||||
| @@ -1,17 +1,24 @@ | |||||||
| import { bind } from "astal"; | import AstalBattery from 'gi://AstalBattery'; | ||||||
| import { execAsync } from "astal"; | import AstalBluetooth from 'gi://AstalBluetooth'; | ||||||
| import AstalBattery from "gi://AstalBattery"; | import AstalNetwork from 'gi://AstalNetwork'; | ||||||
| import AstalBluetooth from "gi://AstalBluetooth"; | import AstalWp from 'gi://AstalWp'; | ||||||
| import AstalNetwork from "gi://AstalNetwork"; | import Brightness from '../../../util/brightness'; | ||||||
| import AstalWp from "gi://AstalWp"; | import { | ||||||
| import { Gtk } from "astal/gtk4"; |     Gtk | ||||||
| import Brightness from "../../../util/brightness"; | } from 'astal/gtk4'; | ||||||
| import QuickActions from "../../QuickActions/QuickActions"; | import QuickActions from '../../QuickActions/QuickActions'; | ||||||
|  | import { | ||||||
|  |     bind | ||||||
|  | } from 'astal'; | ||||||
|  | import { | ||||||
|  |     execAsync | ||||||
|  | } from 'astal'; | ||||||
|  |  | ||||||
| const STATE = AstalNetwork.DeviceState; | const STATE = AstalNetwork.DeviceState; | ||||||
|  |  | ||||||
| const QuickView = () => { | const QuickView = () => { | ||||||
|     const qa = QuickActions.QuickActions(); |     const qa = QuickActions.QuickActions(); | ||||||
|  |  | ||||||
|     const showQuickActions = () => { |     const showQuickActions = () => { | ||||||
|         qa.popup(); |         qa.popup(); | ||||||
|     }; |     }; | ||||||
| @@ -19,14 +26,14 @@ const QuickView = () => { | |||||||
|     return ( |     return ( | ||||||
|         <button |         <button | ||||||
|             onClicked={() => showQuickActions()} |             onClicked={() => showQuickActions()} | ||||||
|             cssClasses={["quick-action-button"]} |             cssClasses={[ 'quick-action-button' ]} | ||||||
|             child={ |             child={ | ||||||
|                 <box> |                 <box> | ||||||
|                     <BatteryWidget></BatteryWidget> |                     <BatteryWidget></BatteryWidget> | ||||||
|                     <Audio></Audio> |                     <Audio></Audio> | ||||||
|                     <BluetoothWidget></BluetoothWidget> |                     <BluetoothWidget></BluetoothWidget> | ||||||
|                     <NetworkWidget></NetworkWidget> |                     <NetworkWidget></NetworkWidget> | ||||||
|                     <image iconName={"system-shutdown-symbolic"}></image> |                     <image iconName={'system-shutdown-symbolic'}></image> | ||||||
|                     {qa} |                     {qa} | ||||||
|                 </box> |                 </box> | ||||||
|             } |             } | ||||||
| @@ -40,37 +47,39 @@ const NetworkWidget = () => { | |||||||
|     return ( |     return ( | ||||||
|         <box> |         <box> | ||||||
|             <image |             <image | ||||||
|                 iconName={bind(network, "state").as(state => { |                 iconName={bind( network, 'state' ).as( state => { | ||||||
|                     if (state === AstalNetwork.State.CONNECTING) { |                     if ( state === AstalNetwork.State.CONNECTING ) { | ||||||
|                         return "chronometer-reset-symbolic"; |                         return 'chronometer-reset-symbolic'; | ||||||
|                     } else if ( |                     } else if ( | ||||||
|                         state === AstalNetwork.State.CONNECTED_LOCAL || |                         state === AstalNetwork.State.CONNECTED_LOCAL | ||||||
|                         state === AstalNetwork.State.CONNECTED_SITE || |                         || state === AstalNetwork.State.CONNECTED_SITE | ||||||
|                         state === AstalNetwork.State.CONNECTED_GLOBAL |                         || state === AstalNetwork.State.CONNECTED_GLOBAL | ||||||
|                     ) { |                     ) { | ||||||
|                         return "network-wired-activated-symbolic"; |                         return 'network-wired-activated-symbolic'; | ||||||
|                     } else { |                     } else { | ||||||
|                         return "paint-unknown-symbolic"; |                         return 'paint-unknown-symbolic'; | ||||||
|                     } |                     } | ||||||
|                 })} |                 } )} | ||||||
|                 cssClasses={["network-widget", "quick-view-symbol"]} |                 cssClasses={[ | ||||||
|                 visible={bind(network.wifi, "state").as( |                     'network-widget', | ||||||
|                     state => state !== STATE.ACTIVATED, |                     'quick-view-symbol' | ||||||
|                 )} |                 ]} | ||||||
|  |                 visible={bind( network.wifi, 'state' ).as( state => state !== STATE.ACTIVATED, )} | ||||||
|             ></image> |             ></image> | ||||||
|             <image |             <image | ||||||
|                 iconName={bind(network.wifi, "state").as(state => { |                 iconName={bind( network.wifi, 'state' ).as( state => { | ||||||
|                     if (state === STATE.ACTIVATED) { |                     if ( state === STATE.ACTIVATED ) { | ||||||
|                         return network.wifi.iconName; |                         return network.wifi.iconName; | ||||||
|                     } else { |                     } else { | ||||||
|                         return ""; |                         return ''; | ||||||
|                     } |                     } | ||||||
|                 })} |                 } )} | ||||||
|                 tooltipText={bind(network.wifi, 'ssid')} |                 tooltipText={bind( network.wifi, 'ssid' )} | ||||||
|                 cssClasses={["network-widget", "quick-view-symbol"]} |                 cssClasses={[ | ||||||
|                 visible={bind(network.wifi, "state").as( |                     'network-widget', | ||||||
|                     state => state === STATE.ACTIVATED, |                     'quick-view-symbol' | ||||||
|                 )} |                 ]} | ||||||
|  |                 visible={bind( network.wifi, 'state' ).as( state => state === STATE.ACTIVATED, )} | ||||||
|             ></image> |             ></image> | ||||||
|         </box> |         </box> | ||||||
|     ); |     ); | ||||||
| @@ -78,44 +87,40 @@ const NetworkWidget = () => { | |||||||
|  |  | ||||||
| const BluetoothWidget = () => { | const BluetoothWidget = () => { | ||||||
|     const bluetooth = AstalBluetooth.get_default(); |     const bluetooth = AstalBluetooth.get_default(); | ||||||
|     const enabled = bind(bluetooth, "isPowered"); |     const enabled = bind( bluetooth, 'isPowered' ); | ||||||
|     const connected = bind(bluetooth, "isConnected"); |     const connected = bind( bluetooth, 'isConnected' ); | ||||||
|  |  | ||||||
|     // For each connected BT device, render status |     // For each connected BT device, render status | ||||||
|     return ( |     return ( | ||||||
|         <box> |         <box> | ||||||
|             <box visible={enabled.as(e => e)}> |             <box visible={enabled.as( e => e )}> | ||||||
|                 <image |                 <image | ||||||
|                     iconName={"bluetooth-active-symbolic"} |                     iconName={'bluetooth-active-symbolic'} | ||||||
|                     visible={connected.as(c => c)} |                     visible={connected.as( c => c )} | ||||||
|                 ></image> |                 ></image> | ||||||
|                 <image |                 <image | ||||||
|                     iconName={"bluetooth-disconnected-symbolic"} |                     iconName={'bluetooth-disconnected-symbolic'} | ||||||
|                     visible={connected.as(c => !c)} |                     visible={connected.as( c => !c )} | ||||||
|                 ></image> |                 ></image> | ||||||
|             </box> |             </box> | ||||||
|             <image |             <image | ||||||
|                 iconName={"bluetooth-disabled-symbolic"} |                 iconName={'bluetooth-disabled-symbolic'} | ||||||
|                 visible={enabled.as(e => !e)} |                 visible={enabled.as( e => !e )} | ||||||
|             ></image> |             ></image> | ||||||
|             <box> |             <box> | ||||||
|                 {bind(bluetooth, "devices").as(devices => { |                 {bind( bluetooth, 'devices' ).as( devices => { | ||||||
|                     return devices.map(device => { |                     return devices.map( device => { | ||||||
|                         return ( |                         return ( | ||||||
|                             <image |                             <image | ||||||
|                                 iconName={bind(device, "icon").as( |                                 iconName={bind( device, 'icon' ).as( icon => icon, )} | ||||||
|                                     icon => icon, |                                 visible={bind( device, 'connected' )} | ||||||
|                                 )} |                                 tooltipText={bind( device, 'batteryPercentage' ).as( n => { | ||||||
|                                 visible={bind(device, "connected")} |                                     return device.get_name() + ': ' + n + '%'; | ||||||
|                                 tooltipText={bind(device, "batteryPercentage").as( |                                 }, )} | ||||||
|                                     n => { |  | ||||||
|                                         return device.get_name() + ': ' + n + "%"; |  | ||||||
|                                     }, |  | ||||||
|                                 )} |  | ||||||
|                             ></image> |                             ></image> | ||||||
|                         ); |                         ); | ||||||
|                     }); |                     } ); | ||||||
|                 })} |                 } )} | ||||||
|             </box> |             </box> | ||||||
|         </box> |         </box> | ||||||
|     ); |     ); | ||||||
| @@ -123,21 +128,25 @@ const BluetoothWidget = () => { | |||||||
|  |  | ||||||
|  |  | ||||||
| let hasSentNotification = false; | let hasSentNotification = false; | ||||||
|  |  | ||||||
| const BatteryWidget = () => { | const BatteryWidget = () => { | ||||||
|     const battery = AstalBattery.get_default(); |     const battery = AstalBattery.get_default(); | ||||||
|     if (battery.get_is_present()) { |  | ||||||
|  |     if ( battery.get_is_present() ) { | ||||||
|         return ( |         return ( | ||||||
|             <image |             <image | ||||||
|                 iconName={bind(battery, "batteryIconName").as(icon => icon)} |                 iconName={bind( battery, 'batteryIconName' ).as( icon => icon )} | ||||||
|                 cssClasses={["quick-view-symbol"]} |                 cssClasses={[ 'quick-view-symbol' ]} | ||||||
|                 tooltipText={bind(battery, 'percentage').as(p => { |                 tooltipText={bind( battery, 'percentage' ).as( p => { | ||||||
|                     const level = Math.round(p * 100) |                     const level = Math.round( p * 100 ); | ||||||
|  |  | ||||||
|                     if ( level < 20 && !hasSentNotification ) { |                     if ( level < 20 && !hasSentNotification ) { | ||||||
|                         hasSentNotification = true; |                         hasSentNotification = true; | ||||||
|                         execAsync( 'bash -c "notify-send \'Battery level below 20%\'"' ); |                         execAsync( 'bash -c "notify-send \'Battery level below 20%\'"' ); | ||||||
|                     } |                     } | ||||||
|                     return `Battery Level: ${level}%` |  | ||||||
|                 })} |                     return `Battery Level: ${ level }%`; | ||||||
|  |                 } )} | ||||||
|             ></image> |             ></image> | ||||||
|         ); |         ); | ||||||
|     } else { |     } else { | ||||||
| @@ -148,14 +157,14 @@ const BatteryWidget = () => { | |||||||
|  |  | ||||||
| const BrightnessWidget = () => { | const BrightnessWidget = () => { | ||||||
|     const brightness = Brightness.get_default(); |     const brightness = Brightness.get_default(); | ||||||
|     const screen_brightness = bind(brightness, "screen"); |     const screen_brightness = bind( brightness, 'screen' ); | ||||||
|  |  | ||||||
|     return ( |     return ( | ||||||
|         <box cssClasses={["quick-view-symbol"]}> |         <box cssClasses={[ 'quick-view-symbol' ]}> | ||||||
|             <image iconName={"brightness-high-symbolic"}></image> |             <image iconName={'brightness-high-symbolic'}></image> | ||||||
|             <label |             <label | ||||||
|                 label={screen_brightness.as(b => '' + Math.round(100 * b))} |                 label={screen_brightness.as( b => '' + Math.round( 100 * b ) )} | ||||||
|                 visible={bind(brightness, "screenAvailable")} |                 visible={bind( brightness, 'screenAvailable' )} | ||||||
|             ></label> |             ></label> | ||||||
|         </box> |         </box> | ||||||
|     ); |     ); | ||||||
| @@ -163,31 +172,27 @@ const BrightnessWidget = () => { | |||||||
|  |  | ||||||
| const Audio = () => { | const Audio = () => { | ||||||
|     const wireplumber = AstalWp.get_default(); |     const wireplumber = AstalWp.get_default(); | ||||||
|     if (wireplumber) { |  | ||||||
|  |     if ( wireplumber ) { | ||||||
|         return ( |         return ( | ||||||
|             <box orientation={Gtk.Orientation.HORIZONTAL}> |             <box orientation={Gtk.Orientation.HORIZONTAL}> | ||||||
|                 <image |                 <image | ||||||
|                     iconName={bind(wireplumber.defaultSpeaker, "volumeIcon").as( |                     iconName={bind( wireplumber.defaultSpeaker, 'volumeIcon' ).as( icon => icon, )} | ||||||
|                         icon => icon, |                     cssClasses={[ 'quick-view-symbol' ]} | ||||||
|                     )} |                     tooltipText={bind( wireplumber.defaultSpeaker, 'volume' ).as( v => Math.round( 100 * v ) + '%' )} | ||||||
|                     cssClasses={["quick-view-symbol"]} |  | ||||||
|                     tooltipText={bind(wireplumber.defaultSpeaker, 'volume').as(v => Math.round(100 * v) + '%')} |  | ||||||
|                 ></image> |                 ></image> | ||||||
|                 <image |                 <image | ||||||
|                     iconName={bind( |                     iconName={bind( wireplumber.defaultMicrophone, | ||||||
|                         wireplumber.defaultMicrophone, |                         'volumeIcon', ).as( icon => icon )} | ||||||
|                         "volumeIcon", |                     cssClasses={[ 'quick-view-symbol' ]} | ||||||
|                     ).as(icon => icon)} |                     tooltipText={bind( wireplumber.defaultMicrophone, 'volume' ).as( v => Math.round( 100 * v ) + '%' )} | ||||||
|                     cssClasses={["quick-view-symbol"]} |  | ||||||
|                     tooltipText={bind(wireplumber.defaultMicrophone, 'volume').as(v => Math.round(100 * v) + '%')} |  | ||||||
|                 ></image> |                 ></image> | ||||||
|             </box> |             </box> | ||||||
|         ); |         ); | ||||||
|     } else { |     } else { | ||||||
|         print( |         print( '[ WirePlumber ] Could not connect, Audio support in bar will be missing', ); | ||||||
|             "[ WirePlumber ] Could not connect, Audio support in bar will be missing", |  | ||||||
|         ); |         return <image iconName={'action-unavailable-symbolic'}></image>; | ||||||
|         return <image iconName={"action-unavailable-symbolic"}></image>; |  | ||||||
|     } |     } | ||||||
| }; | }; | ||||||
|  |  | ||||||
| @@ -195,4 +200,5 @@ const Audio = () => { | |||||||
|  |  | ||||||
| export default { | export default { | ||||||
|     QuickView, |     QuickView, | ||||||
|  |     BrightnessWidget | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -1,35 +1,39 @@ | |||||||
| import { execAsync } from "astal"; | import { | ||||||
| import { Gtk } from "astal/gtk4"; |     Gtk | ||||||
| import sysinfo from "../sysinfo"; | } from 'astal/gtk4'; | ||||||
|  | import { | ||||||
|  |     execAsync | ||||||
|  | } from 'astal'; | ||||||
|  | import sysinfo from '../sysinfo'; | ||||||
|  |  | ||||||
| const info = () => { | const info = () => { | ||||||
|     return ( |     return ( | ||||||
|         <box vertical> |         <box vertical> | ||||||
|             <label |             <label | ||||||
|                 label={"System Information"} |                 label={'System Information'} | ||||||
|                 cssClasses={["title-2"]} |                 cssClasses={[ 'title-2' ]} | ||||||
|             ></label> |             ></label> | ||||||
|             <Gtk.Separator marginTop={5} marginBottom={10}></Gtk.Separator> |             <Gtk.Separator marginTop={5} marginBottom={10}></Gtk.Separator> | ||||||
|             <label |             <label | ||||||
|                 vexpand |                 vexpand | ||||||
|                 halign={Gtk.Align.START} |                 halign={Gtk.Align.START} | ||||||
|                 hexpand |                 hexpand | ||||||
|                 label={sysinfo.ramUsed(used => { |                 label={sysinfo.ramUsed( used => { | ||||||
|                     return "RAM: " + used + ` (${sysinfo.ramUtil.get()}%)`; |                     return 'RAM: ' + used + ` (${ sysinfo.ramUtil.get() }%)`; | ||||||
|                 })} |                 } )} | ||||||
|             ></label> |             ></label> | ||||||
|             <label |             <label | ||||||
|                 label={sysinfo.systemStats(stats => { |                 label={sysinfo.systemStats( stats => { | ||||||
|                     return `CPU: ${stats.cpuTemp}, ${stats.cpuClk} |                     return `CPU: ${ stats.cpuTemp }, ${ stats.cpuClk } | ||||||
| GPU: ${stats.gpuTemp}, ${stats.gpuClk} (${stats.vram} / ${stats.availableVRAM}) | GPU: ${ stats.gpuTemp }, ${ stats.gpuClk } (${ stats.vram } / ${ stats.availableVRAM }) | ||||||
| Kernel: ${stats.kernel}`; | Kernel: ${ stats.kernel }`; | ||||||
|                 })} |                 } )} | ||||||
|             ></label> |             ></label> | ||||||
|             <Gtk.Separator marginTop={10}></Gtk.Separator> |             <Gtk.Separator marginTop={10}></Gtk.Separator> | ||||||
|             <button |             <button | ||||||
|                 onClicked={() => execAsync(`/bin/sh -c "kitty --hold fish -c 'fastfetch'"`)} |                 onClicked={() => execAsync( '/bin/sh -c "kitty --hold fish -c \'fastfetch\'"' )} | ||||||
|                 child={ |                 child={ | ||||||
|                     <label label={"View FastFetch"}></label> |                     <label label={'View FastFetch'}></label> | ||||||
|                 }></button> |                 }></button> | ||||||
|         </box> |         </box> | ||||||
|     ); |     ); | ||||||
| @@ -38,7 +42,7 @@ Kernel: ${stats.kernel}`; | |||||||
| const SystemInformationPanel = () => { | const SystemInformationPanel = () => { | ||||||
|     const popover = new Gtk.Popover(); |     const popover = new Gtk.Popover(); | ||||||
|  |  | ||||||
|     popover.set_child(info()); |     popover.set_child( info() ); | ||||||
|  |  | ||||||
|     return popover; |     return popover; | ||||||
| }; | }; | ||||||
| @@ -54,44 +58,44 @@ const SystemInfo = () => { | |||||||
|         sysinfo.refreshStats(); |         sysinfo.refreshStats(); | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     if (sysinfo.enabled) { |     if ( sysinfo.enabled ) { | ||||||
|         return ( |         return ( | ||||||
|             <button |             <button | ||||||
|                 onClicked={() => openSysInfo()} |                 onClicked={() => openSysInfo()} | ||||||
|                 child={ |                 child={ | ||||||
|                     <box tooltipText={sysinfo.ramUsed(v => v)}> |                     <box tooltipText={sysinfo.ramUsed( v => v )}> | ||||||
|                         <box |                         <box | ||||||
|                             cssClasses={[ 'quick-view-symbol' ]} |                             cssClasses={[ 'quick-view-symbol' ]} | ||||||
|                         > |                         > | ||||||
|                             <image |                             <image | ||||||
|                                 iconName={"power-profile-performance-symbolic"} |                                 iconName={'power-profile-performance-symbolic'} | ||||||
|                                 marginEnd={1} |                                 marginEnd={1} | ||||||
|                             ></image> |                             ></image> | ||||||
|                             <label |                             <label | ||||||
|                                 label={sysinfo.cpuUtil(util => util)} |                                 label={sysinfo.cpuUtil( util => util )} | ||||||
|                                 marginEnd={5} |                                 marginEnd={5} | ||||||
|                             ></label> |                             ></label> | ||||||
|                         </box> |                         </box> | ||||||
|                         <box |                         <box | ||||||
|                             cssClasses={[ 'quick-view-symbol' ]} |                             cssClasses={[ 'quick-view-symbol' ]} | ||||||
|                         > |                         > | ||||||
|                             <image iconName={"memory"}></image> |                             <image iconName={'memory'}></image> | ||||||
|                             <label label={sysinfo.ramUtil(util => util)}></label> |                             <label label={sysinfo.ramUtil( util => util )}></label> | ||||||
|                         </box> |                         </box> | ||||||
|                         <box |                         <box | ||||||
|                             cssClasses={[ 'quick-view-symbol' ]} |                             cssClasses={[ 'quick-view-symbol' ]} | ||||||
|                         > |                         > | ||||||
|                             <image iconName={"show-gpu-effects-symbolic"}></image> |                             <image iconName={'show-gpu-effects-symbolic'}></image> | ||||||
|                             <label label={sysinfo.gpuUtil(util => util)}></label> |                             <label label={sysinfo.gpuUtil( util => util )}></label> | ||||||
|                         </box> |                         </box> | ||||||
|                         {panel} |                         {panel} | ||||||
|                     </box> |                     </box> | ||||||
|                 } |                 } | ||||||
|                 cssClasses={["bar-button"]} |                 cssClasses={[ 'bar-button' ]} | ||||||
|             ></button> |             ></button> | ||||||
|         ); |         ); | ||||||
|     } else { |     } else { | ||||||
|         return <image iconName={"action-unavailable-symbolic"}></image>; |         return <image iconName={'action-unavailable-symbolic'}></image>; | ||||||
|     } |     } | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -3,3 +3,4 @@ $bg-color: #0A0A0F; | |||||||
| $accent-color: #591641; | $accent-color: #591641; | ||||||
| $accent-color-2: #97103A; | $accent-color-2: #97103A; | ||||||
| $shadow-color: rgba(0, 0, 2, 0.3); | $shadow-color: rgba(0, 0, 2, 0.3); | ||||||
|  | $monospace-font: Source Code Pro | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user