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

'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();
}
});