Replace dummy sidebar contents with CallView and ChatView

Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
This commit is contained in:
Daniel Calviño Sánchez 2020-01-15 05:39:04 +01:00
Родитель 045650d1b7
Коммит be8f2d6eed
4 изменённых файлов: 150 добавлений и 14 удалений

Просмотреть файл

@ -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?
}, },
}) })