Display info dialogs if unable to start voice broadcasts (#9453)
This commit is contained in:
parent
3c3df11d32
commit
bb0c175b7e
17 changed files with 546 additions and 160 deletions
|
@ -113,7 +113,6 @@ import { isLocalRoom } from '../../utils/localRoom/isLocalRoom';
|
|||
import { ShowThreadPayload } from "../../dispatcher/payloads/ShowThreadPayload";
|
||||
import { RoomStatusBarUnsentMessages } from './RoomStatusBarUnsentMessages';
|
||||
import { LargeLoader } from './LargeLoader';
|
||||
import { VoiceBroadcastInfoEventType } from '../../voice-broadcast';
|
||||
import { isVideoRoom } from '../../utils/video-rooms';
|
||||
import { SDKContext } from '../../contexts/SDKContext';
|
||||
import { CallStore, CallStoreEvent } from "../../stores/CallStore";
|
||||
|
@ -199,7 +198,6 @@ export interface IRoomState {
|
|||
upgradeRecommendation?: IRecommendedVersion;
|
||||
canReact: boolean;
|
||||
canSendMessages: boolean;
|
||||
canSendVoiceBroadcasts: boolean;
|
||||
tombstone?: MatrixEvent;
|
||||
resizing: boolean;
|
||||
layout: Layout;
|
||||
|
@ -404,7 +402,6 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
statusBarVisible: false,
|
||||
canReact: false,
|
||||
canSendMessages: false,
|
||||
canSendVoiceBroadcasts: false,
|
||||
resizing: false,
|
||||
layout: SettingsStore.getValue("layout"),
|
||||
lowBandwidth: SettingsStore.getValue("lowBandwidth"),
|
||||
|
@ -1377,12 +1374,10 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
);
|
||||
const canSendMessages = room.maySendMessage();
|
||||
const canSelfRedact = room.currentState.maySendEvent(EventType.RoomRedaction, me);
|
||||
const canSendVoiceBroadcasts = room.currentState.maySendEvent(VoiceBroadcastInfoEventType, me);
|
||||
|
||||
this.setState({
|
||||
canReact,
|
||||
canSendMessages,
|
||||
canSendVoiceBroadcasts,
|
||||
canSelfRedact,
|
||||
});
|
||||
}
|
||||
|
@ -2253,7 +2248,6 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
resizeNotifier={this.props.resizeNotifier}
|
||||
replyToEvent={this.state.replyToEvent}
|
||||
permalinkCreator={this.permalinkCreator}
|
||||
showVoiceBroadcastButton={this.state.canSendVoiceBroadcasts}
|
||||
/>;
|
||||
}
|
||||
|
||||
|
|
|
@ -85,7 +85,6 @@ interface IProps {
|
|||
relation?: IEventRelation;
|
||||
e2eStatus?: E2EStatus;
|
||||
compact?: boolean;
|
||||
showVoiceBroadcastButton?: boolean;
|
||||
}
|
||||
|
||||
interface IState {
|
||||
|
@ -384,10 +383,6 @@ export default class MessageComposer extends React.Component<IProps, IState> {
|
|||
return this.state.showStickersButton && !isLocalRoom(this.props.room);
|
||||
}
|
||||
|
||||
private get showVoiceBroadcastButton(): boolean {
|
||||
return this.props.showVoiceBroadcastButton && this.state.showVoiceBroadcastButton;
|
||||
}
|
||||
|
||||
public render() {
|
||||
const isWysiwygComposerEnabled = SettingsStore.getValue("feature_wysiwyg_composer");
|
||||
const controls = [
|
||||
|
@ -532,10 +527,10 @@ export default class MessageComposer extends React.Component<IProps, IState> {
|
|||
showPollsButton={this.state.showPollsButton}
|
||||
showStickersButton={this.showStickersButton}
|
||||
toggleButtonMenu={this.toggleButtonMenu}
|
||||
showVoiceBroadcastButton={this.showVoiceBroadcastButton}
|
||||
showVoiceBroadcastButton={this.state.showVoiceBroadcastButton}
|
||||
onStartVoiceBroadcastClick={() => {
|
||||
startNewVoiceBroadcastRecording(
|
||||
this.props.room.roomId,
|
||||
this.props.room,
|
||||
MatrixClientPeg.get(),
|
||||
VoiceBroadcastRecordingsStore.instance(),
|
||||
);
|
||||
|
|
|
@ -45,7 +45,6 @@ const RoomContext = createContext<IRoomState>({
|
|||
canReact: false,
|
||||
canSelfRedact: false,
|
||||
canSendMessages: false,
|
||||
canSendVoiceBroadcasts: false,
|
||||
resizing: false,
|
||||
layout: Layout.Group,
|
||||
lowBandwidth: false,
|
||||
|
|
|
@ -637,6 +637,10 @@
|
|||
"Send <b>%(msgtype)s</b> messages as you in your active room": "Send <b>%(msgtype)s</b> messages as you in your active room",
|
||||
"See <b>%(msgtype)s</b> messages posted to this room": "See <b>%(msgtype)s</b> messages posted to this room",
|
||||
"See <b>%(msgtype)s</b> messages posted to your active room": "See <b>%(msgtype)s</b> messages posted to your active room",
|
||||
"Can't start a new voice broadcast": "Can't start a new voice broadcast",
|
||||
"You are already recording a voice broadcast. Please end your current voice broadcast to start a new one.": "You are already recording a voice broadcast. Please end your current voice broadcast to start a new one.",
|
||||
"You don't have the required permissions to start a voice broadcast in this room. Contact a room administrator to upgrade your permissions.": "You don't have the required permissions to start a voice broadcast in this room. Contact a room administrator to upgrade your permissions.",
|
||||
"Someone else is already recording a voice broadcast. Wait for their voice broadcast to end to start a new one.": "Someone else is already recording a voice broadcast. Wait for their voice broadcast to end to start a new one.",
|
||||
"Stop live broadcasting?": "Stop live broadcasting?",
|
||||
"Are you sure you want to stop your live broadcast?This will end the broadcast and the full recording will be available in the room.": "Are you sure you want to stop your live broadcast?This will end the broadcast and the full recording will be available in the room.",
|
||||
"Yes, stop broadcast": "Yes, stop broadcast",
|
||||
|
|
|
@ -35,6 +35,7 @@ export * from "./components/molecules/VoiceBroadcastRecordingPip";
|
|||
export * from "./hooks/useVoiceBroadcastRecording";
|
||||
export * from "./stores/VoiceBroadcastPlaybacksStore";
|
||||
export * from "./stores/VoiceBroadcastRecordingsStore";
|
||||
export * from "./utils/hasRoomLiveVoiceBroadcast";
|
||||
export * from "./utils/shouldDisplayAsVoiceBroadcastRecordingTile";
|
||||
export * from "./utils/shouldDisplayAsVoiceBroadcastTile";
|
||||
export * from "./utils/startNewVoiceBroadcastRecording";
|
||||
|
|
54
src/voice-broadcast/utils/hasRoomLiveVoiceBroadcast.ts
Normal file
54
src/voice-broadcast/utils/hasRoomLiveVoiceBroadcast.ts
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { MatrixEvent, Room } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import { VoiceBroadcastInfoEventType, VoiceBroadcastInfoState } from "..";
|
||||
|
||||
interface Result {
|
||||
hasBroadcast: boolean;
|
||||
startedByUser: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds out whether there is a live broadcast in a room.
|
||||
* Also returns if the user started the broadcast (if any).
|
||||
*/
|
||||
export const hasRoomLiveVoiceBroadcast = (room: Room, userId: string): Result => {
|
||||
let hasBroadcast = false;
|
||||
let startedByUser = false;
|
||||
|
||||
const stateEvents = room.currentState.getStateEvents(VoiceBroadcastInfoEventType);
|
||||
stateEvents.forEach((event: MatrixEvent) => {
|
||||
const state = event.getContent()?.state;
|
||||
|
||||
if (state && state !== VoiceBroadcastInfoState.Stopped) {
|
||||
hasBroadcast = true;
|
||||
|
||||
// state key = sender's MXID
|
||||
if (event.getStateKey() === userId) {
|
||||
startedByUser = true;
|
||||
// break here, because more than true / true is not possible
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
hasBroadcast,
|
||||
startedByUser,
|
||||
};
|
||||
};
|
|
@ -1,76 +0,0 @@
|
|||
/*
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { ISendEventResponse, MatrixClient, RoomStateEvent } from "matrix-js-sdk/src/matrix";
|
||||
import { defer } from "matrix-js-sdk/src/utils";
|
||||
|
||||
import {
|
||||
VoiceBroadcastInfoEventContent,
|
||||
VoiceBroadcastInfoEventType,
|
||||
VoiceBroadcastInfoState,
|
||||
VoiceBroadcastRecordingsStore,
|
||||
VoiceBroadcastRecording,
|
||||
} from "..";
|
||||
|
||||
/**
|
||||
* Starts a new Voice Broadcast Recording.
|
||||
* Sends a voice_broadcast_info state event and waits for the event to actually appear in the room state.
|
||||
*/
|
||||
export const startNewVoiceBroadcastRecording = async (
|
||||
roomId: string,
|
||||
client: MatrixClient,
|
||||
recordingsStore: VoiceBroadcastRecordingsStore,
|
||||
): Promise<VoiceBroadcastRecording> => {
|
||||
const room = client.getRoom(roomId);
|
||||
const { promise, resolve } = defer<VoiceBroadcastRecording>();
|
||||
let result: ISendEventResponse = null;
|
||||
|
||||
const onRoomStateEvents = () => {
|
||||
if (!result) return;
|
||||
|
||||
const voiceBroadcastEvent = room.currentState.getStateEvents(
|
||||
VoiceBroadcastInfoEventType,
|
||||
client.getUserId(),
|
||||
);
|
||||
|
||||
if (voiceBroadcastEvent?.getId() === result.event_id) {
|
||||
room.off(RoomStateEvent.Events, onRoomStateEvents);
|
||||
const recording = new VoiceBroadcastRecording(
|
||||
voiceBroadcastEvent,
|
||||
client,
|
||||
);
|
||||
recordingsStore.setCurrent(recording);
|
||||
recording.start();
|
||||
resolve(recording);
|
||||
}
|
||||
};
|
||||
|
||||
room.on(RoomStateEvent.Events, onRoomStateEvents);
|
||||
|
||||
// XXX Michael W: refactor to live event
|
||||
result = await client.sendStateEvent(
|
||||
roomId,
|
||||
VoiceBroadcastInfoEventType,
|
||||
{
|
||||
device_id: client.getDeviceId(),
|
||||
state: VoiceBroadcastInfoState.Started,
|
||||
chunk_length: 300,
|
||||
} as VoiceBroadcastInfoEventContent,
|
||||
client.getUserId(),
|
||||
);
|
||||
|
||||
return promise;
|
||||
};
|
136
src/voice-broadcast/utils/startNewVoiceBroadcastRecording.tsx
Normal file
136
src/voice-broadcast/utils/startNewVoiceBroadcastRecording.tsx
Normal file
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import { ISendEventResponse, MatrixClient, Room, RoomStateEvent } from "matrix-js-sdk/src/matrix";
|
||||
import { defer } from "matrix-js-sdk/src/utils";
|
||||
|
||||
import { _t } from "../../languageHandler";
|
||||
import InfoDialog from "../../components/views/dialogs/InfoDialog";
|
||||
import Modal from "../../Modal";
|
||||
import {
|
||||
VoiceBroadcastInfoEventContent,
|
||||
VoiceBroadcastInfoEventType,
|
||||
VoiceBroadcastInfoState,
|
||||
VoiceBroadcastRecordingsStore,
|
||||
VoiceBroadcastRecording,
|
||||
hasRoomLiveVoiceBroadcast,
|
||||
} from "..";
|
||||
|
||||
const startBroadcast = async (
|
||||
room: Room,
|
||||
client: MatrixClient,
|
||||
recordingsStore: VoiceBroadcastRecordingsStore,
|
||||
): Promise<VoiceBroadcastRecording> => {
|
||||
const { promise, resolve } = defer<VoiceBroadcastRecording>();
|
||||
let result: ISendEventResponse = null;
|
||||
|
||||
const onRoomStateEvents = () => {
|
||||
if (!result) return;
|
||||
|
||||
const voiceBroadcastEvent = room.currentState.getStateEvents(
|
||||
VoiceBroadcastInfoEventType,
|
||||
client.getUserId(),
|
||||
);
|
||||
|
||||
if (voiceBroadcastEvent?.getId() === result.event_id) {
|
||||
room.off(RoomStateEvent.Events, onRoomStateEvents);
|
||||
const recording = new VoiceBroadcastRecording(
|
||||
voiceBroadcastEvent,
|
||||
client,
|
||||
);
|
||||
recordingsStore.setCurrent(recording);
|
||||
recording.start();
|
||||
resolve(recording);
|
||||
}
|
||||
};
|
||||
|
||||
room.on(RoomStateEvent.Events, onRoomStateEvents);
|
||||
|
||||
// XXX Michael W: refactor to live event
|
||||
result = await client.sendStateEvent(
|
||||
room.roomId,
|
||||
VoiceBroadcastInfoEventType,
|
||||
{
|
||||
device_id: client.getDeviceId(),
|
||||
state: VoiceBroadcastInfoState.Started,
|
||||
chunk_length: 300,
|
||||
} as VoiceBroadcastInfoEventContent,
|
||||
client.getUserId(),
|
||||
);
|
||||
|
||||
return promise;
|
||||
};
|
||||
|
||||
const showAlreadyRecordingDialog = () => {
|
||||
Modal.createDialog(InfoDialog, {
|
||||
title: _t("Can't start a new voice broadcast"),
|
||||
description: <p>{ _t("You are already recording a voice broadcast. "
|
||||
+ "Please end your current voice broadcast to start a new one.") }</p>,
|
||||
hasCloseButton: true,
|
||||
});
|
||||
};
|
||||
|
||||
const showInsufficientPermissionsDialog = () => {
|
||||
Modal.createDialog(InfoDialog, {
|
||||
title: _t("Can't start a new voice broadcast"),
|
||||
description: <p>{ _t("You don't have the required permissions to start a voice broadcast in this room. "
|
||||
+ "Contact a room administrator to upgrade your permissions.") }</p>,
|
||||
hasCloseButton: true,
|
||||
});
|
||||
};
|
||||
|
||||
const showOthersAlreadyRecordingDialog = () => {
|
||||
Modal.createDialog(InfoDialog, {
|
||||
title: _t("Can't start a new voice broadcast"),
|
||||
description: <p>{ _t("Someone else is already recording a voice broadcast. "
|
||||
+ "Wait for their voice broadcast to end to start a new one.") }</p>,
|
||||
hasCloseButton: true,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Starts a new Voice Broadcast Recording, if
|
||||
* - the user has the permissions to do so in the room
|
||||
* - there is no other broadcast being recorded in the room, yet
|
||||
* Sends a voice_broadcast_info state event and waits for the event to actually appear in the room state.
|
||||
*/
|
||||
export const startNewVoiceBroadcastRecording = async (
|
||||
room: Room,
|
||||
client: MatrixClient,
|
||||
recordingsStore: VoiceBroadcastRecordingsStore,
|
||||
): Promise<VoiceBroadcastRecording | null> => {
|
||||
const currentUserId = client.getUserId();
|
||||
|
||||
if (!room.currentState.maySendStateEvent(VoiceBroadcastInfoEventType, currentUserId)) {
|
||||
showInsufficientPermissionsDialog();
|
||||
return null;
|
||||
}
|
||||
|
||||
const { hasBroadcast, startedByUser } = hasRoomLiveVoiceBroadcast(room, currentUserId);
|
||||
|
||||
if (hasBroadcast && startedByUser) {
|
||||
showAlreadyRecordingDialog();
|
||||
return null;
|
||||
}
|
||||
|
||||
if (hasBroadcast) {
|
||||
showOthersAlreadyRecordingDialog();
|
||||
return null;
|
||||
}
|
||||
|
||||
return startBroadcast(room, client, recordingsStore);
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue