Optimalization and code refactoring
-- optimized chat date rendering -- improved chat card last message rendering
This commit is contained in:
parent
b97d3ebaeb
commit
edf0334ef2
23
css/main.css
23
css/main.css
@ -148,7 +148,7 @@ button:not(:disabled),
|
|||||||
}
|
}
|
||||||
|
|
||||||
.button {
|
.button {
|
||||||
background-color: rgba(var(--text-color), 0.06);
|
background-color: rgba(var(--text-color), 0.1);
|
||||||
}
|
}
|
||||||
.button--primary, .button--danger {
|
.button--primary, .button--danger {
|
||||||
color: rgba(var(--background-color), 1) !important;
|
color: rgba(var(--background-color), 1) !important;
|
||||||
@ -1420,7 +1420,6 @@ sm-button[variant=primary] {
|
|||||||
#contacts {
|
#contacts {
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
height: 100%;
|
|
||||||
}
|
}
|
||||||
#contacts .scrolling-wrapper {
|
#contacts .scrolling-wrapper {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@ -1463,6 +1462,7 @@ sm-button[variant=primary] {
|
|||||||
#contacts,
|
#contacts,
|
||||||
#mails,
|
#mails,
|
||||||
#settings_page {
|
#settings_page {
|
||||||
|
height: 100%;
|
||||||
overflow-y: hidden;
|
overflow-y: hidden;
|
||||||
}
|
}
|
||||||
#contacts .header,
|
#contacts .header,
|
||||||
@ -1860,7 +1860,6 @@ sm-button[variant=primary] {
|
|||||||
}
|
}
|
||||||
#chat_footer sm-textarea {
|
#chat_footer sm-textarea {
|
||||||
--padding-right: 3rem;
|
--padding-right: 3rem;
|
||||||
--border-radius: 0.5rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#emoji_toggle {
|
#emoji_toggle {
|
||||||
@ -1893,6 +1892,8 @@ sm-button[variant=primary] {
|
|||||||
|
|
||||||
#type_message {
|
#type_message {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
--border-radius: 0.5rem;
|
||||||
|
--background: rgba(var(--text-color), 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.big-emoji {
|
.big-emoji {
|
||||||
@ -2102,18 +2103,12 @@ sm-button[variant=primary] {
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
#settings_page section {
|
#settings_page section {
|
||||||
display: grid;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
padding: 1rem 1.5rem;
|
padding: 1rem 1.5rem;
|
||||||
width: min(60ch, 100%);
|
width: min(60ch, 100%);
|
||||||
}
|
}
|
||||||
#settings_page section sm-button {
|
|
||||||
margin-top: 0.5rem;
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
#settings_page section:not(:last-of-type) {
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
#settings_page #sign_out::part(button) {
|
#settings_page #sign_out::part(button) {
|
||||||
color: var(--error-color);
|
color: var(--error-color);
|
||||||
}
|
}
|
||||||
@ -2224,9 +2219,11 @@ sm-button[variant=primary] {
|
|||||||
position: sticky;
|
position: sticky;
|
||||||
top: 0;
|
top: 0;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
padding: 1rem 1.5rem;
|
padding: 1rem 1.5rem 1rem 0.5rem;
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
background: rgba(var(--foreground-color), 1);
|
background: linear-gradient(rgba(var(--background-color), 0.8), rgba(var(--background-color), 0));
|
||||||
|
-webkit-backdrop-filter: blur(0.5rem);
|
||||||
|
backdrop-filter: blur(0.5rem);
|
||||||
}
|
}
|
||||||
|
|
||||||
.hide-on-mobile {
|
.hide-on-mobile {
|
||||||
|
|||||||
2
css/main.min.css
vendored
2
css/main.min.css
vendored
File diff suppressed because one or more lines are too long
@ -140,7 +140,7 @@ button,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.button {
|
.button {
|
||||||
background-color: rgba(var(--text-color), 0.06);
|
background-color: rgba(var(--text-color), 0.1);
|
||||||
&--primary,
|
&--primary,
|
||||||
&--danger {
|
&--danger {
|
||||||
color: rgba(var(--background-color), 1) !important;
|
color: rgba(var(--background-color), 1) !important;
|
||||||
@ -1283,7 +1283,6 @@ sm-button[variant="primary"] {
|
|||||||
#contacts {
|
#contacts {
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
height: 100%;
|
|
||||||
.scrolling-wrapper {
|
.scrolling-wrapper {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
@ -1324,6 +1323,7 @@ sm-button[variant="primary"] {
|
|||||||
#contacts,
|
#contacts,
|
||||||
#mails,
|
#mails,
|
||||||
#settings_page {
|
#settings_page {
|
||||||
|
height: 100%;
|
||||||
overflow-y: hidden;
|
overflow-y: hidden;
|
||||||
.header {
|
.header {
|
||||||
padding: 1rem 1.5rem 1rem 1.5rem;
|
padding: 1rem 1.5rem 1rem 1.5rem;
|
||||||
@ -1675,7 +1675,6 @@ sm-button[variant="primary"] {
|
|||||||
}
|
}
|
||||||
sm-textarea {
|
sm-textarea {
|
||||||
--padding-right: 3rem;
|
--padding-right: 3rem;
|
||||||
--border-radius: 0.5rem;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#emoji_toggle {
|
#emoji_toggle {
|
||||||
@ -1706,6 +1705,8 @@ sm-button[variant="primary"] {
|
|||||||
}
|
}
|
||||||
#type_message {
|
#type_message {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
--border-radius: 0.5rem;
|
||||||
|
--background: rgba(var(--text-color), 0.1);
|
||||||
}
|
}
|
||||||
.big-emoji {
|
.big-emoji {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@ -1899,17 +1900,11 @@ sm-button[variant="primary"] {
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
section {
|
section {
|
||||||
display: grid;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
padding: 1rem 1.5rem;
|
padding: 1rem 1.5rem;
|
||||||
width: min(60ch, 100%);
|
width: min(60ch, 100%);
|
||||||
sm-button {
|
|
||||||
margin-top: 0.5rem;
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
&:not(:last-of-type) {
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#sign_out::part(button) {
|
#sign_out::part(button) {
|
||||||
color: var(--error-color);
|
color: var(--error-color);
|
||||||
@ -2014,9 +2009,13 @@ sm-button[variant="primary"] {
|
|||||||
position: sticky;
|
position: sticky;
|
||||||
top: 0;
|
top: 0;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
padding: 1rem 1.5rem;
|
padding: 1rem 1.5rem 1rem 0.5rem;
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
background: rgba(var(--foreground-color), 1);
|
background: linear-gradient(
|
||||||
|
rgba(var(--background-color), 0.8),
|
||||||
|
rgba(var(--background-color), 0)
|
||||||
|
);
|
||||||
|
backdrop-filter: blur(0.5rem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.hide-on-mobile {
|
.hide-on-mobile {
|
||||||
|
|||||||
279
index.html
279
index.html
@ -407,12 +407,13 @@
|
|||||||
</aside>
|
</aside>
|
||||||
<div id="settings_panel" class=" hide-on-mobile">
|
<div id="settings_panel" class=" hide-on-mobile">
|
||||||
<header id="settings_header" class="flex align-center hide-on-desktop">
|
<header id="settings_header" class="flex align-center hide-on-desktop">
|
||||||
<svg id="back_settings" onclick='hidePanel()' xmlns="http://www.w3.org/2000/svg" class="icon back"
|
<button id="back_settings" onclick='hidePanel()'>
|
||||||
viewBox="0 0 64 64">
|
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24"
|
||||||
<title>Go back</title>
|
width="24px" fill="#000000">
|
||||||
<line x1="1" y1="32" x2="64" y2="32" />
|
<path d="M0 0h24v24H0V0z" fill="none" />
|
||||||
<polyline points="29.64 60.97 0.65 32 29.64 3.03" />
|
<path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z" />
|
||||||
</svg>
|
</svg>
|
||||||
|
</button>
|
||||||
<h4 id="settings_title"></h4>
|
<h4 id="settings_title"></h4>
|
||||||
</header>
|
</header>
|
||||||
<div id="profile_panel" class="panel">
|
<div id="profile_panel" class="panel">
|
||||||
@ -460,6 +461,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
<section>
|
||||||
|
<h4>Toggle dark theme</h4>
|
||||||
|
<div class="flex align-center space-between">
|
||||||
|
<p>Only applied to this browser</p>
|
||||||
|
<theme-toggle></theme-toggle>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
<section>
|
<section>
|
||||||
<h4>Set chat and mail background image</h4>
|
<h4>Set chat and mail background image</h4>
|
||||||
<fieldset id="bg_preview_container" class="flex">
|
<fieldset id="bg_preview_container" class="flex">
|
||||||
@ -481,14 +489,14 @@
|
|||||||
<h4>Backdrop</h4>
|
<h4>Backdrop</h4>
|
||||||
<label class="grid gap-0-3">
|
<label class="grid gap-0-3">
|
||||||
<span>Dim wallpaper</span>
|
<span>Dim wallpaper</span>
|
||||||
<div class="flex">
|
<div class="flex gap-0-5">
|
||||||
<input type="range" min="0" max="100" id="backdrop_opacity" class="w-100">
|
<input type="range" min="0" max="100" id="backdrop_opacity" class="w-100">
|
||||||
<output id="backdrop_opacity_value"></output>
|
<output id="backdrop_opacity_value"></output>
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
<label class="grid gap-0-3">
|
<label class="grid gap-0-3">
|
||||||
<span>Blur</span>
|
<span>Blur</span>
|
||||||
<div class="flex">
|
<div class="flex gap-0-3">
|
||||||
<input type="range" min="0" max="100" id="backdrop_blur" class="w-100">
|
<input type="range" min="0" max="100" id="backdrop_blur" class="w-100">
|
||||||
<output id="backdrop_blur_value"></output>
|
<output id="backdrop_blur_value"></output>
|
||||||
</div>
|
</div>
|
||||||
@ -1149,16 +1157,13 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFormattedTime(time, format) {
|
function getFormattedTime(timestamp, format) {
|
||||||
try {
|
try {
|
||||||
if (String(time).indexOf('_'))
|
if (String(timestamp).length < 13)
|
||||||
time = String(time).split('_')[0]
|
timestamp *= 1000
|
||||||
const intTime = parseInt(time)
|
let [day, month, date, year] = new Date(timestamp).toString().split(' '),
|
||||||
if (String(intTime).length < 13)
|
minutes = new Date(timestamp).getMinutes(),
|
||||||
time *= 1000
|
hours = new Date(timestamp).getHours(),
|
||||||
let [day, month, date, year] = new Date(intTime).toString().split(' '),
|
|
||||||
minutes = new Date(intTime).getMinutes(),
|
|
||||||
hours = new Date(intTime).getHours(),
|
|
||||||
currentTime = new Date().toString().split(' ')
|
currentTime = new Date().toString().split(' ')
|
||||||
|
|
||||||
minutes = minutes < 10 ? `0${minutes}` : minutes
|
minutes = minutes < 10 ? `0${minutes}` : minutes
|
||||||
@ -1177,12 +1182,14 @@
|
|||||||
break;
|
break;
|
||||||
case 'time-only':
|
case 'time-only':
|
||||||
return finalHours;
|
return finalHours;
|
||||||
|
case 'relative':
|
||||||
|
return relativeTime.from(timestamp)
|
||||||
default:
|
default:
|
||||||
return `${month} ${date}, ${year} at ${finalHours}`;
|
return `${month} ${date}, ${year} at ${finalHours}`;
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
return time;
|
return timestamp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// implement event delegation
|
// implement event delegation
|
||||||
@ -1371,12 +1378,12 @@
|
|||||||
this.updateEndIndex = this.updateEndIndex + this.batchSize
|
this.updateEndIndex = this.updateEndIndex + this.batchSize
|
||||||
} else {
|
} else {
|
||||||
this.intersectionObserver.disconnect()
|
this.intersectionObserver.disconnect()
|
||||||
|
this.updateStartIndex = 0
|
||||||
|
this.updateEndIndex = this.batchSize
|
||||||
if (this.hasUhtml)
|
if (this.hasUhtml)
|
||||||
renderElem(this.lazyContainer, html``)
|
renderElem(this.lazyContainer, html``)
|
||||||
else
|
else
|
||||||
this.lazyContainer.innerHTML = ``;
|
this.lazyContainer.innerHTML = ``;
|
||||||
this.updateStartIndex = 0
|
|
||||||
this.updateEndIndex = this.batchSize
|
|
||||||
}
|
}
|
||||||
this.lastScrollHeight = this.lazyContainer.scrollHeight
|
this.lastScrollHeight = this.lazyContainer.scrollHeight
|
||||||
this.lastScrollTop = this.lazyContainer.scrollTop
|
this.lastScrollTop = this.lazyContainer.scrollTop
|
||||||
@ -1484,7 +1491,7 @@
|
|||||||
frag = document.createDocumentFragment()
|
frag = document.createDocumentFragment()
|
||||||
|
|
||||||
|
|
||||||
const renderedDates = new Set()
|
let renderedDates = {}
|
||||||
|
|
||||||
// render elements
|
// render elements
|
||||||
const render = {
|
const render = {
|
||||||
@ -1507,7 +1514,7 @@
|
|||||||
<li class="${`mail-card interact ${markUnread ? 'unread' : ''}`}" name="${ref}" background-color="${contactColor(floID)}">
|
<li class="${`mail-card interact ${markUnread ? 'unread' : ''}`}" name="${ref}" background-color="${contactColor(floID)}">
|
||||||
<div class="initial flex align-center" style=${`background-color: ${contactColor(floID)}`}>${contact.charAt(0)}</div>
|
<div class="initial flex align-center" style=${`background-color: ${contactColor(floID)}`}>${contact.charAt(0)}</div>
|
||||||
<h5 class="sender">${contact}</h5>
|
<h5 class="sender">${contact}</h5>
|
||||||
<time class="date">${relativeTime.from(timestamp)}</time>
|
<time class="date">${getFormattedTime(timestamp, 'relative')}</time>
|
||||||
<h4 class="subject text-overflow">${subject}</h4>
|
<h4 class="subject text-overflow">${subject}</h4>
|
||||||
<p class="description">${mailSummery}</p>
|
<p class="description">${mailSummery}</p>
|
||||||
</li>
|
</li>
|
||||||
@ -1568,7 +1575,7 @@
|
|||||||
const amISender = type === 'chat' && lastMessage.category === 'sent' || type === 'group' && lastMessage.sender === myFloID
|
const amISender = type === 'chat' && lastMessage.category === 'sent' || type === 'group' && lastMessage.sender === myFloID
|
||||||
const lastText = html`<p class="last-message">${amISender ? 'You: ' : ''} ${lastMessage.message}</p>`
|
const lastText = html`<p class="last-message">${amISender ? 'You: ' : ''} ${lastMessage.message}</p>`
|
||||||
const timeAndOptions = html`
|
const timeAndOptions = html`
|
||||||
<time class="time">${relativeTime.from(lastMessage.time)}</time>
|
<time class="time">${getFormattedTime(lastMessage.time, 'relative')}</time>
|
||||||
<svg class="icon menu" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"> <circle cx="5.59" cy="32" r="5.59"/> <circle cx="58.41" cy="32" r="5.59"/> <circle cx="31.89" cy="32" r="5.59"/> </svg>
|
<svg class="icon menu" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"> <circle cx="5.59" cy="32" r="5.59"/> <circle cx="58.41" cy="32" r="5.59"/> <circle cx="31.89" cy="32" r="5.59"/> </svg>
|
||||||
`;
|
`;
|
||||||
getRef('chats_list').querySelector(`.contact[flo-id="${floID}"]`).append(html.node`${lastText}${timeAndOptions}`)
|
getRef('chats_list').querySelector(`.contact[flo-id="${floID}"]`).append(html.node`${lastText}${timeAndOptions}`)
|
||||||
@ -1651,7 +1658,12 @@
|
|||||||
currentFloID = floID
|
currentFloID = floID
|
||||||
}
|
}
|
||||||
const messageDate = getFormattedTime(timestamp, 'date-only')
|
const messageDate = getFormattedTime(timestamp, 'date-only')
|
||||||
renderedDates.add(messageDate)
|
if (!renderedDates.hasOwnProperty(messageDate) || renderedDates[messageDate].timestamp > timestamp) {
|
||||||
|
renderedDates[messageDate] = {
|
||||||
|
timestamp,
|
||||||
|
isRendered: false
|
||||||
|
}
|
||||||
|
}
|
||||||
const className = `message ${category} ${unconfirmed ? 'unconfirmed' : ''} ${senderName ? 'distinct-sender' : ''} ${isBigEmoji ? 'big-emoji' : ''}`
|
const className = `message ${category} ${unconfirmed ? 'unconfirmed' : ''} ${senderName ? 'distinct-sender' : ''} ${isBigEmoji ? 'big-emoji' : ''}`
|
||||||
return html.node`
|
return html.node`
|
||||||
<div class="${className}" id="${`${floID}_${timestamp}`}" data-date="${messageDate}">
|
<div class="${className}" id="${`${floID}_${timestamp}`}" data-date="${messageDate}">
|
||||||
@ -1721,9 +1733,8 @@
|
|||||||
|
|
||||||
|
|
||||||
function renderDirectUI(data) {
|
function renderDirectUI(data) {
|
||||||
renderMessages({ updateChatCard: true });
|
updateMessageUI(data.messages)
|
||||||
renderMailList(data.mails)
|
// renderMessages({ updateChatCard: true });
|
||||||
//let order = Object.keys(data.messages).map(a => a.split('_')).sort((a, b) => a[0] - b[0]).map(a => a[1])
|
|
||||||
if (Object.keys(data.messages).length) {
|
if (Object.keys(data.messages).length) {
|
||||||
document.title = `New message(s)`
|
document.title = `New message(s)`
|
||||||
}
|
}
|
||||||
@ -1733,7 +1744,77 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function renderGroupUI(data) {
|
function renderGroupUI(data) {
|
||||||
renderMessages({ updateChatCard: true });
|
updateMessageUI(data.messages)
|
||||||
|
// renderMessages({ updateChatCard: true });
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateMessageUI(messagesData) {
|
||||||
|
for (let messageId in messagesData) {
|
||||||
|
const { category, floID, time, message } = messagesData[messageId]
|
||||||
|
if (activeChat.floID && activeChat.floID === floID)
|
||||||
|
getRef('messages_container').append(render.messageBubble(messagesData[messageId]))
|
||||||
|
let chatCard = getRef('chats_list').querySelector(`.chat[flo-id="${floID}"], .group[flo-id="${floID}"]`)
|
||||||
|
if (chatCard) {
|
||||||
|
if (activeChat['chatCard'] !== getRef('chats_list').children[0]) {
|
||||||
|
const cloneContact = chatCard.cloneNode(true)
|
||||||
|
chatCard.remove()
|
||||||
|
activeChat['chatCard'] = cloneContact
|
||||||
|
getRef('chats_list').prepend(cloneContact)
|
||||||
|
animateTo(getRef('chats_list').children[0], [
|
||||||
|
{ transform: 'translateY(1rem)' },
|
||||||
|
{ transform: 'none' },
|
||||||
|
],
|
||||||
|
{
|
||||||
|
easing: 'ease',
|
||||||
|
duration: 300
|
||||||
|
}
|
||||||
|
)
|
||||||
|
animateTo(getRef('chats_list'), [
|
||||||
|
{ transform: 'translateY(-1rem)' },
|
||||||
|
{ transform: 'none' },
|
||||||
|
],
|
||||||
|
{
|
||||||
|
easing: 'ease',
|
||||||
|
duration: 300
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
messenger.addChat(floID)
|
||||||
|
getRef('chats_list').prepend(html.node`${render.contactCard(floID, { type: 'chat', prepend: true })}`)
|
||||||
|
chatCard = getRef('chats_list').children[0]
|
||||||
|
chatCard.classList.add('active')
|
||||||
|
activeChat['chatCard'] = getRef('chats_list').children[0]
|
||||||
|
}
|
||||||
|
let finalMessage
|
||||||
|
if (messenger.groups && messenger.groups[floID]) {
|
||||||
|
if (floGlobals.contacts[floID])
|
||||||
|
finalMessage = `${floGlobals.contacts[floID]}: ${message}`
|
||||||
|
else if (floID === myFloID)
|
||||||
|
finalMessage = `You: ${message}`
|
||||||
|
}
|
||||||
|
else
|
||||||
|
finalMessage = message
|
||||||
|
if (chatCard.querySelector('.last-message'))
|
||||||
|
chatCard.querySelector('.last-message').textContent = finalMessage
|
||||||
|
chatCard.querySelector('.time').textContent = getFormattedTime(time, 'relative')
|
||||||
|
|
||||||
|
if (activeChat.floID === (floID || groupID)) {
|
||||||
|
if (chatScrollInfo.isScrolledUp)
|
||||||
|
getRef('scroll_to_bottom').classList.add('new-message')
|
||||||
|
else {
|
||||||
|
if (document.hasFocus()) {
|
||||||
|
messenger.removeMark((floID || groupID), 'unread')
|
||||||
|
setTimeout(() => {
|
||||||
|
document.title = 'FLO Messenger'
|
||||||
|
activeChat.chatCard.classList.remove('unread')
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener('focus', e => {
|
window.addEventListener('focus', e => {
|
||||||
@ -1964,30 +2045,12 @@
|
|||||||
//detect click on chat cards
|
//detect click on chat cards
|
||||||
if (e.target.closest(".contact")) {
|
if (e.target.closest(".contact")) {
|
||||||
let contact = e.target.closest(".contact")
|
let contact = e.target.closest(".contact")
|
||||||
clickedContact = {
|
const floID = contact.getAttribute("flo-id")
|
||||||
...clickedContact,
|
let chatCard = getRef('chats_list').querySelector(`.chat[flo-id="${floID}"], .group[flo-id="${floID}"]`);
|
||||||
chatCard: contact,
|
if (!chatCard) {
|
||||||
floID: contact.getAttribute("flo-id"),
|
chatCard = getRef('chats_list').prepend(render.contactCard(floID, { type: 'chat' }))
|
||||||
name: contact.getAttribute("name"),
|
|
||||||
isGroup: messenger.groups.hasOwnProperty(clickedContact['floID'])
|
|
||||||
}
|
|
||||||
if (clickedContact['floID'] === myFloID) return
|
|
||||||
contact.classList.remove('unread')
|
|
||||||
if (activeChat['chatCard'] === contact && !isMobileView) return
|
|
||||||
showChatDetails({ show: false, animate: false })
|
|
||||||
document.title = `FLO Messenger`
|
|
||||||
getRef('chat').classList.remove('hide')
|
|
||||||
viewConversation(contact)
|
|
||||||
if (activeChat['chatCard'])
|
|
||||||
activeChat['chatCard'].classList.remove('active')
|
|
||||||
contact.classList.add('active')
|
|
||||||
activeChat['chatCard'] = contact
|
|
||||||
if (activeChatPage.id === 'contacts') {
|
|
||||||
getRef('chat').classList.remove('hide-on-mobile')
|
|
||||||
getRef('contacts').classList.add('hide-on-mobile')
|
|
||||||
activeChatPage = getRef('chat')
|
|
||||||
getRef('main_navbar').classList.add('hide-on-mobile')
|
|
||||||
}
|
}
|
||||||
|
chatCard.click()
|
||||||
closePopup()
|
closePopup()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -2317,43 +2380,19 @@
|
|||||||
msgObj['floID'] = activeChat.floID
|
msgObj['floID'] = activeChat.floID
|
||||||
msgObj['category'] = 'sent'
|
msgObj['category'] = 'sent'
|
||||||
}
|
}
|
||||||
getRef('messages_container').append(render.messageBubble(msgObj))
|
updateMessageUI({ msgObj })
|
||||||
const contact = getRef('chats_list').querySelector(`.chat[flo-id="${receiver}"], .group[flo-id="${receiver}"]`)
|
|
||||||
if (contact) {
|
|
||||||
if (activeChat['chatCard'] !== getRef('chats_list').children[0]) {
|
|
||||||
const cloneContact = contact.cloneNode(true)
|
|
||||||
contact.remove()
|
|
||||||
activeChat['chatCard'] = cloneContact
|
|
||||||
getRef('chats_list').prepend(cloneContact)
|
|
||||||
animateTo(getRef('chats_list').children[0], [
|
|
||||||
{ transform: 'translateY(1rem)' },
|
|
||||||
{ transform: 'none' },
|
|
||||||
],
|
|
||||||
{
|
|
||||||
easing: 'ease',
|
|
||||||
duration: 300
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
messenger.addChat(receiver)
|
|
||||||
getRef('chats_list').prepend(render.contactCard(receiver, { type: 'chat', prepend: true }))
|
|
||||||
getRef('chats_list').children[0].classList.add('active')
|
|
||||||
activeChat['chatCard'] = getRef('chats_list').children[0]
|
|
||||||
}
|
|
||||||
scrollToBottom()
|
scrollToBottom()
|
||||||
if (activeChat.isGroup)
|
if (activeChat.isGroup)
|
||||||
messenger.sendGroupMessage(message, receiver).then(data => {
|
messenger.sendGroupMessage(message, receiver).then(data => {
|
||||||
getRef('messages_container').querySelector(`#${receiver}_${time}`).classList.remove('unconfirmed')
|
getRef('messages_container').querySelector(`#${receiver}_${time}`).classList.remove('unconfirmed')
|
||||||
activeChat.chatCard.querySelector('.last-message').textContent = `You: ${message}`
|
activeChat.chatCard.querySelector('.last-message').textContent = `You: ${message}`
|
||||||
activeChat.chatCard.querySelector('.time').textContent = relativeTime.from(Date.now())
|
activeChat.chatCard.querySelector('.time').textContent = getFormattedTime(Date.now(), 'relative')
|
||||||
}).catch(error => notify(error, "error"));
|
}).catch(error => notify(error, "error"));
|
||||||
else
|
else
|
||||||
messenger.sendMessage(message, receiver).then(data => {
|
messenger.sendMessage(message, receiver).then(data => {
|
||||||
getRef('messages_container').querySelector(`#${receiver}_${time}`).classList.remove('unconfirmed')
|
getRef('messages_container').querySelector(`#${receiver}_${time}`).classList.remove('unconfirmed')
|
||||||
activeChat.chatCard.querySelector('.last-message').textContent = `You: ${message}`
|
activeChat.chatCard.querySelector('.last-message').textContent = `You: ${message}`
|
||||||
activeChat.chatCard.querySelector('.time').textContent = relativeTime.from(Date.now())
|
activeChat.chatCard.querySelector('.time').textContent = getFormattedTime(Date.now(), 'relative')
|
||||||
}).catch(error => notify(error, "error"));
|
}).catch(error => notify(error, "error"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2428,84 +2467,32 @@
|
|||||||
|
|
||||||
let chatLazyLoader
|
let chatLazyLoader
|
||||||
async function renderMessages(options) {
|
async function renderMessages(options) {
|
||||||
let { markUnread = true, updateChatCard = false } = options
|
let { markUnread = true } = options
|
||||||
try {
|
try {
|
||||||
|
let messages = Object.values(await messenger.getChat(activeChat['floID'])).reverse()
|
||||||
if (activeChat.floID) {
|
if (activeChat.floID) {
|
||||||
let messages = Object.values(await messenger.getChat(activeChat['floID'])).reverse()
|
|
||||||
if (chatLazyLoader) {
|
if (chatLazyLoader) {
|
||||||
chatLazyLoader.update(messages)
|
chatLazyLoader.update(messages)
|
||||||
} else {
|
} else {
|
||||||
chatLazyLoader = new LazyLoader('#messages_container', messages, render.messageBubble, {
|
chatLazyLoader = new LazyLoader('#messages_container', messages, render.messageBubble, {
|
||||||
bottomFirst: true, domUpdated: debounce(() => {
|
bottomFirst: true, domUpdated: () => {
|
||||||
renderedDates.forEach(date => {
|
for (const date in renderedDates) {
|
||||||
if (getRef('messages_container').querySelector(`.date-card[data-date="${date}"]`)) {
|
if (renderedDates[date].isRendered) continue
|
||||||
getRef('messages_container').querySelector(`.date-card[data-date="${date}"]`).remove()
|
let dateCard
|
||||||
|
const previousDateCard = getRef('messages_container').querySelector(`.date-card[data-date="${date}"]`)
|
||||||
|
if (previousDateCard) {
|
||||||
|
dateCard = previousDateCard.cloneNode(true)
|
||||||
|
previousDateCard.remove()
|
||||||
|
} else {
|
||||||
|
dateCard = html.node`<time class="date-card" data-date="${date}">${date}</time>`
|
||||||
}
|
}
|
||||||
const dateCard = html.node`<time class="date-card" data-date="${date}">${date}</time>`
|
|
||||||
getRef('messages_container').querySelector(`.message[data-date="${date}"]`).before(dateCard)
|
getRef('messages_container').querySelector(`.message[data-date="${date}"]`).before(dateCard)
|
||||||
renderedDates.delete(date)
|
renderedDates[date].isRendered = true
|
||||||
}, 100)
|
}
|
||||||
})
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
chatLazyLoader.init()
|
chatLazyLoader.init()
|
||||||
|
|
||||||
|
|
||||||
messages.forEach(messageDetails => {
|
|
||||||
let { floID, groupID, sender, message, time, category } = messageDetails
|
|
||||||
const contact = getRef('chats_list').querySelector(`.contact[flo-id='${floID || groupID}']`)
|
|
||||||
if (markUnread && contact) {
|
|
||||||
contact.classList.add("unread");
|
|
||||||
if (contact !== getRef('chats_list').children[0]) {
|
|
||||||
const cloneContact = contact.cloneNode(true)
|
|
||||||
contact.remove()
|
|
||||||
getRef('chats_list').prepend(cloneContact)
|
|
||||||
animateTo(getRef('chats_list').children[0], [
|
|
||||||
{ transform: 'translateY(1rem)' },
|
|
||||||
{ transform: 'none' },
|
|
||||||
],
|
|
||||||
{
|
|
||||||
easing: 'ease',
|
|
||||||
duration: 300
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (updateChatCard) {
|
|
||||||
let chatCard
|
|
||||||
if (!contact) {
|
|
||||||
getRef('chats_list').prepend(render.contactCard(floID, { type: 'chat', markUnread: true }))
|
|
||||||
chatCard = getRef('chats_list').firstElementChild
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
chatCard = contact
|
|
||||||
let finalMessage
|
|
||||||
if (floGlobals.contacts[sender])
|
|
||||||
finalMessage = `${floGlobals.contacts[sender]}: ${message}`
|
|
||||||
else if (sender === myFloID)
|
|
||||||
finalMessage = `You: ${message}`
|
|
||||||
else
|
|
||||||
finalMessage = message
|
|
||||||
if (chatCard.querySelector('.last-message'))
|
|
||||||
chatCard.querySelector('.last-message').textContent = finalMessage
|
|
||||||
chatCard.querySelector('.time').textContent = relativeTime.from(time)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (activeChat.floID === (floID || groupID)) {
|
|
||||||
if (chatScrollInfo.isScrolledUp)
|
|
||||||
getRef('scroll_to_bottom').classList.add('new-message')
|
|
||||||
else {
|
|
||||||
if (document.hasFocus()) {
|
|
||||||
messenger.removeMark((floID || groupID), 'unread')
|
|
||||||
setTimeout(() => {
|
|
||||||
document.title = 'FLO Messenger'
|
|
||||||
activeChat.chatCard.classList.remove('unread')
|
|
||||||
}, 1000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error)
|
console.log(error)
|
||||||
@ -2513,6 +2500,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function viewConversation(contact) {
|
async function viewConversation(contact) {
|
||||||
|
// clear rendered date cards if any
|
||||||
|
renderedDates = {}
|
||||||
let floID = clickedContact['floID'],
|
let floID = clickedContact['floID'],
|
||||||
name = contact.getAttribute('name'),
|
name = contact.getAttribute('name'),
|
||||||
textColor = contact.getAttribute('text-color'),
|
textColor = contact.getAttribute('text-color'),
|
||||||
|
|||||||
@ -609,7 +609,6 @@ smTextarea.innerHTML = `
|
|||||||
:host{
|
:host{
|
||||||
display: grid;
|
display: grid;
|
||||||
--danger-color: red;
|
--danger-color: red;
|
||||||
--border-radius: 0.3rem;
|
|
||||||
--background: rgba(var(--text-color,(17,17,17)), 0.06);
|
--background: rgba(var(--text-color,(17,17,17)), 0.06);
|
||||||
--padding: initial;
|
--padding: initial;
|
||||||
--max-height: 8rem;
|
--max-height: 8rem;
|
||||||
@ -629,7 +628,7 @@ smTextarea.innerHTML = `
|
|||||||
align-items: stretch;
|
align-items: stretch;
|
||||||
max-height: var(--max-height);
|
max-height: var(--max-height);
|
||||||
background: var(--background);
|
background: var(--background);
|
||||||
border-radius: var(--border-radius);
|
border-radius: var(--border-radius, 0.3rem);
|
||||||
padding: var(--padding);
|
padding: var(--padding);
|
||||||
}
|
}
|
||||||
.textarea::after,
|
.textarea::after,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user