You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
349 lines
10 KiB
349 lines
10 KiB
'use strict';
|
|
|
|
const {Gdk, Gio, GLib, Gtk, GObject} = imports.gi;
|
|
|
|
const Util = imports.util;
|
|
|
|
var GroupWidget = GObject.registerClass({
|
|
Template: Util.getBuilderFile('group.ui')
|
|
, InternalChildren: [
|
|
'hBox'
|
|
, 'iconState'
|
|
, 'btnComboStream'
|
|
, 'labelName'
|
|
, 'scaleVolume'
|
|
, 'btnConfig'
|
|
, 'btnMute'
|
|
]
|
|
}, class GroupWidget extends Gtk.Box {
|
|
_init(window, snapcast, group, params = []) {
|
|
this.group = group;
|
|
this.snapcast = snapcast;
|
|
this.win = window;
|
|
super._init(Object.assign({}, params));
|
|
|
|
//this._btnMute.set_active(this.group.muted);
|
|
|
|
this._btnConfig.connect('clicked', () => {
|
|
let cw = new GroupOptions(this.win, this.snapcast, this.group);
|
|
cw.show_all();
|
|
});
|
|
|
|
this.snapcast.sServer.stream(this.group.streamID).connect('updated::status', this._set_stream_status.bind(this));
|
|
this._set_stream_status(this.snapcast.sServer.stream(this.group.streamID));
|
|
|
|
this._labelName.set_text((this.group.name != this.group.streamID) ? this.group.name : '');
|
|
|
|
this.group.connect('updated::name', () => {
|
|
this._labelName.set_text((this.group.name != this.group.streamID) ? this.group.name : '');
|
|
});
|
|
|
|
this._btnMute.set_active(this.group.muted);
|
|
this.group.connect('updated::muted', () => { this._btnMute.set_active(this.group.muted) });
|
|
this._btnMute.connect('clicked', (b) => { this.group.muted = b.get_active() });
|
|
//this.group.connect('updated::name', () => { this._labelName.set_text(this.group.name) });
|
|
this.group.connect('destroy', () => { this.destroy() });
|
|
this._btnComboStream.connect('changed', () => {
|
|
if (this._btnComboStream.get_active_text() !== null){
|
|
this.group.streamID = this._btnComboStream.get_active_text();
|
|
}
|
|
});
|
|
this.snapcast.sServer.connect('clients::added', this._on_clients_added.bind(this));
|
|
this.group.connect("updated::stream_id", () => {
|
|
this.setComboActive();
|
|
this._set_stream_status(this.snapcast.sServer.stream(this.group.streamID));
|
|
});
|
|
|
|
this.setComboActive();
|
|
//this.group.connect('updated::stream_id', this.setComboActive.bind(this));
|
|
|
|
this._scaleVolume.add_mark(0, Gtk.PositionType.BOTTOM, '');
|
|
this._scaleVolume.add_mark(50, Gtk.PositionType.BOTTOM, '');
|
|
this._scaleVolume.add_mark(100, Gtk.PositionType.BOTTOM, '');
|
|
this._scaleVolume.set_value(this.group.volume);
|
|
this._scaleVolume.connect('value-changed', () => {
|
|
this.group.volume = Math.round(this._scaleVolume.get_value());
|
|
});
|
|
this.group.connect('updated::volume', () => { this._scaleVolume.set_value(this.group.volume) });
|
|
|
|
this.show_all();
|
|
}
|
|
|
|
setComboActive() {
|
|
this._btnComboStream.remove_all();
|
|
this.snapcast.sServer.streams.forEach((stream, ii) => {
|
|
this._btnComboStream.append_text(stream.id);
|
|
if (stream.id == this.group.streamID) {
|
|
this._btnComboStream.set_active(ii);
|
|
}
|
|
});
|
|
}
|
|
|
|
_set_stream_status(stream) {
|
|
if (this._iconState === undefined || this._iconState === null) {
|
|
return;
|
|
}
|
|
let _in = '';
|
|
if (stream === undefined) {
|
|
return;
|
|
}
|
|
switch (stream.status) {
|
|
case 'playing':
|
|
_in = 'gtk-media-play';
|
|
break;
|
|
case 'idle':
|
|
default:
|
|
_in = 'gtk-media-pause';
|
|
break;
|
|
}
|
|
this._iconState.set_from_icon_name(_in, Gtk.IconSize.BUTTON);
|
|
}
|
|
|
|
_on_clients_added(server, clients) {
|
|
clients.forEach((client) => {
|
|
if (client.groupID === this.group.id) {
|
|
this.add(new ClientWidget(this.win, this.snapcast, this.group, client));
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
var GroupOptions = GObject.registerClass({
|
|
Template: Util.getBuilderFile('group-options.ui')
|
|
, InternalChildren: [
|
|
'vBox'
|
|
, 'bBox'
|
|
, 'btnCancel'
|
|
, 'btnSave'
|
|
]
|
|
}, class GroupOptions extends Gtk.Window {
|
|
_init(window, snapcast, group, params = []) {
|
|
super._init(Object.assign({
|
|
application: window.get_application()
|
|
, 'transient-for': window
|
|
, 'attached-to': window
|
|
}, params));
|
|
|
|
this.snapcast = snapcast;
|
|
this.group = group;
|
|
this._clientsByName = {};
|
|
|
|
this._btnSave.connect('clicked', () => { this._on_save() });
|
|
this._btnCancel.connect('clicked', () => { this.close() });
|
|
|
|
this.snapcast.sServer._groups.forEach((group) => {
|
|
group._clients.forEach((client) => {
|
|
let cb = new Gtk.CheckButton();
|
|
cb.set_label(client.name);
|
|
cb.set_active(client.groupID == this.group.id);
|
|
this._clientsByName[client.name] = client.id;
|
|
this._vBox.add(cb);
|
|
});
|
|
});
|
|
}
|
|
|
|
_on_save() {
|
|
var clients = [];
|
|
this._vBox.foreach((child) => {
|
|
if (child.get_active()) {
|
|
clients.push(this._clientsByName[child.get_label()]);
|
|
}
|
|
});
|
|
this.close();
|
|
this.group.setClients(clients);
|
|
}
|
|
});
|
|
|
|
var ClientWidget = GObject.registerClass({
|
|
Template: Util.getBuilderFile('client.ui')
|
|
, InternalChildren: [
|
|
'iconStatus'
|
|
, 'labelName'
|
|
, 'btnConfig'
|
|
, 'btnMute'
|
|
, 'scaleVolume'
|
|
, 'labelVolume'
|
|
, 'menuItemDetails'
|
|
, 'menuItemRemove'
|
|
]
|
|
}, class ClientWidget extends Gtk.Box {
|
|
_init(window, snapcast, group, client, params = []) {
|
|
this.client = client;
|
|
this.group = group;
|
|
this.snapcast = snapcast;
|
|
this.win = window;
|
|
|
|
super._init(Object.assign({
|
|
orientation: Gtk.Orientation.VERTICAL
|
|
, expand: false
|
|
}, params));
|
|
|
|
this.client.connect('destroy', this.destroy.bind(this));
|
|
|
|
this._menuItemDetails.connect('activate', this._on_show_details.bind(this));
|
|
this._menuItemRemove.connect('activate', this._on_delete.bind(this));
|
|
|
|
this.client.connect('updated::name', () => { this._labelName.set_text(this.client.name) });
|
|
this.client.connect('updated::connected', () => { this._update() });
|
|
this.client.connect('updated::disconnected', () => { this._update() });
|
|
|
|
this.client.connect('updated::muted', () => { this._btnMute.set_active(this.client.muted) });
|
|
this._btnMute.connect('clicked', (b) => { this.client.muted = b.get_active() });
|
|
|
|
this._scaleVolume.add_mark(0, Gtk.PositionType.BOTTOM, '');
|
|
this._scaleVolume.add_mark(50, Gtk.PositionType.BOTTOM, '');
|
|
this._scaleVolume.add_mark(100, Gtk.PositionType.BOTTOM, '');
|
|
|
|
this._scaleVolume.connect('value-changed', () => {
|
|
this._labelVolume.set_text(Math.round(this._scaleVolume.get_value()) + "%");
|
|
this.client.volume = Math.round(this._scaleVolume.get_value());
|
|
});
|
|
this.client.connect('updated::volume', () => { this._scaleVolume.set_value(this.client.volume) });
|
|
|
|
this._update();
|
|
|
|
this.show_all();
|
|
}
|
|
|
|
destroy() {
|
|
super.destroy();
|
|
}
|
|
|
|
_update() {
|
|
if (this.client.connected) {
|
|
this._iconStatus.set_from_icon_name('gtk-yes', Gtk.IconSize.BUTTON);
|
|
this._labelName.set_sensitive(true);
|
|
} else {
|
|
this._iconStatus.set_from_icon_name('gtk-no', Gtk.IconSize.BUTTON);
|
|
this._labelName.set_sensitive(false);
|
|
}
|
|
this._labelName.set_text(this.client.name);
|
|
this._btnMute.set_active(this.client.muted);
|
|
this._scaleVolume.set_value(this.client.volume);
|
|
}
|
|
|
|
_on_show_details() {
|
|
log("_on_show_details");
|
|
let modal, contentArea, button, actionArea;
|
|
|
|
let storeProps = new Gtk.ListStore ();
|
|
storeProps.set_column_types ([
|
|
GObject.TYPE_STRING
|
|
, GObject.TYPE_STRING
|
|
]);
|
|
|
|
let renderer = new Gtk.CellRendererText();
|
|
let renderer2 = new Gtk.CellRendererText();
|
|
|
|
let column = new Gtk.TreeViewColumn({ title: "Item" });
|
|
let column2 = new Gtk.TreeViewColumn({ title: "Value" });
|
|
|
|
let treeview = new Gtk.TreeView({
|
|
model: storeProps
|
|
, 'headers-visible': false
|
|
});
|
|
|
|
column.pack_start(renderer, false);
|
|
column.add_attribute(renderer, "text", 0);
|
|
|
|
column2.pack_start(renderer2, false);
|
|
column2.add_attribute(renderer2, "text", 1);
|
|
|
|
treeview.append_column(column);
|
|
treeview.append_column(column2);
|
|
treeview.set_margin_top(10);
|
|
treeview.set_margin_bottom(10);
|
|
let sel = treeview.get_selection();
|
|
sel.set_mode(Gtk.SelectionMode.NONE);
|
|
//treeview.set_sensitive(false);
|
|
|
|
//storeProps.set(storeProps.append(), [0,1], ["Latency", this.client.props.config.latency]);
|
|
storeProps.set(storeProps.append(), [0,1], ["ID:", this.client.id]);
|
|
storeProps.set(storeProps.append(), [0,1], ["MAC:", this.client.props.host.mac]);
|
|
storeProps.set(storeProps.append(), [0,1], ["IP:", this.client.props.host.ip]);
|
|
storeProps.set(storeProps.append(), [0,1], ["Hostname:", this.client.props.host.name]);
|
|
storeProps.set(storeProps.append(), [0,1], ["Operating System:", this.client.props.host.os]);
|
|
storeProps.set(storeProps.append(), [0,1], ["Snapclient Version:", this.client.props.snapclient.version]);
|
|
storeProps.set(storeProps.append(), [0,1], ["Last Seen:", Util.time_ago_sec(this.client.props.lastSeen.sec)]);
|
|
|
|
let adjustmentLatency = new Gtk.Adjustment({
|
|
upper: 10000
|
|
, lower: 0.0
|
|
, 'step-increment': 1.0
|
|
});
|
|
let boxValues = new Gtk.Box({
|
|
orientation: Gtk.Orientation.VERTICAL
|
|
, expand: true
|
|
, spacing: 10
|
|
});
|
|
let boxLabels = new Gtk.Box({
|
|
orientation: Gtk.Orientation.VERTICAL
|
|
, expand: true
|
|
, spacing: 10
|
|
});
|
|
let boxItems = new Gtk.Box({
|
|
orientation: Gtk.Orientation.HORIZONTAL
|
|
, expand: true
|
|
, spacing: 10
|
|
});
|
|
boxItems.add(boxLabels);
|
|
boxItems.add(boxValues);
|
|
|
|
let labelName = new Gtk.Label({ label: _("Name: "), expand: true });
|
|
labelName.set_halign(Gtk.Align.START);
|
|
this.entryName = new Gtk.Entry({
|
|
text: this.client.name
|
|
, expand: true
|
|
});
|
|
boxLabels.add(labelName);
|
|
boxValues.add(this.entryName);
|
|
|
|
let labelLatency = new Gtk.Label({ label: _("Latency: "), expand: true });
|
|
labelLatency.set_halign(Gtk.Align.START);
|
|
this.btnSpinLatency = new Gtk.SpinButton({
|
|
numeric: true
|
|
, adjustment: adjustmentLatency
|
|
, expand: true
|
|
});
|
|
this.btnSpinLatency.set_value(this.client.props.config.latency);
|
|
boxLabels.add(labelLatency);
|
|
boxValues.add(this.btnSpinLatency);
|
|
|
|
modal = new Gtk.Dialog({
|
|
default_width: 250
|
|
, modal: true
|
|
, transient_for: this.win
|
|
, title: _("Client Details: ") + this.client.name
|
|
, use_header_bar: false
|
|
});
|
|
|
|
contentArea = modal.get_content_area();
|
|
contentArea.set_margin_top(10);
|
|
contentArea.set_margin_right(10);
|
|
contentArea.set_margin_bottom(10);
|
|
contentArea.set_margin_left(10);
|
|
contentArea.add(boxItems);
|
|
contentArea.add(treeview);
|
|
|
|
button = Gtk.Button.new_with_label('OK');
|
|
button.connect("clicked", () => {
|
|
if (this.entryName.get_text() !== this.client.props.host.name || this.client.name !== this.entryName.get_text()) {
|
|
this.client.name = this.entryName.get_text();
|
|
}
|
|
this.client.latency = this.btnSpinLatency.get_value();
|
|
modal.destroy();
|
|
});
|
|
|
|
actionArea = modal.get_action_area();
|
|
actionArea.add(button);
|
|
|
|
modal.show_all();
|
|
|
|
}
|
|
|
|
_on_delete() {
|
|
log("_on_delete");
|
|
this.client.delete();
|
|
}
|
|
});
|