Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 16 additions & 5 deletions src/components/multiview/ChatCell.vue
Original file line number Diff line number Diff line change
Expand Up @@ -124,16 +124,17 @@ export default {
type: Number,
default: 0,
},
tl: {
type: Boolean,
mode: {
// 0: auto, 1: yt, 2: tl, 3: both
type: Number,
required: false,
default: false,
default: 0,
},
},
data() {
return {
showTlChat: this.tl,
showYtChat: !this.tl,
showTlChat: this.mode === 3 || this.mode === 2 || (this.mode === 0 && this.$store.state.multiview.defaultShowTlChat),
showYtChat: this.mode === 3 || this.mode === 1 || (this.mode === 0 && this.$store.state.multiview.defaultShowYtChat),
scale: 1,
};
},
Expand Down Expand Up @@ -215,10 +216,20 @@ export default {
toggleYtChat() {
this.showYtChat = !this.showYtChat;
if (!this.showYtChat) this.showTlChat = true;
this.$store.commit("multiview/setLayoutContentWithKey", {
id: this.item.i,
key: "mode",
value: (this.showYtChat ? 1 : 0) + (this.showTlChat ? 2 : 0),
});
},
toggleTlChat() {
this.showTlChat = !this.showTlChat;
if (!this.showTlChat) this.showYtChat = true;
this.$store.commit("multiview/setLayoutContentWithKey", {
id: this.item.i,
key: "mode",
value: (this.showYtChat ? 1 : 0) + (this.showTlChat ? 2 : 0),
});
},
handleVideoUpdate(update) {
const v = this.layoutContent[this.videoCellId].video;
Expand Down
24 changes: 20 additions & 4 deletions src/components/multiview/EmptyCell.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
color="teal darken-1"
rounded-sm
large
@click="setItemAsChat(item, false)"
@click="setItemAsChat(item, 1)"
>
<v-icon left>
{{ icons.ytChat }}
Expand All @@ -33,14 +33,30 @@
color="teal darken-1"
rounded-sm
large
@click="setItemAsChat(item, true)"
@click="setItemAsChat(item, 2)"
>
<v-icon left>
{{ icons.tlChat }}
</v-icon>
TL
</v-btn>
</div>
<v-btn
class="mt-2"
color="teal darken-1"
rounded-sm
width="190px"
large
@click="setItemAsChat(item, 3)"
>
<v-icon left>
{{ icons.ytChat }}
</v-icon>
<v-icon left>
{{ icons.tlChat }}
</v-icon>
Chat + TL
</v-btn>
</div>
<CellControl :play-icon="icons.mdiPlay" class="mx-1 mb-2" @delete="deleteCell" />
</div>
Expand All @@ -62,12 +78,12 @@ export default {
};
},
methods: {
setItemAsChat(item, initAsTL) {
setItemAsChat(item, mode) {
this.$store.commit("multiview/setLayoutContentById", {
id: item.i,
content: {
type: "chat",
initAsTL,
mode,
},
});
},
Expand Down
50 changes: 48 additions & 2 deletions src/components/multiview/LayoutPreview.vue
Original file line number Diff line number Diff line change
@@ -1,14 +1,30 @@
<template>
<div class="layout-preview" :class="{ 'theme--light': !$vuetify.theme.dark }" :style="size">
<template v-for="l in layout">
<div :key="l.i" class="layout-preview-cell" :style="getStyle(l)">
<span v-if="content && content[l.i] && content[l.i].type === 'chat'">💬</span>
<div
:key="l.i"
class="layout-preview-cell flex-column"
:style="getStyle(l)"
>
<template v-if="isChat(content, l)">
<v-icon v-if="shouldShowTlIcon(content, l)" :small="!isXSmall(content, l)" :x-small="isXSmall(content, l)">
{{ icons.tlChat }}
</v-icon>
<v-icon v-if="shouldShowYtIcon(content, l)" :small="!isXSmall(content, l)" :x-small="isXSmall(content, l)">
{{ icons.ytChat }}
</v-icon>
<span v-if="shouldShowEmoji(content, l)" class="text-caption" title="Chat+TL">💬</span>
</template>
</div>
</template>
</div>
</template>

<script lang="ts">
import { mapState } from 'vuex';

const MIN_DOUBLE_ICON_HEIGHT = 8;
const MIN_XSMALL_ICON_HEIGHT = 5;
export default {
name: "LayoutPreview",
props: {
Expand All @@ -30,6 +46,7 @@ export default {
},
},
computed: {
...mapState("multiview", ["defaultShowYtChat", "defaultShowTlChat"]),
size() {
const width = this.scale * (this.mobile ? 108 : 192);
const height = this.scale * (this.mobile ? 192 : 108);
Expand All @@ -40,6 +57,35 @@ export default {
},
},
methods: {
isChat(content, l) {
return content && content[l.i] && content[l.i].type === "chat";
},
isXSmall(content, l) {
if (l.h < MIN_DOUBLE_ICON_HEIGHT) {
return l.h < MIN_XSMALL_ICON_HEIGHT;
}
if (this.showBothIcons(content, l)) {
return l.h < (MIN_XSMALL_ICON_HEIGHT * 2);
}
return false;
},
shouldShowEmoji(content, l) {
return l.h < MIN_DOUBLE_ICON_HEIGHT && this.showBothIcons(content, l);
},
showBothIcons(content, l) {
return content[l.i].mode === 3
|| (content[l.i].mode === 0 && this.defaultShowYtChat && this.defaultShowTlChat);
},
shouldShowYtIcon(content, l) {
return content[l.i].mode === 1
|| (content[l.i].mode === 0 && !this.defaultShowTlChat && this.defaultShowYtChat)
|| (this.showBothIcons(content, l) && l.h >= MIN_DOUBLE_ICON_HEIGHT);
},
shouldShowTlIcon(content, l) {
return content[l.i].mode === 2
|| (content[l.i].mode === 0 && this.defaultShowTlChat && !this.defaultShowYtChat)
|| (this.showBothIcons(content, l) && l.h >= MIN_DOUBLE_ICON_HEIGHT);
},
getStyle(l) {
// viewport is constricted to 24 cols and 24 rows
// assuming nothing is off the screen, 0 < x < 24, 0 < y < 24
Expand Down
37 changes: 34 additions & 3 deletions src/components/multiview/PresetSelector.vue
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,31 @@
{{ $t("views.favorites.showall") }}
</v-btn>
</div>
<v-row class="ml-1">
<v-row class="ml-1 text-body-1 d-flex align-center">
<span class="pl-4 pr-2">Chat Defaults:</span>
<v-btn
:color="defaultShowYtChat ? 'primary' : ''"
small
@click.stop="toggleDefaultYtChat"
>
<v-icon small class="mr-1">
{{ icons.ytChat }}
</v-icon>
Chat
</v-btn>
<v-btn
class="ml-1"
:color="defaultShowTlChat ? 'primary' : ''"
small
@click.stop="toggleDefaultTlChat"
>
<v-icon small class="mr-1">
{{ icons.tlChat }}
</v-icon>
TL
</v-btn>
</v-row>
<v-row class="ml-1 mt-1">
<template v-for="preset in currentGroup">
<v-col :key="preset.name" cols="auto" class="justify-center pa-1">
<LayoutPreviewCard
Expand All @@ -141,7 +165,7 @@
<script lang="ts">
import { mdiDotsVertical, mdiToggleSwitch } from "@mdi/js";
import { decodeLayout } from "@/utils/mv-utils";
import { mapState, mapGetters } from "vuex";
import { mapState, mapGetters, mapMutations } from "vuex";
import LayoutPreviewCard from "./LayoutPreviewCard.vue";

export default {
Expand All @@ -164,7 +188,7 @@ export default {
};
},
computed: {
...mapState("multiview", ["presetLayout", "autoLayout", "activeVideos", "layout", "layoutContent"]),
...mapState("multiview", ["presetLayout", "autoLayout", "activeVideos", "layout", "layoutContent", "defaultShowYtChat", "defaultShowTlChat"]),
...mapGetters("multiview", [
"decodedCustomPresets",
"decodedMobilePresets",
Expand All @@ -184,6 +208,7 @@ export default {
},
},
methods: {
...mapMutations("multiview", ["setDefaultYtChat", "setDefaultTlChat"]),
setAutoLayout(index, encodedLayout) {
this.$store.commit("multiview/setAutoLayout", { index, encodedLayout });
},
Expand All @@ -199,6 +224,12 @@ export default {
presetInAuto(preset) {
return this.autoLayoutSet.has(preset.id);
},
toggleDefaultYtChat() {
this.setDefaultYtChat(!this.defaultShowYtChat);
},
toggleDefaultTlChat() {
this.setDefaultTlChat(!this.defaultShowTlChat);
},
},
};
</script>
Expand Down
14 changes: 14 additions & 0 deletions src/store/multiview.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ const persistedState = {
twUrlHistory: [],
// Default true for iOS device
muteOthers: isAppleDevice,
defaultShowYtChat: true,
defaultShowTlChat: false,
syncOffsets: {},
};
export const state = { ...initialState, ...persistedState };
Expand Down Expand Up @@ -233,6 +235,18 @@ const mutations = {
}
});
}, 0, { trailing: true }),
setDefaultYtChat(state, value) {
state.defaultShowYtChat = value;
if (!value && !state.defaultShowTlChat) {
state.defaultShowTlChat = true;
}
},
setDefaultTlChat(state, value) {
state.defaultShowTlChat = value;
if (!value && !state.defaultShowYtChat) {
state.defaultShowYtChat = true;
}
},
setVideoData(state, videos) {
if (!videos) return;
videos.forEach((video) => {
Expand Down
34 changes: 30 additions & 4 deletions src/utils/mv-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,18 @@ export function encodeLayout({ layout, contents, includeVideo = false }) {

if (contents[item.i]) {
const {
id, type, video, currentTab,
id, type, mode, video, currentTab,
} = contents[item.i];
if (type === "chat") {
encodedBlock += `chat${currentTab || 0}`;
let prefix = "chat";
if (mode === 3) {
prefix = "chtl";
} else if (mode === 2) {
prefix = "_tl_";
} else if (mode === 1) {
prefix = "_ch_";
}
encodedBlock += `${prefix}${currentTab || 0}`;
} else if (type === "video" && includeVideo) {
if (video?.type === "twitch") {
encodedBlock += `twitch${id}`;
Expand Down Expand Up @@ -76,7 +84,24 @@ export function decodeLayout(encodedStr) {
const index = generateContentId();
const xywh = str.substring(0, 4);
const idOrChat = str.substring(4, 15);
const isChat = idOrChat.substring(0, 4) === "chat";
const chatModeStr = idOrChat.substring(0, 4);
let chatMode = -1;
switch (chatModeStr) {
case "chtl":
chatMode = 3;
break;
case "_tl_":
chatMode = 2;
break;
case "_ch_":
chatMode = 1;
break;
case "chat":
chatMode = 0;
break;
default:
break;
}
const isTwitch = idOrChat.substring(0, 6) === "twitch";
const channelName = str.substring(15);

Expand All @@ -98,10 +123,11 @@ export function decodeLayout(encodedStr) {
});
videoCellCount += 1;
layoutItem.i = index;
if (isChat) {
if (chatMode >= 0) {
const currentTab = idOrChat.length === 5 ? Number(idOrChat[4]) : -1;
parsedContent[index] = {
type: "chat",
mode: chatMode,
...(currentTab >= 0) && { currentTab },
};
videoCellCount -= 1;
Expand Down
2 changes: 1 addition & 1 deletion src/views/MultiView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@
<ChatCell
v-if="layoutContent[item.i] && layoutContent[item.i].type === 'chat'"
:item="item"
:tl="layoutContent[item.i].initAsTL"
:mode="layoutContent[item.i].mode"
:cell-width="columnWidth * item.w"
@delete="handleDelete"
/>
Expand Down
Loading