Merge branch 'dev' into add-turn-server

This commit is contained in:
Miroslav Šedivý 2021-04-04 22:49:36 +02:00 committed by GitHub
commit 7a61f7e2da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 1895 additions and 1724 deletions

View File

@ -40,6 +40,7 @@ For n.eko room management software visit https://github.com/m1k1o/neko-rooms.
- Added simple language picker. - Added simple language picker.
- Added `?usr=<display-name>` that will prefill username. This allows creating auto-join links. - Added `?usr=<display-name>` that will prefill username. This allows creating auto-join links.
- Added `?cast=1` that will hide all control and show only video. - Added `?cast=1` that will hide all control and show only video.
- Shake keyboard icon if someone attempted to control when is nobody hosting.
- Support for password protected `NEKO_ICESERVERS` (by @mbattista). - Support for password protected `NEKO_ICESERVERS` (by @mbattista).
### Bugs ### Bugs
@ -67,6 +68,7 @@ For n.eko room management software visit https://github.com/m1k1o/neko-rooms.
- Abiltiy to include neko as a component in another Vue.Js project (by @gbrian). - Abiltiy to include neko as a component in another Vue.Js project (by @gbrian).
- Added HEALTHCHECK to Dockerfile. - Added HEALTHCHECK to Dockerfile.
- Arguments in broadcast pipeline are optional, not positional and can be repeated `{url} {device} {display}`. - Arguments in broadcast pipeline are optional, not positional and can be repeated `{url} {device} {display}`.
- Chat messages are dense, when repeated, they are joined together.
### Roadmap & TODOs ### Roadmap & TODOs
- Catch errors from gst pipeline, tell user if broadcast failed. - Catch errors from gst pipeline, tell user if broadcast failed.

View File

@ -25,7 +25,6 @@
"axios": "^0.21.1", "axios": "^0.21.1",
"date-fns": "^2.16.1", "date-fns": "^2.16.1",
"emoji-datasource": "^6.0.1", "emoji-datasource": "^6.0.1",
"emojilib": "^3.0.1",
"eventemitter3": "^4.0.7", "eventemitter3": "^4.0.7",
"resize-observer-polyfill": "^1.5.1", "resize-observer-polyfill": "^1.5.1",
"simple-markdown": "^0.7.2", "simple-markdown": "^0.7.2",
@ -56,6 +55,7 @@
"@vue/eslint-config-prettier": "^6.0.0", "@vue/eslint-config-prettier": "^6.0.0",
"@vue/eslint-config-typescript": "^7.0.0", "@vue/eslint-config-typescript": "^7.0.0",
"core-js": "^3.9.1", "core-js": "^3.9.1",
"emojilib": "^2.4.0",
"eslint": "^6.8.0", "eslint": "^6.8.0",
"eslint-plugin-prettier": "^3.1.4", "eslint-plugin-prettier": "^3.1.4",
"eslint-plugin-vue": "^7.8.0", "eslint-plugin-vue": "^7.8.0",

File diff suppressed because one or more lines are too long

View File

@ -9,7 +9,7 @@
<neko-header /> <neko-header />
</div> </div>
<div class="video-container"> <div class="video-container">
<neko-video ref="video" :hideControls="hideControls" /> <neko-video ref="video" :hideControls="hideControls" @control-attempt="controlAttempt" />
</div> </div>
<div v-if="!hideControls" class="room-container"> <div v-if="!hideControls" class="room-container">
<neko-members /> <neko-members />
@ -18,7 +18,7 @@
<neko-menu /> <neko-menu />
</div> </div>
<div class="controls"> <div class="controls">
<neko-controls /> <neko-controls :shakeKbd="shakeKbd" />
</div> </div>
<div class="emotes"> <div class="emotes">
<neko-emotes /> <neko-emotes />
@ -174,6 +174,8 @@
export default class extends Vue { export default class extends Vue {
@Ref('video') video!: Video @Ref('video') video!: Video
shakeKbd = false
get hideControls() { get hideControls() {
return !!new URL(location.href).searchParams.get('cast') return !!new URL(location.href).searchParams.get('cast')
} }
@ -184,6 +186,13 @@
this.$accessor.settings.setSound(false) this.$accessor.settings.setSound(false)
} }
controlAttempt() {
if (this.shakeKbd || this.$accessor.remote.hosted) return
this.shakeKbd = true
setTimeout(() => (this.shakeKbd = false), 5000)
}
get about() { get about() {
return this.$accessor.client.about return this.$accessor.client.about
} }

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,14 @@
<div class="chat"> <div class="chat">
<ul class="chat-history" ref="history" @click="onClick"> <ul class="chat-history" ref="history" @click="onClick">
<template v-for="(message, index) in history"> <template v-for="(message, index) in history">
<li :key="index" class="message" v-if="message.type === 'text'"> <li
:key="index"
class="message"
v-if="message.type === 'text'"
:class="{
bulk: index > 0 && history[index - 1].id == message.id && history[index - 1].type === 'text',
}"
>
<div class="author" @contextmenu.stop.prevent="onContext($event, { member: member(message.id) })"> <div class="author" @contextmenu.stop.prevent="onContext($event, { member: member(message.id) })">
<neko-avatar class="avatar" :seed="member(message.id).displayname" :size="40" /> <neko-avatar class="avatar" :seed="member(message.id).displayname" :size="40" />
</div> </div>
@ -94,6 +101,7 @@
word-wrap: break-word; word-wrap: break-word;
&.message { &.message {
padding-top: 15px;
font-size: 16px; font-size: 16px;
.author { .author {
@ -104,7 +112,7 @@
height: 40px; height: 40px;
border-radius: 50%; border-radius: 50%;
background: $style-primary; background: $style-primary;
margin: 0px 10px 10px 0px; margin-right: 10px;
.avatar { .avatar {
width: 100%; width: 100%;
@ -219,6 +227,19 @@
} }
} }
} }
&.bulk {
padding-top: 0px;
.author {
visibility: hidden;
height: 0;
}
.content-head {
display: none;
}
}
} }
&.event { &.event {

View File

@ -3,6 +3,7 @@
<li v-if="!isTouch"> <li v-if="!isTouch">
<i <i
:class="[ :class="[
shakeKbd ? 'shake' : '',
hosted && !hosting ? 'disabled' : '', hosted && !hosting ? 'disabled' : '',
!hosted && !hosting ? 'faded' : '', !hosted && !hosting ? 'faded' : '',
'fas', 'fas',
@ -53,6 +54,46 @@
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped>
.shake {
animation: shake 1.25s cubic-bezier(0, 0, 0, 1);
}
@keyframes shake {
0% {
transform: scale(1) translate(0px, 0) rotate(0);
}
10% {
transform: scale(1.25) translate(-2px, -2px) rotate(-20deg);
}
20% {
transform: scale(1.5) translate(4px, -4px) rotate(20deg);
}
30% {
transform: scale(1.75) translate(-4px, -6px) rotate(-20deg);
}
40% {
transform: scale(2) translate(6px, -8px) rotate(20deg);
}
50% {
transform: scale(2.25) translate(-6px, -10px) rotate(-20deg);
}
60% {
transform: scale(2) translate(6px, -8px) rotate(20deg);
}
70% {
transform: scale(1.75) translate(-4px, -6px) rotate(-20deg);
}
80% {
transform: scale(1.5) translate(4px, -4px) rotate(20deg);
}
90% {
transform: scale(1.25) translate(-2px, -2px) rotate(-20deg);
}
100% {
transform: scale(1) translate(0px, 0) rotate(0);
}
}
ul { ul {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
@ -195,10 +236,12 @@
</style> </style>
<script lang="ts"> <script lang="ts">
import { Vue, Component } from 'vue-property-decorator' import { Vue, Component, Prop } from 'vue-property-decorator'
@Component({ name: 'neko-controls' }) @Component({ name: 'neko-controls' })
export default class extends Vue { export default class extends Vue {
@Prop(Boolean) readonly shakeKbd = false
get isTouch() { get isTouch() {
return ( return (
(typeof navigator.maxTouchPoints !== 'undefined' ? navigator.maxTouchPoints < 0 : false) || (typeof navigator.maxTouchPoints !== 'undefined' ? navigator.maxTouchPoints < 0 : false) ||

View File

@ -15,8 +15,8 @@
? $t('room.unlock') ? $t('room.unlock')
: $t('room.lock') : $t('room.lock')
: locked : locked
? $t('room.unlocked') ? $t('room.locked')
: $t('room.locked'), : $t('room.unlocked'),
placement: 'bottom', placement: 'bottom',
offset: 5, offset: 5,
boundariesElement: 'body', boundariesElement: 'body',

View File

@ -552,9 +552,14 @@
} }
onMouseDown(e: MouseEvent) { onMouseDown(e: MouseEvent) {
if (!this.hosting) {
this.$emit('control-attempt', e)
}
if (!this.hosting || this.locked) { if (!this.hosting || this.locked) {
return return
} }
this.onMousePos(e) this.onMousePos(e)
this.$client.sendData('mousedown', { key: e.button + 1 }) this.$client.sendData('mousedown', { key: e.button + 1 })
} }
@ -563,6 +568,7 @@
if (!this.hosting || this.locked) { if (!this.hosting || this.locked) {
return return
} }
this.onMousePos(e) this.onMousePos(e)
this.$client.sendData('mouseup', { key: e.button + 1 }) this.$client.sendData('mouseup', { key: e.button + 1 })
} }

View File

@ -50,7 +50,7 @@ interface Emoji {
category: string category: string
} }
const SHEET_COLUMNS = 57 const SHEET_COLUMNS = 58
const MULTIPLY = 100 / (SHEET_COLUMNS - 1) const MULTIPLY = 100 / (SHEET_COLUMNS - 1)
const css: string[] = [] const css: string[] = []