refactor(ags): improve typecheck and fix bugs

This commit is contained in:
matt1432 2023-12-19 12:28:29 -05:00
parent da30e6f05f
commit a126d97bbf
12 changed files with 201 additions and 157 deletions

View file

@ -1,15 +1,12 @@
import { Label } from 'resource:///com/github/Aylur/ags/widget.js';
export default () => Label({
className: 'clock',
connections: [[1000, (self) => {
export default () => Label({ className: 'clock' })
.poll(1000, (self) => {
const time = imports.gi.GLib
.DateTime.new_now_local();
.DateTime.new_now_local();
self.label = time.format('%a. ') +
time.get_day_of_month() +
time.format(' %b. %H:%M');
}]],
})
});

View file

@ -9,7 +9,7 @@ export const NotifPopups = () => PopupWindow({
anchor: ['bottom', 'left'],
visible: true,
transition: 'none',
closeOnUnfocus: 'stay',
close_on_unfocus: 'stay',
monitor: 1,
child: PopUpsWidget(),

View file

@ -11,7 +11,7 @@ const SPACING = 4;
/**
* @param {Label} self
* @param {string} layout
* @param {void} _
* @param {string} _
*/
const getKbdLayout = (self, _, layout) => {
if (layout) {

View file

@ -9,12 +9,16 @@ export default () => CursorBox({
on_primary_click_release: () => Tablet.toggleOsk(),
setup: (self) => {
self.hook(Tablet, () => {
self.toggleClassName('toggle-on', Tablet.oskState);
}, 'osk-toggled');
},
child: Label({
class_name: 'osk-toggle',
xalign: 0.6,
label: '󰌌 ',
}),
}).hook(Tablet, (self) => {
self.toggleClassName('toggle-on', Tablet.oskState);
}, 'osk-toggled');
});

View file

@ -38,39 +38,50 @@ const SysTray = () => MenuBar({
},
setup: (self) => {
/**
* @param {import('types/widget').default} _
* @param {string} id
*/
const addTray = (_, id) => {
const item = SystemTray.getItem(id);
if (self.attribute.items.has(id) || !item) {
return;
}
const w = SysTrayItem(item);
// Early return if item is in blocklist
if (!w) {
return;
}
self.attribute.items.set(id, w);
self.child = w;
self.show_all();
// @ts-expect-error
w.child.reveal_child = true;
};
/**
* @param {import('types/widget').default} _
* @param {string} id
*/
const removeTray = (_, id) => {
if (!self.attribute.items.has(id)) {
return;
}
self.attribute.items.get(id).child.reveal_child = false;
timeout(REVEAL_DURATION, () => {
self.attribute.items.get(id).destroy();
self.attribute.items.delete(id);
});
};
self
.hook(SystemTray, (_, id) => {
const item = SystemTray.getItem(id);
if (self.attribute.items.has(id) || !item) {
return;
}
const w = SysTrayItem(item);
// Early return if item is in blocklist
if (!w) {
return;
}
self.attribute.items.set(id, w);
self.child = w;
self.show_all();
// @ts-expect-error
w.child.reveal_child = true;
}, 'added')
.hook(SystemTray, (_, id) => {
if (!self.attribute.items.has(id)) {
return;
}
self.attribute.items.get(id).child.reveal_child = false;
timeout(REVEAL_DURATION, () => {
self.attribute.items.get(id).destroy();
self.attribute.items.delete(id);
});
}, 'removed');
.hook(SystemTray, addTray, 'added')
.hook(SystemTray, removeTray, 'removed');
},
});

View file

@ -9,12 +9,16 @@ export default () => CursorBox({
on_primary_click_release: () => Tablet.toggleMode(),
setup: (self) => {
self.hook(Tablet, () => {
self.toggleClassName('toggle-on', Tablet.tabletMode);
}, 'mode-toggled');
},
child: Box({
class_name: 'tablet-toggle',
vertical: false,
children: [Label(' 󰦧 ')],
}),
}).hook(Tablet, (self) => {
self.toggleClassName('toggle-on', Tablet.tabletMode);
}, 'mode-toggled');
});

View file

@ -7,8 +7,6 @@ import CursorBox from '../../misc/cursorbox.js';
const URGENT_DURATION = 1000;
/** @typedef {import('types/widget.js').Widget} Widget */
/** @property {number} id */
const Workspace = ({ id }) => {
@ -17,7 +15,7 @@ const Workspace = ({ id }) => {
attribute: { id },
child: CursorBox({
tooltipText: `${id}`,
tooltip_text: `${id}`,
on_primary_click_release: () => {
Hyprland.sendMessage(`dispatch workspace ${id}`);
@ -29,7 +27,7 @@ const Workspace = ({ id }) => {
setup: (self) => {
/**
* @param {Widget} _
* @param {import('types/widgets/box').default} _
* @param {string|undefined} addr
*/
const update = (_, addr) => {
@ -80,11 +78,11 @@ export default () => {
const L_PADDING = 16;
const WS_WIDTH = 30;
/** @param {Widget} self */
/** @param {import('types/widgets/box').default} self */
const updateHighlight = (self) => {
const currentId = Hyprland.active.workspace.id;
// @ts-expect-error
const indicators = self.get_parent().get_children()[0].child.child.children;
const indicators = self?.get_parent()?.child.child.child.children;
const currentIndex = Array.from(indicators)
.findIndex((w) => w.attribute.id === currentId);
@ -92,7 +90,6 @@ export default () => {
return;
}
// @ts-expect-error
self.setCss(`margin-left: ${L_PADDING + (currentIndex * WS_WIDTH)}px`);
};
@ -100,6 +97,7 @@ export default () => {
vpack: 'center',
hpack: 'start',
class_name: 'button active',
}).hook(Hyprland.active.workspace, updateHighlight);
const widget = Overlay({
@ -118,7 +116,7 @@ export default () => {
rev.reveal_child = false;
});
Array.from(self.attribute.workspaces).forEach((ws) => {
ws.revealChild = true;
ws.reveal_child = true;
});
};

View file

@ -35,20 +35,27 @@ export default (props) => {
vertical: true,
setup: (self) => {
const checkCurrentWsFsState = () => {
const workspace = Hyprland.getWorkspace(
Hyprland.active.workspace.id,
);
if (workspace) {
Revealed.value = !workspace['hasfullscreen'];
}
};
/**
* @param {import('types/widgets/box').default} _
* @param {boolean} fullscreen
*/
const checkGlobalFsState = (_, fullscreen) => {
Revealed.value = !fullscreen;
};
self
.hook(Hyprland.active, () => {
const workspace = Hyprland.getWorkspace(
Hyprland.active.workspace.id,
);
if (workspace) {
Revealed.value = !workspace['hasfullscreen'];
}
})
.hook(Hyprland, (_, fullscreen) => {
Revealed.value = !fullscreen;
}, 'fullscreen');
.hook(Hyprland.active, checkCurrentWsFsState)
.hook(Hyprland, checkGlobalFsState, 'fullscreen');
},
children: [

View file

@ -10,11 +10,17 @@ const TRANSITION = `transition: margin ${ANIM_DURATION}ms ease,
opacity ${ANIM_DURATION}ms ease;`;
/**
* @typedef {import('types/widgets/overlay').OverlayProps} OverlayProps
* @typedef {import('types/widgets/overlay').default} Overlay
*
* @param {OverlayProps & {
* setup?: function(Overlay):void
* }} o
*/
export default ({
attribute = {},
setup = (self) => {
self;
},
setup = () => {/**/},
...props
}) => {
const widget = EventBox();
@ -36,6 +42,7 @@ export default ({
// @ts-expect-error
.filter((ch) => !ch.attribute?.empty),
/** @param {Overlay} playerW */
includesWidget: (playerW) => {
return Array.from(content.attribute.list())
.find((w) => w === playerW);
@ -46,6 +53,7 @@ export default ({
over.visible = over === content.attribute.list().at(-1);
}),
/** @param {import('types/widgets/centerbox').default} player */
moveToTop: (player) => {
player.visible = true;
content.reorder_overlay(player, -1);
@ -61,102 +69,113 @@ export default ({
setup(self);
self
.hook(gesture, (overlay, realGesture) => {
if (realGesture) {
Array.from(overlay.attribute.list()).forEach((over) => {
over.visible = true;
});
}
else {
overlay.attribute.showTopOnly();
}
.hook(gesture,
/**
* @param {Overlay} overlay
* @param {number} realGesture
*/
(overlay, realGesture) => {
if (realGesture) {
Array.from(overlay.attribute.list())
.forEach((over) => {
over.visible = true;
});
}
else {
overlay.attribute.showTopOnly();
}
// Don't allow gesture when only one player
if (overlay.attribute.list().length <= 1) {
return;
}
// Don't allow gesture when only one player
if (overlay.attribute.list().length <= 1) {
return;
}
overlay.attribute.dragging = true;
let offset = gesture.get_offset()[1];
const playerBox = overlay.attribute.list().at(-1);
overlay.attribute.dragging = true;
let offset = gesture.get_offset()[1];
const playerBox = overlay.attribute.list().at(-1);
if (!offset) {
return;
}
if (!offset) {
return;
}
// Slide right
if (offset >= 0) {
playerBox.setCss(`
// Slide right
if (offset >= 0) {
playerBox.setCss(`
margin-left: ${offset}px;
margin-right: -${offset}px;
${playerBox.attribute.bgStyle}
`);
}
}
// Slide left
else {
offset = Math.abs(offset);
playerBox.setCss(`
// Slide left
else {
offset = Math.abs(offset);
playerBox.setCss(`
margin-left: -${offset}px;
margin-right: ${offset}px;
${playerBox.attribute.bgStyle}
`);
}
}, 'drag-update')
}
},
'drag-update')
.hook(gesture, (overlay) => {
// Don't allow gesture when only one player
if (overlay.attribute.list().length <= 1) {
return;
}
overlay.attribute.dragging = false;
const offset = gesture.get_offset()[1];
.hook(gesture,
/** @param {Overlay} overlay */
(overlay) => {
// Don't allow gesture when only one player
if (overlay.attribute.list().length <= 1) {
return;
}
const playerBox = overlay.attribute.list().at(-1);
overlay.attribute.dragging = false;
const offset = gesture.get_offset()[1];
// If crosses threshold after letting go, slide away
if (offset && Math.abs(offset) > MAX_OFFSET) {
// Disable inputs during animation
widget.sensitive = false;
const playerBox = overlay.attribute.list().at(-1);
// Slide away right
if (offset >= 0) {
playerBox.setCss(`
// If crosses threshold after letting go, slide away
if (offset && Math.abs(offset) > MAX_OFFSET) {
// Disable inputs during animation
widget.sensitive = false;
// Slide away right
if (offset >= 0) {
playerBox.setCss(`
${TRANSITION}
margin-left: ${OFFSCREEN}px;
margin-right: -${OFFSCREEN}px;
opacity: 0.7; ${playerBox.attribute.bgStyle}
`);
}
}
// Slide away left
else {
playerBox.setCss(`
// Slide away left
else {
playerBox.setCss(`
${TRANSITION}
margin-left: -${OFFSCREEN}px;
margin-right: ${OFFSCREEN}px;
opacity: 0.7; ${playerBox.attribute.bgStyle}
`);
}
timeout(ANIM_DURATION, () => {
// Put the player in the back after anim
overlay.reorder_overlay(playerBox, 0);
// Recenter player
playerBox.setCss(playerBox.attribute.bgStyle);
widget.sensitive = true;
overlay.attribute.showTopOnly();
});
}
timeout(ANIM_DURATION, () => {
// Put the player in the back after anim
overlay.reorder_overlay(playerBox, 0);
// Recenter player
playerBox.setCss(playerBox.attribute.bgStyle);
widget.sensitive = true;
overlay.attribute.showTopOnly();
});
}
else {
// Recenter with transition for animation
playerBox.setCss(`${TRANSITION}
else {
// Recenter with transition for animation
playerBox.setCss(`${TRANSITION}
${playerBox.attribute.bgStyle}`);
}
}, 'drag-end');
}
},
'drag-end');
},
});

View file

@ -5,11 +5,11 @@ import { EventBox } from 'resource:///com/github/Aylur/ags/widget.js';
const { Gtk } = imports.gi;
// TODO: wrap in another EventBox for disabled cursor
/**
* @typedef {import('types/widgets/eventbox').EventBoxProps} EventBox
* @typedef {import('types/widgets/eventbox').EventBoxProps} EventBoxProps
* @typedef {import('types/widgets/eventbox').default} EventBox
*
* @param {EventBox & {
* @param {EventBoxProps & {
* on_primary_click_release?: function(EventBox):void
* }} o
*/
@ -23,22 +23,7 @@ export default ({
const CanRun = Variable(true);
const Disabled = Variable(false);
const widget = EventBox({
...props,
sensitive: Disabled.bind().transform((v) => !v),
on_primary_click_release: (self) => {
// Every click, do a one shot connect to
// CanRun to wait for location of click
const id = CanRun.connect('changed', () => {
if (CanRun.value) {
on_primary_click_release(self);
}
CanRun.disconnect(id);
});
},
});
let widget; // eslint-disable-line
const wrapper = EventBox({
cursor: 'pointer',
@ -55,14 +40,31 @@ export default ({
},
},
child: widget,
}).hook(Disabled, (self) => {
self.cursor = Disabled.value ?
'not-allowed' :
'pointer';
});
widget = EventBox({
...props,
sensitive: Disabled.bind().transform((v) => !v),
on_primary_click_release: () => {
// Every click, do a one shot connect to
// CanRun to wait for location of click
const id = CanRun.connect('changed', () => {
if (CanRun.value) {
on_primary_click_release(wrapper);
}
CanRun.disconnect(id);
});
},
});
wrapper.child = widget;
const gesture = Gtk.GestureLongPress.new(widget);
widget.hook(gesture, () => {

View file

@ -16,6 +16,7 @@ export const NotifPopups = () => PopupWindow({
const TOP_MARGIN = 6;
// FIXME: opens at wrong place
export const NotifCenter = () => PopupWindow({
name: 'notification-center',
anchor: ['top', 'right'],

View file

@ -7,6 +7,7 @@ import PopupWindow from './misc/popup.js';
import CursorBox from './misc/cursorbox.js';
// FIXME: eventboxes are the wrong size
const PowermenuWidget = () => CenterBox({
class_name: 'powermenu',
// @ts-expect-error