Bug fixes and UX improvements

-- implemented saving typed messages for every chat at changing chat and restore them when revisited
This commit is contained in:
sairaj mote 2022-06-29 15:18:39 +05:30
parent 43af05385b
commit 38eacaa87f
5 changed files with 168 additions and 130 deletions

View File

@ -559,6 +559,22 @@ ol li::before {
margin-left: auto; margin-left: auto;
} }
.margin-block-1 {
margin-block: 1rem;
}
.margin-block-1-5 {
margin-block: 1.5rem;
}
.margin-inline-1 {
margin-inline: 1rem;
}
.margin-inline-1-5 {
margin-inline: 1.5rem;
}
.icon-button { .icon-button {
padding: 0.6rem; padding: 0.6rem;
border-radius: 0.8rem; border-radius: 0.8rem;
@ -700,12 +716,6 @@ ol li::before {
color: rgba(var(--text-color), 0.8); color: rgba(var(--text-color), 0.8);
} }
.card {
display: flex;
flex-direction: column;
margin: 1rem 0;
}
.tip { .tip {
font-size: 0.9rem; font-size: 0.9rem;
color: rgba(var(--text-color), 0.8); color: rgba(var(--text-color), 0.8);
@ -1464,6 +1474,22 @@ sm-button[variant=primary] {
grid-template-rows: max-content 1fr; grid-template-rows: max-content 1fr;
} }
#mail_sections {
overflow-y: auto;
}
#mail_sections > * {
display: flex;
flex-direction: column;
height: 100%;
overflow-y: auto;
}
#mail_sections > * > * {
display: flex;
flex-direction: column;
height: 100%;
overflow-y: auto;
}
#contacts, #contacts,
#mails, #mails,
#settings { #settings {
@ -1539,9 +1565,6 @@ sm-button[variant=primary] {
flex-direction: column; flex-direction: column;
width: 100%; width: 100%;
height: 100%; height: 100%;
}
#chat_page {
overflow: hidden; overflow: hidden;
} }
@ -2270,11 +2293,6 @@ sm-button[variant=primary] {
background: rgba(var(--text-color), 0.06); background: rgba(var(--text-color), 0.06);
} }
.card {
display: inline-flex;
width: auto;
}
#contact_details_popup.is-group { #contact_details_popup.is-group {
--width: 52rem; --width: 52rem;
} }
@ -2316,11 +2334,6 @@ sm-button[variant=primary] {
.mail-card.active { .mail-card.active {
background: rgba(var(--text-color), 0.06); background: rgba(var(--text-color), 0.06);
} }
.card {
display: inline-flex;
width: auto;
}
} }
@media (hover: hover) { @media (hover: hover) {
::-webkit-scrollbar { ::-webkit-scrollbar {

2
css/main.min.css vendored

File diff suppressed because one or more lines are too long

View File

@ -523,6 +523,18 @@ ol {
.margin-left-auto { .margin-left-auto {
margin-left: auto; margin-left: auto;
} }
.margin-block-1 {
margin-block: 1rem;
}
.margin-block-1-5 {
margin-block: 1.5rem;
}
.margin-inline-1 {
margin-inline: 1rem;
}
.margin-inline-1-5 {
margin-inline: 1.5rem;
}
.icon-button { .icon-button {
padding: 0.6rem; padding: 0.6rem;
@ -649,11 +661,6 @@ ol {
color: rgba(var(--text-color), 0.8); color: rgba(var(--text-color), 0.8);
} }
} }
.card {
display: flex;
flex-direction: column;
margin: 1rem 0;
}
.tip { .tip {
font-size: 0.9rem; font-size: 0.9rem;
color: rgba(var(--text-color), 0.8); color: rgba(var(--text-color), 0.8);
@ -1308,6 +1315,21 @@ sm-button[variant="primary"] {
position: relative; position: relative;
grid-template-rows: max-content 1fr; grid-template-rows: max-content 1fr;
} }
#mail_sections {
overflow-y: auto;
& > * {
display: flex;
flex-direction: column;
height: 100%;
overflow-y: auto;
& > * {
display: flex;
flex-direction: column;
height: 100%;
overflow-y: auto;
}
}
}
#contacts, #contacts,
#mails, #mails,
#settings { #settings {
@ -1368,8 +1390,6 @@ sm-button[variant="primary"] {
flex-direction: column; flex-direction: column;
width: 100%; width: 100%;
height: 100%; height: 100%;
}
#chat_page {
overflow: hidden; overflow: hidden;
} }
#group_members_list { #group_members_list {
@ -2037,10 +2057,6 @@ sm-button[variant="primary"] {
.mail-card.active { .mail-card.active {
background: rgba(var(--text-color), 0.06); background: rgba(var(--text-color), 0.06);
} }
.card {
display: inline-flex;
width: auto;
}
#contact_details_popup { #contact_details_popup {
&.is-group { &.is-group {
--width: 52rem; --width: 52rem;
@ -2084,10 +2100,6 @@ sm-button[variant="primary"] {
.mail-card.active { .mail-card.active {
background: rgba(var(--text-color), 0.06); background: rgba(var(--text-color), 0.06);
} }
.card {
display: inline-flex;
width: auto;
}
} }
@media (hover: hover) { @media (hover: hover) {
::-webkit-scrollbar { ::-webkit-scrollbar {

View File

@ -47,6 +47,7 @@
//Check for available bg image //Check for available bg image
setBgImage(); setBgImage();
showPage(window.location.hash, { firstLoad: true }) showPage(window.location.hash, { firstLoad: true })
floGlobals.loaded = true;
}).catch(error => notify(error, "error")) }).catch(error => notify(error, "error"))
}).catch(error => notify(error, "error")) }).catch(error => notify(error, "error"))
} }
@ -144,7 +145,7 @@
<strong>Don't share with anyone. Once lost private key can't be <strong>Don't share with anyone. Once lost private key can't be
recovered.</strong> recovered.</strong>
</div> </div>
<div class="grid gap-1-5 card"> <div class="grid gap-1-5">
<div class="grid gap-0-5"> <div class="grid gap-0-5">
<h5>FLO ID</h5> <h5>FLO ID</h5>
<sm-copy id="generated_flo_id"></sm-copy> <sm-copy id="generated_flo_id"></sm-copy>
@ -567,7 +568,7 @@
<nav id="main_navbar" class="flex hide"> <nav id="main_navbar" class="flex hide">
<ul> <ul>
<li> <li>
<a class="nav-item flex align-center active" href="#/chat_page" title="Chat"> <a id="chat_page_button" class="nav-item flex align-center active" href="#/chat_page" title="Chat">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" <svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24"
width="24px" fill="#000000"> width="24px" fill="#000000">
<path d="M0 0h24v24H0V0z" fill="none" /> <path d="M0 0h24v24H0V0z" fill="none" />
@ -685,13 +686,13 @@
<h5>FLO ID</h5> <h5>FLO ID</h5>
<sm-copy id="contact_flo_id"></sm-copy> <sm-copy id="contact_flo_id"></sm-copy>
</div> </div>
<div id="group_description_card" class="card hide"> <div id="group_description_card" class="hide">
<h4 class="h4">Group description</h4> <h4 class="h4">Group description</h4>
<text-field id="group_description"></text-field> <text-field id="group_description"></text-field>
</div> </div>
<fieldset id="contact_options"></fieldset> <fieldset id="contact_options"></fieldset>
</div> </div>
<div id="group_members_card" class="card hide"> <div id="group_members_card" class="hide">
<div class="flex align-center"> <div class="flex align-center">
<h4 class="h4">Group members</h4> <h4 class="h4">Group members</h4>
<button id="edit_group_button" class="button hide justify-right" <button id="edit_group_button" class="button hide justify-right"
@ -703,8 +704,8 @@
<button id="remove_members_button" class="button button--danger hide" <button id="remove_members_button" class="button button--danger hide"
onclick="removeGroupMembers()"> onclick="removeGroupMembers()">
Remove selected</button> Remove selected</button>
<button id="init_add_members_button" class="button" onclick="openPopup('contacts_popup')">Add member <button id="init_add_members_button" class="button" onclick="openPopup('contacts_popup')">Add
</button> member</button>
</div> </div>
<div id="group_members_list"></div> <div id="group_members_list"></div>
</div> </div>
@ -1429,16 +1430,19 @@
targetPage = 'sign_up' targetPage = 'sign_up'
break; break;
case 'chat_page': case 'chat_page':
if (subPageId) { if (subPageId && activeChat.floID) {
getRef('chat_view').classList.remove('hide') getRef('chat_view').classList.remove('hide')
getRef('chat_view').classList.remove('hide-on-mobile')
getRef('contacts').classList.add('hide-on-mobile') getRef('contacts').classList.add('hide-on-mobile')
getRef('main_navbar').classList.add('hide-on-mobile') getRef('main_navbar').classList.add('hide-on-mobile')
} else { } else {
getRef('chat_view').classList.add('hide') history.replaceState(null, null, '#/chat_page');
getRef('chat_view').classList.add('hide-on-mobile')
getRef('contacts').classList.remove('hide-on-mobile') getRef('contacts').classList.remove('hide-on-mobile')
activeChat = {} activeChat = {}
getRef('main_navbar').classList.remove('hide-on-mobile') getRef('main_navbar').classList.remove('hide-on-mobile')
} }
removeNotificationBadge('chat_page_button')
break; break;
case 'mail_page': case 'mail_page':
if (subPageId) { if (subPageId) {
@ -1454,6 +1458,7 @@
showChildElement('mail_sections', childIndex) showChildElement('mail_sections', childIndex)
getRef("mail_type_selector").value = subPageId getRef("mail_type_selector").value = subPageId
} }
removeNotificationBadge('mail_page_button')
break; break;
case 'settings': case 'settings':
if (subPageId) { if (subPageId) {
@ -1651,9 +1656,6 @@
if (this.lazyContainer.lastElementChild) if (this.lazyContainer.lastElementChild)
this.intersectionObserver.observe(this.lazyContainer.lastElementChild) this.intersectionObserver.observe(this.lazyContainer.lastElementChild)
} }
// Callback to be called if dom is updated
if (this.shouldLazyLoad && this.domUpdated)
this.domUpdated()
} }
} }
}) })
@ -1704,9 +1706,7 @@
this.lazyContainer.append(frag) this.lazyContainer.append(frag)
} }
if (!lazyLoad && this.bottomFirst) { if (!lazyLoad && this.bottomFirst) {
this.lazyContainer.scrollTo({ this.lazyContainer.scrollTop = this.lazyContainer.scrollHeight
top: this.lazyContainer.scrollHeight,
})
} }
// Callback to be called if elements are updated or rendered for first time // Callback to be called if elements are updated or rendered for first time
if (!lazyLoad && this.freshRender) if (!lazyLoad && this.freshRender)
@ -1864,8 +1864,7 @@
</script> </script>
<script> <script>
let activePage = {}, let activeMailPage = getRef('mails'),
activeMailPage = getRef('mails'),
activeChat = {}, activeChat = {},
activeMail, activeMail,
frag = document.createDocumentFragment() frag = document.createDocumentFragment()
@ -1880,18 +1879,15 @@
let mailSummery = content.split(' ').splice(16).join(' ') let mailSummery = content.split(' ').splice(16).join(' ')
let contact; let contact;
if (Array.isArray(floID)) { if (Array.isArray(floID)) {
for (let f of floID) // find known floID name
if (floGlobals.contacts[f]) { contact = floID.find(id => floGlobals.contacts[id])
contact = floGlobals.contacts[f]
break;
}
contact = contact || `${floID[0].substring(12)}...`; contact = contact || `${floID[0].substring(12)}...`;
if (floID.length > 1) if (floID.length > 1)
contact = `${contact} & ${floID.length - 1} others(s)` contact = `${contact} & ${floID.length - 1} others(s)`
floID = floID.join(', ') floID = floID.join(', ')
} else } else
contact = floGlobals.contacts[floID] || floID contact = floGlobals.contacts[floID] || floID
return html` return html.node`
<li class="${`mail-card interactive ${markUnread ? 'unread' : ''}`}" data-name="${ref}" style=${`--contact-color: var(${contactColor(floID)})`}> <li class="${`mail-card interactive ${markUnread ? 'unread' : ''}`}" data-name="${ref}" style=${`--contact-color: var(${contactColor(floID)})`}>
<div class="initial flex align-center">${contact.charAt(0)}</div> <div class="initial flex align-center">${contact.charAt(0)}</div>
<h5 class="sender">${contact}</h5> <h5 class="sender">${contact}</h5>
@ -1971,6 +1967,8 @@
lastText = `${getContactName(lastMessage.sender)}: ${lastMessage.message}` lastText = `${getContactName(lastMessage.sender)}: ${lastMessage.message}`
else else
lastText = 'Group created' lastText = 'Group created'
} else {
lastText = lastMessage.message
} }
} }
const timeAndOptions = html` const timeAndOptions = html`
@ -2160,7 +2158,7 @@
], animOptions) ], animOptions)
} else { } else {
const badge = getRef(elem).querySelector('.badge'); const badge = getRef(elem).querySelector('.badge');
badge.textContent = text; badge.textContent = parseInt(badge.textContent) + parseFloat(text);
badge.animate([ badge.animate([
{ transform: 'scale(1)' }, { transform: 'scale(1)' },
{ transform: `scale(1.5)` }, { transform: `scale(1.5)` },
@ -2192,13 +2190,20 @@
function renderDirectUI(data) { function renderDirectUI(data) {
updateMessageUI(data.messages)
if (Object.keys(data.messages).length) { if (Object.keys(data.messages).length) {
document.title = `New message(s)` if (pagesData.lastPage !== 'chat_page') {
document.title = `New message(s)`
addNotificationBadge('chat_page_button', Object.keys(data.messages).length)
}
} }
if (Object.keys(data.mails).length && activePage.button !== getRef('mail_page_button')) { if (Object.keys(data.mails).length) {
document.title = `New mail(s)` if (pagesData.lastPage !== 'mail_page') {
document.title = `New mail(s)`
addNotificationBadge('mail_page_button', Object.keys(data.mails).length)
}
} }
updateMessageUI(data.messages)
renderMailList(data.mails, true)
} }
function renderGroupUI(data) { function renderGroupUI(data) {
@ -2207,8 +2212,9 @@
function updateMessageUI(messagesData) { function updateMessageUI(messagesData) {
for (let messageId in messagesData) { for (let messageId in messagesData) {
console.log(messagesData[messageId])
const { category, floID, time, message, sender, groupID, admin, name } = messagesData[messageId] const { category, floID, time, message, sender, groupID, admin, name } = messagesData[messageId]
if (activeChat.floID && activeChat.floID === (floID || groupID)) { if (activeChat?.floID === (floID || groupID)) {
if (floGlobals.unconfirmedMessages === 0) if (floGlobals.unconfirmedMessages === 0)
getRef('messages_container').append(render.messageBubble(messagesData[messageId])) getRef('messages_container').append(render.messageBubble(messagesData[messageId]))
if (chatScrollInfo['isScrolledUp']) { if (chatScrollInfo['isScrolledUp']) {
@ -2250,11 +2256,10 @@
} else { } else {
if (floID) { if (floID) {
messenger.addChat(floID) messenger.addChat(floID)
getRef('chats_list').prepend(html.node`${render.contactCard(floID, { type: 'chat', prepend: true })}`) getRef('chats_list').prepend(html.node`${render.contactCard(floID, { type: 'chat', prepend: true, markUnread: true })}`)
} else if (groupID) { } else if (groupID) {
getRef('chats_list').prepend(html.node`${render.contactCard(groupID, { type: 'group', prepend: true })}`) getRef('chats_list').prepend(html.node`${render.contactCard(groupID, { type: 'group', prepend: true, markUnread: true })}`)
} }
console.log('new chat', floID, groupID)
chatCard = getRef('chats_list').children[0] chatCard = getRef('chats_list').children[0]
chatCard.classList.add('active') chatCard.classList.add('active')
activeChat['chatCard'] = getRef('chats_list').children[0] activeChat['chatCard'] = getRef('chats_list').children[0]
@ -2286,7 +2291,6 @@
} }
} }
} else { } else {
console.log(chatCard)
getRef('chats_list').querySelector(`.chat[data-flo-id="${floID}"], .group[data-flo-id="${groupID}"]`).classList.add('unread') getRef('chats_list').querySelector(`.chat[data-flo-id="${floID}"], .group[data-flo-id="${groupID}"]`).classList.add('unread')
} }
} }
@ -2476,9 +2480,9 @@
openPopup('contact_details_popup') openPopup('contact_details_popup')
} else { } else {
e.delegateTarget.classList.remove('unread') e.delegateTarget.classList.remove('unread')
if (activeChat['chatCard'] === e.delegateTarget && !isMobileView) return if (activeChat['chatCard'] === e.delegateTarget && !isMobileView) return // check if chat is already active and if not, open it
document.title = `FLO Messenger` document.title = `FLO Messenger`
viewConversation(e.delegateTarget) viewConversation(e.delegateTarget.dataset.floId)
getRef('chats_list').querySelectorAll('.active').forEach(child => child.classList.remove('active')) getRef('chats_list').querySelectorAll('.active').forEach(child => child.classList.remove('active'))
e.delegateTarget.classList.add('active') e.delegateTarget.classList.add('active')
activeChat['chatCard'] = e.delegateTarget activeChat['chatCard'] = e.delegateTarget
@ -2897,7 +2901,7 @@
chatLazyLoader.update(Object.values(chat)) chatLazyLoader.update(Object.values(chat))
} else { } else {
chatLazyLoader = new LazyLoader('#messages_container', Object.values(chat), render.messageBubble, { chatLazyLoader = new LazyLoader('#messages_container', Object.values(chat), render.messageBubble, {
bottomFirst: true bottomFirst: true,
}); });
} }
chatLazyLoader.init() chatLazyLoader.init()
@ -2909,24 +2913,33 @@
}) })
} }
async function viewConversation(contact) { floGlobals.typedMessages = {}
async function viewConversation(floID) {
// clear rendered date cards if any // clear rendered date cards if any
renderedDates = {} renderedDates = {}
activeChat.floID = clickedContact.floID // save typed message from previous chat
activeChat['isGroup'] = messenger.groups.hasOwnProperty(clickedContact.floID) if (getRef('type_message').value.trim() !== '') {
getRef("receiver_name").textContent = getContactName(clickedContact.floID); floGlobals.typedMessages[activeChat.floID] = getRef('type_message').value
} else {
delete floGlobals.typedMessages[activeChat.floID]
}
// restore typed message if any
getRef('type_message').value = floGlobals.typedMessages[floID] || ''
activeChat.floID = floID
activeChat['isGroup'] = messenger.groups.hasOwnProperty(floID)
getRef("receiver_name").textContent = getContactName(floID);
if (activeChat.isGroup) { if (activeChat.isGroup) {
getRef("receiver_initial").innerHTML = ` <svg class="icon group-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><path d="M13.61,28.09c-1.63,0-4.72-2.35-5.33-3.58a21.65,21.65,0,0,1-1.35-7.32s-.26-6.07,6.68-6.07a6.38,6.38,0,0,1,6.69,6.07A21.65,21.65,0,0,1,19,24.51c-.62,1.23-3.7,3.58-5.34,3.58"/><path d="M50.39,28.09c-1.64,0-4.72-2.35-5.34-3.58a21.9,21.9,0,0,1-1.35-7.32s-.26-6.07,6.69-6.07a6.37,6.37,0,0,1,6.68,6.07,21.65,21.65,0,0,1-1.35,7.32c-.61,1.23-3.7,3.58-5.33,3.58"/><path d="M32,31.74c-2.21,0-6.37-3.17-7.2-4.83A29.3,29.3,0,0,1,23,17s-.35-8.21,9-8.21c8.68,0,9,8.21,9,8.21a29.3,29.3,0,0,1-1.83,9.88c-.82,1.66-5,4.83-7.2,4.83"/><path d="M48.29,38.58c-4.16-1.83-8.57-3.08-10.34-6.4a12,12,0,0,1-6,3.73,12,12,0,0,1-5.95-3.73c-1.77,3.32-6.18,4.57-10.34,6.4-1.7.71-3.11,9.88-1.13,9.88A33.06,33.06,0,0,0,31.23,53h1.54a33.06,33.06,0,0,0,16.65-4.53C51.4,48.46,50,39.29,48.29,38.58Z"/><path d="M14.82,36.57c.76-.33,1.54-.65,2.3-1,2.49-1,4.85-2,6.22-3.44C21.07,31.23,19,30.25,18,28.41a8.83,8.83,0,0,1-4.41,2.76,8.83,8.83,0,0,1-4.4-2.76c-1.31,2.46-4.58,3.38-7.66,4.74-1.26.52-2.3,7.31-.84,7.31a24.55,24.55,0,0,0,10.86,3.31C11.89,40.81,12.86,37.39,14.82,36.57Z"/><path d="M62.45,33.15c-3.08-1.36-6.35-2.28-7.66-4.74a8.83,8.83,0,0,1-4.4,2.76A8.83,8.83,0,0,1,46,28.41c-1,1.84-3,2.82-5.32,3.76,1.37,1.43,3.73,2.41,6.22,3.44.76.31,1.54.63,2.26,1,2,.83,3,4.25,3.29,7.21a24.55,24.55,0,0,0,10.86-3.31C64.75,40.46,63.71,33.67,62.45,33.15Z"/></svg> ` getRef("receiver_initial").innerHTML = ` <svg class="icon group-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><path d="M13.61,28.09c-1.63,0-4.72-2.35-5.33-3.58a21.65,21.65,0,0,1-1.35-7.32s-.26-6.07,6.68-6.07a6.38,6.38,0,0,1,6.69,6.07A21.65,21.65,0,0,1,19,24.51c-.62,1.23-3.7,3.58-5.34,3.58"/><path d="M50.39,28.09c-1.64,0-4.72-2.35-5.34-3.58a21.9,21.9,0,0,1-1.35-7.32s-.26-6.07,6.69-6.07a6.37,6.37,0,0,1,6.68,6.07,21.65,21.65,0,0,1-1.35,7.32c-.61,1.23-3.7,3.58-5.33,3.58"/><path d="M32,31.74c-2.21,0-6.37-3.17-7.2-4.83A29.3,29.3,0,0,1,23,17s-.35-8.21,9-8.21c8.68,0,9,8.21,9,8.21a29.3,29.3,0,0,1-1.83,9.88c-.82,1.66-5,4.83-7.2,4.83"/><path d="M48.29,38.58c-4.16-1.83-8.57-3.08-10.34-6.4a12,12,0,0,1-6,3.73,12,12,0,0,1-5.95-3.73c-1.77,3.32-6.18,4.57-10.34,6.4-1.7.71-3.11,9.88-1.13,9.88A33.06,33.06,0,0,0,31.23,53h1.54a33.06,33.06,0,0,0,16.65-4.53C51.4,48.46,50,39.29,48.29,38.58Z"/><path d="M14.82,36.57c.76-.33,1.54-.65,2.3-1,2.49-1,4.85-2,6.22-3.44C21.07,31.23,19,30.25,18,28.41a8.83,8.83,0,0,1-4.41,2.76,8.83,8.83,0,0,1-4.4-2.76c-1.31,2.46-4.58,3.38-7.66,4.74-1.26.52-2.3,7.31-.84,7.31a24.55,24.55,0,0,0,10.86,3.31C11.89,40.81,12.86,37.39,14.82,36.57Z"/><path d="M62.45,33.15c-3.08-1.36-6.35-2.28-7.66-4.74a8.83,8.83,0,0,1-4.4,2.76A8.83,8.83,0,0,1,46,28.41c-1,1.84-3,2.82-5.32,3.76,1.37,1.43,3.73,2.41,6.22,3.44.76.31,1.54.63,2.26,1,2,.83,3,4.25,3.29,7.21a24.55,24.55,0,0,0,10.86-3.31C64.75,40.46,63.71,33.67,62.45,33.15Z"/></svg> `
} else { } else {
getRef("receiver_initial").textContent = getContactName(clickedContact.floID).charAt(0); getRef("receiver_initial").textContent = getContactName(floID).charAt(0);
} }
getRef("receiver_initial").setAttribute('style', `--contact-color: var(${contactColor(clickedContact.floID)})`) getRef("receiver_initial").setAttribute('style', `--contact-color: var(${contactColor(floID)})`)
renderMessages(clickedContact.floID).then(() => { renderMessages(floID).then(() => {
if (!floGlobals.pubKeys[clickedContact.floID] && !activeChat.isGroup) if (!floGlobals.pubKeys[floID] && !activeChat.isGroup)
getRef('messages_container').prepend(html.node`<strong id="warn_no_encryption">Converstion is not encrypted until receiver replies</strong>`) getRef('messages_container').prepend(html.node`<strong id="warn_no_encryption">Converstion is not encrypted until receiver replies</strong>`)
location.hash = `#/chat_page/messages` location.hash = `#/chat_page/messages`
}) })
messenger.removeMark(clickedContact.floID, "unread"); messenger.removeMark(floID, "unread");
if (this.scrollHeight <= this.clientHeight) { if (this.scrollHeight <= this.clientHeight) {
chatScrollInfo['isScrolledUp'] = false chatScrollInfo['isScrolledUp'] = false
getRef('scroll_to_bottom').classList.remove('no-transformations') getRef('scroll_to_bottom').classList.remove('no-transformations')
@ -2934,17 +2947,17 @@
} }
function renderMailList(mails, markUnread = true) { function renderMailList(mails, markUnread = true) {
const inboxMails = [] const inboxMails = document.createDocumentFragment()
const sentMails = [] const sentMails = document.createDocumentFragment()
for (let m in mails) { for (let m in mails) {
let { from, to, prev, ref, subject, time, content } = mails[m] let { from, to, prev, ref, subject, time, content } = mails[m]
if (from === myFloID) if (from === myFloID)
sentMails.unshift(render.mailCard(to, ref, subject, time, content, markUnread)) sentMails.prepend(render.mailCard(to, ref, subject, time, content, markUnread))
else if (to.includes(myFloID)) else if (to.includes(myFloID))
inboxMails.unshift(render.mailCard(from, ref, subject, time, content, markUnread)) inboxMails.prepend(render.mailCard(from, ref, subject, time, content, markUnread))
} }
renderElem(getRef('inbox_mail_container'), html`${inboxMails}`) getRef('inbox_mail_container').prepend(inboxMails)
renderElem(getRef('sent_mail_container'), html`${sentMails}`) getRef('sent_mail_container').prepend(sentMails)
} }
function viewMail(mailRef, newView = true) { function viewMail(mailRef, newView = true) {
@ -3111,7 +3124,7 @@
changeContactName(e.detail.value.trim()) changeContactName(e.detail.value.trim())
}) })
getRef('group_description').addEventListener('contentchanged', e => { getRef('group_description').addEventListener('contentchanged', e => {
messenger.changeGroupDescription(activeChat.floID, e.detail.value.trim()) messenger.changeGroupDescription(floGlobals.activeFloID, e.detail.value.trim())
.then(res => { .then(res => {
notify('Changed group description', 'success') notify('Changed group description', 'success')
}) })

View File

@ -1,4 +1,4 @@
(function() { (function () {
const messenger = window.messenger = {}; const messenger = window.messenger = {};
const expiredKeys = {}; const expiredKeys = {};
@ -121,7 +121,7 @@
floCloudAPI.closeRequest(groupConnID[groupID]); floCloudAPI.closeRequest(groupConnID[groupID]);
delete groupConnID[groupID]; delete groupConnID[groupID];
} }
let callbackFn = function(dataSet, error) { let callbackFn = function (dataSet, error) {
if (error) if (error)
return console.error(error) return console.error(error)
console.info(dataSet) console.info(dataSet)
@ -203,15 +203,15 @@
UI.group(newInbox); UI.group(newInbox);
} }
floCloudAPI.requestApplicationData(null, { floCloudAPI.requestApplicationData(null, {
receiverID: groupID, receiverID: groupID,
lowerVectorClock: _loaded.appendix[`lastReceived_${groupID}`] + 1, lowerVectorClock: _loaded.appendix[`lastReceived_${groupID}`] + 1,
callback: callbackFn callback: callbackFn
}).then(conn_id => groupConnID[groupID] = conn_id) }).then(conn_id => groupConnID[groupID] = conn_id)
.catch(error => console.error(`request-group(${groupID}):`, error)) .catch(error => console.error(`request-group(${groupID}):`, error))
} }
const initUserDB = function() { const initUserDB = function () {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
var obj = { var obj = {
messages: {}, messages: {},
@ -232,7 +232,7 @@
}) })
} }
messenger.blockUser = function(floID) { messenger.blockUser = function (floID) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (_loaded.blocked.has(floID)) if (_loaded.blocked.has(floID))
return resolve("User is already blocked"); return resolve("User is already blocked");
@ -243,7 +243,7 @@
}) })
} }
messenger.unblockUser = function(floID) { messenger.unblockUser = function (floID) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (!_loaded.blocked.has(floID)) if (!_loaded.blocked.has(floID))
return resolve("User is not blocked"); return resolve("User is not blocked");
@ -254,7 +254,7 @@
}) })
} }
messenger.sendMessage = function(message, receiver) { messenger.sendMessage = function (message, receiver) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
sendRaw(message, receiver, "MESSAGE").then(result => { sendRaw(message, receiver, "MESSAGE").then(result => {
let vc = result.vectorClock; let vc = result.vectorClock;
@ -277,7 +277,7 @@
}) })
} }
messenger.sendMail = function(subject, content, recipients, prev = null) { messenger.sendMail = function (subject, content, recipients, prev = null) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (!Array.isArray(recipients)) if (!Array.isArray(recipients))
recipients = [recipients] recipients = [recipients]
@ -310,12 +310,12 @@
}) })
} }
const requestDirectInbox = function() { const requestDirectInbox = function () {
if (directConnID) { //close existing request connection (if any) if (directConnID) { //close existing request connection (if any)
floCloudAPI.closeRequest(directConnID); floCloudAPI.closeRequest(directConnID);
directConnID = undefined; directConnID = undefined;
} }
let callbackFn = function(dataSet, error) { let callbackFn = function (dataSet, error) {
if (error) if (error)
return console.error(error) return console.error(error)
let newInbox = { let newInbox = {
@ -412,14 +412,14 @@
UI.direct(newInbox) UI.direct(newInbox)
} }
floCloudAPI.requestApplicationData(null, { floCloudAPI.requestApplicationData(null, {
receiverID: myFloID, receiverID: myFloID,
lowerVectorClock: _loaded.appendix.lastReceived + 1, lowerVectorClock: _loaded.appendix.lastReceived + 1,
callback: callbackFn callback: callbackFn
}).then(conn_id => directConnID = conn_id) }).then(conn_id => directConnID = conn_id)
.catch(error => console.error("request-direct:", error)); .catch(error => console.error("request-direct:", error));
} }
messenger.getMail = function(mailRef) { messenger.getMail = function (mailRef) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
compactIDB.readData("mails", mailRef).then(mail => { compactIDB.readData("mails", mailRef).then(mail => {
mail.content = decrypt(mail.content) mail.content = decrypt(mail.content)
@ -428,9 +428,9 @@
}); });
} }
const getChatOrder = messenger.getChatOrder = function(seperate = false) { const getChatOrder = messenger.getChatOrder = function (separate = false) {
let result; let result;
if (seperate) { if (separate) {
result = {}; result = {};
result.direct = Object.keys(_loaded.chats).map(a => [_loaded.chats[a], a]) result.direct = Object.keys(_loaded.chats).map(a => [_loaded.chats[a], a])
.sort((a, b) => b[0] - a[0]).map(a => a[1]); .sort((a, b) => b[0] - a[0]).map(a => a[1]);
@ -444,11 +444,11 @@
return result; return result;
} }
messenger.storeContact = function(floID, name) { messenger.storeContact = function (floID, name) {
return floDapps.storeContact(floID, name) return floDapps.storeContact(floID, name)
} }
const loadDataFromIDB = function(defaultList = true) { const loadDataFromIDB = function (defaultList = true) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (defaultList) if (defaultList)
dataList = ["mails", "marked", "groups", "chats", "blocked", "appendix"] dataList = ["mails", "marked", "groups", "chats", "blocked", "appendix"]
@ -497,19 +497,19 @@
}) })
} }
messenger.addMark = function(key, mark) { messenger.addMark = function (key, mark) {
if (_loaded.marked.hasOwnProperty(key) && !_loaded.marked[key].includes(mark)) if (_loaded.marked.hasOwnProperty(key) && !_loaded.marked[key].includes(mark))
_loaded.marked[key].push(mark) _loaded.marked[key].push(mark)
return addMark(key, mark) return addMark(key, mark)
} }
messenger.removeMark = function(key, mark) { messenger.removeMark = function (key, mark) {
if (_loaded.marked.hasOwnProperty(key)) if (_loaded.marked.hasOwnProperty(key))
_loaded.marked[key] = _loaded.marked[key].filter(v => v !== mark) _loaded.marked[key] = _loaded.marked[key].filter(v => v !== mark)
return removeMark(key, mark) return removeMark(key, mark)
} }
messenger.addChat = function(chatID) { messenger.addChat = function (chatID) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
compactIDB.addData("chats", 0, chatID) compactIDB.addData("chats", 0, chatID)
.then(result => resolve("Added chat")) .then(result => resolve("Added chat"))
@ -517,7 +517,7 @@
}) })
} }
messenger.rmChat = function(chatID) { messenger.rmChat = function (chatID) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
compactIDB.removeData("chats", chatID) compactIDB.removeData("chats", chatID)
.then(result => resolve("Chat removed")) .then(result => resolve("Chat removed"))
@ -525,7 +525,7 @@
}) })
} }
messenger.clearChat = function(chatID) { messenger.clearChat = function (chatID) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let options = { let options = {
lowerKey: `${chatID}|`, lowerKey: `${chatID}|`,
@ -542,7 +542,7 @@
}) })
} }
messenger.getChat = function(chatID) { messenger.getChat = function (chatID) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let options = { let options = {
lowerKey: `${chatID}|`, lowerKey: `${chatID}|`,
@ -557,7 +557,7 @@
}) })
} }
messenger.backupData = function() { messenger.backupData = function () {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
loadDataFromIDB(false).then(data => { loadDataFromIDB(false).then(data => {
delete data.appendix.AESKey; delete data.appendix.AESKey;
@ -577,7 +577,7 @@
}) })
} }
const parseBackup = messenger.parseBackup = function(blob) { const parseBackup = messenger.parseBackup = function (blob) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (blob instanceof Blob || blob instanceof File) { if (blob instanceof Blob || blob instanceof File) {
let reader = new FileReader(); let reader = new FileReader();
@ -607,7 +607,7 @@
}) })
} }
messenger.restoreData = function(arg) { messenger.restoreData = function (arg) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (arg instanceof Blob || arg instanceof File) if (arg instanceof Blob || arg instanceof File)
var parseData = parseBackup var parseData = parseBackup
@ -660,7 +660,7 @@
}) })
} }
messenger.clearUserData = function() { messenger.clearUserData = function () {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let promises = [ let promises = [
compactIDB.deleteDB(), compactIDB.deleteDB(),
@ -674,7 +674,7 @@
//group feature //group feature
messenger.createGroup = function(groupname, description = '') { messenger.createGroup = function (groupname, description = '') {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (!groupname) return reject("Invalid Group Name") if (!groupname) return reject("Invalid Group Name")
let id = floCrypto.generateNewID(); let id = floCrypto.generateNewID();
@ -702,7 +702,7 @@
}) })
} }
messenger.changeGroupName = function(groupID, name) { messenger.changeGroupName = function (groupID, name) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let groupInfo = _loaded.groups[groupID] let groupInfo = _loaded.groups[groupID]
if (myFloID !== groupInfo.admin) if (myFloID !== groupInfo.admin)
@ -714,7 +714,7 @@
}) })
} }
messenger.changeGroupDescription = function(groupID, description) { messenger.changeGroupDescription = function (groupID, description) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let groupInfo = _loaded.groups[groupID] let groupInfo = _loaded.groups[groupID]
if (myFloID !== groupInfo.admin) if (myFloID !== groupInfo.admin)
@ -726,7 +726,7 @@
}) })
} }
messenger.addGroupMembers = function(groupID, newMem, note = undefined) { messenger.addGroupMembers = function (groupID, newMem, note = undefined) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (!Array.isArray(newMem) && typeof newMem === "string") if (!Array.isArray(newMem) && typeof newMem === "string")
newMem = [newMem] newMem = [newMem]
@ -735,7 +735,7 @@
imem2 = [] imem2 = []
newMem.forEach(m => newMem.forEach(m =>
!floCrypto.validateAddr(m) ? imem1.push(m) : !floCrypto.validateAddr(m) ? imem1.push(m) :
m in floGlobals.pubKeys ? null : imem2.push(m) m in floGlobals.pubKeys ? null : imem2.push(m)
); );
if (imem1.length) if (imem1.length)
return reject(`Invalid Members(floIDs): ${imem1}`) return reject(`Invalid Members(floIDs): ${imem1}`)
@ -755,8 +755,8 @@
for (let i in results) for (let i in results)
if (results[i].status === "fulfilled") if (results[i].status === "fulfilled")
success.push(newMem[i]) success.push(newMem[i])
else if (results[i].status === "rejected") else if (results[i].status === "rejected")
failed.push(newMem[i]) failed.push(newMem[i])
let message = encrypt(success.join("|"), k) let message = encrypt(success.join("|"), k)
sendRaw(message, groupID, "ADD_MEMBERS", false, note) sendRaw(message, groupID, "ADD_MEMBERS", false, note)
.then(r => resolve(`Members added: ${success}`)) .then(r => resolve(`Members added: ${success}`))
@ -765,7 +765,7 @@
}) })
} }
messenger.rmGroupMembers = function(groupID, rmMem, note = undefined) { messenger.rmGroupMembers = function (groupID, rmMem, note = undefined) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (!Array.isArray(rmMem) && typeof rmMem === "string") if (!Array.isArray(rmMem) && typeof rmMem === "string")
rmMem = [rmMem] rmMem = [rmMem]
@ -785,7 +785,7 @@
}) })
} }
const revokeKey = messenger.revokeKey = function(groupID) { const revokeKey = messenger.revokeKey = function (groupID) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let groupInfo = _loaded.groups[groupID] let groupInfo = _loaded.groups[groupID]
if (myFloID !== groupInfo.admin) if (myFloID !== groupInfo.admin)
@ -800,7 +800,7 @@
}) })
} }
messenger.sendGroupMessage = function(message, groupID) { messenger.sendGroupMessage = function (message, groupID) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let k = _loaded.groups[groupID].eKey let k = _loaded.groups[groupID].eKey
message = encrypt(message, k) message = encrypt(message, k)
@ -810,7 +810,7 @@
}) })
} }
const disableGroup = messenger.disableGroup = function(groupID) { const disableGroup = messenger.disableGroup = function (groupID) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (!_loaded.groups[groupID]) if (!_loaded.groups[groupID])
return reject("Group not found"); return reject("Group not found");
@ -829,7 +829,7 @@
}) })
} }
messenger.init = function() { messenger.init = function () {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
initUserDB().then(result => { initUserDB().then(result => {
console.debug(result); console.debug(result);