Refactor messages, improve mobile accessibility
- Split messages into separate, reusable components - Move messages to below video on mobile - Size player to 16x9 on mobile - Disable send button if no message - Add icon to send button - Switch message field to single-line for compactness
This commit is contained in:
parent
3ff80a1c63
commit
ecde1b7005
|
@ -318,6 +318,13 @@ video.vjs-tech,
|
|||
padding-top: 0px;
|
||||
}
|
||||
|
||||
/* Make player 16x9 relative to viewport width on mobile */
|
||||
@media screen and (max-width: 1264px) {
|
||||
.ptplayer .video-js {
|
||||
height: calc(0.5625 * 100vw);
|
||||
}
|
||||
}
|
||||
|
||||
.ptplayer .vjs_video_1177-dimensions.vjs-fluid {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
|
|
@ -14,48 +14,51 @@
|
|||
:initialOffset="offset"
|
||||
:createdAt="playerCreatedAt"
|
||||
></videoplayer>
|
||||
<div v-if="playingMetadata && chosenServer">
|
||||
<transition name="fade">
|
||||
<div v-show="hovered">
|
||||
<v-layout row wrap style="position: absolute; top: 0; left: 0; z-index: 2" class="pa-3 hidden-xs-only">
|
||||
<img :src="thumbUrl" class="elevation-20" style="height: 80px; width: auto; vertical-align: middle; margin-left: auto; margin-right: auto;" />
|
||||
<v-flex class="pl-3">
|
||||
<v-container class="pa-0" fill-height>
|
||||
<v-layout column wrap justify-space-apart>
|
||||
<v-flex>
|
||||
<h1>{{ getTitle(playingMetadata) }}</h1>
|
||||
</v-flex>
|
||||
<v-flex>
|
||||
<h3>{{ getUnder(playingMetadata) }}</h3>
|
||||
</v-flex>
|
||||
<v-flex>
|
||||
<h5>Playing from {{ chosenServer.name }}</h5>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-container>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
<v-layout row wrap style="position: absolute; top: 0; right: 0; z-index: 2" class="pa-3 hidden-xs-only">
|
||||
<v-flex class="text-xs-right pa-1">
|
||||
<div class="hidden-xs-only">
|
||||
<v-tooltip bottom color="accent" v-if="me && me.role !== 'host'">
|
||||
<v-icon slot="activator" color="white" class="clickable" :disabled="manualSyncQueued" v-on:click="doManualSync">compare_arrows</v-icon>
|
||||
Manual Sync
|
||||
</v-tooltip>
|
||||
<v-icon slot="activator" color="white" class="clickable pl-3" v-on:click="dialog = !dialog">settings</v-icon>
|
||||
<router-link to="/browse" slot="activator">
|
||||
<v-icon color="white" class="pl-3" v-on:click.native="stopPlayback()">close</v-icon>
|
||||
</router-link>
|
||||
</div>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
<v-layout row wrap class="hoverBar" style="height: 120px; width: 100%; pointer-events: none; position: absolute; top: 0;">
|
||||
<v-flex xs12>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="playingMetadata && chosenServer">
|
||||
<transition name="fade">
|
||||
<div v-show="hovered">
|
||||
<v-layout row wrap style="position: absolute; top: 0; left: 0; z-index: 2" class="pa-3 hidden-xs-only">
|
||||
<img :src="thumbUrl" class="elevation-20" style="height: 80px; width: auto; vertical-align: middle; margin-left: auto; margin-right: auto;" />
|
||||
<v-flex class="pl-3">
|
||||
<v-container class="pa-0" fill-height>
|
||||
<v-layout column wrap justify-space-apart>
|
||||
<v-flex>
|
||||
<h1>{{ getTitle(playingMetadata) }}</h1>
|
||||
</v-flex>
|
||||
<v-flex>
|
||||
<h3>{{ getUnder(playingMetadata) }}</h3>
|
||||
</v-flex>
|
||||
<v-flex>
|
||||
<h5>Playing from {{ chosenServer.name }}</h5>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-container>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
<v-layout row wrap style="position: absolute; top: 0; right: 0; z-index: 2" class="pa-3 hidden-xs-only">
|
||||
<v-flex class="text-xs-right pa-1">
|
||||
<div class="hidden-xs-only">
|
||||
<v-tooltip bottom color="accent" v-if="me && me.role !== 'host'">
|
||||
<v-icon slot="activator" color="white" class="clickable" :disabled="manualSyncQueued" v-on:click="doManualSync">compare_arrows</v-icon>
|
||||
Manual Sync
|
||||
</v-tooltip>
|
||||
<v-icon slot="activator" color="white" class="clickable pl-3" v-on:click="dialog = !dialog">settings</v-icon>
|
||||
<router-link to="/browse" slot="activator">
|
||||
<v-icon color="white" class="pl-3" v-on:click.native="stopPlayback()">close</v-icon>
|
||||
</router-link>
|
||||
</div>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
<v-layout row wrap class="hoverBar" style="height: 120px; width: 100%; pointer-events: none; position: absolute; top: 0;">
|
||||
<v-flex xs12>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
<div class="messages-wrapper" v-if="$vuetify.breakpoint.mdAndDown">
|
||||
<messages :ptRoom="'room'"></messages>
|
||||
</div>
|
||||
<v-dialog v-model="dialog" width="350">
|
||||
<v-card>
|
||||
|
@ -106,9 +109,9 @@
|
|||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
<v-layout v-if="playingMetadata && chosenServer" justify-center align-center row class="pa-3 hidden-sm-and-up">
|
||||
<v-layout v-if="playingMetadata && chosenServer" justify-center row class="pa-3 hidden-sm-and-up">
|
||||
<v-flex xs12>
|
||||
<v-layout row wrap align-center justify-start>
|
||||
<v-layout row wrap>
|
||||
<img :src="thumbUrl" class="elevation-20" style="height: 80px; width: auto; vertical-align: middle; margin-left: auto; margin-right: auto" />
|
||||
<v-flex class="pl-2">
|
||||
<v-container class="pa-0" fill-height>
|
||||
|
@ -144,8 +147,18 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.messages-wrapper {
|
||||
height: calc(100vh - (0.5625 * 100vw) - 150px);
|
||||
}
|
||||
.is-fullscreen .messages-wrapper {
|
||||
height: calc(100vh - (0.5625 * 100vw));
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import videoplayer from './ptplayer/videoplayer.vue';
|
||||
import messages from '@/components/messages';
|
||||
|
||||
const plexthumb = require('./plexbrowser/plexthumb.vue');
|
||||
|
||||
|
@ -155,7 +168,7 @@ const parseXMLString = require('xml2js').parseString;
|
|||
export default {
|
||||
name: 'ptplayer',
|
||||
components: {
|
||||
videoplayer, plexthumb,
|
||||
videoplayer, plexthumb, messages,
|
||||
},
|
||||
mounted() {
|
||||
// Check if we have params
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
@statechanged="playerStateChanged($event)"
|
||||
|
||||
@ready="playerReadied"
|
||||
style="background-color:transparent !important; min-height: 75vh"
|
||||
style="background-color:transparent !important;"
|
||||
class="ptplayer"
|
||||
>
|
||||
</video-player>
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
<template>
|
||||
<v-flex align-center xs12 class="pb-1">
|
||||
<v-layout row wrap justify-start>
|
||||
<v-flex xs3 class="text-xs-center">
|
||||
<img :src="message.user.thumb || message.user.avatarUrl" style="width: 36px; height: 36px; border-radius: 50%" />
|
||||
</v-flex>
|
||||
<v-flex xs9 class="pr-2">
|
||||
<v-layout row wrap>
|
||||
<v-flex><b style="opacity:1;font-size:80%; float:left"> {{ message.user.username }}</b></v-flex>
|
||||
<v-flex><span style="opacity:0.6;font-size:60%; float:right"> {{ message.time}}</span></v-flex>
|
||||
<v-flex xs12>
|
||||
<div style="opacity:0.8;color:white;font-size:90%; max-width: 100%; word-wrap: break-word"> {{ message.msg }}</div>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
<v-layout row class="pt-1">
|
||||
<v-divider style="opacity: 0.6"></v-divider>
|
||||
</v-layout>
|
||||
</v-flex>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: ['message'],
|
||||
methods: {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
<template>
|
||||
<v-layout row wrap style="height: 100%;">
|
||||
<v-flex xs12 style="height: calc(100% - 96px)">
|
||||
<v-divider class="hidden-md-and-down"></v-divider>
|
||||
<v-layout row wrap id="chatbox" v-if="messages.length > 0" style="max-height: 100%; overflow-y: scroll">
|
||||
<message :message="msg" :id="getMsgId(msg)" v-for="(msg, index) in messages" :key="index"></message>
|
||||
</v-layout>
|
||||
<v-subheader v-else>Say something to the room down below :)</v-subheader>
|
||||
</v-flex>
|
||||
<v-flex xs12>
|
||||
<v-text-field
|
||||
prepend-icon="message"
|
||||
:label="'Send a message to ' + '#' + ptRoom"
|
||||
hide-details
|
||||
single-line
|
||||
class="ma-0 ml-1 pr-1 wideinput"
|
||||
v-on:keyup.enter.native="sendMessage()"
|
||||
v-model="messageToBeSent"
|
||||
></v-text-field>
|
||||
<v-btn block color="primary" @click="sendMessage()" :disabled="messageToBeSent.length === 0">Send<v-icon right>send</v-icon></v-btn>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import message from '@/components/message';
|
||||
import fscreen from 'fscreen';
|
||||
|
||||
import { mapActions, mapGetters } from 'vuex';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
message
|
||||
},
|
||||
props: ['ptRoom'],
|
||||
data() {
|
||||
return {
|
||||
messageToBeSent: '',
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
messages() {
|
||||
const options = {
|
||||
container: '#chatbox',
|
||||
easing: 'linear',
|
||||
duration: 1,
|
||||
cancelable: false,
|
||||
};
|
||||
console.info(this.$vuetify.breakpoint)
|
||||
this.$scrollTo('#lastMessage', 5, options);
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
messages() {
|
||||
return this.$store.getters.getMessages;
|
||||
},
|
||||
chatBoxMessage() {
|
||||
return `Message ${this.$store.getters.getRoom}`;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getMsgId(msg) {
|
||||
if (this.messages && msg === this.messages[this.messages.length - 1]) {
|
||||
return 'lastMessage';
|
||||
}
|
||||
},
|
||||
sendMessage() {
|
||||
if (this.messageToBeSent === '') {
|
||||
return;
|
||||
}
|
||||
console.log(`We should send this message: ${this.messageToBeSent}`);
|
||||
this.$store.dispatch('sendNewMessage', this.messageToBeSent);
|
||||
this.messageToBeSent = '';
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
|
@ -92,44 +92,7 @@
|
|||
</v-list>
|
||||
</v-flex>
|
||||
<v-flex xs12 style="position: relative; height: 50vh; max-height: 50vh">
|
||||
<v-layout row wrap style="height: 100%">
|
||||
<v-flex style="height: calc(100% - 96px); max-height: calc(100% - 96px)">
|
||||
<v-divider></v-divider>
|
||||
<v-subheader>Messages</v-subheader>
|
||||
<v-layout row wrap id="chatbox" style="max-height: calc(100% - 48px); overflow-y: auto">
|
||||
<v-flex align-center xs12 class="pb-1" :id="getMsgId(msg)" v-for="(msg, index) in messages" :key="index">
|
||||
<v-layout row wrap justify-start>
|
||||
<v-flex xs3 class="text-xs-center">
|
||||
<img :src="msg.user.thumb || msg.user.avatarUrl" style="width: 36px; height: 36px; border-radius: 50%" />
|
||||
</v-flex>
|
||||
<v-flex xs9 class="pr-2">
|
||||
<v-layout row wrap>
|
||||
<v-flex><b style="opacity:1;font-size:80%; float:left"> {{ msg.user.username }}</b></v-flex>
|
||||
<v-flex><span style="opacity:0.6;font-size:60%; float:right"> {{ msg.time}}</span></v-flex>
|
||||
<v-flex xs12>
|
||||
<div style="opacity:0.8;color:white;font-size:90%; max-width: 100%; word-wrap: break-word"> {{ msg.msg }}</div>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
<v-layout row class="pt-1">
|
||||
<v-divider style="opacity: 0.6"></v-divider>
|
||||
</v-layout>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-flex>
|
||||
<v-flex>
|
||||
<v-text-field
|
||||
prepend-icon="message"
|
||||
:label="'Send a message to ' + '#' + ptRoom"
|
||||
hide-details
|
||||
class="ma-0 ml-1 pr-1 wideinput"
|
||||
v-on:keyup.enter.native="sendMessage()"
|
||||
v-model="messageToBeSent"
|
||||
></v-text-field>
|
||||
<v-btn block color="primary" @click="sendMessage()">Send</v-btn>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
<messages :ptRoom="ptRoom" v-if="$vuetify.breakpoint.lgAndUp"></messages>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-container>
|
||||
|
@ -139,12 +102,14 @@
|
|||
|
||||
import { mapActions, mapGetters } from 'vuex';
|
||||
|
||||
import messages from '@/components/messages.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
messages
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
messageToBeSent: '',
|
||||
lastRecievedUpdate: new Date().getTime(),
|
||||
now: new Date().getTime(),
|
||||
|
||||
|
@ -157,15 +122,6 @@ export default {
|
|||
}, 250);
|
||||
},
|
||||
watch: {
|
||||
messages() {
|
||||
const options = {
|
||||
container: '#chatbox',
|
||||
easing: 'linear',
|
||||
duration: 1,
|
||||
cancelable: false,
|
||||
};
|
||||
this.$scrollTo('#lastMessage', 5, options);
|
||||
},
|
||||
ptUsers: {
|
||||
deep: true,
|
||||
handler() {
|
||||
|
@ -245,9 +201,6 @@ export default {
|
|||
}
|
||||
return `${count} users`;
|
||||
},
|
||||
chatBoxMessage() {
|
||||
return `Message ${this.$store.getters.getRoom}`;
|
||||
},
|
||||
playercount() {
|
||||
if (this.$store.state.plex && this.$store.state.plex.gotDevices) {
|
||||
return `(${this.$store.state.plex.clients.length})`;
|
||||
|
@ -269,9 +222,6 @@ export default {
|
|||
serverDelay() {
|
||||
return Math.round(this.$store.state.synclounge.commands[Object.keys(this.$store.state.synclounge.commands).length - 1].difference);
|
||||
},
|
||||
messages() {
|
||||
return this.$store.getters.getMessages;
|
||||
},
|
||||
difference() {
|
||||
return Math.abs(this.now - this.lastRecievedUpdate);
|
||||
},
|
||||
|
@ -331,11 +281,6 @@ export default {
|
|||
}
|
||||
return perc;
|
||||
},
|
||||
getMsgId(msg) {
|
||||
if (this.messages && msg === this.messages[this.messages.length - 1]) {
|
||||
return 'lastMessage';
|
||||
}
|
||||
},
|
||||
getCurrent(user) {
|
||||
if (isNaN(user.time) || user.time === 0 || !user.time) {
|
||||
return this.getTimeFromMs(0);
|
||||
|
@ -360,14 +305,6 @@ export default {
|
|||
}
|
||||
return 'Nothing';
|
||||
},
|
||||
sendMessage() {
|
||||
if (this.messageToBeSent === '') {
|
||||
return;
|
||||
}
|
||||
console.log(`We should send this message: ${this.messageToBeSent}`);
|
||||
this.$store.dispatch('sendNewMessage', this.messageToBeSent);
|
||||
this.messageToBeSent = '';
|
||||
},
|
||||
playerState(user) {
|
||||
if (user.playerState) {
|
||||
if (user.playerState === 'stopped') {
|
||||
|
|
Loading…
Reference in New Issue