Merge pull request #241 from jeyemwey/jv-119-remove-avatars

Remove Chat Avatars
Thanks for the cleanup! Looks great.
This commit is contained in:
gingervitis 2020-10-14 11:16:58 -07:00 committed by GitHub
commit 57f2e4b567
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 19 additions and 98 deletions

View File

@ -36,7 +36,6 @@ func createTable(db *sql.DB) {
"id" string NOT NULL PRIMARY KEY,
"author" TEXT,
"body" TEXT,
"image" TEXT,
"messageType" TEXT,
"visible" INTEGER,
"timestamp" DATE
@ -51,11 +50,11 @@ func createTable(db *sql.DB) {
func addMessage(message models.ChatMessage) {
tx, err := _db.Begin()
stmt, err := tx.Prepare("INSERT INTO messages(id, author, body, image, messageType, visible, timestamp) values(?, ?, ?, ?, ?, ?, ?)")
stmt, err := tx.Prepare("INSERT INTO messages(id, author, body, messageType, visible, timestamp) values(?, ?, ?, ?, ?, ?)")
if err != nil {
log.Fatal(err)
}
_, err = stmt.Exec(message.ID, message.Author, message.Body, message.Image, message.MessageType, 1, message.Timestamp)
_, err = stmt.Exec(message.ID, message.Author, message.Body, message.MessageType, 1, message.Timestamp)
if err != nil {
log.Fatal(err)
}
@ -78,12 +77,11 @@ func getChatHistory() []models.ChatMessage {
var id string
var author string
var body string
var image string
var messageType string
var visible int
var timestamp time.Time
err = rows.Scan(&id, &author, &body, &image, &messageType, &visible, &timestamp)
err = rows.Scan(&id, &author, &body, &messageType, &visible, &timestamp)
if err != nil {
log.Fatal(err)
}
@ -92,7 +90,6 @@ func getChatHistory() []models.ChatMessage {
message.ID = id
message.Author = author
message.Body = body
message.Image = image
message.MessageType = messageType
message.Visible = visible == 1
message.Timestamp = timestamp

View File

@ -140,7 +140,7 @@ func (s *server) sendWelcomeMessageToClient(c *Client) {
time.Sleep(7 * time.Second)
initialChatMessageText := fmt.Sprintf("Welcome to %s! %s", config.Config.InstanceDetails.Title, config.Config.InstanceDetails.Summary)
initialMessage := models.ChatMessage{"owncast-server", config.Config.InstanceDetails.Name, initialChatMessageText, config.Config.InstanceDetails.Logo.Small, "initial-message-1", "CHAT", true, time.Now()}
initialMessage := models.ChatMessage{"owncast-server", config.Config.InstanceDetails.Name, initialChatMessageText, "initial-message-1", "CHAT", true, time.Now()}
c.Write(initialMessage)
}()

View File

@ -18,7 +18,6 @@ type ChatMessage struct {
Author string `json:"author"`
Body string `json:"body"`
Image string `json:"image"`
ID string `json:"id"`
MessageType string `json:"type"`
Visible bool `json:"visible"`

View File

@ -311,9 +311,6 @@ paths:
body:
type: string
description: Escaped HTML of the chat message content.
image:
type: string
description: URL of the chat user avatar.
id:
type: string
description: Unique ID of the chat message.

View File

@ -4,8 +4,8 @@ const html = htm.bind(h);
import Chat from './components/chat/chat.js';
import Websocket from './utils/websocket.js';
import { getLocalStorage, generateAvatar, generateUsername } from './utils/helpers.js';
import { KEY_USERNAME, KEY_AVATAR } from './utils/constants.js';
import { getLocalStorage, generateUsername } from './utils/helpers.js';
import { KEY_USERNAME } from './utils/constants.js';
export default class StandaloneChat extends Component {
constructor(props, context) {
@ -15,28 +15,25 @@ export default class StandaloneChat extends Component {
websocket: new Websocket(),
chatEnabled: true, // always true for standalone chat
username: getLocalStorage(KEY_USERNAME) || generateUsername(),
userAvatarImage: getLocalStorage(KEY_AVATAR) || generateAvatar(`${this.username}${Date.now()}`),
};
this.websocket = null;
this.handleUsernameChange = this.handleUsernameChange.bind(this);
}
handleUsernameChange(newName, newAvatar) {
handleUsernameChange(newName) {
this.setState({
username: newName,
userAvatarImage: newAvatar,
});
}
render(props, state) {
const { username, userAvatarImage, websocket } = state;
const { username, websocket } = state;
return (
html`
<${Chat}
websocket=${websocket}
username=${username}
userAvatarImage=${userAvatarImage}
messagesOnly
/>
`

View File

@ -14,7 +14,6 @@ import {
classNames,
clearLocalStorage,
debounce,
generateAvatar,
generateUsername,
getLocalStorage,
pluralize,
@ -22,7 +21,6 @@ import {
} from './utils/helpers.js';
import {
HEIGHT_SHORT_WIDE,
KEY_AVATAR,
KEY_CHAT_DISPLAYED,
KEY_USERNAME,
MESSAGE_OFFLINE,
@ -50,9 +48,6 @@ export default class App extends Component {
displayChat: chatStorage === null ? true : chatStorage,
chatInputEnabled: false, // chat input box state
username: getLocalStorage(KEY_USERNAME) || generateUsername(),
userAvatarImage:
getLocalStorage(KEY_AVATAR) ||
generateAvatar(`${this.username}${Date.now()}`),
configData: {},
extraPageContent: '',
@ -282,10 +277,9 @@ export default class App extends Component {
}
handleUsernameChange(newName, newAvatar) {
handleUsernameChange(newName) {
this.setState({
username: newName,
userAvatarImage: newAvatar,
});
}
@ -330,7 +324,6 @@ export default class App extends Component {
playerActive,
streamOnline,
streamStatusMessage,
userAvatarImage,
username,
viewerCount,
websocket,
@ -415,7 +408,6 @@ export default class App extends Component {
>
<${UsernameForm}
username=${username}
userAvatarImage=${userAvatarImage}
handleUsernameChange=${this.handleUsernameChange}
/>
<button
@ -499,7 +491,6 @@ export default class App extends Component {
<${Chat}
websocket=${websocket}
username=${username}
userAvatarImage=${userAvatarImage}
chatInputEnabled=${chatInputEnabled}
/>
</div>

View File

@ -43,14 +43,14 @@ export default class Chat extends Component {
componentDidUpdate(prevProps, prevState) {
const { username: prevName } = prevProps;
const { username, userAvatarImage } = this.props;
const { username } = this.props;
const { messages: prevMessages } = prevState;
const { messages } = this.state;
// if username updated, send a message
if (prevName !== username) {
this.sendUsernameChange(prevName, username, userAvatarImage);
this.sendUsernameChange(prevName, username);
}
// scroll to bottom of messages list when new ones come in
if (messages.length > prevMessages.length) {
@ -94,12 +94,11 @@ export default class Chat extends Component {
});
}
sendUsernameChange(oldName, newName, image) {
sendUsernameChange(oldName, newName) {
const nameChange = {
type: SOCKET_MESSAGE_TYPES.NAME_CHANGE,
oldName,
newName,
image,
};
this.websocket.send(nameChange);
}
@ -145,11 +144,10 @@ export default class Chat extends Component {
if (!content) {
return;
}
const { username, userAvatarImage } = this.props;
const { username } = this.props;
const message = {
body: content,
author: username,
image: userAvatarImage,
type: SOCKET_MESSAGE_TYPES.CHAT,
};
this.websocket.send(message);

View File

@ -3,7 +3,6 @@ import htm from '/js/web_modules/htm.js';
const html = htm.bind(h);
import { messageBubbleColorForString } from '../../utils/user-colors.js';
import { generateAvatar } from '../../utils/helpers.js';
import { convertToText } from '../../utils/chat.js';
import { SOCKET_MESSAGE_TYPES } from '../../utils/websocket.js';
@ -12,23 +11,15 @@ export default class Message extends Component {
const { message, username } = props;
const { type } = message;
if (type === SOCKET_MESSAGE_TYPES.CHAT) {
const { image, author, body, timestamp } = message;
const { author, body, timestamp } = message;
const formattedMessage = formatMessageText(body, username);
const avatar = image || generateAvatar(author);
const formattedTimestamp = formatTimestamp(timestamp);
const authorColor = messageBubbleColorForString(author);
const avatarBgColor = { backgroundColor: authorColor };
const authorTextColor = { color: authorColor };
return (
html`
<div class="message flex flex-row items-start p-3">
<div
class="message-avatar rounded-full flex items-center justify-center mr-3"
style=${avatarBgColor}
>
<img src=${avatar} class="p-1" />
</div>
<div class="message-content text-sm break-words w-full">
<div class="message-author text-white font-bold" style=${authorTextColor}>
${author}
@ -44,17 +35,11 @@ export default class Message extends Component {
</div>
`);
} else if (type === SOCKET_MESSAGE_TYPES.NAME_CHANGE) {
const { oldName, newName, image } = message;
const { oldName, newName } = message;
return (
html`
<div class="message message-name-change flex items-center justify-start p-3">
<div class="message-content flex flex-row items-center justify-center text-sm w-full">
<div
class="message-avatar rounded-full mr-3 bg-gray-900"
>
<img class="mr-2 p-1" src=${image} />
</div>
<div class="text-white text-center opacity-50">
<span class="font-bold">${oldName}</span> is now known as <span class="font-bold">${newName}</span>.
</div>

View File

@ -2,8 +2,8 @@ import { h, Component, createRef } from '/js/web_modules/preact.js';
import htm from '/js/web_modules/htm.js';
const html = htm.bind(h);
import { generateAvatar, setLocalStorage } from '../../utils/helpers.js';
import { KEY_USERNAME, KEY_AVATAR } from '../../utils/constants.js';
import { setLocalStorage } from '../../utils/helpers.js';
import { KEY_USERNAME } from '../../utils/constants.js';
export default class UsernameForm extends Component {
constructor(props, context) {
@ -47,11 +47,9 @@ export default class UsernameForm extends Component {
let newName = this.textInput.current.value;
newName = newName.trim();
if (newName !== '' && newName !== curName) {
const newAvatar = generateAvatar(`${newName}${Date.now()}`);
setLocalStorage(KEY_USERNAME, newName);
setLocalStorage(KEY_AVATAR, newAvatar);
if (handleUsernameChange) {
handleUsernameChange(newName, newAvatar);
handleUsernameChange(newName);
}
this.handleHideForm();
}
@ -59,7 +57,7 @@ export default class UsernameForm extends Component {
}
render(props, state) {
const { username, userAvatarImage } = props;
const { username } = props;
const { displayForm } = state;
const narrowSpace = document.body.clientWidth < 640;
@ -77,12 +75,6 @@ export default class UsernameForm extends Component {
html`
<div id="user-info">
<div id="user-info-display" style=${styles.info} title="Click to update user name" class="flex flex-row justify-end items-center cursor-pointer py-2 px-4 overflow-hidden w-full opacity-1 transition-opacity duration-200 hover:opacity-75" onClick=${this.handleDisplayForm}>
<img
src=${userAvatarImage}
alt=""
id="username-avatar"
class="rounded-full bg-black bg-opacity-50 border border-solid border-gray-700 mr-2 h-8 w-8"
/>
<span id="username-display" class="text-indigo-600 text-xs font-semibold truncate overflow-hidden whitespace-no-wrap">${username}</span>
</div>

View File

@ -22,7 +22,6 @@ export const PLAYER_VOLUME = 'owncast_volume';
export const KEY_USERNAME = 'owncast_username';
export const KEY_AVATAR = 'owncast_avatar';
export const KEY_CHAT_DISPLAYED = 'owncast_chat';
export const KEY_CHAT_FIRST_MESSAGE_SENT = 'owncast_first_message_sent';
export const CHAT_INITIAL_PLACEHOLDER_TEXT = 'Type here to chat, no account necessary.';

View File

@ -92,16 +92,6 @@ export function getOrientation(forTouch = false) {
}
}
// generate random avatar from https://robohash.org
export function generateAvatar(hash) {
const avatarSource = 'https://robohash.org/';
const optionSize = '?size=80x80';
const optionSet = '&set=set2';
const optionBg = ''; // or &bgset=bg1 or bg2
return avatarSource + hash + optionSize + optionSet + optionBg;
}
export function generateUsername() {
return `User ${(Math.floor(Math.random() * 42) + 1)}`;
}

View File

@ -115,22 +115,6 @@
scrollbar-color: var(--category-button-color) black;
}
/******************************/
.message-avatar {
height: 3.0em;
width: 3.0em;
}
.message-avatar img {
max-width: unset;
height: 3.0em;
width: 3.0em;
padding: 5px;
}
/* MESSAGE TEXT HTML */
/* MESSAGE TEXT HTML */
/* MESSAGE TEXT HTML */

View File

@ -28,14 +28,6 @@ The styles in this file mostly ovveride those coming from chat.css
#messages-only .message-content {
text-shadow: 1px 1px 0px rgba(0,0,0,0.25);
}
#messages-only .message-avatar {
display: none;
box-shadow: 0px 0px 3px 0px rgba(0,0,0,0.25);
}
#messages-only .message-avatar img {
height: 1.8em;
width: 1.8em;
}
#messages-only .message {
padding: .5em;
}