From 22a17e14db93668580acc32116f80a08c8a933e1 Mon Sep 17 00:00:00 2001 From: retrozinndev Date: Wed, 30 Jul 2025 17:54:44 -0300 Subject: [PATCH] :boom: fix(control-center/page, control-center/pages): scope errors i basically restructured the page widget lol --- ags/widget/control-center/Pages.tsx | 59 +++-- ags/widget/control-center/QuickActions.tsx | 31 +-- ags/widget/control-center/Sliders.tsx | 48 ++-- ags/widget/control-center/Tiles.tsx | 12 +- ags/widget/control-center/pages/Bluetooth.tsx | 102 ++++---- .../control-center/pages/Microphone.tsx | 45 ++-- ags/widget/control-center/pages/Network.tsx | 50 ++-- .../control-center/pages/NightLight.tsx | 19 +- ags/widget/control-center/pages/Page.tsx | 221 +++++++++--------- ags/widget/control-center/pages/Sound.tsx | 155 ++++++------ ags/widget/control-center/tiles/Bluetooth.tsx | 2 +- ags/widget/control-center/tiles/Network.tsx | 6 +- .../control-center/tiles/NightLight.tsx | 2 +- ags/widget/control-center/tiles/Recording.tsx | 1 - ags/widget/control-center/tiles/Tile.tsx | 7 +- 15 files changed, 378 insertions(+), 382 deletions(-) diff --git a/ags/widget/control-center/Pages.tsx b/ags/widget/control-center/Pages.tsx index cf1a970..7bdb7ec 100644 --- a/ags/widget/control-center/Pages.tsx +++ b/ags/widget/control-center/Pages.tsx @@ -2,16 +2,13 @@ import { register } from "ags/gobject"; import { Gtk } from "ags/gtk4"; import { Page } from "./pages/Page"; import { timeout } from "ags/time"; -import { variableToBoolean } from "../../scripts/utils"; import AstalIO from "gi://AstalIO"; -import { createRoot } from "ags"; export { Pages }; export type PagesProps = { initialPage?: Page; - class?: string; transitionDuration?: number; }; @@ -19,21 +16,20 @@ export type PagesProps = { class Pages extends Gtk.Box { #timeouts: Array<[AstalIO.Time, (() => void)|undefined]> = []; #page: (Page|undefined); - #pageWidget: (Gtk.Revealer|undefined); #transDuration: number; #transType: Gtk.RevealerTransitionType = Gtk.RevealerTransitionType.SLIDE_DOWN; - get isOpen() { return Boolean(this.get_first_child()); } + get isOpen() { return Boolean(this.#page); } + get page() { return this.#page; } constructor(props?: PagesProps) { super({ orientation: Gtk.Orientation.VERTICAL, - cssName: "pages" + cssName: "pages", + name: "pages" }); - this.name = "pages"; - props?.class?.split(' ').filter(variableToBoolean).forEach(clss => - this.add_css_class(clss)); + this.add_css_class("pages"); this.#transDuration = props?.transitionDuration ?? 280; @@ -53,7 +49,7 @@ class Pages extends Gtk.Box { } toggle(newPage?: Page, onToggled?: () => void): void { - if(!newPage || (this.#page?.id === newPage?.id)) { + if(!newPage || (this.#page?.id === newPage.id)) { this.close(onToggled); return; } @@ -69,38 +65,35 @@ class Pages extends Gtk.Box { } } - open(newPage: Page, onOpened?: () => void) { - const pageWidget = createRoot(() => - - {newPage as unknown as Gtk.Widget} - as Gtk.Revealer); - - this.prepend(pageWidget); - - this.#pageWidget = pageWidget; + open(newPage: Page, onOpen?: () => void) { this.#page = newPage; - this.reorder_child_after(this.get_last_child()!, null); - (this.get_first_child() as Gtk.Revealer).revealChild = true; - onOpened?.(); + this.prepend( + + + {newPage.create()} + as Gtk.Revealer + ); + + (this.get_first_child() as Gtk.Revealer)?.set_reveal_child(true); + onOpen?.(); } close(onClosed?: () => void): void { - if(!this.#pageWidget) return; + const page = this.get_first_child() as Gtk.Revealer|null; + if(!page) return; - this.#pageWidget.revealChild = false; - const closingPage = this.#pageWidget!; + this.#page?.actionClosed?.(); + this.#page = undefined; + page.set_reveal_child(false); this.#timeouts.push([ - timeout(closingPage.transitionDuration, () => { - this.remove(closingPage); + timeout(page.transitionDuration, () => { + this.remove(page); onClosed?.(); }), - onClosed]); - - this.#pageWidget = undefined; + onClosed + ]); } } diff --git a/ags/widget/control-center/QuickActions.tsx b/ags/widget/control-center/QuickActions.tsx index 1fd29d7..5271df5 100644 --- a/ags/widget/control-center/QuickActions.tsx +++ b/ags/widget/control-center/QuickActions.tsx @@ -2,12 +2,14 @@ import { Gtk } from "ags/gtk4"; import { Windows } from "../../windows"; import { Wallpaper } from "../../scripts/wallpaper"; import { execApp } from "../../scripts/apps"; -import GLib from "gi://GLib?version=2.0"; import { Accessor } from "ags"; import { createPoll } from "ags/time"; +import GLib from "gi://GLib?version=2.0"; +import Gio from "gi://Gio?version=2.0"; +const userFace: Gio.File = Gio.File.new_for_path(`${GLib.get_home_dir()}/.face`); const uptime: Accessor = createPoll("Just turned on", 1000, "uptime -p"); function LockButton(): Gtk.Button { @@ -57,22 +59,25 @@ function LogoutButton(): Gtk.Button { export const QuickActions = () => - + + {userFace.query_exists(null) && + + } + + - - - - - str.replace(/^up /, ""))} /> + + + str.replace(/^up /, ""))} /> + - - + diff --git a/ags/widget/control-center/Sliders.tsx b/ags/widget/control-center/Sliders.tsx index 49fd084..b253328 100644 --- a/ags/widget/control-center/Sliders.tsx +++ b/ags/widget/control-center/Sliders.tsx @@ -3,7 +3,7 @@ import { Wireplumber } from "../../scripts/volume"; import { Pages } from "./Pages"; import { PageSound } from "./pages/Sound"; import { PageMicrophone } from "./pages/Microphone"; -import { createBinding, createRoot, With } from "ags"; +import { createBinding, With } from "ags"; import AstalWp from "gi://AstalWp"; @@ -11,51 +11,43 @@ import AstalWp from "gi://AstalWp"; export let slidersPages: Pages|undefined; export function Sliders() { - slidersPages = createRoot(() => new Pages())!; - return slidersPages = undefined}> + hexpand spacing={10} onUnmap={() => slidersPages = undefined}> {(sink: AstalWp.Endpoint) => - Wireplumber.getDefault().toggleMuteSink()} iconName={createBinding(sink, "volumeIcon").as((icon) => (!Wireplumber.getDefault().isMutedSink() && - Wireplumber.getDefault().getSinkVolume() > 0) ? - icon - : "audio-volume-muted-symbolic" + Wireplumber.getDefault().getSinkVolume() > 0 + ) ? icon : "audio-volume-muted-symbolic" )} /> - self.value = Math.floor(sink.volume * 100)} - value={createBinding(sink, "volume").as(v => Math.floor(v * 100))} - max={Wireplumber.getDefault().getMaxSinkVolume()} - onChangeValue={(_, _scrollType, value) => sink.set_volume(value / 100)} /> + sink.set_volume(value)} /> - - slidersPages!.toggle(PageSound())} /> + + slidersPages?.toggle(PageSound)} /> } {(source: AstalWp.Endpoint) => - Wireplumber.getDefault().toggleMuteSource()} iconName={createBinding(source, "volumeIcon").as((icon) => - (!Wireplumber.getDefault().isMutedSink() && - Wireplumber.getDefault().getSinkVolume() > 0) ? - icon - : "microphone-sensitivity-muted-symbolic" + (!Wireplumber.getDefault().isMutedSource() && + Wireplumber.getDefault().getSourceVolume() > 0 + ) ? icon : "microphone-sensitivity-muted-symbolic" )} /> - self.value = Math.floor(source.volume * 100)} - value={createBinding(source, "volume").as(v => Math.floor(v * 100))} - max={Wireplumber.getDefault().getMaxSinkVolume()} - onChangeValue={(_, _scrollType, value) => source.set_volume(value / 100)} /> + source.set_volume(value)} /> - - slidersPages!.toggle(PageMicrophone())} /> + + slidersPages?.toggle(PageMicrophone)} /> } - {slidersPages} + slidersPages = self} /> } diff --git a/ags/widget/control-center/Tiles.tsx b/ags/widget/control-center/Tiles.tsx index b319a7b..2a6f43c 100644 --- a/ags/widget/control-center/Tiles.tsx +++ b/ags/widget/control-center/Tiles.tsx @@ -5,7 +5,6 @@ import { TileDND } from "./tiles/DoNotDisturb"; import { TileRecording } from "./tiles/Recording"; import { TileNightLight } from "./tiles/NightLight"; import { Pages } from "./Pages"; -import { createRoot } from "/usr/share/ags/js/gnim/src/jsx/scope"; export let TilesPages: Pages|undefined; @@ -19,18 +18,15 @@ export const tileList: Array<() => JSX.Element|Gtk.Widget> = [ export function Tiles(): Gtk.Widget { return TilesPages = undefined} $={(self) => { - if(!TilesPages) - TilesPages = createRoot(() => new Pages({ class: "tile-pages" })); - - self.append(TilesPages!); - }}> + onUnmap={() => TilesPages = undefined}> + maxChildrenPerLine={2} hexpand homogeneous> {tileList.map(t => t())} + + TilesPages = self} /> as Gtk.Box; } diff --git a/ags/widget/control-center/pages/Bluetooth.tsx b/ags/widget/control-center/pages/Bluetooth.tsx index 5d1929f..7bcf065 100644 --- a/ags/widget/control-center/pages/Bluetooth.tsx +++ b/ags/widget/control-center/pages/Bluetooth.tsx @@ -4,60 +4,70 @@ import { tr } from "../../../i18n/intl"; import { Windows } from "../../../windows"; import { Notifications } from "../../../scripts/notifications"; import { execApp } from "../../../scripts/apps"; +import { createBinding, createComputed, For, With } from "ags"; import AstalNotifd from "gi://AstalNotifd"; import AstalBluetooth from "gi://AstalBluetooth"; -import { variableToBoolean } from "../../../scripts/utils"; -import { createBinding, createComputed, For, With } from "ags"; -export const BluetoothPage = () => discovering ? - "arrow-circular-top-right-symbolic" - : "media-playback-stop-symbolic")} tooltipText={ - createBinding(AstalBluetooth.get_default().adapter, "discovering").as((discovering) => - !discovering ? - tr("control_center.pages.bluetooth.start_discovering") - : tr("control_center.pages.bluetooth.stop_discovering"))} - onClicked={() => { - if(AstalBluetooth.get_default().adapter.discovering) { - AstalBluetooth.get_default().adapter.stop_discovery(); - return; - } +export const BluetoothPage = new Page({ + id: "bluetooth", + title: tr("control_center.pages.bluetooth.title"), + spacing: 6, + description: tr("control_center.pages.bluetooth.description"), + headerButtons: [{ + icon: createBinding(AstalBluetooth.get_default().adapter, "discovering") + .as(discovering => !discovering ? + "arrow-circular-top-right-symbolic" + : "media-playback-stop-symbolic" + ), + tooltipText: createBinding(AstalBluetooth.get_default().adapter, "discovering") + .as((discovering) => !discovering ? + tr("control_center.pages.bluetooth.start_discovering") + : tr("control_center.pages.bluetooth.stop_discovering")), + actionClicked: () => { + if(AstalBluetooth.get_default().adapter.discovering) { + AstalBluetooth.get_default().adapter.stop_discovery(); + return; + } - AstalBluetooth.get_default().adapter.start_discovery(); - }} - /> - ]} - actionClose={() => AstalBluetooth.get_default().adapter.discovering && - AstalBluetooth.get_default().adapter.stop_discovery()} - bottomButtons={[{ + AstalBluetooth.get_default().adapter.start_discovery(); + } + }], + actionClosed: () => AstalBluetooth.get_default().adapter.discovering && + AstalBluetooth.get_default().adapter.stop_discovery(), + bottomButtons: [{ title: tr("control_center.pages.more_settings"), - onClick: () => { + actionClicked: () => { Windows.getDefault().close("control-center"); execApp("overskride", "[float; animation slide right]"); } - }]} spacing={2}> - + }], + content: () => [ + adptrs.length > 1) + } spacing={2}> - - {(adapter: AstalBluetooth.Adapter) => - + + adpts.length > 1)}> + + {(hasMoreAdapters: boolean) => hasMoreAdapters && + + + {(adapter: AstalBluetooth.Adapter) => + + } + + } - - + + , - devs.filter(dev => dev.paired || dev.connected || dev.trusted).length > 0)}> @@ -68,7 +78,7 @@ export const BluetoothPage = () => } - devs.filter(dev => !dev.connected && !dev.paired && !dev.trusted).length > 0)}> @@ -80,7 +90,8 @@ export const BluetoothPage = () => - as Page; + ] +}); function DeviceWidget({ device }: { device: AstalBluetooth.Device }): Gtk.Widget { return @@ -93,7 +104,7 @@ function DeviceWidget({ device }: { device: AstalBluetooth.Device }): Gtk.Widget tooltipText={ createBinding(device, "connected").as(connected => !connected ? tr("connect") : "") - } onClick={() => { + } actionClicked={() => { if(device.connected) return; let skipConnection: boolean = false; @@ -135,8 +146,8 @@ function DeviceWidget({ device }: { device: AstalBluetooth.Device }): Gtk.Widget createBinding(device, "connected"), createBinding(device, "trusted") ])}> - {([connected, trusted]: [boolean, boolean]) => trusted && - + {([connected, trusted]: [boolean, boolean]) => + { device.set_trusted(!trusted)} /> - } + + } } - /> as Page; + /> as Gtk.Widget; } diff --git a/ags/widget/control-center/pages/Microphone.tsx b/ags/widget/control-center/pages/Microphone.tsx index 6cec762..bca1efb 100644 --- a/ags/widget/control-center/pages/Microphone.tsx +++ b/ags/widget/control-center/pages/Microphone.tsx @@ -3,27 +3,32 @@ import { Wireplumber } from "../../../scripts/volume"; import { Gtk } from "ags/gtk4"; import { tr } from "../../../i18n/intl"; import { createBinding, For } from "ags"; -import AstalWp from "gi://AstalWp?version=0.1"; import { lookupIcon } from "../../../scripts/apps"; +import AstalWp from "gi://AstalWp?version=0.1"; -export const PageMicrophone = () => - - - - {(source: AstalWp.Endpoint) => isDefault ? "default" : "") - } icon={createBinding(source, "icon").as(ico => lookupIcon(ico) ? - ico : "audio-input-microphone-symbolic")} title={ - createBinding(source, "description").as(desc => desc ?? "Microphone") - } onClick={() => !source.isDefault && source.set_is_default(true)} - endWidget={ - - } - />} - - as Page; +export const PageMicrophone = new Page({ + id: "microphone", + title: tr("control_center.pages.microphone.title"), + description: tr("control_center.pages.microphone.description"), + content: () => [ + , + + + {(source: AstalWp.Endpoint) => isDefault ? "default" : "") + } icon={createBinding(source, "icon").as(ico => lookupIcon(ico) ? + ico : "audio-input-microphone-symbolic")} title={ + createBinding(source, "description").as(desc => desc ?? "Microphone") + } actionClicked={() => !source.isDefault && source.set_is_default(true)} + endWidget={ + + } + />} + + + ] +}); diff --git a/ags/widget/control-center/pages/Network.tsx b/ags/widget/control-center/pages/Network.tsx index a743d9d..d7752f2 100644 --- a/ags/widget/control-center/pages/Network.tsx +++ b/ags/widget/control-center/pages/Network.tsx @@ -6,32 +6,34 @@ import { execApp } from "../../../scripts/apps"; import { Notifications } from "../../../scripts/notifications"; import { AskPopup, AskPopupProps } from "../../AskPopup"; import { encoder, variableToBoolean } from "../../../scripts/utils"; +import { createBinding, For, With } from "ags"; import GLib from "gi://GLib?version=2.0"; import NM from "gi://NM"; import AstalNetwork from "gi://AstalNetwork"; -import { createBinding, For, With } from "ags"; -export const PageNetwork = () => - - primary === AstalNetwork.Primary.WIFI)} - tooltipText={"Re-scan networks"} onClicked={() => - AstalNetwork.get_default().wifi.scan()} - /> - ]} bottomButtons={[{ - title: tr("control_center.pages.more_settings"), - onClick: () => { - Windows.getDefault().close("control-center"); - execApp("nm-connection-editor", "[animationstyle gnomed]"); - } - }]}> - - +export const PageNetwork = new Page({ + id: "network", + title: tr("control_center.pages.network.title"), + headerButtons: createBinding(AstalNetwork.get_default(), "primary").as(primary => + primary === AstalNetwork.Primary.WIFI ? [{ + icon: "arrow-circular-top-right-symbolic", + tooltipText: "Re-scan networks", + actionClicked: () => AstalNetwork.get_default().wifi.scan() + }] : [] + ), + bottomButtons: [{ + title: tr("control_center.pages.more_settings"), + actionClicked: () => { + Windows.getDefault().close("control-center"); + execApp("nm-connection-editor", "[animationstyle gnomed]"); + } + }], + content: () => [ + @@ -52,8 +54,7 @@ export const PageNetwork = () => ]} />} - - + , primary === AstalNetwork.Primary.WIFI)}> @@ -95,7 +96,7 @@ export const PageNetwork = () => }) } }}/> - ]} onClick={() => { + ]} actionClicked={() => { const uuid = NM.utils_uuid_generate(); const ssidBytes = GLib.Bytes.new(encoder.encode(ap.ssid)); @@ -129,7 +130,8 @@ export const PageNetwork = () => } - as Page; + ] +}); function activateWirelessConnection(connection: NM.RemoteConnection, ssid: string): void { AstalNetwork.get_default().get_client().activate_connection_async( diff --git a/ags/widget/control-center/pages/NightLight.tsx b/ags/widget/control-center/pages/NightLight.tsx index 574f00e..16be810 100644 --- a/ags/widget/control-center/pages/NightLight.tsx +++ b/ags/widget/control-center/pages/NightLight.tsx @@ -5,14 +5,14 @@ import { Astal, Gtk } from "ags/gtk4"; import { addSliderMarksFromMinMax } from "../../../scripts/utils"; import { createBinding } from "ags"; -export const PageNightLight = () => - - +export const PageNightLight = new Page({ + id: "night-light", + title: tr("control_center.pages.night_light.title"), + description: tr("control_center.pages.night_light.description"), + content: () => [ + )} xalign={0} />, { self.value = NightLight.getDefault().temperature; addSliderMarksFromMinMax(self, 5, "{}K"); @@ -24,10 +24,10 @@ export const PageNightLight = () => if(type != undefined && type !== null) NightLight.getDefault().temperature = Math.floor(value) }} - /> + />, + )} xalign={0} />, { self.value = NightLight.getDefault().gamma; addSliderMarksFromMinMax(self, 5, "{}%"); @@ -39,4 +39,5 @@ export const PageNightLight = () => NightLight.getDefault().gamma = Math.floor(value) }} /> - as Page; + ] +}); diff --git a/ags/widget/control-center/pages/Page.tsx b/ags/widget/control-center/pages/Page.tsx index 799f9ba..74c1dac 100644 --- a/ags/widget/control-center/pages/Page.tsx +++ b/ags/widget/control-center/pages/Page.tsx @@ -1,24 +1,21 @@ -import { register } from "ags/gobject"; import { Gtk } from "ags/gtk4"; import { Separator } from "../../Separator"; -import { Accessor, For } from "ags"; -import { transform, transformWidget, variableToBoolean, WidgetNodeType } from "../../../scripts/utils"; +import { Accessor, createRoot } from "ags"; +import { transformWidget, variableToBoolean, WidgetNodeType } from "../../../scripts/utils"; import Pango from "gi://Pango?version=1.0"; export type PageProps = { - $?: () => void; - actionClose?: () => void; id: string; - class?: string | Accessor; - title: string | Accessor; - description?: string | Accessor; - headerButtons?: Array | Accessor>; + title: string; + description?: string; + headerButtons?: Array | Accessor>; bottomButtons?: Array | Accessor>; orientation?: Gtk.Orientation | Accessor; - spacing?: number; - children?: WidgetNodeType; + spacing?: number | Accessor; + content: () => WidgetNodeType; + actionClosed?: () => void; }; export type BottomButton = { @@ -26,142 +23,134 @@ export type BottomButton = { description?: string | Accessor; tooltipText?: string | Accessor; tooltipMarkup?: string | Accessor; - onClick?: () => void; + actionClicked?: () => void; }; -export { Page }; +export type HeaderButton = { + label?: string|Accessor; + icon: string|Accessor; + tooltipText?: string | Accessor; + tooltipMarkup?: string | Accessor; + actionClicked?: () => void; +}; -@register({ GTypeName: "Page" }) -class Page extends Gtk.Box { - #id: string | number = ""; - readonly bottomButtons?: Array = []; - - #subs: Array<() => void> = []; - #title: string | Accessor = ""; - #description?: string | Accessor; +export class Page { + #title: string; + #description?: string; + #orientation: Gtk.Orientation|Accessor< + Gtk.Orientation> = Gtk.Orientation.VERTICAL; + #spacing: number|Accessor = 4; + #headerButtons?: Array|Accessor>; + #bottomButtons?: Array|Accessor>; + readonly #id?: string; + readonly #create: () => WidgetNodeType; + public get id() { return this.#id; } public get title() { return this.#title; } public get description() { return this.#description; } - public get id() { return this.#id; } - public actionClose?: () => void = () => {}; + public get headerButtons() { return this.#headerButtons; } + public get bottomButtons() { return this.#bottomButtons; } + public readonly actionClosed?: () => void; constructor(props: PageProps) { - super(); - - this.set_hexpand(true); - this.set_orientation(Gtk.Orientation.VERTICAL); - - if(props.class instanceof Accessor) { - this.#subs.push(props.class.subscribe(() => { - const clss = (props.class as Accessor).get(); - - this.cssClasses = ["page", ...clss.split(' ').filter(s => s !== "")]; - })); - } else { - if(props.class) - this.cssClasses = ["page", - ...(props.class as string).split(' ').filter(s => s)]; - else - this.add_css_class("page"); - } - this.#id = props.id; this.#title = props.title; this.#description = props.description; - this.actionClose = props.actionClose; + this.#create = props.content; + this.actionClosed = props.actionClosed; - this.prepend( - - - + if(props.orientation != null) + this.#orientation = props.orientation; + + if(props.spacing != null) + this.#spacing = props.spacing; + + if(props.headerButtons != null) + this.#headerButtons = props.headerButtons; + } + + public create(): Gtk.Box { + return createRoot((dispose) => + dispose()}> + + + + + + + + + + + {this.#headerButtons && transformWidget(this.#headerButtons, (button) => + button.actionClicked?.()} + tooltipText={button.tooltipText} tooltipMarkup={button.tooltipMarkup} + /> + )} + + + + + + {this.#create()} + + + - {props.headerButtons && - { - (props.headerButtons instanceof Accessor) ? - - {(button) => button} - - : props.headerButtons - } - } - - + {this.#bottomButtons && transformWidget(this.#bottomButtons, (button) => + button?.actionClicked?.()} tooltipText={button?.tooltipText} + tooltipMarkup={button?.tooltipMarkup}> - - as Gtk.Box); + + + + )} + + as Gtk.Box + ); + } - this.append( - - {props.children} - as Gtk.Box); - - this.append( buttons.length > 0) - : (!props.bottomButtons ? false : props.bottomButtons.length > 0)} - /> as Gtk.Widget); - - this.append( - - {transformWidget(props.bottomButtons, (button) => - - - - - - )} - as Gtk.Box); - - props.$?.(); + public static getContent(pageWidget: Gtk.Box) { + return pageWidget.get_first_child()!.get_next_sibling()! as Gtk.Box; } } -function BottomButton(props: BottomButton) { - return - - - - - - as Gtk.Button; -} - -export function PageButton({ onDestroy, ...props }: { +export function PageButton({ onUnmap, ...props }: { class?: string | Accessor; icon?: string | Accessor; title: string | Accessor; endWidget?: WidgetNodeType; description?: string | Accessor; extraButtons?: Array | WidgetNodeType; - onDestroy?: (self: Gtk.Box) => void; - onClick?: (self: Gtk.Button) => void; + maxWidthChars?: number | Accessor; + onUnmap?: (self: Gtk.Box) => void; + actionClicked?: (self: Gtk.Button) => void; tooltipText?: string | Accessor; tooltipMarkup?: string | Accessor; -}) { - return - onUnmap?.(self)} class={"page-button"}> + - + {props.icon && } - + - `${title.substring(0, 35)}${title.length > 35 ? '…' : ""}`) - } + ellipsize={Pango.EllipsizeMode.END} label={props.title} + maxWidthChars={props.maxWidthChars ?? 28} /> - + {props.extraButtons} as Gtk.Box; diff --git a/ags/widget/control-center/pages/Sound.tsx b/ags/widget/control-center/pages/Sound.tsx index 9cc1b76..f3b1065 100644 --- a/ags/widget/control-center/pages/Sound.tsx +++ b/ags/widget/control-center/pages/Sound.tsx @@ -4,92 +4,93 @@ import { getAppIcon, lookupIcon } from "../../../scripts/apps"; import { Wireplumber } from "../../../scripts/volume"; import { tr } from "../../../i18n/intl"; import { createBinding, For } from "ags"; -import AstalWp from "gi://AstalWp"; import { variableToBoolean } from "../../../scripts/utils"; + +import AstalWp from "gi://AstalWp"; import GObject from "gi://GObject?version=2.0"; import Pango from "gi://Pango?version=1.0"; -export const PageSound = () => - - - - {(sink: AstalWp.Endpoint) => - - isDefault ? "default" : "")} - icon={createBinding(sink, "icon").as(ico => - lookupIcon(ico) ? ico : "audio-card-symbolic")} - title={createBinding(sink, "description").as(desc => - desc ?? "Speaker")} - onClick={() => !sink.isDefault && sink.set_is_default(true)} - endWidget={ - - } - />} - +export const PageSound = new Page({ + id: "sound", + title: tr("control_center.pages.sound.title"), + description: tr("control_center.pages.sound.description"), + content: () => [ + , + + + {(sink: AstalWp.Endpoint) => + + isDefault ? "default" : "")} + icon={createBinding(sink, "icon").as(ico => + lookupIcon(ico) ? ico : "audio-card-symbolic")} + title={createBinding(sink, "description").as(desc => + desc ?? "Speaker")} + actionClicked={() => !sink.isDefault && sink.set_is_default(true)} + endWidget={ + + } + />} + + , + + + + {(stream: AstalWp.Stream) => + { + const conns: Map> = new Map(); + const controllerMotion = Gtk.EventControllerMotion.new(); - - - {(stream: AstalWp.Stream) => - { - const conns: Map> = new Map(); - const controllerMotion = Gtk.EventControllerMotion.new(); + self.add_controller(controllerMotion); - self.add_controller(controllerMotion); + conns.set(controllerMotion, [ + controllerMotion.connect("enter", () => { + const revealer = self.get_last_child()!.get_first_child() as Gtk.Revealer; + revealer.set_reveal_child(true); + }), + controllerMotion.connect("leave", () => { + const revealer = self.get_last_child()!.get_first_child() as Gtk.Revealer; + revealer.set_reveal_child(false); + }) + ]); - conns.set(controllerMotion, [ - controllerMotion.connect("enter", () => { - const revealer = self.get_last_child()!.get_first_child() as Gtk.Revealer; - revealer.set_reveal_child(true); - }), - controllerMotion.connect("leave", () => { - const revealer = self.get_first_child()!.get_first_child() as Gtk.Revealer; - revealer.set_reveal_child(true); - }) - ]); + conns.set(self, [ + self.connect("destroy", () => conns.forEach((ids, obj) => + ids.forEach(id => obj.disconnect(id)) + )) + ]); + }}> + + getAppIcon(name.split(' ')[0]) ?? "application-x-executable-symbolic")} + css={"font-size: 18px; margin-right: 6px;"} /> - conns.set(self, [ - self.connect("destroy", () => conns.forEach((ids, obj) => - ids.forEach(id => obj.disconnect(id)) - )) - ]); - }}> + + + + + desc ?? "Unnamed audio stream")} + ellipsize={Pango.EllipsizeMode.END} + tooltipText={createBinding(stream, "name")} + class={"name"} xalign={0} + /> + - - getAppIcon(name.split(' ')[0]) ?? "application-x-executable-symbolic")} - css={"font-size: 18px; margin-right: 6px;"} /> - - - - - - name ?? "Unnamed audio stream")} - ellipsize={Pango.EllipsizeMode.END} - tooltipText={createBinding(stream, "name")} - class={"name"} xalign={0} + stream.set_volume(value)} + hexpand min={0} max={1.5} /> - - - { - self.value = Math.floor(stream.volume * 100); - }} value={createBinding(stream, "volume").as(vol => - Math.floor(vol * 100))} - onChangeValue={(_, type, value) => { - if(type !== undefined && type !== null) - stream.volume = Math.floor(value / 100); - }} - /> + - - } - - as Page; + } + + + ] +}); diff --git a/ags/widget/control-center/tiles/Bluetooth.tsx b/ags/widget/control-center/tiles/Bluetooth.tsx index 3c1ad2b..0d49cda 100644 --- a/ags/widget/control-center/tiles/Bluetooth.tsx +++ b/ags/widget/control-center/tiles/Bluetooth.tsx @@ -13,7 +13,7 @@ export const TileBluetooth = () => return connected && connectedDev ? connectedDev.get_alias() : "" })} onToggledOn={() => AstalBluetooth.get_default().adapter?.set_powered(true)} onToggledOff={() => AstalBluetooth.get_default().adapter?.set_powered(false)} - onClickMore={() => TilesPages?.toggle(BluetoothPage())} + onClickMore={() => TilesPages?.toggle(BluetoothPage)} enableOnClickMore={true} iconSize={16} toggleState={createBinding(AstalBluetooth.get_default(), "isPowered")} icon={createComputed([ diff --git a/ags/widget/control-center/tiles/Network.tsx b/ags/widget/control-center/tiles/Network.tsx index 9ab0bfd..c2eee33 100644 --- a/ags/widget/control-center/tiles/Network.tsx +++ b/ags/widget/control-center/tiles/Network.tsx @@ -31,7 +31,7 @@ export const TileNetwork = () => })() )} onToggledOn={() => wifi.set_enabled(true)} onToggledOff={() => wifi.set_enabled(false)} - onClickMore={() => TilesPages?.toggle(PageNetwork())} + onClickMore={() => TilesPages?.toggle(PageNetwork)} icon={"network-wireless-signal-excellent-symbolic"} toggleState={createBinding(wifi, "enabled")} /> @@ -50,7 +50,7 @@ export const TileNetwork = () => })} onToggledOn={() => execAsync("nmcli n on")} onToggledOff={() => execAsync("nmcli n off")} - onClickMore={() => TilesPages?.toggle(PageNetwork())} + onClickMore={() => TilesPages?.toggle(PageNetwork)} icon={createBinding(wired, "internet").as((internet: AstalNetwork.Internet) => { switch(internet) { case AstalNetwork.Internet.CONNECTED: @@ -74,7 +74,7 @@ export const TileNetwork = () => description={tr("disconnected")} onToggledOn={() => execAsync("nmcli n on")} onToggledOff={() => execAsync("nmcli n off")} - onClickMore={() => TilesPages?.toggle(PageNetwork())} + onClickMore={() => TilesPages?.toggle(PageNetwork)} icon={"network-wired-disconnected-symbolic"} iconSize={16} toggleState={createBinding(wired, "internet").as((internet: AstalNetwork.Internet) => diff --git a/ags/widget/control-center/tiles/NightLight.tsx b/ags/widget/control-center/tiles/NightLight.tsx index 0ee5cc5..5def169 100644 --- a/ags/widget/control-center/tiles/NightLight.tsx +++ b/ags/widget/control-center/tiles/NightLight.tsx @@ -20,6 +20,6 @@ export const TileNightLight = () => onToggledOff={() => NightLight.getDefault().identity = true} onToggledOn={() => NightLight.getDefault().identity = false} enableOnClickMore={true} - onClickMore={() => TilesPages?.toggle(PageNightLight())} + onClickMore={() => TilesPages?.toggle(PageNightLight)} toggleState={createBinding(NightLight.getDefault(), "identity").as(identity => !identity)} /> diff --git a/ags/widget/control-center/tiles/Recording.tsx b/ags/widget/control-center/tiles/Recording.tsx index ad90376..5dd5bd9 100644 --- a/ags/widget/control-center/tiles/Recording.tsx +++ b/ags/widget/control-center/tiles/Recording.tsx @@ -3,7 +3,6 @@ import { Recording } from "../../../scripts/recording"; import { tr } from "../../../i18n/intl"; import { isInstalled, time } from "../../../scripts/utils"; import { createBinding, createComputed } from "ags"; -import { Gtk } from "ags/gtk4"; export const TileRecording = () => diff --git a/ags/widget/control-center/tiles/Tile.tsx b/ags/widget/control-center/tiles/Tile.tsx index 33dbc9e..adfb92d 100644 --- a/ags/widget/control-center/tiles/Tile.tsx +++ b/ags/widget/control-center/tiles/Tile.tsx @@ -15,7 +15,7 @@ export type TileProps = { description?: string | Accessor; toggleState?: boolean | Accessor; enableOnClickMore?: boolean | Accessor; - onDestroy?: (self: Gtk.Box) => void; + onUnmap?: (self: Gtk.Box) => void; onToggledOn: () => void; onToggledOff: () => void; onClickMore?: () => void; @@ -35,7 +35,8 @@ export function Tile(props: TileProps): Gtk.Widget { onCleanup(() => subs.forEach(s => s())); - return `tile ${clss} ${isToggled ? "toggled" : ""} ${ @@ -47,7 +48,7 @@ export function Tile(props: TileProps): Gtk.Widget { props.onClickMore ? "has-more" : "" }` ) - }> + }> { if(toggled.get()) { setToggled(false);