✨ ags: add brightness class, media widget on center-window and more
This commit is contained in:
@@ -71,14 +71,47 @@ function handleVolumeArgs(args: Array<string>) {
|
||||
if(!args[1])
|
||||
return `Please specify what you want to do!\n\n${volumeHelp()}`
|
||||
|
||||
if(!/(sink|source)\-mute/.test(args[1]) && !args[2])
|
||||
if(/^(sink|source)(\-increase|\-decrease|\-set)$/.test(args[1]) && !args[2])
|
||||
return `You forgot to add a value to be set!`;
|
||||
|
||||
if(Number.isNaN(Number.parseFloat(args[2])) && Number.isSafeInteger(Number.parseFloat(args[2])))
|
||||
return `Argument "${args[2]} is not a valid number! Please use integers"`;
|
||||
|
||||
const command: Array<string> = args[1].split('-');
|
||||
|
||||
if(/help/.test(args[1]))
|
||||
return volumeHelp();
|
||||
|
||||
switch(command[1]) {
|
||||
case "set":
|
||||
command[0] === "sink" ?
|
||||
Wireplumber.getDefault().setSinkVolume(Number.parseInt(args[2]))
|
||||
:
|
||||
Wireplumber.getDefault().setSourceVolume(Number.parseInt(args[2]))
|
||||
return `Done! Set ${command[0]} volume to ${args[2]}`;
|
||||
|
||||
case "mute":
|
||||
command[0] === "sink" ?
|
||||
Wireplumber.getDefault().toggleMuteSink()
|
||||
:
|
||||
Wireplumber.getDefault().toggleMuteSource()
|
||||
return `Done toggling mute!`;
|
||||
|
||||
case "increase":
|
||||
command[0] === "sink" ?
|
||||
Wireplumber.getDefault().increaseSinkVolume(Number.parseInt(args[2]))
|
||||
:
|
||||
Wireplumber.getDefault().increaseSourceVolume(Number.parseInt(args[2]))
|
||||
|
||||
return `Done increasing volume by ${args[2]}`;
|
||||
|
||||
case "decrease":
|
||||
command[0] === "sink" ?
|
||||
Wireplumber.getDefault().decreaseSinkVolume(Number.parseInt(args[2]))
|
||||
:
|
||||
Wireplumber.getDefault().decreaseSourceVolume(Number.parseInt(args[2]))
|
||||
|
||||
return `Done decreasing volume to ${args[2]}`;
|
||||
}
|
||||
|
||||
return `Couldn't resolve arguments! "${args.join(' ').replace(new RegExp(`^${args[0]}`), "")}"`;
|
||||
@@ -109,9 +142,10 @@ Options:
|
||||
close [window_name]: sets specified window's visibility to false.
|
||||
toggle [window_name]: toggles visibility of specified window.
|
||||
reload: creates a new astal instance and removes this one.
|
||||
volume: wireplumber volume controller, see "volume help".
|
||||
help, -h, --help: shows this help message.
|
||||
|
||||
2024 (c) retrozinndev's Hyprland-Dots, licensed under the MIT License.
|
||||
2025 (c) retrozinndev's Hyprland-Dots, licensed under the MIT License.
|
||||
https://github.com/retrozinndev/Hyprland-Dots
|
||||
`.trim();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
import { exec, execAsync, GObject, monitorFile, Process, readFileAsync, register, signal } from "astal";
|
||||
import { Connectable } from "astal/binding";
|
||||
|
||||
|
||||
/** !!TODO!! Needs more work and testing
|
||||
* I(retrozinndev) don't have a monitor that has software-controlled brightness
|
||||
*/
|
||||
@register({ GTypeName: "Brightness" })
|
||||
class Brightness extends GObject.Object implements Connectable {
|
||||
private readonly backlight: string|undefined;
|
||||
private max: number;
|
||||
private brightness: number;
|
||||
|
||||
@signal(Number)
|
||||
declare brightnessChanged: (value: number) => void;
|
||||
|
||||
constructor(backlightDevice?: string) {
|
||||
super();
|
||||
this.backlight = backlightDevice || "";
|
||||
this.max = Number.parseInt(exec(`brightnessctl -d ${backlightDevice} max`))
|
||||
this.brightness = Number.parseInt(exec(`brightnessctl -d ${backlightDevice} get`))
|
||||
|
||||
readFileAsync(`/sys/class/backlight/${backlightDevice}/brightness`).catch(() => {
|
||||
throw new Error(`Couldn't find backlight ${backlightDevice}`);
|
||||
});
|
||||
|
||||
monitorFile(`/sys/class/backlight/${backlightDevice}/brightness`, async () => {
|
||||
this.brightness = Number.parseInt(await execAsync(`brightnessctl -d ${backlightDevice} get`));
|
||||
this.max = Number.parseInt(await execAsync(`brightnessctl -d ${backlightDevice} max`));
|
||||
|
||||
this.emit("brightness-changed", this.brightness);
|
||||
});
|
||||
}
|
||||
|
||||
public setBrightness(newBrightness: number): void {
|
||||
execAsync(`brightnessctl -d ${this.backlight} set ${newBrightness || this.brightness}`).catch(() => {
|
||||
throw new Error(`Couldn't set brightness of backlight ${this.backlight}`);
|
||||
});
|
||||
|
||||
this.emit("brightness-changed", newBrightness);
|
||||
}
|
||||
}
|
||||
@@ -1,29 +1,32 @@
|
||||
import AstalNotifd from "gi://AstalNotifd";
|
||||
import { timeout } from "astal/time";
|
||||
import { Connectable } from "astal/binding";
|
||||
import { GObject, register, property, signal } from "astal";
|
||||
import { GObject, register, signal } from "astal";
|
||||
import { Windows } from "../windows";
|
||||
|
||||
@register()
|
||||
class Notifications extends GObject.Object implements Connectable {
|
||||
@register({ GTypeName: "Notifications" })
|
||||
class NotificationsClass extends GObject.Object implements Connectable {
|
||||
|
||||
private static instance: Notifications;
|
||||
private static instance: NotificationsClass;
|
||||
private notifd: AstalNotifd.Notifd;
|
||||
|
||||
public notifications: Array<AstalNotifd.Notification> = [];
|
||||
public notificationHistory: Array<AstalNotifd.Notification> = [];
|
||||
|
||||
@signal()
|
||||
declare "notification-added": (notification: AstalNotifd.Notification) => void;
|
||||
@signal(AstalNotifd.Notification)
|
||||
declare notificationAdded: (added: AstalNotifd.Notification) => void;
|
||||
|
||||
@signal(Number)
|
||||
declare notificationRemoved: (id: number) => void;
|
||||
|
||||
|
||||
public static getDefault(): Notifications {
|
||||
if(!Notifications.instance) {
|
||||
Notifications.instance = new Notifications();
|
||||
public static getDefault(): NotificationsClass {
|
||||
if(!NotificationsClass.instance) {
|
||||
NotificationsClass.instance = new NotificationsClass();
|
||||
this.instance._init();
|
||||
}
|
||||
|
||||
return Notifications.instance;
|
||||
return NotificationsClass.instance;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
@@ -95,3 +98,5 @@ class Notifications extends GObject.Object implements Connectable {
|
||||
return this.notifd;
|
||||
}
|
||||
}
|
||||
|
||||
export const Notifications = new NotificationsClass();
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { GObject } from "astal";
|
||||
import { GObject, register } from "astal";
|
||||
import AstalWp from "gi://AstalWp";
|
||||
|
||||
export const Wireplumber = GObject.registerClass({
|
||||
GTypeName: "Wireplumber",
|
||||
Signals: {}
|
||||
}, class WireplumberClass extends GObject.Object {
|
||||
export { WireplumberClass as Wireplumber };
|
||||
|
||||
|
||||
@register({ GTypeName: "Wireplumber" })
|
||||
class WireplumberClass extends GObject.Object {
|
||||
private static astalWireplumber: (AstalWp.Wp|null) = AstalWp.get_default();
|
||||
private static inst: WireplumberClass;
|
||||
|
||||
@@ -14,8 +15,8 @@ export const Wireplumber = GObject.registerClass({
|
||||
private maxSinkVolume: number = 100;
|
||||
private maxSourceVolume: number = 100;
|
||||
|
||||
_init(...props: any[]) {
|
||||
super._init(props);
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
if(!WireplumberClass.astalWireplumber)
|
||||
throw new Error("Audio features will not work correctly! Please install wireplumber first", {
|
||||
@@ -145,4 +146,4 @@ export const Wireplumber = GObject.registerClass({
|
||||
|
||||
return this.muteSource();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+1
-18
@@ -112,27 +112,10 @@
|
||||
|
||||
& > button {
|
||||
margin: 4px 1px;
|
||||
border-radius: 4px;
|
||||
|
||||
label {
|
||||
& label {
|
||||
font-size: 8px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: colors.$bg-secondary;
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
border-top-left-radius: 12px;
|
||||
border-bottom-left-radius: 12px;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
border-top-right-radius: 12px;
|
||||
border-bottom-right-radius: 12px;
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,38 +1,75 @@
|
||||
@use "sass:color";
|
||||
@use "./wal";
|
||||
@use "./functions" as funs; // Did you know that you can use the 'as' keyword? I just found out!
|
||||
@use "./colors";
|
||||
@use "./functions" as funs;
|
||||
|
||||
.center-window-container {
|
||||
background: wal.$background;
|
||||
background: colors.$bg-translucent;
|
||||
border-radius: 18px;
|
||||
padding: 12px;
|
||||
|
||||
& .left {
|
||||
.top {
|
||||
.time {
|
||||
font-size: 22px;
|
||||
& > .top {
|
||||
padding-bottom: 10px;
|
||||
|
||||
& .time {
|
||||
font-size: 28px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.date {
|
||||
& .date {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: funs.toRGB(color.adjust($color: wal.$foreground, $lightness: -15%));
|
||||
color: colors.$fg-disabled;
|
||||
}
|
||||
}
|
||||
|
||||
& .big-media {
|
||||
padding: 6px 16px;
|
||||
|
||||
& > box > .image {
|
||||
background-size: cover;
|
||||
background-position: center center;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
& > .info {
|
||||
padding: {
|
||||
top: 4px;
|
||||
bottom: 6px;
|
||||
};
|
||||
|
||||
& .title {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
& .artist {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: colors.$fg-disabled;
|
||||
}
|
||||
}
|
||||
|
||||
& > .controls {
|
||||
padding: 8px 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
& .calendar-box {
|
||||
padding: 5px;
|
||||
& calendar {
|
||||
border-radius: 6px;
|
||||
padding: 2px;
|
||||
& .right {
|
||||
& .calendar-box {
|
||||
padding: 5px;
|
||||
& calendar {
|
||||
border-radius: 6px;
|
||||
padding: 2px;
|
||||
|
||||
&.view {
|
||||
background: funs.toRGB(color.adjust($color: wal.$color1, $lightness: -35%));
|
||||
&.view {
|
||||
background: funs.toRGB(color.adjust($color: wal.$color1, $lightness: -35%));
|
||||
|
||||
& header {
|
||||
background: funs.toRGB(color.adjust($color: wal.$background, $lightness: -20%));
|
||||
& header {
|
||||
background: funs.toRGB(color.adjust($color: wal.$background, $lightness: -20%));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
@use "sass:color";
|
||||
@use "./wal";
|
||||
@use "./colors";
|
||||
@use "./functions" as funs;
|
||||
@use "./mixins";
|
||||
|
||||
.control-center-container {
|
||||
background: rgba(wal.$background, .65);
|
||||
@include mixins.reset-props;
|
||||
@include mixins.default-styles;
|
||||
|
||||
background: colors.$bg-translucent;
|
||||
border-radius: 24px;
|
||||
padding: 20px 14px;
|
||||
|
||||
@@ -58,25 +63,5 @@
|
||||
margin-right: 8px;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
trough {
|
||||
background: funs.toRGB(color.adjust($color: wal.$color1, $lightness: -20%));
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
trough highlight {
|
||||
background: wal.$color1;
|
||||
border-top-left-radius: inherit;
|
||||
border-bottom-left-radius: inherit;
|
||||
}
|
||||
|
||||
trough slider {
|
||||
min-width: 1.2em;
|
||||
min-height: 1.2em;
|
||||
border-radius: 50%;
|
||||
margin: -3px 0;
|
||||
background: wal.$foreground;
|
||||
margin-left: -1px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+23
-1
@@ -19,7 +19,7 @@
|
||||
& > button {
|
||||
background: colors.$bg-secondary;
|
||||
margin: 0 1px;
|
||||
padding: 0 6px;
|
||||
padding: 4px 6px;
|
||||
border-radius: 2px;
|
||||
|
||||
&:hover {
|
||||
@@ -78,4 +78,26 @@
|
||||
color: colors.$fg-primary;
|
||||
}
|
||||
}
|
||||
|
||||
& trough {
|
||||
background: funs.toRGB(color.adjust($color: wal.$color1, $lightness: -20%));
|
||||
border-radius: 8px;
|
||||
margin: 2px 0;
|
||||
}
|
||||
|
||||
& trough highlight {
|
||||
background: wal.$color1;
|
||||
min-height: .9em;
|
||||
border-top-left-radius: inherit;
|
||||
border-bottom-left-radius: inherit;
|
||||
}
|
||||
|
||||
& trough slider {
|
||||
border-radius: 50%;
|
||||
margin: -2px 0;
|
||||
background: wal.$foreground;
|
||||
margin-left: -1px;
|
||||
min-width: 1.2em;
|
||||
min-height: 1.2em;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
border-radius: 20px;
|
||||
|
||||
.icon {
|
||||
margin-right: 14px;
|
||||
margin-right: 10px;
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
import { Astal, Gtk, Widget } from "astal/gtk3";
|
||||
|
||||
|
||||
const { TOP, BOTTOM, LEFT, RIGHT }: typeof Astal.WindowAnchor = Astal.WindowAnchor;
|
||||
|
||||
/**
|
||||
* Creates a screen-size window and opens the provided window after it.
|
||||
* When clicking in the transparent background window, it closes(hides)
|
||||
* the provided window.
|
||||
* @param window the window to be rendered and closed when clicking outside of it
|
||||
*/
|
||||
export function PopupWindow(window: Gtk.Window) {
|
||||
const bgWindow: Gtk.Window = new Widget.Window({
|
||||
namespace: "popup-bg-window",
|
||||
anchor: TOP | BOTTOM | LEFT | RIGHT,
|
||||
|
||||
} as Widget.WindowProps);
|
||||
}
|
||||
@@ -29,11 +29,15 @@ export function FocusedClient() {
|
||||
new Widget.Label({
|
||||
className: "class",
|
||||
xalign: 0,
|
||||
max_width_chars: 65,
|
||||
truncate: false,
|
||||
label: bind(focusedClient, "class")
|
||||
} as Widget.LabelProps),
|
||||
new Widget.Label({
|
||||
className: "title",
|
||||
xalign: 0,
|
||||
max_width_chars: 48,
|
||||
truncate: false,
|
||||
label: bind(focusedClient, "title")
|
||||
} as Widget.LabelProps)
|
||||
] : []
|
||||
|
||||
@@ -54,6 +54,7 @@ export function Media(): Gtk.Widget {
|
||||
new Widget.Button({
|
||||
className: "next nf",
|
||||
label: "",
|
||||
tooltipText: "Next",
|
||||
onClick: () => players[0].canGoNext && players[0].next()
|
||||
} as Widget.ButtonProps)
|
||||
] : new Widget.Label({
|
||||
|
||||
@@ -1,6 +1,116 @@
|
||||
import { AstalIO, bind, GLib, Process, timeout } from "astal";
|
||||
import { Gtk, Widget } from "astal/gtk3";
|
||||
import AstalMpris from "gi://AstalMpris";
|
||||
|
||||
let dragTimer: (AstalIO.Time|undefined);
|
||||
|
||||
export const BigMedia: Gtk.Widget = new Widget.Box({
|
||||
className: "big-media",
|
||||
//TODO
|
||||
orientation: Gtk.Orientation.VERTICAL,
|
||||
homogeneous: false,
|
||||
children: bind(AstalMpris.get_default(), "players").as((players: Array<AstalMpris.Player>) =>
|
||||
players[0] ? [
|
||||
new Widget.Box({
|
||||
halign: Gtk.Align.CENTER,
|
||||
child: new Widget.Box({
|
||||
className: "image",
|
||||
hexpand: false,
|
||||
orientation: Gtk.Orientation.VERTICAL,
|
||||
visible: bind(players[0], "coverArt").as((coverArt: string) =>
|
||||
coverArt !== ""),
|
||||
css: bind(players[0], "coverArt").as((coverArt: string) =>
|
||||
`.image { background-image: url('${coverArt}'); }`),
|
||||
width_request: 132,
|
||||
height_request: 128
|
||||
} as Widget.BoxProps)
|
||||
} as Widget.BoxProps),
|
||||
new Widget.Box({
|
||||
className: "info",
|
||||
orientation: Gtk.Orientation.VERTICAL,
|
||||
children: [
|
||||
new Widget.Label({
|
||||
className: "title",
|
||||
tooltipText: bind(players[0], "title").as((title: string) => !title ? "No Title" : title),
|
||||
label: bind(players[0], "title").as((title: string) => !title ? "No Title" : title),
|
||||
truncate: true
|
||||
} as Widget.LabelProps),
|
||||
new Widget.Label({
|
||||
className: "artist",
|
||||
tooltipText: bind(players[0], "artist").as((artist: string) => !artist ? "No Artist" : artist),
|
||||
label: bind(players[0], "artist").as((artist: string) => !artist ? "No Artist" : artist),
|
||||
truncate: true
|
||||
} as Widget.LabelProps)
|
||||
]
|
||||
} as Widget.BoxProps),
|
||||
new Widget.Box({
|
||||
className: "progress",
|
||||
hexpand: true,
|
||||
visible: bind(players[0], "canSeek"),
|
||||
children: [
|
||||
/*new Widget.Label({
|
||||
className: "elapsed",
|
||||
label: bind(players[0], "position").as((position: number) =>
|
||||
Math.floor(position).toString())
|
||||
}),*/
|
||||
new Widget.Slider({
|
||||
min: 0,
|
||||
hexpand: true,
|
||||
max: bind(players[0], "length").as((length: number) =>
|
||||
Math.floor(length)),
|
||||
value: bind(players[0], "position").as((position: number) =>
|
||||
Math.floor(position)),
|
||||
onDragged: (slider: Widget.Slider) => {
|
||||
if(dragTimer === undefined)
|
||||
dragTimer = timeout(600, () =>
|
||||
players[0].set_position(Math.round(slider.value)));
|
||||
else {
|
||||
dragTimer.cancel();
|
||||
dragTimer = timeout(600, () =>
|
||||
players[0].set_position(Math.round(slider.value)));
|
||||
}
|
||||
}
|
||||
})
|
||||
]
|
||||
}),
|
||||
new Widget.Box({
|
||||
className: "controls button-row",
|
||||
hexpand: true,
|
||||
halign: Gtk.Align.CENTER,
|
||||
children: [
|
||||
new Widget.Button({
|
||||
className: "link nf",
|
||||
label: "",
|
||||
tooltipText: "Copy link to Clipboard",
|
||||
visible: bind(players[0], "metadata").as((_metadata: GLib.HashTable) =>
|
||||
players[0].get_meta("xesam:url") === null),
|
||||
onClick: () => Process.exec(`wl-copy ${players[0].get_meta("xesam:url")?.get_string()[0]}`)
|
||||
} as Widget.ButtonProps),
|
||||
new Widget.Button({
|
||||
className: "previous nf",
|
||||
label: "",
|
||||
tooltipText: "Previous",
|
||||
onClick: () => players[0].canGoPrevious && players[0].previous()
|
||||
} as Widget.ButtonProps),
|
||||
new Widget.Button({
|
||||
className: "pause nf",
|
||||
tooltipText: bind(players[0], "playback_status").as((status: AstalMpris.PlaybackStatus) =>
|
||||
status === AstalMpris.PlaybackStatus.PLAYING ? "Pause" : "Play"),
|
||||
label: bind(players[0], "playbackStatus").as((status: AstalMpris.PlaybackStatus) =>
|
||||
status === AstalMpris.PlaybackStatus.PLAYING ? "" : ""),
|
||||
onClick: () => {
|
||||
players[0].playbackStatus === AstalMpris.PlaybackStatus.PAUSED ?
|
||||
players[0].play()
|
||||
:
|
||||
players[0].pause()
|
||||
}
|
||||
} as Widget.ButtonProps),
|
||||
new Widget.Button({
|
||||
className: "next nf",
|
||||
label: "",
|
||||
tooltipText: "Next",
|
||||
onClick: () => players[0].canGoNext && players[0].next()
|
||||
} as Widget.ButtonProps)
|
||||
]
|
||||
})
|
||||
] : new Widget.Box({ className: "empty no-media" }))
|
||||
} as Widget.BoxProps);
|
||||
|
||||
@@ -1,12 +1,22 @@
|
||||
import { Gtk, Widget } from "astal/gtk3";
|
||||
|
||||
export const tileList: Array<Gtk.Widget> = [
|
||||
]
|
||||
export const tileList: Array<Gtk.Widget> = [];
|
||||
|
||||
export const Tiles: Widget.Box = new Widget.Box({
|
||||
child: new Gtk.Grid({
|
||||
export function TilesWidget(): Gtk.Widget {
|
||||
const tilesFlowBox: Gtk.FlowBox = new Gtk.FlowBox({
|
||||
visible: true,
|
||||
orientation: Gtk.Orientation.HORIZONTAL,
|
||||
rowHomogeneous: true
|
||||
} as Gtk.Grid.ConstructorProps)
|
||||
} as Widget.BoxProps);
|
||||
noShowAll: false,
|
||||
orientation: Gtk.Orientation.HORIZONTAL
|
||||
} as Gtk.Grid.ConstructorProps);
|
||||
|
||||
tileList.map((item: Gtk.Widget) =>
|
||||
tilesFlowBox.insert(item, -1));
|
||||
|
||||
return new Widget.Box({
|
||||
children: [
|
||||
tilesFlowBox
|
||||
]
|
||||
} as Widget.BoxProps);
|
||||
}
|
||||
|
||||
export const Tiles: Gtk.Widget = TilesWidget();
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
import { Binding } from "astal";
|
||||
import { Gtk, Widget } from "astal/gtk3";
|
||||
|
||||
export interface MoreTileProps {
|
||||
className?: string | Binding<string | undefined>;
|
||||
iconName?: string | Binding<string | undefined>;
|
||||
iconSize?: Gtk.IconSize;
|
||||
title: string | Binding<string>;
|
||||
description?: string | Binding<string | undefined>;
|
||||
defaultToggleState?: boolean;
|
||||
onToggledOn: Function;
|
||||
onToggledOff: Function;
|
||||
onClickMore: Function;
|
||||
}
|
||||
|
||||
export function MoreTile(props: MoreTileProps): Gtk.Widget {
|
||||
|
||||
let toggleState: boolean = props?.defaultToggleState !== undefined ?
|
||||
props.defaultToggleState : false;
|
||||
|
||||
const mainEventBox = new Widget.EventBox({
|
||||
onClick: () => toggleState ? props.onToggledOff() : props.onToggledOn(),
|
||||
expand: true,
|
||||
child: new Widget.Box({
|
||||
className: props?.className || "",
|
||||
expand: true,
|
||||
children: [
|
||||
new Widget.Icon({
|
||||
iconName: props?.iconName,
|
||||
visible: props.iconName !== undefined,
|
||||
iconSize: props.iconSize || Gtk.IconSize.BUTTON
|
||||
}),
|
||||
new Widget.Box({
|
||||
className: "text",
|
||||
orientation: Gtk.Orientation.VERTICAL,
|
||||
children: [
|
||||
new Widget.Label({
|
||||
className: "title",
|
||||
label: props.title
|
||||
} as Widget.LabelProps),
|
||||
new Widget.Label({
|
||||
className: "description",
|
||||
visible: props?.description !== undefined,
|
||||
label: props?.description
|
||||
} as Widget.LabelProps)
|
||||
]
|
||||
} as Widget.BoxProps),
|
||||
new Widget.Button({
|
||||
onClick: () => props.onClickMore(),
|
||||
child: new Widget.Icon({
|
||||
iconName: "go-next",
|
||||
iconSize: Gtk.IconSize.BUTTON
|
||||
} as Widget.IconProps),
|
||||
} as Widget.ButtonProps)
|
||||
]
|
||||
} as Widget.BoxProps)
|
||||
} as Widget.EventBoxProps);
|
||||
|
||||
return mainEventBox;
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
import { Binding, Variable } from "astal";
|
||||
import { Gtk, Widget } from "astal/gtk3";
|
||||
|
||||
export interface NormalTileProps {
|
||||
className?: string | Binding<string | undefined>;
|
||||
iconName?: string | Binding<string | undefined>;
|
||||
iconSize?: Gtk.IconSize;
|
||||
title: string | Binding<string>;
|
||||
description?: string | Binding<string | undefined>;
|
||||
toggleState?: boolean | Binding<boolean | undefined>;
|
||||
onToggledOn: Function;
|
||||
onToggledOff: Function;
|
||||
}
|
||||
|
||||
export function MoreTile(props: NormalTileProps): Gtk.Widget {
|
||||
|
||||
const mainEventBox = new Widget.EventBox({
|
||||
onClick: () => toggleState ? props.onToggledOff() : props.onToggledOn(),
|
||||
expand: true,
|
||||
child: new Widget.Box({
|
||||
className: props?.className || "",
|
||||
expand: true,
|
||||
children: [
|
||||
new Widget.Icon({
|
||||
iconName: props?.iconName,
|
||||
visible: props.iconName !== undefined,
|
||||
iconSize: props.iconSize || Gtk.IconSize.BUTTON
|
||||
}),
|
||||
new Widget.Box({
|
||||
className: "text",
|
||||
orientation: Gtk.Orientation.VERTICAL,
|
||||
children: [
|
||||
new Widget.Label({
|
||||
className: "title",
|
||||
label: props.title
|
||||
} as Widget.LabelProps),
|
||||
new Widget.Label({
|
||||
className: "description",
|
||||
visible: props?.description !== undefined,
|
||||
label: props?.description
|
||||
} as Widget.LabelProps)
|
||||
]
|
||||
} as Widget.BoxProps)
|
||||
]
|
||||
} as Widget.BoxProps)
|
||||
} as Widget.EventBoxProps);
|
||||
|
||||
function toggleOn(): void {
|
||||
mainEventBox.set_class_name(mainEventBox + "")
|
||||
props.onToggledOn();
|
||||
}
|
||||
|
||||
function toggleOff(): void {
|
||||
props.onToggledOff();
|
||||
}
|
||||
|
||||
return mainEventBox;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import { Binding } from "astal";
|
||||
import { Gtk, Widget } from "astal/gtk3";
|
||||
|
||||
export type TileProps = {
|
||||
className?: string | Binding<string | undefined>;
|
||||
iconName?: string | Binding<string | undefined>;
|
||||
visible?: boolean | Binding<boolean | undefined>;
|
||||
iconSize?: number | Binding<number | undefined>;
|
||||
title: string | Binding<string>;
|
||||
description?: string | Binding<string | undefined>;
|
||||
defaultToggleState?: boolean;
|
||||
onToggledOn: () => void;
|
||||
onToggledOff: () => void;
|
||||
onClickMore?: () => void;
|
||||
}
|
||||
|
||||
export function Tile(props: TileProps): Widget.Box {
|
||||
|
||||
const toggleButton = new Gtk.ToggleButton();
|
||||
toggleButton.set_active(props.defaultToggleState || false);
|
||||
|
||||
const moreButton = new Widget.Button({
|
||||
className: "more",
|
||||
visible: props.onClickMore
|
||||
});
|
||||
|
||||
return new Widget.Box({
|
||||
className: (typeof Binding<string | undefined>) === (typeof props.className) ?
|
||||
(props.className as Binding<string | undefined>).as((clsName: (string|undefined)) =>
|
||||
`tile ${clsName || ""}`)
|
||||
:
|
||||
props.className,
|
||||
visible: props.visible,
|
||||
children: [
|
||||
toggleButton,
|
||||
moreButton
|
||||
]
|
||||
})
|
||||
}
|
||||
+2
-3
@@ -1,4 +1,4 @@
|
||||
import { Gdk, Astal, Gtk, Widget } from "astal/gtk3";
|
||||
import { Astal, Gtk, Widget } from "astal/gtk3";
|
||||
|
||||
import { Clock } from "../widget/bar/Clock";
|
||||
import { Logo } from "../widget/bar/Logo";
|
||||
@@ -11,12 +11,11 @@ import { Media } from "../widget/bar/Media";
|
||||
export const Bar: Widget.Window = new Widget.Window({
|
||||
monitor: 0,
|
||||
namespace: "top-bar",
|
||||
anchor: Astal.WindowAnchor.TOP,
|
||||
anchor: Astal.WindowAnchor.TOP | Astal.WindowAnchor.LEFT | Astal.WindowAnchor.RIGHT,
|
||||
layer: Astal.Layer.TOP,
|
||||
exclusivity: Astal.Exclusivity.EXCLUSIVE,
|
||||
canFocus: false,
|
||||
visible: true,
|
||||
widthRequest: Gdk.Screen.get_default()?.get_monitor_geometry(0)?.width,
|
||||
child: new Widget.Box({
|
||||
className: "bar-container",
|
||||
child: new Widget.CenterBox({
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Astal, Gtk, Widget } from "astal/gtk3";
|
||||
import { GLib } from "astal";
|
||||
|
||||
import { getDateTime } from "../scripts/time";
|
||||
import { BigMedia } from "../widget/center-window/BigMedia";
|
||||
|
||||
export const CenterWindow: Widget.Window = new Widget.Window({
|
||||
className: "center-window",
|
||||
@@ -25,6 +26,7 @@ export const CenterWindow: Widget.Window = new Widget.Window({
|
||||
new Widget.Box({
|
||||
className: "top",
|
||||
orientation: Gtk.Orientation.VERTICAL,
|
||||
valign: Gtk.Align.START,
|
||||
children: [
|
||||
new Widget.Label({
|
||||
className: "time",
|
||||
@@ -38,6 +40,7 @@ export const CenterWindow: Widget.Window = new Widget.Window({
|
||||
} as Widget.LabelProps)
|
||||
]
|
||||
} as Widget.BoxProps),
|
||||
BigMedia
|
||||
]
|
||||
} as Widget.BoxProps),
|
||||
new Widget.Box({
|
||||
|
||||
@@ -3,10 +3,65 @@ import AstalNotifd from "gi://AstalNotifd";
|
||||
import { bind } from "astal";
|
||||
import { Notifications } from "../scripts/notification-handler";
|
||||
|
||||
function NotificationWidget(notification: AstalNotifd.Notification): Gtk.Widget {
|
||||
return new Widget.Box({
|
||||
className: "notification",
|
||||
homogeneous: false,
|
||||
expand: false,
|
||||
orientation: Gtk.Orientation.VERTICAL,
|
||||
children: [
|
||||
new Widget.Box({
|
||||
className: "top",
|
||||
orientation: Gtk.Orientation.HORIZONTAL,
|
||||
hexpand: true,
|
||||
vexpand: false,
|
||||
children: [
|
||||
new Widget.Label({
|
||||
className: "app-name",
|
||||
halign: Gtk.Align.START,
|
||||
label: notification.appName || "Unknown Application"
|
||||
} as Widget.LabelProps),
|
||||
new Widget.Button({
|
||||
className: "close-button",
|
||||
onClick: () => Notifications.removeNotification(notification.id)
|
||||
} as Widget.ButtonProps)
|
||||
]
|
||||
} as Widget.BoxProps),
|
||||
new Widget.Box({
|
||||
className: "content",
|
||||
orientation: Gtk.Orientation.HORIZONTAL,
|
||||
children: [
|
||||
new Widget.Box({
|
||||
className: "image",
|
||||
visible: notification.image !== "",
|
||||
css: `box.image { background-image: url('${notification.image}'); }`
|
||||
} as Widget.BoxProps),
|
||||
new Widget.Box({
|
||||
className: "text",
|
||||
orientation: Gtk.Orientation.VERTICAL,
|
||||
children: [
|
||||
new Widget.Label({
|
||||
className: "summary",
|
||||
useMarkup: true,
|
||||
label: notification.summary
|
||||
}),
|
||||
new Widget.Label({
|
||||
className: "body",
|
||||
useMarkup: true,
|
||||
label: notification.body
|
||||
} as Widget.LabelProps)
|
||||
]
|
||||
} as Widget.BoxProps)
|
||||
]
|
||||
} as Widget.BoxProps)
|
||||
]
|
||||
} as Widget.BoxProps);
|
||||
}
|
||||
|
||||
export const FloatingNotifications: Widget.Window = new Widget.Window({
|
||||
namespace: "floating-notifications",
|
||||
canFocus: false,
|
||||
anchor: Astal.WindowAnchor.RIGHT,
|
||||
anchor: Astal.WindowAnchor.TOP | Astal.WindowAnchor.RIGHT,
|
||||
monitor: 0,
|
||||
layer: Astal.Layer.OVERLAY,
|
||||
visible: false,
|
||||
@@ -16,62 +71,8 @@ export const FloatingNotifications: Widget.Window = new Widget.Window({
|
||||
className: "floating-notifications-container",
|
||||
orientation: Gtk.Orientation.VERTICAL,
|
||||
homogeneous: false,
|
||||
children: bind(Notifications, "notifications").as((notifications: Array<AstalNotifd.Notification>) => {
|
||||
console.log("something changed!");
|
||||
return notifications.map((notification: AstalNotifd.Notification) =>
|
||||
new Widget.Box({
|
||||
className: "notification",
|
||||
homogeneous: false,
|
||||
expand: false,
|
||||
orientation: Gtk.Orientation.VERTICAL,
|
||||
children: [
|
||||
new Widget.Box({
|
||||
className: "top",
|
||||
orientation: Gtk.Orientation.HORIZONTAL,
|
||||
hexpand: true,
|
||||
vexpand: false,
|
||||
children: [
|
||||
new Widget.Label({
|
||||
className: "app-name",
|
||||
halign: Gtk.Align.START,
|
||||
label: notification.appName || "Unknown Application"
|
||||
} as Widget.LabelProps),
|
||||
new Widget.Button({
|
||||
className: "close-button",
|
||||
onClick: () => Notifications.removeNotification(notification.id)
|
||||
} as Widget.ButtonProps)
|
||||
]
|
||||
} as Widget.BoxProps),
|
||||
new Widget.Box({
|
||||
className: "content",
|
||||
orientation: Gtk.Orientation.HORIZONTAL,
|
||||
children: [
|
||||
new Widget.Box({
|
||||
className: "image",
|
||||
visible: notification.image !== "",
|
||||
css: `.image { background-image: url('${notification.image}'); }`
|
||||
} as Widget.BoxProps),
|
||||
new Widget.Box({
|
||||
className: "text",
|
||||
orientation: Gtk.Orientation.VERTICAL,
|
||||
children: [
|
||||
new Widget.Label({
|
||||
className: "summary",
|
||||
useMarkup: true,
|
||||
label: notification.summary
|
||||
}),
|
||||
new Widget.Label({
|
||||
className: "body",
|
||||
useMarkup: true,
|
||||
label: notification.body
|
||||
} as Widget.LabelProps)
|
||||
]
|
||||
} as Widget.BoxProps)
|
||||
]
|
||||
} as Widget.BoxProps)
|
||||
]
|
||||
} as Widget.BoxProps)
|
||||
)
|
||||
})
|
||||
children: bind(Notifications, "notifications").as((notifications: Array<AstalNotifd.Notification>) =>
|
||||
notifications.map((notification: AstalNotifd.Notification) =>
|
||||
NotificationWidget(notification)))
|
||||
} as Widget.BoxProps)
|
||||
} as Widget.WindowProps);
|
||||
|
||||
@@ -12,8 +12,6 @@ export const LogoutMenu: Widget.Window = new Widget.Window({
|
||||
exclusivity: Astal.Exclusivity.IGNORE,
|
||||
monitor: 0,
|
||||
visible: false,
|
||||
widthRequest: Gdk.Screen.get_default()?.get_monitor_geometry(0)?.width,
|
||||
height_request: Gdk.Screen.get_default()?.get_monitor_geometry(0)?.height,
|
||||
child: new Widget.EventBox({
|
||||
className: "logout-menu",
|
||||
onClick: () => Process.exec_async("astal close logout-menu", () => {}),
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { bind, Binding, Variable } from "astal";
|
||||
import { Astal, Gtk, Widget } from "astal/gtk3";
|
||||
import { Wireplumber } from "../scripts/volume";
|
||||
import AstalWp from "gi://AstalWp?version=0.1";
|
||||
|
||||
export enum OSDModes {
|
||||
SINK,
|
||||
|
||||
Reference in New Issue
Block a user