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
|
|
};
|