Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add muted indicator to people list #6152

Merged
merged 11 commits into from
Jul 12, 2023
14 changes: 11 additions & 3 deletions src/components/avatar-volume-controls.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ AFRAME.registerComponent("avatar-volume-controls", {
this.onRemoteMuteUpdated = this.onRemoteMuteUpdated.bind(this);
this.playerInfo.el.addEventListener("remote_mute_updated", this.onRemoteMuteUpdated);
this.muteButton.object3D.visible = this.playerInfo.data.muted;
const volumePref = getAvatarVolumePref(this.playerInfo.displayName);
const volumePref = getAvatarVolumePref(this.playerInfo.playerSessionId);
this.updateGainMultiplier(volumePref === undefined ? DEFAULT_VOLUME_BAR_MULTIPLIER : volumePref.gainMultiplier);
this.updateLocalMuted(volumePref === undefined ? false : volumePref.muted);
},
Expand All @@ -48,7 +48,11 @@ AFRAME.registerComponent("avatar-volume-controls", {
this.updateVolumeLabel();
this.el.emit("gain_multiplier_updated", { gainMultiplier });
const isLocalMuted = APP.mutedState.has(this.audioEl);
updatePref && updateAvatarVolumesPref(this.playerInfo.displayName, gainMultiplier, isLocalMuted);
updatePref && updateAvatarVolumesPref(this.playerInfo.playerSessionId, gainMultiplier, isLocalMuted);
// If the gainMultiplier is lowered to 0, updated muted status in local storage
if (!gainMultiplier) {
this.updateLocalMuted(true, true);
}
},

updateLocalMuted(muted, updatePref = false) {
Expand All @@ -65,7 +69,7 @@ AFRAME.registerComponent("avatar-volume-controls", {
this.el.emit("local_muted_updated", { muted });
const gainMultiplier = APP.gainMultipliers.get(this.audioEl);
const isLocalMuted = APP.mutedState.has(this.audioEl);
updatePref && updateAvatarVolumesPref(this.playerInfo.displayName, gainMultiplier, isLocalMuted);
updatePref && updateAvatarVolumesPref(this.playerInfo.playerSessionId, gainMultiplier, isLocalMuted);
},

volumeUp() {
Expand All @@ -80,6 +84,10 @@ AFRAME.registerComponent("avatar-volume-controls", {
const step = -calcGainStepDown(gainMultiplier);
gainMultiplier = THREE.MathUtils.clamp(gainMultiplier + step, 0, MAX_GAIN_MULTIPLIER);
this.updateGainMultiplier(gainMultiplier, true);
// If the gainMultiplier is lowered to 0, updated muted status in local storage
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is already calling updateGainMultiplier which already calls updateLocalMuted so I believe we can remove the updateLocalMuted call from here.

if (!gainMultiplier) {
this.updateLocalMuted(true, true);
}
},

updateVolumeLabel() {
Expand Down
6 changes: 6 additions & 0 deletions src/react-components/room/PeopleSidebar.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ export function PeopleSidebar({
return a.hand_raised ? -1 : 1;
});
me && filteredPeople.unshift(me);
const store = window.APP.store;

return (
<Sidebar
Expand Down Expand Up @@ -156,6 +157,11 @@ export function PeopleSidebar({
height={12}
/>
)}
{store._preferences?.avatarVoiceLevels?.[person.id]?.muted && (
<span className={styles.isMuted}>
{intl.formatMessage({ id: "people-sidebar.muted-label", defaultMessage: "muted" })}
</span>
)}
<p className={styles.presence}>{getPresenceMessage(person.presence, intl)}</p>
</ButtonListItem>
);
Expand Down
5 changes: 5 additions & 0 deletions src/react-components/room/PeopleSidebar.scss
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,8 @@
flex: 1;
justify-content: flex-end;
}

:local(.isMuted) {
font-style: italic;
color: theme.$color-semantic-warning;
}
1 change: 1 addition & 0 deletions src/react-components/room/UserProfileSidebar.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export function UserProfileSidebar({
[updateMultiplier]
);
const newLevel = calcLevel(multiplier);

return (
<Sidebar
beforeTitle={showBackButton ? <BackButton onClick={onBack} /> : <CloseButton onClick={onClose} />}
Expand Down
168 changes: 135 additions & 33 deletions src/react-components/styles/theme.scss
Original file line number Diff line number Diff line change
Expand Up @@ -10,60 +10,60 @@ $transparent: transparent;
$transparent-hover: rgba(0, 0, 0, 0.08);
$transparent-pressed: rgba(0, 0, 0, 0.12);

$white: #FFFFFF;
$white-hover: #E7E7E7;
$white-pressed: #DBDBDB;
$white: #ffffff;
$white-hover: #e7e7e7;
$white-pressed: #dbdbdb;

$lightgrey: #E7E7E7;
$lightgrey-hover: #F5F5F5;
$lightgrey-pressed: #DBDBDB;
$lightgrey: #e7e7e7;
$lightgrey-hover: #f5f5f5;
$lightgrey-pressed: #dbdbdb;

$grey: #BBBBBB;
$grey-hover: #C7C7C7;
$grey-pressed: #ADADAD;
$grey: #bbbbbb;
$grey-hover: #c7c7c7;
$grey-pressed: #adadad;

$darkgrey: #868686;
$darkgrey-hover: #949494;
$darkgrey-pressed: #7A7A7A;
$darkgrey-pressed: #7a7a7a;

$black: #000000;
$black-hover: #404040;
$black-pressed: #7A7A7A;
$black-pressed: #7a7a7a;

$red: #F5325C;
$red-hover: #F64B70;
$red-pressed: #F41A49;
$red: #f5325c;
$red-hover: #f64b70;
$red-pressed: #f41a49;

$orange: #FF8500;
$orange-hover: #FF911A;
$orange-pressed: #E67800;
$orange: #ff8500;
$orange-hover: #ff911a;
$orange-pressed: #e67800;

$green: #7ED320;
$green-hover: #8CDF2F;
$green-pressed: #72BE1D;
$green: #7ed320;
$green-hover: #8cdf2f;
$green-pressed: #72be1d;

$blue: #007AB8;
$blue-hover: #008BD1;
$blue-pressed: #00699E;
$blue: #007ab8;
$blue-hover: #008bd1;
$blue-pressed: #00699e;

$purple: #7854F6;
$purple-hover: #8C6EF7;
$purple-pressed: #663DF5;
$purple: #7854f6;
$purple-hover: #8c6ef7;
$purple-pressed: #663df5;

$recessed-bg: #f9f9f9;

$yellow: #FFC000;
$yellow: #ffc000;

// Brand Colors
$spoke-primary-color: #2F80ED;
$twitter-primary-color: #6FC0FD;
$slack-primary-color: #611F69;
$discord--primary-color: #7289DA;
$spoke-primary-color: #2f80ed;
$twitter-primary-color: #6fc0fd;
$slack-primary-color: #611f69;
$discord--primary-color: #7289da;

// Discord Bot Page Colors
$discord-bg-color: #2A2D32;
$discord-bg-color: #2a2d32;
$discord-text1-color: white;
$discord-text2-color: #A3A3A3;
$discord-text2-color: #a3a3a3;
$discord-text3-color: rgb(127, 127, 127);
$discord-text4-color: rgb(64, 64, 64);

Expand Down Expand Up @@ -272,3 +272,105 @@ $tile-button-bg-color-hover: var(--tile-button-bg-color-hover);
$tile-button-bg-color-pressed: var(--tile-button-bg-color-pressed);
$tile-button-border-color: var(--tile-button-border-color);

// Lilypad compatible variables (to eventually replace the above)

/**
PRIMARY INTERACTION
**/
$color-interaction-primary: var(--color-interaction-primary);
$color-interaction-primary-hover: var(--color-interaction-primary-hover);
$color-interaction-primary-active: var(--color-interaction-primary-active);
$color-interaction-primary-disabled: var(--color-interaction-primary-disabled);
$color-interaction-primary-alt: var(--color-interaction-primary-alt);
$color-interaction-primary-alt-hover: var(--color-interaction-primary-alt-hover);
$color-interaction-primary-alt-active: var(--color-interaction-primary-alt-active);
$color-interaction-primary-alt-disabled: var(--color-interaction-primary-alt-disabled);

/**
SECONDARY INTERACTION
**/
$color-interaction-secondary: var(--color-interaction-secondary);
$color-interaction-secondary-hover: var(--color-interaction-secondary-hover);
$color-interaction-secondary-active: var(--color-interaction-secondary-active);
$color-interaction-secondary-disabled: var(--color-interaction-secondary-disabled);
$color-interaction-secondary-alt: var(--color-interaction-secondary-alt);
$color-interaction-secondary-alt-hover: var(--color-interaction-secondary-alt-hover);
$color-interaction-secondary-alt-active: var(--color-interaction-secondary-alt-active);
$color-interaction-secondary-alt-disabled: var(--color-interaction-secondary-alt-disabled);

/**
SEMANTIC
**/
$color-semantic-info: var(--color-semantic-info);
$color-semantic-info-hover: var(--color-semantic-info-hover);
$color-semantic-info-active: var(--color-semantic-info-active);
$color-semantic-disabled: var(--color-semantic-disabled);
$color-semantic-success: var(--color-semantic-success);
$color-semantic-success-hover: var(--color-semantic-success-hover);
$color-semantic--success-active: var(--color-semantic-success-active);
$color-semantic-success-disabled: var(--color-semantic-success-disabled);
$color-semantic-warning: var(--color-semantic-warning);
$color-semantic-warning-hover: var(--color-semantic-warning-hover);
$color-semantic-warning-active: var(--color-semantic-warning-active);
$color-semantic-warning-disabled: var(--color-semantic-warning-disabled);
$color-semantic-critical: var(--color-semantic-critical);
$color-semantic-critical-hover: var(--color-semantic-critical-hover);
$color-semantic-critical-active: var(--color-semantic-critical-active);
$color-semantic-critical-disabled: var(--color-semantic-critical-disabled);
$color-semantic-critical-bg-alt: var(--color-semantic-critical-bg-alt);
$color-semantic-neutral: var(--color-semantic-neutral);
$color-semantic-neutral-hover: var(--color-semantic-neutral-hover);
$color-semantic-neutral-active: var(--color-semantic-neutral-active);
$color-semantic-neutral-inactive: var(--color-semantic-neutral-inactive);

/**
TEXT
**/
$color-text-main: var(--color-text-main);
$color-text-subtle: var(--color-text-subtle);
$color-text-reverse: var(--color-text-reverse);
$color-text-reverse-subtle: var(--color-text-reverse-subtle);
$color-text-disabled: var(--color-text-disabled);
$color-text-info: var(--color-text-info);
$color-text-success: var(--color-text-success);
$color-text-warning: var(--color-text-warning);
$color-text-critical: var(--color-text-critical);

/**
BORDER
**/
$color-border-1: var(--color-border-1);
$color-border-2: var(--color-border-2);
$color-border-3: var(--color-border-3);

/**
NEUTRALS
**/
$color-neutral-0: var(--color-neutral-0);
$color-neutral-0-reverse: var(--color-neutral-0-reverse);
$color-neutral-1: var(--color-neutral-1);
$color-neutral-2: var(--color-neutral-2);
$color-neutral-3: var(--color-neutral-3);

/**
STATUS
**/
$color-status-ready: var(--color-status-ready);
$color-status-offline: var(--color-status-offline);
$color-status-busy: var(--color-status-busy);

/**
BACKGROUNDS
**/
$color-background-overlay: var(--color-background-overlay);
$color-background-callout: var(--color-background-subtle-callout);
$color-background-modal-overlay: var(--color-background-modal-overlay);
$color-background-critical: var(--color-background-critical);
$color-background-neutral-0: var(--color-background-neutral-0);

/**
MENU
**/
$color-interactions-menu: var(--color-interactions-menu);
$color-interactions-menu-hover: var(--color-interactions-menu-hover);
$color-interactions-menu-inactive: var(--color-interactions-menu-inactive);
8 changes: 4 additions & 4 deletions src/utils/avatar-volume-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ export function calcGainMultiplier(level) {
);
}

export function updateAvatarVolumesPref(displayName, gainMultiplier, muted) {
export function updateAvatarVolumesPref(playerSessionId, gainMultiplier, muted) {
const avatarVoiceLevels = APP.store.state.preferences.avatarVoiceLevels || {};
avatarVoiceLevels[displayName] = {
avatarVoiceLevels[playerSessionId] = {
gainMultiplier,
muted
};
Expand All @@ -43,6 +43,6 @@ export function updateAvatarVolumesPref(displayName, gainMultiplier, muted) {
});
}

export function getAvatarVolumePref(displayName) {
return APP.store.state.preferences.avatarVoiceLevels?.[displayName];
export function getAvatarVolumePref(playerSessionId) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe the reason to use the display name instead of the session id is that the session id is ephemeral and different for each session while the display name is stored locally and only changes if the user updates it which tends to be not that often. This way we can restore user volumes across different session as long as the user doesn't update the display name.

It seems that at some point we stopped storing the displayName here:
https://github.com/mozilla/hubs/blob/9b2c6f5ba06431c2b503567335d32f710e90348a/src/components/player-info.js#L136-L143

We have two options, either store the displayName there so we can keep on accessing it through this.playerInfo.displayName or subscribe to the presence notifications in avatar-volume-controls like we do here and store the display name locally:
https://github.com/mozilla/hubs/blob/9b2c6f5ba06431c2b503567335d32f710e90348a/src/components/player-info.js#L99

Let me know if there is any other reason why we should switch to using the sessionId other than that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the context! I'll have a look into adding displayName back in.

return APP.store.state.preferences.avatarVoiceLevels?.[playerSessionId];
}