199 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			199 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| import { bind } from "astal";
 | |
| import { execAsync } from "astal";
 | |
| import AstalBattery from "gi://AstalBattery";
 | |
| import AstalBluetooth from "gi://AstalBluetooth";
 | |
| import AstalNetwork from "gi://AstalNetwork";
 | |
| import AstalWp from "gi://AstalWp";
 | |
| import { Gtk } from "astal/gtk4";
 | |
| import Brightness from "../../../util/brightness";
 | |
| import QuickActions from "../../QuickActions/QuickActions";
 | |
| 
 | |
| const STATE = AstalNetwork.DeviceState;
 | |
| 
 | |
| const QuickView = () => {
 | |
|     const qa = QuickActions.QuickActions();
 | |
|     const showQuickActions = () => {
 | |
|         qa.popup();
 | |
|     };
 | |
| 
 | |
|     return (
 | |
|         <button
 | |
|             onClicked={() => showQuickActions()}
 | |
|             cssClasses={["quick-action-button"]}
 | |
|             child={
 | |
|                 <box>
 | |
|                     <BatteryWidget></BatteryWidget>
 | |
|                     <Audio></Audio>
 | |
|                     <BluetoothWidget></BluetoothWidget>
 | |
|                     <NetworkWidget></NetworkWidget>
 | |
|                     <image iconName={"system-shutdown-symbolic"}></image>
 | |
|                     {qa}
 | |
|                 </box>
 | |
|             }
 | |
|         ></button>
 | |
|     );
 | |
| };
 | |
| 
 | |
| const NetworkWidget = () => {
 | |
|     const network = AstalNetwork.get_default();
 | |
| 
 | |
|     return (
 | |
|         <box>
 | |
|             <image
 | |
|                 iconName={bind(network, "state").as(state => {
 | |
|                     if (state === AstalNetwork.State.CONNECTING) {
 | |
|                         return "chronometer-reset-symbolic";
 | |
|                     } else if (
 | |
|                         state === AstalNetwork.State.CONNECTED_LOCAL ||
 | |
|                         state === AstalNetwork.State.CONNECTED_SITE ||
 | |
|                         state === AstalNetwork.State.CONNECTED_GLOBAL
 | |
|                     ) {
 | |
|                         return "network-wired-activated-symbolic";
 | |
|                     } else {
 | |
|                         return "paint-unknown-symbolic";
 | |
|                     }
 | |
|                 })}
 | |
|                 cssClasses={["network-widget", "quick-view-symbol"]}
 | |
|                 visible={bind(network.wifi, "state").as(
 | |
|                     state => state !== STATE.ACTIVATED,
 | |
|                 )}
 | |
|             ></image>
 | |
|             <image
 | |
|                 iconName={bind(network.wifi, "state").as(state => {
 | |
|                     if (state === STATE.ACTIVATED) {
 | |
|                         return network.wifi.iconName;
 | |
|                     } else {
 | |
|                         return "";
 | |
|                     }
 | |
|                 })}
 | |
|                 tooltipText={bind(network.wifi, 'ssid')}
 | |
|                 cssClasses={["network-widget", "quick-view-symbol"]}
 | |
|                 visible={bind(network.wifi, "state").as(
 | |
|                     state => state === STATE.ACTIVATED,
 | |
|                 )}
 | |
|             ></image>
 | |
|         </box>
 | |
|     );
 | |
| };
 | |
| 
 | |
| const BluetoothWidget = () => {
 | |
|     const bluetooth = AstalBluetooth.get_default();
 | |
|     const enabled = bind(bluetooth, "isPowered");
 | |
|     const connected = bind(bluetooth, "isConnected");
 | |
| 
 | |
|     // For each connected BT device, render status
 | |
|     return (
 | |
|         <box>
 | |
|             <box visible={enabled.as(e => e)}>
 | |
|                 <image
 | |
|                     iconName={"bluetooth-active-symbolic"}
 | |
|                     visible={connected.as(c => c)}
 | |
|                 ></image>
 | |
|                 <image
 | |
|                     iconName={"bluetooth-disconnected-symbolic"}
 | |
|                     visible={connected.as(c => !c)}
 | |
|                 ></image>
 | |
|             </box>
 | |
|             <image
 | |
|                 iconName={"bluetooth-disabled-symbolic"}
 | |
|                 visible={enabled.as(e => !e)}
 | |
|             ></image>
 | |
|             <box>
 | |
|                 {bind(bluetooth, "devices").as(devices => {
 | |
|                     return devices.map(device => {
 | |
|                         return (
 | |
|                             <image
 | |
|                                 iconName={bind(device, "icon").as(
 | |
|                                     icon => icon,
 | |
|                                 )}
 | |
|                                 visible={bind(device, "connected")}
 | |
|                                 tooltipText={bind(device, "batteryPercentage").as(
 | |
|                                     n => {
 | |
|                                         return device.get_name() + ': ' + n + "%";
 | |
|                                     },
 | |
|                                 )}
 | |
|                             ></image>
 | |
|                         );
 | |
|                     });
 | |
|                 })}
 | |
|             </box>
 | |
|         </box>
 | |
|     );
 | |
| };
 | |
| 
 | |
| 
 | |
| let hasSentNotification = false;
 | |
| const BatteryWidget = () => {
 | |
|     const battery = AstalBattery.get_default();
 | |
|     if (battery.get_is_present()) {
 | |
|         return (
 | |
|             <image
 | |
|                 iconName={bind(battery, "batteryIconName").as(icon => icon)}
 | |
|                 cssClasses={["quick-view-symbol"]}
 | |
|                 tooltipText={bind(battery, 'percentage').as(p => {
 | |
|                     const level = Math.round(p * 100)
 | |
|                     if ( level < 20 && !hasSentNotification ) {
 | |
|                         hasSentNotification = true;
 | |
|                         execAsync( 'bash -c "notify-send \'Battery level below 20%\'"' );
 | |
|                     }
 | |
|                     return `Battery Level: ${level}%`
 | |
|                 })}
 | |
|             ></image>
 | |
|         );
 | |
|     } else {
 | |
|         return <box></box>;
 | |
|     }
 | |
|     // Else, no battery available -> Don't show the widget
 | |
| };
 | |
| 
 | |
| const BrightnessWidget = () => {
 | |
|     const brightness = Brightness.get_default();
 | |
|     const screen_brightness = bind(brightness, "screen");
 | |
| 
 | |
|     return (
 | |
|         <box cssClasses={["quick-view-symbol"]}>
 | |
|             <image iconName={"brightness-high-symbolic"}></image>
 | |
|             <label
 | |
|                 label={screen_brightness.as(b => '' + Math.round(100 * b))}
 | |
|                 visible={bind(brightness, "screenAvailable")}
 | |
|             ></label>
 | |
|         </box>
 | |
|     );
 | |
| };
 | |
| 
 | |
| const Audio = () => {
 | |
|     const wireplumber = AstalWp.get_default();
 | |
|     if (wireplumber) {
 | |
|         return (
 | |
|             <box orientation={Gtk.Orientation.HORIZONTAL}>
 | |
|                 <image
 | |
|                     iconName={bind(wireplumber.defaultSpeaker, "volumeIcon").as(
 | |
|                         icon => icon,
 | |
|                     )}
 | |
|                     cssClasses={["quick-view-symbol"]}
 | |
|                     tooltipText={bind(wireplumber.defaultSpeaker, 'volume').as(v => Math.round(100 * v) + '%')}
 | |
|                 ></image>
 | |
|                 <image
 | |
|                     iconName={bind(
 | |
|                         wireplumber.defaultMicrophone,
 | |
|                         "volumeIcon",
 | |
|                     ).as(icon => icon)}
 | |
|                     cssClasses={["quick-view-symbol"]}
 | |
|                     tooltipText={bind(wireplumber.defaultMicrophone, 'volume').as(v => Math.round(100 * v) + '%')}
 | |
|                 ></image>
 | |
|             </box>
 | |
|         );
 | |
|     } else {
 | |
|         print(
 | |
|             "[ WirePlumber ] Could not connect, Audio support in bar will be missing",
 | |
|         );
 | |
|         return <image iconName={"action-unavailable-symbolic"}></image>;
 | |
|     }
 | |
| };
 | |
| 
 | |
| // cssClasses={[ 'quick-view-symbol' ]}
 | |
| 
 | |
| export default {
 | |
|     QuickView,
 | |
| };
 |