зеркало из https://github.com/nextcloud/spreed.git
Replace dummy sidebar contents with CallView and ChatView
Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
This commit is contained in:
Родитель
045650d1b7
Коммит
be8f2d6eed
|
@ -1,2 +1,3 @@
|
||||||
|
@import 'At.scss';
|
||||||
@import 'icons.scss';
|
@import 'icons.scss';
|
||||||
@import 'publicshare.scss';
|
@import 'publicshare.scss';
|
||||||
|
|
|
@ -29,18 +29,23 @@
|
||||||
<span v-if="joiningConversation" class="icon icon-loading-small" />
|
<span v-if="joiningConversation" class="icon icon-loading-small" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="emptycontent">
|
<template v-else>
|
||||||
<div class="icon icon-talk" />
|
<CallView v-if="isInCall" :token="token" :use-constrained-layout="true" />
|
||||||
<h2>Conversation joined</h2>
|
<CallButton class="call-button" />
|
||||||
</div>
|
<ChatView :token="token" />
|
||||||
|
</template>
|
||||||
</aside>
|
</aside>
|
||||||
</transition>
|
</transition>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import CallView from './components/CallView/CallView'
|
||||||
|
import ChatView from './components/ChatView'
|
||||||
|
import CallButton from './components/TopBar/CallButton'
|
||||||
|
import { PARTICIPANT } from './constants'
|
||||||
import { EventBus } from './services/EventBus'
|
import { EventBus } from './services/EventBus'
|
||||||
import { fetchConversation } from './services/conversationsService'
|
import { fetchConversation } from './services/conversationsService'
|
||||||
import { getPublicShareConversationToken } from './services/filesIntegrationServices'
|
import { getPublicShareConversationData } from './services/filesIntegrationServices'
|
||||||
import { joinConversation } from './services/participantsService'
|
import { joinConversation } from './services/participantsService'
|
||||||
import { getSignaling } from './utils/webrtc/index'
|
import { getSignaling } from './utils/webrtc/index'
|
||||||
|
|
||||||
|
@ -48,6 +53,12 @@ export default {
|
||||||
|
|
||||||
name: 'PublicShareSidebar',
|
name: 'PublicShareSidebar',
|
||||||
|
|
||||||
|
components: {
|
||||||
|
CallButton,
|
||||||
|
CallView,
|
||||||
|
ChatView,
|
||||||
|
},
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
shareToken: {
|
shareToken: {
|
||||||
type: String,
|
type: String,
|
||||||
|
@ -79,6 +90,17 @@ export default {
|
||||||
isOpen() {
|
isOpen() {
|
||||||
return this.state.isOpen
|
return this.state.isOpen
|
||||||
},
|
},
|
||||||
|
|
||||||
|
isInCall() {
|
||||||
|
const participantIndex = this.$store.getters.getParticipantIndex(this.token, this.$store.getters.getParticipantIdentifier())
|
||||||
|
if (participantIndex === -1) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
const participant = this.$store.getters.getParticipant(this.token, participantIndex)
|
||||||
|
|
||||||
|
return participant.inCall !== PARTICIPANT.CALL_FLAG.DISCONNECTED
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -86,7 +108,7 @@ export default {
|
||||||
async joinConversation() {
|
async joinConversation() {
|
||||||
this.joiningConversation = true
|
this.joiningConversation = true
|
||||||
|
|
||||||
await this.getPublicShareConversationToken()
|
await this.getPublicShareConversationData()
|
||||||
|
|
||||||
await joinConversation(this.token)
|
await joinConversation(this.token)
|
||||||
|
|
||||||
|
@ -113,10 +135,31 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async getPublicShareConversationToken() {
|
async getPublicShareConversationData() {
|
||||||
const token = await getPublicShareConversationToken(this.shareToken)
|
const data = await getPublicShareConversationData(this.shareToken)
|
||||||
|
|
||||||
this.$store.dispatch('updateToken', token)
|
this.$store.dispatch('updateToken', data.token)
|
||||||
|
|
||||||
|
if (data.userId) {
|
||||||
|
// Instead of using "getCurrentUser()" the current user is set
|
||||||
|
// from the data returned by the controller (as the public share
|
||||||
|
// page uses the incognito mode, and thus it always returns an
|
||||||
|
// anonymous user).
|
||||||
|
//
|
||||||
|
// When the external signaling server is used it should wait
|
||||||
|
// until the current user is set before trying to connect, as
|
||||||
|
// otherwise the connection would fail due to a mismatch between
|
||||||
|
// the user ID given when connecting to the backend (an
|
||||||
|
// anonymous user) and the user that fetched the signaling
|
||||||
|
// settings (the actual user). However, if that happens the
|
||||||
|
// signaling server will retry the connection again and again,
|
||||||
|
// so at some point the anonymous user will have been overriden
|
||||||
|
// with the current user and the connection will succeed.
|
||||||
|
this.$store.dispatch('setCurrentUser', {
|
||||||
|
uid: data.userId,
|
||||||
|
displayName: data.displayName,
|
||||||
|
})
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async fetchCurrentConversation() {
|
async fetchCurrentConversation() {
|
||||||
|
@ -127,6 +170,14 @@ export default {
|
||||||
try {
|
try {
|
||||||
const response = await fetchConversation(this.token)
|
const response = await fetchConversation(this.token)
|
||||||
this.$store.dispatch('addConversation', response.data.ocs.data)
|
this.$store.dispatch('addConversation', response.data.ocs.data)
|
||||||
|
|
||||||
|
// Although the current participant is automatically added to
|
||||||
|
// the participants store it must be explicitly set in the
|
||||||
|
// actors store.
|
||||||
|
if (!this.$store.getters.getUserId()) {
|
||||||
|
// Setting a guest only uses "sessionId" and "participantType".
|
||||||
|
this.$store.dispatch('setCurrentParticipant', response.data.ocs.data)
|
||||||
|
}
|
||||||
} catch (exception) {
|
} catch (exception) {
|
||||||
window.clearInterval(this.fetchCurrentConversationIntervalId)
|
window.clearInterval(this.fetchCurrentConversationIntervalId)
|
||||||
|
|
||||||
|
@ -175,6 +226,18 @@ export default {
|
||||||
max-width: 0 !important;
|
max-width: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#talk-sidebar {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#talk-sidebar > .emptycontent {
|
||||||
|
/* Remove default margin-top as it is unneeded when showing only the empty
|
||||||
|
* content in a flex sidebar. */
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
#talk-sidebar .emptycontent button .icon {
|
#talk-sidebar .emptycontent button .icon {
|
||||||
/* Override rules set for the main icon of an empty content area when an
|
/* Override rules set for the main icon of an empty content area when an
|
||||||
* icon is shown in a button. */
|
* icon is shown in a button. */
|
||||||
|
@ -187,4 +250,66 @@ export default {
|
||||||
top: -3px;
|
top: -3px;
|
||||||
right: -5px;
|
right: -5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#talk-sidebar .call-button {
|
||||||
|
/* Center button horizontally. */
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
|
||||||
|
margin-top: 10px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#talk-sidebar #call-container {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
flex-grow: 1;
|
||||||
|
|
||||||
|
/* Prevent shadows of videos from leaking on other elements. */
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
/* Show the call container in a 16/9 proportion based on the sidebar
|
||||||
|
* width. This is the same proportion used for previews of images by the
|
||||||
|
* SidebarPreviewManager. */
|
||||||
|
padding-bottom: 56.25%;
|
||||||
|
max-height: 56.25%;
|
||||||
|
|
||||||
|
/* Override the call container height so it properly adjusts to the 16/9
|
||||||
|
* proportion. */
|
||||||
|
height: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
#talk-sidebar #call-container ::v-deep .videoContainer {
|
||||||
|
/* The video container has some small padding to prevent the video from
|
||||||
|
* reaching the edges, but it also uses "width: 100%", so the padding should
|
||||||
|
* be included in the full width of the element. */
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
#talk-sidebar #call-container ::v-deep .videoContainer.promoted video {
|
||||||
|
/* Base the size of the video on its width instead of on its height;
|
||||||
|
* otherwise the video could appear in full height but cropped on the sides
|
||||||
|
* due to the space available in the sidebar being typically larger in
|
||||||
|
* vertical than in horizontal. */
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#talk-sidebar #call-container ::v-deep .nameIndicator {
|
||||||
|
/* The name indicator has some small padding to prevent the name from
|
||||||
|
* reaching the edges, but it also uses "width: 100%", so the padding should
|
||||||
|
* be included in the full width of the element. */
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
#talk-sidebar .chatView {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
flex-grow: 1;
|
||||||
|
|
||||||
|
/* Distribute available height between call container and chat view. */
|
||||||
|
height: 50%;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -46,12 +46,12 @@ const getFileConversation = async function({ fileId }, options) {
|
||||||
* @returns {String} the conversation token
|
* @returns {String} the conversation token
|
||||||
* @throws {Exception} if the conversation token could not be got
|
* @throws {Exception} if the conversation token could not be got
|
||||||
*/
|
*/
|
||||||
const getPublicShareConversationToken = async function(shareToken) {
|
const getPublicShareConversationData = async function(shareToken) {
|
||||||
const response = await axios.get(generateOcsUrl('apps/spreed/api/v1', 2) + `publicshare/${shareToken}`)
|
const response = await axios.get(generateOcsUrl('apps/spreed/api/v1', 2) + `publicshare/${shareToken}`)
|
||||||
return response.data.ocs.data.token
|
return response.data.ocs.data
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
getFileConversation,
|
getFileConversation,
|
||||||
getPublicShareConversationToken,
|
getPublicShareConversationData,
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,7 +78,17 @@ const actions = {
|
||||||
addConversation(context, conversation) {
|
addConversation(context, conversation) {
|
||||||
context.commit('addConversation', conversation)
|
context.commit('addConversation', conversation)
|
||||||
|
|
||||||
const currentUser = getCurrentUser()
|
let currentUser = {
|
||||||
|
uid: context.getters.getUserId(),
|
||||||
|
displayName: context.getters.getDisplayName(),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback to getCurrentUser() only if if has not been set yet (as
|
||||||
|
// getCurrentUser() needs to be overriden in public share pages as it
|
||||||
|
// always returns an anonymous user).
|
||||||
|
if (!currentUser.uid) {
|
||||||
|
currentUser = getCurrentUser()
|
||||||
|
}
|
||||||
context.dispatch('addParticipantOnce', {
|
context.dispatch('addParticipantOnce', {
|
||||||
token: conversation.token,
|
token: conversation.token,
|
||||||
participant: {
|
participant: {
|
||||||
|
@ -86,7 +96,7 @@ const actions = {
|
||||||
lastPing: conversation.lastPing,
|
lastPing: conversation.lastPing,
|
||||||
sessionId: conversation.sessionId,
|
sessionId: conversation.sessionId,
|
||||||
participantType: conversation.participantType,
|
participantType: conversation.participantType,
|
||||||
userId: currentUser ? currentUser.uid : '', // TODO Does this work for public shares while being logged in, etc?
|
userId: currentUser ? currentUser.uid : '',
|
||||||
displayName: currentUser && currentUser.displayName ? currentUser.displayName : '', // TODO guest name from localstore?
|
displayName: currentUser && currentUser.displayName ? currentUser.displayName : '', // TODO guest name from localstore?
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
Загрузка…
Ссылка в новой задаче