feat: client interaction
This commit is contained in:
parent
f434022e88
commit
7bb21ea379
|
@ -4,15 +4,15 @@
|
|||
</head>
|
||||
<body>
|
||||
|
||||
<!-- TODO: conversations -->
|
||||
|
||||
<div id="header">
|
||||
<h1>Hester Gomez</h1>
|
||||
<p class="delay">(Luna, <span id="delay-text"></span>)</p>
|
||||
</div>
|
||||
|
||||
<!-- messages from current conversations -->
|
||||
<ul id="messages"></ul>
|
||||
|
||||
<!-- message box displays the next message to send -->
|
||||
<p id="typing-indicator">Hester is typing...</p>
|
||||
|
||||
<div id="textbox">
|
||||
<input id="textbox-input" class="rounded-rectangle" type="text" disabled></input>
|
||||
<button class="rounded-rectangle" onclick="pressSendButton()">send</button>
|
||||
|
|
103
main.js
103
main.js
|
@ -26,8 +26,9 @@ conversation = [
|
|||
{ c: 1, text: ":)"}
|
||||
];
|
||||
|
||||
sentMessages = []
|
||||
let messageIdx = 1;
|
||||
let title = "hester";
|
||||
let title = "Hester Gomez";
|
||||
let pings = 0;
|
||||
|
||||
function getMessageList() {
|
||||
|
@ -41,17 +42,17 @@ function getMessageElement(messageIdx) {
|
|||
}
|
||||
|
||||
class SentMessage {
|
||||
constructor(oneWayLag, idx) {
|
||||
constructor(oneWayLag, idx, onDelivered) {
|
||||
this.oneWayLag = oneWayLag;
|
||||
this.idx = idx;
|
||||
//this.content = conversation[idx].text;
|
||||
this.createdTime = Date.now();
|
||||
this.onDelivered = onDelivered;
|
||||
|
||||
this.updateBarIntervalId = setInterval(() => {
|
||||
let elapsed = Math.abs(Date.now() - this.createdTime) / 1000;
|
||||
let progress = elapsed / this.oneWayLag;
|
||||
|
||||
// divide in half so we measure the round trip
|
||||
// divide in half to measure the round trip
|
||||
progress /= 2;
|
||||
|
||||
this.setProgress(progress);
|
||||
|
@ -77,11 +78,11 @@ class SentMessage {
|
|||
this.updateStatus("delivered");
|
||||
clearInterval(this.updateBarIntervalId);
|
||||
amount = 0;
|
||||
this.onDelivered();
|
||||
}
|
||||
amount = Math.min(amount, 1);
|
||||
let percentage = `${amount * 100}%`;
|
||||
progressBar.style.width = percentage;
|
||||
|
||||
}
|
||||
|
||||
updateStatus(newStatus) {
|
||||
|
@ -95,23 +96,17 @@ function updateTextBox(message) {
|
|||
document.getElementById("textbox-input").value = message;
|
||||
}
|
||||
|
||||
// show messages up to index
|
||||
function showMessages(idx) {
|
||||
|
||||
let messageList = getMessageList();
|
||||
|
||||
// TODO: rebuilding the DOM here clears this status of sent messages. instead of
|
||||
// rebuilding it completely, append a new message onto the end of the inner html.
|
||||
// TODO: is this also the juncture to clear the status of previous messages?
|
||||
|
||||
// clear current messages
|
||||
messageList.innerHTML = "";
|
||||
|
||||
// inject messages into ul
|
||||
for (let i = 0; i < idx; i++) {
|
||||
let message = conversation[i];
|
||||
messageList.innerHTML += getMessageHtml(message.text, isMessageOurs(message));
|
||||
function setTypingIndicator(isTyping) {
|
||||
document.getElementById("typing-indicator").innerHTML = isTyping
|
||||
? "Hester is typing..."
|
||||
: "";
|
||||
}
|
||||
|
||||
// add the message at the index to the displayed messages
|
||||
function addMessage(idx) {
|
||||
let message = conversation[idx];
|
||||
let messageHtml = getMessageHtml(message.text, isMessageOurs(message));
|
||||
getMessageList().innerHTML += messageHtml;
|
||||
}
|
||||
|
||||
function getMessageHtml(text, isOurs) {
|
||||
|
@ -187,29 +182,45 @@ function getResponses(idx) {
|
|||
}
|
||||
|
||||
function updateChat(messageIdx) {
|
||||
showMessages(messageIdx);
|
||||
addMessage(messageIdx-1);
|
||||
updatePreviewText(messageIdx);
|
||||
updatePings();
|
||||
}
|
||||
|
||||
function getRandomDelay(min, max) {
|
||||
const range = max - min;
|
||||
return min + Math.random() * range;
|
||||
}
|
||||
|
||||
function waitForIncomingMessages() {
|
||||
// we don't want messages to arrive all at once if there are multiple messages,
|
||||
// so we need to add a small delay to consecutive messages and wait for them one by one
|
||||
let smallDelay = 2;
|
||||
let smallDelay = getRandomDelay(2, 10);
|
||||
let responses = getResponses(messageIdx);
|
||||
let lightLag = getLightLag();
|
||||
|
||||
setTimeout(() => {
|
||||
setTypingIndicator(true);
|
||||
|
||||
for (let i = 0; i < responses.length; i++) {
|
||||
let delaySeconds = lightLag + smallDelay * i;
|
||||
|
||||
const stopTyping = i == responses.length - 1;
|
||||
|
||||
setTimeout(() => {
|
||||
messageIdx++;
|
||||
pings++;
|
||||
|
||||
// update the chat with their message
|
||||
updateChat(messageIdx);
|
||||
|
||||
if (stopTyping) {
|
||||
setTypingIndicator(false);
|
||||
}
|
||||
|
||||
}, delaySeconds * 1000);
|
||||
}
|
||||
},getRandomDelay(1, 3));
|
||||
}
|
||||
|
||||
function updatePreviewText(messageIdx) {
|
||||
|
@ -226,24 +237,37 @@ function sendOurMessage() {
|
|||
// before advancing the conversation
|
||||
let oneWayLag = getLightLag();
|
||||
let currentMessage = conversation[messageIdx];
|
||||
let sentMessage = new SentMessage(oneWayLag, messageIdx);
|
||||
console.log(sentMessage);
|
||||
let nextMessage = conversation[messageIdx + 1];
|
||||
|
||||
// message.send()
|
||||
// when we send the message, we want to start an interval that updates the progress animation
|
||||
// message.setProgress() should be a private method that updates the appropriate element
|
||||
let sentMessage = new SentMessage(oneWayLag, messageIdx, () => {
|
||||
|
||||
// if the next message is ours we don't need to wait for anything
|
||||
if (isMessageOurs(nextMessage))
|
||||
return;
|
||||
|
||||
// wait for them to read the message
|
||||
setTimeout(() => {
|
||||
// set the message status to read
|
||||
sentMessage.updateStatus("read");
|
||||
|
||||
// hide the status of previous messages we first need to have references to all of them
|
||||
// when creating messages we need to add these too an array
|
||||
for (let i = 0; i < sentMessages.length; i++) {
|
||||
let message = sentMessages[i];
|
||||
if (message != sentMessage) {
|
||||
message.updateStatus("");
|
||||
}
|
||||
}
|
||||
|
||||
waitForIncomingMessages();
|
||||
}, getRandomDelay(5, 30) * 1000);
|
||||
});
|
||||
sentMessages.push(sentMessage);
|
||||
|
||||
// advance conversation with our next message
|
||||
messageIdx++;
|
||||
nextMessage = conversation[messageIdx];
|
||||
|
||||
// if the next message is not ours, we need to wait for it: set off a thread that
|
||||
// will update the message index and the displayed messages in a few seconds
|
||||
// we are still waiting to receive messages so pressing the button oughtn't do anything
|
||||
if (!isMessageOurs(nextMessage)) {
|
||||
waitForIncomingMessages();
|
||||
}
|
||||
|
||||
// update displayed messages
|
||||
updateChat(messageIdx);
|
||||
}
|
||||
|
||||
|
@ -273,7 +297,12 @@ function startLightLagUpdateLoop() {
|
|||
}
|
||||
|
||||
function init() {
|
||||
showMessages(messageIdx);
|
||||
setTimeout(() => {
|
||||
addMessage(0);
|
||||
updatePings();
|
||||
setTypingIndicator(false);
|
||||
}, 400);
|
||||
|
||||
// load the first message into the text box
|
||||
updateTextBox(conversation[messageIdx].text);
|
||||
pings = 1;
|
||||
|
|
57
styles.css
57
styles.css
|
@ -2,7 +2,17 @@ html {
|
|||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
body {
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
#page {
|
||||
max-width: 600px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin-left: 0.5em;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
|
@ -36,7 +46,7 @@ h1 {
|
|||
}
|
||||
|
||||
ul {
|
||||
margin-bottom: 1.5em;
|
||||
margin: 1em;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
@ -45,18 +55,31 @@ li {
|
|||
height: 2.5em;
|
||||
width: 100%;
|
||||
|
||||
margin-top: 1.5em;
|
||||
margin-bottom: 1.5em;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
|
||||
#textbox {
|
||||
margin-top: 2em;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
|
||||
#typing-indicator {
|
||||
margin: 0;
|
||||
margin-left: 1em;
|
||||
margin-bottom: 0.5em;
|
||||
|
||||
position: absolute;
|
||||
bottom: 3em;
|
||||
}
|
||||
|
||||
#textbox input {
|
||||
margin: 0.5em;
|
||||
margin-left: 0;
|
||||
left: 1em;
|
||||
|
||||
width: 85%;
|
||||
font-size: 1em;
|
||||
|
@ -71,16 +94,6 @@ button {
|
|||
font-size: 1em;
|
||||
}
|
||||
|
||||
/*
|
||||
.loader-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100vh;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
.progress-bar {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
@ -101,9 +114,6 @@ button {
|
|||
width: 0;
|
||||
height: 100%;
|
||||
background-color: #ff5c35;
|
||||
/*
|
||||
animation: fill 4s infinite;
|
||||
*/
|
||||
}
|
||||
|
||||
.message-status {
|
||||
|
@ -113,14 +123,3 @@ button {
|
|||
right: 1em;
|
||||
font-size: .8em;
|
||||
}
|
||||
|
||||
/*
|
||||
@keyframes fill {
|
||||
0% {
|
||||
width: 0;
|
||||
}
|
||||
100% {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue