diff --git a/src/components/multiview/MultiviewLayoutMixin.ts b/src/components/multiview/MultiviewLayoutMixin.ts
index dc8a3c1b4..16c67e6f2 100644
--- a/src/components/multiview/MultiviewLayoutMixin.ts
+++ b/src/components/multiview/MultiviewLayoutMixin.ts
@@ -1,5 +1,5 @@
import type { Content } from "@/utils/mv-utils";
-import { decodeLayout, sortLayout } from "@/utils/mv-utils";
+import { decodeLayout, generateContentId, sortLayout } from "@/utils/mv-utils";
import { mapGetters } from "vuex";
export default {
@@ -178,18 +178,24 @@ export default {
if (mergeContent) {
const contentsToMerge = {};
let videoIndex = 0;
- const currentVideos = Object.values(this.layoutContent as Content[]).filter((o) => o.type === "video");
+ // Maintain the original layout ordering when chosing new videos.
+ const currentVideoContents = this.layout.filter(({ i }) => this.layoutContent[i]?.type === "video");
const newVideoIdToIndex = {};
// Loop through the incoming layout, and fill with current content
layout.filter((item) => !content[item.i]).forEach((item) => {
// For empty cells fill until there's no more current videos
if (videoIndex < this.activeVideos.length) {
// get next video to fill this item's cell
- const key = item.i;
- contentsToMerge[key] = currentVideos[videoIndex];
+ const key = currentVideoContents[videoIndex].i;
+ // Re-use the original video's index so that the component is not re-mounted.
+ item.i = key;
+ contentsToMerge[key] = this.layoutContent[key];
// Infer next activeVideos to be used in auto chat tabbing below
- newVideoIdToIndex[currentVideos[videoIndex].video.id] = videoIndex;
+ newVideoIdToIndex[this.layoutContent[key].video.id] = videoIndex;
videoIndex += 1;
+ } else {
+ // Create a new id because the templates are cached with re-used ids that would otherwise cause issues.
+ item.i = generateContentId();
}
});
diff --git a/src/store/multiview.module.ts b/src/store/multiview.module.ts
index 7781f3346..648831130 100644
--- a/src/store/multiview.module.ts
+++ b/src/store/multiview.module.ts
@@ -3,6 +3,7 @@ import type { LayoutItem } from "@/external/vue-grid-layout/src/helpers/utils";
import { getFirstCollision } from "@/external/vue-grid-layout/src/helpers/utils";
import {
getDesktopDefaults, desktopPresets, mobilePresets, decodeLayout,
+ generateContentId,
} from "@/utils/mv-utils";
import type { Content } from "@/utils/mv-utils";
import api from "@/utils/backend-api";
@@ -128,7 +129,6 @@ const mutations = {
},
addLayoutItem(state) {
// Increment the counter to ensure key is always unique.
- state.index = new Date().getTime();
let newLayoutItem: LayoutItem;
// try to find a good location for it:
@@ -140,7 +140,7 @@ const mutations = {
y,
w: 4,
h: 6,
- i: state.index,
+ i: generateContentId(),
isResizable: true,
isDraggable: true,
};
@@ -158,7 +158,7 @@ const mutations = {
y: 24, // puts it at the bottom
w: 4,
h: 6,
- i: state.index,
+ i: generateContentId(),
isResizable: true,
isDraggable: true,
};
diff --git a/src/utils/mv-utils.ts b/src/utils/mv-utils.ts
index 22e2a7b27..034453940 100644
--- a/src/utils/mv-utils.ts
+++ b/src/utils/mv-utils.ts
@@ -13,6 +13,10 @@ const b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.";
export const sortLayout = (a, b) => a.x - b.x || a.y - b.y;
// export const sortLayout = (a, b) => a.y - b.y || a.x - b.x;
+export const generateContentId = () => Array.from({ length: 8 })
+ .map(() => b64[Math.floor(Math.random() * b64.length)])
+ .join("");
+
/**
* Encodes a layout array and contents to a compact URI
* @param {{layout, contents, includeVideo?}} layout and layout contents
@@ -68,7 +72,8 @@ export function decodeLayout(encodedStr) {
let videoCellCount = 0;
const parts = encodedStr.split(",");
parts.sort(); // DO NOT TOUCH THIS LINE
- parts.forEach((str, index) => {
+ parts.forEach((str) => {
+ const index = generateContentId();
const xywh = str.substring(0, 4);
const idOrChat = str.substring(4, 15);
const isChat = idOrChat.substring(0, 4) === "chat";
diff --git a/src/views/MultiView.vue b/src/views/MultiView.vue
index 56736e556..7473c4278 100644
--- a/src/views/MultiView.vue
+++ b/src/views/MultiView.vue
@@ -81,41 +81,44 @@
:margin="[1, 1]"
@layout-updated="onLayoutUpdated"
>
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+