Merge branch 'retrozinndev:ryo' into ryo

This commit is contained in:
Mephisto
2025-06-14 12:25:46 +03:00
committed by GitHub
13 changed files with 144 additions and 82 deletions
+72 -43
View File
@@ -1,4 +1,4 @@
import { AstalIO, timeout } from "astal"; import { AstalIO, GObject, timeout } from "astal";
import { Astal, Gdk, Gtk, Widget } from "astal/gtk3"; import { Astal, Gdk, Gtk, Widget } from "astal/gtk3";
import { PopupWindow, PopupWindowProps } from "../widget/PopupWindow"; import { PopupWindow, PopupWindowProps } from "../widget/PopupWindow";
import { updateApps } from "../scripts/apps"; import { updateApps } from "../scripts/apps";
@@ -44,11 +44,11 @@ export function regExMatch(search: string, item: (string|number)): boolean {
if(typeof item === "number") if(typeof item === "number")
return new RegExp(`${search.split('').map(c => return new RegExp(`${search.split('').map(c =>
`.*${c}.*`).join('')}`, `${c}`).join('')}`,
"g").test(item.toString()); "g").test(item.toString());
return new RegExp(`${search.split('').map(c => return new RegExp(`${search.split('').map(c =>
`.*${c}.*`).join('')}`, `${c}`).join('')}`,
"gi").test(item); "gi").test(item);
} }
@@ -82,7 +82,6 @@ export function setEntryText(text: string): void {
export function openDefault(initialText?: string) { export function openDefault(initialText?: string) {
return Runner.openRunner({ return Runner.openRunner({
entryPlaceHolder: "Start typing...", entryPlaceHolder: "Start typing...",
showResultsPlaceHolderOnStartup: false,
initialText, initialText,
resultsLimit: 24 resultsLimit: 24
} as Runner.RunnerProps, } as Runner.RunnerProps,
@@ -132,16 +131,28 @@ export function openDefault(initialText?: string) {
]); ]);
} }
export function openRunner(props?: RunnerProps, placeholder?: () => Array<ResultWidget>): Widget.Window { export function openRunner(props: RunnerProps, placeholder?: () => Array<ResultWidget>): Widget.Window {
let onClickTimeout: (AstalIO.Time|undefined); let onClickTimeout: (AstalIO.Time|undefined);
const connections: Map<GObject.Object, number> = new Map();
props.width ??= 780;
props.height ??= 420;
gtkEntry = new Widget.Entry({ gtkEntry = new Widget.Entry({
className: "search", className: "search",
placeholderText: props?.entryPlaceHolder || "", placeholderText: props?.entryPlaceHolder || "",
onChanged: (self) => { onChanged: async (self) => {
updateResultsList(self.text); updateResultsList(self.text);
resultsList.get_row_at_index(0) && resultsList.get_row_at_index(0) &&
resultsList.select_row(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) => { onActivate: (entry) => {
const resultWidget = resultsList.get_selected_row()?.get_child(); const resultWidget = resultsList.get_selected_row()?.get_child();
@@ -154,12 +165,31 @@ export function openRunner(props?: RunnerProps, placeholder?: () => Array<Result
primary_icon_name: "system-search" primary_icon_name: "system-search"
} as Widget.EntryProps); } as Widget.EntryProps);
const defaultHeight = 420; const mainBox = new Widget.Box({
className: `runner main ${props.showResultsPlaceHolderOnStartup ? "empty" : ""}`,
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,
visible: props.showResultsPlaceHolderOnStartup ?? false,
propagateNaturalHeight: true,
maxContentHeight: props.height,
child: new Gtk.ListBox({
visible: true,
expand: true,
} as Gtk.ListBox.ConstructorProps)
})
]
} as Widget.BoxProps);
const resultsList: Gtk.ListBox = new Gtk.ListBox({ const scrollable = mainBox.get_children()[1] as Widget.Scrollable;
visible: true, const resultsList = scrollable.get_child() as Gtk.ListBox;
expand: true
} as Gtk.ListBox.ConstructorProps);
if(props?.showResultsPlaceHolderOnStartup && placeholder) { if(props?.showResultsPlaceHolderOnStartup && placeholder) {
const placeholderWidgets = placeholder(); const placeholderWidgets = placeholder();
@@ -211,27 +241,38 @@ export function openRunner(props?: RunnerProps, placeholder?: () => Array<Result
widgets.map((resultWidget: ResultWidget) => { widgets.map((resultWidget: ResultWidget) => {
resultsList.insert(resultWidget, -1); resultsList.insert(resultWidget, -1);
resultsList.connect("row-activated", (_, row: Gtk.ListBoxRow) => { const conns: Array<number> = [];
const rWidget = row.get_child();
if(rWidget instanceof ResultWidget) {
if(onClickTimeout) return;
// Timeout, so it doesn't fire the event a hundred times :skull: conns.push(
onClickTimeout = timeout(500, () => onClickTimeout = undefined); resultsList.connect("row-activated", (_, row: Gtk.ListBoxRow) => {
rWidget.onClick(); const rWidget = row.get_child();
rWidget.closeOnClick && Runner.close(); 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) if(!instance)
instance = Windows.createWindowForFocusedMonitor((mon: number): (Widget.Window) => PopupWindow({ instance = Windows.createWindowForFocusedMonitor((mon: number): (Widget.Window) => PopupWindow({
namespace: "runner", namespace: "runner",
monitor: mon, monitor: mon,
widthRequest: props?.width ?? 780, widthRequest: props.width,
heightRequest: props?.height ?? defaultHeight, heightRequest: props.height,
marginTop: (AstalHyprland.get_default().get_monitor(mon)?.height / 2) - 220, marginTop: (AstalHyprland.get_default().get_monitor(mon)?.height / 2) - (props.height! / 2),
exclusivity: Astal.Exclusivity.IGNORE, exclusivity: Astal.Exclusivity.IGNORE,
halign: Gtk.Align.CENTER, halign: Gtk.Align.CENTER,
valign: Gtk.Align.START, valign: Gtk.Align.START,
@@ -256,29 +297,17 @@ export function openRunner(props?: RunnerProps, placeholder?: () => Array<Result
updateApps(); updateApps();
}, },
onDestroy: () => { onDestroy: () => {
connections.forEach((id, obj) => GObject.signal_handler_is_connected(obj, id) &&
obj.disconnect(id));
gtkEntry = null; gtkEntry = null;
[...plugins.values()].map(plugin =>
[...plugins.values()].forEach(plugin =>
plugin && plugin.onClose && plugin.onClose()); plugin && plugin.onClose && plugin.onClose());
instance = null; instance = null;
}, },
child: new Widget.Box({ child: mainBox
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)
} as PopupWindowProps))(); } as PopupWindowProps))();
return instance!; return instance!;
+1 -1
View File
@@ -68,7 +68,7 @@ class Wallpaper extends GObject.Object {
switch(key) { switch(key) {
case "splash": 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; break;
case "wallpaper": case "wallpaper":
+5 -3
View File
@@ -2,10 +2,12 @@
@use "./wal"; @use "./wal";
@use "./colors"; @use "./colors";
.center-window-container {
.popup-window.center-window .center-window-container {
background: colors.$bg-translucent; background: colors.$bg-translucent;
border-radius: 18px; border-radius: 24px;
padding: 12px; padding: 12px;
box-shadow: 0 0 6px colors.$bg-translucent;
& .big-media { & .big-media {
padding: 6px; padding: 6px;
@@ -85,7 +87,7 @@
& .calendar-box { & .calendar-box {
& calendar { & calendar {
$border-radius: 10px; $border-radius: 14px;
font-weight: 600; font-weight: 600;
padding-bottom: 2px; padding-bottom: 2px;
+1
View File
@@ -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-tertiary: functions.toRGB(color.adjust($color: $bg-secondary, $lightness: 10%));
$bg-light: wal.$foreground; $bg-light: wal.$foreground;
$bg-translucent: functions.toRGB(color.change($color: $bg-primary, $alpha: 75%)); $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%)); $bg-translucent-secondary: functions.toRGB(color.change($color: $bg-translucent, $alpha: 78%));
$fg-primary: wal.$foreground; $fg-primary: wal.$foreground;
$fg-light: $bg-primary; $fg-light: $bg-primary;
+4 -3
View File
@@ -10,6 +10,7 @@
background: colors.$bg-translucent; background: colors.$bg-translucent;
border-radius: 28px; border-radius: 28px;
padding: 20px; padding: 20px;
box-shadow: 0 0 6px 1px colors.$bg-translucent;
& > * { & > * {
margin: 9px 0; margin: 9px 0;
@@ -164,10 +165,10 @@
} }
box.history { box.history {
margin-top: 10px;
background: colors.$bg-translucent; background: colors.$bg-translucent;
box-shadow: 0 0 6px 1px colors.$bg-translucent;
border-radius: 24px; border-radius: 24px;
padding: 20px; padding: 18px;
transition: 120ms linear; transition: 120ms linear;
&.hide { &.hide {
@@ -176,7 +177,7 @@ box.history {
& .notifications { & .notifications {
& .notification { & .notification {
background: colors.$bg-primary; background: colors.$bg-translucent-primary;
} }
} }
+11 -7
View File
@@ -2,13 +2,17 @@
@use "./mixins"; @use "./mixins";
.floating-notifications-container { .floating-notifications-container {
padding: { padding: 16px;
right: 6px;
top: 6px;
};
& .notification { & .float-notification {
margin: 6px; $radius: 18px;
box-shadow: 0 0 4px .5px colors.$bg-primary;
box-shadow: 0 0 8px 1px colors.$bg-translucent;
border-radius: $radius;
& .notification {
padding: 4px;
border-radius: $radius;
}
} }
} }
+20 -10
View File
@@ -1,19 +1,24 @@
@use "./colors"; @use "./colors";
.runner.main { .runner.main {
background: colors.$bg-translucent; $radius: 24px;
padding: 10px;
border-radius: 22px; 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 { & entry {
background: colors.$bg-primary; transition: 80ms ease-in;
padding: 10px 9px; min-height: 1.6em;
border-radius: 12px; padding: 14px;
margin-bottom: 1px; border-radius: inherit;
min-height: 1.4em; background: none;
&:focus { &:focus {
box-shadow: inset 0 0 0 2px colors.$bg-secondary; box-shadow: none;
} }
& image.left { & image.left {
@@ -22,7 +27,8 @@
} }
& list { & list {
all: unset; padding: 6px;
padding-top: 0;
& > *:selected > .result, & > *:selected > .result,
& > *:active > .result, & > *:active > .result,
@@ -39,6 +45,10 @@
} }
} }
& trough {
margin-bottom: 10px;
}
& list .result { & list .result {
padding: 10px; padding: 10px;
background: colors.$bg-primary; background: colors.$bg-primary;
+7 -1
View File
@@ -45,8 +45,14 @@ export function PopupWindow(props: PopupWindowProps): Widget.Window {
css: props.cssBackgroundWindow, css: props.cssBackgroundWindow,
}) : undefined; }) : 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({ return new Widget.Window({
...props, ...winProps,
namespace: props?.namespace ?? "popup-window", namespace: props?.namespace ?? "popup-window",
className: `popup-window ${(props.namespace instanceof Binding ? className: `popup-window ${(props.namespace instanceof Binding ?
props.namespace.get() : props.namespace) || ""}`, props.namespace.get() : props.namespace) || ""}`,
+4 -4
View File
@@ -80,12 +80,12 @@ export const BluetoothPage: (() => Page) = () => new Page({
visible: bind(AstalBluetooth.get_default(), "devices").as((devs) => visible: bind(AstalBluetooth.get_default(), "devices").as((devs) =>
devs.filter(dev => dev.paired || dev.connected).length > 0), devs.filter(dev => dev.paired || dev.connected).length > 0),
children: bind(AstalBluetooth.get_default(), "devices").as((devs) => { 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 [ return [
new Widget.Label({ new Widget.Label({
className: "sub-header", className: "sub-header",
label: tr("control_center.pages.bluetooth.paired_devices"), label: tr("devices"),
xalign: 0, xalign: 0,
} as Widget.LabelProps), } as Widget.LabelProps),
...connectedDevices.map((dev) => DeviceWidget(dev)) ...connectedDevices.map((dev) => DeviceWidget(dev))
@@ -99,7 +99,7 @@ export const BluetoothPage: (() => Page) = () => new Page({
visible: bind(AstalBluetooth.get_default(), "devices").as((devs) => visible: bind(AstalBluetooth.get_default(), "devices").as((devs) =>
devs.filter((dev) => !dev.connected && !dev.paired).length > 0), devs.filter((dev) => !dev.connected && !dev.paired).length > 0),
children: bind(AstalBluetooth.get_default(), "devices").as((devices) => { 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 [ return [
new Widget.Label({ 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}`, body: `Couldn't connect to ${dev.alias ?? dev.name}, an error occurred: ${err.message || err.stack}`,
urgency: AstalNotifd.Urgency.NORMAL urgency: AstalNotifd.Urgency.NORMAL
}) })
}); }).then(() => dev.set_trusted(true));
if(!skipConnection) if(!skipConnection)
(async () => dev.connect_device(null))().catch((err: Gio.IOErrorEnum) => (async () => dev.connect_device(null))().catch((err: Gio.IOErrorEnum) =>
+4 -1
View File
@@ -24,7 +24,9 @@ export const CenterWindow = (mon: number) => PopupWindow({
new Widget.Box({ new Widget.Box({
className: "datetime", className: "datetime",
orientation: Gtk.Orientation.VERTICAL, orientation: Gtk.Orientation.VERTICAL,
valign: Gtk.Align.START, halign: Gtk.Align.CENTER,
valign: Gtk.Align.CENTER,
vexpand: true,
children: [ children: [
new Widget.Label({ new Widget.Label({
className: "time", className: "time",
@@ -56,6 +58,7 @@ export const CenterWindow = (mon: number) => PopupWindow({
orientation: Gtk.Orientation.HORIZONTAL, orientation: Gtk.Orientation.HORIZONTAL,
cssColor: "gray", cssColor: "gray",
margin: 5, margin: 5,
spacing: 8,
alpha: .3, alpha: .3,
visible: bind(AstalMpris.get_default(), "players").as(players => players.length > 0), visible: bind(AstalMpris.get_default(), "players").as(players => players.length > 0),
} as SeparatorProps), } as SeparatorProps),
+1
View File
@@ -19,6 +19,7 @@ export const ControlCenter = (mon: number) => PopupWindow({
widthRequest: 395, widthRequest: 395,
child: new Widget.Box({ child: new Widget.Box({
orientation: Gtk.Orientation.VERTICAL, orientation: Gtk.Orientation.VERTICAL,
spacing: 16,
children: [ children: [
new Widget.Box({ new Widget.Box({
className: "control-center-container", className: "control-center-container",
+7 -3
View File
@@ -16,11 +16,15 @@ export const FloatingNotifications = (mon: number) => new Widget.Window({
className: "floating-notifications-container", className: "floating-notifications-container",
orientation: Gtk.Orientation.VERTICAL, orientation: Gtk.Orientation.VERTICAL,
homogeneous: false, homogeneous: false,
spacing: 12,
visible: bind(Notifications.getDefault(), "notifications").as(notifs => notifs.length > 0), visible: bind(Notifications.getDefault(), "notifications").as(notifs => notifs.length > 0),
children: bind(Notifications.getDefault(), "notifications").as((notifs) => children: bind(Notifications.getDefault(), "notifications").as((notifs) =>
notifs.map((item) => NotificationWidget(item, notifs.map((item) => new Widget.Box({
() => Notifications.getDefault().removeNotification(item), className: "float-notification",
false, true)) child: NotificationWidget(item,
() => Notifications.getDefault().removeNotification(item),
false, true)
} as Widget.BoxProps))
), ),
} as Widget.BoxProps) } as Widget.BoxProps)
} as Widget.WindowProps); } as Widget.WindowProps);
+7 -6
View File
@@ -45,12 +45,13 @@ decoration {
blur { blur {
enabled = true enabled = true
new_optimizations = true new_optimizations = true
xray = false # Setting to true can cause issues with nvidia cards! xray = false # Setting to true may cause glitches on nvidia cards!
size = 2 size = 18
passes = 5 passes = 3
vibrancy = 0.9 vibrancy = 12
# popups = true
# popups_ignorealpha = 0.6 popups = false # Enable blur for popups
popups_ignorealpha = 0.7
} }
} }