From d7b03d219274cecc54d3e6ae33b5ed56e9d50fdf Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Mon, 24 Sep 2018 15:36:37 +0200 Subject: [PATCH] Display user avatars instead of talking indicators when possible --- app/index.html | 20 ++++++++++++++ app/index.js | 45 +++++++++++++++++++++++++++++++ package.json | 2 +- themes/MetroMumbleLight/main.scss | 25 +++++++++++++++-- 4 files changed, 89 insertions(+), 3 deletions(-) diff --git a/app/index.html b/app/index.html index 1ed87e3..0d85f8c 100644 --- a/app/index.html +++ b/app/index.html @@ -160,6 +160,17 @@ + + Show Avatars + + @@ -304,6 +315,15 @@
+ + avatar + + talk off 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) diff --git a/package.json b/package.json index 59fec02..0b3bebf 100644 --- a/package.json +++ b/package.json @@ -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" } } diff --git a/themes/MetroMumbleLight/main.scss b/themes/MetroMumbleLight/main.scss index f29bbbc..bc2863b 100644 --- a/themes/MetroMumbleLight/main.scss +++ b/themes/MetroMumbleLight/main.scss @@ -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); }