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