presence, experiment overrides, design improvements

This commit is contained in:
hippoz 2021-06-10 18:42:53 +03:00
parent 2f220e511e
commit 033d0e4da1
No known key found for this signature in database
GPG key ID: 7C52899193467641
15 changed files with 99 additions and 44 deletions

View file

@ -10,6 +10,8 @@ const opcodes = {
2: { name: "YOO_ACK", data: "JSON" }, 2: { name: "YOO_ACK", data: "JSON" },
3: { name: "ACTION_CREATE_MESSAGE", data: "JSON" }, 3: { name: "ACTION_CREATE_MESSAGE", data: "JSON" },
4: { name: "EVENT_CREATE_MESSAGE", data: "JSON" }, 4: { name: "EVENT_CREATE_MESSAGE", data: "JSON" },
5: { name: "ACTION_UPDATE_STATUS", data: "JSON" },
6: { name: "EVENT_CHANNEL_MEMBERS", data: "JSON" },
21: { name: "ACTION_VOICE_REQUEST_SESSION", data: "JSON" }, 21: { name: "ACTION_VOICE_REQUEST_SESSION", data: "JSON" },
22: { name: "EVENT_VOICE_ASSIGN_SERVER", data: "JSON" }, 22: { name: "EVENT_VOICE_ASSIGN_SERVER", data: "JSON" },
23: { name: "ACTION_VOICE_CONNECTION_REQUEST", data: "JSON" }, 23: { name: "ACTION_VOICE_CONNECTION_REQUEST", data: "JSON" },
@ -84,6 +86,20 @@ GatewayConnection.prototype.connect = function(token) {
this.ws.send(this.packet("YOO", { token })); this.ws.send(this.packet("YOO", { token }));
break; break;
} }
case "EVENT_CHANNEL_MEMBERS": {
this.presence = {
...this.presence,
...packet.data
}
for (const [userId, user] of Object.entries(this.presence)) {
if (user.status <= 0)
delete this.presence[userId];
}
this.fire("presenceUpdate", this.presence);
break;
}
case "YOO_ACK": { case "YOO_ACK": {
// Server accepted connection // Server accepted connection
logGateway("Got YOO_ACK", packet.data); logGateway("Got YOO_ACK", packet.data);

View file

@ -1,6 +1,9 @@
import GatewayConnection from './GatewayConnection'; import GatewayConnection from './GatewayConnection';
import config from '../../Config'; import config from '../../Config';
import store from '../../Global/store'; import store from '../../Global/store';
import logger from '../../Util/Logger';
const { warn } = logger(["Experiments"]);
const globalGatewayConnection = new GatewayConnection(config.gatewayUrl); const globalGatewayConnection = new GatewayConnection(config.gatewayUrl);
@ -8,13 +11,29 @@ globalGatewayConnection.onopen = (sessionData) => {
store.dispatch({ type: 'gateway/connectionstatus', gateway: { isConnected: true } }); store.dispatch({ type: 'gateway/connectionstatus', gateway: { isConnected: true } });
store.dispatch({ type: 'authenticator/updatelocaluserobject', user: sessionData.user }); store.dispatch({ type: 'authenticator/updatelocaluserobject', user: sessionData.user });
store.dispatch({ type: 'channels/updatechannellist', channels: sessionData.channels }); store.dispatch({ type: 'channels/updatechannellist', channels: sessionData.channels });
store.dispatch({ type: 'application/updateexperiments', experiments: sessionData.__global_experiments || [] });
if (localStorage.getItem("enableExperimentOverrides")) {
warn("Experiment overrides are enabled");
const experimentModifiers = JSON.parse(localStorage.getItem("experimentOverrides"));
const experiments = {
...sessionData.__global_experiments || {},
...experimentModifiers || {}
};
store.dispatch({ type: 'application/updateexperiments', experiments });
store.dispatch({ type: 'application/updatebannertext', text: "Experiment overrides are enabled! Things could go haywire!" });
} else {
store.dispatch({ type: 'application/updateexperiments', experiments: sessionData.__global_experiments || {} });
}
}; };
globalGatewayConnection.onmessage = (message) => { globalGatewayConnection.onmessage = (message) => {
store.dispatch({ type: 'messagestore/addmessage', message }); store.dispatch({ type: 'messagestore/addmessage', message });
}; };
globalGatewayConnection.presenceUpdate = (presence) => {
store.dispatch({ type: 'channels/updatepresence', clientListEvent: presence });
};
globalGatewayConnection.onclose = function() { globalGatewayConnection.onclose = function() {
store.dispatch({ type: 'authenticator/updatelocaluserobject', user: undefined }); store.dispatch({ type: 'authenticator/updatelocaluserobject', user: undefined });
store.dispatch({ type: 'gateway/connectionstatus', gateway: { isConnected: false } }); store.dispatch({ type: 'gateway/connectionstatus', gateway: { isConnected: false } });

View file

@ -59,7 +59,7 @@ export default function Login() {
<br /> <br />
<input type="password" name="password" className="text-input" onChange={ ({ target }) => setPasswordInput(target.value) } /> <input type="password" name="password" className="text-input" onChange={ ({ target }) => setPasswordInput(target.value) } />
<br /> <br />
<button id="login-submit" className="button" onClick={ handleLoginContinueButton }>Continue</button> <button id="login-submit" className="button-pressed" onClick={ handleLoginContinueButton }>Continue</button>
<Notification text={ info } /> <Notification text={ info } />
</div> </div>
); );

View file

@ -1,26 +1,14 @@
import UserProfileButton from '../Users/UserButton'; import UserProfileButton from '../Users/UserButton';
import { connect } from 'react-redux'; function ChannelUserList({ presence }) {
console.log(presence);
function ChannelUserList({ channelPresenceClientList }) {
const users = [
{ username: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", _id: "a" },
{ username: "FDGFEGSDFHRFGHNERTYBNRNBTYJMNUM", _id: "b" }
];
return ( return (
<div className="main-card sidebar"> <div className="main-card sidebar">
<div className="channel-list"> <div className="channel-list">
{ users.map((user) => <UserProfileButton key={ user._id } user={ user } />) } { Object.keys(presence).map((userId) => <UserProfileButton key={ userId } user={ presence[userId] } />) }
</div> </div>
</div> </div>
) )
} }
const stateToProps = (state) => { export default ChannelUserList;
return {
channelPresenceClientList: state?.channelPresenceClientList
};
};
export default connect(stateToProps)(ChannelUserList);

View file

@ -9,7 +9,7 @@ import { connect, useDispatch } from 'react-redux';
import { useState, useRef, useEffect } from 'react'; import { useState, useRef, useEffect } from 'react';
const ChannelView = ({ channels, messages, channel, selectedChannelId, experiments }) => { const ChannelView = ({ channels, messages, channel, selectedChannelId, experiments, channelPresenceClientList, gradientBannerNotificationText }) => {
const { id } = useParams(); const { id } = useParams();
const [ textInput, setTextInput ] = useState(''); const [ textInput, setTextInput ] = useState('');
@ -60,6 +60,10 @@ const ChannelView = ({ channels, messages, channel, selectedChannelId, experimen
</button>} </button>}
</div> </div>
{(gradientBannerNotificationText !== undefined) && <div className="gradient-banner-card">
{ gradientBannerNotificationText }
</div>}
<div className="main-card row-flex-card hidden-overflow"> <div className="main-card row-flex-card hidden-overflow">
<div className="col-flex-card channel-message-panel hidden-overflow"> <div className="col-flex-card channel-message-panel hidden-overflow">
<div className="message-list-card"> <div className="message-list-card">
@ -71,7 +75,7 @@ const ChannelView = ({ channels, messages, channel, selectedChannelId, experimen
<input className="text-input message-input" type="text" placeholder="Go on, type something interesting!" ref={ textInputRef } onKeyDown={ handleTextboxKeydown } onChange={ ({ target }) => setTextInput(target.value) }></input> <input className="text-input message-input" type="text" placeholder="Go on, type something interesting!" ref={ textInputRef } onKeyDown={ handleTextboxKeydown } onChange={ ({ target }) => setTextInput(target.value) }></input>
</div> </div>
</div> </div>
{ (experiments.userListTest) && <ChannelUserList /> } { (experiments.userListTest) && <ChannelUserList presence={ channelPresenceClientList || [] } /> }
</div> </div>
</div> </div>
) )
@ -100,7 +104,9 @@ const stateToProps = (state, ownProps) => {
channel: state?.channels?.find(x => x._id === channelId), channel: state?.channels?.find(x => x._id === channelId),
messages: state?.messages[channelId] || [], messages: state?.messages[channelId] || [],
selectedChannelId: state?.selectedChannelId, selectedChannelId: state?.selectedChannelId,
experiments: state?.experiments || {} experiments: state?.experiments || {},
channelPresenceClientList: state?.channelPresenceClientList,
gradientBannerNotificationText: state?.gradientBannerNotificationText
}; };
}; };

View file

@ -9,7 +9,7 @@ export default function Root(props) {
return ( return (
<div id="login-message-container"> <div id="login-message-container">
<h1>Welcome back!</h1> <h1>Welcome back!</h1>
<button className="button" onClick={ () => { history.push('/login') } }>Log in</button> <button className="button-pressed" onClick={ () => { history.push('/login') } }>Log in</button>
<button className="button" onClick={ () => { history.push('/create') } }>Create an account</button> <button className="button" onClick={ () => { history.push('/create') } }>Create an account</button>
</div> </div>
); );

View file

@ -1,5 +1,3 @@
import defaultProfile from '../../Content/Images/defaultprofile_256px-256px.png'
// This is a mess pls fix later // This is a mess pls fix later
export default function ProfileLink({ object, size, type, offset=true, children=null }) { export default function ProfileLink({ object, size, type, offset=true, children=null }) {
let picture; let picture;

View file

@ -2,7 +2,7 @@ import UserProfile from './UserProfileLink';
import { useHistory } from 'react-router-dom'; import { useHistory } from 'react-router-dom';
export default function ChannelUserButton({ user }) { export default function ChannelUserButton({ user, subtext }) {
const history = useHistory(); const history = useHistory();
let buttonClasses = 'button button-channel'; let buttonClasses = 'button button-channel';
@ -13,7 +13,7 @@ export default function ChannelUserButton({ user }) {
return ( return (
<button className={ buttonClasses } onClick={ handleClick }> <button className={ buttonClasses } onClick={ handleClick }>
<UserProfile user={ user } size="32" /> <UserProfile subtext={ subtext } user={ user } size="32" />
</button> </button>
); );
} }

View file

@ -1,8 +1,8 @@
import ProfileLink from '../UI/ProfileLink' import ProfileLink from '../UI/ProfileLink'
// TODO: Stop using this component and just use the ProfileLink component // TODO: Stop using this component and just use the ProfileLink component
export default function ChannelProfile({ user, size, offset=false }) { export default function UserProfile({ user, size, subtext }) {
return ( return (
<ProfileLink object={ user } size={ size } type="user" offset={ offset } /> <ProfileLink object={ user } size={ size } type="user" offset={ subtext !== undefined } children={ (subtext) && (<span>{ subtext }</span>) } />
); );
} }

View file

@ -8,6 +8,7 @@ const intitialState = {
gateway: { isConnected: false }, gateway: { isConnected: false },
messages: {}, messages: {},
channelPresenceClientList: {}, channelPresenceClientList: {},
gradientBannerNotificationText: undefined,
selectedChannelId: undefined selectedChannelId: undefined
}; };
@ -57,13 +58,10 @@ const reducer = (state = intitialState, payload) => {
}; };
} }
case 'presence/channel/clientlistupdate': { case 'channels/updatepresence': {
return { return {
...state, ...state,
channelPresenceClientList: { channelPresenceClientList: payload.clientListEvent
...state.channelPresenceClientList || [],
[payload.clientListEvent.channel._id]: payload.clientListEvent.clientList
}
}; };
} }
@ -74,6 +72,13 @@ const reducer = (state = intitialState, payload) => {
} }
} }
case 'application/updatebannertext': {
return {
...state,
gradientBannerNotificationText: payload.text
}
}
default: { default: {
return state; return state;
} }

View file

@ -26,13 +26,13 @@
&-pressed { &-pressed {
@extend .button; @extend .button;
background-color: var(--button-selected-color); background: var(--focus-accent-background);
color: var(--default-text-color); color: var(--default-text-color);
} }
} }
.button:hover:not(.button-pressed) { .button:hover:not(.button-pressed) {
background-color: var(--button-hover-color); background: var(--focus-accent-background-deep);
} }
@media only screen and (max-width: 600px) { @media only screen and (max-width: 600px) {

View file

@ -67,4 +67,15 @@
flex-grow: 10; flex-grow: 10;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
}
.gradient-banner-card {
background: var(--default-user-background);
height: 1.5rem;
padding: 10px;
margin: 10px;
border-radius: 0.3243rem;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
} }

View file

@ -17,7 +17,7 @@
flex-direction: column; flex-direction: column;
overflow: auto; overflow: auto;
overflow-x: hidden; overflow-x: hidden;
min-width: 230px; min-width: 235px;
} }
.channel-list { .channel-list {

View file

@ -24,5 +24,5 @@
.message-content { .message-content {
padding-left: 6px; padding-left: 6px;
text-rendering: "optimizeLegibility"; text-rendering: optimizeLegibility;
} }

View file

@ -1,21 +1,33 @@
:root { :root {
--background-color: #030303; --background-color: hsl(0, 0%, 1%);
--default-text-color: hsl(0, 0%, 79%);
--darker-text-color: hsl(0, 0%, 53%);
--card-accent-color: hsl(0, 0%, 10%);
--card-accent-color-dark: hsl(0, 0%, 5%);
--default-main-card-color: var(--background-color); --default-main-card-color: var(--background-color);
--card-box-shadow-color: 0 1px 0 #1d1a1abe; --card-box-shadow-color: 0 1px 0 #1d1a1abe;
--default-text-color: #cacaca; --focus-accent-background: var(--card-accent-color);
--darker-text-color: #808080; --focus-accent-background-deep: var(--card-accent-color-dark);
--card-accent-color: #212121; --default-user-background: linear-gradient(
--focus-accent-color: hsl(246, 57%, 38%); to bottom right,
--focus-accent-color-deep: hsl(255, 70%, 30%); hsl(275, 55%, 40%),
hsl(300, 55%, 40%),
hsl(325, 55%, 40%)
);
--default-channel-background: linear-gradient(
to bottom right,
hsl(150, 55%, 40%),
hsl(175, 55%, 40%),
hsl(200, 55%, 40%)
);
--channel-top-bar-color-accent: var(--background-color); --channel-top-bar-color-accent: var(--background-color);
--channel-top-bar-color: var(--background-color); --channel-top-bar-color: var(--background-color);
--bar-card-border-bottom: solid 1px #1d1d1d; --bar-card-border-bottom: solid 1px #1d1d1d;
--message-box-color: var(--card-accent-color); --message-box-color: var(--card-accent-color);
--message-box-shadow: #22222273 6px 8px 12px;
--channel-top-bar-border-color: var(--accent-color-dark); --channel-top-bar-border-color: var(--accent-color-dark);
--channel-list-background-color: var(--background-color); --channel-list-background-color: var(--background-color);