[gnome] Update extensions for version 48
This commit is contained in:
@ -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';
|
||||
|
||||
|
||||
|
||||
@ -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';
|
||||
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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({
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 = {};
|
||||
}
|
||||
}
|
||||
|
||||
@ -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([
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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 = {
|
||||
|
||||
@ -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();
|
||||
|
||||
Reference in New Issue
Block a user