[gnome] Update extensions for version 48

This commit is contained in:
2025-03-29 17:52:56 -04:00
parent e01589e836
commit a84b79ca08
153 changed files with 3479 additions and 2189 deletions

View File

@ -7,6 +7,7 @@ import GLib from 'gi://GLib';
import GObject from 'gi://GObject';
import * as Components from '../components/index.js';
import * as Core from '../core.js';
import Plugin from '../plugin.js';

View File

@ -6,6 +6,7 @@ import Gio from 'gi://Gio';
import GLib from 'gi://GLib';
import GObject from 'gi://GObject';
import * as Core from '../core.js';
import Plugin from '../plugin.js';

View File

@ -7,6 +7,7 @@ import GObject from 'gi://GObject';
import Plugin from '../plugin.js';
import Contacts from '../components/contacts.js';
import * as Core from '../core.js';
/*
* We prefer libebook's vCard parser if it's available
@ -18,7 +19,7 @@ export const setEBookContacts = (ebook) => { // This function is only for tests
try {
EBookContacts = (await import('gi://EBookContacts')).default;
} catch (e) {
} catch {
EBookContacts = null;
}
@ -150,7 +151,7 @@ const ContactsPlugin = GObject.registerClass({
* See: https://github.com/mathiasbynens/quoted-printable/blob/master/src/quoted-printable.js
*
* @param {string} input - The QUOTED-PRINTABLE string
* @return {string} The decoded string
* @returns {string} The decoded string
*/
_decodeQuotedPrintable(input) {
return input
@ -171,7 +172,7 @@ const ContactsPlugin = GObject.registerClass({
* See: https://github.com/kvz/locutus/blob/master/src/php/xml/utf8_decode.js
*
* @param {string} input - The UTF-8 string
* @return {string} The decoded string
* @returns {string} The decoded string
*/
_decodeUTF8(input) {
try {
@ -215,7 +216,7 @@ const ContactsPlugin = GObject.registerClass({
return output.join('');
// Fallback to old unfaithful
} catch (e) {
} catch {
try {
return decodeURIComponent(escape(input));
@ -233,7 +234,7 @@ const ContactsPlugin = GObject.registerClass({
* See: http://jsfiddle.net/ARTsinn/P2t2P/
*
* @param {string} vcard_data - The raw VCard data
* @return {Object} dictionary of vCard data
* @returns {object} dictionary of vCard data
*/
_parseVCard21(vcard_data) {
// vcard skeleton

View File

@ -183,7 +183,7 @@ const MousepadPlugin = GObject.registerClass({
/**
* Handle a input event.
*
* @param {Object} input - The body of a `kdeconnect.mousepad.request`
* @param {object} input - The body of a `kdeconnect.mousepad.request`
*/
_handleInput(input) {
if (!this.settings.get_boolean('share-control'))
@ -285,7 +285,7 @@ const MousepadPlugin = GObject.registerClass({
/**
* Handle an echo/ACK of a event we sent, displaying it the dialog entry.
*
* @param {Object} input - The body of a `kdeconnect.mousepad.echo`
* @param {object} input - The body of a `kdeconnect.mousepad.echo`
*/
_handleEcho(input) {
if (!this._dialog || !this._dialog.visible)
@ -308,7 +308,7 @@ const MousepadPlugin = GObject.registerClass({
* Handle a state change from the remote keyboard. This is an indication
* that the remote keyboard is ready to accept input.
*
* @param {Object} packet - A `kdeconnect.mousepad.keyboardstate` packet
* @param {object} packet - A `kdeconnect.mousepad.keyboardstate` packet
*/
_handleState(packet) {
this._state = !!packet.body.state;
@ -318,7 +318,7 @@ const MousepadPlugin = GObject.registerClass({
/**
* Send an echo/ACK of @input, if requested
*
* @param {Object} input - The body of a 'kdeconnect.mousepad.request'
* @param {object} input - The body of a 'kdeconnect.mousepad.request'
*/
_sendEcho(input) {
if (!input.sendAck)
@ -335,8 +335,6 @@ const MousepadPlugin = GObject.registerClass({
/**
* Send the local keyboard state
*
* @param {boolean} state - Whether we're ready to accept input
*/
_sendState() {
this.device.sendPacket({

View File

@ -8,6 +8,7 @@ import GObject from 'gi://GObject';
import * as Components from '../components/index.js';
import Config from '../../config.js';
import * as Core from '../core.js';
import * as DBus from '../utils/dbus.js';
import {Player} from '../components/mpris.js';
import Plugin from '../plugin.js';
@ -42,6 +43,8 @@ const MPRISPlugin = GObject.registerClass({
this._transferring = new WeakSet();
this._updating = new WeakSet();
this._queueTimers = new Map();
this._mpris = Components.acquire('mpris');
this._playerAddedId = this._mpris.connect(
@ -75,6 +78,12 @@ const MPRISPlugin = GObject.registerClass({
disconnected() {
super.disconnected();
for (const [identity, timer] of this._queueTimers) {
if (timer)
GLib.source_remove(timer);
this._queueTimers.delete(identity);
}
for (const [identity, player] of this._players) {
this._players.delete(identity);
player.destroy();
@ -144,7 +153,7 @@ const MPRISPlugin = GObject.registerClass({
/**
* Handle an update for a remote player.
*
* @param {Object} packet - A `kdeconnect.mpris` packet
* @param {object} packet - A `kdeconnect.mpris` packet
*/
_handlePlayerUpdate(packet) {
const player = this._players.get(packet.body.player);
@ -174,7 +183,7 @@ const MPRISPlugin = GObject.registerClass({
* Handle a request for player information or action.
*
* @param {Core.Packet} packet - a `kdeconnect.mpris.request`
* @return {undefined} no return value
* @returns {undefined} no return value
*/
_handleRequest(packet) {
// A request for the list of players
@ -258,18 +267,35 @@ const MPRISPlugin = GObject.registerClass({
}
}
// Information Request
let hasResponse = false;
if (packet.body.hasOwnProperty('requestNowPlaying') ||
packet.body.hasOwnProperty('requestVolume')) {
const response = this._getUpdate(player.Identity, packet);
this._sendUpdate(player, response);
}
const response = {
type: 'kdeconnect.mpris',
body: {
player: packet.body.player,
},
};
} catch (e) {
debug(e, this.device.name);
} finally {
this._updating.delete(player);
}
}
// Respond to information request (or push updated information)
_getUpdate(identity, packet) {
const player = this._mpris?.getPlayer(identity);
if (!player)
return;
const response = {
type: 'kdeconnect.mpris',
body: {
player: player.Identity,
},
};
try {
if (packet.body.hasOwnProperty('requestNowPlaying')) {
hasResponse = true;
Object.assign(response.body, {
pos: Math.floor(player.Position / 1000),
@ -330,31 +356,61 @@ const MPRISPlugin = GObject.registerClass({
}
}
if (packet.body.hasOwnProperty('requestVolume')) {
hasResponse = true;
if (packet.body.hasOwnProperty('requestVolume'))
response.body.volume = Math.floor(player.Volume * 100);
}
if (hasResponse)
this.device.sendPacket(response);
return response;
} catch (e) {
debug(e, this.device.name);
} finally {
this._updating.delete(player);
}
}
_sendUpdate(player, packet = null) {
if (!player || (!packet && this._updating.has(player)))
return GLib.SOURCE_REMOVE;
debug(`Sending update for ${player.Identity}`);
this._updating.add(player);
if (this._queueTimers.has(player.Identity)) {
const timer_id = this._queueTimers.get(player.Identity);
if (timer_id) {
debug(`Stopping timer id ${timer_id}`);
GLib.source_remove(timer_id);
}
this._queueTimers.delete(player.Identity);
}
if (!packet) {
packet = this._getUpdate(player.Identity, {
body: {
requestNowPlaying: true,
requestVolume: true,
},
}, false);
}
this.device.sendPacket(packet);
this._updating.delete(player);
return GLib.SOURCE_REMOVE;
}
_onPlayerChanged(mpris, player) {
if (!this.settings.get_boolean('share-players'))
return;
this._handleCommand({
body: {
player: player.Identity,
requestNowPlaying: true,
requestVolume: true,
},
});
// Set a timer to send the updated state after a short delay.
// Allows further state changes to be bundled into a single packet.
if (this._queueTimers.has(player.Identity))
return;
this._queueTimers.set(player.Identity, 0);
const timer_id = GLib.timeout_add(
GLib.PRIORITY_DEFAULT,
250, // ms (0.25 seconds)
this._sendUpdate.bind(this, player)
);
this._queueTimers.set(player.Identity, timer_id);
debug(`Set update timer id ${timer_id} for ${player.Identity}`);
}
_onPlayerSeeked(mpris, player, offset) {
@ -434,6 +490,11 @@ const MPRISPlugin = GObject.registerClass({
}
destroy() {
for (const [identity, timer] of this._queueTimers) {
this._queueTimers.delete(identity);
GLib.source_remove(timer);
}
if (this._mpris !== undefined) {
this._mpris.disconnect(this._playerAddedId);
this._mpris.disconnect(this._playerRemovedId);

View File

@ -8,6 +8,7 @@ import GObject from 'gi://GObject';
import Gtk from 'gi://Gtk';
import * as Components from '../components/index.js';
import * as Core from '../core.js';
import Config from '../../config.js';
import Plugin from '../plugin.js';
import ReplyDialog from '../ui/notification.js';
@ -103,7 +104,7 @@ const SMS_APPS = [
* Try to determine if an notification is from an SMS app
*
* @param {Core.Packet} packet - A `kdeconnect.notification`
* @return {boolean} Whether the notification is from an SMS app
* @returns {boolean} Whether the notification is from an SMS app
*/
function _isSmsNotification(packet) {
const id = packet.body.id;
@ -123,8 +124,8 @@ function _isSmsNotification(packet) {
/**
* Remove a local libnotify or Gtk notification.
*
* @param {String|Number} id - Gtk (string) or libnotify id (uint32)
* @param {String|null} application - Application Id if Gtk or null
* @param {string | number} id - Gtk (string) or libnotify id (uint32)
* @param {string | null} application - Application Id if Gtk or null
*/
function _removeNotification(id, application = null) {
let name, path, method, variant;
@ -416,7 +417,7 @@ const NotificationPlugin = GObject.registerClass({
*
* @param {Core.Packet} packet - A `kdeconnect.notification`
* @param {Gio.Icon|string|null} icon - An icon or %null
* @return {Promise} A promise for the operation
* @returns {Promise} A promise for the operation
*/
_uploadIcon(packet, icon = null) {
// Normalize strings into GIcons
@ -438,7 +439,7 @@ const NotificationPlugin = GObject.registerClass({
/**
* Send a local notification to the remote device.
*
* @param {Object} notif - A dictionary of notification parameters
* @param {object} notif - A dictionary of notification parameters
* @param {string} notif.appName - The notifying application
* @param {string} notif.id - The notification ID
* @param {string} notif.title - The notification title
@ -631,7 +632,7 @@ const NotificationPlugin = GObject.registerClass({
*
* @param {string} uuid - The requestReplyId for the repliable notification
* @param {string} message - The message to reply with
* @param {Object} notification - The original notification packet
* @param {object} notification - The original notification packet
*/
replyNotification(uuid, message, notification) {
// If this happens for some reason, things will explode

View File

@ -150,14 +150,14 @@ const RunCommandPlugin = GObject.registerClass({
* Parse the response to a request for the remote command list. Remove the
* command menu if there are no commands, otherwise amend the menu.
*
* @param {string|Object[]} commandList - A list of remote commands
* @param {string | object[]} commandList - A list of remote commands
*/
_handleCommandList(commandList) {
// See: https://github.com/GSConnect/gnome-shell-extension-gsconnect/issues/1051
if (typeof commandList === 'string') {
try {
commandList = JSON.parse(commandList);
} catch (e) {
} catch {
commandList = {};
}
}

View File

@ -7,6 +7,7 @@ import GLib from 'gi://GLib';
import GObject from 'gi://GObject';
import Config from '../../config.js';
import * as Core from '../core.js';
import Plugin from '../plugin.js';
@ -246,7 +247,7 @@ const SFTPPlugin = GObject.registerClass({
* Add GSConnect's private key identity to the authentication agent so our
* identity can be verified by Android during private key authentication.
*
* @return {Promise} A promise for the operation
* @returns {Promise} A promise for the operation
*/
async _addPrivateKey() {
const ssh_add = this._launcher.spawnv([

View File

@ -443,7 +443,7 @@ const FileChooserDialog = GObject.registerClass({
chooser.preview_widget.pixbuf = pixbuf;
chooser.preview_widget.visible = true;
chooser.preview_widget_active = true;
} catch (e) {
} catch {
chooser.preview_widget.visible = false;
chooser.preview_widget_active = false;
}

View File

@ -206,7 +206,7 @@ const SMSPlugin = GObject.registerClass({
/**
* Handle a digest of threads.
*
* @param {Object[]} messages - A list of message objects
* @param {object[]} messages - A list of message objects
* @param {string[]} thread_ids - A list of thread IDs as strings
*/
_handleDigest(messages, thread_ids) {
@ -244,7 +244,7 @@ const SMSPlugin = GObject.registerClass({
/**
* Handle a new single message
*
* @param {Object} message - A message object
* @param {object} message - A message object
*/
_handleMessage(message) {
let conversation = null;
@ -261,7 +261,7 @@ const SMSPlugin = GObject.registerClass({
/**
* Parse a conversation (thread of messages) and sort them
*
* @param {Object[]} thread - A list of sms message objects from a thread
* @param {object[]} thread - A list of sms message objects from a thread
*/
_handleThread(thread) {
// If there are no addresses this will cause major problems...
@ -300,7 +300,7 @@ const SMSPlugin = GObject.registerClass({
/**
* Handle a response to telephony.request_conversation(s)
*
* @param {Object[]} messages - A list of sms message objects
* @param {object[]} messages - A list of sms message objects
*/
_handleMessages(messages) {
try {
@ -394,7 +394,7 @@ const SMSPlugin = GObject.registerClass({
/**
* Send a message
*
* @param {Object[]} addresses - A list of address objects
* @param {object[]} addresses - A list of address objects
* @param {string} messageBody - The message text
* @param {number} [event] - An event bitmask
* @param {boolean} [forceSms] - Whether to force SMS
@ -508,8 +508,8 @@ const SMSPlugin = GObject.registerClass({
/**
* Try to find a thread_id in @smsPlugin for @addresses.
*
* @param {Object[]} addresses - a list of address objects
* @return {string|null} a thread ID
* @param {object[]} addresses - a list of address objects
* @returns {string|null} a thread ID
*/
getThreadIdForAddresses(addresses = []) {
const threads = Object.values(this.threads);

View File

@ -2,13 +2,27 @@
//
// SPDX-License-Identifier: GPL-2.0-or-later
import GIRepository from 'gi://GIRepository';
import GLib from 'gi://GLib';
import GObject from 'gi://GObject';
import * as Components from '../components/index.js';
import Config from '../../config.js';
import * as Core from '../core.js';
import Plugin from '../plugin.js';
let Gvc = null;
try {
// Add gnome-shell's typelib dir to the search path
const typelibDir = GLib.build_filenamev([Config.GNOME_SHELL_LIBDIR, 'gnome-shell']);
GIRepository.Repository.prepend_search_path(typelibDir);
GIRepository.Repository.prepend_library_path(typelibDir);
Gvc = (await import('gi://Gvc')).default;
} catch {}
export const Metadata = {
label: _('System Volume'),
description: _('Enable the paired device to control the system volume'),
@ -73,12 +87,6 @@ const SystemVolumePlugin = GObject.registerClass({
}
}
connected() {
super.connected();
this._sendSinkList();
}
/**
* Handle a request to change an output
*
@ -121,7 +129,7 @@ const SystemVolumePlugin = GObject.registerClass({
* Update the cache for @stream
*
* @param {Gvc.MixerStream} stream - The stream to cache
* @return {Object} The updated cache object
* @returns {object} The updated cache object
*/
_updateCache(stream) {
const state = {

View File

@ -8,6 +8,7 @@ import GLib from 'gi://GLib';
import GObject from 'gi://GObject';
import * as Components from '../components/index.js';
import * as Core from '../core.js';
import Plugin from '../plugin.js';
@ -114,7 +115,7 @@ const TelephonyPlugin = GObject.registerClass({
* Load a Gdk.Pixbuf from base64 encoded data
*
* @param {string} data - Base64 encoded JPEG data
* @return {Gdk.Pixbuf|null} A contact photo
* @returns {GdkPixbuf.Pixbuf|null} A contact photo
*/
_getThumbnailPixbuf(data) {
const loader = new GdkPixbuf.PixbufLoader();