Skip to content

Commit 41f4d14

Browse files
authored
Merge pull request #18112 from nextcloud/fix/18069/voice-room-followups
fix: voice room followups
2 parents eb52b8b + eb8ff43 commit 41f4d14

6 files changed

Lines changed: 76 additions & 49 deletions

File tree

‎src/App.vue‎

Lines changed: 8 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -176,14 +176,6 @@ export default {
176176
currentConversation() {
177177
return this.$store.getters.conversation(this.token)
178178
},
179-
180-
isVoiceRoom() {
181-
return Boolean(this.currentConversation?.attributes & CONVERSATION.ATTRIBUTE.VOICE_ROOM)
182-
},
183-
184-
voiceRoomIdentifier() {
185-
return [this.token, this.isVoiceRoom]
186-
},
187179
},
188180
189181
watch: {
@@ -205,30 +197,6 @@ export default {
205197
}
206198
},
207199
208-
voiceRoomIdentifier: {
209-
immediate: true,
210-
handler(newValue, oldValue = []) {
211-
const [newToken, newIsVoiceRoom] = newValue
212-
const [oldToken, oldIsVoiceRoom] = oldValue
213-
214-
if (!newIsVoiceRoom && oldIsVoiceRoom && newToken !== oldToken) {
215-
this.callViewStore.setForceCallView(false)
216-
}
217-
218-
if (oldIsVoiceRoom && newToken !== oldToken) {
219-
this.callViewStore.setSelectedVideoPeerId(null)
220-
this.$store.dispatch('leaveCall', {
221-
token: oldToken,
222-
participantIdentifier: this.actorStore.participantIdentifier,
223-
})
224-
}
225-
226-
if (newIsVoiceRoom && newToken) {
227-
this.joinCallAutomatically(newToken, oldToken)
228-
}
229-
},
230-
},
231-
232200
isInCall: {
233201
immediate: true,
234202
handler(value) {
@@ -406,7 +374,7 @@ export default {
406374
if (from.name === 'conversation' && to.name === 'conversation' && from.params.token === to.params.token) {
407375
// Navigating within the same conversation
408376
beforeRouteChangeListener(to, from, next)
409-
} else if (!this.warnLeaving || this.skipLeaveWarning || this.isVoiceRoom) {
377+
} else if (!this.warnLeaving || this.skipLeaveWarning || this.isVoiceRoom(from.params.token)) {
410378
// Safe to navigate
411379
// Note: voice rooms are intended to be left without confirmation.
412380
beforeRouteChangeListener(to, from, next)
@@ -450,8 +418,13 @@ export default {
450418
this.fetchSingleConversation(this.token)
451419
},
452420
421+
isVoiceRoom(token) {
422+
const conversation = this.$store.getters.conversation(token)
423+
return Boolean(conversation?.attributes & CONVERSATION.ATTRIBUTE.VOICE_ROOM)
424+
},
425+
453426
preventUnload(event) {
454-
if (!this.warnLeaving && !this.isSendingMessages) {
427+
if ((!this.warnLeaving && !this.isSendingMessages) || this.isVoiceRoom(this.token)) {
455428
return
456429
}
457430
@@ -543,7 +516,7 @@ export default {
543516
},
544517
545518
async joinCallAutomatically(targetToken, prevToken = this.token) {
546-
if (this.isInCall || this.isVoiceRoom) {
519+
if (this.isInCall) {
547520
this.callViewStore.setForceCallView(true)
548521
549522
const enableAudio = !BrowserStorage.getItem('audioDisabled_' + prevToken)

‎src/components/LeftSidebar/ConversationsList/ConversationItem.vue‎

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,15 @@
3636
</template>
3737
<template #name>
3838
<template v-if="compact && iconType">
39-
<component :is="iconType.component" :size="15" :fillColor="iconType.color" />
39+
<component
40+
:is="iconType.component"
41+
:size="15"
42+
:fillColor="iconType.color" />
4043
<span class="hidden-visually">{{ iconType.text }}</span>
4144
</template>
4245
<span class="text"> {{ item.displayName }} </span>
4346
</template>
44-
<template v-if="!compact && !item.isSensitive" #subname>
47+
<template v-if="!compact && !item.isSensitive && !isVoiceRoom" #subname>
4548
<span class="conversation__subname" :title="conversationInformation.title">
4649
<span
4750
v-if="conversationInformation.actor"
@@ -292,7 +295,7 @@ import { emit } from '@nextcloud/event-bus'
292295
import { t } from '@nextcloud/l10n'
293296
import { useIsDarkTheme } from '@nextcloud/vue/composables/useIsDarkTheme'
294297
import { spawnDialog } from '@nextcloud/vue/functions/dialog'
295-
import { ref, toRefs } from 'vue'
298+
import { h, ref, toRefs } from 'vue'
296299
import { isNavigationFailure, NavigationFailureType } from 'vue-router'
297300
import NcActionButton from '@nextcloud/vue/components/NcActionButton'
298301
import NcActionSeparator from '@nextcloud/vue/components/NcActionSeparator'
@@ -324,6 +327,7 @@ import IconVideo from 'vue-material-design-icons/Video.vue' // Filled for better
324327
import ConfirmDialog from '../../UIShared/ConfirmDialog.vue'
325328
import ConversationIcon from './../../ConversationIcon.vue'
326329
import IconMarkChatRead from '../../../../img/material-icons/mark-chat-read.svg?raw'
330+
import IconVolumeHighOutline from '../../../../img/material-icons/volume-high-outline.svg?raw'
327331
import { useConversationInfo } from '../../../composables/useConversationInfo.ts'
328332
import { AVATAR, CONVERSATION, PARTICIPANT } from '../../../constants.ts'
329333
import { getTalkConfig, hasTalkFeature } from '../../../services/CapabilitiesManager.ts'
@@ -486,6 +490,10 @@ export default {
486490
&& (!this.item.remoteServer || hasTalkFeature(this.item.token, 'federation-v2'))
487491
},
488492
493+
isVoiceRoom() {
494+
return !!(this.item.attributes & CONVERSATION.ATTRIBUTE.VOICE_ROOM)
495+
},
496+
489497
iconType() {
490498
if (this.item.hasCall) {
491499
return {
@@ -499,6 +507,11 @@ export default {
499507
color: this.isDarkTheme ? '#FFCC00' : 'currentColor',
500508
text: t('spreed', 'Favorite'),
501509
}
510+
} else if (this.isVoiceRoom) {
511+
return {
512+
component: h(NcIconSvgWrapper, { svg: IconVolumeHighOutline, inline: true }),
513+
text: t('spreed', 'Voice room'),
514+
}
502515
}
503516
return null
504517
},
@@ -758,7 +771,6 @@ export default {
758771
font-weight: 400;
759772
}
760773
}
761-
762774
}
763775
764776
&__subname {

‎src/components/MediaSettings/MediaSettings.vue‎

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
v-if="show"
1010
:size="isDialog ? 'large' : undefined"
1111
:labelId="isDialog ? dialogHeaderId : undefined"
12-
@close="close">
12+
:noClose="hideCloseButton"
13+
@close="handleDialogClose">
1314
<div class="media-settings">
1415
<h2
1516
v-if="isDialog"
@@ -40,6 +41,11 @@
4041
</NcCheckboxRadioSwitch>
4142
</template>
4243
</NcNoteCard>
44+
<NcNoteCard
45+
v-if="isBeforeJoinCall && isVoiceRoom"
46+
type="info">
47+
{{ t('spreed', 'You can only join a voice room via a call.') }}
48+
</NcNoteCard>
4349
<div class="media-settings__content" :class="{ 'media-settings__content--mobile': isMobile }">
4450
<!-- Preview -->
4551
<div class="media-settings__preview">
@@ -276,7 +282,7 @@ import IconBackground from '../../../img/material-icons/replace-background.svg?r
276282
import { useDevices } from '../../composables/useDevices.js'
277283
import { useGetToken } from '../../composables/useGetToken.ts'
278284
import { useIsInCall } from '../../composables/useIsInCall.js'
279-
import { ATTENDEE, AVATAR, CALL, CONFIG, PARTICIPANT, VIRTUAL_BACKGROUND } from '../../constants.ts'
285+
import { ATTENDEE, AVATAR, CALL, CONFIG, CONVERSATION, PARTICIPANT, VIRTUAL_BACKGROUND } from '../../constants.ts'
280286
import BrowserStorage from '../../services/BrowserStorage.js'
281287
import {
282288
getTalkConfig,
@@ -438,6 +444,15 @@ export default {
438444
return !this.userId && this.actorStore.actorType === ATTENDEE.ACTOR_TYPE.GUESTS
439445
},
440446
447+
isVoiceRoom() {
448+
return Boolean(this.conversation.attributes & CONVERSATION.ATTRIBUTE.VOICE_ROOM)
449+
},
450+
451+
hideCloseButton() {
452+
// Guests don't have Home dashboard so no rooting possible
453+
return this.isGuest && this.isVoiceRoom && this.isBeforeJoinCall
454+
},
455+
441456
userId() {
442457
return this.actorStore.userId
443458
},
@@ -519,7 +534,7 @@ export default {
519534
520535
showNotifyCallOption() {
521536
return !this.hasCall && !this.isPublicShareAuthSidebar
522-
&& this.isBeforeJoinCall
537+
&& this.isBeforeJoinCall && !this.isVoiceRoom
523538
},
524539
525540
showStartRecordingOption() {
@@ -711,6 +726,13 @@ export default {
711726
712727
methods: {
713728
t,
729+
handleDialogClose() {
730+
if (this.isBeforeJoinCall && this.isVoiceRoom && !this.isGuest) {
731+
this.$router?.push({ name: 'root' })
732+
}
733+
this.close()
734+
},
735+
714736
showMediaSettings(page) {
715737
this.show = true
716738
if (page === 'video-verification') {

‎src/stores/callView.ts‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ export const useCallViewStore = defineStore('callView', {
7575
if (!conversation) {
7676
return
7777
}
78+
// Start every call with a clean selection, so a stale peer id
79+
// from a previous call is not carried over
80+
this.setSelectedVideoPeerId(null)
7881
const gridPreference = BrowserStorage.getItem(`callprefs-${conversation.token}-isgrid`)
7982
const isGrid = gridPreference === null
8083
// not defined yet, default to grid view for group/public calls, otherwise speaker view

‎src/utils/sounds.js‎

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,22 @@
33
* SPDX-License-Identifier: AGPL-3.0-or-later
44
*/
55

6+
import { CONVERSATION } from '../constants.ts'
7+
import store from '../store/index.js'
68
import pinia from '../stores/pinia.ts'
79
import { useSoundsStore } from '../stores/sounds.js'
10+
import { useTokenStore } from '../stores/token.ts'
811

912
const soundsStore = useSoundsStore(pinia)
13+
const tokenStore = useTokenStore(pinia)
14+
15+
/**
16+
* Checks if the current conversation is a voice room.
17+
*/
18+
function isVoiceRoom() {
19+
const conversation = store.getters.conversation(tokenStore.token)
20+
return Boolean(conversation?.attributes & CONVERSATION.ATTRIBUTE.VOICE_ROOM)
21+
}
1022

1123
export const Sounds = {
1224
BLOCK_SOUND_TIMEOUT: 3000,
@@ -24,7 +36,7 @@ export const Sounds = {
2436
},
2537

2638
async playWaiting() {
27-
if (!soundsStore.shouldPlaySounds) {
39+
if (!soundsStore.shouldPlaySounds || isVoiceRoom()) {
2840
return
2941
}
3042

‎src/views/MainView.vue‎

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,17 @@ function stopWatchingJoinedConversation() {
4848
4949
const isInLobby = computed(() => store.getters.isInLobby)
5050
const connectionFailed = computed(() => store.getters.connectionFailed(props.token))
51+
const isVoiceRoom = computed(() => Boolean(store.getters.conversation(props.token)?.attributes & CONVERSATION.ATTRIBUTE.VOICE_ROOM))
52+
53+
watch([() => props.token, isVoiceRoom], ([newToken, newIsVoiceRoom]) => {
54+
// Release a stale joined-conversation listener when navigating away
55+
if (watchedJoinedConversationToken && watchedJoinedConversationToken !== newToken) {
56+
stopWatchingJoinedConversation()
57+
}
58+
if (newIsVoiceRoom && newToken) {
59+
handleDirectCall(newToken)
60+
}
61+
}, { immediate: true })
5162
5263
watch(isInLobby, (isInLobby) => {
5364
// User is now blocked by the lobby
@@ -59,12 +70,6 @@ watch(isInLobby, (isInLobby) => {
5970
}
6071
})
6172
62-
watch(() => props.token, (newToken) => {
63-
if (watchedJoinedConversationToken && watchedJoinedConversationToken !== newToken) {
64-
stopWatchingJoinedConversation()
65-
}
66-
})
67-
6873
onMounted(() => {
6974
watchEffect(() => {
7075
if (route.hash === '#direct-call') {

0 commit comments

Comments
 (0)