This commit is contained in:
2024-07-08 11:57:27 +07:00
parent 9ec3402f4a
commit 21c5d8c692
9 changed files with 119 additions and 200 deletions
+8 -7
View File
@@ -1,7 +1,7 @@
import { Bar } from "./layouts/bar.js";
import { Notifications } from "./layouts/notifications.js";
// import { OSD } from "./layouts/osd.js";
import { Quicksettings } from "./layouts/quicksettings.js";
import { Notifications } from "./layouts/notifications.js";
import { OSD } from "./layouts/osd.js";
import { Quicksettings } from "./layouts/quicksettings.js";
import Gtk from "gi://Gtk?version=3.0";
import Gdk from "gi://Gdk";
@@ -17,13 +17,14 @@ export function forMonitors(widget) {
App.config({
closeWindowDelay: {
quicksettings: 300,
notifications: 300,
notifications: 200,
osd: 300,
},
style: `${App.configDir}/style.css`,
windows: [
...forMonitors(Bar),
Quicksettings(),
Notifications(),
// OSD(),
Quicksettings(),
Notifications(),
OSD(),
],
});
+82 -83
View File
@@ -1,86 +1,85 @@
import { lookUpIcon } from 'resource:///com/github/Aylur/ags/utils.js';
import { Window, Revealer, Stack, Box, Icon } from 'resource:///com/github/Aylur/ags/widget.js'
import { FontIcon, Progress } from "../misc.js";
import Indicator from "../services/osd.js";
import { getIcon } from "../modules/audio.js";
import brightness from "../services/brightness.js";
export const OSD = () =>
Window({
name: "osd",
popup: true,
// Follow active monitor
monitor: undefined,
visible: false,
layer: "overlay",
anchor: ["bottom"],
child: Revealer({
transition: "crossfade",
connections: [
[
Indicator,
(revealer, value) => {
revealer.revealChild = value > -1;
},
],
],
child: Box({
className: "osd bgcont osd",
vpack: "center",
hpack: "center",
children: [
Stack({
vpack: "center",
hpack: "center",
css: "padding: 20px;",
hexpand: false,
items: [
[
"true",
Icon({
hpack: "center",
vpack: "center",
size: 40,
connections: [[Indicator, (icon, _v, name) => (icon.icon = name || "")]],
}),
],
[
"false",
FontIcon({
hpack: "center",
vpack: "center",
hexpand: true,
css: `font-size: 40px;`,
connections: [[Indicator, ({ label }, _v, name) => (label.label = name || "")]],
}),
],
],
connections: [
[
Indicator,
(stack, _v, name) => {
stack.shown = `${!!lookUpIcon(name)}`;
},
],
],
}),
Progress({
width: 200,
height: 10,
hpack: "center",
vpack: "center",
css: "margin-right: 20px;",
hexpand: false,
vexpand: false,
connections: [
[
Indicator,
(progress, value, icon) => {
if (!icon) return;
progress.setValue(value, icon.startsWith("audio") ? 1.5 : 1);
},
],
],
}),
],
}),
const audio = await Service.import("audio");
const DELAY = 1000;
function OnScreenProgress() {
const indicator = Widget.Icon({
vpack: "start",
hpack: "center",
size: 30,
css: "padding-right: 12px;",
});
const progress = Widget.Slider({
drawValue: false,
hexpand: true,
});
const revealer = Widget.Revealer({
transition: "crossfade",
css: "opacity: 0",
revealChild: true,
vpack: "center",
hpack: "center",
child: Widget.Box({
vpack: "center",
hpack: "center",
className: "osd bgcount",
css: "padding: 20px;",
children: [indicator, progress],
}),
});
// Prevent OSD to be shown when starting ags.
Utils.timeout(DELAY * 2, () => {
revealer.css = "opacity: 1";
});
let count = 0;
/**
* @param {number} value
* @param {string} icon
*/
function show(value, icon) {
revealer.reveal_child = true;
indicator.icon = icon;
progress.value = value;
count++;
Utils.timeout(DELAY, () => {
count--;
if (count === 0) revealer.reveal_child = false;
});
}
return revealer
.hook(
brightness,
() => show(brightness.screen, "display-brightness-symbolic"),
"notify::screen",
)
.hook(
audio.speaker,
() => show(audio.speaker.volume, getIcon(audio.speaker.volume * 100)),
"notify::volume",
)
.hook(
audio.speaker,
() =>
show(
audio.speaker.is_muted ? 0 : audio.speaker.volume,
audio.speaker.is_muted
? "audio-volume-muted-symbolic"
: getIcon(audio.speaker.volume * 100),
),
"notify::is-muted",
);
}
export const OSD = () =>
Widget.Window({
name: "osd",
className: "indicator",
layer: "overlay",
clickThrough: true,
anchor: ["bottom"],
child: OnScreenProgress(),
});
@@ -126,6 +126,7 @@ export const Quicksettings = () =>
exclusivity: "exclusive",
transition: "slide_down",
layout: "top-right",
duration: 300,
child: Widget.Box({
vertical: true,
className: "bgcont qs-container",
+21 -7
View File
@@ -1,5 +1,10 @@
import { icon } from "../misc/utils.js";
import { Arrow, Menu, SettingsButton, SimpleToggleButton } from "../misc/menu.js";
import {
Arrow,
Menu,
SettingsButton,
SimpleToggleButton,
} from "../misc/menu.js";
const audio = await Service.import("audio");
@@ -11,6 +16,12 @@ const volumeIcons = /** @type {const} */ ([
[0, "muted"],
]);
/** @param {number} volume */
export const getIcon = (volume) => {
const icon = volumeIcons.find(([threshold]) => threshold <= volume)?.[1];
return `audio-volume-${icon}-symbolic`;
};
/** @param {{type?: "speaker" | "microphone"} & import("types/widgets/icon").IconProps} props */
export const VolumeIndicator = ({ type = "speaker", ...props }) =>
Widget.Icon(props).hook(audio, (self) => {
@@ -20,8 +31,7 @@ export const VolumeIndicator = ({ type = "speaker", ...props }) =>
return;
}
const vol = audio[type].volume * 100;
const icon = volumeIcons.find(([threshold]) => threshold <= vol)?.[1];
self.icon = `audio-volume-${icon}-symbolic`;
self.icon = getIcon(vol);
self.tooltip_text = `Volume: ${Math.floor(vol)}%`;
});
@@ -38,7 +48,7 @@ export const MicrophoneIndicator = (props) =>
const VolumeSlider = ({ type = "speaker", ...props }) =>
Widget.Slider({
hexpand: true,
draw_value: false,
drawValue: false,
onChange: ({ value, dragging }) => {
if (dragging) {
audio[type].volume = value;
@@ -101,9 +111,13 @@ export const MuteToggle = ({ ...props } = {}) =>
.bind("is_muted")
.as((x) => (x ? "Unmute" : "Mute")),
}),
activate: () => (audio.microphone.is_muted = true),
deactivate: () => (audio.microphone.is_muted = false),
connection: [audio.microphone, () => audio.microphone.is_muted],
activate: () => {
audio.microphone.is_muted = true;
},
deactivate: () => {
audio.microphone.is_muted = false;
},
connection: [audio.microphone, () => audio.microphone.is_muted || false],
...props,
});
+1 -1
View File
@@ -245,7 +245,7 @@ export const Placeholder = (props) =>
/** @param {import("types/widgets/button").ButtonProps} props */
export const ClearButton = (props) =>
Widget.Button({
className: "button surface",
className: "surface r20 p10",
onClicked: () => notifications.clear(),
sensitive: notifications.bind("notifications").as((x) => x.length > 0),
child: Widget.Box({
+2 -2
View File
@@ -6,7 +6,7 @@ const systemtray = await Service.import("systemtray");
export const Toggle = (props) =>
ArrowToggleButton({
name: "systray",
icon: Widget.Icon({ className: "qs-icon" }),
icon: Widget.Icon({ icon: "open-menu-symbolic", className: "qs-icon" }),
label: Widget.Label("Systray"),
activate: () => {},
deactivate: () => {},
@@ -18,7 +18,7 @@ export const Toggle = (props) =>
export const Selection = (props) =>
Menu({
name: "systray",
icon: Widget.Icon(),
icon: Widget.Icon("open-menu-symbolic"),
title: "Systray",
content: [
Widget.Box({
@@ -16,7 +16,6 @@ class Brightness extends Service {
set screen(percent) {
if (percent < 0) percent = 0;
if (percent > 1) percent = 1;
Utils.execAsync(`brightnessctl s ${percent * 100}% -q`)
-82
View File
@@ -1,82 +0,0 @@
import App from 'resource:///com/github/Aylur/ags/app.js';
import Service from 'resource:///com/github/Aylur/ags/service.js';
import Audio from 'resource:///com/github/Aylur/ags/service/audio.js';
import Brightness from '../services/brightness.js';
import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
class Indicator extends Service {
static {
Service.register(this, {
'popup': ['double', 'string'],
});
}
#openned = false
#delay = 1500;
#count = 0;
/**
* @param {number} value - 0 < v < 1
* @param {string} icon
*/
popup(value, icon) {
if (!this.#openned) {
this.#openned = true;
App.openWindow("osd");
}
this.emit('popup', value, icon);
this.#count++;
Utils.timeout(this.#delay, () => {
this.#count--;
if (this.#count === 0) {
this.emit('popup', -1, icon);
App.closeWindow("osd");
this.#openned = false;
}
});
}
speaker() {
const icon = (value) => {
const icons = [];
icons[0] = "audio-volume-muted-symbolic";
icons[1] = "audio-volume-low-symbolic";
icons[34] = "audio-volume-medium-symbolic";
icons[67] = "audio-volume-high-symbolic";
icons[101] = "audio-volume-overamplified-symbolic";
if (Audio.speaker.isMuted) return icons[0];
for (const i of [101, 67, 34, 1, 0]) {
if (i <= value * 100) return icons[i];
}
return icon;
}
this.popup(
Audio.speaker.volume,
icon(Audio.speaker.volume),
);
}
display() {
// brightness is async, so lets wait a bit
Utils.timeout(10, () => this.popup(
Brightness.screen,
"display-brightness-symbolic"));
}
kbd() {
// brightness is async, so lets wait a bit
Utils.timeout(10, () => this.popup(
(Brightness.kbd * 33 + 1) / 100,
"keyboard-brightness-symbolic"));
}
connect(event = 'popup', callback) {
return super.connect(event, callback);
}
}
const indicator = new Indicator();
globalThis.indicator = indicator;
export default indicator;
+4 -17
View File
@@ -61,20 +61,6 @@ separator {
min-width: 1px;
}
/* Progress bar */
.progress {
border-radius: 10px;
}
.max-indicator {
min-width: 1px;
min-height: 1px;
}
.button {
border-radius: 20px;
padding: 10px;
}
/* Slider */
slider {
box-shadow: none;
@@ -93,6 +79,7 @@ trough {
highlight, fill {
background-color: #94e2d5;
border-radius: 100px;
transition: 200ms;
}
mark {
background-color: #F38BA8;
@@ -133,10 +120,10 @@ switch image {
/* On Screen Display */
.osd {
border-radius: 50px;
border-radius: 20px;
margin-bottom: 150px;
min-width: 300px;
min-height: 80px;
min-width: 175px;
min-height: 30px;
}
/* Quick settings */