diff --git a/resources/js/meet-room.js b/resources/js/meet-room.js
index 7981630..94842ce 100644
--- a/resources/js/meet-room.js
+++ b/resources/js/meet-room.js
@@ -979,23 +979,30 @@ function meetRoom() {
if (room) {
const all = [room.localParticipant, ...room.remoteParticipants.values()];
all.forEach((participant) => {
- const tile = this.findParticipantTile(participant.identity);
- if (!tile) return;
-
const target = this.getTileContainerForIdentity(participant.identity);
- if (target) {
- if (tile.parentElement !== target) {
- target.appendChild(tile);
- }
+ if (!target) {
+ this.removeParticipantTile(participant.identity);
+ return;
+ }
- const isSpotlightTile = target === spotlight;
+ const existingTile = this.findParticipantTile(participant.identity);
+ const previousParent = existingTile?.parentElement ?? null;
+ const tile = this.getOrCreateParticipantTile(participant);
+ if (!tile) {
+ return;
+ }
- tile.classList.toggle('meet-stage-spotlight-tile', isSpotlightTile);
- tile.classList.toggle('meet-stage-panel-tile', target === grid && this.stageLayout === 'panel');
- tile.classList.toggle('aspect-video', !isSpotlightTile && !this.audioOnly);
- tile.classList.toggle('rounded-xl', !isSpotlightTile && !this.audioOnly);
+ const isSpotlightTile = target === spotlight;
+
+ tile.classList.toggle('meet-stage-spotlight-tile', isSpotlightTile);
+ tile.classList.toggle('meet-stage-panel-tile', target === grid && this.stageLayout === 'panel');
+ tile.classList.toggle('aspect-video', !isSpotlightTile && !this.audioOnly);
+ tile.classList.toggle('rounded-xl', !isSpotlightTile && !this.audioOnly);
+
+ if (!existingTile || previousParent !== target) {
+ this.reattachParticipantVideo(participant);
} else {
- tile.remove();
+ this.updateParticipantTile(participant);
}
});
}
@@ -1353,6 +1360,14 @@ function meetRoom() {
if (hasVideo) {
avatar.classList.add('hidden');
+ if (!stage.querySelector('video')) {
+ const publication = Array.from(participant.videoTrackPublications.values())
+ .find((pub) => pub.source !== Track.Source.ScreenShare && pub.track && !pub.isMuted);
+ if (publication?.track) {
+ this.attachVideoToTile(participant, publication.track);
+ }
+ }
+
return;
}
@@ -1379,6 +1394,22 @@ function meetRoom() {
stage.appendChild(el);
},
+ reattachParticipantVideo(participant) {
+ if (this.audioOnly || !participant) {
+ return;
+ }
+
+ const publication = Array.from(participant.videoTrackPublications.values())
+ .find((pub) => pub.source !== Track.Source.ScreenShare && pub.track && !pub.isMuted);
+
+ if (publication?.track) {
+ this.attachVideoToTile(participant, publication.track);
+ return;
+ }
+
+ this.updateParticipantTile(participant);
+ },
+
setupCaptionPipeline() {
if (!this.liveCaptions || !this.config.captionUrl) return;
if (room?.localParticipant?.isMicrophoneEnabled) return;
@@ -2019,6 +2050,15 @@ function meetRoom() {
return !this.canPublish || this.audioOnlyPublish;
},
+ /** Mobile primary toolbar — webinars/conferences only; meetings use More for extras. */
+ showPrimaryToolbarAudienceControls() {
+ if (!this.usesSpeakAccess) {
+ return false;
+ }
+
+ return this.showAudienceControls();
+ },
+
showStagePublisherControls() {
return this.usesSpeakAccess && this.canPublish && !this.audioOnlyPublish;
},
diff --git a/resources/views/meet/room/show.blade.php b/resources/views/meet/room/show.blade.php
index 3ebef27..6b7b150 100644
--- a/resources/views/meet/room/show.blade.php
+++ b/resources/views/meet/room/show.blade.php
@@ -375,19 +375,19 @@
@include('meet.room.partials.meet-icon', ['icon' => 'screen-share'])