From 531543bb462be5793df2117ad96116e148119eac Mon Sep 17 00:00:00 2001 From: matt1432 Date: Thu, 9 Nov 2023 02:19:18 -0500 Subject: [PATCH] feat(quicksett): start working on menus for buttons --- .../ags/js/quick-settings/button-grid.js | 330 +++++++++++------- .../wim/config/ags/js/quick-settings/main.js | 5 +- .../ags/scss/widgets/quick-settings.scss | 54 +-- 3 files changed, 237 insertions(+), 152 deletions(-) diff --git a/devices/wim/config/ags/js/quick-settings/button-grid.js b/devices/wim/config/ags/js/quick-settings/button-grid.js index 077e67b..b4170b5 100644 --- a/devices/wim/config/ags/js/quick-settings/button-grid.js +++ b/devices/wim/config/ags/js/quick-settings/button-grid.js @@ -2,43 +2,149 @@ import App from 'resource:///com/github/Aylur/ags/app.js'; import Audio from 'resource:///com/github/Aylur/ags/service/audio.js'; import Bluetooth from 'resource:///com/github/Aylur/ags/service/bluetooth.js'; import Network from 'resource:///com/github/Aylur/ags/service/network.js'; -import { Box, CenterBox, Label, Icon } from 'resource:///com/github/Aylur/ags/widget.js'; +import Variable from 'resource:///com/github/Aylur/ags/variable.js'; +import { Box, Icon, Label, Revealer } from 'resource:///com/github/Aylur/ags/widget.js'; import { execAsync } from 'resource:///com/github/Aylur/ags/utils.js'; -import EventBox from '../misc/cursorbox.js'; +import EventBox from '../misc/cursorbox.js'; +import Separator from '../misc/separator.js'; +const ButtonStates = []; const GridButton = ({ command = () => {}, secondaryCommand = () => {}, icon, -} = {}) => Box({ - className: 'grid-button', - children: [ + indicator, + menu, +} = {}) => { + const Activated = Variable(false); + ButtonStates.push(Activated); - EventBox({ - className: 'left-part', - onPrimaryClickRelease: () => command(), - child: icon, - }), + // allow setting icon dynamically or statically + if (typeof icon === 'string') { + icon = Icon({ + className: 'grid-label', + icon: icon, + connections: [[Activated, self => { + self.setCss(`color: ${Activated.value ? 'rgba(189, 147, 249, 0.8)' : 'unset'};`); + }]], + }); + } + else { + icon = Icon({ + className: 'grid-label', + connections: [ + icon, + [Activated, self => { + self.setCss(`color: ${Activated.value ? 'rgba(189, 147, 249, 0.8)' : 'unset'};`); + }], + ], + }); + } - EventBox({ - className: 'right-part', - onPrimaryClickRelease: () => secondaryCommand(), - child: Label({ - label: ' ', - className: 'grid-chev', + if (indicator) { + indicator = Label({ + className: 'sub-label', + justification: 'left', + truncate: 'end', + maxWidthChars: 12, + connections: [indicator], + }); + } + + if (menu) { + menu = Revealer({ + transition: 'slide_down', + child: menu, + binds: [['revealChild', Activated, 'value']], + }); + } + + const widget = Box({ + vertical: true, + children: [ + Box({ + className: 'grid-button', + children: [ + + EventBox({ + className: 'left-part', + onPrimaryClickRelease: () => { + if (!Activated.value) + command(); + else + secondaryCommand(); + }, + child: icon, + }), + + EventBox({ + className: 'right-part', + onPrimaryClickRelease: () => { + ButtonStates.forEach(state => { + if (state !== Activated) + state.value = false; + }); + Activated.value = !Activated.value; + }, + onHover: self => { + if (menu) { + const rowMenu = self.get_parent().get_parent() + .get_parent().get_parent().children[1]; + + if (!rowMenu.get_children().find(ch => ch === menu)) { + rowMenu.add(menu); + rowMenu.show_all(); + } + } + }, + child: Icon({ + icon: App.configDir + '/icons/down-large.svg', + connections: [[Activated, self => { + let deg = 270; + if (Activated.value) + deg = menu ? 360 : 450; + self.setCss(`-gtk-icon-transform: rotate(${deg}deg);`); + }]], + className: 'grid-chev', + }), + }), + + ], }), - }), + indicator, + ], + }); + return widget; +}; - ], -}); +const Row = ({ buttons } = {}) => { + const widget = Box({ + vertical: true, + children: [ + Box({ + className: 'button-row', + hpack: 'center', + }), + Box(), + ], + }); -const FirstRow = () => Box({ - className: 'button-row', - hpack: 'center', - css: 'margin-top: 15px; margin-bottom: 7px;', - children: [ + for (let i = 0; i < buttons.length; ++i) { + if (i !== buttons.length - 1) { + widget.children[0].add(buttons[i]); + widget.children[0].add(Separator(28)); + } + else { + widget.children[0].add(buttons[i]); + } + } + return widget; +}; + +const FirstRow = () => Row({ + buttons: [ GridButton({ command: () => Network.toggleWifi(), @@ -46,15 +152,29 @@ const FirstRow = () => Box({ execAsync(['bash', '-c', 'nm-connection-editor']) .catch(print); }, - icon: Icon({ - className: 'grid-label', - connections: [[Network, icon => { - if (Network.wifi.enabled) - icon.icon = 'network-wireless-connected-symbolic'; + icon: [Network, icon => icon.icon = Network.wifi?.iconName], + indicator: [Network, self => self.label = Network.wifi?.ssid || Network.wired?.internet], - else - icon.icon = 'network-wireless-offline-symbolic'; - }, 'changed']], + menu: Box({ + className: 'menu', + vertical: true, + connections: [[Network, box => box.children = + Network.wifi?.access_points.map(ap => EventBox({ + isButton: true, + on_clicked: () => execAsync(`nmcli device wifi connect ${ap.bssid}`).catch(print), + child: Box({ + children: [ + Icon(ap.iconName), + Label(ap.ssid || ''), + ap.active && Icon({ + icon: 'object-select-symbolic', + hexpand: true, + hpack: 'end', + }), + ], + }), + })), + ]], }), }), @@ -67,23 +187,27 @@ const FirstRow = () => Box({ execAsync(['bash', '-c', 'blueberry']) .catch(print); }, - icon: Icon({ - className: 'grid-label', - connections: [[Bluetooth, self => { - if (Bluetooth.enabled) { - self.icon = 'bluetooth-active-symbolic'; - execAsync(['bash', '-c', 'echo 󰂯 > $HOME/.config/.bluetooth']) - .catch(print); - } - else { - self.icon = 'bluetooth-disabled-symbolic'; - execAsync(['bash', '-c', 'echo 󰂲 > $HOME/.config/.bluetooth']) - .catch(print); - } - }, 'changed']], - }), + icon: [Bluetooth, self => { + if (Bluetooth.enabled) { + self.icon = 'bluetooth-active-symbolic'; + execAsync(['bash', '-c', 'echo 󰂯 > $HOME/.config/.bluetooth']) + .catch(print); + } + else { + self.icon = 'bluetooth-disabled-symbolic'; + execAsync(['bash', '-c', 'echo 󰂲 > $HOME/.config/.bluetooth']) + .catch(print); + } + }, 'changed'], + indicator: [Bluetooth, self => { + if (Bluetooth.connectedDevices[0]) + self.label = String(Bluetooth.connectedDevices[0]); + else + self.label = 'Disconnected'; + }, 'changed'], }), + // TODO: replace with vpn GridButton({ command: () => { execAsync(['bash', '-c', '$AGS_PATH/qs-toggles.sh toggle-radio']) @@ -93,48 +217,14 @@ const FirstRow = () => Box({ execAsync(['notify-send', 'set this up moron']) .catch(print); }, - icon: Icon({ - className: 'grid-label', - connections: [[Network, self => { - if (Network.wifi.enabled) - self.icon = 'airplane-mode-disabled-symbolic'; - else - self.icon = 'airplane-mode-symbolic'; - }, 'changed']], - }), - }), - - ], -}); - -const SubRow = () => CenterBox({ - hpack: 'start', - children: [ - - Label({ - className: 'sub-label', - truncate: 'end', - maxWidthChars: 12, - connections: [[Network, self => { - // TODO: handle ethernet too - self.label = Network.wifi.ssid; - }, 'changed']], - }), - - Label({ - className: 'sub-label', - truncate: 'end', - maxWidthChars: 12, - connections: [[Bluetooth, self => { - if (Bluetooth.connectedDevices[0]) - self.label = String(Bluetooth.connectedDevices[0]); + icon: [Network, self => { + if (Network.wifi.enabled) + self.icon = 'airplane-mode-disabled-symbolic'; else - self.label = 'Disconnected'; - }, 'changed']], + self.icon = 'airplane-mode-symbolic'; + }, 'changed'], }), - null, - ], }); @@ -152,11 +242,8 @@ const itemsMic = { 0: 'audio-input-microphone-muted-symbolic', }; -const SecondRow = () => Box({ - className: 'button-row', - hpack: 'center', - css: 'margin-top: 7px; margin-bottom: 15px;', - children: [ +const SecondRow = () => Row({ + buttons: [ GridButton({ command: () => { @@ -169,23 +256,20 @@ const SecondRow = () => Box({ .catch(print); }, - icon: Icon({ - className: 'grid-label', - connections: [[Audio, icon => { - if (Audio.speaker) { - if (Audio.speaker.stream.isMuted) { - icon.icon = items[0]; - } - else { - const vol = Audio.speaker.volume * 100; - for (const threshold of [-1, 0, 33, 66, 100]) { - if (vol > threshold + 1) - icon.icon = items[threshold + 1]; - } + icon: [Audio, icon => { + if (Audio.speaker) { + if (Audio.speaker.stream.isMuted) { + icon.icon = items[0]; + } + else { + const vol = Audio.speaker.volume * 100; + for (const threshold of [-1, 0, 33, 66, 100]) { + if (vol > threshold + 1) + icon.icon = items[threshold + 1]; } } - }, 'speaker-changed']], - }), + } + }, 'speaker-changed'], }), GridButton({ @@ -199,23 +283,20 @@ const SecondRow = () => Box({ .catch(print); }, - icon: Icon({ - className: 'grid-label', - connections: [[Audio, icon => { - if (Audio.microphone) { - if (Audio.microphone.stream.isMuted) { - icon.icon = itemsMic[0]; - } - else { - const vol = Audio.microphone.volume * 100; - for (const threshold of [-1, 0, 1]) { - if (vol > threshold + 1) - icon.icon = itemsMic[threshold + 1]; - } + icon: [Audio, icon => { + if (Audio.microphone) { + if (Audio.microphone.stream.isMuted) { + icon.icon = itemsMic[0]; + } + else { + const vol = Audio.microphone.volume * 100; + for (const threshold of [-1, 0, 1]) { + if (vol > threshold + 1) + icon.icon = itemsMic[threshold + 1]; } } - }, 'microphone-changed']], - }), + } + }, 'microphone-changed'], }), GridButton({ @@ -224,10 +305,7 @@ const SecondRow = () => Box({ .catch(print); }, secondaryCommand: () => App.openWindow('powermenu'), - icon: Label({ - className: 'grid-label', - label: ' 󰌾 ', - }), + icon: 'system-lock-screen-symbolic', }), ], @@ -239,7 +317,7 @@ export default () => Box({ hpack: 'center', children: [ FirstRow(), - SubRow(), + Separator(10, { vertical: true }), SecondRow(), ], }); diff --git a/devices/wim/config/ags/js/quick-settings/main.js b/devices/wim/config/ags/js/quick-settings/main.js index a192723..bb6f688 100644 --- a/devices/wim/config/ags/js/quick-settings/main.js +++ b/devices/wim/config/ags/js/quick-settings/main.js @@ -21,7 +21,10 @@ const QuickSettingsWidget = () => Box({ label: 'Control Center', className: 'title', hpack: 'start', - css: 'margin-left: 20px', + css: ` + margin-left: 20px; + margin-bottom: 30px; + `, }), ButtonGrid(), diff --git a/devices/wim/config/ags/scss/widgets/quick-settings.scss b/devices/wim/config/ags/scss/widgets/quick-settings.scss index 20679f4..83757d7 100644 --- a/devices/wim/config/ags/scss/widgets/quick-settings.scss +++ b/devices/wim/config/ags/scss/widgets/quick-settings.scss @@ -17,57 +17,61 @@ margin-left: 15px; margin-right: 10px; min-width: 50px; + transition: color 0.3s ease-in-out; +} + +.menu { + margin: 10px; + padding: 5px; + border: 1.5px solid $contrast-bg; + border-radius: 10px; + font-size: 12px; + + button { + margin: 5px; + + label { + font-size: 16px; + margin-left: 5px; + } + + image { + font-size: 20px; + } + } } .sub-label { font-size: 14px; - margin-top: -10px; - margin-left: 31px; - - &:nth-child(1) { - margin-left: 25px; - } - margin-bottom: 10px; padding: 3px; border: 2px solid $contrast-bg; border-radius: 10px 20px 20px 10px; min-width: 106px; background: #1b1b1b; + margin-top: 5px; } .grid-chev { - margin-left: 0; + margin-left: 10px; + margin-right: 12px; + font-size: 25px; - font-size: 40px; - margin-right: 5px; + transition: -gtk-icon-transform 0.3s ease-in-out; } .button-grid { font-size: 10px; - min-height: 160px; - min-width: 470px; + min-width: 440px; background-color: $bgfull; border-top: 2px solid $contrast-bg; border-bottom: 2px solid $contrast-bg; border-radius: 15px; - margin-top: 30px; -} - -.button-row { - min-height: 70px; - min-width: 450px; - margin-left: 20px; + padding: 10px 15px; } .grid-button { min-height: 65px; min-width: 70px; - margin: 5px; - margin-left: 22px; - - &:nth-child(1) { - margin-left: 5px; - } } .left-part {