205 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			205 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| import AstalBattery from 'gi://AstalBattery';
 | |
| import AstalBluetooth from 'gi://AstalBluetooth';
 | |
| import AstalNetwork from 'gi://AstalNetwork';
 | |
| import AstalWp from 'gi://AstalWp';
 | |
| import Brightness from '../../../util/brightness';
 | |
| import {
 | |
|     Gtk
 | |
| } from 'astal/gtk4';
 | |
| import QuickActions from '../../QuickActions/QuickActions';
 | |
| import {
 | |
|     bind
 | |
| } from 'astal';
 | |
| import {
 | |
|     execAsync
 | |
| } from 'astal';
 | |
| 
 | |
| 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,
 | |
|     BrightnessWidget
 | |
| };
 |