Display user avatars instead of talking indicators when possible

This commit is contained in:
Jonas Herzig 2018-09-24 15:36:37 +02:00
parent 2b7f7c1625
commit d7b03d2192
4 changed files with 89 additions and 3 deletions

View file

@ -160,6 +160,17 @@
<input type="button" data-bind="value: pttKeyDisplay, click: recordPttKey">
</td>
</tr>
<tr>
<td>Show Avatars</td>
<td>
<select data-bind='value: showAvatars'>
<option value="always">Always</option>
<option value="own_channel">Same Channel</option>
<option value="linked_channel">Linked Channels</option>
<option value="minimal_only">Minimal View</option>
<option value="never">Never</option>
</td>
</tr>
</table>
<div class="dialog-footer">
<input class="dialog-close" type="button" data-bind="click: $root.closeSettings" value="Cancel">
@ -304,6 +315,15 @@
<div data-bind="if: comment">
<div class="user-comment tooltip" data-bind="html: comment"></div>
</div>
<!-- ko if: show_avatar() -->
<img class="user-avatar" alt="avatar"
data-bind="attr: { src: texture },
css: { 'user-avatar-talk-off': talking() == 'off',
'user-avatar-talk-on': talking() == 'on',
'user-avatar-talk-whisper': talking() == 'whisper',
'user-avatar-talk-shout': talking() == 'shout' }">
<!-- /ko -->
<!-- ko ifnot: show_avatar() -->
<img class="user-talk user-talk-off" data-bind="visible: talking() == 'off'"
alt="talk off" src="/svg/talking_off.svg">
<img class="user-talk user-talk-on" data-bind="visible: talking() == 'on'"

View file

@ -78,6 +78,7 @@ class SettingsDialog {
this.vadLevel = ko.observable(settings.vadLevel)
this.testVadLevel = ko.observable(0)
this.testVadActive = ko.observable(false)
this.showAvatars = ko.observable(settings.showAvatars())
this._setupTestVad()
this.vadLevel.subscribe(() => this._setupTestVad())
@ -98,6 +99,7 @@ class SettingsDialog {
settings.voiceMode = this.voiceMode()
settings.pttKey = this.pttKey()
settings.vadLevel = this.vadLevel()
settings.showAvatars(this.showAvatars())
}
end () {
@ -133,6 +135,7 @@ class Settings {
this.pttKey = load('pttKey') || 'ctrl + shift'
this.vadLevel = load('vadLevel') || 0.3
this.toolbarVertical = load('toolbarVertical') || false
this.showAvatars = ko.observable(load('showAvatars') || 'always')
}
save () {
@ -141,6 +144,7 @@ class Settings {
save('pttKey', this.pttKey)
save('vadLevel', this.vadLevel)
save('toolbarVertical', this.toolbarVertical)
save('showAvatars', this.showAvatars())
}
}
@ -295,6 +299,8 @@ class GlobalBindings {
suppress: 'suppress',
selfMute: 'selfMute',
selfDeaf: 'selfDeaf',
texture: 'rawTexture',
textureHash: 'textureHash',
comment: 'comment'
}
var ui = user.__ui = {
@ -302,6 +308,40 @@ class GlobalBindings {
talking: ko.observable('off'),
channel: ko.observable()
}
ui.texture = ko.pureComputed(() => {
let raw = ui.rawTexture()
if (!raw || raw.offset >= raw.limit) return null
return 'data:image/*;base64,' + raw.toBase64()
})
ui.show_avatar = () => {
let setting = this.settings.showAvatars()
switch (setting) {
case 'always':
break
case 'own_channel':
if (this.thisUser().channel() !== ui.channel()) return false
break
case 'linked_channel':
if (!ui.channel().linked()) return false
break
case 'minimal_only':
if (!this.minimalView()) return false
if (this.thisUser().channel() !== ui.channel()) return false
break
case 'never':
default: return false
}
if (!ui.texture()) {
if (ui.textureHash()) {
// The user has an avatar set but it's of sufficient size to not be
// included by default, so we need to fetch it explicitly now.
// mumble-client should make sure we only send one request per hash
user.requestTexture()
}
return false
}
return true
}
Object.entries(simpleProperties).forEach(key => {
ui[key[1]] = ko.observable(user[key[0]])
})
@ -327,6 +367,11 @@ class GlobalBindings {
ui.channel().users.sort(compareUsers)
this._updateLinks()
}
if (properties.textureHash !== undefined) {
// Invalidate avatar texture when its hash has changed
// If the avatar is still visible, this will trigger a fetch of the new one.
ui.rawTexture(null)
}
}).on('remove', () => {
if (ui.channel()) {
ui.channel().users.remove(ui)

View file

@ -48,7 +48,7 @@
"libsamplerate.js": "^1.0.0",
"mumble-client-codecs-browser": "^1.1.1",
"mumble-client-websocket": "^1.0.0",
"mumble-client": "^1.1.1",
"mumble-client": "^1.2.0",
"web-audio-buffer-queue": "^1.0.0"
}
}

View file

@ -17,6 +17,9 @@ $chat-channel-color: orange !default
$chat-user-color: green !default
$chat-input-color: $font-color !default
$mic-volume-border-color: $black !default
$talk-outline-color: green !default
$whisper-outline-color: purple !default
$shout-outline-color: cyan !default
$toolbar-hover-bg-color: $lightgray !default
$toolbar-hover-border-color: $gray !default
@ -144,9 +147,27 @@ html, body {
.user {
margin-left: 9px;
}
.user-talk {
.user-avatar, .user-talk {
vertical-align: middle;
}
@mixin drop-shadow-4x($size, $blur, $color) {
filter: drop-shadow(#{+$size} #{+$size} $blur $color)
drop-shadow(#{+$size} #{-$size} $blur $color)
drop-shadow(#{-$size} #{+$size} $blur $color)
drop-shadow(#{-$size} #{-$size} $blur $color);
}
@mixin user-avatar-drop-shadow($color) {
@include drop-shadow-4x(1px, 1px, $color);
}
.user-avatar-talk-on {
@include user-avatar-drop-shadow($talk-outline-color);
}
.user-avatar-talk-whisper {
@include user-avatar-drop-shadow($whisper-outline-color);
}
.user-avatar-talk-shout {
@include user-avatar-drop-shadow($shout-outline-color);
}
.user-status, .channel-status {
float: right;
}
@ -339,7 +360,7 @@ form {
}
.settings-dialog {
width: 300px;
height: 156px;
height: 200px;
top: calc(50% - 100px);
left: calc(50% - 150px);
}