Add deafen button

This commit is contained in:
Ryan Alexander 2021-08-22 12:22:44 +10:00
parent db43c02e01
commit ccda5e8609
7 changed files with 124 additions and 16 deletions

View file

@ -12,12 +12,12 @@ import { AppContext, useClient } from "../../../context/revoltjs/RevoltClient";
import IconBase, { IconBaseProps } from "../IconBase"; import IconBase, { IconBaseProps } from "../IconBase";
import fallback from "../assets/user.png"; import fallback from "../assets/user.png";
import {VolumeMute} from "@styled-icons/boxicons-solid";
type VoiceStatus = "muted";
interface Props extends IconBaseProps<User> { interface Props extends IconBaseProps<User> {
mask?: string; mask?: string;
status?: boolean; status?: boolean;
voice?: VoiceStatus; voice?: string;
showServerIdentity?: boolean; showServerIdentity?: boolean;
} }
@ -33,7 +33,7 @@ export function useStatusColour(user?: User) {
: theme["status-invisible"]; : theme["status-invisible"];
} }
const VoiceIndicator = styled.div<{ status: VoiceStatus }>` const VoiceIndicator = styled.div<{ status: string }>`
width: 10px; width: 10px;
height: 10px; height: 10px;
border-radius: var(--border-radius-half); border-radius: var(--border-radius-half);
@ -47,7 +47,7 @@ const VoiceIndicator = styled.div<{ status: VoiceStatus }>`
} }
${(props) => ${(props) =>
props.status === "muted" && (props.status === "muted" || props.status === "deaf") &&
css` css`
background: var(--error); background: var(--error);
`} `}
@ -125,7 +125,9 @@ export default observer(
{props.voice && ( {props.voice && (
<foreignObject x="22" y="22" width="10" height="10"> <foreignObject x="22" y="22" width="10" height="10">
<VoiceIndicator status={props.voice}> <VoiceIndicator status={props.voice}>
{props.voice === "muted" && ( {props.voice === "deaf" && (
<VolumeMute size={6} />
) ||props.voice === "muted" && (
<MicrophoneOff size={6} /> <MicrophoneOff size={6} />
)} )}
</VoiceIndicator> </VoiceIndicator>

View file

@ -40,6 +40,8 @@ export default class VoiceClient extends EventEmitter<VoiceEvents> {
sendTransport?: Transport; sendTransport?: Transport;
recvTransport?: Transport; recvTransport?: Transport;
isDeaf?: boolean;
userId?: string; userId?: string;
roomId?: string; roomId?: string;
participants: Map<string, VoiceUser>; participants: Map<string, VoiceUser>;
@ -54,6 +56,8 @@ export default class VoiceClient extends EventEmitter<VoiceEvents> {
this.participants = new Map(); this.participants = new Map();
this.consumers = new Map(); this.consumers = new Map();
this.isDeaf = false;
this.signaling.on( this.signaling.on(
"data", "data",
(json) => { (json) => {

View file

@ -143,6 +143,33 @@ class VoiceStateReference {
} }
} }
isDeaf() {
if(!this.client)
return false;
return this.client.isDeaf;
}
async startDeafen() {
if(!this.client)
return console.log("No client object"); // ! TODO: let the user know
this.client.isDeaf = true;
this.client?.consumers.forEach(consumer => {
consumer.audio?.pause();
})
}
async stopDeafen() {
if(!this.client)
return console.log("No client object"); // ! TODO: let the user know
this.client.isDeaf = false;
this.client?.consumers.forEach(consumer => {
consumer.audio?.resume();
})
}
async startProducing(type: ProduceType) { async startProducing(type: ProduceType) {
switch (type) { switch (type) {
case "audio": { case "audio": {

View file

@ -11,6 +11,18 @@ import { useClient } from "../../../context/revoltjs/RevoltClient";
import UserIcon from "../../../components/common/user/UserIcon"; import UserIcon from "../../../components/common/user/UserIcon";
import Button from "../../../components/ui/Button"; import Button from "../../../components/ui/Button";
import {
Megaphone,
Microphone,
MicrophoneOff,
PhoneOff,
Speaker,
VolumeFull,
VolumeMute
} from "@styled-icons/boxicons-solid";
import Tooltip from "../../../components/common/Tooltip";
import {Hashnode, Speakerdeck, Teamspeak} from "@styled-icons/simple-icons";
import VoiceClient from "../../../lib/vortex/VoiceClient";
interface Props { interface Props {
id: string; id: string;
@ -89,7 +101,8 @@ export default observer(({ id }: Props) => {
target={user} target={user}
status={false} status={false}
voice={ voice={
voiceState.participants!.get(id) client.user?._id === id && voiceState.isDeaf()?"deaf"
: voiceState.participants!.get(id)
?.audio ?.audio
? undefined ? undefined
: "muted" : "muted"
@ -115,18 +128,38 @@ export default observer(({ id }: Props) => {
)} )}
</div> </div>
<div className="actions"> <div className="actions">
<Tooltip content={"Leave call"} placement={"bottom"}>
<Button error onClick={voiceState.disconnect}> <Button error onClick={voiceState.disconnect}>
<Text id="app.main.channel.voice.leave" /> <PhoneOff width={25} />
</Button> </Button>
</Tooltip>
{voiceState.isProducing("audio") ? ( {voiceState.isProducing("audio") ? (
<Tooltip content={"Mute microphone"} placement={"bottom"}>
<Button onClick={() => voiceState.stopProducing("audio")}> <Button onClick={() => voiceState.stopProducing("audio")}>
<Text id="app.main.channel.voice.mute" /> <Microphone width={25} />
</Button> </Button>
</Tooltip>
) : ( ) : (
<Tooltip content={"Unmute microphone"} placement={"bottom"}>
<Button onClick={() => voiceState.startProducing("audio")}> <Button onClick={() => voiceState.startProducing("audio")}>
<Text id="app.main.channel.voice.unmute" /> <MicrophoneOff width={25} />
</Button> </Button>
</Tooltip>
)} )}
{voiceState.isDeaf() ? (
<Tooltip content={"Deafen"} placement={"bottom"}>
<Button onClick={() => voiceState.stopDeafen()}>
<VolumeMute width={25} />
</Button>
</Tooltip>
): (
<Tooltip content={"Deafen"} placement={"bottom"}>
<Button onClick={() => voiceState.startDeafen()}>
<VolumeFull width={25} />
</Button>
</Tooltip>
)
}
</div> </div>
</VoiceBase> </VoiceBase>
); );

View file

@ -15,6 +15,7 @@ import {
Flask, Flask,
User, User,
Megaphone, Megaphone,
Shield,
} from "@styled-icons/boxicons-solid"; } from "@styled-icons/boxicons-solid";
import { Route, Switch, useHistory } from "react-router-dom"; import { Route, Switch, useHistory } from "react-router-dom";
import { LIBRARY_VERSION } from "revolt.js"; import { LIBRARY_VERSION } from "revolt.js";
@ -76,6 +77,11 @@ export default function Settings() {
icon: <IdCard size={20} />, icon: <IdCard size={20} />,
title: <Text id="app.settings.pages.profile.title" />, title: <Text id="app.settings.pages.profile.title" />,
}, },
{
id: "privacy",
icon: <Shield size={20} />,
title: <Text id="app.settings.pages.profile.title" />,
},
{ {
id: "sessions", id: "sessions",
icon: <CheckShield size={20} />, icon: <CheckShield size={20} />,

View file

@ -0,0 +1,36 @@
import styles from "./Panes.module.scss";
import { Text } from "preact-i18n";
import { dispatch } from "../../../redux";
import { connectState } from "../../../redux/connector";
import { SyncKeys, SyncOptions } from "../../../redux/reducers/sync";
import Checkbox from "../../../components/ui/Checkbox";
interface Props {
options?: SyncOptions;
}
export function Component(props: Props) {
return (
<div className={styles.notifications}>
<Checkbox
key={"everyone_dm"}
checked={false}
description={
<Text
id={`app.settings.pages.privacy.allow_dms.d`}
/>
}
onChange={(enabled) => {console.log(enabled)}}>
<Text id="app.settings.pages.privacy.allow_dms.t" />
</Checkbox>
</div>
);
}
export const Sync = connectState(Component, (state) => {
return {
options: state.sync,
};
});

View file

@ -152,7 +152,7 @@ export const Overview = observer(({ server }: Props) => {
<Text id="general.disabled" /> <Text id="general.disabled" />
</option> </option>
{server.channels {server.channels
.filter((x) => typeof x !== "undefined") .filter((x) => (typeof x !== "undefined" && x.channel_type === "TextChannel"))
.map((channel) => ( .map((channel) => (
<option key={channel!._id} value={channel!._id}> <option key={channel!._id} value={channel!._id}>
{getChannelName(channel!, true)} {getChannelName(channel!, true)}