TT#43554 Call: Refactor CSC call vue.js component

Change-Id: Icefd79362d414bca9ffb857857af461ad3564c24
changes/96/23696/2
Hans-Peter Herzog 7 years ago
parent 68ee7088ba
commit 82a98ed539

@ -3,176 +3,187 @@
<audio
ref="incomingSound"
loop
playsinline
preload="auto"
src="statics/ring.mp3"
></audio>
<q-card
flat
color="secondary"
/>
<div class="csc-call-title absolute-top-left">
<q-icon
v-if="isPreparing"
name="call"
color="primary"
size="26px"
/>
<q-icon
v-if="isEstablished && isCaller"
name="call made"
color="primary"
size="26px"
/>
<q-icon
v-if="isEstablished && isCallee"
name="call received"
color="primary"
size="26px"
/>
<q-icon
v-if="isEnded"
name="error"
color="primary"
size="26px"
/>
<span
v-if="isPreparing"
class="text"
>
{{ $t('call.startNew') }}
</span>
<span
v-else-if="isInitiating"
class="text"
>
{{ $t('call.initiating') }}
</span>
<span
v-else-if="isRinging"
class="text"
>
{{ $t('call.ringing') }}
</span>
<span
v-else-if="isEnded"
class="text"
>
{{ $t('call.ended') }}
</span>
<span
v-else-if="isIncoming"
class="text"
>
{{ $t('call.incoming') }}
</span>
<span
v-else
class="text"
>
{{ $t('call.call') }}
</span>
</div>
<div
class="csc-call-top-actions absolute-top-right"
>
<q-card-title>
<span v-if="isRinging || isInitiating || isIncoming">
<q-spinner-rings
color="primary"
:size="50"
/>
</span>
<q-icon
v-if="isPreparing"
name="call"
color="primary"
size="26px"
/>
<q-icon
v-if="isEstablished && isCaller"
name="call made"
color="primary"
size="26px"
/>
<q-icon
v-if="isEstablished && isCallee"
name="call received"
color="primary"
size="26px"
/>
<q-icon
v-if="isEnded"
name="error"
color="primary"
size="26px"
/>
<span
v-if="isPreparing"
class="text"
>
{{ $t('call.startNew') }}
</span>
<span
v-else-if="isInitiating"
class="text"
>
{{ $t('call.initiating') }}
</span>
<span
v-else-if="isRinging"
class="text"
>
{{ $t('call.ringing') }}
</span>
<span
v-else-if="isEnded"
class="text"
>
{{ $t('call.ended') }}
</span>
<span
v-else-if="isIncoming"
class="text"
>
{{ $t('call.incoming') }}
</span>
<span
v-else
class="text"
>
{{ $t('call.call') }}
</span>
<q-btn
v-if="isFullscreenEnabled && !isMobile"
round
:small="!isFullscreenEnabled"
slot="right"
class="no-shadow"
@click="toggleFullscreen()"
icon="fullscreen exit"
/>
<q-btn
v-else-if="!isMobile"
round
:small="!isFullscreenEnabled"
slot="right"
class="no-shadow"
@click="toggleFullscreen()"
icon="fullscreen"
/>
<q-btn
round
:small="!isFullscreenEnabled"
slot="right"
class="no-shadow"
@click="close()"
icon="clear"
/>
</q-card-title>
<q-card-main>
<q-alert
v-if="desktopSharingInstall"
v-model="desktopSharingInstall"
color="warning"
:actions="desktopSharingAlertActions"
>
{{ $t('call.desktopSharingNotInstalled') }}
</q-alert>
<div class="csc-call-info">
<csc-phone-number-input
ref="phoneNumberInput"
v-if="isPreparing"
:enabled="isPhoneNumberInputEnabled"
/>
<div
v-if="!isPreparing"
class="phone-number"
>
<q-icon
v-if="isCalling && (localMediaType == 'audioVideo' || remoteMediaType == 'audioVideo')"
name="videocam"
color="primary"
size="26px"
/>
<q-icon
v-else-if="isCalling && (localMediaType == 'audioOnly' || remoteMediaType == 'audioVideo')"
name="mic"
color="primary"
size="26px"
/>
{{ getNumber | destinationFormat }}
</div>
<div
v-if="isEnded"
class="ended-reason"
>
{{ getEndedReason }}
</div>
<csc-call-dialpad
class="csc-call-dialpad"
v-if="isDialpadEnabled"
@inserted="dialpadInserted"
/>
</div>
<div class="csc-call-media">
<csc-media
:class="mediaPreviewClasses"
id="local-media"
:muted="true"
v-show="isCalling"
:stream="localMediaStream"
/>
<csc-media
class="csc-media-remote"
id="remote-media"
:muted="isMuted"
v-show="isEstablished"
:stream="remoteMediaStream"
/>
</div>
</q-card-main>
<q-card-actions align="center">
<q-btn
v-if="isFullscreenEnabled && !isMobile"
round
:small="!isFullscreenEnabled"
slot="right"
class="no-shadow"
@click="toggleFullscreen()"
icon="fullscreen exit"
color="default"
/>
<q-btn
v-else-if="!isMobile"
round
:small="!isFullscreenEnabled"
slot="right"
class="no-shadow"
@click="toggleFullscreen()"
icon="fullscreen"
color="default"
/>
<q-btn
round
:small="!isFullscreenEnabled"
slot="right"
class="no-shadow"
@click="close()"
icon="clear"
color="default"
/>
</div>
<div
class="csc-call-spinner row justify-center"
v-if="isRinging || isInitiating || isIncoming"
>
<q-spinner-rings
color="primary"
:size="50"
/>
</div>
<q-alert
v-if="desktopSharingInstall"
v-model="desktopSharingInstall"
color="warning"
:actions="desktopSharingAlertActions"
>
{{ $t('call.desktopSharingNotInstalled') }}
</q-alert>
<csc-phone-number-input
v-if="isPreparing"
class="csc-phone-number-input"
ref="phoneNumberInput"
:enabled="isPhoneNumberInputEnabled"
:dialpad-button="true"
@toggle-dialpad="toggleDialpad()"
@key-return="call('audioOnly')"
/>
<div
v-if="!isPreparing"
class="csc-phone-number"
>
<q-icon
v-if="isCalling && (localMediaType == 'audioVideo' || remoteMediaType == 'audioVideo')"
name="videocam"
color="primary"
size="26px"
/>
<q-icon
v-else-if="isCalling && (localMediaType == 'audioOnly' || remoteMediaType == 'audioVideo')"
name="mic"
color="primary"
size="26px"
/>
{{ getNumber | destinationFormat }}
</div>
<div
v-if="isEnded"
class="csc-call-ended-reason"
>
{{ getEndedReason | startCase }}
</div>
<div
:class="callMediaClasses"
v-show="isCalling || isEstablished"
>
<csc-media
class="csc-media-local"
id="local-media"
:muted="true"
v-show="isCalling"
:stream="localMediaStream"
/>
<csc-media
class="csc-media-remote"
id="remote-media"
:muted="isMuted"
v-show="isEstablished"
:stream="remoteMediaStream"
/>
</div>
<div
:class="callControlClasses"
>
<csc-call-dialpad
class="csc-call-dialpad"
v-if="isDialpadEnabled"
@inserted="dialpadInserted"
@remove="dialpadRemove"
@remove-all="dialpadRemoveAll"
/>
<div
class="csc-call-actions"
>
<q-btn
v-if="isEstablished"
round
@ -261,14 +272,6 @@
@click="accept('audioScreen')"
icon="computer"
/>
<q-btn
v-if="isDialpadButtonEnabled"
round
:small="!isFullscreenEnabled"
color="primary"
@click="toggleDialpad()"
icon="dialpad"
/>
<q-btn
v-if="isIncoming"
round
@ -277,8 +280,8 @@
@click="decline()"
icon="call end"
/>
</q-card-actions>
</q-card>
</div>
</div>
</div>
</template>
@ -350,6 +353,16 @@
this.$refs.phoneNumberInput.concat(value);
}
},
dialpadRemove() {
if(!this.isEstablished) {
this.$refs.phoneNumberInput.remove();
}
},
dialpadRemoveAll() {
if(!this.isEstablished) {
this.$refs.phoneNumberInput.removeAll();
}
},
focusNumberInput() {
this.$refs.phoneNumberInput.focusInput();
},
@ -474,13 +487,6 @@
return 'volume up';
}
},
mediaPreviewClasses() {
var classes = [];
if(this.isEstablished && this.hasRemoteVideo) {
classes.push('csc-media-preview');
}
return classes;
},
localMediaStream() {
if(this.$store.state.call.localMediaStream !== null) {
return this.$store.state.call.localMediaStream.getStream();
@ -544,18 +550,34 @@
isDialpadEnabled() {
return this.dialpadEnabled && (this.isPreparing || this.isEstablished);
},
isDialpadButtonEnabled() {
return this.isPreparing || this.isEstablished;
},
callClasses() {
let callClasses = ['csc-call'];
if(this.isEstablished) {
callClasses.push('csc-call-established');
let classes = ['csc-call', 'call-state-' + this.callState];
if (this.isFullscreenEnabled) {
classes.push('csc-call-fullscreen');
}
if (this.isMobile) {
classes.push('csc-call-mobile');
}
return classes;
},
callMediaClasses() {
let classes = ['csc-call-media'];
if (this.hasVideo) {
classes.push('csc-call-media-video');
}
return callClasses;
return classes;
},
callControlClasses() {
let classes = ['csc-call-controls'];
return classes;
}
},
watch: {
isEstablished(established) {
if(established) {
this.dialpadEnabled = false;
}
},
callState(state) {
if(state === 'incoming') {
showCallNotification(numberFormat(this.getNumber));
@ -566,6 +588,9 @@
}
else if (state === 'input') {
this.stopIncomingSound();
if(this.isMobile) {
this.dialpadEnabled = true;
}
}
else {
this.stopIncomingSound();
@ -577,77 +602,165 @@
<style lang="stylus" rel="stylesheet/stylus">
@import '../themes/quasar.variables.styl';
.csc-call {
width: inherit;
}
.csc-call .q-card {
margin: 0;
}
.csc-call .q-card-main {
padding: 0;
}
.csc-call .q-field {
margin: 0px;
padding-left: 16px;
padding-right: 16px;
}
.csc-call .q-card-actions {
padding: 16px;
}
.csc-spinner {
text-align: center;
margin-bottom: 16px;
}
.q-card-title .text {
color: #adb3b8;
}
.csc-call-fullscreen .csc-call .q-card-title .text {
color: white;
}
.csc-call .phone-number {
font-size: 18px;
text-align: center;
color: #adb3b8;
margin-bottom: 16px;
}
.csc-call-fullscreen .csc-call .phone-number {
color: white;
}
.csc-call .ended-reason {
font-size: 18px;
text-align: center;
color: #adb3b8;
}
.csc-call-media {
position: relative;
}
.csc-media.csc-media-preview {
position: absolute;
bottom: 0;
left: 0;
width: 25%;
z-index: 10;
}
.csc-call .q-alert-container {
margin-bottom: 16px;
}
.csc-call.csc-call-established
.csc-call
position relative
z-index 2
padding-top 64px
height 100%
.csc-call-title
z-index 11
padding 16px
color white
font-size 16px
line-height: 40px
.csc-call-top-actions
z-index 10
padding 16px
.csc-phone-number-input
position relative
z-index 9
margin 0
padding 16px
.csc-call-dialpad
position relative
z-index 8
padding 16px
.csc-call-actions
display flex
flex-direction row
position relative
z-index 7
padding 16px
padding-top 8px
justify-content center
.q-btn
margin-right 16px
display flex
.q-btn:last-child
margin-right 0
.csc-call-ended-reason
color indianred
text-align center
padding 16px
padding-top 0
position relative
z-index 6
font-size 16px
.csc-phone-number
text-align center
padding 16px
color white
position relative
z-index 6
font-size 16px
.q-icon
vertical-align middle
.csc-media-local
position relative
.csc-call-media.csc-call-media-video
padding-top 16px
padding-bottom 16px
position relative
z-index 2
.csc-call-spinner
position relative
padding 16px
z-index 3
.csc-call.csc-call-fullscreen
.csc-call-title
font-size 20px
line-height: 56px
.csc-call-controls
padding: 32px
.csc-call-actions
.q-btn
margin-right 16px
.q-btn:last-child
margin-right 0
.csc-call-media
padding 0
position absolute
top 0
left 0
right 0
bottom 0
.csc-media-local
position relative
padding 0
width: 100%
height: 100%
.csc-phone-number
font-size: 20px
.csc-call-ended-reason
font-size: 20px
.csc-call.csc-call-fullscreen.call-state-initiating,
.csc-call.csc-call-fullscreen.call-state-ringing
.csc-call-controls
position absolute
bottom 0
right 0
left 0
background-color alpha($secondary, 0.4)
.csc-call.call-state-established
.csc-call-media
.csc-media-local
position absolute
width 30%
height auto
z-index 2
bottom 24px
left 8px
-webkit-box-shadow: 0px 0px 29px -4px rgba(0,0,0,0.75);
-moz-box-shadow: 0px 0px 29px -4px rgba(0,0,0,0.75);
box-shadow: 0px 0px 29px -4px rgba(0,0,0,0.75);
.csc-media-remote
position relative
width 100%
height 100%
z-index 1
.csc-call.csc-call-fullscreen.call-state-established
.csc-call-media
.csc-media-local
bottom 16px
left 16px
width 20%
-webkit-box-shadow: 0px 0px 29px -4px rgba(0,0,0,0.75);
-moz-box-shadow: 0px 0px 29px -4px rgba(0,0,0,0.75);
box-shadow: 0px 0px 29px -4px rgba(0,0,0,0.75);
.csc-call-controls
position absolute
bottom 0
right 0
left 0
background-color alpha($secondary, 0.4)
.csc-call.csc-call-fullscreen.csc-call-mobile
padding-top 72px
.csc-call-title
padding 8px
padding-left 16px
font-size 20 px
line-height 56px
.csc-call-top-actions
padding 8px
.csc-phone-number-input
margin 0
padding 16px
.csc-call-dialpad
padding 4px
.csc-call-actions
padding 4px
.q-btn
margin-right 16px
.q-btn:last-child
margin-right 0
.csc-call.csc-call-fullscreen.csc-call-mobile.call-state-established
.csc-media-local
bottom 120px
left: 32px
.csc-call-controls
.csc-call-actions
padding-bottom 0
</style>

@ -3,6 +3,34 @@
<div
class="column"
>
<div
class="csc-dialpad-btn-group csc-dialpad-btn-group-special"
>
<div
class="csc-dialpad-btn"
>
<q-btn
color="primary"
round
outline
small
@click="remove()"
icon="backspace"
/>
</div>
<div
class="csc-dialpad-btn"
>
<q-btn
color="primary"
round
outline
small
@click="removeAll()"
icon="cancel"
/>
</div>
</div>
<div
class="csc-dialpad-btn-group"
v-for="(keyRow, rowIndex) in keys"
@ -81,6 +109,12 @@
if(this.isEstablished) {
this.$store.dispatch('call/sendDTMF', value);
}
},
remove() {
this.$emit('remove');
},
removeAll() {
this.$emit('remove-all');
}
}
}
@ -94,7 +128,8 @@
padding-bottom 0
.csc-dialpad-btn
display inline-block
display flex
flex-direction column
margin-left 16px
.q-btn-inner
font-size 22px
@ -106,8 +141,15 @@
margin-left 0
.csc-dialpad-btn-group
display: block
display: flex
flex-direction row
margin-bottom 8px
justify-content: flex-end
.csc-dialpad-btn-group.csc-dialpad-btn-group-special
justify-content: center
.q-btn
font-size 14px
.csc-dialpad-btn-group:last-child
margin-bottom 0

@ -1,9 +1,23 @@
<template>
<div class="csc-media">
<div v-show="loading" class="csc-spinner">
<q-spinner-mat color="primary" :size="60" />
<div
class="csc-media"
>
<div
v-show="loading"
class="csc-spinner"
>
<q-spinner-mat
color="primary"
:size="60"
/>
</div>
<video v-show="!loading && hasVideo" ref="media" autoplay :muted="muted"></video>
<video
v-show="!loading && hasVideo"
ref="media"
autoplay
:muted="muted"
playsinline
/>
</div>
</template>
@ -70,11 +84,20 @@
</script>
<style lang="stylus" rel="stylesheet/stylus">
.csc-media {
position: relative;
}
.csc-media video {
.csc-media
position: relative;
width: 100%;
}
font-size 0
video
position: relative;
width: 100%;
.csc-spinner
display flex
flex-direction row
justify-content center
.q-spinner-mat
display flex
flex-direction column
</style>

@ -1,5 +1,6 @@
<template>
<q-field
v-if="!isMobile"
dark
:count="maxLength"
:helper="helperMessage"
@ -19,6 +20,32 @@
@input="inputPhoneNumber"
@keypress.space.prevent
@keydown.space.prevent
@keyup.space.prevent
:after="inputButtons"
@keyup.enter="keyReturn()"
/>
</q-field>
<q-field
v-else
dark
:error="$v.phoneNumber.$error"
:error-label="errorMessage"
>
<q-input
ref="inputField"
dark
clearable
type="text"
:placeholder="$t('call.number')"
:value="phoneNumber"
:error="$v.phoneNumber.$error"
:max-length="maxLength"
:readonly="!enabled"
@input="inputPhoneNumber"
@keypress.space.prevent
@keydown.space.prevent
@keyup.space.prevent
:after="inputButtons"
/>
</q-field>
</template>
@ -64,6 +91,10 @@
enabled: {
type: Boolean,
default: true
},
dialpadButton: {
type: Boolean,
default: false
}
},
mixins: [
@ -78,9 +109,27 @@
},
inputReadonly() {
return this.isMobile;
},
inputButtons() {
let self = this;
let buttons = [];
if (this.dialpadButton) {
buttons.push({
icon: 'dialpad',
error: false,
handler (event) {
event.stopPropagation();
self.toggleDialpad();
}
});
}
return buttons;
}
},
methods: {
keyReturn() {
this.$emit('key-return');
},
inputPhoneNumber(value) {
this.phoneNumber = normalizeNumber(value, this.isMobile);
this.$v.phoneNumber.$touch();
@ -106,6 +155,18 @@
Vue.nextTick(() => {
this.$refs.inputField.blur();
});
},
remove() {
this.phoneNumber = _.trim(this.phoneNumber.substring(0, this.phoneNumber.length - 1));
if (this.phoneNumber === '+') {
this.phoneNumber = '';
}
},
removeAll() {
this.phoneNumber = '';
},
toggleDialpad() {
this.$emit('toggle-dialpad');
}
}
}

@ -581,11 +581,7 @@
}
.csc-call-fullscreen .csc-call .q-card-actions {
position: absolute;
bottom: 0;
right: 0;
left: 0;
z-index: 6001;
}
.csc-call-fullscreen .csc-call .q-card-main {

@ -5,9 +5,11 @@ import NumberFormatFilter from './number-format'
import { normalizeDestination } from './number-format'
import DateFilter from './date'
import { smartTime } from './date'
import { startCase } from './string'
Vue.filter('number', NumberFilter);
Vue.filter('readableDate', DateFilter);
Vue.filter('numberFormat', NumberFormatFilter);
Vue.filter('destinationFormat', normalizeDestination);
Vue.filter('smartTime', smartTime);
Vue.filter('startCase', startCase);

@ -0,0 +1,6 @@
import _ from 'lodash'
export function startCase(str) {
return _.startCase(str);
}
Loading…
Cancel
Save