Merge branch 'develop' into kegan/lists-as-keys
commit
6ec25234d7
|
@ -1,3 +1,9 @@
|
||||||
|
Changes in [3.64.2](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.64.2) (2023-01-20)
|
||||||
|
=====================================================================================================
|
||||||
|
|
||||||
|
## 🐛 Bug Fixes
|
||||||
|
* Fix second occurence of a crash in older browsers
|
||||||
|
|
||||||
Changes in [3.64.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.64.1) (2023-01-18)
|
Changes in [3.64.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.64.1) (2023-01-18)
|
||||||
=====================================================================================================
|
=====================================================================================================
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "matrix-react-sdk",
|
"name": "matrix-react-sdk",
|
||||||
"version": "3.64.1",
|
"version": "3.64.2",
|
||||||
"description": "SDK for matrix.org using React",
|
"description": "SDK for matrix.org using React",
|
||||||
"author": "matrix.org",
|
"author": "matrix.org",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
@ -57,7 +57,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.12.5",
|
"@babel/runtime": "^7.12.5",
|
||||||
"@matrix-org/analytics-events": "^0.4.0",
|
"@matrix-org/analytics-events": "^0.4.0",
|
||||||
"@matrix-org/matrix-wysiwyg": "^0.19.0",
|
"@matrix-org/matrix-wysiwyg": "^0.20.0",
|
||||||
"@matrix-org/react-sdk-module-api": "^0.0.3",
|
"@matrix-org/react-sdk-module-api": "^0.0.3",
|
||||||
"@sentry/browser": "^7.0.0",
|
"@sentry/browser": "^7.0.0",
|
||||||
"@sentry/tracing": "^7.0.0",
|
"@sentry/tracing": "^7.0.0",
|
||||||
|
|
|
@ -84,7 +84,7 @@ limitations under the License.
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
&:hover,
|
&:hover,
|
||||||
&:focus {
|
&:focus-visible {
|
||||||
background-color: $menu-selected-color;
|
background-color: $menu-selected-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -108,7 +108,7 @@ limitations under the License.
|
||||||
display: flex;
|
display: flex;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
|
|
||||||
&:not(.mx_RoomHeader_name--textonly):hover {
|
&:hover {
|
||||||
background-color: $quinary-content;
|
background-color: $quinary-content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,9 +44,21 @@ limitations under the License.
|
||||||
padding-inline-start: $spacing-28;
|
padding-inline-start: $spacing-28;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
blockquote {
|
||||||
|
color: #777;
|
||||||
|
border-left: 2px solid $blockquote-bar-color;
|
||||||
|
border-radius: 2px;
|
||||||
|
padding: 0 10px;
|
||||||
|
|
||||||
|
margin-block-start: 0;
|
||||||
|
margin-block-end: 0;
|
||||||
|
margin-inline-start: 0;
|
||||||
|
margin-inline-end: 0;
|
||||||
|
}
|
||||||
|
|
||||||
// model output always includes a linebreak but we do not want the user
|
// model output always includes a linebreak but we do not want the user
|
||||||
// to see it when writing input in lists
|
// to see it when writing input in lists
|
||||||
:is(ol, ul, pre) + br:last-of-type {
|
:is(ol, ul, pre, blockquote) + br:last-of-type {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,4 +17,5 @@ limitations under the License.
|
||||||
.mx_CallDuration {
|
.mx_CallDuration {
|
||||||
color: $secondary-content;
|
color: $secondary-content;
|
||||||
font-size: $font-12px;
|
font-size: $font-12px;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
|
@ -160,7 +160,7 @@ limitations under the License.
|
||||||
content: "";
|
content: "";
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
mask-image: url("$(res)/img/feather-customised/chevron-down.svg");
|
mask-image: url("$(res)/img/feather-customised/chevron-down.svg");
|
||||||
mask-size: $size;
|
mask-size: 20px;
|
||||||
mask-position: center;
|
mask-position: center;
|
||||||
background-color: $call-primary-content;
|
background-color: $call-primary-content;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
@ -181,7 +181,7 @@ limitations under the License.
|
||||||
.mx_CallView_deviceButton {
|
.mx_CallView_deviceButton {
|
||||||
&.mx_CallView_deviceButton_audio::before {
|
&.mx_CallView_deviceButton_audio::before {
|
||||||
mask-image: url("$(res)/img/element-icons/Mic-off.svg");
|
mask-image: url("$(res)/img/element-icons/Mic-off.svg");
|
||||||
mask-size: 14px;
|
mask-size: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.mx_CallView_deviceButton_video::before {
|
&.mx_CallView_deviceButton_video::before {
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
<svg width="14" height="12" viewBox="0 0 14 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M2.1458 0.893371C2.20888 0.465499 1.90205 0.0690897 1.46046 0.00796516C1.01887 -0.0531594 0.609758 0.244148 0.546674 0.67202L0.00822047 4.32413C-0.0548633 4.752 0.251974 5.14841 0.69356 5.20954C1.13515 5.27066 1.54426 4.97336 1.60735 4.54548L2.1458 0.893371Z" fill="currentColor"/>
|
||||||
|
<path d="M10.2226 7.67587C10.2857 7.248 9.97885 6.85159 9.53726 6.79046C9.09568 6.72934 8.68656 7.02664 8.62348 7.45452L8.08502 11.1066C8.02194 11.5345 8.32878 11.9309 8.77036 11.992C9.21195 12.0532 9.62107 11.7559 9.68415 11.328L10.2226 7.67587Z" fill="currentColor"/>
|
||||||
|
<path d="M5.21224 0.00574343C5.65509 0.0575575 5.97074 0.447414 5.91727 0.876513L5.90255 0.993287C5.89309 1.06788 5.87936 1.17541 5.86224 1.30757C5.828 1.57178 5.78013 1.93492 5.72561 2.33035C5.6179 3.11153 5.48009 4.04989 5.36895 4.58829C5.28147 5.01211 4.85597 5.28697 4.41856 5.20221C3.98115 5.11744 3.69748 4.70515 3.78496 4.28133C3.88411 3.80099 4.01552 2.91329 4.12447 2.12309C4.17828 1.73284 4.22559 1.37397 4.25946 1.11259C4.27639 0.981947 4.28994 0.875787 4.29925 0.802389L4.31351 0.689266C4.36698 0.260167 4.76938 -0.0460706 5.21224 0.00574343Z" fill="currentColor"/>
|
||||||
|
<path d="M13.9918 7.67587C14.0549 7.248 13.748 6.85159 13.3064 6.79046C12.8649 6.72934 12.4557 7.02664 12.3927 7.45452L11.8542 11.1066C11.7911 11.5345 12.098 11.9309 12.5395 11.992C12.9811 12.0532 13.3902 11.7559 13.4533 11.328L13.9918 7.67587Z" fill="currentColor"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.5 KiB |
|
@ -336,6 +336,7 @@ export class MessageComposer extends React.Component<IProps, IState> {
|
||||||
const { permalinkCreator, relation, replyToEvent } = this.props;
|
const { permalinkCreator, relation, replyToEvent } = this.props;
|
||||||
const composerContent = this.state.composerContent;
|
const composerContent = this.state.composerContent;
|
||||||
this.setState({ composerContent: "", initialComposerContent: "" });
|
this.setState({ composerContent: "", initialComposerContent: "" });
|
||||||
|
dis.dispatch({ action: Action.ClearAndFocusSendMessageComposer });
|
||||||
await sendMessage(composerContent, this.state.isRichTextEnabled, {
|
await sendMessage(composerContent, this.state.isRichTextEnabled, {
|
||||||
mxClient: this.props.mxClient,
|
mxClient: this.props.mxClient,
|
||||||
roomContext: this.context,
|
roomContext: this.context,
|
||||||
|
@ -343,7 +344,6 @@ export class MessageComposer extends React.Component<IProps, IState> {
|
||||||
relation,
|
relation,
|
||||||
replyToEvent,
|
replyToEvent,
|
||||||
});
|
});
|
||||||
dis.dispatch({ action: Action.ClearAndFocusSendMessageComposer });
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -743,6 +743,13 @@ export default class RoomHeader extends React.Component<IProps, IState> {
|
||||||
|
|
||||||
const buttons = this.props.showButtons ? this.renderButtons(isVideoRoom) : null;
|
const buttons = this.props.showButtons ? this.renderButtons(isVideoRoom) : null;
|
||||||
|
|
||||||
|
let oobName = _t("Join Room");
|
||||||
|
if (this.props.oobData && this.props.oobData.name) {
|
||||||
|
oobName = this.props.oobData.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
const name = this.renderName(oobName);
|
||||||
|
|
||||||
if (this.props.viewingCall && !isVideoRoom) {
|
if (this.props.viewingCall && !isVideoRoom) {
|
||||||
return (
|
return (
|
||||||
<header className="mx_RoomHeader light-panel">
|
<header className="mx_RoomHeader light-panel">
|
||||||
|
@ -752,9 +759,7 @@ export default class RoomHeader extends React.Component<IProps, IState> {
|
||||||
>
|
>
|
||||||
<div className="mx_RoomHeader_avatar">{roomAvatar}</div>
|
<div className="mx_RoomHeader_avatar">{roomAvatar}</div>
|
||||||
{icon}
|
{icon}
|
||||||
<div className="mx_RoomHeader_name mx_RoomHeader_name--textonly mx_RoomHeader_name--small">
|
{name}
|
||||||
{_t("Video call")}
|
|
||||||
</div>
|
|
||||||
{this.props.activeCall instanceof ElementCall && (
|
{this.props.activeCall instanceof ElementCall && (
|
||||||
<GroupCallDuration groupCall={this.props.activeCall.groupCall} />
|
<GroupCallDuration groupCall={this.props.activeCall.groupCall} />
|
||||||
)}
|
)}
|
||||||
|
@ -779,13 +784,6 @@ export default class RoomHeader extends React.Component<IProps, IState> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let oobName = _t("Join Room");
|
|
||||||
if (this.props.oobData && this.props.oobData.name) {
|
|
||||||
oobName = this.props.oobData.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
const name = this.renderName(oobName);
|
|
||||||
|
|
||||||
const topicElement = <RoomTopic room={this.props.room} className="mx_RoomHeader_topic" />;
|
const topicElement = <RoomTopic room={this.props.room} className="mx_RoomHeader_topic" />;
|
||||||
|
|
||||||
const viewLabs = (): void =>
|
const viewLabs = (): void =>
|
||||||
|
|
|
@ -22,6 +22,7 @@ import { Icon as BoldIcon } from "../../../../../../res/img/element-icons/room/c
|
||||||
import { Icon as ItalicIcon } from "../../../../../../res/img/element-icons/room/composer/italic.svg";
|
import { Icon as ItalicIcon } from "../../../../../../res/img/element-icons/room/composer/italic.svg";
|
||||||
import { Icon as UnderlineIcon } from "../../../../../../res/img/element-icons/room/composer/underline.svg";
|
import { Icon as UnderlineIcon } from "../../../../../../res/img/element-icons/room/composer/underline.svg";
|
||||||
import { Icon as StrikeThroughIcon } from "../../../../../../res/img/element-icons/room/composer/strikethrough.svg";
|
import { Icon as StrikeThroughIcon } from "../../../../../../res/img/element-icons/room/composer/strikethrough.svg";
|
||||||
|
import { Icon as QuoteIcon } from "../../../../../../res/img/element-icons/room/composer/quote.svg";
|
||||||
import { Icon as InlineCodeIcon } from "../../../../../../res/img/element-icons/room/composer/inline_code.svg";
|
import { Icon as InlineCodeIcon } from "../../../../../../res/img/element-icons/room/composer/inline_code.svg";
|
||||||
import { Icon as LinkIcon } from "../../../../../../res/img/element-icons/room/composer/link.svg";
|
import { Icon as LinkIcon } from "../../../../../../res/img/element-icons/room/composer/link.svg";
|
||||||
import { Icon as BulletedListIcon } from "../../../../../../res/img/element-icons/room/composer/bulleted_list.svg";
|
import { Icon as BulletedListIcon } from "../../../../../../res/img/element-icons/room/composer/bulleted_list.svg";
|
||||||
|
@ -126,6 +127,12 @@ export function FormattingButtons({ composer, actionStates }: FormattingButtonsP
|
||||||
onClick={() => composer.orderedList()}
|
onClick={() => composer.orderedList()}
|
||||||
icon={<NumberedListIcon className="mx_FormattingButtons_Icon" />}
|
icon={<NumberedListIcon className="mx_FormattingButtons_Icon" />}
|
||||||
/>
|
/>
|
||||||
|
<Button
|
||||||
|
actionState={actionStates.quote}
|
||||||
|
label={_td("Quote")}
|
||||||
|
onClick={() => composer.quote()}
|
||||||
|
icon={<QuoteIcon className="mx_FormattingButtons_Icon" />}
|
||||||
|
/>
|
||||||
<Button
|
<Button
|
||||||
actionState={actionStates.inlineCode}
|
actionState={actionStates.inlineCode}
|
||||||
label={_td("Code")}
|
label={_td("Code")}
|
||||||
|
|
|
@ -38,7 +38,7 @@ import IconizedContextMenu, {
|
||||||
IconizedContextMenuOption,
|
IconizedContextMenuOption,
|
||||||
IconizedContextMenuOptionList,
|
IconizedContextMenuOptionList,
|
||||||
} from "../context_menus/IconizedContextMenu";
|
} from "../context_menus/IconizedContextMenu";
|
||||||
import { aboveLeftOf, ContextMenuButton, useContextMenu } from "../../structures/ContextMenu";
|
import { aboveRightOf, ContextMenuButton, useContextMenu } from "../../structures/ContextMenu";
|
||||||
import { Alignment } from "../elements/Tooltip";
|
import { Alignment } from "../elements/Tooltip";
|
||||||
import { ButtonEvent } from "../elements/AccessibleButton";
|
import { ButtonEvent } from "../elements/AccessibleButton";
|
||||||
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
|
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
|
||||||
|
@ -81,7 +81,7 @@ const DeviceButton: FC<DeviceButtonProps> = ({
|
||||||
if (showMenu) {
|
if (showMenu) {
|
||||||
const buttonRect = buttonRef.current!.getBoundingClientRect();
|
const buttonRect = buttonRef.current!.getBoundingClientRect();
|
||||||
contextMenu = (
|
contextMenu = (
|
||||||
<IconizedContextMenu {...aboveLeftOf(buttonRect)} onFinished={closeMenu}>
|
<IconizedContextMenu {...aboveRightOf(buttonRect, undefined, 10)} onFinished={closeMenu}>
|
||||||
<IconizedContextMenuOptionList>
|
<IconizedContextMenuOptionList>
|
||||||
{devices.map((d) => (
|
{devices.map((d) => (
|
||||||
<IconizedContextMenuOption key={d.deviceId} label={d.label} onClick={() => selectDevice(d)} />
|
<IconizedContextMenuOption key={d.deviceId} label={d.label} onClick={() => selectDevice(d)} />
|
||||||
|
@ -101,6 +101,7 @@ const DeviceButton: FC<DeviceButtonProps> = ({
|
||||||
>
|
>
|
||||||
<AccessibleTooltipButton
|
<AccessibleTooltipButton
|
||||||
className={`mx_CallView_deviceButton mx_CallView_deviceButton_${kind}`}
|
className={`mx_CallView_deviceButton mx_CallView_deviceButton_${kind}`}
|
||||||
|
inputRef={buttonRef}
|
||||||
title={muted ? mutedTitle : unmutedTitle}
|
title={muted ? mutedTitle : unmutedTitle}
|
||||||
alignment={Alignment.Top}
|
alignment={Alignment.Top}
|
||||||
onClick={toggle}
|
onClick={toggle}
|
||||||
|
@ -109,7 +110,6 @@ const DeviceButton: FC<DeviceButtonProps> = ({
|
||||||
{devices.length > 1 ? (
|
{devices.length > 1 ? (
|
||||||
<ContextMenuButton
|
<ContextMenuButton
|
||||||
className="mx_CallView_deviceListButton"
|
className="mx_CallView_deviceListButton"
|
||||||
inputRef={buttonRef}
|
|
||||||
onClick={openMenu}
|
onClick={openMenu}
|
||||||
isExpanded={showMenu}
|
isExpanded={showMenu}
|
||||||
label={deviceListLabel}
|
label={deviceListLabel}
|
||||||
|
|
|
@ -63,6 +63,9 @@ export function useEventEmitter(emitter: EventEmitter | undefined, eventName: st
|
||||||
|
|
||||||
type Mapper<T> = (...args: any[]) => T;
|
type Mapper<T> = (...args: any[]) => T;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link useEventEmitterState}
|
||||||
|
*/
|
||||||
export function useTypedEventEmitterState<T, Events extends string, Arguments extends ListenerMap<Events>>(
|
export function useTypedEventEmitterState<T, Events extends string, Arguments extends ListenerMap<Events>>(
|
||||||
emitter: TypedEventEmitter<Events, Arguments>,
|
emitter: TypedEventEmitter<Events, Arguments>,
|
||||||
eventName: Events,
|
eventName: Events,
|
||||||
|
@ -71,6 +74,16 @@ export function useTypedEventEmitterState<T, Events extends string, Arguments ex
|
||||||
return useEventEmitterState<T>(emitter, eventName, fn);
|
return useEventEmitterState<T>(emitter, eventName, fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a state, that can be updated by events.
|
||||||
|
*
|
||||||
|
* @param emitter The emitter sending the event
|
||||||
|
* @param eventName Event name to listen for
|
||||||
|
* @param fn The callback function, that should return the state value.
|
||||||
|
* It should have the signature of the event callback, except that all parameters are optional.
|
||||||
|
* If the params are not set, a default value for the state should be returned.
|
||||||
|
* @returns State
|
||||||
|
*/
|
||||||
export function useEventEmitterState<T>(
|
export function useEventEmitterState<T>(
|
||||||
emitter: EventEmitter | undefined,
|
emitter: EventEmitter | undefined,
|
||||||
eventName: string | symbol,
|
eventName: string | symbol,
|
||||||
|
|
|
@ -1997,9 +1997,9 @@
|
||||||
"Close call": "Close call",
|
"Close call": "Close call",
|
||||||
"View chat timeline": "View chat timeline",
|
"View chat timeline": "View chat timeline",
|
||||||
"Room options": "Room options",
|
"Room options": "Room options",
|
||||||
|
"Join Room": "Join Room",
|
||||||
"(~%(count)s results)|other": "(~%(count)s results)",
|
"(~%(count)s results)|other": "(~%(count)s results)",
|
||||||
"(~%(count)s results)|one": "(~%(count)s result)",
|
"(~%(count)s results)|one": "(~%(count)s result)",
|
||||||
"Join Room": "Join Room",
|
|
||||||
"Video rooms are a beta feature": "Video rooms are a beta feature",
|
"Video rooms are a beta feature": "Video rooms are a beta feature",
|
||||||
"Video room": "Video room",
|
"Video room": "Video room",
|
||||||
"Public space": "Public space",
|
"Public space": "Public space",
|
||||||
|
|
|
@ -14,9 +14,7 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { useState } from "react";
|
import { useTypedEventEmitterState } from "../../hooks/useEventEmitter";
|
||||||
|
|
||||||
import { useTypedEventEmitter } from "../../hooks/useEventEmitter";
|
|
||||||
import { VoiceBroadcastPlayback } from "../models/VoiceBroadcastPlayback";
|
import { VoiceBroadcastPlayback } from "../models/VoiceBroadcastPlayback";
|
||||||
import {
|
import {
|
||||||
VoiceBroadcastPlaybacksStore,
|
VoiceBroadcastPlaybacksStore,
|
||||||
|
@ -28,15 +26,11 @@ export const useCurrentVoiceBroadcastPlayback = (
|
||||||
): {
|
): {
|
||||||
currentVoiceBroadcastPlayback: VoiceBroadcastPlayback | null;
|
currentVoiceBroadcastPlayback: VoiceBroadcastPlayback | null;
|
||||||
} => {
|
} => {
|
||||||
const [currentVoiceBroadcastPlayback, setVoiceBroadcastPlayback] = useState(
|
const currentVoiceBroadcastPlayback = useTypedEventEmitterState(
|
||||||
voiceBroadcastPlaybackStore.getCurrent(),
|
|
||||||
);
|
|
||||||
|
|
||||||
useTypedEventEmitter(
|
|
||||||
voiceBroadcastPlaybackStore,
|
voiceBroadcastPlaybackStore,
|
||||||
VoiceBroadcastPlaybacksStoreEvent.CurrentChanged,
|
VoiceBroadcastPlaybacksStoreEvent.CurrentChanged,
|
||||||
(playback: VoiceBroadcastPlayback) => {
|
(playback?: VoiceBroadcastPlayback) => {
|
||||||
setVoiceBroadcastPlayback(playback);
|
return playback ?? voiceBroadcastPlaybackStore.getCurrent();
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -14,9 +14,7 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { useState } from "react";
|
import { useTypedEventEmitterState } from "../../hooks/useEventEmitter";
|
||||||
|
|
||||||
import { useTypedEventEmitter } from "../../hooks/useEventEmitter";
|
|
||||||
import { VoiceBroadcastPreRecordingStore } from "../stores/VoiceBroadcastPreRecordingStore";
|
import { VoiceBroadcastPreRecordingStore } from "../stores/VoiceBroadcastPreRecordingStore";
|
||||||
import { VoiceBroadcastPreRecording } from "../models/VoiceBroadcastPreRecording";
|
import { VoiceBroadcastPreRecording } from "../models/VoiceBroadcastPreRecording";
|
||||||
|
|
||||||
|
@ -25,12 +23,14 @@ export const useCurrentVoiceBroadcastPreRecording = (
|
||||||
): {
|
): {
|
||||||
currentVoiceBroadcastPreRecording: VoiceBroadcastPreRecording | null;
|
currentVoiceBroadcastPreRecording: VoiceBroadcastPreRecording | null;
|
||||||
} => {
|
} => {
|
||||||
const [currentVoiceBroadcastPreRecording, setCurrentVoiceBroadcastPreRecording] = useState(
|
const currentVoiceBroadcastPreRecording = useTypedEventEmitterState(
|
||||||
voiceBroadcastPreRecordingStore.getCurrent(),
|
voiceBroadcastPreRecordingStore,
|
||||||
|
"changed",
|
||||||
|
(preRecording?: VoiceBroadcastPreRecording) => {
|
||||||
|
return preRecording ?? voiceBroadcastPreRecordingStore.getCurrent();
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
useTypedEventEmitter(voiceBroadcastPreRecordingStore, "changed", setCurrentVoiceBroadcastPreRecording);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
currentVoiceBroadcastPreRecording,
|
currentVoiceBroadcastPreRecording,
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,24 +14,20 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { useState } from "react";
|
|
||||||
|
|
||||||
import { VoiceBroadcastRecording, VoiceBroadcastRecordingsStore, VoiceBroadcastRecordingsStoreEvent } from "..";
|
import { VoiceBroadcastRecording, VoiceBroadcastRecordingsStore, VoiceBroadcastRecordingsStoreEvent } from "..";
|
||||||
import { useTypedEventEmitter } from "../../hooks/useEventEmitter";
|
import { useTypedEventEmitterState } from "../../hooks/useEventEmitter";
|
||||||
|
|
||||||
export const useCurrentVoiceBroadcastRecording = (
|
export const useCurrentVoiceBroadcastRecording = (
|
||||||
voiceBroadcastRecordingsStore: VoiceBroadcastRecordingsStore,
|
voiceBroadcastRecordingsStore: VoiceBroadcastRecordingsStore,
|
||||||
): {
|
): {
|
||||||
currentVoiceBroadcastRecording: VoiceBroadcastRecording;
|
currentVoiceBroadcastRecording: VoiceBroadcastRecording;
|
||||||
} => {
|
} => {
|
||||||
const [currentVoiceBroadcastRecording, setCurrentVoiceBroadcastRecording] = useState(
|
const currentVoiceBroadcastRecording = useTypedEventEmitterState(
|
||||||
voiceBroadcastRecordingsStore.getCurrent(),
|
|
||||||
);
|
|
||||||
|
|
||||||
useTypedEventEmitter(
|
|
||||||
voiceBroadcastRecordingsStore,
|
voiceBroadcastRecordingsStore,
|
||||||
VoiceBroadcastRecordingsStoreEvent.CurrentChanged,
|
VoiceBroadcastRecordingsStoreEvent.CurrentChanged,
|
||||||
setCurrentVoiceBroadcastRecording,
|
(recording?: VoiceBroadcastRecording) => {
|
||||||
|
return recording ?? voiceBroadcastRecordingsStore.getCurrent();
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -14,17 +14,17 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { useState } from "react";
|
|
||||||
import { Room } from "matrix-js-sdk/src/models/room";
|
import { Room } from "matrix-js-sdk/src/models/room";
|
||||||
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
|
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
|
||||||
|
|
||||||
import { useTypedEventEmitter } from "../../hooks/useEventEmitter";
|
import { useTypedEventEmitterState } from "../../hooks/useEventEmitter";
|
||||||
import { MatrixClientPeg } from "../../MatrixClientPeg";
|
import { MatrixClientPeg } from "../../MatrixClientPeg";
|
||||||
import {
|
import {
|
||||||
VoiceBroadcastLiveness,
|
VoiceBroadcastLiveness,
|
||||||
VoiceBroadcastPlayback,
|
VoiceBroadcastPlayback,
|
||||||
VoiceBroadcastPlaybackEvent,
|
VoiceBroadcastPlaybackEvent,
|
||||||
VoiceBroadcastPlaybackState,
|
VoiceBroadcastPlaybackState,
|
||||||
|
VoiceBroadcastPlaybackTimes,
|
||||||
} from "..";
|
} from "..";
|
||||||
|
|
||||||
export const useVoiceBroadcastPlayback = (
|
export const useVoiceBroadcastPlayback = (
|
||||||
|
@ -52,24 +52,35 @@ export const useVoiceBroadcastPlayback = (
|
||||||
playback.toggle();
|
playback.toggle();
|
||||||
};
|
};
|
||||||
|
|
||||||
const [playbackState, setPlaybackState] = useState(playback.getState());
|
const playbackState = useTypedEventEmitterState(
|
||||||
useTypedEventEmitter(
|
|
||||||
playback,
|
playback,
|
||||||
VoiceBroadcastPlaybackEvent.StateChanged,
|
VoiceBroadcastPlaybackEvent.StateChanged,
|
||||||
(state: VoiceBroadcastPlaybackState, _playback: VoiceBroadcastPlayback) => {
|
(state?: VoiceBroadcastPlaybackState) => {
|
||||||
setPlaybackState(state);
|
return state ?? playback.getState();
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
const [times, setTimes] = useState({
|
const times = useTypedEventEmitterState(
|
||||||
duration: playback.durationSeconds,
|
playback,
|
||||||
position: playback.timeSeconds,
|
VoiceBroadcastPlaybackEvent.TimesChanged,
|
||||||
timeLeft: playback.timeLeftSeconds,
|
(t?: VoiceBroadcastPlaybackTimes) => {
|
||||||
});
|
return (
|
||||||
useTypedEventEmitter(playback, VoiceBroadcastPlaybackEvent.TimesChanged, (t) => setTimes(t));
|
t ?? {
|
||||||
|
duration: playback.durationSeconds,
|
||||||
|
position: playback.timeSeconds,
|
||||||
|
timeLeft: playback.timeLeftSeconds,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
const [liveness, setLiveness] = useState(playback.getLiveness());
|
const liveness = useTypedEventEmitterState(
|
||||||
useTypedEventEmitter(playback, VoiceBroadcastPlaybackEvent.LivenessChanged, (l) => setLiveness(l));
|
playback,
|
||||||
|
VoiceBroadcastPlaybackEvent.LivenessChanged,
|
||||||
|
(l?: VoiceBroadcastLiveness) => {
|
||||||
|
return l ?? playback.getLiveness();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
times,
|
times,
|
||||||
|
|
|
@ -16,7 +16,7 @@ limitations under the License.
|
||||||
|
|
||||||
import { Room } from "matrix-js-sdk/src/models/room";
|
import { Room } from "matrix-js-sdk/src/models/room";
|
||||||
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
|
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
|
||||||
import React, { useState } from "react";
|
import React from "react";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
VoiceBroadcastInfoState,
|
VoiceBroadcastInfoState,
|
||||||
|
@ -25,7 +25,7 @@ import {
|
||||||
VoiceBroadcastRecordingState,
|
VoiceBroadcastRecordingState,
|
||||||
} from "..";
|
} from "..";
|
||||||
import QuestionDialog from "../../components/views/dialogs/QuestionDialog";
|
import QuestionDialog from "../../components/views/dialogs/QuestionDialog";
|
||||||
import { useTypedEventEmitter } from "../../hooks/useEventEmitter";
|
import { useTypedEventEmitterState } from "../../hooks/useEventEmitter";
|
||||||
import { _t } from "../../languageHandler";
|
import { _t } from "../../languageHandler";
|
||||||
import { MatrixClientPeg } from "../../MatrixClientPeg";
|
import { MatrixClientPeg } from "../../MatrixClientPeg";
|
||||||
import Modal from "../../Modal";
|
import Modal from "../../Modal";
|
||||||
|
@ -74,17 +74,21 @@ export const useVoiceBroadcastRecording = (
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const [recordingState, setRecordingState] = useState(recording.getState());
|
const recordingState = useTypedEventEmitterState(
|
||||||
useTypedEventEmitter(
|
|
||||||
recording,
|
recording,
|
||||||
VoiceBroadcastRecordingEvent.StateChanged,
|
VoiceBroadcastRecordingEvent.StateChanged,
|
||||||
(state: VoiceBroadcastInfoState, _recording: VoiceBroadcastRecording) => {
|
(state?: VoiceBroadcastRecordingState) => {
|
||||||
setRecordingState(state);
|
return state ?? recording.getState();
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
const [timeLeft, setTimeLeft] = useState(recording.getTimeLeft());
|
const timeLeft = useTypedEventEmitterState(
|
||||||
useTypedEventEmitter(recording, VoiceBroadcastRecordingEvent.TimeLeftChanged, setTimeLeft);
|
recording,
|
||||||
|
VoiceBroadcastRecordingEvent.TimeLeftChanged,
|
||||||
|
(t?: number) => {
|
||||||
|
return t ?? recording.getTimeLeft();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
const live = (
|
const live = (
|
||||||
[VoiceBroadcastInfoState.Started, VoiceBroadcastInfoState.Resumed] as VoiceBroadcastRecordingState[]
|
[VoiceBroadcastInfoState.Started, VoiceBroadcastInfoState.Resumed] as VoiceBroadcastRecordingState[]
|
||||||
|
|
|
@ -57,7 +57,7 @@ export enum VoiceBroadcastPlaybackEvent {
|
||||||
InfoStateChanged = "info_state_changed",
|
InfoStateChanged = "info_state_changed",
|
||||||
}
|
}
|
||||||
|
|
||||||
type VoiceBroadcastPlaybackTimes = {
|
export type VoiceBroadcastPlaybackTimes = {
|
||||||
duration: number;
|
duration: number;
|
||||||
position: number;
|
position: number;
|
||||||
timeLeft: number;
|
timeLeft: number;
|
||||||
|
|
|
@ -32,6 +32,7 @@ const mockWysiwyg = {
|
||||||
link: jest.fn(),
|
link: jest.fn(),
|
||||||
orderedList: jest.fn(),
|
orderedList: jest.fn(),
|
||||||
unorderedList: jest.fn(),
|
unorderedList: jest.fn(),
|
||||||
|
quote: jest.fn(),
|
||||||
} as unknown as FormattingFunctions;
|
} as unknown as FormattingFunctions;
|
||||||
|
|
||||||
const openLinkModalSpy = jest.spyOn(LinkModal, "openLinkModal");
|
const openLinkModalSpy = jest.spyOn(LinkModal, "openLinkModal");
|
||||||
|
@ -49,6 +50,7 @@ const testCases: Record<
|
||||||
link: { label: "Link", mockFormatFn: openLinkModalSpy },
|
link: { label: "Link", mockFormatFn: openLinkModalSpy },
|
||||||
orderedList: { label: "Numbered list", mockFormatFn: mockWysiwyg.orderedList },
|
orderedList: { label: "Numbered list", mockFormatFn: mockWysiwyg.orderedList },
|
||||||
unorderedList: { label: "Bulleted list", mockFormatFn: mockWysiwyg.unorderedList },
|
unorderedList: { label: "Bulleted list", mockFormatFn: mockWysiwyg.unorderedList },
|
||||||
|
quote: { label: "Quote", mockFormatFn: mockWysiwyg.quote },
|
||||||
};
|
};
|
||||||
|
|
||||||
const createActionStates = (state: ActionState): AllActionStates => {
|
const createActionStates = (state: ActionState): AllActionStates => {
|
||||||
|
|
12
yarn.lock
12
yarn.lock
|
@ -1589,10 +1589,10 @@
|
||||||
resolved "https://registry.yarnpkg.com/@matrix-org/matrix-sdk-crypto-js/-/matrix-sdk-crypto-js-0.1.0-alpha.2.tgz#a09d0fea858e817da971a3c9f904632ef7b49eb6"
|
resolved "https://registry.yarnpkg.com/@matrix-org/matrix-sdk-crypto-js/-/matrix-sdk-crypto-js-0.1.0-alpha.2.tgz#a09d0fea858e817da971a3c9f904632ef7b49eb6"
|
||||||
integrity sha512-oVkBCh9YP7H9i4gAoQbZzswniczfo/aIptNa4dxRi4Ff9lSvUCFv6Hvzi7C+90c0/PWZLXjIDTIAWZYmwyd2fA==
|
integrity sha512-oVkBCh9YP7H9i4gAoQbZzswniczfo/aIptNa4dxRi4Ff9lSvUCFv6Hvzi7C+90c0/PWZLXjIDTIAWZYmwyd2fA==
|
||||||
|
|
||||||
"@matrix-org/matrix-wysiwyg@^0.19.0":
|
"@matrix-org/matrix-wysiwyg@^0.20.0":
|
||||||
version "0.19.0"
|
version "0.20.0"
|
||||||
resolved "https://registry.yarnpkg.com/@matrix-org/matrix-wysiwyg/-/matrix-wysiwyg-0.19.0.tgz#5ffbabf8a59317ecdb45ba5fa1d06fff150ede40"
|
resolved "https://registry.yarnpkg.com/@matrix-org/matrix-wysiwyg/-/matrix-wysiwyg-0.20.0.tgz#6193f790b031eaa96e944b647fe2b27018639d57"
|
||||||
integrity sha512-1iL/+kjwWAlpWAq64DbkDkE7KGxvR5lNojZgCKMIyuvuKWv8Ikqxa9VOOYFtovKvSqgGRJaYN7/OkKWxZjiDcw==
|
integrity sha512-9VqzyccwizglssShi/M+tCxdZDgzsecH4WjlS0HC5KkLmljIxxlHFstf/D3C/G4ZfRodFUh6wUvd+oQI/ScPpw==
|
||||||
|
|
||||||
"@matrix-org/olm@https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.14.tgz":
|
"@matrix-org/olm@https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.14.tgz":
|
||||||
version "3.2.14"
|
version "3.2.14"
|
||||||
|
@ -6492,8 +6492,8 @@ matrix-events-sdk@0.0.1:
|
||||||
integrity sha512-1QEOsXO+bhyCroIe2/A5OwaxHvBm7EsSQ46DEDn8RBIfQwN5HWBpFvyWWR4QY0KHPPnnJdI99wgRiAl7Ad5qaA==
|
integrity sha512-1QEOsXO+bhyCroIe2/A5OwaxHvBm7EsSQ46DEDn8RBIfQwN5HWBpFvyWWR4QY0KHPPnnJdI99wgRiAl7Ad5qaA==
|
||||||
|
|
||||||
"matrix-js-sdk@github:matrix-org/matrix-js-sdk#develop":
|
"matrix-js-sdk@github:matrix-org/matrix-js-sdk#develop":
|
||||||
version "23.1.0"
|
version "23.1.1"
|
||||||
resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/83563c7a01bbeaf7f83f4b7feccc03647b536e7c"
|
resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/c309fe69426d701893ebee315105f8fa8fef03f8"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/runtime" "^7.12.5"
|
"@babel/runtime" "^7.12.5"
|
||||||
"@matrix-org/matrix-sdk-crypto-js" "^0.1.0-alpha.2"
|
"@matrix-org/matrix-sdk-crypto-js" "^0.1.0-alpha.2"
|
||||||
|
|
Loading…
Reference in New Issue