mirror of
https://github.com/revoltchat/revite.git
synced 2024-11-22 07:00:58 -05:00
feat(mobx): migrate audio settings
This commit is contained in:
parent
c7df0088fc
commit
120e6a35d8
13 changed files with 147 additions and 188 deletions
|
@ -1,29 +0,0 @@
|
||||||
import call_join from "./call_join.mp3";
|
|
||||||
import call_leave from "./call_leave.mp3";
|
|
||||||
import message from "./message.mp3";
|
|
||||||
import outbound from "./outbound.mp3";
|
|
||||||
|
|
||||||
const SoundMap: { [key in Sounds]: string } = {
|
|
||||||
message,
|
|
||||||
outbound,
|
|
||||||
call_join,
|
|
||||||
call_leave,
|
|
||||||
};
|
|
||||||
|
|
||||||
export type Sounds = "message" | "outbound" | "call_join" | "call_leave";
|
|
||||||
export const SOUNDS_ARRAY: Sounds[] = [
|
|
||||||
"message",
|
|
||||||
"outbound",
|
|
||||||
"call_join",
|
|
||||||
"call_leave",
|
|
||||||
];
|
|
||||||
|
|
||||||
export function playSound(sound: Sounds) {
|
|
||||||
const file = SoundMap[sound];
|
|
||||||
const el = new Audio(file);
|
|
||||||
try {
|
|
||||||
el.play();
|
|
||||||
} catch (err) {
|
|
||||||
console.error("Failed to play audio file", file, err);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { EmojiPacks } from "../../redux/reducers/settings";
|
export type EmojiPack = "mutant" | "twemoji" | "noto" | "openmoji";
|
||||||
|
|
||||||
let EMOJI_PACK = "mutant";
|
let EMOJI_PACK: EmojiPack = "mutant";
|
||||||
const REVISION = 3;
|
const REVISION = 3;
|
||||||
|
|
||||||
export function setGlobalEmojiPack(pack: EmojiPacks) {
|
export function setGlobalEmojiPack(pack: EmojiPack) {
|
||||||
EMOJI_PACK = pack;
|
EMOJI_PACK = pack;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,10 +21,8 @@ import {
|
||||||
} from "../../../lib/renderer/Singleton";
|
} from "../../../lib/renderer/Singleton";
|
||||||
|
|
||||||
import { useApplicationState } from "../../../mobx/State";
|
import { useApplicationState } from "../../../mobx/State";
|
||||||
import { dispatch, getState } from "../../../redux";
|
|
||||||
import { Reply } from "../../../redux/reducers/queue";
|
import { Reply } from "../../../redux/reducers/queue";
|
||||||
|
|
||||||
import { SoundContext } from "../../../context/Settings";
|
|
||||||
import { useIntermediate } from "../../../context/intermediate/Intermediate";
|
import { useIntermediate } from "../../../context/intermediate/Intermediate";
|
||||||
import {
|
import {
|
||||||
FileUploader,
|
FileUploader,
|
||||||
|
@ -123,7 +121,6 @@ export default observer(({ channel }: Props) => {
|
||||||
});
|
});
|
||||||
const [typing, setTyping] = useState<boolean | number>(false);
|
const [typing, setTyping] = useState<boolean | number>(false);
|
||||||
const [replies, setReplies] = useState<Reply[]>([]);
|
const [replies, setReplies] = useState<Reply[]>([]);
|
||||||
const playSound = useContext(SoundContext);
|
|
||||||
const { openScreen } = useIntermediate();
|
const { openScreen } = useIntermediate();
|
||||||
const client = useContext(AppContext);
|
const client = useContext(AppContext);
|
||||||
const translate = useTranslation();
|
const translate = useTranslation();
|
||||||
|
@ -242,7 +239,7 @@ export default observer(({ channel }: Props) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
playSound("outbound");
|
state.settings.sounds.playSound("outbound");
|
||||||
|
|
||||||
state.queue.add(nonce, channel._id, {
|
state.queue.add(nonce, channel._id, {
|
||||||
_id: nonce,
|
_id: nonce,
|
||||||
|
@ -351,7 +348,7 @@ export default observer(({ channel }: Props) => {
|
||||||
|
|
||||||
setMessage();
|
setMessage();
|
||||||
setReplies([]);
|
setReplies([]);
|
||||||
playSound("outbound");
|
state.settings.sounds.playSound("outbound");
|
||||||
|
|
||||||
if (files.length > CAN_UPLOAD_AT_ONCE) {
|
if (files.length > CAN_UPLOAD_AT_ONCE) {
|
||||||
setUploadState({
|
setUploadState({
|
||||||
|
|
|
@ -2,8 +2,7 @@ import styled from "styled-components";
|
||||||
|
|
||||||
import { Text } from "preact-i18n";
|
import { Text } from "preact-i18n";
|
||||||
|
|
||||||
import { EmojiPack } from "../../../mobx/stores/Settings";
|
import { EmojiPack } from "../../common/Emoji";
|
||||||
|
|
||||||
import mutantSVG from "./mutant_emoji.svg";
|
import mutantSVG from "./mutant_emoji.svg";
|
||||||
import notoSVG from "./noto_emoji.svg";
|
import notoSVG from "./noto_emoji.svg";
|
||||||
import openmojiSVG from "./openmoji_emoji.svg";
|
import openmojiSVG from "./openmoji_emoji.svg";
|
||||||
|
|
|
@ -1,61 +0,0 @@
|
||||||
// This code is more or less redundant, but settings has so little state
|
|
||||||
// updates that I can't be asked to pass everything through props each
|
|
||||||
// time when I can just use the Context API.
|
|
||||||
//
|
|
||||||
// Replace references to SettingsContext with connectState in the future
|
|
||||||
// if it does cause problems though.
|
|
||||||
//
|
|
||||||
// This now also supports Audio stuff.
|
|
||||||
import defaultsDeep from "lodash.defaultsdeep";
|
|
||||||
|
|
||||||
import { createContext } from "preact";
|
|
||||||
import { useMemo } from "preact/hooks";
|
|
||||||
|
|
||||||
import { connectState } from "../redux/connector";
|
|
||||||
import {
|
|
||||||
DEFAULT_SOUNDS,
|
|
||||||
Settings,
|
|
||||||
SoundOptions,
|
|
||||||
} from "../redux/reducers/settings";
|
|
||||||
|
|
||||||
import { playSound, Sounds } from "../assets/sounds/Audio";
|
|
||||||
import { Children } from "../types/Preact";
|
|
||||||
|
|
||||||
export const SettingsContext = createContext<Settings>({});
|
|
||||||
export const SoundContext = createContext<(sound: Sounds) => void>(null!);
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
children?: Children;
|
|
||||||
settings: Settings;
|
|
||||||
}
|
|
||||||
|
|
||||||
function SettingsProvider({ settings, children }: Props) {
|
|
||||||
const play = useMemo(() => {
|
|
||||||
const enabled: SoundOptions = defaultsDeep(
|
|
||||||
settings.notification?.sounds ?? {},
|
|
||||||
DEFAULT_SOUNDS,
|
|
||||||
);
|
|
||||||
return (sound: Sounds) => {
|
|
||||||
if (enabled[sound]) {
|
|
||||||
playSound(sound);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}, [settings.notification]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<SettingsContext.Provider value={settings}>
|
|
||||||
<SoundContext.Provider value={play}>
|
|
||||||
{children}
|
|
||||||
</SoundContext.Provider>
|
|
||||||
</SettingsContext.Provider>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connectState<Omit<Props, "settings">>(
|
|
||||||
SettingsProvider,
|
|
||||||
(state) => {
|
|
||||||
return {
|
|
||||||
settings: state.settings,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
);
|
|
|
@ -4,7 +4,6 @@ import State from "../redux/State";
|
||||||
|
|
||||||
import { Children } from "../types/Preact";
|
import { Children } from "../types/Preact";
|
||||||
import Locale from "./Locale";
|
import Locale from "./Locale";
|
||||||
import Settings from "./Settings";
|
|
||||||
import Theme from "./Theme";
|
import Theme from "./Theme";
|
||||||
import Intermediate from "./intermediate/Intermediate";
|
import Intermediate from "./intermediate/Intermediate";
|
||||||
import Client from "./revoltjs/RevoltClient";
|
import Client from "./revoltjs/RevoltClient";
|
||||||
|
@ -17,13 +16,11 @@ export default function Context({ children }: { children: Children }) {
|
||||||
return (
|
return (
|
||||||
<Router basename={import.meta.env.BASE_URL}>
|
<Router basename={import.meta.env.BASE_URL}>
|
||||||
<State>
|
<State>
|
||||||
<Settings>
|
<Locale>
|
||||||
<Locale>
|
<Intermediate>
|
||||||
<Intermediate>
|
<Client>{children}</Client>
|
||||||
<Client>{children}</Client>
|
</Intermediate>
|
||||||
</Intermediate>
|
</Locale>
|
||||||
</Locale>
|
|
||||||
</Settings>
|
|
||||||
<Theme />
|
<Theme />
|
||||||
</State>
|
</State>
|
||||||
</Router>
|
</Router>
|
||||||
|
|
|
@ -9,21 +9,9 @@ import { useCallback, useContext, useEffect } from "preact/hooks";
|
||||||
import { useTranslation } from "../../lib/i18n";
|
import { useTranslation } from "../../lib/i18n";
|
||||||
|
|
||||||
import { useApplicationState } from "../../mobx/State";
|
import { useApplicationState } from "../../mobx/State";
|
||||||
import { connectState } from "../../redux/connector";
|
|
||||||
import {
|
|
||||||
getNotificationState,
|
|
||||||
Notifications,
|
|
||||||
shouldNotify,
|
|
||||||
} from "../../redux/reducers/notifications";
|
|
||||||
import { NotificationOptions } from "../../redux/reducers/settings";
|
|
||||||
|
|
||||||
import { SoundContext } from "../Settings";
|
|
||||||
import { AppContext } from "./RevoltClient";
|
import { AppContext } from "./RevoltClient";
|
||||||
|
|
||||||
interface Props {
|
|
||||||
options?: NotificationOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
const notifications: { [key: string]: Notification } = {};
|
const notifications: { [key: string]: Notification } = {};
|
||||||
|
|
||||||
async function createNotification(
|
async function createNotification(
|
||||||
|
@ -38,10 +26,11 @@ async function createNotification(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function Notifier({ options }: Props) {
|
function Notifier() {
|
||||||
const translate = useTranslation();
|
const translate = useTranslation();
|
||||||
const showNotification = options?.desktopEnabled ?? false;
|
const state = useApplicationState();
|
||||||
const notifs = useApplicationState().notifications;
|
const notifs = state.notifications;
|
||||||
|
const showNotification = state.settings.get("notifications:desktop");
|
||||||
|
|
||||||
const client = useContext(AppContext);
|
const client = useContext(AppContext);
|
||||||
const { guild: guild_id, channel: channel_id } = useParams<{
|
const { guild: guild_id, channel: channel_id } = useParams<{
|
||||||
|
@ -49,14 +38,13 @@ function Notifier({ options }: Props) {
|
||||||
channel: string;
|
channel: string;
|
||||||
}>();
|
}>();
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
const playSound = useContext(SoundContext);
|
|
||||||
|
|
||||||
const message = useCallback(
|
const message = useCallback(
|
||||||
async (msg: Message) => {
|
async (msg: Message) => {
|
||||||
if (msg.channel_id === channel_id && document.hasFocus()) return;
|
if (msg.channel_id === channel_id && document.hasFocus()) return;
|
||||||
if (!notifs.shouldNotify(msg)) return;
|
if (!notifs.shouldNotify(msg)) return;
|
||||||
|
|
||||||
playSound("message");
|
state.settings.sounds.playSound("message");
|
||||||
if (!showNotification) return;
|
if (!showNotification) return;
|
||||||
|
|
||||||
let title;
|
let title;
|
||||||
|
@ -209,7 +197,7 @@ function Notifier({ options }: Props) {
|
||||||
channel_id,
|
channel_id,
|
||||||
client,
|
client,
|
||||||
notifs,
|
notifs,
|
||||||
playSound,
|
state,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -257,7 +245,7 @@ function Notifier({ options }: Props) {
|
||||||
};
|
};
|
||||||
}, [
|
}, [
|
||||||
client,
|
client,
|
||||||
playSound,
|
state,
|
||||||
guild_id,
|
guild_id,
|
||||||
channel_id,
|
channel_id,
|
||||||
showNotification,
|
showNotification,
|
||||||
|
@ -285,27 +273,17 @@ function Notifier({ options }: Props) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const NotifierComponent = connectState(
|
|
||||||
Notifier,
|
|
||||||
(state) => {
|
|
||||||
return {
|
|
||||||
options: state.settings.notification,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
|
|
||||||
export default function NotificationsComponent() {
|
export default function NotificationsComponent() {
|
||||||
return (
|
return (
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route path="/server/:server/channel/:channel">
|
<Route path="/server/:server/channel/:channel">
|
||||||
<NotifierComponent />
|
<Notifier />
|
||||||
</Route>
|
</Route>
|
||||||
<Route path="/channel/:channel">
|
<Route path="/channel/:channel">
|
||||||
<NotifierComponent />
|
<Notifier />
|
||||||
</Route>
|
</Route>
|
||||||
<Route path="/">
|
<Route path="/">
|
||||||
<NotifierComponent />
|
<Notifier />
|
||||||
</Route>
|
</Route>
|
||||||
</Switch>
|
</Switch>
|
||||||
);
|
);
|
||||||
|
|
|
@ -4,17 +4,13 @@ import { mapToRecord } from "../../lib/conversion";
|
||||||
|
|
||||||
import { Fonts, MonospaceFonts, Overrides } from "../../context/Theme";
|
import { Fonts, MonospaceFonts, Overrides } from "../../context/Theme";
|
||||||
|
|
||||||
import { Sounds } from "../../assets/sounds/Audio";
|
import { EmojiPack } from "../../components/common/Emoji";
|
||||||
|
|
||||||
import Persistent from "../interfaces/Persistent";
|
import Persistent from "../interfaces/Persistent";
|
||||||
import Store from "../interfaces/Store";
|
import Store from "../interfaces/Store";
|
||||||
|
import SAudio, { SoundOptions } from "./helpers/SAudio";
|
||||||
import STheme from "./helpers/STheme";
|
import STheme from "./helpers/STheme";
|
||||||
|
|
||||||
export type SoundOptions = {
|
|
||||||
[key in Sounds]?: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type EmojiPack = "mutant" | "twemoji" | "noto" | "openmoji";
|
|
||||||
|
|
||||||
interface ISettings {
|
interface ISettings {
|
||||||
"notifications:desktop": boolean;
|
"notifications:desktop": boolean;
|
||||||
"notifications:sounds": SoundOptions;
|
"notifications:sounds": SoundOptions;
|
||||||
|
@ -37,6 +33,7 @@ export default class Settings implements Store, Persistent<ISettings> {
|
||||||
private data: ObservableMap<string, unknown>;
|
private data: ObservableMap<string, unknown>;
|
||||||
|
|
||||||
theme: STheme;
|
theme: STheme;
|
||||||
|
sounds: SAudio;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct new Settings store.
|
* Construct new Settings store.
|
||||||
|
@ -46,6 +43,7 @@ export default class Settings implements Store, Persistent<ISettings> {
|
||||||
makeAutoObservable(this);
|
makeAutoObservable(this);
|
||||||
|
|
||||||
this.theme = new STheme(this);
|
this.theme = new STheme(this);
|
||||||
|
this.sounds = new SAudio(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
get id() {
|
get id() {
|
||||||
|
|
107
src/mobx/stores/helpers/SAudio.ts
Normal file
107
src/mobx/stores/helpers/SAudio.ts
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
import { makeAutoObservable, computed, action } from "mobx";
|
||||||
|
|
||||||
|
import Settings from "../Settings";
|
||||||
|
import call_join from "./call_join.mp3";
|
||||||
|
import call_leave from "./call_leave.mp3";
|
||||||
|
import message from "./message.mp3";
|
||||||
|
import outbound from "./outbound.mp3";
|
||||||
|
|
||||||
|
export type Sounds = "message" | "outbound" | "call_join" | "call_leave";
|
||||||
|
|
||||||
|
export interface Sound {
|
||||||
|
enabled: boolean;
|
||||||
|
path: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type SoundOptions = {
|
||||||
|
[key in Sounds]?: Partial<Sound>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const DefaultSoundPack: { [key in Sounds]: string } = {
|
||||||
|
message,
|
||||||
|
outbound,
|
||||||
|
call_join,
|
||||||
|
call_leave,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ALL_SOUNDS: Sounds[] = [
|
||||||
|
"message",
|
||||||
|
"outbound",
|
||||||
|
"call_join",
|
||||||
|
"call_leave",
|
||||||
|
];
|
||||||
|
export const DEFAULT_SOUNDS: Sounds[] = ["message", "call_join", "call_leave"];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper class for reading and writing themes.
|
||||||
|
*/
|
||||||
|
export default class SAudio {
|
||||||
|
private settings: Settings;
|
||||||
|
private cache: Map<string, HTMLAudioElement>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a new sound helper.
|
||||||
|
* @param settings Settings parent class
|
||||||
|
*/
|
||||||
|
constructor(settings: Settings) {
|
||||||
|
this.settings = settings;
|
||||||
|
makeAutoObservable(this);
|
||||||
|
|
||||||
|
this.cache = new Map();
|
||||||
|
|
||||||
|
// Asynchronously load Audio files into cache.
|
||||||
|
setTimeout(() => this.loadCache(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@action setEnabled(sound: Sounds, enabled: boolean) {
|
||||||
|
const obj = this.settings.get("notifications:sounds");
|
||||||
|
this.settings.set("notifications:sounds", {
|
||||||
|
...obj,
|
||||||
|
[sound]: {
|
||||||
|
...obj?.[sound],
|
||||||
|
enabled,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@computed getSound(sound: Sounds, options?: SoundOptions): Sound {
|
||||||
|
return {
|
||||||
|
path: DefaultSoundPack[sound],
|
||||||
|
enabled: DEFAULT_SOUNDS.includes(sound),
|
||||||
|
...(options ?? this.settings.get("notifications:sounds"))?.[sound],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@computed getState(): ({ id: Sounds } & Sound)[] {
|
||||||
|
const options = this.settings.get("notifications:sounds");
|
||||||
|
return ALL_SOUNDS.map((id) => {
|
||||||
|
return { id, ...this.getSound(id, options) };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getAudio(path: string) {
|
||||||
|
if (this.cache.has(path)) {
|
||||||
|
return this.cache.get(path)!;
|
||||||
|
} else {
|
||||||
|
const el = new Audio(path);
|
||||||
|
this.cache.set(path, el);
|
||||||
|
return el;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loadCache() {
|
||||||
|
this.getState().map(({ path }) => this.getAudio(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
playSound(sound: Sounds) {
|
||||||
|
const definition = this.getSound(sound);
|
||||||
|
if (definition.enabled) {
|
||||||
|
const audio = this.getAudio(definition.path);
|
||||||
|
try {
|
||||||
|
audio.play();
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Hit error while playing", sound + ":", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,26 +1,19 @@
|
||||||
import defaultsDeep from "lodash.defaultsdeep";
|
|
||||||
|
|
||||||
import styles from "./Panes.module.scss";
|
import styles from "./Panes.module.scss";
|
||||||
import { Text } from "preact-i18n";
|
import { Text } from "preact-i18n";
|
||||||
import { useContext, useEffect, useState } from "preact/hooks";
|
import { useContext, useEffect, useState } from "preact/hooks";
|
||||||
|
|
||||||
import { urlBase64ToUint8Array } from "../../../lib/conversion";
|
import { urlBase64ToUint8Array } from "../../../lib/conversion";
|
||||||
|
|
||||||
|
import { useApplicationState } from "../../../mobx/State";
|
||||||
import { dispatch } from "../../../redux";
|
import { dispatch } from "../../../redux";
|
||||||
import { connectState } from "../../../redux/connector";
|
import { connectState } from "../../../redux/connector";
|
||||||
import {
|
import { NotificationOptions } from "../../../redux/reducers/settings";
|
||||||
DEFAULT_SOUNDS,
|
|
||||||
NotificationOptions,
|
|
||||||
SoundOptions,
|
|
||||||
} from "../../../redux/reducers/settings";
|
|
||||||
|
|
||||||
import { useIntermediate } from "../../../context/intermediate/Intermediate";
|
import { useIntermediate } from "../../../context/intermediate/Intermediate";
|
||||||
import { AppContext } from "../../../context/revoltjs/RevoltClient";
|
import { AppContext } from "../../../context/revoltjs/RevoltClient";
|
||||||
|
|
||||||
import Checkbox from "../../../components/ui/Checkbox";
|
import Checkbox from "../../../components/ui/Checkbox";
|
||||||
|
|
||||||
import { SOUNDS_ARRAY } from "../../../assets/sounds/Audio";
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
options?: NotificationOptions;
|
options?: NotificationOptions;
|
||||||
}
|
}
|
||||||
|
@ -28,6 +21,7 @@ interface Props {
|
||||||
export function Component({ options }: Props) {
|
export function Component({ options }: Props) {
|
||||||
const client = useContext(AppContext);
|
const client = useContext(AppContext);
|
||||||
const { openScreen } = useIntermediate();
|
const { openScreen } = useIntermediate();
|
||||||
|
const sounds = useApplicationState().settings.sounds;
|
||||||
const [pushEnabled, setPushEnabled] = useState<undefined | boolean>(
|
const [pushEnabled, setPushEnabled] = useState<undefined | boolean>(
|
||||||
undefined,
|
undefined,
|
||||||
);
|
);
|
||||||
|
@ -42,10 +36,6 @@ export function Component({ options }: Props) {
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const enabledSounds: SoundOptions = defaultsDeep(
|
|
||||||
options?.sounds ?? {},
|
|
||||||
DEFAULT_SOUNDS,
|
|
||||||
);
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.notifications}>
|
<div className={styles.notifications}>
|
||||||
<h3>
|
<h3>
|
||||||
|
@ -125,24 +115,12 @@ export function Component({ options }: Props) {
|
||||||
<h3>
|
<h3>
|
||||||
<Text id="app.settings.pages.notifications.sounds" />
|
<Text id="app.settings.pages.notifications.sounds" />
|
||||||
</h3>
|
</h3>
|
||||||
{SOUNDS_ARRAY.map((key) => (
|
{sounds.getState().map(({ id, enabled }) => (
|
||||||
<Checkbox
|
<Checkbox
|
||||||
key={key}
|
key={id}
|
||||||
checked={!!enabledSounds[key]}
|
checked={enabled}
|
||||||
onChange={(enabled) =>
|
onChange={(enabled) => sounds.setEnabled(id, enabled)}>
|
||||||
dispatch({
|
<Text id={`app.settings.pages.notifications.sound.${id}`} />
|
||||||
type: "SETTINGS_SET_NOTIFICATION_OPTIONS",
|
|
||||||
options: {
|
|
||||||
sounds: {
|
|
||||||
...options?.sounds,
|
|
||||||
[key]: enabled,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}>
|
|
||||||
<Text
|
|
||||||
id={`app.settings.pages.notifications.sound.${key}`}
|
|
||||||
/>
|
|
||||||
</Checkbox>
|
</Checkbox>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -2,9 +2,10 @@ import type { Theme, ThemeOptions } from "../../context/Theme";
|
||||||
|
|
||||||
import { setGlobalEmojiPack } from "../../components/common/Emoji";
|
import { setGlobalEmojiPack } from "../../components/common/Emoji";
|
||||||
|
|
||||||
import type { Sounds } from "../../assets/sounds/Audio";
|
|
||||||
import type { SyncUpdateAction } from "./sync";
|
import type { SyncUpdateAction } from "./sync";
|
||||||
|
|
||||||
|
type Sounds = "message" | "outbound" | "call_join" | "call_leave";
|
||||||
|
|
||||||
export type SoundOptions = {
|
export type SoundOptions = {
|
||||||
[key in Sounds]?: boolean;
|
[key in Sounds]?: boolean;
|
||||||
};
|
};
|
||||||
|
|
|
@ -78,11 +78,10 @@ export function UI() {
|
||||||
|
|
||||||
render(
|
render(
|
||||||
<>
|
<>
|
||||||
<Theme>
|
<UIDemo>
|
||||||
<UIDemo>
|
<UI />
|
||||||
<UI />
|
</UIDemo>
|
||||||
</UIDemo>
|
<Theme />
|
||||||
</Theme>
|
|
||||||
</>,
|
</>,
|
||||||
document.getElementById("app")!,
|
document.getElementById("app")!,
|
||||||
);
|
);
|
||||||
|
|
|
@ -3877,11 +3877,6 @@ serialize-javascript@^4.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
randombytes "^2.1.0"
|
randombytes "^2.1.0"
|
||||||
|
|
||||||
shade-blend-color@^1.0.0:
|
|
||||||
version "1.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/shade-blend-color/-/shade-blend-color-1.0.0.tgz#cfa10d3673a22ba31d552a0e793b708bc24be0bc"
|
|
||||||
integrity sha512-Tnp/ppF5h3YhPCpeHiZJ2DRnvmo4luu9qpMhuksCT+QInIXJ9alA3Vd9klfEi+RY8Oh7MaK5vzH/qcLo892L1g==
|
|
||||||
|
|
||||||
shallowequal@^1.1.0:
|
shallowequal@^1.1.0:
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8"
|
resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8"
|
||||||
|
|
Loading…
Reference in a new issue