Skip to content

Commit

Permalink
feat(always-on-top): Updates buttons for visitors. (jitsi#15369)
Browse files Browse the repository at this point in the history
* feat(always-on-top): Updates buttons for visitors.

* squash: rename listener.

* squash: Adds visitor to the conference joined event.

* squash: fix comments and lint.

* squash: fix comments.
  • Loading branch information
damencho authored Dec 6, 2024
1 parent 3834f1e commit f85d0e6
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 5 deletions.
11 changes: 11 additions & 0 deletions modules/API/external/external_api.js
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,7 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
this._participants = {};
this._myUserID = undefined;
this._onStageParticipant = undefined;
this._iAmvisitor = undefined;
this._setupListeners();
id++;
}
Expand Down Expand Up @@ -619,6 +620,7 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
email: data.email,
avatarURL: data.avatarURL
};
this._iAmvisitor = data.visitor;
}

// eslint-disable-next-line no-fallthrough
Expand Down Expand Up @@ -1168,6 +1170,15 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
});
}

/**
* Returns whether we have joined as visitor in a meeting.
*
* @returns {boolean} - Returns true if we have joined as visitor.
*/
isVisitor() {
return this._iAmvisitor;
}

/**
* Returns the avatar URL of a participant.
*
Expand Down
85 changes: 82 additions & 3 deletions react/features/always-on-top/Toolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import AudioMuteButton from './AudioMuteButton';
import HangupButton from './HangupButton';
import VideoMuteButton from './VideoMuteButton';

const { api } = window.alwaysOnTop;

/**
* The type of the React {@code Component} props of {@link Toolbar}.
*/
Expand All @@ -25,12 +27,89 @@ interface IProps {
onMouseOver: (e?: React.MouseEvent) => void;
}

/**
* The type of the React {@code Component} state of {@link Toolbar}.
*/
interface IState {

/**
* Whether audio button to be shown or not.
*/
showAudioButton: boolean;

/**
* Whether video button to be shown or not.
*/
showVideoButton: boolean;
}

type Props = Partial<IProps>;

/**
* Represents the toolbar in the Always On Top window.
*
* @augments Component
*/
export default class Toolbar extends Component<IProps> {
export default class Toolbar extends Component<Props, IState> {
/**
* Initializes a new {@code Toolbar} instance.
*
* @param {IProps} props - The React {@code Component} props to initialize the new {@code Toolbar} instance with.
*/
constructor(props: Props) {
super(props);

this.state = {
showAudioButton: true,
showVideoButton: true
};

this._videoConferenceJoinedListener = this._videoConferenceJoinedListener.bind(this);
}

/**
* Sets listens for changing meetings while showing the toolbar.
*
* @inheritdoc
* @returns {void}
*/
componentDidMount() {
api.on('videoConferenceJoined', this._videoConferenceJoinedListener);

this._videoConferenceJoinedListener();
}

/**
* Handles is visitor changes.
*
* @returns {void}
*/
_videoConferenceJoinedListener() {
// for electron clients that embed the api and are not updated
if (!api.isVisitor) {
console.warn('external API not updated');

return;
}

const isNotVisitor = !api.isVisitor();

this.setState({
showAudioButton: isNotVisitor,
showVideoButton: isNotVisitor
});
}

/**
* Removes all listeners.
*
* @inheritdoc
* @returns {void}
*/
componentWillUnmount() {
api.removeListener('videoConferenceJoined', this._videoConferenceJoinedListener);
}

/**
* Implements React's {@link Component#render()}.
*
Expand All @@ -49,8 +128,8 @@ export default class Toolbar extends Component<IProps> {
className = { `toolbox-content-items always-on-top-toolbox ${className}` }
onMouseOut = { onMouseOut }
onMouseOver = { onMouseOver }>
<AudioMuteButton />
<VideoMuteButton />
{ this.state.showAudioButton && <AudioMuteButton /> }
{ this.state.showVideoButton && <VideoMuteButton /> }
<HangupButton customClass = 'hangup-button' />
</div>
);
Expand Down
4 changes: 3 additions & 1 deletion react/features/external-api/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { getBaseUrl } from '../base/util/helpers';
import { appendSuffix } from '../display-name/functions';
import { SUBMIT_FEEDBACK_ERROR, SUBMIT_FEEDBACK_SUCCESS } from '../feedback/actionTypes';
import { SET_FILMSTRIP_VISIBLE } from '../filmstrip/actionTypes';
import { iAmVisitor } from '../visitors/functions';

import './subscriber';

Expand Down Expand Up @@ -120,7 +121,8 @@ MiddlewareRegistry.register(store => next => action => {
),
avatarURL: loadableAvatarUrl,
breakoutRoom,
email
email,
visitor: iAmVisitor(state)
}
);
break;
Expand Down
4 changes: 3 additions & 1 deletion react/features/toolbox/functions.any.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { IReduxState } from '../app/types';
import { isJwtFeatureEnabledStateless } from '../base/jwt/functions';
import { IGUMPendingState } from '../base/media/types';
import { IParticipantFeatures } from '../base/participants/types';
import { iAmVisitor } from '../visitors/functions';

/**
* Indicates if the audio mute button is disabled or not.
Expand All @@ -13,7 +14,8 @@ export function isAudioMuteButtonDisabled(state: IReduxState) {
const { available, muted, unmuteBlocked, gumPending } = state['features/base/media'].audio;
const { startSilent } = state['features/base/config'];

return Boolean(!available || startSilent || (muted && unmuteBlocked) || gumPending !== IGUMPendingState.NONE);
return Boolean(!available || startSilent || (muted && unmuteBlocked) || gumPending !== IGUMPendingState.NONE
|| iAmVisitor(state));
}

/**
Expand Down

0 comments on commit f85d0e6

Please sign in to comment.