This commit is contained in:
Paul
2021-08-30 12:35:14 +01:00
17 changed files with 244 additions and 27 deletions

View File

@@ -96,7 +96,7 @@ export default function MessageEditor({ message, finish }: Props) {
<AutoComplete detached {...autoCompleteProps} />
<TextAreaAutoSize
forceFocus
maxRows={3}
maxRows={10}
value={content}
maxLength={2000}
padding="var(--message-box-padding)"

View File

@@ -11,6 +11,18 @@ import { useClient } from "../../../context/revoltjs/RevoltClient";
import UserIcon from "../../../components/common/user/UserIcon";
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 {
id: string;
@@ -89,7 +101,8 @@ export default observer(({ id }: Props) => {
target={user}
status={false}
voice={
voiceState.participants!.get(id)
client.user?._id === id && voiceState.isDeaf()?"deaf"
: voiceState.participants!.get(id)
?.audio
? undefined
: "muted"
@@ -115,18 +128,38 @@ export default observer(({ id }: Props) => {
)}
</div>
<div className="actions">
<Button error onClick={voiceState.disconnect}>
<Text id="app.main.channel.voice.leave" />
</Button>
<Tooltip content={"Leave call"} placement={"bottom"}>
<Button error onClick={voiceState.disconnect}>
<PhoneOff width={25} />
</Button>
</Tooltip>
{voiceState.isProducing("audio") ? (
<Button onClick={() => voiceState.stopProducing("audio")}>
<Text id="app.main.channel.voice.mute" />
</Button>
<Tooltip content={"Mute microphone"} placement={"bottom"}>
<Button onClick={() => voiceState.stopProducing("audio")}>
<Microphone width={25} />
</Button>
</Tooltip>
) : (
<Button onClick={() => voiceState.startProducing("audio")}>
<Text id="app.main.channel.voice.unmute" />
</Button>
<Tooltip content={"Unmute microphone"} placement={"bottom"}>
<Button onClick={() => voiceState.startProducing("audio")}>
<MicrophoneOff width={25} />
</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>
</VoiceBase>
);

View File

@@ -16,10 +16,12 @@ function mapMailProvider(email?: string): [string, string] | undefined {
const domain = match[1];
switch (domain) {
case "gmail.com":
case "googlemail.com":
return ["Gmail", "https://gmail.com"];
case "tuta.io":
return ["Tutanota", "https://mail.tutanota.com"];
case "outlook.com":
case "hotmail.com":
return ["Outlook", "https://outlook.live.com"];
case "yahoo.com":
return ["Yahoo", "https://mail.yahoo.com"];
@@ -27,11 +29,24 @@ function mapMailProvider(email?: string): [string, string] | undefined {
return ["WP Poczta", "https://poczta.wp.pl"];
case "protonmail.com":
case "protonmail.ch":
case "pm.me":
return ["ProtonMail", "https://mail.protonmail.com"];
case "seznam.cz":
case "email.cz":
case "post.cz":
return ["Seznam", "https://email.seznam.cz"];
case "zoho.com":
return ["Zoho Mail", "https://mail.zoho.com/zm/"];
case "aol.com":
case "aim.com":
return ["AOL Mail", "https://mail.aol.com/"];
case "icloud.com":
return ["iCloud Mail", "https://mail.aol.com/"];
case "mail.com":
case "email.com":
return ["mail.com", "https://www.mail.com/mail/"];
case "yandex.com":
return ["Yandex Mail", "https://mail.yandex.com/"];
default:
return [domain, `https://${domain}`];
}

View File

@@ -15,6 +15,7 @@ import {
Flask,
User,
Megaphone,
Speaker,
} from "@styled-icons/boxicons-solid";
import { Route, Switch, useHistory } from "react-router-dom";
import { LIBRARY_VERSION } from "revolt.js";
@@ -37,6 +38,7 @@ import { APP_VERSION } from "../../version";
import { GenericSettings } from "./GenericSettings";
import { Account } from "./panes/Account";
import { Appearance } from "./panes/Appearance";
import { Audio } from "./panes/Audio";
import { ExperimentsPage } from "./panes/Experiments";
import { Feedback } from "./panes/Feedback";
import { Languages } from "./panes/Languages";
@@ -85,6 +87,12 @@ export default function Settings() {
category: (
<Text id="app.settings.categories.client_settings" />
),
id: "audio",
icon: <Speaker size={20} />,
title: <Text id="app.settings.pages.audio.title" />,
},
{
id: "appearance",
icon: <Palette size={20} />,
title: <Text id="app.settings.pages.appearance.title" />,
@@ -141,6 +149,9 @@ export default function Settings() {
<Route path="/settings/appearance">
<Appearance />
</Route>
<Route path="/settings/audio">
<Audio />
</Route>
<Route path="/settings/notifications">
<Notifications />
</Route>

View File

@@ -0,0 +1,61 @@
import styles from "./Panes.module.scss";
import { Text } from "preact-i18n";
import { connectState } from "../../../redux/connector";
import { voiceState, VoiceStatus } from "../../../lib/vortex/VoiceState";
import ComboBox from "../../../components/ui/ComboBox";
import {useEffect, useState} from "preact/hooks";
export function Component() {
const [mediaDevices, setMediaDevices] = useState<MediaDeviceInfo[] | undefined>(undefined);
useEffect(() => {
navigator
.mediaDevices
.enumerateDevices()
.then( devices => {
setMediaDevices(devices)
})
}, []);
return (
<>
<div>
<h3>
<Text id="app.settings.pages.audio.input_device" />
</h3>
<ComboBox
value={window.localStorage.getItem("audioInputDevice") ?? 0}
onChange={(e) => changeAudioDevice(e.currentTarget.value, "input")}>
{
mediaDevices?.filter(device => device.kind === "audioinput").map(device => {
return (
<option value={device.deviceId} key={device.deviceId}>
{device.label}
</option>
)
})
}
</ComboBox>
</div>
</>
);
}
function changeAudioDevice(deviceId: string, deviceType: string) {
if(deviceType === "input") {
window.localStorage.setItem("audioInputDevice", deviceId)
if(voiceState.isProducing("audio")) {
voiceState.stopProducing("audio");
voiceState.startProducing("audio");
}
}else if(deviceType === "output") {
window.localStorage.setItem("audioOutputDevice", deviceId)
}
}
export const Audio = connectState(Component, () => {
return;
});

View File

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

View File

@@ -6,7 +6,7 @@ import { Server } from "revolt.js/dist/maps/Servers";
import styles from "./Panes.module.scss";
import { Text } from "preact-i18n";
import { useCallback, useEffect, useMemo, useState } from "preact/hooks";
import {useCallback, useContext, useEffect, useMemo, useState} from "preact/hooks";
import { useIntermediate } from "../../../context/intermediate/Intermediate";
@@ -17,6 +17,7 @@ import InputBox from "../../../components/ui/InputBox";
import Overline from "../../../components/ui/Overline";
import ButtonItem from "../../../components/navigation/items/ButtonItem";
import {AppContext} from "../../../context/revoltjs/RevoltClient";
interface Props {
server: Server;
@@ -26,6 +27,7 @@ const I32ToU32 = (arr: number[]) => arr.map((x) => x >>> 0);
// ! FIXME: bad code :)
export const Roles = observer(({ server }: Props) => {
const client = useContext(AppContext);
const [role, setRole] = useState("default");
const { openScreen } = useIntermediate();
const roles = useMemo(() => server.roles ?? {}, [server]);
@@ -35,6 +37,8 @@ export const Roles = observer(({ server }: Props) => {
return null;
}
const clientPermissions = client.servers.get(server._id)!.permission;
const {
name: roleName,
colour: roleColour,
@@ -207,6 +211,7 @@ export const Roles = observer(({ server }: Props) => {
onChange={() =>
setPerm([perm[0] ^ value, perm[1]])
}
disabled={!(clientPermissions & value)}
description={
<Text id={`permissions.server.${key}.d`} />
}>
@@ -233,7 +238,7 @@ export const Roles = observer(({ server }: Props) => {
onChange={() =>
setPerm([perm[0], perm[1] ^ value])
}
disabled={key === "View"}
disabled={key === "View" || (!(clientPermissions & value))}
description={
<Text id={`permissions.channel.${key}.d`} />
}>