Using a React base modal for the client/music volume change which uses a logarithmic volume bar
parent
09b636fd8d
commit
93fd5af1b8
|
@ -28,6 +28,7 @@ import * as hex from "tc-shared/crypto/hex";
|
||||||
import { ClientEntry as ClientEntryView } from "./tree/Client";
|
import { ClientEntry as ClientEntryView } from "./tree/Client";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import {ChannelTreeEntry, ChannelTreeEntryEvents} from "tc-shared/ui/TreeEntry";
|
import {ChannelTreeEntry, ChannelTreeEntryEvents} from "tc-shared/ui/TreeEntry";
|
||||||
|
import {spawnClientVolumeChange, spawnMusicBotVolumeChange} from "tc-shared/ui/modal/ModalChangeVolumeNew";
|
||||||
|
|
||||||
export enum ClientType {
|
export enum ClientType {
|
||||||
CLIENT_VOICE,
|
CLIENT_VOICE,
|
||||||
|
@ -145,7 +146,8 @@ export interface ClientEvents extends ChannelTreeEntryEvents {
|
||||||
client_properties: ClientProperties
|
client_properties: ClientProperties
|
||||||
},
|
},
|
||||||
notify_mute_state_change: { muted: boolean }
|
notify_mute_state_change: { muted: boolean }
|
||||||
notify_speak_state_change: { speaking: boolean }
|
notify_speak_state_change: { speaking: boolean },
|
||||||
|
"notify_audio_level_changed": { newValue: number },
|
||||||
|
|
||||||
"music_status_update": {
|
"music_status_update": {
|
||||||
player_buffered_index: number,
|
player_buffered_index: number,
|
||||||
|
@ -515,8 +517,8 @@ export class ClientEntry extends ChannelTreeEntry<ClientEvents> {
|
||||||
type: contextmenu.MenuEntryType.ENTRY,
|
type: contextmenu.MenuEntryType.ENTRY,
|
||||||
icon_class: "client-change_nickname",
|
icon_class: "client-change_nickname",
|
||||||
name: (contextmenu.get_provider().html_format_enabled() ? "<b>" : "") +
|
name: (contextmenu.get_provider().html_format_enabled() ? "<b>" : "") +
|
||||||
tr("Open text chat") +
|
tr("Open text chat") +
|
||||||
(contextmenu.get_provider().html_format_enabled() ? "</b>" : ""),
|
(contextmenu.get_provider().html_format_enabled() ? "</b>" : ""),
|
||||||
callback: () => {
|
callback: () => {
|
||||||
this.open_text_chat();
|
this.open_text_chat();
|
||||||
}
|
}
|
||||||
|
@ -657,15 +659,7 @@ export class ClientEntry extends ChannelTreeEntry<ClientEvents> {
|
||||||
type: contextmenu.MenuEntryType.ENTRY,
|
type: contextmenu.MenuEntryType.ENTRY,
|
||||||
icon_class: "client-volume",
|
icon_class: "client-volume",
|
||||||
name: tr("Change Volume"),
|
name: tr("Change Volume"),
|
||||||
callback: () => {
|
callback: () => spawnClientVolumeChange(this)
|
||||||
spawnChangeVolume(this, true, this._audio_volume, undefined, volume => {
|
|
||||||
this._audio_volume = volume;
|
|
||||||
this.channelTree.client.settings.changeServer("volume_client_" + this.clientUid(), volume);
|
|
||||||
if(this._audio_handle)
|
|
||||||
this._audio_handle.set_volume(volume);
|
|
||||||
//TODO: Update in info
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: contextmenu.MenuEntryType.ENTRY,
|
type: contextmenu.MenuEntryType.ENTRY,
|
||||||
|
@ -933,6 +927,22 @@ export class ClientEntry extends ChannelTreeEntry<ClientEvents> {
|
||||||
this._info_connection_promise_resolve = undefined;
|
this._info_connection_promise_resolve = undefined;
|
||||||
this._info_connection_promise_reject = undefined;
|
this._info_connection_promise_reject = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setAudioVolume(value: number) {
|
||||||
|
if(this._audio_volume == value)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this._audio_volume = value;
|
||||||
|
|
||||||
|
this.get_audio_handle()?.set_volume(value);
|
||||||
|
this.channelTree.client.settings.changeServer("volume_client_" + this.clientUid(), value);
|
||||||
|
|
||||||
|
this.events.fire("notify_audio_level_changed", { newValue: value });
|
||||||
|
}
|
||||||
|
|
||||||
|
getAudioVolume() {
|
||||||
|
return this._audio_volume;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class LocalClientEntry extends ClientEntry {
|
export class LocalClientEntry extends ClientEntry {
|
||||||
|
@ -952,8 +962,8 @@ export class LocalClientEntry extends ClientEntry {
|
||||||
...this.contextmenu_info(), {
|
...this.contextmenu_info(), {
|
||||||
|
|
||||||
name: (contextmenu.get_provider().html_format_enabled() ? "<b>" : "") +
|
name: (contextmenu.get_provider().html_format_enabled() ? "<b>" : "") +
|
||||||
tr("Change name") +
|
tr("Change name") +
|
||||||
(contextmenu.get_provider().html_format_enabled() ? "</b>" : ""),
|
(contextmenu.get_provider().html_format_enabled() ? "</b>" : ""),
|
||||||
icon_class: "client-change_nickname",
|
icon_class: "client-change_nickname",
|
||||||
callback: () =>_self.openRename(),
|
callback: () =>_self.openRename(),
|
||||||
type: contextmenu.MenuEntryType.ENTRY
|
type: contextmenu.MenuEntryType.ENTRY
|
||||||
|
@ -1106,8 +1116,8 @@ export class MusicClientEntry extends ClientEntry {
|
||||||
contextmenu.spawn_context_menu(x, y,
|
contextmenu.spawn_context_menu(x, y,
|
||||||
...this.contextmenu_info(), {
|
...this.contextmenu_info(), {
|
||||||
name: (contextmenu.get_provider().html_format_enabled() ? "<b>" : "") +
|
name: (contextmenu.get_provider().html_format_enabled() ? "<b>" : "") +
|
||||||
tr("Change bot name") +
|
tr("Change bot name") +
|
||||||
(contextmenu.get_provider().html_format_enabled() ? "</b>" : ""),
|
(contextmenu.get_provider().html_format_enabled() ? "</b>" : ""),
|
||||||
icon_class: "client-change_nickname",
|
icon_class: "client-change_nickname",
|
||||||
disabled: false,
|
disabled: false,
|
||||||
callback: () => {
|
callback: () => {
|
||||||
|
@ -1224,12 +1234,7 @@ export class MusicClientEntry extends ClientEntry {
|
||||||
type: contextmenu.MenuEntryType.ENTRY,
|
type: contextmenu.MenuEntryType.ENTRY,
|
||||||
icon_class: "client-volume",
|
icon_class: "client-volume",
|
||||||
name: tr("Change local volume"),
|
name: tr("Change local volume"),
|
||||||
callback: () => {
|
callback: () => spawnClientVolumeChange(this)
|
||||||
spawnChangeVolume(this, true, this._audio_handle.get_volume(), undefined, volume => {
|
|
||||||
this.channelTree.client.settings.changeServer("volume_client_" + this.clientUid(), volume);
|
|
||||||
this._audio_handle.set_volume(volume);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: contextmenu.MenuEntryType.ENTRY,
|
type: contextmenu.MenuEntryType.ENTRY,
|
||||||
|
@ -1240,17 +1245,7 @@ export class MusicClientEntry extends ClientEntry {
|
||||||
if(max_volume < 0)
|
if(max_volume < 0)
|
||||||
max_volume = 100;
|
max_volume = 100;
|
||||||
|
|
||||||
spawnChangeVolume(this, false, this.properties.player_volume, max_volume / 100, value => {
|
spawnMusicBotVolumeChange(this, max_volume / 100);
|
||||||
if(typeof(value) !== "number")
|
|
||||||
return;
|
|
||||||
|
|
||||||
this.channelTree.client.serverConnection.send_command("clientedit", {
|
|
||||||
clid: this.clientId(),
|
|
||||||
player_volume: value,
|
|
||||||
}).then(() => {
|
|
||||||
//TODO: Update in info
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1274,11 +1269,11 @@ export class MusicClientEntry extends ClientEntry {
|
||||||
callback: () => {
|
callback: () => {
|
||||||
const tag = $.spawn("div").append(formatMessage(tr("Do you really want to delete {0}"), this.createChatTag(false)));
|
const tag = $.spawn("div").append(formatMessage(tr("Do you really want to delete {0}"), this.createChatTag(false)));
|
||||||
spawnYesNo(tr("Are you sure?"), $.spawn("div").append(tag), result => {
|
spawnYesNo(tr("Are you sure?"), $.spawn("div").append(tag), result => {
|
||||||
if(result) {
|
if(result) {
|
||||||
this.channelTree.client.serverConnection.send_command("musicbotdelete", {
|
this.channelTree.client.serverConnection.send_command("musicbotdelete", {
|
||||||
bot_id: this.properties.client_database_id
|
bot_id: this.properties.client_database_id
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
type: contextmenu.MenuEntryType.ENTRY
|
type: contextmenu.MenuEntryType.ENTRY
|
||||||
|
@ -1294,7 +1289,7 @@ export class MusicClientEntry extends ClientEntry {
|
||||||
handlePlayerInfo(json) {
|
handlePlayerInfo(json) {
|
||||||
if(json) {
|
if(json) {
|
||||||
const info = new MusicClientPlayerInfo();
|
const info = new MusicClientPlayerInfo();
|
||||||
JSON.map_to(info, json);
|
JSON.map_to(info, json);
|
||||||
if(this._info_promise_resolve)
|
if(this._info_promise_resolve)
|
||||||
this._info_promise_resolve(info);
|
this._info_promise_resolve(info);
|
||||||
this._info_promise_reject = undefined;
|
this._info_promise_reject = undefined;
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
@import "../../../css/static/mixin";
|
||||||
|
|
||||||
|
.container {
|
||||||
|
width: 30em;
|
||||||
|
min-width: 8em;
|
||||||
|
flex-shrink: 1;
|
||||||
|
max-width: 100%;
|
||||||
|
|
||||||
|
padding: 1em;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: flex-start;
|
||||||
|
|
||||||
|
@include user-select(none);
|
||||||
|
|
||||||
|
> * {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info {
|
||||||
|
margin-bottom: .5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sliderContainer {
|
||||||
|
margin-bottom: 1em;
|
||||||
|
|
||||||
|
.slider {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.value {
|
||||||
|
margin-left: .5em;
|
||||||
|
width: 3em;
|
||||||
|
|
||||||
|
flex-shrink: 0;
|
||||||
|
flex-grow: 0;
|
||||||
|
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttons {
|
||||||
|
.reset {
|
||||||
|
margin-right: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.apply, .ok, .cancel {
|
||||||
|
margin-left: 1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ import {sliderfy} from "tc-shared/ui/elements/Slider";
|
||||||
import {createModal, Modal} from "tc-shared/ui/elements/Modal";
|
import {createModal, Modal} from "tc-shared/ui/elements/Modal";
|
||||||
import {ClientEntry} from "tc-shared/ui/client";
|
import {ClientEntry} from "tc-shared/ui/client";
|
||||||
import * as htmltags from "tc-shared/ui/htmltags";
|
import * as htmltags from "tc-shared/ui/htmltags";
|
||||||
|
import {spawnReactModal} from "tc-shared/ui/react-elements/Modal";
|
||||||
|
|
||||||
let modal: Modal;
|
let modal: Modal;
|
||||||
export function spawnChangeVolume(client: ClientEntry, local: boolean, current: number, max: number | undefined, callback: (number) => void) {
|
export function spawnChangeVolume(client: ClientEntry, local: boolean, current: number, max: number | undefined, callback: (number) => void) {
|
||||||
|
|
|
@ -0,0 +1,289 @@
|
||||||
|
import {Modal, spawnReactModal} from "tc-shared/ui/react-elements/Modal";
|
||||||
|
import * as React from "react";
|
||||||
|
import {Slider} from "tc-shared/ui/react-elements/Slider";
|
||||||
|
import {Button} from "tc-shared/ui/react-elements/Button";
|
||||||
|
import {Translatable} from "tc-shared/ui/react-elements/i18n";
|
||||||
|
import {EventHandler, ReactEventHandler, Registry} from "tc-shared/events";
|
||||||
|
import {ClientEntry, MusicClientEntry} from "tc-shared/ui/client";
|
||||||
|
const cssStyle = require("./ModalChangeVolume.scss");
|
||||||
|
|
||||||
|
export interface VolumeChangeEvents {
|
||||||
|
"change-volume": {
|
||||||
|
newValue: number,
|
||||||
|
origin: "user-input" | "reset" | "unknown"
|
||||||
|
}
|
||||||
|
|
||||||
|
"query-volume": {},
|
||||||
|
"query-volume-response": {
|
||||||
|
volume: number
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
"apply-volume": {
|
||||||
|
newValue: number,
|
||||||
|
origin: "user-input" | "reset" | "unknown"
|
||||||
|
},
|
||||||
|
"apply-volume-result": {
|
||||||
|
newValue: number,
|
||||||
|
success: boolean
|
||||||
|
},
|
||||||
|
|
||||||
|
"close-modal": {}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface VolumeChangeModalState {
|
||||||
|
state: "querying" | "applying" | "user-input";
|
||||||
|
|
||||||
|
volumeModifier: number;
|
||||||
|
sliderValue: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ReactEventHandler(e => e.props.events)
|
||||||
|
class VolumeChangeModal extends React.Component<{ clientName: string, remote: boolean, events: Registry<VolumeChangeEvents> }, VolumeChangeModalState> {
|
||||||
|
private readonly refSlider = React.createRef<Slider>();
|
||||||
|
|
||||||
|
private originalValue: number;
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
volumeModifier: 1,
|
||||||
|
sliderValue: 100,
|
||||||
|
state: "querying"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount(): void {
|
||||||
|
this.props.events.fire("query-volume");
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const db = Math.log2(this.state.volumeModifier) * 10;
|
||||||
|
let valueString = db.toFixed(1) + "db";
|
||||||
|
if(!valueString.startsWith("-") && valueString !== "0") valueString = "+" + valueString;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={cssStyle.container}>
|
||||||
|
<div className={cssStyle.info}>
|
||||||
|
<a>Change value for client {this.props.clientName}</a>
|
||||||
|
</div>
|
||||||
|
<div className={cssStyle.sliderContainer}>
|
||||||
|
<Slider
|
||||||
|
minValue={0}
|
||||||
|
maxValue={200}
|
||||||
|
stepSize={1}
|
||||||
|
|
||||||
|
className={cssStyle.slider}
|
||||||
|
tooltip={() => valueString}
|
||||||
|
|
||||||
|
onInput={value => this.onValueChanged(value)}
|
||||||
|
|
||||||
|
value={this.state.sliderValue}
|
||||||
|
disabled={this.state.state !== "user-input"}
|
||||||
|
|
||||||
|
ref={this.refSlider}
|
||||||
|
/>
|
||||||
|
<a className={cssStyle.value}>{valueString}</a>
|
||||||
|
</div>
|
||||||
|
<div className={cssStyle.buttons}>
|
||||||
|
<Button type={"small"} color={"blue"} className={cssStyle.reset} onClick={() => this.onResetClicked()} disabled={this.state.state !== "user-input" || this.state.sliderValue === 100}>
|
||||||
|
<Translatable>Reset</Translatable>
|
||||||
|
</Button>
|
||||||
|
<Button type={"small"} color={"green"} className={cssStyle.apply} onClick={() => this.onApplyClick()} hidden={!this.props.remote} disabled={this.state.state !== "user-input" || this.originalValue === this.state.volumeModifier}>
|
||||||
|
<Translatable>Apply</Translatable>
|
||||||
|
</Button>
|
||||||
|
<Button type={"small"} color={"red"} className={cssStyle.cancel} onClick={() => this.onCancelClick()}>
|
||||||
|
<Translatable>Cancel</Translatable>
|
||||||
|
</Button>
|
||||||
|
<Button type={"small"} color={"green"} className={cssStyle.ok} onClick={() => this.onOkClick()}>
|
||||||
|
<Translatable>Ok</Translatable>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static slider2value(target: number) {
|
||||||
|
if(target > 100) {
|
||||||
|
/* between +0db and +20db */
|
||||||
|
const value = (target - 100) * 20 / 100;
|
||||||
|
return Math.pow(2, value / 10);
|
||||||
|
} else if(target < 100) {
|
||||||
|
/* between -30db and +0db */
|
||||||
|
const value = 30 - target * 30 / 100;
|
||||||
|
return Math.pow(2, -value / 10);
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static value2slider(value: number) {
|
||||||
|
const db = Math.log2(value) * 10;
|
||||||
|
if(db > 0) {
|
||||||
|
return 100 + db * 100 / 20;
|
||||||
|
} else if(db < 0) {
|
||||||
|
return 100 + db * 100 / 30; /* db is negative */
|
||||||
|
} else {
|
||||||
|
return 100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private onValueChanged(target: number) {
|
||||||
|
this.props.events.fire("change-volume", {
|
||||||
|
newValue: VolumeChangeModal.slider2value(target),
|
||||||
|
origin: "user-input"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private onResetClicked() {
|
||||||
|
this.props.events.fire("change-volume", { newValue: 1, origin: "reset" });
|
||||||
|
}
|
||||||
|
|
||||||
|
private onApplyClick() {
|
||||||
|
this.props.events.fire("apply-volume", {
|
||||||
|
newValue: this.state.volumeModifier,
|
||||||
|
origin: "user-input"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private onCancelClick() {
|
||||||
|
this.props.events.fire("change-volume", { origin: "user-input", newValue: this.originalValue });
|
||||||
|
this.props.events.fire("close-modal");
|
||||||
|
}
|
||||||
|
|
||||||
|
private onOkClick() {
|
||||||
|
if(this.props.remote && this.state.volumeModifier !== this.originalValue)
|
||||||
|
this.props.events.fire("apply-volume", { origin: "user-input", newValue: this.originalValue });
|
||||||
|
this.props.events.fire("close-modal");
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler<VolumeChangeEvents>("change-volume")
|
||||||
|
private handleVolumeChanged(event: VolumeChangeEvents["change-volume"]) {
|
||||||
|
const sliderValue = VolumeChangeModal.value2slider(event.newValue);
|
||||||
|
this.setState({
|
||||||
|
volumeModifier: event.newValue,
|
||||||
|
sliderValue: sliderValue
|
||||||
|
});
|
||||||
|
|
||||||
|
if(event.origin !== "user-input")
|
||||||
|
this.refSlider.current?.setState({ value: sliderValue });
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler<VolumeChangeEvents>("query-volume")
|
||||||
|
private handleVolumeQuery() {
|
||||||
|
this.setState({
|
||||||
|
state: "querying"
|
||||||
|
});
|
||||||
|
|
||||||
|
this.refSlider.current?.setState({
|
||||||
|
disabled: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler<VolumeChangeEvents>("apply-volume")
|
||||||
|
private handleApplyVolume() {
|
||||||
|
this.setState({
|
||||||
|
state: "applying"
|
||||||
|
});
|
||||||
|
|
||||||
|
this.refSlider.current?.setState({
|
||||||
|
disabled: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler<VolumeChangeEvents>("query-volume-response")
|
||||||
|
private handleVolumeQueryResponse(event: VolumeChangeEvents["query-volume-response"]) {
|
||||||
|
const sliderValue = VolumeChangeModal.value2slider(event.volume);
|
||||||
|
this.setState({
|
||||||
|
volumeModifier: event.volume,
|
||||||
|
sliderValue: sliderValue,
|
||||||
|
state: "user-input"
|
||||||
|
});
|
||||||
|
|
||||||
|
this.refSlider.current?.setState({
|
||||||
|
value: sliderValue,
|
||||||
|
disabled: false
|
||||||
|
});
|
||||||
|
|
||||||
|
this.originalValue = event.volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler<VolumeChangeEvents>("apply-volume-result")
|
||||||
|
private handleApplyVolumeResult(event: VolumeChangeEvents["apply-volume-result"]) {
|
||||||
|
const sliderValue = VolumeChangeModal.value2slider(event.newValue);
|
||||||
|
this.setState({
|
||||||
|
volumeModifier: event.newValue,
|
||||||
|
sliderValue: sliderValue,
|
||||||
|
state: "user-input"
|
||||||
|
});
|
||||||
|
|
||||||
|
this.refSlider.current?.setState({
|
||||||
|
value: sliderValue,
|
||||||
|
disabled: false
|
||||||
|
});
|
||||||
|
|
||||||
|
this.originalValue = event.newValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function spawnClientVolumeChange(client: ClientEntry) {
|
||||||
|
const events = new Registry<VolumeChangeEvents>();
|
||||||
|
|
||||||
|
events.on("query-volume", () => {
|
||||||
|
events.fire_async("query-volume-response", {
|
||||||
|
volume: client.getAudioVolume()
|
||||||
|
});
|
||||||
|
});
|
||||||
|
events.on("change-volume", event => {
|
||||||
|
client.setAudioVolume(event.newValue);
|
||||||
|
});
|
||||||
|
|
||||||
|
const modal = spawnReactModal(class extends Modal {
|
||||||
|
renderBody() {
|
||||||
|
return <VolumeChangeModal remote={false} clientName={client.clientNickName()} events={events} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
title(): string {
|
||||||
|
return tr("Change local volume");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
events.on("close-modal", event => modal.destroy());
|
||||||
|
modal.show();
|
||||||
|
return modal;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function spawnMusicBotVolumeChange(client: MusicClientEntry, maxValue: number) {
|
||||||
|
//FIXME: Max value!
|
||||||
|
const events = new Registry<VolumeChangeEvents>();
|
||||||
|
|
||||||
|
events.on("query-volume", () => {
|
||||||
|
events.fire_async("query-volume-response", {
|
||||||
|
volume: client.properties.player_volume
|
||||||
|
});
|
||||||
|
});
|
||||||
|
events.on("apply-volume", event => {
|
||||||
|
client.channelTree.client.serverConnection.send_command("clientedit", {
|
||||||
|
clid: client.clientId(),
|
||||||
|
player_volume: event.newValue,
|
||||||
|
}).then(() => {
|
||||||
|
events.fire("apply-volume-result", { newValue: client.properties.player_volume, success: true });
|
||||||
|
}).catch(() => {
|
||||||
|
events.fire("apply-volume-result", { newValue: client.properties.player_volume, success: false });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const modal = spawnReactModal(class extends Modal {
|
||||||
|
renderBody() {
|
||||||
|
return <VolumeChangeModal remote={true} clientName={client.clientNickName()} events={events} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
title(): string {
|
||||||
|
return tr("Change remote volume");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
events.on("close-modal", event => modal.destroy());
|
||||||
|
modal.show();
|
||||||
|
return modal;
|
||||||
|
}
|
Loading…
Reference in New Issue