diff --git a/ags/runner/Runner.ts b/ags/runner/Runner.ts index f06fdd4..92cad32 100644 --- a/ags/runner/Runner.ts +++ b/ags/runner/Runner.ts @@ -1,4 +1,4 @@ -import { AstalIO, timeout } from "astal"; +import { AstalIO, GObject, timeout } from "astal"; import { Astal, Gdk, Gtk, Widget } from "astal/gtk3"; import { PopupWindow, PopupWindowProps } from "../widget/PopupWindow"; import { updateApps } from "../scripts/apps"; @@ -44,11 +44,11 @@ export function regExMatch(search: string, item: (string|number)): boolean { if(typeof item === "number") return new RegExp(`${search.split('').map(c => - `.*${c}.*`).join('')}`, + `${c}`).join('')}`, "g").test(item.toString()); return new RegExp(`${search.split('').map(c => - `.*${c}.*`).join('')}`, + `${c}`).join('')}`, "gi").test(item); } @@ -82,7 +82,6 @@ export function setEntryText(text: string): void { export function openDefault(initialText?: string) { return Runner.openRunner({ entryPlaceHolder: "Start typing...", - showResultsPlaceHolderOnStartup: false, initialText, resultsLimit: 24 } as Runner.RunnerProps, @@ -132,16 +131,28 @@ export function openDefault(initialText?: string) { ]); } -export function openRunner(props?: RunnerProps, placeholder?: () => Array): Widget.Window { +export function openRunner(props: RunnerProps, placeholder?: () => Array): Widget.Window { let onClickTimeout: (AstalIO.Time|undefined); + const connections: Map = new Map(); + + props.width ??= 780; + props.height ??= 420; gtkEntry = new Widget.Entry({ className: "search", placeholderText: props?.entryPlaceHolder || "", - onChanged: (self) => { + onChanged: async (self) => { updateResultsList(self.text); resultsList.get_row_at_index(0) && resultsList.select_row(resultsList.get_row_at_index(0)); + + if(self.text.trim().length < 1 && !mainBox.get_style_context().has_class("empty-input")) { + mainBox.get_style_context().add_class("empty-input"); + return; + } + + mainBox.get_style_context().has_class("empty-input") && + mainBox.get_style_context().remove_class("empty-input"); }, onActivate: (entry) => { const resultWidget = resultsList.get_selected_row()?.get_child(); @@ -154,12 +165,31 @@ export function openRunner(props?: RunnerProps, placeholder?: () => Array Array { resultsList.insert(resultWidget, -1); - resultsList.connect("row-activated", (_, row: Gtk.ListBoxRow) => { - const rWidget = row.get_child(); - if(rWidget instanceof ResultWidget) { - if(onClickTimeout) return; + const conns: Array = []; - // Timeout, so it doesn't fire the event a hundred times :skull: - onClickTimeout = timeout(500, () => onClickTimeout = undefined); - rWidget.onClick(); - rWidget.closeOnClick && Runner.close(); - } - }); + conns.push( + resultsList.connect("row-activated", (_, row: Gtk.ListBoxRow) => { + const rWidget = row.get_child(); + if(rWidget instanceof ResultWidget) { + if(onClickTimeout) return; + + // Timeout, so it doesn't fire the event a hundred times :skull: + onClickTimeout = timeout(500, () => onClickTimeout = undefined); + rWidget.onClick(); + rWidget.closeOnClick && Runner.close(); + } + }), + resultsList.connect("destroy", () => + conns.forEach((id) => resultsList.disconnect(id)) + ) + ); }); + + widgets.length > 0 ? + (!scrollable.visible && scrollable.show()) + : scrollable.hide(); } if(!instance) instance = Windows.createWindowForFocusedMonitor((mon: number): (Widget.Window) => PopupWindow({ namespace: "runner", monitor: mon, - widthRequest: props?.width ?? 780, - heightRequest: props?.height ?? defaultHeight, - marginTop: (AstalHyprland.get_default().get_monitor(mon)?.height / 2) - 220, + widthRequest: props.width, + heightRequest: props.height, + marginTop: (AstalHyprland.get_default().get_monitor(mon)?.height / 2) - (props.height! / 2), exclusivity: Astal.Exclusivity.IGNORE, halign: Gtk.Align.CENTER, valign: Gtk.Align.START, @@ -256,29 +297,17 @@ export function openRunner(props?: RunnerProps, placeholder?: () => Array { + connections.forEach((id, obj) => GObject.signal_handler_is_connected(obj, id) && + obj.disconnect(id)); + gtkEntry = null; - [...plugins.values()].map(plugin => + + [...plugins.values()].forEach(plugin => plugin && plugin.onClose && plugin.onClose()); + instance = null; }, - child: new Widget.Box({ - className: "runner main", - orientation: Gtk.Orientation.VERTICAL, - hexpand: true, - valign: Gtk.Align.START, - children: [ - gtkEntry, - new Widget.Scrollable({ - className: "results-scrollable", - vscroll: Gtk.PolicyType.AUTOMATIC, - hscroll: Gtk.PolicyType.NEVER, - expand: true, - propagateNaturalHeight: true, - maxContentHeight: props?.height ?? defaultHeight, - child: resultsList - }) - ] - } as Widget.BoxProps) + child: mainBox } as PopupWindowProps))(); return instance!; diff --git a/ags/scripts/wallpaper.ts b/ags/scripts/wallpaper.ts index 471ae4e..020fb37 100644 --- a/ags/scripts/wallpaper.ts +++ b/ags/scripts/wallpaper.ts @@ -68,7 +68,7 @@ class Wallpaper extends GObject.Object { switch(key) { case "splash": - this.splash = /(yes|true|on|enable|enabled)/.test(value) ? true : false; + this.splash = (/(yes|true|on|enable|enabled|1).*/.test(value)) ? true : false; break; case "wallpaper": diff --git a/ags/style/_center-window.scss b/ags/style/_center-window.scss index b077c66..aed536e 100644 --- a/ags/style/_center-window.scss +++ b/ags/style/_center-window.scss @@ -2,10 +2,12 @@ @use "./wal"; @use "./colors"; -.center-window-container { + +.popup-window.center-window .center-window-container { background: colors.$bg-translucent; - border-radius: 18px; + border-radius: 24px; padding: 12px; + box-shadow: 0 0 6px colors.$bg-translucent; & .big-media { padding: 6px; @@ -85,7 +87,7 @@ & .calendar-box { & calendar { - $border-radius: 10px; + $border-radius: 14px; font-weight: 600; padding-bottom: 2px; diff --git a/ags/style/_colors.scss b/ags/style/_colors.scss index 47febd8..b487360 100644 --- a/ags/style/_colors.scss +++ b/ags/style/_colors.scss @@ -7,6 +7,7 @@ $bg-secondary: functions.toRGB(color.adjust($color: wal.$color1, $lightness: -16 $bg-tertiary: functions.toRGB(color.adjust($color: $bg-secondary, $lightness: 10%)); $bg-light: wal.$foreground; $bg-translucent: functions.toRGB(color.change($color: $bg-primary, $alpha: 75%)); +$bg-translucent-primary: $bg-translucent; $bg-translucent-secondary: functions.toRGB(color.change($color: $bg-translucent, $alpha: 78%)); $fg-primary: wal.$foreground; $fg-light: $bg-primary; diff --git a/ags/style/_control-center.scss b/ags/style/_control-center.scss index 2a9a3d9..2866152 100644 --- a/ags/style/_control-center.scss +++ b/ags/style/_control-center.scss @@ -10,6 +10,7 @@ background: colors.$bg-translucent; border-radius: 28px; padding: 20px; + box-shadow: 0 0 6px 1px colors.$bg-translucent; & > * { margin: 9px 0; @@ -164,10 +165,10 @@ } box.history { - margin-top: 10px; background: colors.$bg-translucent; + box-shadow: 0 0 6px 1px colors.$bg-translucent; border-radius: 24px; - padding: 20px; + padding: 18px; transition: 120ms linear; &.hide { @@ -176,7 +177,7 @@ box.history { & .notifications { & .notification { - background: colors.$bg-primary; + background: colors.$bg-translucent-primary; } } diff --git a/ags/style/_float-notifications.scss b/ags/style/_float-notifications.scss index d743704..8126592 100644 --- a/ags/style/_float-notifications.scss +++ b/ags/style/_float-notifications.scss @@ -2,13 +2,17 @@ @use "./mixins"; .floating-notifications-container { - padding: { - right: 6px; - top: 6px; - }; + padding: 16px; - & .notification { - margin: 6px; - box-shadow: 0 0 4px .5px colors.$bg-primary; + & .float-notification { + $radius: 18px; + + box-shadow: 0 0 8px 1px colors.$bg-translucent; + border-radius: $radius; + + & .notification { + padding: 4px; + border-radius: $radius; + } } } diff --git a/ags/style/_runner.scss b/ags/style/_runner.scss index 4615b78..1860085 100644 --- a/ags/style/_runner.scss +++ b/ags/style/_runner.scss @@ -1,19 +1,24 @@ @use "./colors"; .runner.main { - background: colors.$bg-translucent; - padding: 10px; - border-radius: 22px; + $radius: 24px; + + background: rgba($color: colors.$bg-primary, $alpha: .8); + border-radius: $radius; + box-shadow: inset 0 0 0 1px colors.$bg-secondary, + 0 0 8px 1px colors.$bg-translucent; + + padding: 4px; & entry { - background: colors.$bg-primary; - padding: 10px 9px; - border-radius: 12px; - margin-bottom: 1px; - min-height: 1.4em; + transition: 80ms ease-in; + min-height: 1.6em; + padding: 14px; + border-radius: inherit; + background: none; &:focus { - box-shadow: inset 0 0 0 2px colors.$bg-secondary; + box-shadow: none; } & image.left { @@ -22,7 +27,8 @@ } & list { - all: unset; + padding: 6px; + padding-top: 0; & > *:selected > .result, & > *:active > .result, @@ -39,6 +45,10 @@ } } + & trough { + margin-bottom: 10px; + } + & list .result { padding: 10px; background: colors.$bg-primary; diff --git a/ags/widget/PopupWindow.ts b/ags/widget/PopupWindow.ts index 4b382d1..fe66b05 100644 --- a/ags/widget/PopupWindow.ts +++ b/ags/widget/PopupWindow.ts @@ -45,8 +45,14 @@ export function PopupWindow(props: PopupWindowProps): Widget.Window { css: props.cssBackgroundWindow, }) : undefined; + const winProps: Widget.WindowProps = {}; + for(const key of Object.keys(props).filter(k => k !== "onClickedOutside")) { + // @ts-ignore ignore the `onClickedOutside()` method because astal thinks it's a signal + winProps[key as keyof typeof winProps] = props[key as keyof typeof props]; + } + return new Widget.Window({ - ...props, + ...winProps, namespace: props?.namespace ?? "popup-window", className: `popup-window ${(props.namespace instanceof Binding ? props.namespace.get() : props.namespace) || ""}`, diff --git a/ags/widget/control-center/pages/Bluetooth.ts b/ags/widget/control-center/pages/Bluetooth.ts index 516c118..2db0444 100644 --- a/ags/widget/control-center/pages/Bluetooth.ts +++ b/ags/widget/control-center/pages/Bluetooth.ts @@ -80,12 +80,12 @@ export const BluetoothPage: (() => Page) = () => new Page({ visible: bind(AstalBluetooth.get_default(), "devices").as((devs) => devs.filter(dev => dev.paired || dev.connected).length > 0), children: bind(AstalBluetooth.get_default(), "devices").as((devs) => { - const connectedDevices = devs.filter((dev) => dev.connected || dev.paired) + const connectedDevices = devs.filter((dev) => (dev.connected || dev.paired) && dev.trusted) return [ new Widget.Label({ className: "sub-header", - label: tr("control_center.pages.bluetooth.paired_devices"), + label: tr("devices"), xalign: 0, } as Widget.LabelProps), ...connectedDevices.map((dev) => DeviceWidget(dev)) @@ -99,7 +99,7 @@ export const BluetoothPage: (() => Page) = () => new Page({ visible: bind(AstalBluetooth.get_default(), "devices").as((devs) => devs.filter((dev) => !dev.connected && !dev.paired).length > 0), children: bind(AstalBluetooth.get_default(), "devices").as((devices) => { - const discoveredDevices = devices.filter((dev) => !dev.connected && !dev.paired); + const discoveredDevices = devices.filter((dev) => !dev.connected && !dev.paired && !dev.trusted); return [ new Widget.Label({ @@ -172,7 +172,7 @@ function DeviceWidget(dev: AstalBluetooth.Device): Gtk.Widget { body: `Couldn't connect to ${dev.alias ?? dev.name}, an error occurred: ${err.message || err.stack}`, urgency: AstalNotifd.Urgency.NORMAL }) - }); + }).then(() => dev.set_trusted(true)); if(!skipConnection) (async () => dev.connect_device(null))().catch((err: Gio.IOErrorEnum) => diff --git a/ags/window/CenterWindow.ts b/ags/window/CenterWindow.ts index 039a2c9..ccccc96 100644 --- a/ags/window/CenterWindow.ts +++ b/ags/window/CenterWindow.ts @@ -24,7 +24,9 @@ export const CenterWindow = (mon: number) => PopupWindow({ new Widget.Box({ className: "datetime", orientation: Gtk.Orientation.VERTICAL, - valign: Gtk.Align.START, + halign: Gtk.Align.CENTER, + valign: Gtk.Align.CENTER, + vexpand: true, children: [ new Widget.Label({ className: "time", @@ -56,6 +58,7 @@ export const CenterWindow = (mon: number) => PopupWindow({ orientation: Gtk.Orientation.HORIZONTAL, cssColor: "gray", margin: 5, + spacing: 8, alpha: .3, visible: bind(AstalMpris.get_default(), "players").as(players => players.length > 0), } as SeparatorProps), diff --git a/ags/window/ControlCenter.ts b/ags/window/ControlCenter.ts index bacad1a..e6a5fb4 100644 --- a/ags/window/ControlCenter.ts +++ b/ags/window/ControlCenter.ts @@ -19,6 +19,7 @@ export const ControlCenter = (mon: number) => PopupWindow({ widthRequest: 395, child: new Widget.Box({ orientation: Gtk.Orientation.VERTICAL, + spacing: 16, children: [ new Widget.Box({ className: "control-center-container", diff --git a/ags/window/FloatingNotifications.ts b/ags/window/FloatingNotifications.ts index 732ed02..ceb018e 100644 --- a/ags/window/FloatingNotifications.ts +++ b/ags/window/FloatingNotifications.ts @@ -16,11 +16,15 @@ export const FloatingNotifications = (mon: number) => new Widget.Window({ className: "floating-notifications-container", orientation: Gtk.Orientation.VERTICAL, homogeneous: false, + spacing: 12, visible: bind(Notifications.getDefault(), "notifications").as(notifs => notifs.length > 0), children: bind(Notifications.getDefault(), "notifications").as((notifs) => - notifs.map((item) => NotificationWidget(item, - () => Notifications.getDefault().removeNotification(item), - false, true)) + notifs.map((item) => new Widget.Box({ + className: "float-notification", + child: NotificationWidget(item, + () => Notifications.getDefault().removeNotification(item), + false, true) + } as Widget.BoxProps)) ), } as Widget.BoxProps) } as Widget.WindowProps); diff --git a/hypr/shell/decorations.conf b/hypr/shell/decorations.conf index 460786c..bb2379b 100644 --- a/hypr/shell/decorations.conf +++ b/hypr/shell/decorations.conf @@ -45,12 +45,13 @@ decoration { blur { enabled = true new_optimizations = true - xray = false # Setting to true can cause issues with nvidia cards! - size = 2 - passes = 5 - vibrancy = 0.9 - # popups = true - # popups_ignorealpha = 0.6 + xray = false # Setting to true may cause glitches on nvidia cards! + size = 18 + passes = 3 + vibrancy = 12 + + popups = false # Enable blur for popups + popups_ignorealpha = 0.7 } }