231 lines
7.0 KiB
JavaScript
231 lines
7.0 KiB
JavaScript
/* GsConnect Proxy
|
|
*
|
|
* Copyright (C) 2021, 2025 Sundeep Mediratta (smedius@gmail.com)
|
|
* Translation to javascript of python file with tweaks for DING
|
|
*
|
|
* Based on nautilus-gsconnect.py -
|
|
* A Nautilus extension for sending files via GSConnect by Andy Holmes
|
|
*fg
|
|
* A great deal of credit and appreciation is owed to the indicator-kdeconnect
|
|
* developers for the sister Python script 'kdeconnect-send-nautilus.py':
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, version 3 of the License.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
import {Gio, GLib} from '../../dependencies/gi.js';
|
|
|
|
export {GsConnectSendFileOperationsManager};
|
|
|
|
var GsConnectSendFileOperationsManager = class {
|
|
constructor(GsConnectManager, mainApp) {
|
|
this._mainApp = mainApp;
|
|
this.gsConnectDevices = {};
|
|
this.devices = {};
|
|
this.gsConnectServiceName = 'org.gnome.Shell.Extensions.GSConnect';
|
|
this.gsConnectServicePath = '/org/gnome/Shell/Extensions/GSConnect';
|
|
this.GsConnectManager = GsConnectManager;
|
|
|
|
this.GsConnectManager.connect('changed-status', () => {
|
|
GLib.timeout_add(GLib.PRIORITY_DEFAULT, 1000, () => {
|
|
this._startGsConnectService();
|
|
return false;
|
|
});
|
|
});
|
|
|
|
this._startGsConnectService();
|
|
this._createSendAction();
|
|
}
|
|
|
|
_startGsConnectService() {
|
|
if (this.GsConnectManager.isAvailable) {
|
|
this.gsConnectProxy = this.GsConnectManager.proxy;
|
|
|
|
if (!this.gsConnectProxy) {
|
|
this._stopService();
|
|
return;
|
|
}
|
|
|
|
this.signalID =
|
|
this.gsConnectProxy.connect(
|
|
'g-signal',
|
|
this._on_g_signal.bind(this)
|
|
);
|
|
|
|
this._on_name_owner_changed();
|
|
} else {
|
|
this._stopService();
|
|
}
|
|
}
|
|
|
|
_stopService() {
|
|
this.gsConnectDevices = {};
|
|
this.devices = {};
|
|
|
|
if (this.signalID) {
|
|
this.gsConnectProxy.disconnect(this.signalID);
|
|
this.signalID = null;
|
|
}
|
|
}
|
|
|
|
_on_g_signal(proxy, senderName, signalName, parameters) {
|
|
// Wait until the service is ready
|
|
if (!this.gsConnectProxy.get_name_owner())
|
|
return;
|
|
|
|
let objects = parameters.recursiveUnpack();
|
|
|
|
if (signalName === 'InterfacesAdded') {
|
|
for (let [objectPath, props] of Object.entries(objects)) {
|
|
props = props['org.gnome.Shell.Extensions.GSConnect.Device'];
|
|
|
|
if (!props)
|
|
continue;
|
|
|
|
let action =
|
|
Gio.DBusActionGroup.get(
|
|
this.gsConnectProxy.get_connection(),
|
|
this.gsConnectServiceName,
|
|
objectPath
|
|
);
|
|
|
|
this.gsConnectDevices[objectPath] = [props['Name'], action];
|
|
}
|
|
} else if (signalName === 'InterfacesRemoved') {
|
|
for (const objectPath of Object.keys(objects)) {
|
|
try {
|
|
delete this.gsConnectDevices[objectPath];
|
|
} catch (e) {}
|
|
}
|
|
}
|
|
|
|
this._update_devices();
|
|
}
|
|
|
|
_on_name_owner_changed() {
|
|
// Wait until the service is ready
|
|
if (!this.gsConnectProxy.get_name_owner()) {
|
|
this.gsConnectDevices = {};
|
|
} else {
|
|
this.gsConnectProxy.call(
|
|
'GetManagedObjects',
|
|
null,
|
|
Gio.DBusCallFlags.NO_AUTO_START,
|
|
-1,
|
|
null,
|
|
this._get_managed_objects.bind(this)
|
|
);
|
|
}
|
|
}
|
|
|
|
_get_managed_objects(proxy, res) {
|
|
let objects = this.gsConnectProxy.call_finish(res).recursiveUnpack()[0];
|
|
|
|
if (objects) {
|
|
for (let [objectPath, props] of Object.entries(objects)) {
|
|
props = props['org.gnome.Shell.Extensions.GSConnect.Device'];
|
|
|
|
if (!Object.keys(props).length > 0)
|
|
continue;
|
|
|
|
let action =
|
|
Gio.DBusActionGroup.get(
|
|
this.gsConnectProxy.get_connection(),
|
|
this.gsConnectServiceName,
|
|
objectPath
|
|
);
|
|
|
|
this.gsConnectDevices[objectPath] = [props['Name'], action];
|
|
}
|
|
|
|
this._update_devices();
|
|
}
|
|
}
|
|
|
|
_createSendAction() {
|
|
let sendfiles = new Gio.SimpleAction({
|
|
name: 'sendfiles',
|
|
parameter_type: new GLib.VariantType('s'),
|
|
});
|
|
|
|
sendfiles.connect('activate', (action, parameter) => {
|
|
let device = parameter.recursiveUnpack();
|
|
this._send_files(device);
|
|
});
|
|
|
|
this._mainApp.add_action(sendfiles);
|
|
}
|
|
|
|
_send_files(device) {
|
|
// send files to shareFile action in actiongroup
|
|
// for the devices actiongroup
|
|
let actionGroup = this.devices[device];
|
|
|
|
for (let file of this.sendablefiles) {
|
|
let variant = GLib.Variant.new('(sb)', [file.get_uri(), false]);
|
|
actionGroup.activate_action('shareFile', variant);
|
|
}
|
|
}
|
|
|
|
_update_devices() {
|
|
this.devices = {};
|
|
|
|
for (let [name, actionGroup] of Object.values(this.gsConnectDevices)) {
|
|
if (actionGroup.get_action_enabled('shareFile'))
|
|
this.devices[name] = actionGroup;
|
|
}
|
|
}
|
|
|
|
_get_devices() {
|
|
// No capable devices
|
|
if (!Object.keys(this.devices).length > 0)
|
|
return null;
|
|
else
|
|
return true;
|
|
}
|
|
|
|
_sendable_file_items(files) {
|
|
// Return a list of select files to be sent
|
|
// Only accept regular files
|
|
for (let f of files) {
|
|
if (f.get_uri_scheme() !== 'file')
|
|
return null;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
create_gsconnect_menu(files) {
|
|
this.sendablefiles = files.map(f => f.file);
|
|
this._update_devices();
|
|
|
|
if (
|
|
this._sendable_file_items(this.sendablefiles) &&
|
|
this._get_devices()
|
|
) {
|
|
this._menu = new Gio.Menu();
|
|
|
|
for (let device of Object.keys(this.devices)) {
|
|
let menuitem = Gio.MenuItem.new(`${device}`, null);
|
|
|
|
menuitem.set_action_and_target_value(
|
|
'app.sendfiles',
|
|
GLib.Variant.new('s', `${device}`)
|
|
);
|
|
|
|
this._menu.append_item(menuitem);
|
|
}
|
|
|
|
return this._menu;
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
};
|